-From f3bd6419099a0cfefc3b13cf95ba34015f06ffb3 Mon Sep 17 00:00:00 2001
+From 1fe826bf63cef59dde06a3e53f44445469c3ec75 Mon Sep 17 00:00:00 2001
From: Josh Wu <josh.wu@atmel.com>
Date: Fri, 23 Mar 2012 17:56:29 +0800
Subject: MAINTAINERS: add entry for Atmel isi driver
+commit 1551554518371d919bbf6f3f1b1599ea2e7d2ac0 upstream.
+
Signed-off-by: Josh Wu <josh.wu@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From ef899cb1d2fda864b02a7efa424767981353f1b5 Mon Sep 17 00:00:00 2001
+From 5dfa35bf3ff4ceaa13e05e8ed563435b499a665e Mon Sep 17 00:00:00 2001
From: Josh Wu <josh.wu@atmel.com>
Date: Fri, 23 Mar 2012 17:56:55 +0800
Subject: MAINTAINERS: add entry for Atmel touch screen ADC controller driver
+commit ff2675d6994157c308d7ce504b9f19a1c22d01a8 upstream.
+
Signed-off-by: Josh Wu <josh.wu@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 2dd30cf629c3267c2925a9925b31addf1ef168b6 Mon Sep 17 00:00:00 2001
+From aebdb4a2d3da9740c830b56ebdaaf9ade2e52b93 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Mon, 26 Mar 2012 15:50:36 +0200
Subject: MAINTAINERS: add entry for Atmel DMA driver
+commit b414dc16f6ee64a23c525f80b924e44b0f0bee18 upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
MAINTAINERS | 8 ++++++++
-From 811046c42ca111ebc64328429ae035f48dddb2fd Mon Sep 17 00:00:00 2001
+From 5ef2e8ea2b7b19632f2d8d931ddaa130669d50a1 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Mon, 26 Mar 2012 15:59:32 +0200
Subject: MAINTAINERS: add entry for Atmel timer counter (TC)
+commit e9cb1c5a5ba906d01bf49a27460bd357aa6089ab upstream.
+
Add an entry for the Timer Counter (TC) library and the clocksource
driver that is using this library.
-From ff97bdd9bbdcd2f550b68c11d90a3e01873933c7 Mon Sep 17 00:00:00 2001
+From c28695c921cee53829198558dc3ed95d9b65c83c Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Mon, 26 Mar 2012 16:11:19 +0200
Subject: MAINTAINERS: remove non-responding web link for atmel_usba driver
+commit 1066c51ee28189aabff073bcd197b84a4f87ea81 upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Haavard Skinnemoen <hskinnemoen@gmail.com>
Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no>
-From cfcd98b36cbb2f074a06b1665727a72d3677ce64 Mon Sep 17 00:00:00 2001
+From 0bec15efe762b830db265b747b134a15e6600045 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 12:21:12 +0100
Subject: ARM: at91: change AT91 Kconfig entry comment
+commit 929e994f7e249a58f50ccdd066da9899a6e39c7a upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
arch/arm/Kconfig | 4 ++--
-From 4b6fd2b781b2091e70dbfe0d3b3bf5ad70e9664b Mon Sep 17 00:00:00 2001
+From 9826d66f3e249659ca04a31885496ecb04f956ee Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 12:26:43 +0100
Subject: ARM: at91/Kconfig: change at91sam9g45 entry
+commit ca1dcbf7fc6a9d849f487a50f8ee34f923d8e16b upstream.
+
The AT91SAM9G45 entry covers the whole family so we also add the AT91SAM9M10
name and the "families" qualifier. Then, add a comment to explain which SoCs
are supported by this entry: AT91SAM9G45, AT91SAM9G46 but also
-From 780545021feb2796b0595ebb300522c862bafc55 Mon Sep 17 00:00:00 2001
+From 146a8f586032093247b7fbe75bde12d4d9bb4129 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 12:48:41 +0100
Subject: ARM: at91/Kconfig: add comment to at91sam9x5 family entry
+commit a26e1af50e716711c340146529403b37c5d455e8 upstream.
+
Add comment to make it clear that several SoC are supported by
this generic entry.
-From 2eb2471c5bf340e1057c2e5faba6d8b23f6f23e4 Mon Sep 17 00:00:00 2001
+From 18a3e8c78f1e37ef27874b915a8719589c801557 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 12:57:03 +0100
Subject: ARM: at91/Kconfig: add clarifications to AT91SAM9M10G45-EK entry
+commit fefbc4075a191e9e8c1064906c400ed19a0bc48a upstream.
+
Add clarifications about the SoCs that can be found on an AT91SAM9M10G45-EK
board. Add also the web link to this board on Atmel's website.
-From f46c2a68a6ad0d570c5c8894d8589cb91f0e2d5f Mon Sep 17 00:00:00 2001
+From 7be4beaa63a35e15e2c80938cc45aee62670cf49 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 13:49:21 +0100
Subject: ARM: at91/Kconfig: add AT91SAM9x5 family to AT91_EARLY_DBGU0 entry
+commit 514982adc7a5439140e09facf492e58fc8a7fcc3 upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
arch/arm/mach-at91/Kconfig | 2 +-
-From 761e63c4d6f8cbf48f12bc90aff9083eefb37e2c Mon Sep 17 00:00:00 2001
+From b1331a2b88162177d8a1f011736a51401724c20e Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 13:56:44 +0100
Subject: ARM: at91/Kconfig: website link for AT91SAM9G20-EK
+commit ff65e398f3e3d1ee38a6b23d5a9f8e2fd950be49 upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
arch/arm/mach-at91/Kconfig | 1 +
-From aa2c1a9a69b0a74992d2e4d129f69f58c9b9c433 Mon Sep 17 00:00:00 2001
+From 4af884378298168d5bdd0e8d16a3d0ce86b0925a Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 14:38:09 +0100
Subject: rtc: Kconfig: remove dependency for AT91 rtc driver
+commit 938f970eb23d40dba49d7b14b774ed7ae7ec974a upstream.
+
This will allow to select this driver for newer SoCs.
Keep dependency on AT91 because of the use of an header
file located in include/mach directory.
-From 3f06a6301f2cba15b6e6f60283c5910f6383ed3f Mon Sep 17 00:00:00 2001
+From 491ea72aa5bb04a0ab7078c74e0f8159044ececc Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 16:02:02 +0100
Subject: Input: Kconfig: remove dependency for atmel_tsadcc driver
+commit 1fc4ec3791729db4e2602e9afb1045aef1bc3a58 upstream.
+
This will allow to select this driver for newer SoCs.
Keep dependency on AT91 because of the use of an header
file located in include/mach directory.
-From 3511638f3d8c7369a85592a17b186482c1057b99 Mon Sep 17 00:00:00 2001
+From 2a6149a2914f5495085f2535a26b19a6e74de0bc Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Thu, 15 Mar 2012 16:10:59 +0100
Subject: hwrng: Kconfig: remove dependency for atmel-rng driver
+commit 1234f4bada54cfcd4dfeeebccf0295d49174da40 upstream.
+
This will allow to select this driver for newer SoCs. Make sure to
keep dependency on HAVE_CLK to avoid breaking other machines.
-From d100869e11a7ed455412896d44314a81a386ed42 Mon Sep 17 00:00:00 2001
+From 07c647f806c4b990c3ece3a6389de178d131b0d3 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 15 Feb 2012 18:35:40 +0800
Subject: ARM: at91: uncompress Store UART address in a variable
+commit c40a763be603867c226505dbe0845ea16a4ee538 upstream.
+
This will allow a future change to auto-detect which UART to use.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From e740a739f469c0128ad12bf8388cdb69bdccc005 Mon Sep 17 00:00:00 2001
+From b975f66bd77491d4f1b426fb4c02f337f0178f5f Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 15 Feb 2012 18:44:40 +0800
Subject: ARM: at91: uncompress: autodetect the uart to use
+commit 5f29d0a0ee2c3c2ed06384c923db336183ee6708 upstream.
+
This will now autodetect the first uart enabled by the bootloader
and will use it for uncompress. This will still assume that the bootloader
configured it (pins and clock).
-From 9e4b59887ceab4e5a9a311f91da86196106c75c1 Mon Sep 17 00:00:00 2001
+From bfb9a880b47717d96c83725f5134f1b24fc43550 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 5 Apr 2012 13:43:40 +0800
Subject: ARM: at91: drop at91_set_serial_console
+commit a27fa58117ae1161adefedde449e5a71b3c593a4 upstream.
+
at91_set_serial_console is used to define the default console of linux.
This is already manage by the cmdline. And if the boot loader can not be
modified you can still set it by enabling the CONFIG_CMDLINE_EXTEND option.
-From 01175552b5bdf3438fa9bb6acbbfa5498414d2ab Mon Sep 17 00:00:00 2001
+From 2f0374f8e78dc83a1589f405fac8c86e7fe2f2cd Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 5 Apr 2012 14:14:28 +0800
Subject: ARM: at91: do not pin mux the UARTs in init_early
+commit 71b149b3f740501c2d59c80de5b10f5e45051099 upstream.
+
There is no need to pinmux the UART so early in the kernel.
Move it to the board init.
-From 0543012c6006a0638654943130daae637f764d5a Mon Sep 17 00:00:00 2001
+From 940c679c9142bff7bc2c16192d6e118b9b07d9a2 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 5 Apr 2012 14:27:57 +0800
Subject: ARM: at91: move at91_init_leds to board init
+commit 7eb1dbb3beb982a7d72514abff96ebc08a22e5cd upstream.
+
This will also allow to finally move the gpio driver to platform device/driver.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From e7d4df4ef74b1ed11a0e2037bc5cbe8123cf258d Mon Sep 17 00:00:00 2001
+From ec2eded8dc34a9404174de06999cdeab641651c4 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Mon, 13 Feb 2012 14:58:30 +0800
Subject: ARM: at91: pm select memory controler at runtime
+commit efd09165aa554f84a42565d5ae6a1af58b06a97a upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
[nicolas.ferre@atmel.com: add cpuidle modification]
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-From 54af5dc6fcc90243d7d161c83f2c94cb1ef67697 Mon Sep 17 00:00:00 2001
+From c57f12b42c6bb7481d27ffb9073b32102ab3015c Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 6 Apr 2012 13:04:04 +0800
Subject: ARM: at91: add SOC_AT91SAM9 kconfig option to factorise select
+commit 1441bd325bbbcd38d190b2444481b23cdf70069a upstream.
+
This will allow to simplify the switch to multi soc in the same kernel.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 420a99e1110afb0a9a2fd8ac6e1c18ba2136002e Mon Sep 17 00:00:00 2001
+From f9375e3c4c45dafefe52350547b1f927f966ddd3 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 6 Apr 2012 11:51:50 +0800
Subject: ARN: at91: introduce SOC_AT91xxx define to allow to compile SoC core
support
+commit 1e3ce2b8545390a2aee8dbfcd49ca4161b636000 upstream.
+
We can now compile all SoC core support together and DT boards.
We still can not compile together the non DT board.
So We keep the ARCH_AT91xxx for the non DT board and for backward defconfig
-From 77a5977e7fdc175bb1963143b80ad2a74cf3d9b8 Mon Sep 17 00:00:00 2001
+From 48fbfca1c5db644eb14c62307d2608def41a78cf Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 1 Mar 2012 14:47:44 +0800
Subject: ARM: at91/dt: do not specify the board any more
+commit 7c8a98c8c0475f0659beb9798f6ddebc2c840079 upstream.
+
This will allow to add any board to a compiled kernel by just passing the DTB.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 73aa3911713fc739b9213475b4ff86d85d80d113 Mon Sep 17 00:00:00 2001
+From 5227ce7aea2f044e2e189626ea6f8d0cb7ac682c Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Sun, 8 Apr 2012 17:40:06 +0200
Subject: ARM: at91: add defconfig for device tree
+commit 39ecc143b4c1f3d42e8300e7f5274681b99f95c2 upstream.
+
This will enable all current SoC support on DT (9260, 9g20, 9g45 family
and 9x5 family).
-From d795dab6d067cd5734cd7af4b67634f3b3961bd7 Mon Sep 17 00:00:00 2001
+From 91c5d96f8c4ace401677cb00a843a1ab9f8646c6 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Mon, 9 Apr 2012 19:26:33 +0800
Subject: ARM: at91: add at91sam9260 DT support
+commit 5b6089cb6f283b29e7b1e181f95afd3dcf2d8948 upstream.
+
The at91sam9260 and at91sam9g20 share most of the same IP.
So udpate the node property in the at91sam9g20 only.
-From 735aea5075e405af25ecdaea8a00091fa0b45c29 Mon Sep 17 00:00:00 2001
+From e3ade6b868e15d2280fee9d17e5bdd0301411e76 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Mon, 30 Jan 2012 23:45:52 +0800
Subject: arm: at91: add Calao TNY-A9260 and TNY-A9G20 board support
+commit 995376a54460ea2e6279ad96353323048f7db3ab upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From a72c0834c3f846f3fe9f2c782c8d6a67df258458 Mon Sep 17 00:00:00 2001
+From 8eb252d75d14c55d013aafe27d6fd74f587d7e53 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Mon, 13 Feb 2012 00:54:47 +0800
Subject: ARM: at91: add at91sam9g20ek boards dt support
+commit 5cb4e73575e3c66b73ccda811b2ba70339703ea5 upstream.
+
Add both board revision support 1mmc and 2mmc and use a dtsi for common part.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From b2b5334c32e6c1c8c0333279e4ee9600b3d4d34a Mon Sep 17 00:00:00 2001
+From 820b7c95d6958edce4db6d204c9e3ccb8fb742a5 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 11 Apr 2012 23:40:31 +0800
Subject: ARM: at91: USB A926x update nand partition
+commit d78504774435d5fc961f58a92ba7ec441d8b74c9 upstream.
+
We now store the dtb in a nand partition.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 23f3c5a2f5746c2e1eca2364ea6fb3d3e4515cf3 Mon Sep 17 00:00:00 2001
+From 7c87b9d5d1ab4d9487de665e92ab94de3bdf050f Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 11 Apr 2012 23:42:44 +0800
Subject: ARM: at91: Calao USB A926x factorize common binding in
usb_a9260_common
+commit cff4175ecdc2447847526b6352ca6f7d1139d5b5 upstream.
+
This will simplify the adding of the A9260.
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 83be7b15e8dea5beb4d3299835b79347c3148fd2 Mon Sep 17 00:00:00 2001
+From 4c5e3f92533de94648bd618ec5825c9952f1ab57 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Mon, 9 Apr 2012 14:43:34 +0800
Subject: ARM: at91: DT: add Calao USB A9260 DT support
+commit 4e114c9576b53461b14ac30f5e6159e73aa6abd3 upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 07e34d884cb904668fe1e413fe10958a65de3c57 Mon Sep 17 00:00:00 2001
+From e693aa3e62f8ab17d523978b44543d489c4525e6 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Tue, 28 Feb 2012 15:23:43 +0800
Subject: ARM: at91: standard device init only if DT is not populated.
+commit 8cf93b9ceaf4534cdeda5727782001f8fecb1688 upstream.
+
This will avoid the CONFIG_OF on the *_devices.c as this file is deprecated
for DT support.
-From 6703c4d1f42cf346f9a6f5f174f46c01ece33c90 Mon Sep 17 00:00:00 2001
+From 04f070b90ea4e6121ecf05da4f2d86e28a7e3d72 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Sun, 26 Feb 2012 19:12:43 +0800
Subject: ARM: at91: add at91sam9263 DT support
+commit 4abb367722c2dc06972658c8fad5b4763114477c upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 57fab5b53e9cf05574fffd706373b62713eb616c Mon Sep 17 00:00:00 2001
+From 8dc26edb6641e03867239b76f0a6ab0042308db4 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Sun, 26 Feb 2012 19:12:43 +0800
Subject: ARM: at91: add at91sam9263ek DT support
+commit 39f31cd40ae0c2301c00e6f1cf17bf20863c498c upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 6c84b391e098cad2350f661ebffd8b8d4f6b8981 Mon Sep 17 00:00:00 2001
+From ae8f5dd8fc1213e42edc565e31cd14f4aee1ff8d Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 12 Apr 2012 18:01:33 +0800
Subject: ARM: at91: DT: add Calao USB A9263 board support
+commit 1fb4f71977c5ffe5875412949b0b7ab2bed3a283 upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 242797da12e5e34231572f9d5472ab2f80bbc301 Mon Sep 17 00:00:00 2001
+From 7c00f8580d1555427d9619881d0ad59f57665fbc Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 12 Apr 2012 18:47:32 +0800
Subject: ARM: at91: DT: add Calao TNY A9263 board support
+commit 15787753d08107f2066b8ed8c9f8046ef3b766bb upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From 1dd636835a243a050417ff1c10f221ef545d5ab0 Mon Sep 17 00:00:00 2001
+From 32a078f6d401977db0ed9eca60974a7f52db183f Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <linux-arm@overkiz.com>
Date: Fri, 20 Apr 2012 14:37:50 +0200
Subject: ARM: at91: add kizbox board dt support.
+commit df8267487c7f8d707faca430f4d759dbc2dad6f5 upstream.
+
This patch adds support for the kizbox board (based on at91sam9g20 SoC)
Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
-From 6d9ded2c6183d8098f852b2a5dcd18454f9de0e7 Mon Sep 17 00:00:00 2001
+From b05042223346bdeceecd5f4039da27b86010f682 Mon Sep 17 00:00:00 2001
From: Tim Schendekehl <tim.schendekehl@egnite.de>
Date: Tue, 24 Apr 2012 18:47:59 +0200
Subject: Ethernut 5 board support
+commit 26690863e2c1fa4fee5f6137b219f4b8a1a02287 upstream.
+
Add support for the Ethernut 5 open hardware design, based
on Atmel's AT91SAM9XE512 SoC.
-From 771d02d8690db4118b239f864edca3d80d1c163f Mon Sep 17 00:00:00 2001
+From 917cda0ea634a3812fbe22a20f634254beafa1a0 Mon Sep 17 00:00:00 2001
From: Hong Xu <hong.xu@atmel.com>
Date: Tue, 17 Apr 2012 14:26:30 +0800
Subject: ARM: at91: Add machine header file for AT91SAM9N12 SoC
+commit 02059684271079f96e2a7a4bdc7912f029997866 upstream.
+
Signed-off-by: Hong Xu <hong.xu@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 37b8c7ad2aa24a15b778cff614913c63b7e5c505 Mon Sep 17 00:00:00 2001
+From db8c0e1e68b38c879f7ff677bdacd20c3ec5b388 Mon Sep 17 00:00:00 2001
From: Hong Xu <hong.xu@atmel.com>
Date: Tue, 17 Apr 2012 14:26:31 +0800
Subject: ARM: at91: Add machine files for AT91SAM9N12 SoC
+commit 74db4fb93e4ed4d6241bf0f28e4b5d68a7a05577 upstream.
+
Signed-off-by: Hong Xu <hong.xu@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 2fc9a0d7df19f33a08242efb22d64e8d3d0280de Mon Sep 17 00:00:00 2001
+From a38377b607a1019457b443714b66b7d9cdd47380 Mon Sep 17 00:00:00 2001
From: Hong Xu <hong.xu@atmel.com>
Date: Tue, 17 Apr 2012 14:26:29 +0800
Subject: ARM: at91: Add DT description files for AT91SAM9N12-EK
+commit cce783c608fee0716cff65926d1835a5fd097b69 upstream.
+
Added AT91SAM9N12 SoC DT file, as well as the board definition
.dts file for AT91SAM9N12-EK.
-From 2d672820ba5d6f2b3be8f73decfc00d4994af6ba Mon Sep 17 00:00:00 2001
+From cf269a7d1c0c08e2f7d609f026c28e32d41a1b0d Mon Sep 17 00:00:00 2001
From: Paul Bolle <pebolle@tiscali.nl>
Date: Thu, 7 Jun 2012 12:18:46 +0200
Subject: ARM: at91: remove two unused headers
+commit 2d1c9ccd68cdee502eb4829dfe1def7debc0298e upstream.
+
Commit 82c583e3ae31ffa76d1280197274cc1e1cde3179 ("AT91RM9200 hardware
headers") introduced arch/arm/mach-at91/include/mach/at91_spi.h and
arch/arm/mach-at91/include/mach/at91_ssc.h. (These files were called
-From f7a7be1650e7160181c9ab1c4aeb5dd8b67ac939 Mon Sep 17 00:00:00 2001
+From 27948a35ec0d89d516dad5eca85e2bd27109483e Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Thu, 31 May 2012 17:26:05 +0200
Subject: ARM: at91: fix at91_aic_write macro
+commit f25b00be60ab3865308a89437af66b277b04f53e upstream.
+
Fix at91_aic_write macro to avoid potential issues.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-From 6b36e56532a5b9d9f2311165a95f2a0d31c40464 Mon Sep 17 00:00:00 2001
+From b6a6d64d8d141bd4f88453c6586dfe67813db266 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 9 May 2012 10:49:41 +0200
Subject: USB: ohci-at91: use resource_size() for memory/io resource length
+commit 7a82f612fa3aadb5676184ae202903f5a42e4f4a upstream.
+
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
--- /dev/null
+From 4bd0bf333245414643729d864fdea1023984b8e9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 9 Jul 2012 21:06:25 +0200
+Subject: ARM: at91/clock: fix PLLA overclock warning
+
+commit 2ed1f58900280f79485bbc15f781687bd9584675 upstream.
+
+Fix PLLA overclock warning in relation with datasheet numbers.
+Add new > 240 MHz and > 210 MHz SoC categories.
+
+Reported-by: Jiri Prchal <jiri.prchal@aksignal.cz>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/clock.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
+index de2ec6b..188c829 100644
+--- a/arch/arm/mach-at91/clock.c
++++ b/arch/arm/mach-at91/clock.c
+@@ -63,6 +63,12 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
+
+ #define cpu_has_300M_plla() (cpu_is_at91sam9g10())
+
++#define cpu_has_240M_plla() (cpu_is_at91sam9261() \
++ || cpu_is_at91sam9263() \
++ || cpu_is_at91sam9rl())
++
++#define cpu_has_210M_plla() (cpu_is_at91sam9260())
++
+ #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5() \
+@@ -706,6 +712,12 @@ static int __init at91_pmc_init(unsigned long main_clock)
+ } else if (cpu_has_800M_plla()) {
+ if (plla.rate_hz > 800000000)
+ pll_overclock = true;
++ } else if (cpu_has_240M_plla()) {
++ if (plla.rate_hz > 240000000)
++ pll_overclock = true;
++ } else if (cpu_has_210M_plla()) {
++ if (plla.rate_hz > 210000000)
++ pll_overclock = true;
+ } else {
+ if (plla.rate_hz > 209000000)
+ pll_overclock = true;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 4a0e29935e53da412664f85d25d46ba719ec2294 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 19 Jun 2012 13:14:10 +0200
-Subject: USB: Kconfig: add Atmel usba driver entry
-
-Allow the USBA entry to be selected for every AT91 SoC.
-Will allow to select driver for newer SoCs.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/usb/gadget/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
-index 2633f75..10fea8b 100644
---- a/drivers/usb/gadget/Kconfig
-+++ b/drivers/usb/gadget/Kconfig
-@@ -150,7 +150,7 @@ config USB_AT91
- config USB_ATMEL_USBA
- tristate "Atmel USBA"
- select USB_GADGET_DUALSPEED
-- depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
-+ depends on AVR32 || ARCH_AT91
- help
- USBA is the integrated high-speed USB Device controller on
- the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 0880824561e6e9769027d83be21e5ab3f8aa9d31 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 9 Jul 2012 21:06:25 +0200
-Subject: ARM: at91/clock: fix PLLA overclock warning
-
-Fix PLLA overclock warning in relation with datasheet numbers.
-Add new > 240 MHz and > 210 MHz SoC categories.
-
-Reported-by: Jiri Prchal <jiri.prchal@aksignal.cz>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/clock.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
-index de2ec6b..188c829 100644
---- a/arch/arm/mach-at91/clock.c
-+++ b/arch/arm/mach-at91/clock.c
-@@ -63,6 +63,12 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
-
- #define cpu_has_300M_plla() (cpu_is_at91sam9g10())
-
-+#define cpu_has_240M_plla() (cpu_is_at91sam9261() \
-+ || cpu_is_at91sam9263() \
-+ || cpu_is_at91sam9rl())
-+
-+#define cpu_has_210M_plla() (cpu_is_at91sam9260())
-+
- #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
-@@ -706,6 +712,12 @@ static int __init at91_pmc_init(unsigned long main_clock)
- } else if (cpu_has_800M_plla()) {
- if (plla.rate_hz > 800000000)
- pll_overclock = true;
-+ } else if (cpu_has_240M_plla()) {
-+ if (plla.rate_hz > 240000000)
-+ pll_overclock = true;
-+ } else if (cpu_has_210M_plla()) {
-+ if (plla.rate_hz > 210000000)
-+ pll_overclock = true;
- } else {
- if (plla.rate_hz > 209000000)
- pll_overclock = true;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From d8b0eeec1568a9dd566c733e25d349704aa0ba61 Mon Sep 17 00:00:00 2001
+From: Bo Shen <voice.shen@atmel.com>
+Date: Fri, 17 Aug 2012 16:23:56 +0800
+Subject: ARM: at91/dts: remove partial parameter in at91sam9g25ek.dts
+
+commit 9e0255dd035348953e23161b7158b2ce0ddc182e upstream.
+
+Remove the malformed "mem=" bootargs parameter in at91sam9g25ek.dts
+
+Signed-off-by: Bo Shen <voice.shen@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 7829a4d..96514c1 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -15,7 +15,7 @@
+ compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ chosen {
+- bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ };
+
+ ahb {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5870fd6e3a30ac854a4f38eba8976fbde68fa705 Mon Sep 17 00:00:00 2001
-From: Bo Shen <voice.shen@atmel.com>
-Date: Fri, 17 Aug 2012 16:23:56 +0800
-Subject: ARM: at91/dts: remove partial parameter in at91sam9g25ek.dts
-
-Remove the malformed "mem=" bootargs parameter in at91sam9g25ek.dts
-
-Signed-off-by: Bo Shen <voice.shen@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9g25ek.dts | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
-index 7829a4d..96514c1 100644
---- a/arch/arm/boot/dts/at91sam9g25ek.dts
-+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
-@@ -15,7 +15,7 @@
- compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
-
- chosen {
-- bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
-+ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
- };
-
- ahb {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 119447ac8e1e07bc8a44760ffa4a72ec55fce825 Mon Sep 17 00:00:00 2001
+From: Paul Bolle <pebolle@tiscali.nl>
+Date: Thu, 24 May 2012 16:30:29 +0200
+Subject: ARM: at91: set i2c_board_info.type to "ds1339" directly
+
+commit c1cb59fde7d1570e23d97d9b2a988760f732e28b upstream.
+
+The single element of the cpu9krea_i2c_devices array (of type struct
+i2c_board_info) has its "type" member set twice. First to "rtc-ds1307"
+(through the I2C_BOARD_INFO macro) and then directly to "ds1339". Just
+set it (once and) directly to "ds1339" instead.
+
+Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-cpu9krea.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 69951ec..ece0d76 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -253,8 +253,7 @@ static struct gpio_led cpu9krea_leds[] = {
+
+ static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
+ {
+- I2C_BOARD_INFO("rtc-ds1307", 0x68),
+- .type = "ds1339",
++ I2C_BOARD_INFO("ds1339", 0x68),
+ },
+ };
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 10bcd9d24bf2abbe98c2e12f83926e1aa1dc4799 Mon Sep 17 00:00:00 2001
+From: Richard Genoud <richard.genoud@gmail.com>
+Date: Fri, 22 Jun 2012 15:29:28 +0200
+Subject: ARM: at91/defconfig: Remove unaffected config option
+
+commit b4084bcf5ae833e049b0c428868de7e4efae2e4f upstream.
+
+The commit bf4289cba02b8cf770ecd7959ca70839f0dd9d3c removed the use of
+CONFIG_MTD_NAND_ATMEL_ECC_NONE and CONFIG_MTD_NAND_ATMEL_ECC_HW but the
+Kconfig file was forgotten.
+
+This patch remove those inoperative options.
+
+Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/afeb9260_defconfig | 1 -
+ arch/arm/configs/at91sam9263_defconfig | 1 -
+ arch/arm/configs/qil-a9260_defconfig | 1 -
+ arch/arm/configs/usb-a9260_defconfig | 1 -
+ drivers/mtd/nand/Kconfig | 40 ----------------------------------
+ 5 files changed, 44 deletions(-)
+
+diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig
+index 2afdf67..c285a9d 100644
+--- a/arch/arm/configs/afeb9260_defconfig
++++ b/arch/arm/configs/afeb9260_defconfig
+@@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_ATMEL_SSC=y
+diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
+index 1cf9626..585e7e0 100644
+--- a/arch/arm/configs/at91sam9263_defconfig
++++ b/arch/arm/configs/at91sam9263_defconfig
+@@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_BLOCK2MTD=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_MTD_UBI=y
+ CONFIG_MTD_UBI_GLUEBI=y
+ CONFIG_BLK_DEV_LOOP=y
+diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
+index 9160f3b..2bb100b 100644
+--- a/arch/arm/configs/qil-a9260_defconfig
++++ b/arch/arm/configs/qil-a9260_defconfig
+@@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_LOOP=y
+ # CONFIG_MISC_DEVICES is not set
+ CONFIG_SCSI=y
+diff --git a/arch/arm/configs/usb-a9260_defconfig b/arch/arm/configs/usb-a9260_defconfig
+index 2e39f38..a1501e1 100644
+--- a/arch/arm/configs/usb-a9260_defconfig
++++ b/arch/arm/configs/usb-a9260_defconfig
+@@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y
+ CONFIG_MTD_DATAFLASH=y
+ CONFIG_MTD_NAND=y
+ CONFIG_MTD_NAND_ATMEL=y
+-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+ CONFIG_BLK_DEV_LOOP=y
+ # CONFIG_MISC_DEVICES is not set
+ CONFIG_SCSI=y
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 7d17cec..0e43a3f 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -366,46 +366,6 @@ config MTD_NAND_ATMEL
+ help
+ Enables support for NAND Flash / Smart Media Card interface
+ on Atmel AT91 and AVR32 processors.
+-choice
+- prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
+- depends on MTD_NAND_ATMEL
+-
+-config MTD_NAND_ATMEL_ECC_HW
+- bool "Hardware ECC"
+- depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
+- help
+- Use hardware ECC instead of software ECC when the chip
+- supports it.
+-
+- The hardware ECC controller is capable of single bit error
+- correction and 2-bit random detection per page.
+-
+- NB : hardware and software ECC schemes are incompatible.
+- If you switch from one to another, you'll have to erase your
+- mtd partition.
+-
+- If unsure, say Y
+-
+-config MTD_NAND_ATMEL_ECC_SOFT
+- bool "Software ECC"
+- help
+- Use software ECC.
+-
+- NB : hardware and software ECC schemes are incompatible.
+- If you switch from one to another, you'll have to erase your
+- mtd partition.
+-
+-config MTD_NAND_ATMEL_ECC_NONE
+- bool "No ECC (testing only, DANGEROUS)"
+- depends on DEBUG_KERNEL
+- help
+- No ECC will be used.
+- It's not a good idea and it should be reserved for testing
+- purpose only.
+-
+- If unsure, say N
+-
+-endchoice
+
+ config MTD_NAND_PXA3xx
+ tristate "Support for NAND flash devices on PXA3xx"
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 632b3f90968b823b65b84cac6b348b13ad662a95 Mon Sep 17 00:00:00 2001
-From: Paul Bolle <pebolle@tiscali.nl>
-Date: Thu, 24 May 2012 16:30:29 +0200
-Subject: ARM: at91: set i2c_board_info.type to "ds1339" directly
-
-The single element of the cpu9krea_i2c_devices array (of type struct
-i2c_board_info) has its "type" member set twice. First to "rtc-ds1307"
-(through the I2C_BOARD_INFO macro) and then directly to "ds1339". Just
-set it (once and) directly to "ds1339" instead.
-
-Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/board-cpu9krea.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
-index 69951ec..ece0d76 100644
---- a/arch/arm/mach-at91/board-cpu9krea.c
-+++ b/arch/arm/mach-at91/board-cpu9krea.c
-@@ -253,8 +253,7 @@ static struct gpio_led cpu9krea_leds[] = {
-
- static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
- {
-- I2C_BOARD_INFO("rtc-ds1307", 0x68),
-- .type = "ds1339",
-+ I2C_BOARD_INFO("ds1339", 0x68),
- },
- };
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 7b849b56ec5599dbe5454204511d904c0d1c2be4 Mon Sep 17 00:00:00 2001
-From: Richard Genoud <richard.genoud@gmail.com>
-Date: Fri, 22 Jun 2012 15:29:28 +0200
-Subject: ARM: at91/defconfig: Remove unaffected config option
-
-The commit bf4289cba02b8cf770ecd7959ca70839f0dd9d3c removed the use of
-CONFIG_MTD_NAND_ATMEL_ECC_NONE and CONFIG_MTD_NAND_ATMEL_ECC_HW but the
-Kconfig file was forgotten.
-
-This patch remove those inoperative options.
-
-Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/configs/afeb9260_defconfig | 1 -
- arch/arm/configs/at91sam9263_defconfig | 1 -
- arch/arm/configs/qil-a9260_defconfig | 1 -
- arch/arm/configs/usb-a9260_defconfig | 1 -
- drivers/mtd/nand/Kconfig | 40 ----------------------------------
- 5 files changed, 44 deletions(-)
-
-diff --git a/arch/arm/configs/afeb9260_defconfig b/arch/arm/configs/afeb9260_defconfig
-index 2afdf67..c285a9d 100644
---- a/arch/arm/configs/afeb9260_defconfig
-+++ b/arch/arm/configs/afeb9260_defconfig
-@@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y
- CONFIG_MTD_DATAFLASH=y
- CONFIG_MTD_NAND=y
- CONFIG_MTD_NAND_ATMEL=y
--CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
- CONFIG_BLK_DEV_RAM=y
- CONFIG_BLK_DEV_RAM_SIZE=8192
- CONFIG_ATMEL_SSC=y
-diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
-index 1cf9626..585e7e0 100644
---- a/arch/arm/configs/at91sam9263_defconfig
-+++ b/arch/arm/configs/at91sam9263_defconfig
-@@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y
- CONFIG_MTD_BLOCK2MTD=y
- CONFIG_MTD_NAND=y
- CONFIG_MTD_NAND_ATMEL=y
--CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
- CONFIG_MTD_UBI=y
- CONFIG_MTD_UBI_GLUEBI=y
- CONFIG_BLK_DEV_LOOP=y
-diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
-index 9160f3b..2bb100b 100644
---- a/arch/arm/configs/qil-a9260_defconfig
-+++ b/arch/arm/configs/qil-a9260_defconfig
-@@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y
- CONFIG_MTD_DATAFLASH=y
- CONFIG_MTD_NAND=y
- CONFIG_MTD_NAND_ATMEL=y
--CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
- CONFIG_BLK_DEV_LOOP=y
- # CONFIG_MISC_DEVICES is not set
- CONFIG_SCSI=y
-diff --git a/arch/arm/configs/usb-a9260_defconfig b/arch/arm/configs/usb-a9260_defconfig
-index 2e39f38..a1501e1 100644
---- a/arch/arm/configs/usb-a9260_defconfig
-+++ b/arch/arm/configs/usb-a9260_defconfig
-@@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y
- CONFIG_MTD_DATAFLASH=y
- CONFIG_MTD_NAND=y
- CONFIG_MTD_NAND_ATMEL=y
--CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
- CONFIG_BLK_DEV_LOOP=y
- # CONFIG_MISC_DEVICES is not set
- CONFIG_SCSI=y
-diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
-index 7d17cec..0e43a3f 100644
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -366,46 +366,6 @@ config MTD_NAND_ATMEL
- help
- Enables support for NAND Flash / Smart Media Card interface
- on Atmel AT91 and AVR32 processors.
--choice
-- prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
-- depends on MTD_NAND_ATMEL
--
--config MTD_NAND_ATMEL_ECC_HW
-- bool "Hardware ECC"
-- depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
-- help
-- Use hardware ECC instead of software ECC when the chip
-- supports it.
--
-- The hardware ECC controller is capable of single bit error
-- correction and 2-bit random detection per page.
--
-- NB : hardware and software ECC schemes are incompatible.
-- If you switch from one to another, you'll have to erase your
-- mtd partition.
--
-- If unsure, say Y
--
--config MTD_NAND_ATMEL_ECC_SOFT
-- bool "Software ECC"
-- help
-- Use software ECC.
--
-- NB : hardware and software ECC schemes are incompatible.
-- If you switch from one to another, you'll have to erase your
-- mtd partition.
--
--config MTD_NAND_ATMEL_ECC_NONE
-- bool "No ECC (testing only, DANGEROUS)"
-- depends on DEBUG_KERNEL
-- help
-- No ECC will be used.
-- It's not a good idea and it should be reserved for testing
-- purpose only.
--
-- If unsure, say N
--
--endchoice
-
- config MTD_NAND_PXA3xx
- tristate "Support for NAND flash devices on PXA3xx"
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From d735b914ddb8a98a5a79c817c04625c70158941d Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 13 Sep 2012 12:40:26 +0200
+Subject: ARM: at91: fix missing #interrupt-cells on gpio-controller
+
+commit 51ac51a6a5ab5f0aff46c4757ba4c32f3f8f7a2e upstream.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Tested-by: Bo Shen <voice.shen@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 3 +++
+ arch/arm/boot/dts/at91sam9263.dtsi | 5 +++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 5 +++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 4 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
+ 5 files changed, 21 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index f4605ff..eddc467 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -103,6 +103,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -112,6 +113,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -121,6 +123,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 0209913..d330de9 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -94,6 +94,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+@@ -103,6 +104,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+@@ -112,6 +114,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+@@ -121,6 +124,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+@@ -130,6 +134,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index c804214..d1c497d 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -112,6 +112,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+@@ -121,6 +122,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+@@ -130,6 +132,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+@@ -139,6 +142,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+@@ -148,6 +152,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index cb84de7..a69e89a 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -107,6 +107,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -116,6 +117,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -125,6 +127,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+@@ -134,6 +137,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index dd4ed74..80a50864 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -114,6 +114,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+@@ -123,6 +124,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+@@ -132,6 +134,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+@@ -141,6 +144,7 @@
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@fffff200 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 567e6c4f49b1acf13d0e60ba9a6e1faa78f865a1 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Thu, 13 Sep 2012 12:40:26 +0200
-Subject: ARM: at91: fix missing #interrupt-cells on gpio-controller
-
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Tested-by: Bo Shen <voice.shen@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9260.dtsi | 3 +++
- arch/arm/boot/dts/at91sam9263.dtsi | 5 +++++
- arch/arm/boot/dts/at91sam9g45.dtsi | 5 +++++
- arch/arm/boot/dts/at91sam9n12.dtsi | 4 ++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
- 5 files changed, 21 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index f4605ff..eddc467 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -103,6 +103,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioB: gpio@fffff600 {
-@@ -112,6 +113,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioC: gpio@fffff800 {
-@@ -121,6 +123,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@fffff200 {
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 0209913..d330de9 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -94,6 +94,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioB: gpio@fffff400 {
-@@ -103,6 +104,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioC: gpio@fffff600 {
-@@ -112,6 +114,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioD: gpio@fffff800 {
-@@ -121,6 +124,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioE: gpio@fffffa00 {
-@@ -130,6 +134,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@ffffee00 {
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index c804214..d1c497d 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -112,6 +112,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioB: gpio@fffff400 {
-@@ -121,6 +122,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioC: gpio@fffff600 {
-@@ -130,6 +132,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioD: gpio@fffff800 {
-@@ -139,6 +142,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioE: gpio@fffffa00 {
-@@ -148,6 +152,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@ffffee00 {
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index cb84de7..a69e89a 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -107,6 +107,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioB: gpio@fffff600 {
-@@ -116,6 +117,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioC: gpio@fffff800 {
-@@ -125,6 +127,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioD: gpio@fffffa00 {
-@@ -134,6 +137,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@fffff200 {
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index dd4ed74..80a50864 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -114,6 +114,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioB: gpio@fffff600 {
-@@ -123,6 +124,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioC: gpio@fffff800 {
-@@ -132,6 +134,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- pioD: gpio@fffffa00 {
-@@ -141,6 +144,7 @@
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@fffff200 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 232aa09c9e9aa7e03a83382ef27612bcbed93570 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 19 Sep 2012 10:02:32 +0200
+Subject: ARM: at91: missing header file for rtc-at91rm9200.c
+
+Included in commit 14070ade02cc378bc30dae383532768a94805988 upstream.
+
+Missing asm/io.h inclusion causing issue with __raw_readl and
+__raw_writel.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/rtc/rtc-at91rm9200.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
+index dc474bc..f02acb0 100644
+--- a/drivers/rtc/rtc-at91rm9200.c
++++ b/drivers/rtc/rtc-at91rm9200.c
+@@ -28,6 +28,7 @@
+ #include <linux/ioctl.h>
+ #include <linux/completion.h>
+
++#include <asm/io.h>
+ #include <asm/uaccess.h>
+
+ #include <mach/at91_rtc.h>
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From d20929e0422398f34a241a11d9183fc7750c9f4e Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 19 Sep 2012 10:02:32 +0200
-Subject: ARM: at91: missing header file for rtc-at91rm9200.c
-
-Missing asm/io.h inclusion causing issue with __raw_readl and
-__raw_writel.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/rtc/rtc-at91rm9200.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
-index dc474bc..f02acb0 100644
---- a/drivers/rtc/rtc-at91rm9200.c
-+++ b/drivers/rtc/rtc-at91rm9200.c
-@@ -28,6 +28,7 @@
- #include <linux/ioctl.h>
- #include <linux/completion.h>
-
-+#include <asm/io.h>
- #include <asm/uaccess.h>
-
- #include <mach/at91_rtc.h>
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 79625ccc49e70d4cc8bb3361c98fd5ff3ad40157 Mon Sep 17 00:00:00 2001
+From: Joachim Eastwood <manabian@gmail.com>
+Date: Thu, 23 Aug 2012 18:14:54 +0200
+Subject: ASoC: atmel-ssc: include linux/io.h for raw io
+
+commit b969afc8b719bbe3f0842a694e6bf5e87f08868f upstream.
+
+Include linux/io.h for raw io operations in atmel-scc header.
+
+This fixes the following build error:
+ CC [M] sound/soc/atmel/atmel_ssc_dai.o
+sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_interrupt':
+sound/soc/atmel/atmel_ssc_dai.c:171: error: implicit declaration of function '__raw_readl'
+sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_shutdown':
+sound/soc/atmel/atmel_ssc_dai.c:249: error: implicit declaration of function '__raw_writel'
+
+Signed-off-by: Joachim Eastwood <joachim.eastwood@jotron.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+---
+ include/linux/atmel-ssc.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
+index 0602339..4eb3175 100644
+--- a/include/linux/atmel-ssc.h
++++ b/include/linux/atmel-ssc.h
+@@ -3,6 +3,7 @@
+
+ #include <linux/platform_device.h>
+ #include <linux/list.h>
++#include <linux/io.h>
+
+ struct ssc_device {
+ struct list_head list;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 6c4b12f6fc72208ab963463412acba210d137e71 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 25 May 2012 14:11:51 +0200
+Subject: ARM: at91: aic can use fast eoi handler type
+
+commit 42a859daaf6af4d234fcf964a421666d5cca3f6a upstream.
+
+The Advanced Interrupt Controller allows us to use the fast EOI handler type.
+It lets us remove the Atmel specific workaround into arch/arm/kernel/irq.c
+used to indicate to the AIC the end of the interrupt treatment.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+---
+ arch/arm/kernel/irq.c | 10 ----------
+ arch/arm/mach-at91/gpio.c | 9 +++++----
+ arch/arm/mach-at91/include/mach/irqs.h | 7 -------
+ arch/arm/mach-at91/irq.c | 15 ++++++++++++---
+ 4 files changed, 17 insertions(+), 24 deletions(-)
+
+diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
+index 8349d4e..16cedb4 100644
+--- a/arch/arm/kernel/irq.c
++++ b/arch/arm/kernel/irq.c
+@@ -40,13 +40,6 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/time.h>
+
+-/*
+- * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
+- */
+-#ifndef irq_finish
+-#define irq_finish(irq) do { } while (0)
+-#endif
+-
+ unsigned long irq_err_count;
+
+ int arch_show_interrupts(struct seq_file *p, int prec)
+@@ -85,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
+ generic_handle_irq(irq);
+ }
+
+- /* AT91 specific workaround */
+- irq_finish(irq);
+-
+ irq_exit();
+ set_irq_regs(old_regs);
+ }
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index 325837a..be42cf0 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -26,6 +26,8 @@
+ #include <linux/of_irq.h>
+ #include <linux/of_gpio.h>
+
++#include <asm/mach/irq.h>
++
+ #include <mach/hardware.h>
+ #include <mach/at91_pio.h>
+
+@@ -585,15 +587,14 @@ static struct irq_chip gpio_irqchip = {
+
+ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ {
++ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_data *idata = irq_desc_get_irq_data(desc);
+- struct irq_chip *chip = irq_data_get_irq_chip(idata);
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned long isr;
+ int n;
+
+- /* temporarily mask (level sensitive) parent IRQ */
+- chip->irq_ack(idata);
++ chained_irq_enter(chip, desc);
+ for (;;) {
+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+ * When there none are pending, we're finished unless we need
+@@ -614,7 +615,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+ n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
+ }
+ }
+- chip->irq_unmask(idata);
++ chained_irq_exit(chip, desc);
+ /* now it may re-trigger */
+ }
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+index ac8b7df..2d510ee 100644
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ b/arch/arm/mach-at91/include/mach/irqs.h
+@@ -28,13 +28,6 @@
+
+
+ /*
+- * Acknowledge interrupt with AIC after interrupt has been handled.
+- * (by kernel/irq.c)
+- */
+-#define irq_finish(irq) do { at91_aic_write(AT91_AIC_EOICR, 0); } while (0)
+-
+-
+-/*
+ * IRQ interrupt symbols are the AT91xxx_ID_* symbols
+ * for IRQs handled directly through the AIC, or else the AT91_PIN_*
+ * symbols in gpio.h for ones handled indirectly as GPIOs.
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index cfcfcbe..2d5d4c8 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -55,6 +55,15 @@ static void at91_aic_unmask_irq(struct irq_data *d)
+ at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
+ }
+
++static void at91_aic_eoi(struct irq_data *d)
++{
++ /*
++ * Mark end-of-interrupt on AIC, the controller doesn't care about
++ * the value written. Moreover it's a write-only register.
++ */
++ at91_aic_write(AT91_AIC_EOICR, 0);
++}
++
+ unsigned int at91_extern_irq;
+
+ #define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
+@@ -128,11 +137,11 @@ void at91_irq_resume(void)
+
+ static struct irq_chip at91_aic_chip = {
+ .name = "AIC",
+- .irq_ack = at91_aic_mask_irq,
+ .irq_mask = at91_aic_mask_irq,
+ .irq_unmask = at91_aic_unmask_irq,
+ .irq_set_type = at91_aic_set_type,
+ .irq_set_wake = at91_aic_set_wake,
++ .irq_eoi = at91_aic_eoi,
+ };
+
+ static void __init at91_aic_hw_init(unsigned int spu_vector)
+@@ -171,7 +180,7 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ /* Active Low interrupt, without priority */
+ at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
+
+- irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
++ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+@@ -238,7 +247,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+
+- irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
++ irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From dc55ac7fd56dc3973d15f3a263b29ce222715771 Mon Sep 17 00:00:00 2001
-From: Joachim Eastwood <manabian@gmail.com>
-Date: Thu, 23 Aug 2012 18:14:54 +0200
-Subject: ASoC: atmel-ssc: include linux/io.h for raw io
-
-Include linux/io.h for raw io operations in atmel-scc header.
-
-This fixes the following build error:
- CC [M] sound/soc/atmel/atmel_ssc_dai.o
-sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_interrupt':
-sound/soc/atmel/atmel_ssc_dai.c:171: error: implicit declaration of function '__raw_readl'
-sound/soc/atmel/atmel_ssc_dai.c: In function 'atmel_ssc_shutdown':
-sound/soc/atmel/atmel_ssc_dai.c:249: error: implicit declaration of function '__raw_writel'
-
-Signed-off-by: Joachim Eastwood <joachim.eastwood@jotron.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
----
- include/linux/atmel-ssc.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h
-index 0602339..4eb3175 100644
---- a/include/linux/atmel-ssc.h
-+++ b/include/linux/atmel-ssc.h
-@@ -3,6 +3,7 @@
-
- #include <linux/platform_device.h>
- #include <linux/list.h>
-+#include <linux/io.h>
-
- struct ssc_device {
- struct list_head list;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6d79a82baf09ee3a77f305542cf0ed0c00fa325f Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 9 Apr 2012 19:36:36 +0800
+Subject: ARM: at91: aic add dt support for external irqs
+
+commit c65739437045c351a2a0ddb834719b9d616d4d47 upstream.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ Documentation/devicetree/bindings/arm/atmel-aic.txt | 1 +
+ arch/arm/boot/dts/at91sam9260.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9263.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9g45.dtsi | 1 +
+ arch/arm/boot/dts/at91sam9x5.dtsi | 1 +
+ arch/arm/mach-at91/at91sam9x5.c | 2 --
+ arch/arm/mach-at91/irq.c | 12 ++++++++++++
+ 7 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+index aabca4f..1953b0c 100644
+--- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
++++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+@@ -15,6 +15,7 @@ Required properties:
+ Valid combinations are 1, 2, 3, 4, 8.
+ Default flag for internal sources should be set to 4 (active high).
+ - reg: Should contain AIC registers location and length
++- atmel,external-irqs: u32 array of external irqs.
+
+ Examples:
+ /*
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index eddc467..fb86de0 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -56,6 +56,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <29 30 31>;
+ };
+
+ ramc0: ramc@ffffea00 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index d330de9..78b2808 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -52,6 +52,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <30 31>;
+ };
+
+ pmc: pmc@fffffc00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index d1c497d..779ffca 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -57,6 +57,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <31>;
+ };
+
+ ramc0: ramc@ffffe400 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 80a50864..170b6f8 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -55,6 +55,7 @@
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
++ atmel,external-irqs = <31>;
+ };
+
+ ramc0: ramc@ffffe800 {
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 13c8cae..dce3ff3 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -306,8 +306,6 @@ static void __init at91sam9x5_map_io(void)
+
+ void __init at91sam9x5_initialize(void)
+ {
+- at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
+-
+ /* Register GPIO subsystem (using DT) */
+ at91_gpio_init(NULL, 0);
+ }
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 2d5d4c8..df8605f 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -194,6 +194,10 @@ static struct irq_domain_ops at91_aic_irq_ops = {
+ int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent)
+ {
++ struct property *prop;
++ const __be32 *p;
++ u32 val;
++
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+@@ -202,6 +206,14 @@ int __init at91_aic_of_init(struct device_node *node,
+ if (!at91_aic_domain)
+ panic("Unable to add AIC irq domain (DT)\n");
+
++ at91_extern_irq = 0;
++ of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
++ if (val > 31)
++ pr_warn("AIC: external irq %d > 31 skip it\n", val);
++ else
++ at91_extern_irq |= (1 << val);
++ }
++
+ irq_set_default_host(at91_aic_domain);
+
+ at91_aic_hw_init(NR_AIC_IRQS);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From adc32a9ee5875fe4c0da12b676b38c696d95437c Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 25 May 2012 14:11:51 +0200
-Subject: ARM: at91: aic can use fast eoi handler type
-
-The Advanced Interrupt Controller allows us to use the fast EOI handler type.
-It lets us remove the Atmel specific workaround into arch/arm/kernel/irq.c
-used to indicate to the AIC the end of the interrupt treatment.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Will Deacon <will.deacon@arm.com>
----
- arch/arm/kernel/irq.c | 10 ----------
- arch/arm/mach-at91/gpio.c | 9 +++++----
- arch/arm/mach-at91/include/mach/irqs.h | 7 -------
- arch/arm/mach-at91/irq.c | 15 ++++++++++++---
- 4 files changed, 17 insertions(+), 24 deletions(-)
-
-diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
-index 8349d4e..16cedb4 100644
---- a/arch/arm/kernel/irq.c
-+++ b/arch/arm/kernel/irq.c
-@@ -40,13 +40,6 @@
- #include <asm/mach/irq.h>
- #include <asm/mach/time.h>
-
--/*
-- * No architecture-specific irq_finish function defined in arm/arch/irqs.h.
-- */
--#ifndef irq_finish
--#define irq_finish(irq) do { } while (0)
--#endif
--
- unsigned long irq_err_count;
-
- int arch_show_interrupts(struct seq_file *p, int prec)
-@@ -85,9 +78,6 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
- generic_handle_irq(irq);
- }
-
-- /* AT91 specific workaround */
-- irq_finish(irq);
--
- irq_exit();
- set_irq_regs(old_regs);
- }
-diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
-index 325837a..be42cf0 100644
---- a/arch/arm/mach-at91/gpio.c
-+++ b/arch/arm/mach-at91/gpio.c
-@@ -26,6 +26,8 @@
- #include <linux/of_irq.h>
- #include <linux/of_gpio.h>
-
-+#include <asm/mach/irq.h>
-+
- #include <mach/hardware.h>
- #include <mach/at91_pio.h>
-
-@@ -585,15 +587,14 @@ static struct irq_chip gpio_irqchip = {
-
- static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
- {
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
- struct irq_data *idata = irq_desc_get_irq_data(desc);
-- struct irq_chip *chip = irq_data_get_irq_chip(idata);
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
- void __iomem *pio = at91_gpio->regbase;
- unsigned long isr;
- int n;
-
-- /* temporarily mask (level sensitive) parent IRQ */
-- chip->irq_ack(idata);
-+ chained_irq_enter(chip, desc);
- for (;;) {
- /* Reading ISR acks pending (edge triggered) GPIO interrupts.
- * When there none are pending, we're finished unless we need
-@@ -614,7 +615,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
- n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
- }
- }
-- chip->irq_unmask(idata);
-+ chained_irq_exit(chip, desc);
- /* now it may re-trigger */
- }
-
-diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
-index ac8b7df..2d510ee 100644
---- a/arch/arm/mach-at91/include/mach/irqs.h
-+++ b/arch/arm/mach-at91/include/mach/irqs.h
-@@ -28,13 +28,6 @@
-
-
- /*
-- * Acknowledge interrupt with AIC after interrupt has been handled.
-- * (by kernel/irq.c)
-- */
--#define irq_finish(irq) do { at91_aic_write(AT91_AIC_EOICR, 0); } while (0)
--
--
--/*
- * IRQ interrupt symbols are the AT91xxx_ID_* symbols
- * for IRQs handled directly through the AIC, or else the AT91_PIN_*
- * symbols in gpio.h for ones handled indirectly as GPIOs.
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index cfcfcbe..2d5d4c8 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -55,6 +55,15 @@ static void at91_aic_unmask_irq(struct irq_data *d)
- at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
- }
-
-+static void at91_aic_eoi(struct irq_data *d)
-+{
-+ /*
-+ * Mark end-of-interrupt on AIC, the controller doesn't care about
-+ * the value written. Moreover it's a write-only register.
-+ */
-+ at91_aic_write(AT91_AIC_EOICR, 0);
-+}
-+
- unsigned int at91_extern_irq;
-
- #define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
-@@ -128,11 +137,11 @@ void at91_irq_resume(void)
-
- static struct irq_chip at91_aic_chip = {
- .name = "AIC",
-- .irq_ack = at91_aic_mask_irq,
- .irq_mask = at91_aic_mask_irq,
- .irq_unmask = at91_aic_unmask_irq,
- .irq_set_type = at91_aic_set_type,
- .irq_set_wake = at91_aic_set_wake,
-+ .irq_eoi = at91_aic_eoi,
- };
-
- static void __init at91_aic_hw_init(unsigned int spu_vector)
-@@ -171,7 +180,7 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- /* Active Low interrupt, without priority */
- at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
-
-- irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq);
-+ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
-
- return 0;
-@@ -238,7 +247,7 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
- /* Active Low interrupt, with the specified priority */
- at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
-
-- irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq);
-+ irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 70df58d418b354d8e1ad6597463da2b3d32148c3 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 20 Jun 2012 16:13:30 +0200
+Subject: ARM: at91: add of irq priorities support
+
+commit f8a073ee378b9893aee0749c3868a6ecfb0c1636 upstream.
+
+Add a third cell to define irq priority.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9260.dtsi
+ arch/arm/boot/dts/at91sam9g45.dtsi
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ .../devicetree/bindings/arm/atmel-aic.txt | 8 +++--
+ arch/arm/boot/dts/at91sam9260.dtsi | 34 ++++++++++----------
+ arch/arm/boot/dts/at91sam9263.dtsi | 30 +++++++++---------
+ arch/arm/boot/dts/at91sam9g45.dtsi | 36 +++++++++++-----------
+ arch/arm/boot/dts/at91sam9n12.dtsi | 30 +++++++++---------
+ arch/arm/boot/dts/at91sam9x5.dtsi | 36 +++++++++++-----------
+ arch/arm/mach-at91/include/mach/at91_aic.h | 3 ++
+ arch/arm/mach-at91/irq.c | 34 ++++++++++++++++++--
+ 8 files changed, 122 insertions(+), 89 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+index 1953b0c..19078bf 100644
+--- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
++++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
+@@ -4,7 +4,7 @@ Required properties:
+ - compatible: Should be "atmel,<chip>-aic"
+ - interrupt-controller: Identifies the node as an interrupt controller.
+ - interrupt-parent: For single AIC system, it is an empty property.
+-- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
++- #interrupt-cells: The number of cells to define the interrupts. It sould be 3.
+ The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
+ The second cell is used to specify flags:
+ bits[3:0] trigger type and level flags:
+@@ -14,6 +14,8 @@ Required properties:
+ 8 = active low level-sensitive.
+ Valid combinations are 1, 2, 3, 4, 8.
+ Default flag for internal sources should be set to 4 (active high).
++ The third cell is used to specify the irq priority from 0 (lowest) to 7
++ (highest).
+ - reg: Should contain AIC registers location and length
+ - atmel,external-irqs: u32 array of external irqs.
+
+@@ -25,7 +27,7 @@ Examples:
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ interrupt-parent;
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ reg = <0xfffff000 0x200>;
+ };
+
+@@ -35,5 +37,5 @@ Examples:
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 5>;
+ };
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index fb86de0..12df8ca 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -52,7 +52,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -82,25 +82,25 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@fffa0000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa0000 0x100>;
+- interrupts = <17 4 18 4 19 4>;
++ interrupts = <17 4 0 18 4 0 19 4 0>;
+ };
+
+ tcb1: timer@fffdc000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffdc000 0x100>;
+- interrupts = <26 4 27 4 28 4>;
++ interrupts = <26 4 0 27 4 0 28 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -110,7 +110,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -120,7 +120,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -130,14 +130,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fffb0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb0000 0x200>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -146,7 +146,7 @@
+ usart1: serial@fffb4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb4000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -155,7 +155,7 @@
+ usart2: serial@fffb8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb8000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -164,7 +164,7 @@
+ usart3: serial@fffd0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd0000 0x200>;
+- interrupts = <23 4>;
++ interrupts = <23 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -173,7 +173,7 @@
+ usart4: serial@fffd4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd4000 0x200>;
+- interrupts = <24 4>;
++ interrupts = <24 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -182,7 +182,7 @@
+ usart5: serial@fffd8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd8000 0x200>;
+- interrupts = <25 4>;
++ interrupts = <25 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -191,14 +191,14 @@
+ macb0: ethernet@fffc4000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffc4000 0x100>;
+- interrupts = <21 4>;
++ interrupts = <21 4 3>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fffa4000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfffa4000 0x4000>;
+- interrupts = <10 4>;
++ interrupts = <10 4 2>;
+ status = "disabled";
+ };
+ };
+@@ -222,7 +222,7 @@
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x100000>;
+- interrupts = <20 4>;
++ interrupts = <20 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 78b2808..195019b 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -48,7 +48,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -69,13 +69,13 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@fff7c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfff7c000 0x100>;
+- interrupts = <19 4>;
++ interrupts = <19 4 0>;
+ };
+
+ rstc@fffffd00 {
+@@ -91,7 +91,7 @@
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -101,7 +101,7 @@
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -111,7 +111,7 @@
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -121,7 +121,7 @@
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -131,7 +131,7 @@
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -141,14 +141,14 @@
+ dbgu: serial@ffffee00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fff8c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff8c000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -157,7 +157,7 @@
+ usart1: serial@fff90000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff90000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -166,7 +166,7 @@
+ usart2: serial@fff94000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff94000 0x200>;
+- interrupts = <9 4>;
++ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -175,14 +175,14 @@
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffbc000 0x100>;
+- interrupts = <21 4>;
++ interrupts = <21 4 3>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fff78000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfff78000 0x4000>;
+- interrupts = <24 4>;
++ interrupts = <24 4 2>;
+ status = "disabled";
+ };
+ };
+@@ -206,7 +206,7 @@
+ usb0: ohci@00a00000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00a00000 0x100000>;
+- interrupts = <29 4>;
++ interrupts = <29 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 779ffca..6a3ed54 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -53,7 +53,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -79,7 +79,7 @@
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+
+@@ -91,25 +91,25 @@
+ tcb0: timer@fff7c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfff7c000 0x100>;
+- interrupts = <18 4>;
++ interrupts = <18 4 0>;
+ };
+
+ tcb1: timer@fffd4000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffd4000 0x100>;
+- interrupts = <18 4>;
++ interrupts = <18 4 0>;
+ };
+
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 0>;
+ };
+
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -119,7 +119,7 @@
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -129,7 +129,7 @@
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <4 4>;
++ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -139,7 +139,7 @@
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <5 4>;
++ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -149,7 +149,7 @@
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <5 4>;
++ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -159,14 +159,14 @@
+ dbgu: serial@ffffee00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@fff8c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff8c000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -175,7 +175,7 @@
+ usart1: serial@fff90000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff90000 0x200>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -184,7 +184,7 @@
+ usart2: serial@fff94000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff94000 0x200>;
+- interrupts = <9 4>;
++ interrupts = <9 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -193,7 +193,7 @@
+ usart3: serial@fff98000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff98000 0x200>;
+- interrupts = <10 4>;
++ interrupts = <10 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -202,7 +202,7 @@
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffbc000 0x100>;
+- interrupts = <25 4>;
++ interrupts = <25 4 3>;
+ status = "disabled";
+ };
+ };
+@@ -226,14 +226,14 @@
+ usb0: ohci@00700000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00700000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+
+ usb1: ehci@00800000 {
+ compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+ reg = <0x00800000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index a69e89a..ef9336a 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -50,7 +50,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -74,7 +74,7 @@
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ shdwc@fffffe10 {
+@@ -85,25 +85,25 @@
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <20 4>;
++ interrupts = <20 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -113,7 +113,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -123,7 +123,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -133,7 +133,7 @@
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -143,14 +143,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x4000>;
+- interrupts = <5 4>;
++ interrupts = <5 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -159,7 +159,7 @@
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x4000>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -168,7 +168,7 @@
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x4000>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -177,7 +177,7 @@
+ usart3: serial@f8028000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8028000 0x4000>;
+- interrupts = <8 4>;
++ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -205,7 +205,7 @@
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x00100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 170b6f8..fc38d21 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -51,7 +51,7 @@
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+- #interrupt-cells = <2>;
++ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+@@ -81,37 +81,37 @@
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+- interrupts = <17 4>;
++ interrupts = <17 4 0>;
+ };
+
+ dma0: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+- interrupts = <20 4>;
++ interrupts = <20 4 0>;
+ };
+
+ dma1: dma-controller@ffffee00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffee00 0x200>;
+- interrupts = <21 4>;
++ interrupts = <21 4 0>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -121,7 +121,7 @@
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+- interrupts = <2 4>;
++ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -131,7 +131,7 @@
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -141,7 +141,7 @@
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+- interrupts = <3 4>;
++ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+@@ -151,14 +151,14 @@
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+- interrupts = <1 4>;
++ interrupts = <1 4 7>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x200>;
+- interrupts = <5 4>;
++ interrupts = <5 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -167,7 +167,7 @@
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x200>;
+- interrupts = <6 4>;
++ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -176,7 +176,7 @@
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x200>;
+- interrupts = <7 4>;
++ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+@@ -185,14 +185,14 @@
+ macb0: ethernet@f802c000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf802c000 0x100>;
+- interrupts = <24 4>;
++ interrupts = <24 4 3>;
+ status = "disabled";
+ };
+
+ macb1: ethernet@f8030000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf8030000 0x100>;
+- interrupts = <27 4>;
++ interrupts = <27 4 3>;
+ status = "disabled";
+ };
+ };
+@@ -215,14 +215,14 @@
+ usb0: ohci@00600000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00600000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+
+ usb1: ehci@00700000 {
+ compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
+ reg = <0x00700000 0x100000>;
+- interrupts = <22 4>;
++ interrupts = <22 4 2>;
+ status = "disabled";
+ };
+ };
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index c1413ed..3af7272 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
+ .extern at91_aic_base
+ #endif
+
++#define AT91_AIC_IRQ_MIN_PRIORITY 0
++#define AT91_AIC_IRQ_MAX_PRIORITY 7
++
+ #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
+ #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
+ #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index df8605f..db8e141 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -30,6 +30,7 @@
+ #include <linux/of_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/err.h>
++#include <linux/slab.h>
+
+ #include <mach/hardware.h>
+ #include <asm/irq.h>
+@@ -42,6 +43,7 @@
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
++static unsigned int *at91_aic_irq_priorities;
+
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+@@ -177,8 +179,9 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ /* Put virq number in Source Vector Register */
+ at91_aic_write(AT91_AIC_SVR(hw), virq);
+
+- /* Active Low interrupt, without priority */
+- at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
++ /* Active Low interrupt, with priority */
++ at91_aic_write(AT91_AIC_SMR(hw),
++ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
+
+ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+@@ -186,9 +189,28 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ return 0;
+ }
+
++static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
++ const u32 *intspec, unsigned int intsize,
++ irq_hw_number_t *out_hwirq, unsigned int *out_type)
++{
++ if (WARN_ON(intsize < 3))
++ return -EINVAL;
++ if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
++ return -EINVAL;
++ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
++ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
++ return -EINVAL;
++
++ *out_hwirq = intspec[0];
++ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
++ at91_aic_irq_priorities[*out_hwirq] = intspec[2];
++
++ return 0;
++}
++
+ static struct irq_domain_ops at91_aic_irq_ops = {
+ .map = at91_aic_irq_map,
+- .xlate = irq_domain_xlate_twocell,
++ .xlate = at91_aic_irq_domain_xlate,
+ };
+
+ int __init at91_aic_of_init(struct device_node *node,
+@@ -198,6 +220,12 @@ int __init at91_aic_of_init(struct device_node *node,
+ const __be32 *p;
+ u32 val;
+
++ at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
++ * sizeof(*at91_aic_irq_priorities),
++ GFP_KERNEL);
++ if (!at91_aic_irq_priorities)
++ return -ENOMEM;
++
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 6591d7a4f331b00fa020ef27b367239854944459 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Mon, 9 Apr 2012 19:36:36 +0800
-Subject: ARM: at91: aic add dt support for external irqs
-
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- Documentation/devicetree/bindings/arm/atmel-aic.txt | 1 +
- arch/arm/boot/dts/at91sam9260.dtsi | 1 +
- arch/arm/boot/dts/at91sam9263.dtsi | 1 +
- arch/arm/boot/dts/at91sam9g45.dtsi | 1 +
- arch/arm/boot/dts/at91sam9x5.dtsi | 1 +
- arch/arm/mach-at91/at91sam9x5.c | 2 --
- arch/arm/mach-at91/irq.c | 12 ++++++++++++
- 7 files changed, 17 insertions(+), 2 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
-index aabca4f..1953b0c 100644
---- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
-+++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
-@@ -15,6 +15,7 @@ Required properties:
- Valid combinations are 1, 2, 3, 4, 8.
- Default flag for internal sources should be set to 4 (active high).
- - reg: Should contain AIC registers location and length
-+- atmel,external-irqs: u32 array of external irqs.
-
- Examples:
- /*
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index eddc467..fb86de0 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -56,6 +56,7 @@
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-+ atmel,external-irqs = <29 30 31>;
- };
-
- ramc0: ramc@ffffea00 {
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index d330de9..78b2808 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -52,6 +52,7 @@
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-+ atmel,external-irqs = <30 31>;
- };
-
- pmc: pmc@fffffc00 {
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index d1c497d..779ffca 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -57,6 +57,7 @@
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-+ atmel,external-irqs = <31>;
- };
-
- ramc0: ramc@ffffe400 {
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 80a50864..170b6f8 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -55,6 +55,7 @@
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-+ atmel,external-irqs = <31>;
- };
-
- ramc0: ramc@ffffe800 {
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index 13c8cae..dce3ff3 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -306,8 +306,6 @@ static void __init at91sam9x5_map_io(void)
-
- void __init at91sam9x5_initialize(void)
- {
-- at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
--
- /* Register GPIO subsystem (using DT) */
- at91_gpio_init(NULL, 0);
- }
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index 2d5d4c8..df8605f 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -194,6 +194,10 @@ static struct irq_domain_ops at91_aic_irq_ops = {
- int __init at91_aic_of_init(struct device_node *node,
- struct device_node *parent)
- {
-+ struct property *prop;
-+ const __be32 *p;
-+ u32 val;
-+
- at91_aic_base = of_iomap(node, 0);
- at91_aic_np = node;
-
-@@ -202,6 +206,14 @@ int __init at91_aic_of_init(struct device_node *node,
- if (!at91_aic_domain)
- panic("Unable to add AIC irq domain (DT)\n");
-
-+ at91_extern_irq = 0;
-+ of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
-+ if (val > 31)
-+ pr_warn("AIC: external irq %d > 31 skip it\n", val);
-+ else
-+ at91_extern_irq |= (1 << val);
-+ }
-+
- irq_set_default_host(at91_aic_domain);
-
- at91_aic_hw_init(NR_AIC_IRQS);
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 2e9f08703ba386c61ee33e8a7018ef12c361b463 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 20 Jun 2012 16:13:30 +0200
-Subject: ARM: at91: add of irq priorities support
-
-Add a third cell to define irq priority.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Reviewed-by: Rob Herring <rob.herring@calxeda.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9260.dtsi
- arch/arm/boot/dts/at91sam9g45.dtsi
- arch/arm/boot/dts/at91sam9x5.dtsi
----
- .../devicetree/bindings/arm/atmel-aic.txt | 8 +++--
- arch/arm/boot/dts/at91sam9260.dtsi | 34 ++++++++++----------
- arch/arm/boot/dts/at91sam9263.dtsi | 30 +++++++++---------
- arch/arm/boot/dts/at91sam9g45.dtsi | 36 +++++++++++-----------
- arch/arm/boot/dts/at91sam9n12.dtsi | 30 +++++++++---------
- arch/arm/boot/dts/at91sam9x5.dtsi | 36 +++++++++++-----------
- arch/arm/mach-at91/include/mach/at91_aic.h | 3 ++
- arch/arm/mach-at91/irq.c | 34 ++++++++++++++++++--
- 8 files changed, 122 insertions(+), 89 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/arm/atmel-aic.txt b/Documentation/devicetree/bindings/arm/atmel-aic.txt
-index 1953b0c..19078bf 100644
---- a/Documentation/devicetree/bindings/arm/atmel-aic.txt
-+++ b/Documentation/devicetree/bindings/arm/atmel-aic.txt
-@@ -4,7 +4,7 @@ Required properties:
- - compatible: Should be "atmel,<chip>-aic"
- - interrupt-controller: Identifies the node as an interrupt controller.
- - interrupt-parent: For single AIC system, it is an empty property.
--- #interrupt-cells: The number of cells to define the interrupts. It sould be 2.
-+- #interrupt-cells: The number of cells to define the interrupts. It sould be 3.
- The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet).
- The second cell is used to specify flags:
- bits[3:0] trigger type and level flags:
-@@ -14,6 +14,8 @@ Required properties:
- 8 = active low level-sensitive.
- Valid combinations are 1, 2, 3, 4, 8.
- Default flag for internal sources should be set to 4 (active high).
-+ The third cell is used to specify the irq priority from 0 (lowest) to 7
-+ (highest).
- - reg: Should contain AIC registers location and length
- - atmel,external-irqs: u32 array of external irqs.
-
-@@ -25,7 +27,7 @@ Examples:
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- interrupt-parent;
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- reg = <0xfffff000 0x200>;
- };
-
-@@ -35,5 +37,5 @@ Examples:
- dma: dma-controller@ffffec00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
-- interrupts = <21 4>;
-+ interrupts = <21 4 5>;
- };
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index fb86de0..12df8ca 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -52,7 +52,7 @@
- ranges;
-
- aic: interrupt-controller@fffff000 {
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-@@ -82,25 +82,25 @@
- pit: timer@fffffd30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffd30 0xf>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- };
-
- tcb0: timer@fffa0000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfffa0000 0x100>;
-- interrupts = <17 4 18 4 19 4>;
-+ interrupts = <17 4 0 18 4 0 19 4 0>;
- };
-
- tcb1: timer@fffdc000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfffdc000 0x100>;
-- interrupts = <26 4 27 4 28 4>;
-+ interrupts = <26 4 0 27 4 0 28 4 0>;
- };
-
- pioA: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -110,7 +110,7 @@
- pioB: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -120,7 +120,7 @@
- pioC: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
-- interrupts = <4 4>;
-+ interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -130,14 +130,14 @@
- dbgu: serial@fffff200 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffff200 0x200>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- status = "disabled";
- };
-
- usart0: serial@fffb0000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb0000 0x200>;
-- interrupts = <6 4>;
-+ interrupts = <6 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -146,7 +146,7 @@
- usart1: serial@fffb4000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb4000 0x200>;
-- interrupts = <7 4>;
-+ interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -155,7 +155,7 @@
- usart2: serial@fffb8000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb8000 0x200>;
-- interrupts = <8 4>;
-+ interrupts = <8 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -164,7 +164,7 @@
- usart3: serial@fffd0000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd0000 0x200>;
-- interrupts = <23 4>;
-+ interrupts = <23 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -173,7 +173,7 @@
- usart4: serial@fffd4000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd4000 0x200>;
-- interrupts = <24 4>;
-+ interrupts = <24 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -182,7 +182,7 @@
- usart5: serial@fffd8000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd8000 0x200>;
-- interrupts = <25 4>;
-+ interrupts = <25 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -191,14 +191,14 @@
- macb0: ethernet@fffc4000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xfffc4000 0x100>;
-- interrupts = <21 4>;
-+ interrupts = <21 4 3>;
- status = "disabled";
- };
-
- usb1: gadget@fffa4000 {
- compatible = "atmel,at91rm9200-udc";
- reg = <0xfffa4000 0x4000>;
-- interrupts = <10 4>;
-+ interrupts = <10 4 2>;
- status = "disabled";
- };
- };
-@@ -222,7 +222,7 @@
- usb0: ohci@00500000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00500000 0x100000>;
-- interrupts = <20 4>;
-+ interrupts = <20 4 2>;
- status = "disabled";
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 78b2808..195019b 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -48,7 +48,7 @@
- ranges;
-
- aic: interrupt-controller@fffff000 {
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-@@ -69,13 +69,13 @@
- pit: timer@fffffd30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffd30 0xf>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- };
-
- tcb0: timer@fff7c000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfff7c000 0x100>;
-- interrupts = <19 4>;
-+ interrupts = <19 4 0>;
- };
-
- rstc@fffffd00 {
-@@ -91,7 +91,7 @@
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -101,7 +101,7 @@
- pioB: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -111,7 +111,7 @@
- pioC: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
-- interrupts = <4 4>;
-+ interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -121,7 +121,7 @@
- pioD: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
-- interrupts = <4 4>;
-+ interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -131,7 +131,7 @@
- pioE: gpio@fffffa00 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
-- interrupts = <4 4>;
-+ interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -141,14 +141,14 @@
- dbgu: serial@ffffee00 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xffffee00 0x200>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- status = "disabled";
- };
-
- usart0: serial@fff8c000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff8c000 0x200>;
-- interrupts = <7 4>;
-+ interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -157,7 +157,7 @@
- usart1: serial@fff90000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff90000 0x200>;
-- interrupts = <8 4>;
-+ interrupts = <8 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -166,7 +166,7 @@
- usart2: serial@fff94000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff94000 0x200>;
-- interrupts = <9 4>;
-+ interrupts = <9 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -175,14 +175,14 @@
- macb0: ethernet@fffbc000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xfffbc000 0x100>;
-- interrupts = <21 4>;
-+ interrupts = <21 4 3>;
- status = "disabled";
- };
-
- usb1: gadget@fff78000 {
- compatible = "atmel,at91rm9200-udc";
- reg = <0xfff78000 0x4000>;
-- interrupts = <24 4>;
-+ interrupts = <24 4 2>;
- status = "disabled";
- };
- };
-@@ -206,7 +206,7 @@
- usb0: ohci@00a00000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00a00000 0x100000>;
-- interrupts = <29 4>;
-+ interrupts = <29 4 2>;
- status = "disabled";
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index 779ffca..6a3ed54 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -53,7 +53,7 @@
- ranges;
-
- aic: interrupt-controller@fffff000 {
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-@@ -79,7 +79,7 @@
- pit: timer@fffffd30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffd30 0xf>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- };
-
-
-@@ -91,25 +91,25 @@
- tcb0: timer@fff7c000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfff7c000 0x100>;
-- interrupts = <18 4>;
-+ interrupts = <18 4 0>;
- };
-
- tcb1: timer@fffd4000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfffd4000 0x100>;
-- interrupts = <18 4>;
-+ interrupts = <18 4 0>;
- };
-
- dma: dma-controller@ffffec00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
-- interrupts = <21 4>;
-+ interrupts = <21 4 0>;
- };
-
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -119,7 +119,7 @@
- pioB: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -129,7 +129,7 @@
- pioC: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
-- interrupts = <4 4>;
-+ interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -139,7 +139,7 @@
- pioD: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
-- interrupts = <5 4>;
-+ interrupts = <5 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -149,7 +149,7 @@
- pioE: gpio@fffffa00 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
-- interrupts = <5 4>;
-+ interrupts = <5 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -159,14 +159,14 @@
- dbgu: serial@ffffee00 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xffffee00 0x200>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- status = "disabled";
- };
-
- usart0: serial@fff8c000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff8c000 0x200>;
-- interrupts = <7 4>;
-+ interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -175,7 +175,7 @@
- usart1: serial@fff90000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff90000 0x200>;
-- interrupts = <8 4>;
-+ interrupts = <8 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -184,7 +184,7 @@
- usart2: serial@fff94000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff94000 0x200>;
-- interrupts = <9 4>;
-+ interrupts = <9 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -193,7 +193,7 @@
- usart3: serial@fff98000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfff98000 0x200>;
-- interrupts = <10 4>;
-+ interrupts = <10 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -202,7 +202,7 @@
- macb0: ethernet@fffbc000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xfffbc000 0x100>;
-- interrupts = <25 4>;
-+ interrupts = <25 4 3>;
- status = "disabled";
- };
- };
-@@ -226,14 +226,14 @@
- usb0: ohci@00700000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00700000 0x100000>;
-- interrupts = <22 4>;
-+ interrupts = <22 4 2>;
- status = "disabled";
- };
-
- usb1: ehci@00800000 {
- compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
- reg = <0x00800000 0x100000>;
-- interrupts = <22 4>;
-+ interrupts = <22 4 2>;
- status = "disabled";
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index a69e89a..ef9336a 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -50,7 +50,7 @@
- ranges;
-
- aic: interrupt-controller@fffff000 {
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-@@ -74,7 +74,7 @@
- pit: timer@fffffe30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffe30 0xf>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- };
-
- shdwc@fffffe10 {
-@@ -85,25 +85,25 @@
- tcb0: timer@f8008000 {
- compatible = "atmel,at91sam9x5-tcb";
- reg = <0xf8008000 0x100>;
-- interrupts = <17 4>;
-+ interrupts = <17 4 0>;
- };
-
- tcb1: timer@f800c000 {
- compatible = "atmel,at91sam9x5-tcb";
- reg = <0xf800c000 0x100>;
-- interrupts = <17 4>;
-+ interrupts = <17 4 0>;
- };
-
- dma: dma-controller@ffffec00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
-- interrupts = <20 4>;
-+ interrupts = <20 4 0>;
- };
-
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -113,7 +113,7 @@
- pioB: gpio@fffff600 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -123,7 +123,7 @@
- pioC: gpio@fffff800 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -133,7 +133,7 @@
- pioD: gpio@fffffa00 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -143,14 +143,14 @@
- dbgu: serial@fffff200 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffff200 0x200>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- status = "disabled";
- };
-
- usart0: serial@f801c000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf801c000 0x4000>;
-- interrupts = <5 4>;
-+ interrupts = <5 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -159,7 +159,7 @@
- usart1: serial@f8020000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf8020000 0x4000>;
-- interrupts = <6 4>;
-+ interrupts = <6 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -168,7 +168,7 @@
- usart2: serial@f8024000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf8024000 0x4000>;
-- interrupts = <7 4>;
-+ interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -177,7 +177,7 @@
- usart3: serial@f8028000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf8028000 0x4000>;
-- interrupts = <8 4>;
-+ interrupts = <8 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -205,7 +205,7 @@
- usb0: ohci@00500000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00500000 0x00100000>;
-- interrupts = <22 4>;
-+ interrupts = <22 4 2>;
- status = "disabled";
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 170b6f8..fc38d21 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -51,7 +51,7 @@
- ranges;
-
- aic: interrupt-controller@fffff000 {
-- #interrupt-cells = <2>;
-+ #interrupt-cells = <3>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
-@@ -81,37 +81,37 @@
- pit: timer@fffffe30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffe30 0xf>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- };
-
- tcb0: timer@f8008000 {
- compatible = "atmel,at91sam9x5-tcb";
- reg = <0xf8008000 0x100>;
-- interrupts = <17 4>;
-+ interrupts = <17 4 0>;
- };
-
- tcb1: timer@f800c000 {
- compatible = "atmel,at91sam9x5-tcb";
- reg = <0xf800c000 0x100>;
-- interrupts = <17 4>;
-+ interrupts = <17 4 0>;
- };
-
- dma0: dma-controller@ffffec00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
-- interrupts = <20 4>;
-+ interrupts = <20 4 0>;
- };
-
- dma1: dma-controller@ffffee00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffee00 0x200>;
-- interrupts = <21 4>;
-+ interrupts = <21 4 0>;
- };
-
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -121,7 +121,7 @@
- pioB: gpio@fffff600 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
-- interrupts = <2 4>;
-+ interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -131,7 +131,7 @@
- pioC: gpio@fffff800 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -141,7 +141,7 @@
- pioD: gpio@fffffa00 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
-- interrupts = <3 4>;
-+ interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
-@@ -151,14 +151,14 @@
- dbgu: serial@fffff200 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffff200 0x200>;
-- interrupts = <1 4>;
-+ interrupts = <1 4 7>;
- status = "disabled";
- };
-
- usart0: serial@f801c000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf801c000 0x200>;
-- interrupts = <5 4>;
-+ interrupts = <5 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -167,7 +167,7 @@
- usart1: serial@f8020000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf8020000 0x200>;
-- interrupts = <6 4>;
-+ interrupts = <6 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -176,7 +176,7 @@
- usart2: serial@f8024000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xf8024000 0x200>;
-- interrupts = <7 4>;
-+ interrupts = <7 4 5>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
-@@ -185,14 +185,14 @@
- macb0: ethernet@f802c000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xf802c000 0x100>;
-- interrupts = <24 4>;
-+ interrupts = <24 4 3>;
- status = "disabled";
- };
-
- macb1: ethernet@f8030000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xf8030000 0x100>;
-- interrupts = <27 4>;
-+ interrupts = <27 4 3>;
- status = "disabled";
- };
- };
-@@ -215,14 +215,14 @@
- usb0: ohci@00600000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00600000 0x100000>;
-- interrupts = <22 4>;
-+ interrupts = <22 4 2>;
- status = "disabled";
- };
-
- usb1: ehci@00700000 {
- compatible = "atmel,at91sam9g45-ehci", "usb-ehci";
- reg = <0x00700000 0x100000>;
-- interrupts = <22 4>;
-+ interrupts = <22 4 2>;
- status = "disabled";
- };
- };
-diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
-index c1413ed..3af7272 100644
---- a/arch/arm/mach-at91/include/mach/at91_aic.h
-+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
-@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
- .extern at91_aic_base
- #endif
-
-+#define AT91_AIC_IRQ_MIN_PRIORITY 0
-+#define AT91_AIC_IRQ_MAX_PRIORITY 7
-+
- #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
- #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
- #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index df8605f..db8e141 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -30,6 +30,7 @@
- #include <linux/of_irq.h>
- #include <linux/irqdomain.h>
- #include <linux/err.h>
-+#include <linux/slab.h>
-
- #include <mach/hardware.h>
- #include <asm/irq.h>
-@@ -42,6 +43,7 @@
- void __iomem *at91_aic_base;
- static struct irq_domain *at91_aic_domain;
- static struct device_node *at91_aic_np;
-+static unsigned int *at91_aic_irq_priorities;
-
- static void at91_aic_mask_irq(struct irq_data *d)
- {
-@@ -177,8 +179,9 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- /* Put virq number in Source Vector Register */
- at91_aic_write(AT91_AIC_SVR(hw), virq);
-
-- /* Active Low interrupt, without priority */
-- at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW);
-+ /* Active Low interrupt, with priority */
-+ at91_aic_write(AT91_AIC_SMR(hw),
-+ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
-
- irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
-@@ -186,9 +189,28 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- return 0;
- }
-
-+static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
-+ const u32 *intspec, unsigned int intsize,
-+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
-+{
-+ if (WARN_ON(intsize < 3))
-+ return -EINVAL;
-+ if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
-+ return -EINVAL;
-+ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
-+ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
-+ return -EINVAL;
-+
-+ *out_hwirq = intspec[0];
-+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
-+ at91_aic_irq_priorities[*out_hwirq] = intspec[2];
-+
-+ return 0;
-+}
-+
- static struct irq_domain_ops at91_aic_irq_ops = {
- .map = at91_aic_irq_map,
-- .xlate = irq_domain_xlate_twocell,
-+ .xlate = at91_aic_irq_domain_xlate,
- };
-
- int __init at91_aic_of_init(struct device_node *node,
-@@ -198,6 +220,12 @@ int __init at91_aic_of_init(struct device_node *node,
- const __be32 *p;
- u32 val;
-
-+ at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
-+ * sizeof(*at91_aic_irq_priorities),
-+ GFP_KERNEL);
-+ if (!at91_aic_irq_priorities)
-+ return -ENOMEM;
-+
- at91_aic_base = of_iomap(node, 0);
- at91_aic_np = node;
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 3513672c75cce07bc51cc8e433b18c238490e05f Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 22 Jun 2012 11:41:34 +0200
+Subject: ARM: at91: remove static irq priorities for sam9x5
+
+commit 3a6b37134c71be1b085be7fe5234f364dc68e2de upstream.
+
+Since irq priorites are managed in DT, static ones are no more required for
+sam9x5 which only has DT support.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5.c | 38 --------------------------------------
+ 1 file changed, 38 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index dce3ff3..c949dc7 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -313,47 +313,9 @@ void __init at91sam9x5_initialize(void)
+ /* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+-/*
+- * The default interrupt priority levels (0 = lowest, 7 = highest).
+- */
+-static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
+- 7, /* Advanced Interrupt Controller (FIQ) */
+- 7, /* System Peripherals */
+- 1, /* Parallel IO Controller A and B */
+- 1, /* Parallel IO Controller C and D */
+- 4, /* Soft Modem */
+- 5, /* USART 0 */
+- 5, /* USART 1 */
+- 5, /* USART 2 */
+- 5, /* USART 3 */
+- 6, /* Two-Wire Interface 0 */
+- 6, /* Two-Wire Interface 1 */
+- 6, /* Two-Wire Interface 2 */
+- 0, /* Multimedia Card Interface 0 */
+- 5, /* Serial Peripheral Interface 0 */
+- 5, /* Serial Peripheral Interface 1 */
+- 5, /* UART 0 */
+- 5, /* UART 1 */
+- 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+- 0, /* Pulse Width Modulation Controller */
+- 0, /* ADC Controller */
+- 0, /* DMA Controller 0 */
+- 0, /* DMA Controller 1 */
+- 2, /* USB Host High Speed port */
+- 2, /* USB Device High speed port */
+- 3, /* Ethernet MAC 0 */
+- 3, /* LDC Controller or Image Sensor Interface */
+- 0, /* Multimedia Card Interface 1 */
+- 3, /* Ethernet MAC 1 */
+- 4, /* Synchronous Serial Interface */
+- 4, /* CAN Controller 0 */
+- 4, /* CAN Controller 1 */
+- 0, /* Advanced Interrupt Controller (IRQ0) */
+-};
+
+ struct at91_init_soc __initdata at91sam9x5_soc = {
+ .map_io = at91sam9x5_map_io,
+- .default_irq_priority = at91sam9x5_default_irq_priority,
+ .register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
+ };
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 567e7d20c108ffb8974c7294ec0263da01ce419d Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 11 Jun 2012 15:38:03 +0200
+Subject: ARM: at91: at91 based machines specify their own irq handler at run
+ time
+
+commit 3e135466745a62b1814edef74c7b4a25e6bda707 upstream.
+
+SOC_AT91SAM9 selects MULTI_IRQ_HANDLER in order to let machines specify their
+own IRQ handler at run time.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 1 +
+ arch/arm/mach-at91/board-1arm.c | 2 ++
+ arch/arm/mach-at91/board-afeb-9260v1.c | 2 ++
+ arch/arm/mach-at91/board-cam60.c | 2 ++
+ arch/arm/mach-at91/board-carmeva.c | 2 ++
+ arch/arm/mach-at91/board-cpu9krea.c | 2 ++
+ arch/arm/mach-at91/board-cpuat91.c | 2 ++
+ arch/arm/mach-at91/board-csb337.c | 2 ++
+ arch/arm/mach-at91/board-csb637.c | 2 ++
+ arch/arm/mach-at91/board-dt.c | 2 ++
+ arch/arm/mach-at91/board-eb01.c | 2 ++
+ arch/arm/mach-at91/board-eb9200.c | 2 ++
+ arch/arm/mach-at91/board-ecbat91.c | 2 ++
+ arch/arm/mach-at91/board-eco920.c | 2 ++
+ arch/arm/mach-at91/board-flexibity.c | 2 ++
+ arch/arm/mach-at91/board-foxg20.c | 2 ++
+ arch/arm/mach-at91/board-gsia18s.c | 2 ++
+ arch/arm/mach-at91/board-kafa.c | 2 ++
+ arch/arm/mach-at91/board-kb9202.c | 2 ++
+ arch/arm/mach-at91/board-neocore926.c | 2 ++
+ arch/arm/mach-at91/board-pcontrol-g20.c | 2 ++
+ arch/arm/mach-at91/board-picotux200.c | 2 ++
+ arch/arm/mach-at91/board-qil-a9260.c | 2 ++
+ arch/arm/mach-at91/board-rm9200dk.c | 2 ++
+ arch/arm/mach-at91/board-rm9200ek.c | 2 ++
+ arch/arm/mach-at91/board-rsi-ews.c | 2 ++
+ arch/arm/mach-at91/board-sam9-l9260.c | 2 ++
+ arch/arm/mach-at91/board-sam9260ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9261ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9263ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9g20ek.c | 3 +++
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 2 ++
+ arch/arm/mach-at91/board-sam9rlek.c | 2 ++
+ arch/arm/mach-at91/board-snapper9260.c | 2 ++
+ arch/arm/mach-at91/board-stamp9g20.c | 3 +++
+ arch/arm/mach-at91/board-usb-a926x.c | 4 ++++
+ arch/arm/mach-at91/board-yl-9200.c | 2 ++
+ arch/arm/mach-at91/include/mach/at91_aic.h | 2 ++
+ arch/arm/mach-at91/include/mach/entry-macro.S | 27 ---------------------------
+ arch/arm/mach-at91/irq.c | 19 +++++++++++++++++++
+ 40 files changed, 98 insertions(+), 27 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/entry-macro.S
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 19505c0..e401dea 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -29,6 +29,7 @@ comment "Atmel AT91 Processor"
+ config SOC_AT91SAM9
+ bool
+ select CPU_ARM926T
++ select MULTI_IRQ_HANDLER
+ select AT91_SAM9_TIME
+ select AT91_SAM9_SMC
+
+diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
+index 271f994..22d8856 100644
+--- a/arch/arm/mach-at91/board-1arm.c
++++ b/arch/arm/mach-at91/board-1arm.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -91,6 +92,7 @@ MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
+ /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = onearm_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = onearm_board_init,
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index b7d8aa7..de7be19 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -44,6 +44,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -212,6 +213,7 @@ MACHINE_START(AFEB9260, "Custom afeb9260 board")
+ /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = afeb9260_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = afeb9260_board_init,
+diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
+index 29d3ef0..477e708 100644
+--- a/arch/arm/mach-at91/board-cam60.c
++++ b/arch/arm/mach-at91/board-cam60.c
+@@ -39,6 +39,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -188,6 +189,7 @@ MACHINE_START(CAM60, "KwikByte CAM60")
+ /* Maintainer: KwikByte */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cam60_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cam60_board_init,
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index 44328a6..a5b002f 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -158,6 +159,7 @@ MACHINE_START(CARMEVA, "Carmeva")
+ /* Maintainer: Conitec Datasystems */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = carmeva_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = carmeva_board_init,
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index ece0d76..7ddc219 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -41,6 +41,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91sam9260_matrix.h>
+ #include <mach/at91_matrix.h>
+@@ -375,6 +376,7 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cpu9krea_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cpu9krea_board_init,
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index 895cf2d..2e6d043 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -37,6 +37,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -178,6 +179,7 @@ MACHINE_START(CPUAT91, "Eukrea")
+ /* Maintainer: Eric Benard - EUKREA Electromatique */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = cpuat91_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = cpuat91_board_init,
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index cd81336..462bc31 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -39,6 +39,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -252,6 +253,7 @@ MACHINE_START(CSB337, "Cogent CSB337")
+ /* Maintainer: Bill Gatliff */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = csb337_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = csb337_board_init,
+diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
+index 7c8b05a..872871a 100644
+--- a/arch/arm/mach-at91/board-csb637.c
++++ b/arch/arm/mach-at91/board-csb637.c
+@@ -36,6 +36,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -133,6 +134,7 @@ MACHINE_START(CSB637, "Cogent CSB637")
+ /* Maintainer: Bill Gatliff */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = csb637_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = csb637_board_init,
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index a1fce05..e8f45c4 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -16,6 +16,7 @@
+ #include <linux/of_platform.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include <asm/setup.h>
+ #include <asm/irq.h>
+@@ -53,6 +54,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91_dt_initialize,
+ .init_irq = at91_dt_init_irq,
+ .init_machine = at91_dt_device_init,
+diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c
+index d2023f2..01f66e9 100644
+--- a/arch/arm/mach-at91/board-eb01.c
++++ b/arch/arm/mach-at91/board-eb01.c
+@@ -28,6 +28,7 @@
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include "generic.h"
+
+ static void __init at91eb01_init_irq(void)
+@@ -43,6 +44,7 @@ static void __init at91eb01_init_early(void)
+ MACHINE_START(AT91EB01, "Atmel AT91 EB01")
+ /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
+ .timer = &at91x40_timer,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91eb01_init_early,
+ .init_irq = at91eb01_init_irq,
+ MACHINE_END
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index bd10172..d1e1f3f 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -36,6 +36,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -118,6 +119,7 @@ static void __init eb9200_board_init(void)
+ MACHINE_START(ATEB9200, "Embest ATEB9200")
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = eb9200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = eb9200_board_init,
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 89cc372..9c24cb2 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -39,6 +39,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -170,6 +171,7 @@ MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
+ /* Maintainer: emQbit.com */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ecb_at91init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ecb_at91board_init,
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index 558546c..82bdfde 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -25,6 +25,7 @@
+ #include <asm/mach/map.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -132,6 +133,7 @@ MACHINE_START(ECO920, "eco920")
+ /* Maintainer: Sascha Hauer */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = eco920_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = eco920_board_init,
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 47658f7..6cc83a8 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -34,6 +34,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include "generic.h"
+
+@@ -160,6 +161,7 @@ MACHINE_START(FLEXIBITY, "Flexibity Connect")
+ /* Maintainer: Maxim Osipov */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = flexibity_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = flexibity_board_init,
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index 33411e6..69ab124 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -42,6 +42,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -262,6 +263,7 @@ MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
+ /* Maintainer: Sergio Tanzilli */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = foxg20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = foxg20_board_init,
+diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
+index 3e0dfa6..a9d5e78 100644
+--- a/arch/arm/mach-at91/board-gsia18s.c
++++ b/arch/arm/mach-at91/board-gsia18s.c
+@@ -31,6 +31,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/gsia18s.h>
+ #include <mach/stamp9g20.h>
+@@ -575,6 +576,7 @@ static void __init gsia18s_board_init(void)
+ MACHINE_START(GSIA18S, "GS_IA18_S")
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = gsia18s_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = gsia18s_board_init,
+diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
+index f260657..64c1dbf 100644
+--- a/arch/arm/mach-at91/board-kafa.c
++++ b/arch/arm/mach-at91/board-kafa.c
+@@ -35,6 +35,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/cpu.h>
+
+ #include "generic.h"
+@@ -93,6 +94,7 @@ MACHINE_START(KAFA, "Sperry-Sun KAFA")
+ /* Maintainer: Sergei Sharonov */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = kafa_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = kafa_board_init,
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index ba39db5..5d96cb8 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -37,6 +37,7 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -133,6 +134,7 @@ MACHINE_START(KB9200, "KB920x")
+ /* Maintainer: KwikByte, Inc. */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = kb9202_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = kb9202_board_init,
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index d2f4cc1..18103c5d 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -45,6 +45,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -378,6 +379,7 @@ MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
+ /* Maintainer: ADENEO */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = neocore926_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = neocore926_board_init,
+diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
+index 7fe6383..9ca3e32 100644
+--- a/arch/arm/mach-at91/board-pcontrol-g20.c
++++ b/arch/arm/mach-at91/board-pcontrol-g20.c
+@@ -30,6 +30,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/stamp9g20.h>
+
+@@ -218,6 +219,7 @@ MACHINE_START(PCONTROL_G20, "PControl G20")
+ /* Maintainer: pgsellmann@portner-elektronik.at */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = pcontrol_g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = pcontrol_g20_board_init,
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index b45c0a5..1270655 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -38,6 +38,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -120,6 +121,7 @@ MACHINE_START(PICOTUX2XX, "picotux 200")
+ /* Maintainer: Kleinhenz Elektronik GmbH */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = picotux200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = picotux200_board_init,
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index 0c61bf0..bf351e2 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -41,6 +41,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -258,6 +259,7 @@ MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index afd7a47..cc2bf97 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -40,6 +40,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -223,6 +224,7 @@ MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
+ /* Maintainer: SAN People/Atmel */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = dk_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = dk_board_init,
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index 2b15b8a..62e19e6 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -40,6 +40,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+
+@@ -190,6 +191,7 @@ MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
+ /* Maintainer: SAN People/Atmel */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index 24ab9be..c3b43ae 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -26,6 +26,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+
+ #include <linux/gpio.h>
+
+@@ -225,6 +226,7 @@ MACHINE_START(RSI_EWS, "RSI EWS")
+ /* Maintainer: Josef Holzmayr <holzmayr@rsi-elektrotechnik.de> */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = rsi_ews_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = rsi_ews_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index cdd21f2..7bf6da7 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -38,6 +38,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -202,6 +203,7 @@ MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
+ /* Maintainer: Olimex */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index 7b3c391..889c1bf 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -42,6 +42,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -344,6 +345,7 @@ MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 2736453..2269be5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -46,6 +46,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -615,6 +616,7 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 983cb98..82adf58 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -45,6 +45,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -443,6 +444,7 @@ MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index 3d61553..da6d019 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -42,6 +42,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/system_rev.h>
+
+@@ -399,6 +400,7 @@ MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -408,6 +410,7 @@ MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index 9a87f0b..d1882d5 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -41,6 +41,7 @@
+ #include <asm/mach/irq.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+@@ -491,6 +492,7 @@ MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index be3239f..e7dc3ea 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -31,6 +31,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -319,6 +320,7 @@ MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
+ /* Maintainer: Atmel */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
+index 9d446f1..a4e031a 100644
+--- a/arch/arm/mach-at91/board-snapper9260.c
++++ b/arch/arm/mach-at91/board-snapper9260.c
+@@ -33,6 +33,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -178,6 +179,7 @@ static void __init snapper9260_board_init(void)
+ MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = snapper9260_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = snapper9260_board_init,
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index ee86f9d..29eae16 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -26,6 +26,7 @@
+ #include <asm/mach/arch.h>
+
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+@@ -287,6 +288,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = portuxg20_board_init,
+@@ -296,6 +298,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
+ /* Maintainer: taskit GmbH */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = stamp9g20_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = stamp9g20evb_board_init,
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index 95393fc..c1476b9 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -42,6 +42,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+@@ -358,6 +359,7 @@ MACHINE_START(USB_A9263, "CALAO USB_A9263")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -367,6 +369,7 @@ MACHINE_START(USB_A9260, "CALAO USB_A9260")
+ /* Maintainer: calao-systems */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+@@ -376,6 +379,7 @@ MACHINE_START(USB_A9G20, "CALAO USB_A92G0")
+ /* Maintainer: Jean-Christophe PLAGNIOL-VILLARD */
+ .timer = &at91sam926x_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = ek_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = ek_board_init,
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index d56665e..516d340 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -44,6 +44,7 @@
+
+ #include <mach/hardware.h>
+ #include <mach/board.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91rm9200_mc.h>
+ #include <mach/at91_ramc.h>
+ #include <mach/cpu.h>
+@@ -590,6 +591,7 @@ MACHINE_START(YL9200, "uCdragon YL-9200")
+ /* Maintainer: S.Birtles */
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
++ .handle_irq = at91_aic_handle_irq,
+ .init_early = yl9200_init_early,
+ .init_irq = at91_init_irq_default,
+ .init_machine = yl9200_board_init,
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index 3af7272..7867378 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -65,4 +65,6 @@ extern void __iomem *at91_aic_base;
+ #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
+ #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
+
++void at91_aic_handle_irq(struct pt_regs *regs);
++
+ #endif
+diff --git a/arch/arm/mach-at91/include/mach/entry-macro.S b/arch/arm/mach-at91/include/mach/entry-macro.S
+deleted file mode 100644
+index 903bf20..0000000
+--- a/arch/arm/mach-at91/include/mach/entry-macro.S
++++ /dev/null
+@@ -1,27 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/entry-macro.S
+- *
+- * Copyright (C) 2003-2005 SAN People
+- *
+- * Low-level IRQ helper macros for AT91RM9200 platforms
+- *
+- * This file is licensed under the terms of the GNU General Public
+- * License version 2. This program is licensed "as is" without any
+- * warranty of any kind, whether express or implied.
+- */
+-
+-#include <mach/hardware.h>
+-#include <mach/at91_aic.h>
+-
+- .macro get_irqnr_preamble, base, tmp
+- ldr \base, =at91_aic_base @ base virtual address of AIC peripheral
+- ldr \base, [\base]
+- .endm
+-
+- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+- ldr \irqnr, [\base, #AT91_AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
+- ldr \irqstat, [\base, #AT91_AIC_ISR] @ read interrupt source number
+- teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt
+- streq \tmp, [\base, #AT91_AIC_EOICR] @ not going to be handled further, then ACK it now.
+- .endm
+-
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index db8e141..390d4df 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -36,6 +36,7 @@
+ #include <asm/irq.h>
+ #include <asm/setup.h>
+
++#include <asm/exception.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/irq.h>
+ #include <asm/mach/map.h>
+@@ -45,6 +46,24 @@ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+ static unsigned int *at91_aic_irq_priorities;
+
++asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
++{
++ u32 irqnr;
++ u32 irqstat;
++
++ irqnr = at91_aic_read(AT91_AIC_IVR);
++ irqstat = at91_aic_read(AT91_AIC_ISR);
++
++ /*
++ * ISR value is 0 when there is no current interrupt or when there is
++ * a spurious interrupt
++ */
++ if (!irqstat)
++ at91_aic_write(AT91_AIC_EOICR, 0);
++ else
++ handle_IRQ(irqnr, regs);
++}
++
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+ /* Disable interrupt on AIC */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 253f40569228efcd947997772f9e913aef4e8dec Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 22 Jun 2012 11:41:34 +0200
-Subject: ARM: at91: remove static irq priorities for sam9x5
-
-Since irq priorites are managed in DT, static ones are no more required for
-sam9x5 which only has DT support.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/at91sam9x5.c | 38 --------------------------------------
- 1 file changed, 38 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index dce3ff3..c949dc7 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -313,47 +313,9 @@ void __init at91sam9x5_initialize(void)
- /* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
--/*
-- * The default interrupt priority levels (0 = lowest, 7 = highest).
-- */
--static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
-- 7, /* Advanced Interrupt Controller (FIQ) */
-- 7, /* System Peripherals */
-- 1, /* Parallel IO Controller A and B */
-- 1, /* Parallel IO Controller C and D */
-- 4, /* Soft Modem */
-- 5, /* USART 0 */
-- 5, /* USART 1 */
-- 5, /* USART 2 */
-- 5, /* USART 3 */
-- 6, /* Two-Wire Interface 0 */
-- 6, /* Two-Wire Interface 1 */
-- 6, /* Two-Wire Interface 2 */
-- 0, /* Multimedia Card Interface 0 */
-- 5, /* Serial Peripheral Interface 0 */
-- 5, /* Serial Peripheral Interface 1 */
-- 5, /* UART 0 */
-- 5, /* UART 1 */
-- 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
-- 0, /* Pulse Width Modulation Controller */
-- 0, /* ADC Controller */
-- 0, /* DMA Controller 0 */
-- 0, /* DMA Controller 1 */
-- 2, /* USB Host High Speed port */
-- 2, /* USB Device High speed port */
-- 3, /* Ethernet MAC 0 */
-- 3, /* LDC Controller or Image Sensor Interface */
-- 0, /* Multimedia Card Interface 1 */
-- 3, /* Ethernet MAC 1 */
-- 4, /* Synchronous Serial Interface */
-- 4, /* CAN Controller 0 */
-- 4, /* CAN Controller 1 */
-- 0, /* Advanced Interrupt Controller (IRQ0) */
--};
-
- struct at91_init_soc __initdata at91sam9x5_soc = {
- .map_io = at91sam9x5_map_io,
-- .default_irq_priority = at91sam9x5_default_irq_priority,
- .register_clocks = at91sam9x5_register_clocks,
- .init = at91sam9x5_initialize,
- };
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 4d4e7847287b4ad784ac97768d4768bbbfabe8a1 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Mon, 11 Jun 2012 15:38:03 +0200
-Subject: ARM: at91: at91 based machines specify their own irq handler at run
- time
-
-SOC_AT91SAM9 selects MULTI_IRQ_HANDLER in order to let machines specify their
-own IRQ handler at run time.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/Kconfig | 1 +
- arch/arm/mach-at91/board-1arm.c | 2 ++
- arch/arm/mach-at91/board-afeb-9260v1.c | 2 ++
- arch/arm/mach-at91/board-cam60.c | 2 ++
- arch/arm/mach-at91/board-carmeva.c | 2 ++
- arch/arm/mach-at91/board-cpu9krea.c | 2 ++
- arch/arm/mach-at91/board-cpuat91.c | 2 ++
- arch/arm/mach-at91/board-csb337.c | 2 ++
- arch/arm/mach-at91/board-csb637.c | 2 ++
- arch/arm/mach-at91/board-dt.c | 2 ++
- arch/arm/mach-at91/board-eb01.c | 2 ++
- arch/arm/mach-at91/board-eb9200.c | 2 ++
- arch/arm/mach-at91/board-ecbat91.c | 2 ++
- arch/arm/mach-at91/board-eco920.c | 2 ++
- arch/arm/mach-at91/board-flexibity.c | 2 ++
- arch/arm/mach-at91/board-foxg20.c | 2 ++
- arch/arm/mach-at91/board-gsia18s.c | 2 ++
- arch/arm/mach-at91/board-kafa.c | 2 ++
- arch/arm/mach-at91/board-kb9202.c | 2 ++
- arch/arm/mach-at91/board-neocore926.c | 2 ++
- arch/arm/mach-at91/board-pcontrol-g20.c | 2 ++
- arch/arm/mach-at91/board-picotux200.c | 2 ++
- arch/arm/mach-at91/board-qil-a9260.c | 2 ++
- arch/arm/mach-at91/board-rm9200dk.c | 2 ++
- arch/arm/mach-at91/board-rm9200ek.c | 2 ++
- arch/arm/mach-at91/board-rsi-ews.c | 2 ++
- arch/arm/mach-at91/board-sam9-l9260.c | 2 ++
- arch/arm/mach-at91/board-sam9260ek.c | 2 ++
- arch/arm/mach-at91/board-sam9261ek.c | 2 ++
- arch/arm/mach-at91/board-sam9263ek.c | 2 ++
- arch/arm/mach-at91/board-sam9g20ek.c | 3 +++
- arch/arm/mach-at91/board-sam9m10g45ek.c | 2 ++
- arch/arm/mach-at91/board-sam9rlek.c | 2 ++
- arch/arm/mach-at91/board-snapper9260.c | 2 ++
- arch/arm/mach-at91/board-stamp9g20.c | 3 +++
- arch/arm/mach-at91/board-usb-a926x.c | 4 ++++
- arch/arm/mach-at91/board-yl-9200.c | 2 ++
- arch/arm/mach-at91/include/mach/at91_aic.h | 2 ++
- arch/arm/mach-at91/include/mach/entry-macro.S | 27 ---------------------------
- arch/arm/mach-at91/irq.c | 19 +++++++++++++++++++
- 40 files changed, 98 insertions(+), 27 deletions(-)
- delete mode 100644 arch/arm/mach-at91/include/mach/entry-macro.S
-
-diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
-index 19505c0..e401dea 100644
---- a/arch/arm/mach-at91/Kconfig
-+++ b/arch/arm/mach-at91/Kconfig
-@@ -29,6 +29,7 @@ comment "Atmel AT91 Processor"
- config SOC_AT91SAM9
- bool
- select CPU_ARM926T
-+ select MULTI_IRQ_HANDLER
- select AT91_SAM9_TIME
- select AT91_SAM9_SMC
-
-diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
-index 271f994..22d8856 100644
---- a/arch/arm/mach-at91/board-1arm.c
-+++ b/arch/arm/mach-at91/board-1arm.c
-@@ -36,6 +36,7 @@
-
- #include <mach/board.h>
- #include <mach/cpu.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -91,6 +92,7 @@ MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
- /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = onearm_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = onearm_board_init,
-diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
-index b7d8aa7..de7be19 100644
---- a/arch/arm/mach-at91/board-afeb-9260v1.c
-+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
-@@ -44,6 +44,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -212,6 +213,7 @@ MACHINE_START(AFEB9260, "Custom afeb9260 board")
- /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = afeb9260_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = afeb9260_board_init,
-diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
-index 29d3ef0..477e708 100644
---- a/arch/arm/mach-at91/board-cam60.c
-+++ b/arch/arm/mach-at91/board-cam60.c
-@@ -39,6 +39,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -188,6 +189,7 @@ MACHINE_START(CAM60, "KwikByte CAM60")
- /* Maintainer: KwikByte */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = cam60_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cam60_board_init,
-diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
-index 44328a6..a5b002f 100644
---- a/arch/arm/mach-at91/board-carmeva.c
-+++ b/arch/arm/mach-at91/board-carmeva.c
-@@ -36,6 +36,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -158,6 +159,7 @@ MACHINE_START(CARMEVA, "Carmeva")
- /* Maintainer: Conitec Datasystems */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = carmeva_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = carmeva_board_init,
-diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
-index ece0d76..7ddc219 100644
---- a/arch/arm/mach-at91/board-cpu9krea.c
-+++ b/arch/arm/mach-at91/board-cpu9krea.c
-@@ -41,6 +41,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91sam9260_matrix.h>
- #include <mach/at91_matrix.h>
-@@ -375,6 +376,7 @@ MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
- /* Maintainer: Eric Benard - EUKREA Electromatique */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = cpu9krea_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cpu9krea_board_init,
-diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
-index 895cf2d..2e6d043 100644
---- a/arch/arm/mach-at91/board-cpuat91.c
-+++ b/arch/arm/mach-at91/board-cpuat91.c
-@@ -37,6 +37,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
- #include <mach/cpu.h>
-@@ -178,6 +179,7 @@ MACHINE_START(CPUAT91, "Eukrea")
- /* Maintainer: Eric Benard - EUKREA Electromatique */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = cpuat91_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cpuat91_board_init,
-diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
-index cd81336..462bc31 100644
---- a/arch/arm/mach-at91/board-csb337.c
-+++ b/arch/arm/mach-at91/board-csb337.c
-@@ -39,6 +39,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -252,6 +253,7 @@ MACHINE_START(CSB337, "Cogent CSB337")
- /* Maintainer: Bill Gatliff */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = csb337_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = csb337_board_init,
-diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
-index 7c8b05a..872871a 100644
---- a/arch/arm/mach-at91/board-csb637.c
-+++ b/arch/arm/mach-at91/board-csb637.c
-@@ -36,6 +36,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -133,6 +134,7 @@ MACHINE_START(CSB637, "Cogent CSB637")
- /* Maintainer: Bill Gatliff */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = csb637_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = csb637_board_init,
-diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
-index a1fce05..e8f45c4 100644
---- a/arch/arm/mach-at91/board-dt.c
-+++ b/arch/arm/mach-at91/board-dt.c
-@@ -16,6 +16,7 @@
- #include <linux/of_platform.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include <asm/setup.h>
- #include <asm/irq.h>
-@@ -53,6 +54,7 @@ DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = at91_dt_initialize,
- .init_irq = at91_dt_init_irq,
- .init_machine = at91_dt_device_init,
-diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c
-index d2023f2..01f66e9 100644
---- a/arch/arm/mach-at91/board-eb01.c
-+++ b/arch/arm/mach-at91/board-eb01.c
-@@ -28,6 +28,7 @@
- #include <asm/mach/arch.h>
- #include <asm/mach/map.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include "generic.h"
-
- static void __init at91eb01_init_irq(void)
-@@ -43,6 +44,7 @@ static void __init at91eb01_init_early(void)
- MACHINE_START(AT91EB01, "Atmel AT91 EB01")
- /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
- .timer = &at91x40_timer,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = at91eb01_init_early,
- .init_irq = at91eb01_init_irq,
- MACHINE_END
-diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
-index bd10172..d1e1f3f 100644
---- a/arch/arm/mach-at91/board-eb9200.c
-+++ b/arch/arm/mach-at91/board-eb9200.c
-@@ -36,6 +36,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -118,6 +119,7 @@ static void __init eb9200_board_init(void)
- MACHINE_START(ATEB9200, "Embest ATEB9200")
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = eb9200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = eb9200_board_init,
-diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
-index 89cc372..9c24cb2 100644
---- a/arch/arm/mach-at91/board-ecbat91.c
-+++ b/arch/arm/mach-at91/board-ecbat91.c
-@@ -39,6 +39,7 @@
-
- #include <mach/board.h>
- #include <mach/cpu.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -170,6 +171,7 @@ MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
- /* Maintainer: emQbit.com */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ecb_at91init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ecb_at91board_init,
-diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
-index 558546c..82bdfde 100644
---- a/arch/arm/mach-at91/board-eco920.c
-+++ b/arch/arm/mach-at91/board-eco920.c
-@@ -25,6 +25,7 @@
- #include <asm/mach/map.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
- #include <mach/cpu.h>
-@@ -132,6 +133,7 @@ MACHINE_START(ECO920, "eco920")
- /* Maintainer: Sascha Hauer */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = eco920_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = eco920_board_init,
-diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
-index 47658f7..6cc83a8 100644
---- a/arch/arm/mach-at91/board-flexibity.c
-+++ b/arch/arm/mach-at91/board-flexibity.c
-@@ -34,6 +34,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include "generic.h"
-
-@@ -160,6 +161,7 @@ MACHINE_START(FLEXIBITY, "Flexibity Connect")
- /* Maintainer: Maxim Osipov */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = flexibity_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = flexibity_board_init,
-diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
-index 33411e6..69ab124 100644
---- a/arch/arm/mach-at91/board-foxg20.c
-+++ b/arch/arm/mach-at91/board-foxg20.c
-@@ -42,6 +42,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -262,6 +263,7 @@ MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
- /* Maintainer: Sergio Tanzilli */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = foxg20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = foxg20_board_init,
-diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
-index 3e0dfa6..a9d5e78 100644
---- a/arch/arm/mach-at91/board-gsia18s.c
-+++ b/arch/arm/mach-at91/board-gsia18s.c
-@@ -31,6 +31,7 @@
- #include <asm/mach/arch.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/gsia18s.h>
- #include <mach/stamp9g20.h>
-@@ -575,6 +576,7 @@ static void __init gsia18s_board_init(void)
- MACHINE_START(GSIA18S, "GS_IA18_S")
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = gsia18s_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = gsia18s_board_init,
-diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
-index f260657..64c1dbf 100644
---- a/arch/arm/mach-at91/board-kafa.c
-+++ b/arch/arm/mach-at91/board-kafa.c
-@@ -35,6 +35,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/cpu.h>
-
- #include "generic.h"
-@@ -93,6 +94,7 @@ MACHINE_START(KAFA, "Sperry-Sun KAFA")
- /* Maintainer: Sergei Sharonov */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = kafa_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = kafa_board_init,
-diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
-index ba39db5..5d96cb8 100644
---- a/arch/arm/mach-at91/board-kb9202.c
-+++ b/arch/arm/mach-at91/board-kb9202.c
-@@ -37,6 +37,7 @@
-
- #include <mach/board.h>
- #include <mach/cpu.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
-
-@@ -133,6 +134,7 @@ MACHINE_START(KB9200, "KB920x")
- /* Maintainer: KwikByte, Inc. */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = kb9202_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = kb9202_board_init,
-diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
-index d2f4cc1..18103c5d 100644
---- a/arch/arm/mach-at91/board-neocore926.c
-+++ b/arch/arm/mach-at91/board-neocore926.c
-@@ -45,6 +45,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -378,6 +379,7 @@ MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
- /* Maintainer: ADENEO */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = neocore926_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = neocore926_board_init,
-diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
-index 7fe6383..9ca3e32 100644
---- a/arch/arm/mach-at91/board-pcontrol-g20.c
-+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
-@@ -30,6 +30,7 @@
- #include <asm/mach/arch.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/stamp9g20.h>
-
-@@ -218,6 +219,7 @@ MACHINE_START(PCONTROL_G20, "PControl G20")
- /* Maintainer: pgsellmann@portner-elektronik.at */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = pcontrol_g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = pcontrol_g20_board_init,
-diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
-index b45c0a5..1270655 100644
---- a/arch/arm/mach-at91/board-picotux200.c
-+++ b/arch/arm/mach-at91/board-picotux200.c
-@@ -38,6 +38,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
-
-@@ -120,6 +121,7 @@ MACHINE_START(PICOTUX2XX, "picotux 200")
- /* Maintainer: Kleinhenz Elektronik GmbH */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = picotux200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = picotux200_board_init,
-diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
-index 0c61bf0..bf351e2 100644
---- a/arch/arm/mach-at91/board-qil-a9260.c
-+++ b/arch/arm/mach-at91/board-qil-a9260.c
-@@ -41,6 +41,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
-
-@@ -258,6 +259,7 @@ MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
- /* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
-index afd7a47..cc2bf97 100644
---- a/arch/arm/mach-at91/board-rm9200dk.c
-+++ b/arch/arm/mach-at91/board-rm9200dk.c
-@@ -40,6 +40,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
-
-@@ -223,6 +224,7 @@ MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
- /* Maintainer: SAN People/Atmel */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = dk_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = dk_board_init,
-diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
-index 2b15b8a..62e19e6 100644
---- a/arch/arm/mach-at91/board-rm9200ek.c
-+++ b/arch/arm/mach-at91/board-rm9200ek.c
-@@ -40,6 +40,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
-
-@@ -190,6 +191,7 @@ MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
- /* Maintainer: SAN People/Atmel */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
-index 24ab9be..c3b43ae 100644
---- a/arch/arm/mach-at91/board-rsi-ews.c
-+++ b/arch/arm/mach-at91/board-rsi-ews.c
-@@ -26,6 +26,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
-
- #include <linux/gpio.h>
-
-@@ -225,6 +226,7 @@ MACHINE_START(RSI_EWS, "RSI EWS")
- /* Maintainer: Josef Holzmayr <holzmayr@rsi-elektrotechnik.de> */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = rsi_ews_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = rsi_ews_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
-index cdd21f2..7bf6da7 100644
---- a/arch/arm/mach-at91/board-sam9-l9260.c
-+++ b/arch/arm/mach-at91/board-sam9-l9260.c
-@@ -38,6 +38,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -202,6 +203,7 @@ MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
- /* Maintainer: Olimex */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
-index 7b3c391..889c1bf 100644
---- a/arch/arm/mach-at91/board-sam9260ek.c
-+++ b/arch/arm/mach-at91/board-sam9260ek.c
-@@ -42,6 +42,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-@@ -344,6 +345,7 @@ MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
-index 2736453..2269be5 100644
---- a/arch/arm/mach-at91/board-sam9261ek.c
-+++ b/arch/arm/mach-at91/board-sam9261ek.c
-@@ -46,6 +46,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-@@ -615,6 +616,7 @@ MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
-index 983cb98..82adf58 100644
---- a/arch/arm/mach-at91/board-sam9263ek.c
-+++ b/arch/arm/mach-at91/board-sam9263ek.c
-@@ -45,6 +45,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-@@ -443,6 +444,7 @@ MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
-index 3d61553..da6d019 100644
---- a/arch/arm/mach-at91/board-sam9g20ek.c
-+++ b/arch/arm/mach-at91/board-sam9g20ek.c
-@@ -42,6 +42,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/system_rev.h>
-
-@@ -399,6 +400,7 @@ MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-@@ -408,6 +410,7 @@ MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
-index 9a87f0b..d1882d5 100644
---- a/arch/arm/mach-at91/board-sam9m10g45ek.c
-+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
-@@ -41,6 +41,7 @@
- #include <asm/mach/irq.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-@@ -491,6 +492,7 @@ MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
-index be3239f..e7dc3ea 100644
---- a/arch/arm/mach-at91/board-sam9rlek.c
-+++ b/arch/arm/mach-at91/board-sam9rlek.c
-@@ -31,6 +31,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
-
-@@ -319,6 +320,7 @@ MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
- /* Maintainer: Atmel */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
-index 9d446f1..a4e031a 100644
---- a/arch/arm/mach-at91/board-snapper9260.c
-+++ b/arch/arm/mach-at91/board-snapper9260.c
-@@ -33,6 +33,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -178,6 +179,7 @@ static void __init snapper9260_board_init(void)
- MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = snapper9260_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = snapper9260_board_init,
-diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
-index ee86f9d..29eae16 100644
---- a/arch/arm/mach-at91/board-stamp9g20.c
-+++ b/arch/arm/mach-at91/board-stamp9g20.c
-@@ -26,6 +26,7 @@
- #include <asm/mach/arch.h>
-
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-@@ -287,6 +288,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
- /* Maintainer: taskit GmbH */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = stamp9g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = portuxg20_board_init,
-@@ -296,6 +298,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
- /* Maintainer: taskit GmbH */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = stamp9g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = stamp9g20evb_board_init,
-diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
-index 95393fc..c1476b9 100644
---- a/arch/arm/mach-at91/board-usb-a926x.c
-+++ b/arch/arm/mach-at91/board-usb-a926x.c
-@@ -42,6 +42,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
-
-@@ -358,6 +359,7 @@ MACHINE_START(USB_A9263, "CALAO USB_A9263")
- /* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-@@ -367,6 +369,7 @@ MACHINE_START(USB_A9260, "CALAO USB_A9260")
- /* Maintainer: calao-systems */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-@@ -376,6 +379,7 @@ MACHINE_START(USB_A9G20, "CALAO USB_A92G0")
- /* Maintainer: Jean-Christophe PLAGNIOL-VILLARD */
- .timer = &at91sam926x_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
-index d56665e..516d340 100644
---- a/arch/arm/mach-at91/board-yl-9200.c
-+++ b/arch/arm/mach-at91/board-yl-9200.c
-@@ -44,6 +44,7 @@
-
- #include <mach/hardware.h>
- #include <mach/board.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91rm9200_mc.h>
- #include <mach/at91_ramc.h>
- #include <mach/cpu.h>
-@@ -590,6 +591,7 @@ MACHINE_START(YL9200, "uCdragon YL-9200")
- /* Maintainer: S.Birtles */
- .timer = &at91rm9200_timer,
- .map_io = at91_map_io,
-+ .handle_irq = at91_aic_handle_irq,
- .init_early = yl9200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = yl9200_board_init,
-diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
-index 3af7272..7867378 100644
---- a/arch/arm/mach-at91/include/mach/at91_aic.h
-+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
-@@ -65,4 +65,6 @@ extern void __iomem *at91_aic_base;
- #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
- #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
-
-+void at91_aic_handle_irq(struct pt_regs *regs);
-+
- #endif
-diff --git a/arch/arm/mach-at91/include/mach/entry-macro.S b/arch/arm/mach-at91/include/mach/entry-macro.S
-deleted file mode 100644
-index 903bf20..0000000
---- a/arch/arm/mach-at91/include/mach/entry-macro.S
-+++ /dev/null
-@@ -1,27 +0,0 @@
--/*
-- * arch/arm/mach-at91/include/mach/entry-macro.S
-- *
-- * Copyright (C) 2003-2005 SAN People
-- *
-- * Low-level IRQ helper macros for AT91RM9200 platforms
-- *
-- * This file is licensed under the terms of the GNU General Public
-- * License version 2. This program is licensed "as is" without any
-- * warranty of any kind, whether express or implied.
-- */
--
--#include <mach/hardware.h>
--#include <mach/at91_aic.h>
--
-- .macro get_irqnr_preamble, base, tmp
-- ldr \base, =at91_aic_base @ base virtual address of AIC peripheral
-- ldr \base, [\base]
-- .endm
--
-- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-- ldr \irqnr, [\base, #AT91_AIC_IVR] @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
-- ldr \irqstat, [\base, #AT91_AIC_ISR] @ read interrupt source number
-- teq \irqstat, #0 @ ISR is 0 when no current interrupt, or spurious interrupt
-- streq \tmp, [\base, #AT91_AIC_EOICR] @ not going to be handled further, then ACK it now.
-- .endm
--
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index db8e141..390d4df 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -36,6 +36,7 @@
- #include <asm/irq.h>
- #include <asm/setup.h>
-
-+#include <asm/exception.h>
- #include <asm/mach/arch.h>
- #include <asm/mach/irq.h>
- #include <asm/mach/map.h>
-@@ -45,6 +46,24 @@ static struct irq_domain *at91_aic_domain;
- static struct device_node *at91_aic_np;
- static unsigned int *at91_aic_irq_priorities;
-
-+asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
-+{
-+ u32 irqnr;
-+ u32 irqstat;
-+
-+ irqnr = at91_aic_read(AT91_AIC_IVR);
-+ irqstat = at91_aic_read(AT91_AIC_ISR);
-+
-+ /*
-+ * ISR value is 0 when there is no current interrupt or when there is
-+ * a spurious interrupt
-+ */
-+ if (!irqstat)
-+ at91_aic_write(AT91_AIC_EOICR, 0);
-+ else
-+ handle_IRQ(irqnr, regs);
-+}
-+
- static void at91_aic_mask_irq(struct irq_data *d)
- {
- /* Disable interrupt on AIC */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f53355af7dda7196da453539fae26457c459dfb2 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 21 Jun 2012 14:47:27 +0200
+Subject: ARM: at91: sparse irq support
+
+commit 8fe82a5550a8e97b3f59c74f994b88ed6b3544a3 upstream.
+
+Enable sparse irq support for multisoc image. It involves to add the
+NR_IRQS_LEGACY offset to static SoC irq number definitions since NR_IRQS_LEGACY
+irq descs are allocated before AIC requests irq descs allocation.
+Move NR_AIC_IRQS macro to a more appropiate place with the purpose to
+remove mach/irqs.h later.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9260_devices.c
+ arch/arm/mach-at91/at91sam9g45_devices.c
+---
+ arch/arm/mach-at91/Kconfig | 1 +
+ arch/arm/mach-at91/at91rm9200.c | 1 +
+ arch/arm/mach-at91/at91rm9200_devices.c | 84 +++++++++++------------
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9260_devices.c | 88 ++++++++++++------------
+ arch/arm/mach-at91/at91sam9261.c | 1 +
+ arch/arm/mach-at91/at91sam9261_devices.c | 68 +++++++++----------
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9263_devices.c | 80 +++++++++++-----------
+ arch/arm/mach-at91/at91sam926x_time.c | 2 +-
+ arch/arm/mach-at91/at91sam9g45.c | 1 +
+ arch/arm/mach-at91/at91sam9g45_devices.c | 104 ++++++++++++++---------------
+ arch/arm/mach-at91/at91sam9rl.c | 1 +
+ arch/arm/mach-at91/at91sam9rl_devices.c | 76 ++++++++++-----------
+ arch/arm/mach-at91/at91x40.c | 1 +
+ arch/arm/mach-at91/include/mach/at91_aic.h | 3 +
+ arch/arm/mach-at91/include/mach/irqs.h | 12 ----
+ arch/arm/mach-at91/irq.c | 6 +-
+ arch/arm/mach-at91/pm.c | 1 +
+ 19 files changed, 267 insertions(+), 265 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index e401dea..7d0c40a 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -30,6 +30,7 @@ config SOC_AT91SAM9
+ bool
+ select CPU_ARM926T
+ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select AT91_SAM9_TIME
+ select AT91_SAM9_SMC
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index d50da1a..801c30b 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -17,6 +17,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91rm9200.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_st.h>
+ #include <mach/cpu.h>
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 99affb5..04d69d3 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -41,8 +41,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_UHP,
+- .end = AT91RM9200_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -94,8 +94,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_UDP,
+- .end = AT91RM9200_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -145,8 +145,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_EMAC,
+- .end = AT91RM9200_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -305,8 +305,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_MCI,
+- .end = AT91RM9200_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -488,8 +488,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TWI,
+- .end = AT91RM9200_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -532,8 +532,8 @@ static struct resource spi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SPI,
+- .end = AT91RM9200_ID_SPI,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -598,18 +598,18 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TC0,
+- .end = AT91RM9200_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91RM9200_ID_TC1,
+- .end = AT91RM9200_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91RM9200_ID_TC2,
+- .end = AT91RM9200_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -628,18 +628,18 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_TC3,
+- .end = AT91RM9200_ID_TC3,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91RM9200_ID_TC4,
+- .end = AT91RM9200_ID_TC4,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91RM9200_ID_TC5,
+- .end = AT91RM9200_ID_TC5,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -673,8 +673,8 @@ static struct resource rtc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -729,8 +729,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC0,
+- .end = AT91RM9200_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -771,8 +771,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC1,
+- .end = AT91RM9200_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -813,8 +813,8 @@ static struct resource ssc2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_SSC2,
+- .end = AT91RM9200_ID_SSC2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -897,8 +897,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -935,8 +935,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US0,
+- .end = AT91RM9200_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -984,8 +984,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US1,
+- .end = AT91RM9200_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1035,8 +1035,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US2,
+- .end = AT91RM9200_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1078,8 +1078,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91RM9200_ID_US3,
+- .end = AT91RM9200_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index a27bbec..c644131 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -20,6 +20,7 @@
+ #include <mach/cpu.h>
+ #include <mach/at91_dbgu.h>
+ #include <mach/at91sam9260.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index d556de1..43e60fb 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -42,8 +42,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_UHP,
+- .end = AT91SAM9260_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -95,8 +95,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_UDP,
+- .end = AT91SAM9260_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -146,8 +146,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_EMAC,
+- .end = AT91SAM9260_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -220,8 +220,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_MCI,
+- .end = AT91SAM9260_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -302,8 +302,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_MCI,
+- .end = AT91SAM9260_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -493,8 +493,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TWI,
+- .end = AT91SAM9260_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -537,8 +537,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SPI0,
+- .end = AT91SAM9260_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -563,8 +563,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SPI1,
+- .end = AT91SAM9260_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -649,18 +649,18 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TC0,
+- .end = AT91SAM9260_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9260_ID_TC1,
+- .end = AT91SAM9260_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9260_ID_TC2,
+- .end = AT91SAM9260_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -679,18 +679,18 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_TC3,
+- .end = AT91SAM9260_ID_TC3,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9260_ID_TC4,
+- .end = AT91SAM9260_ID_TC4,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9260_ID_TC5,
+- .end = AT91SAM9260_ID_TC5,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -804,8 +804,8 @@ static struct resource ssc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_SSC,
+- .end = AT91SAM9260_ID_SSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -879,8 +879,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -917,8 +917,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US0,
+- .end = AT91SAM9260_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -968,8 +968,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US1,
+- .end = AT91SAM9260_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1011,8 +1011,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US2,
+- .end = AT91SAM9260_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1054,8 +1054,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US3,
+- .end = AT91SAM9260_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1097,8 +1097,8 @@ static struct resource uart4_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US4,
+- .end = AT91SAM9260_ID_US4,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1135,8 +1135,8 @@ static struct resource uart5_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9260_ID_US5,
+- .end = AT91SAM9260_ID_US5,
++ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
++ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index c77d503..f40762c 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -19,6 +19,7 @@
+ #include <asm/system_misc.h>
+ #include <mach/cpu.h>
+ #include <mach/at91sam9261.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 9295e90..8df5c1b 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -45,8 +45,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_UHP,
+- .end = AT91SAM9261_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -98,8 +98,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_UDP,
+- .end = AT91SAM9261_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -148,8 +148,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_MCI,
+- .end = AT91SAM9261_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -310,8 +310,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_TWI,
+- .end = AT91SAM9261_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -354,8 +354,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SPI0,
+- .end = AT91SAM9261_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -380,8 +380,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SPI1,
+- .end = AT91SAM9261_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -468,8 +468,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_LCDC,
+- .end = AT91SAM9261_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ #if defined(CONFIG_FB_INTSRAM)
+@@ -566,18 +566,18 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_TC0,
+- .end = AT91SAM9261_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9261_ID_TC1,
+- .end = AT91SAM9261_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9261_ID_TC2,
+- .end = AT91SAM9261_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -689,8 +689,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC0,
+- .end = AT91SAM9261_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -731,8 +731,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC1,
+- .end = AT91SAM9261_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -773,8 +773,8 @@ static struct resource ssc2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_SSC2,
+- .end = AT91SAM9261_ID_SSC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -857,8 +857,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -895,8 +895,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US0,
+- .end = AT91SAM9261_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -938,8 +938,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US1,
+- .end = AT91SAM9261_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -981,8 +981,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9261_ID_US2,
+- .end = AT91SAM9261_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index ed91c7e..84b3810 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -18,6 +18,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91sam9263.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index 175e000..eb6bbf8 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -44,8 +44,8 @@ static struct resource usbh_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_UHP,
+- .end = AT91SAM9263_ID_UHP,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -104,8 +104,8 @@ static struct resource udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_UDP,
+- .end = AT91SAM9263_ID_UDP,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -155,8 +155,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_EMAC,
+- .end = AT91SAM9263_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -229,8 +229,8 @@ static struct resource mmc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_MCI0,
+- .end = AT91SAM9263_ID_MCI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -254,8 +254,8 @@ static struct resource mmc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_MCI1,
+- .end = AT91SAM9263_ID_MCI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -567,8 +567,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_TWI,
+- .end = AT91SAM9263_ID_TWI,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -611,8 +611,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SPI0,
+- .end = AT91SAM9263_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -637,8 +637,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SPI1,
+- .end = AT91SAM9263_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -725,8 +725,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_AC97C,
+- .end = AT91SAM9263_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -776,8 +776,8 @@ static struct resource can_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_CAN,
+- .end = AT91SAM9263_ID_CAN,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -816,8 +816,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_LCDC,
+- .end = AT91SAM9263_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -883,8 +883,8 @@ struct resource isi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_ISI,
+- .end = AT91SAM9263_ID_ISI,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -940,8 +940,8 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_TCB,
+- .end = AT91SAM9263_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1108,8 +1108,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_PWMC,
+- .end = AT91SAM9263_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1161,8 +1161,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SSC0,
+- .end = AT91SAM9263_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1203,8 +1203,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_SSC1,
+- .end = AT91SAM9263_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1284,8 +1284,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1322,8 +1322,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US0,
+- .end = AT91SAM9263_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1365,8 +1365,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US1,
+- .end = AT91SAM9263_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1408,8 +1408,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9263_ID_US2,
+- .end = AT91SAM9263_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
+index a94758b..ffc0957 100644
+--- a/arch/arm/mach-at91/at91sam926x_time.c
++++ b/arch/arm/mach-at91/at91sam926x_time.c
+@@ -137,7 +137,7 @@ static struct irqaction at91sam926x_pit_irq = {
+ .name = "at91_tick",
+ .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = at91sam926x_pit_interrupt,
+- .irq = AT91_ID_SYS,
++ .irq = NR_IRQS_LEGACY + AT91_ID_SYS,
+ };
+
+ static void at91sam926x_pit_reset(void)
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index f205449..55d2959 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -18,6 +18,7 @@
+ #include <asm/mach/map.h>
+ #include <asm/system_misc.h>
+ #include <mach/at91sam9g45.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/cpu.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 35bd42d..7a3f0b3 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -50,8 +50,8 @@ static struct resource hdmac_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_DMA,
+- .end = AT91SAM9G45_ID_DMA,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -91,8 +91,8 @@ static struct resource usbh_ohci_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_UHPHS,
+- .end = AT91SAM9G45_ID_UHPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -153,8 +153,8 @@ static struct resource usbh_ehci_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_UHPHS,
+- .end = AT91SAM9G45_ID_UHPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -210,8 +210,8 @@ static struct resource usba_udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9G45_ID_UDPHS,
+- .end = AT91SAM9G45_ID_UDPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -293,8 +293,8 @@ static struct resource eth_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_EMAC,
+- .end = AT91SAM9G45_ID_EMAC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -367,8 +367,8 @@ static struct resource mmc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_MCI0,
+- .end = AT91SAM9G45_ID_MCI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -392,8 +392,8 @@ static struct resource mmc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_MCI1,
+- .end = AT91SAM9G45_ID_MCI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -643,8 +643,8 @@ static struct resource twi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TWI0,
+- .end = AT91SAM9G45_ID_TWI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -663,8 +663,8 @@ static struct resource twi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TWI1,
+- .end = AT91SAM9G45_ID_TWI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -718,8 +718,8 @@ static struct resource spi0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SPI0,
+- .end = AT91SAM9G45_ID_SPI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -744,8 +744,8 @@ static struct resource spi1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SPI1,
+- .end = AT91SAM9G45_ID_SPI1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -832,8 +832,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_AC97C,
+- .end = AT91SAM9G45_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -885,8 +885,8 @@ struct resource isi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_ISI,
+- .end = AT91SAM9G45_ID_ISI,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -977,8 +977,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_LCDC,
+- .end = AT91SAM9G45_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1052,8 +1052,8 @@ static struct resource tcb0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TCB,
+- .end = AT91SAM9G45_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1073,8 +1073,8 @@ static struct resource tcb1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TCB,
+- .end = AT91SAM9G45_ID_TCB,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1108,8 +1108,8 @@ static struct resource rtc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1145,8 +1145,8 @@ static struct resource tsadcc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_TSC,
+- .end = AT91SAM9G45_ID_TSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+@@ -1300,8 +1300,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_PWMC,
+- .end = AT91SAM9G45_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1353,8 +1353,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SSC0,
+- .end = AT91SAM9G45_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1395,8 +1395,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_SSC1,
+- .end = AT91SAM9G45_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1475,8 +1475,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1513,8 +1513,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US0,
+- .end = AT91SAM9G45_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1556,8 +1556,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US1,
+- .end = AT91SAM9G45_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1599,8 +1599,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US2,
+- .end = AT91SAM9G45_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1642,8 +1642,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9G45_ID_US3,
+- .end = AT91SAM9G45_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index e420085..72ce50a 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -19,6 +19,7 @@
+ #include <mach/cpu.h>
+ #include <mach/at91_dbgu.h>
+ #include <mach/at91sam9rl.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/at91_rstc.h>
+
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 9c0b148..f09fff9 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -41,8 +41,8 @@ static struct resource hdmac_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_DMA,
+- .end = AT91SAM9RL_ID_DMA,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -84,8 +84,8 @@ static struct resource usba_udc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_UDPHS,
+- .end = AT91SAM9RL_ID_UDPHS,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -172,8 +172,8 @@ static struct resource mmc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_MCI,
+- .end = AT91SAM9RL_ID_MCI,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -339,8 +339,8 @@ static struct resource twi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TWI0,
+- .end = AT91SAM9RL_ID_TWI0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -383,8 +383,8 @@ static struct resource spi_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SPI,
+- .end = AT91SAM9RL_ID_SPI,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -452,8 +452,8 @@ static struct resource ac97_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_AC97C,
+- .end = AT91SAM9RL_ID_AC97C,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -507,8 +507,8 @@ static struct resource lcdc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_LCDC,
+- .end = AT91SAM9RL_ID_LCDC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -574,18 +574,18 @@ static struct resource tcb_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TC0,
+- .end = AT91SAM9RL_ID_TC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+- .start = AT91SAM9RL_ID_TC1,
+- .end = AT91SAM9RL_ID_TC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+- .start = AT91SAM9RL_ID_TC2,
+- .end = AT91SAM9RL_ID_TC2,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -621,8 +621,8 @@ static struct resource tsadcc_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_TSC,
+- .end = AT91SAM9RL_ID_TSC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+@@ -768,8 +768,8 @@ static struct resource pwm_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_PWMC,
+- .end = AT91SAM9RL_ID_PWMC,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -821,8 +821,8 @@ static struct resource ssc0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SSC0,
+- .end = AT91SAM9RL_ID_SSC0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -863,8 +863,8 @@ static struct resource ssc1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_SSC1,
+- .end = AT91SAM9RL_ID_SSC1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -943,8 +943,8 @@ static struct resource dbgu_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91_ID_SYS,
+- .end = AT91_ID_SYS,
++ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
++ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -981,8 +981,8 @@ static struct resource uart0_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US0,
+- .end = AT91SAM9RL_ID_US0,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1032,8 +1032,8 @@ static struct resource uart1_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US1,
+- .end = AT91SAM9RL_ID_US1,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1075,8 +1075,8 @@ static struct resource uart2_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US2,
+- .end = AT91SAM9RL_ID_US2,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+@@ -1118,8 +1118,8 @@ static struct resource uart3_resources[] = {
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+- .start = AT91SAM9RL_ID_US3,
+- .end = AT91SAM9RL_ID_US3,
++ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
++ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
+index d62fe09..4c0f5fd 100644
+--- a/arch/arm/mach-at91/at91x40.c
++++ b/arch/arm/mach-at91/at91x40.c
+@@ -17,6 +17,7 @@
+ #include <asm/system_misc.h>
+ #include <asm/mach/arch.h>
+ #include <mach/at91x40.h>
++#include <mach/at91_aic.h>
+ #include <mach/at91_st.h>
+ #include <mach/timex.h>
+ #include "generic.h"
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index 7867378..fd42a85 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
+ .extern at91_aic_base
+ #endif
+
++/* Number of irq lines managed by AIC */
++#define NR_AIC_IRQS 32
++
+ #define AT91_AIC_IRQ_MIN_PRIORITY 0
+ #define AT91_AIC_IRQ_MAX_PRIORITY 7
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+index 2d510ee..cab60d5 100644
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ b/arch/arm/mach-at91/include/mach/irqs.h
+@@ -22,18 +22,6 @@
+ #define __ASM_ARCH_IRQS_H
+
+ #include <linux/io.h>
+-#include <mach/at91_aic.h>
+-
+-#define NR_AIC_IRQS 32
+-
+-
+-/*
+- * IRQ interrupt symbols are the AT91xxx_ID_* symbols
+- * for IRQs handled directly through the AIC, or else the AT91_PIN_*
+- * symbols in gpio.h for ones handled indirectly as GPIOs.
+- * We make provision for 5 banks of GPIO.
+- */
+-#define NR_IRQS (NR_AIC_IRQS + (5 * 32))
+
+ /* FIQ is AIC source 0. */
+ #define FIQ_START AT91_ID_FIQ
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 390d4df..75ca2f4 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -41,6 +41,8 @@
+ #include <asm/mach/irq.h>
+ #include <asm/mach/map.h>
+
++#include <mach/at91_aic.h>
++
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+@@ -302,11 +304,11 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ */
+ for (i = 0; i < NR_AIC_IRQS; i++) {
+ /* Put hardware irq number in Source Vector Register: */
+- at91_aic_write(AT91_AIC_SVR(i), i);
++ at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+
+- irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
++ irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
+index 1bfaad6..2c2d865 100644
+--- a/arch/arm/mach-at91/pm.c
++++ b/arch/arm/mach-at91/pm.c
+@@ -25,6 +25,7 @@
+ #include <asm/mach/time.h>
+ #include <asm/mach/irq.h>
+
++#include <mach/at91_aic.h>
+ #include <mach/at91_pmc.h>
+ #include <mach/cpu.h>
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From eb023f54611256fb88f23973139adb9c7c0b4c7f Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 14 Jun 2012 15:41:04 +0200
+Subject: ARM: at91: remove mach/irqs.h
+
+commit 4c6971a6debb340d487cf6189f15a1332702330f upstream.
+
+mach/irqs only defines FIQ_START which doesn't appear to be used anywhere
+so remove it.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/irqs.h | 29 -----------------------------
+ 1 file changed, 29 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/irqs.h
+
+diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
+deleted file mode 100644
+index cab60d5..0000000
+--- a/arch/arm/mach-at91/include/mach/irqs.h
++++ /dev/null
+@@ -1,29 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/irqs.h
+- *
+- * Copyright (C) 2004 SAN People
+- *
+- * 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.
+- *
+- * This program 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 General Public License for more details.
+- *
+- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- */
+-
+-#ifndef __ASM_ARCH_IRQS_H
+-#define __ASM_ARCH_IRQS_H
+-
+-#include <linux/io.h>
+-
+-/* FIQ is AIC source 0. */
+-#define FIQ_START AT91_ID_FIQ
+-
+-#endif
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 6fdddfc0d9b97a191bf49bb1b180822f156c515c Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Thu, 21 Jun 2012 14:47:27 +0200
-Subject: ARM: at91: sparse irq support
-
-Enable sparse irq support for multisoc image. It involves to add the
-NR_IRQS_LEGACY offset to static SoC irq number definitions since NR_IRQS_LEGACY
-irq descs are allocated before AIC requests irq descs allocation.
-Move NR_AIC_IRQS macro to a more appropiate place with the purpose to
-remove mach/irqs.h later.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-
-Conflicts:
- arch/arm/mach-at91/at91sam9260_devices.c
- arch/arm/mach-at91/at91sam9g45_devices.c
----
- arch/arm/mach-at91/Kconfig | 1 +
- arch/arm/mach-at91/at91rm9200.c | 1 +
- arch/arm/mach-at91/at91rm9200_devices.c | 84 +++++++++++------------
- arch/arm/mach-at91/at91sam9260.c | 1 +
- arch/arm/mach-at91/at91sam9260_devices.c | 88 ++++++++++++------------
- arch/arm/mach-at91/at91sam9261.c | 1 +
- arch/arm/mach-at91/at91sam9261_devices.c | 68 +++++++++----------
- arch/arm/mach-at91/at91sam9263.c | 1 +
- arch/arm/mach-at91/at91sam9263_devices.c | 80 +++++++++++-----------
- arch/arm/mach-at91/at91sam926x_time.c | 2 +-
- arch/arm/mach-at91/at91sam9g45.c | 1 +
- arch/arm/mach-at91/at91sam9g45_devices.c | 104 ++++++++++++++---------------
- arch/arm/mach-at91/at91sam9rl.c | 1 +
- arch/arm/mach-at91/at91sam9rl_devices.c | 76 ++++++++++-----------
- arch/arm/mach-at91/at91x40.c | 1 +
- arch/arm/mach-at91/include/mach/at91_aic.h | 3 +
- arch/arm/mach-at91/include/mach/irqs.h | 12 ----
- arch/arm/mach-at91/irq.c | 6 +-
- arch/arm/mach-at91/pm.c | 1 +
- 19 files changed, 267 insertions(+), 265 deletions(-)
-
-diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
-index e401dea..7d0c40a 100644
---- a/arch/arm/mach-at91/Kconfig
-+++ b/arch/arm/mach-at91/Kconfig
-@@ -30,6 +30,7 @@ config SOC_AT91SAM9
- bool
- select CPU_ARM926T
- select MULTI_IRQ_HANDLER
-+ select SPARSE_IRQ
- select AT91_SAM9_TIME
- select AT91_SAM9_SMC
-
-diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
-index d50da1a..801c30b 100644
---- a/arch/arm/mach-at91/at91rm9200.c
-+++ b/arch/arm/mach-at91/at91rm9200.c
-@@ -17,6 +17,7 @@
- #include <asm/mach/map.h>
- #include <asm/system_misc.h>
- #include <mach/at91rm9200.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/at91_st.h>
- #include <mach/cpu.h>
-diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
-index 99affb5..04d69d3 100644
---- a/arch/arm/mach-at91/at91rm9200_devices.c
-+++ b/arch/arm/mach-at91/at91rm9200_devices.c
-@@ -41,8 +41,8 @@ static struct resource usbh_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_UHP,
-- .end = AT91RM9200_ID_UHP,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -94,8 +94,8 @@ static struct resource udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_UDP,
-- .end = AT91RM9200_ID_UDP,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -145,8 +145,8 @@ static struct resource eth_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_EMAC,
-- .end = AT91RM9200_ID_EMAC,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -305,8 +305,8 @@ static struct resource mmc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_MCI,
-- .end = AT91RM9200_ID_MCI,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -488,8 +488,8 @@ static struct resource twi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_TWI,
-- .end = AT91RM9200_ID_TWI,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -532,8 +532,8 @@ static struct resource spi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_SPI,
-- .end = AT91RM9200_ID_SPI,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -598,18 +598,18 @@ static struct resource tcb0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_TC0,
-- .end = AT91RM9200_ID_TC0,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91RM9200_ID_TC1,
-- .end = AT91RM9200_ID_TC1,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91RM9200_ID_TC2,
-- .end = AT91RM9200_ID_TC2,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -628,18 +628,18 @@ static struct resource tcb1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_TC3,
-- .end = AT91RM9200_ID_TC3,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91RM9200_ID_TC4,
-- .end = AT91RM9200_ID_TC4,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91RM9200_ID_TC5,
-- .end = AT91RM9200_ID_TC5,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -673,8 +673,8 @@ static struct resource rtc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -729,8 +729,8 @@ static struct resource ssc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_SSC0,
-- .end = AT91RM9200_ID_SSC0,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -771,8 +771,8 @@ static struct resource ssc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_SSC1,
-- .end = AT91RM9200_ID_SSC1,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -813,8 +813,8 @@ static struct resource ssc2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_SSC2,
-- .end = AT91RM9200_ID_SSC2,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -897,8 +897,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -935,8 +935,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_US0,
-- .end = AT91RM9200_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -984,8 +984,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_US1,
-- .end = AT91RM9200_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1035,8 +1035,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_US2,
-- .end = AT91RM9200_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1078,8 +1078,8 @@ static struct resource uart3_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91RM9200_ID_US3,
-- .end = AT91RM9200_ID_US3,
-+ .start = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
-+ .end = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index a27bbec..c644131 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -20,6 +20,7 @@
- #include <mach/cpu.h>
- #include <mach/at91_dbgu.h>
- #include <mach/at91sam9260.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/at91_rstc.h>
-
-diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
-index d556de1..43e60fb 100644
---- a/arch/arm/mach-at91/at91sam9260_devices.c
-+++ b/arch/arm/mach-at91/at91sam9260_devices.c
-@@ -42,8 +42,8 @@ static struct resource usbh_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_UHP,
-- .end = AT91SAM9260_ID_UHP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -95,8 +95,8 @@ static struct resource udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_UDP,
-- .end = AT91SAM9260_ID_UDP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -146,8 +146,8 @@ static struct resource eth_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_EMAC,
-- .end = AT91SAM9260_ID_EMAC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -220,8 +220,8 @@ static struct resource mmc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_MCI,
-- .end = AT91SAM9260_ID_MCI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -302,8 +302,8 @@ static struct resource mmc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_MCI,
-- .end = AT91SAM9260_ID_MCI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -493,8 +493,8 @@ static struct resource twi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_TWI,
-- .end = AT91SAM9260_ID_TWI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -537,8 +537,8 @@ static struct resource spi0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_SPI0,
-- .end = AT91SAM9260_ID_SPI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -563,8 +563,8 @@ static struct resource spi1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_SPI1,
-- .end = AT91SAM9260_ID_SPI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -649,18 +649,18 @@ static struct resource tcb0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_TC0,
-- .end = AT91SAM9260_ID_TC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91SAM9260_ID_TC1,
-- .end = AT91SAM9260_ID_TC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91SAM9260_ID_TC2,
-- .end = AT91SAM9260_ID_TC2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -679,18 +679,18 @@ static struct resource tcb1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_TC3,
-- .end = AT91SAM9260_ID_TC3,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91SAM9260_ID_TC4,
-- .end = AT91SAM9260_ID_TC4,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91SAM9260_ID_TC5,
-- .end = AT91SAM9260_ID_TC5,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -804,8 +804,8 @@ static struct resource ssc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_SSC,
-- .end = AT91SAM9260_ID_SSC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -879,8 +879,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -917,8 +917,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US0,
-- .end = AT91SAM9260_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -968,8 +968,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US1,
-- .end = AT91SAM9260_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1011,8 +1011,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US2,
-- .end = AT91SAM9260_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1054,8 +1054,8 @@ static struct resource uart3_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US3,
-- .end = AT91SAM9260_ID_US3,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1097,8 +1097,8 @@ static struct resource uart4_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US4,
-- .end = AT91SAM9260_ID_US4,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1135,8 +1135,8 @@ static struct resource uart5_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9260_ID_US5,
-- .end = AT91SAM9260_ID_US5,
-+ .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
-+ .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
-index c77d503..f40762c 100644
---- a/arch/arm/mach-at91/at91sam9261.c
-+++ b/arch/arm/mach-at91/at91sam9261.c
-@@ -19,6 +19,7 @@
- #include <asm/system_misc.h>
- #include <mach/cpu.h>
- #include <mach/at91sam9261.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/at91_rstc.h>
-
-diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
-index 9295e90..8df5c1b 100644
---- a/arch/arm/mach-at91/at91sam9261_devices.c
-+++ b/arch/arm/mach-at91/at91sam9261_devices.c
-@@ -45,8 +45,8 @@ static struct resource usbh_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_UHP,
-- .end = AT91SAM9261_ID_UHP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -98,8 +98,8 @@ static struct resource udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_UDP,
-- .end = AT91SAM9261_ID_UDP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -148,8 +148,8 @@ static struct resource mmc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_MCI,
-- .end = AT91SAM9261_ID_MCI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -310,8 +310,8 @@ static struct resource twi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_TWI,
-- .end = AT91SAM9261_ID_TWI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -354,8 +354,8 @@ static struct resource spi0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_SPI0,
-- .end = AT91SAM9261_ID_SPI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -380,8 +380,8 @@ static struct resource spi1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_SPI1,
-- .end = AT91SAM9261_ID_SPI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -468,8 +468,8 @@ static struct resource lcdc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_LCDC,
-- .end = AT91SAM9261_ID_LCDC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
- #if defined(CONFIG_FB_INTSRAM)
-@@ -566,18 +566,18 @@ static struct resource tcb_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_TC0,
-- .end = AT91SAM9261_ID_TC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91SAM9261_ID_TC1,
-- .end = AT91SAM9261_ID_TC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91SAM9261_ID_TC2,
-- .end = AT91SAM9261_ID_TC2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -689,8 +689,8 @@ static struct resource ssc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_SSC0,
-- .end = AT91SAM9261_ID_SSC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -731,8 +731,8 @@ static struct resource ssc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_SSC1,
-- .end = AT91SAM9261_ID_SSC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -773,8 +773,8 @@ static struct resource ssc2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_SSC2,
-- .end = AT91SAM9261_ID_SSC2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -857,8 +857,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -895,8 +895,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_US0,
-- .end = AT91SAM9261_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -938,8 +938,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_US1,
-- .end = AT91SAM9261_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -981,8 +981,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9261_ID_US2,
-- .end = AT91SAM9261_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index ed91c7e..84b3810 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -18,6 +18,7 @@
- #include <asm/mach/map.h>
- #include <asm/system_misc.h>
- #include <mach/at91sam9263.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/at91_rstc.h>
-
-diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
-index 175e000..eb6bbf8 100644
---- a/arch/arm/mach-at91/at91sam9263_devices.c
-+++ b/arch/arm/mach-at91/at91sam9263_devices.c
-@@ -44,8 +44,8 @@ static struct resource usbh_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_UHP,
-- .end = AT91SAM9263_ID_UHP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -104,8 +104,8 @@ static struct resource udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_UDP,
-- .end = AT91SAM9263_ID_UDP,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -155,8 +155,8 @@ static struct resource eth_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_EMAC,
-- .end = AT91SAM9263_ID_EMAC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -229,8 +229,8 @@ static struct resource mmc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_MCI0,
-- .end = AT91SAM9263_ID_MCI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -254,8 +254,8 @@ static struct resource mmc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_MCI1,
-- .end = AT91SAM9263_ID_MCI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -567,8 +567,8 @@ static struct resource twi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_TWI,
-- .end = AT91SAM9263_ID_TWI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -611,8 +611,8 @@ static struct resource spi0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_SPI0,
-- .end = AT91SAM9263_ID_SPI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -637,8 +637,8 @@ static struct resource spi1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_SPI1,
-- .end = AT91SAM9263_ID_SPI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -725,8 +725,8 @@ static struct resource ac97_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_AC97C,
-- .end = AT91SAM9263_ID_AC97C,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -776,8 +776,8 @@ static struct resource can_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_CAN,
-- .end = AT91SAM9263_ID_CAN,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -816,8 +816,8 @@ static struct resource lcdc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_LCDC,
-- .end = AT91SAM9263_ID_LCDC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -883,8 +883,8 @@ struct resource isi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_ISI,
-- .end = AT91SAM9263_ID_ISI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -940,8 +940,8 @@ static struct resource tcb_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_TCB,
-- .end = AT91SAM9263_ID_TCB,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1108,8 +1108,8 @@ static struct resource pwm_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_PWMC,
-- .end = AT91SAM9263_ID_PWMC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1161,8 +1161,8 @@ static struct resource ssc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_SSC0,
-- .end = AT91SAM9263_ID_SSC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1203,8 +1203,8 @@ static struct resource ssc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_SSC1,
-- .end = AT91SAM9263_ID_SSC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1284,8 +1284,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1322,8 +1322,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_US0,
-- .end = AT91SAM9263_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1365,8 +1365,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_US1,
-- .end = AT91SAM9263_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1408,8 +1408,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9263_ID_US2,
-- .end = AT91SAM9263_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
-index a94758b..ffc0957 100644
---- a/arch/arm/mach-at91/at91sam926x_time.c
-+++ b/arch/arm/mach-at91/at91sam926x_time.c
-@@ -137,7 +137,7 @@ static struct irqaction at91sam926x_pit_irq = {
- .name = "at91_tick",
- .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = at91sam926x_pit_interrupt,
-- .irq = AT91_ID_SYS,
-+ .irq = NR_IRQS_LEGACY + AT91_ID_SYS,
- };
-
- static void at91sam926x_pit_reset(void)
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index f205449..55d2959 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -18,6 +18,7 @@
- #include <asm/mach/map.h>
- #include <asm/system_misc.h>
- #include <mach/at91sam9g45.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/cpu.h>
-
-diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
-index 35bd42d..7a3f0b3 100644
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -50,8 +50,8 @@ static struct resource hdmac_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_DMA,
-- .end = AT91SAM9G45_ID_DMA,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -91,8 +91,8 @@ static struct resource usbh_ohci_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_UHPHS,
-- .end = AT91SAM9G45_ID_UHPHS,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -153,8 +153,8 @@ static struct resource usbh_ehci_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_UHPHS,
-- .end = AT91SAM9G45_ID_UHPHS,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -210,8 +210,8 @@ static struct resource usba_udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [2] = {
-- .start = AT91SAM9G45_ID_UDPHS,
-- .end = AT91SAM9G45_ID_UDPHS,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -293,8 +293,8 @@ static struct resource eth_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_EMAC,
-- .end = AT91SAM9G45_ID_EMAC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -367,8 +367,8 @@ static struct resource mmc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_MCI0,
-- .end = AT91SAM9G45_ID_MCI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -392,8 +392,8 @@ static struct resource mmc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_MCI1,
-- .end = AT91SAM9G45_ID_MCI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -643,8 +643,8 @@ static struct resource twi0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_TWI0,
-- .end = AT91SAM9G45_ID_TWI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -663,8 +663,8 @@ static struct resource twi1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_TWI1,
-- .end = AT91SAM9G45_ID_TWI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -718,8 +718,8 @@ static struct resource spi0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_SPI0,
-- .end = AT91SAM9G45_ID_SPI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -744,8 +744,8 @@ static struct resource spi1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_SPI1,
-- .end = AT91SAM9G45_ID_SPI1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -832,8 +832,8 @@ static struct resource ac97_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_AC97C,
-- .end = AT91SAM9G45_ID_AC97C,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -885,8 +885,8 @@ struct resource isi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_ISI,
-- .end = AT91SAM9G45_ID_ISI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -977,8 +977,8 @@ static struct resource lcdc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_LCDC,
-- .end = AT91SAM9G45_ID_LCDC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1052,8 +1052,8 @@ static struct resource tcb0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_TCB,
-- .end = AT91SAM9G45_ID_TCB,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1073,8 +1073,8 @@ static struct resource tcb1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_TCB,
-- .end = AT91SAM9G45_ID_TCB,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1108,8 +1108,8 @@ static struct resource rtc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1145,8 +1145,8 @@ static struct resource tsadcc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_TSC,
-- .end = AT91SAM9G45_ID_TSC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
- .flags = IORESOURCE_IRQ,
- }
- };
-@@ -1300,8 +1300,8 @@ static struct resource pwm_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_PWMC,
-- .end = AT91SAM9G45_ID_PWMC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1353,8 +1353,8 @@ static struct resource ssc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_SSC0,
-- .end = AT91SAM9G45_ID_SSC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1395,8 +1395,8 @@ static struct resource ssc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_SSC1,
-- .end = AT91SAM9G45_ID_SSC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1475,8 +1475,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1513,8 +1513,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_US0,
-- .end = AT91SAM9G45_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1556,8 +1556,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_US1,
-- .end = AT91SAM9G45_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1599,8 +1599,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_US2,
-- .end = AT91SAM9G45_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1642,8 +1642,8 @@ static struct resource uart3_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9G45_ID_US3,
-- .end = AT91SAM9G45_ID_US3,
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
-index e420085..72ce50a 100644
---- a/arch/arm/mach-at91/at91sam9rl.c
-+++ b/arch/arm/mach-at91/at91sam9rl.c
-@@ -19,6 +19,7 @@
- #include <mach/cpu.h>
- #include <mach/at91_dbgu.h>
- #include <mach/at91sam9rl.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/at91_rstc.h>
-
-diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
-index 9c0b148..f09fff9 100644
---- a/arch/arm/mach-at91/at91sam9rl_devices.c
-+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
-@@ -41,8 +41,8 @@ static struct resource hdmac_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [2] = {
-- .start = AT91SAM9RL_ID_DMA,
-- .end = AT91SAM9RL_ID_DMA,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -84,8 +84,8 @@ static struct resource usba_udc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [2] = {
-- .start = AT91SAM9RL_ID_UDPHS,
-- .end = AT91SAM9RL_ID_UDPHS,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -172,8 +172,8 @@ static struct resource mmc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_MCI,
-- .end = AT91SAM9RL_ID_MCI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -339,8 +339,8 @@ static struct resource twi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_TWI0,
-- .end = AT91SAM9RL_ID_TWI0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -383,8 +383,8 @@ static struct resource spi_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_SPI,
-- .end = AT91SAM9RL_ID_SPI,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -452,8 +452,8 @@ static struct resource ac97_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_AC97C,
-- .end = AT91SAM9RL_ID_AC97C,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -507,8 +507,8 @@ static struct resource lcdc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_LCDC,
-- .end = AT91SAM9RL_ID_LCDC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -574,18 +574,18 @@ static struct resource tcb_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_TC0,
-- .end = AT91SAM9RL_ID_TC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
-- .start = AT91SAM9RL_ID_TC1,
-- .end = AT91SAM9RL_ID_TC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
-- .start = AT91SAM9RL_ID_TC2,
-- .end = AT91SAM9RL_ID_TC2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -621,8 +621,8 @@ static struct resource tsadcc_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_TSC,
-- .end = AT91SAM9RL_ID_TSC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
- .flags = IORESOURCE_IRQ,
- }
- };
-@@ -768,8 +768,8 @@ static struct resource pwm_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_PWMC,
-- .end = AT91SAM9RL_ID_PWMC,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -821,8 +821,8 @@ static struct resource ssc0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_SSC0,
-- .end = AT91SAM9RL_ID_SSC0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -863,8 +863,8 @@ static struct resource ssc1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_SSC1,
-- .end = AT91SAM9RL_ID_SSC1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -943,8 +943,8 @@ static struct resource dbgu_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91_ID_SYS,
-- .end = AT91_ID_SYS,
-+ .start = NR_IRQS_LEGACY + AT91_ID_SYS,
-+ .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -981,8 +981,8 @@ static struct resource uart0_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_US0,
-- .end = AT91SAM9RL_ID_US0,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1032,8 +1032,8 @@ static struct resource uart1_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_US1,
-- .end = AT91SAM9RL_ID_US1,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1075,8 +1075,8 @@ static struct resource uart2_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_US2,
-- .end = AT91SAM9RL_ID_US2,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
- };
-@@ -1118,8 +1118,8 @@ static struct resource uart3_resources[] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = AT91SAM9RL_ID_US3,
-- .end = AT91SAM9RL_ID_US3,
-+ .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
-+ .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
- };
-diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
-index d62fe09..4c0f5fd 100644
---- a/arch/arm/mach-at91/at91x40.c
-+++ b/arch/arm/mach-at91/at91x40.c
-@@ -17,6 +17,7 @@
- #include <asm/system_misc.h>
- #include <asm/mach/arch.h>
- #include <mach/at91x40.h>
-+#include <mach/at91_aic.h>
- #include <mach/at91_st.h>
- #include <mach/timex.h>
- #include "generic.h"
-diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
-index 7867378..fd42a85 100644
---- a/arch/arm/mach-at91/include/mach/at91_aic.h
-+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
-@@ -28,6 +28,9 @@ extern void __iomem *at91_aic_base;
- .extern at91_aic_base
- #endif
-
-+/* Number of irq lines managed by AIC */
-+#define NR_AIC_IRQS 32
-+
- #define AT91_AIC_IRQ_MIN_PRIORITY 0
- #define AT91_AIC_IRQ_MAX_PRIORITY 7
-
-diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
-index 2d510ee..cab60d5 100644
---- a/arch/arm/mach-at91/include/mach/irqs.h
-+++ b/arch/arm/mach-at91/include/mach/irqs.h
-@@ -22,18 +22,6 @@
- #define __ASM_ARCH_IRQS_H
-
- #include <linux/io.h>
--#include <mach/at91_aic.h>
--
--#define NR_AIC_IRQS 32
--
--
--/*
-- * IRQ interrupt symbols are the AT91xxx_ID_* symbols
-- * for IRQs handled directly through the AIC, or else the AT91_PIN_*
-- * symbols in gpio.h for ones handled indirectly as GPIOs.
-- * We make provision for 5 banks of GPIO.
-- */
--#define NR_IRQS (NR_AIC_IRQS + (5 * 32))
-
- /* FIQ is AIC source 0. */
- #define FIQ_START AT91_ID_FIQ
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index 390d4df..75ca2f4 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -41,6 +41,8 @@
- #include <asm/mach/irq.h>
- #include <asm/mach/map.h>
-
-+#include <mach/at91_aic.h>
-+
- void __iomem *at91_aic_base;
- static struct irq_domain *at91_aic_domain;
- static struct device_node *at91_aic_np;
-@@ -302,11 +304,11 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
- */
- for (i = 0; i < NR_AIC_IRQS; i++) {
- /* Put hardware irq number in Source Vector Register: */
-- at91_aic_write(AT91_AIC_SVR(i), i);
-+ at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
- /* Active Low interrupt, with the specified priority */
- at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
-
-- irq_set_chip_and_handler(i, &at91_aic_chip, handle_fasteoi_irq);
-+ irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-
-diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
-index 1bfaad6..2c2d865 100644
---- a/arch/arm/mach-at91/pm.c
-+++ b/arch/arm/mach-at91/pm.c
-@@ -25,6 +25,7 @@
- #include <asm/mach/time.h>
- #include <asm/mach/irq.h>
-
-+#include <mach/at91_aic.h>
- #include <mach/at91_pmc.h>
- #include <mach/cpu.h>
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 908da403154b9fc68fdefdca20cc4049cd13c7b9 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 30 May 2012 10:01:09 +0200
+Subject: ARM: at91: add AIC5 support
+
+commit c4b68520dc0ec96153bc0d87bca5ffba508edfcf upstream.
+
+The number of lines of AIC5 has increased from 32 to 128. Due to this
+increase, a source select register has been introduced for the interrupt
+line selection. Moreover, register mapping has been changed. For that reasons,
+we need some dedicated callbacks for AIC5.
+Power management is also concerned by these changes. On suspend, we can't get
+the whole interrupt mask register as before, we have to read this register 128
+times. To reduce this overhead, a snapshot of the whole IMR is maintained.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/generic.h | 2 +
+ arch/arm/mach-at91/include/mach/at91_aic.h | 26 +++
+ arch/arm/mach-at91/irq.c | 343 ++++++++++++++++++++++++-----
+ 3 files changed, 314 insertions(+), 57 deletions(-)
+
+diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
+index 0a60bf8..f496506 100644
+--- a/arch/arm/mach-at91/generic.h
++++ b/arch/arm/mach-at91/generic.h
+@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
+ extern void __init at91_aic_init(unsigned int priority[]);
+ extern int __init at91_aic_of_init(struct device_node *node,
+ struct device_node *parent);
++extern int __init at91_aic5_of_init(struct device_node *node,
++ struct device_node *parent);
+
+
+ /* Timer */
+diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
+index fd42a85..eaea661 100644
+--- a/arch/arm/mach-at91/include/mach/at91_aic.h
++++ b/arch/arm/mach-at91/include/mach/at91_aic.h
+@@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base;
+
+ /* Number of irq lines managed by AIC */
+ #define NR_AIC_IRQS 32
++#define NR_AIC5_IRQS 128
++
++#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */
++#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */
+
+ #define AT91_AIC_IRQ_MIN_PRIORITY 0
+ #define AT91_AIC_IRQ_MAX_PRIORITY 7
+
+ #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
++#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */
+ #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
+ #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
+ #define AT91_AIC_SRCTYPE_LOW (0 << 5)
+@@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base;
+ #define AT91_AIC_SRCTYPE_RISING (3 << 5)
+
+ #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */
++#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */
+ #define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */
++#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */
++#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_ISR 0x108 /* Interrupt Status Register */
++#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */
+ #define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */
+
+ #define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */
++#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */
++#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */
++#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */
++#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */
+ #define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */
++#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */
+ #define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */
++#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */
+ #define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */
+ #define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */
+
+ #define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */
++#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */
+ #define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */
++#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */
+ #define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */
++#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */
+ #define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */
++#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */
+ #define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */
++#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */
+ #define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */
++#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */
+ #define AT91_AIC_DCR 0x138 /* Debug Control Register */
++#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */
+ #define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */
+ #define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */
+
+ #define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */
++#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */
+ #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
++#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */
+ #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
++#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */
+
+ void at91_aic_handle_irq(struct pt_regs *regs);
++void at91_aic5_handle_irq(struct pt_regs *regs);
+
+ #endif
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index 75ca2f4..c5eaaa0 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -23,6 +23,7 @@
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/mm.h>
++#include <linux/bitmap.h>
+ #include <linux/types.h>
+ #include <linux/irq.h>
+ #include <linux/of.h>
+@@ -46,9 +47,116 @@
+ void __iomem *at91_aic_base;
+ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
++static unsigned int n_irqs = NR_AIC_IRQS;
++static unsigned long at91_aic_caps = 0;
+ static unsigned int *at91_aic_irq_priorities;
+
+-asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
++/* AIC5 introduces a Source Select Register */
++#define AT91_AIC_CAP_AIC5 (1 << 0)
++#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5)
++
++#ifdef CONFIG_PM
++
++static unsigned long *wakeups;
++static unsigned long *backups;
++
++#define set_backup(bit) set_bit(bit, backups)
++#define clear_backup(bit) clear_bit(bit, backups)
++
++static int at91_aic_pm_init(void)
++{
++ backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
++ if (!backups)
++ return -ENOMEM;
++
++ wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
++ if (!wakeups) {
++ kfree(backups);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static int at91_aic_set_wake(struct irq_data *d, unsigned value)
++{
++ if (unlikely(d->hwirq >= n_irqs))
++ return -EINVAL;
++
++ if (value)
++ set_bit(d->hwirq, wakeups);
++ else
++ clear_bit(d->hwirq, wakeups);
++
++ return 0;
++}
++
++void at91_irq_suspend(void)
++{
++ int i = 0, bit;
++
++ if (has_aic5()) {
++ /* disable enabled irqs */
++ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ i = bit;
++ }
++ /* enable wakeup irqs */
++ i = 0;
++ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ i = bit;
++ }
++ } else {
++ at91_aic_write(AT91_AIC_IDCR, *backups);
++ at91_aic_write(AT91_AIC_IECR, *wakeups);
++ }
++}
++
++void at91_irq_resume(void)
++{
++ int i = 0, bit;
++
++ if (has_aic5()) {
++ /* disable wakeup irqs */
++ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ i = bit;
++ }
++ /* enable irqs disabled for suspend */
++ i = 0;
++ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
++ at91_aic_write(AT91_AIC5_SSR,
++ bit & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ i = bit;
++ }
++ } else {
++ at91_aic_write(AT91_AIC_IDCR, *wakeups);
++ at91_aic_write(AT91_AIC_IECR, *backups);
++ }
++}
++
++#else
++static inline int at91_aic_pm_init(void)
++{
++ return 0;
++}
++
++#define set_backup(bit)
++#define clear_backup(bit)
++#define at91_aic_set_wake NULL
++
++#endif /* CONFIG_PM */
++
++asmlinkage void __exception_irq_entry
++at91_aic_handle_irq(struct pt_regs *regs)
+ {
+ u32 irqnr;
+ u32 irqstat;
+@@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
+ handle_IRQ(irqnr, regs);
+ }
+
++asmlinkage void __exception_irq_entry
++at91_aic5_handle_irq(struct pt_regs *regs)
++{
++ u32 irqnr;
++ u32 irqstat;
++
++ irqnr = at91_aic_read(AT91_AIC5_IVR);
++ irqstat = at91_aic_read(AT91_AIC5_ISR);
++
++ if (!irqstat)
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++ else
++ handle_IRQ(irqnr, regs);
++}
++
+ static void at91_aic_mask_irq(struct irq_data *d)
+ {
+ /* Disable interrupt on AIC */
+ at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
++ /* Update ISR cache */
++ clear_backup(d->hwirq);
++}
++
++static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
++{
++ /* Disable interrupt on AIC5 */
++ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ /* Update ISR cache */
++ clear_backup(d->hwirq);
+ }
+
+ static void at91_aic_unmask_irq(struct irq_data *d)
+ {
+ /* Enable interrupt on AIC */
+ at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
++ /* Update ISR cache */
++ set_backup(d->hwirq);
++}
++
++static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
++{
++ /* Enable interrupt on AIC5 */
++ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IECR, 1);
++ /* Update ISR cache */
++ set_backup(d->hwirq);
+ }
+
+ static void at91_aic_eoi(struct irq_data *d)
+@@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d)
+ at91_aic_write(AT91_AIC_EOICR, 0);
+ }
+
+-unsigned int at91_extern_irq;
++static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
++{
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++}
+
+-#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
++unsigned long *at91_extern_irq;
+
+-static int at91_aic_set_type(struct irq_data *d, unsigned type)
++#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
++
++static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
+ {
+- unsigned int smr, srctype;
++ int srctype;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+@@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
+ if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
+ srctype = AT91_AIC_SRCTYPE_LOW;
+ else
+- return -EINVAL;
++ srctype = -EINVAL;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
+ srctype = AT91_AIC_SRCTYPE_FALLING;
+ else
+- return -EINVAL;
++ srctype = -EINVAL;
+ break;
+ default:
+- return -EINVAL;
++ srctype = -EINVAL;
+ }
+
+- smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
+- at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
+- return 0;
++ return srctype;
+ }
+
+-#ifdef CONFIG_PM
+-
+-static u32 wakeups;
+-static u32 backups;
+-
+-static int at91_aic_set_wake(struct irq_data *d, unsigned value)
++static int at91_aic_set_type(struct irq_data *d, unsigned type)
+ {
+- if (unlikely(d->hwirq >= NR_AIC_IRQS))
+- return -EINVAL;
+-
+- if (value)
+- wakeups |= (1 << d->hwirq);
+- else
+- wakeups &= ~(1 << d->hwirq);
++ unsigned int smr;
++ int srctype;
++
++ srctype = at91_aic_compute_srctype(d, type);
++ if (srctype < 0)
++ return srctype;
++
++ if (has_aic5()) {
++ at91_aic_write(AT91_AIC5_SSR,
++ d->hwirq & AT91_AIC5_INTSEL_MSK);
++ smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
++ at91_aic_write(AT91_AIC5_SMR, smr | srctype);
++ } else {
++ smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
++ & ~AT91_AIC_SRCTYPE;
++ at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
++ }
+
+ return 0;
+ }
+
+-void at91_irq_suspend(void)
+-{
+- backups = at91_aic_read(AT91_AIC_IMR);
+- at91_aic_write(AT91_AIC_IDCR, backups);
+- at91_aic_write(AT91_AIC_IECR, wakeups);
+-}
+-
+-void at91_irq_resume(void)
+-{
+- at91_aic_write(AT91_AIC_IDCR, wakeups);
+- at91_aic_write(AT91_AIC_IECR, backups);
+-}
+-
+-#else
+-#define at91_aic_set_wake NULL
+-#endif
+-
+ static struct irq_chip at91_aic_chip = {
+ .name = "AIC",
+ .irq_mask = at91_aic_mask_irq,
+@@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
+ at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
+ }
+
++static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
++{
++ int i;
++
++ /*
++ * Perform 8 End Of Interrupt Command to make sure AIC
++ * will not Lock out nIRQ
++ */
++ for (i = 0; i < 8; i++)
++ at91_aic_write(AT91_AIC5_EOICR, 0);
++
++ /*
++ * Spurious Interrupt ID in Spurious Vector Register.
++ * When there is no current interrupt, the IRQ Vector Register
++ * reads the value stored in AIC_SPU
++ */
++ at91_aic_write(AT91_AIC5_SPU, spu_vector);
++
++ /* No debugging in AIC: Debug (Protect) Control Register */
++ at91_aic_write(AT91_AIC5_DCR, 0);
++
++ /* Disable and clear all interrupts initially */
++ for (i = 0; i < n_irqs; i++) {
++ at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
++ at91_aic_write(AT91_AIC5_IDCR, 1);
++ at91_aic_write(AT91_AIC5_ICCR, 1);
++ }
++}
++
+ #if defined(CONFIG_OF)
+ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+@@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ return 0;
+ }
+
++static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
++
++ /* Put virq number in Source Vector Register */
++ at91_aic_write(AT91_AIC5_SVR, virq);
++
++ /* Active Low interrupt, with priority */
++ at91_aic_write(AT91_AIC5_SMR,
++ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
++
++ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
++ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
++
++ return 0;
++}
++
+ static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+ {
+ if (WARN_ON(intsize < 3))
+ return -EINVAL;
+- if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
++ if (WARN_ON(intspec[0] >= n_irqs))
+ return -EINVAL;
+ if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
+ || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
+@@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = {
+ .xlate = at91_aic_irq_domain_xlate,
+ };
+
+-int __init at91_aic_of_init(struct device_node *node,
+- struct device_node *parent)
++int __init at91_aic_of_common_init(struct device_node *node,
++ struct device_node *parent)
+ {
+ struct property *prop;
+ const __be32 *p;
+ u32 val;
+
+- at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
++ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
++ * sizeof(*at91_extern_irq), GFP_KERNEL);
++ if (!at91_extern_irq)
++ return -ENOMEM;
++
++ if (at91_aic_pm_init()) {
++ kfree(at91_extern_irq);
++ return -ENOMEM;
++ }
++
++ at91_aic_irq_priorities = kzalloc(n_irqs
+ * sizeof(*at91_aic_irq_priorities),
+ GFP_KERNEL);
+ if (!at91_aic_irq_priorities)
+@@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node,
+ at91_aic_base = of_iomap(node, 0);
+ at91_aic_np = node;
+
+- at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
++ at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
+ &at91_aic_irq_ops, NULL);
+ if (!at91_aic_domain)
+ panic("Unable to add AIC irq domain (DT)\n");
+
+- at91_extern_irq = 0;
+ of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
+- if (val > 31)
+- pr_warn("AIC: external irq %d > 31 skip it\n", val);
++ if (val >= n_irqs)
++ pr_warn("AIC: external irq %d >= %d skip it\n",
++ val, n_irqs);
+ else
+- at91_extern_irq |= (1 << val);
++ set_bit(val, at91_extern_irq);
+ }
+
+ irq_set_default_host(at91_aic_domain);
+
+- at91_aic_hw_init(NR_AIC_IRQS);
++ return 0;
++}
++
++int __init at91_aic_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int err;
++
++ err = at91_aic_of_common_init(node, parent);
++ if (err)
++ return err;
++
++ at91_aic_hw_init(n_irqs);
++
++ return 0;
++}
++
++int __init at91_aic5_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int err;
++
++ at91_aic_caps |= AT91_AIC_CAP_AIC5;
++ n_irqs = NR_AIC5_IRQS;
++ at91_aic_chip.irq_ack = at91_aic5_mask_irq;
++ at91_aic_chip.irq_mask = at91_aic5_mask_irq;
++ at91_aic_chip.irq_unmask = at91_aic5_unmask_irq;
++ at91_aic_chip.irq_eoi = at91_aic5_eoi;
++ at91_aic_irq_ops.map = at91_aic5_irq_map;
++
++ err = at91_aic_of_common_init(node, parent);
++ if (err)
++ return err;
++
++ at91_aic5_hw_init(n_irqs);
+
+ return 0;
+ }
+@@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node,
+ /*
+ * Initialize the AIC interrupt controller.
+ */
+-void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
++void __init at91_aic_init(unsigned int *priority)
+ {
+ unsigned int i;
+ int irq_base;
+
++ if (at91_aic_pm_init())
++ panic("Unable to allocate bit maps\n");
++
+ at91_aic_base = ioremap(AT91_AIC, 512);
+ if (!at91_aic_base)
+ panic("Unable to ioremap AIC registers\n");
+
+ /* Add irq domain for AIC */
+- irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
++ irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
+ if (irq_base < 0) {
+ WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
+ irq_base = 0;
+ }
+- at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
++ at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
+ irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+@@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+ * The IVR is used by macro get_irqnr_and_base to read and verify.
+ * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
+ */
+- for (i = 0; i < NR_AIC_IRQS; i++) {
++ for (i = 0; i < n_irqs; i++) {
+ /* Put hardware irq number in Source Vector Register: */
+ at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
+ /* Active Low interrupt, with the specified priority */
+ at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
+-
+ irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+
+- at91_aic_hw_init(NR_AIC_IRQS);
++ at91_aic_hw_init(n_irqs);
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 45fba6f03c7b2ec9fd1b0d37715c6e8b9ebb3a4d Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Thu, 14 Jun 2012 15:41:04 +0200
-Subject: ARM: at91: remove mach/irqs.h
-
-mach/irqs only defines FIQ_START which doesn't appear to be used anywhere
-so remove it.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/include/mach/irqs.h | 29 -----------------------------
- 1 file changed, 29 deletions(-)
- delete mode 100644 arch/arm/mach-at91/include/mach/irqs.h
-
-diff --git a/arch/arm/mach-at91/include/mach/irqs.h b/arch/arm/mach-at91/include/mach/irqs.h
-deleted file mode 100644
-index cab60d5..0000000
---- a/arch/arm/mach-at91/include/mach/irqs.h
-+++ /dev/null
-@@ -1,29 +0,0 @@
--/*
-- * arch/arm/mach-at91/include/mach/irqs.h
-- *
-- * Copyright (C) 2004 SAN People
-- *
-- * 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.
-- *
-- * This program 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 General Public License for more details.
-- *
-- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-- */
--
--#ifndef __ASM_ARCH_IRQS_H
--#define __ASM_ARCH_IRQS_H
--
--#include <linux/io.h>
--
--/* FIQ is AIC source 0. */
--#define FIQ_START AT91_ID_FIQ
--
--#endif
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 2ab4fd505a722e59d1a7b02d4b8fe5a89bc2f761 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 30 May 2012 10:01:09 +0200
-Subject: ARM: at91: add AIC5 support
-
-The number of lines of AIC5 has increased from 32 to 128. Due to this
-increase, a source select register has been introduced for the interrupt
-line selection. Moreover, register mapping has been changed. For that reasons,
-we need some dedicated callbacks for AIC5.
-Power management is also concerned by these changes. On suspend, we can't get
-the whole interrupt mask register as before, we have to read this register 128
-times. To reduce this overhead, a snapshot of the whole IMR is maintained.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/generic.h | 2 +
- arch/arm/mach-at91/include/mach/at91_aic.h | 26 +++
- arch/arm/mach-at91/irq.c | 343 ++++++++++++++++++++++++-----
- 3 files changed, 314 insertions(+), 57 deletions(-)
-
-diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
-index 0a60bf8..f496506 100644
---- a/arch/arm/mach-at91/generic.h
-+++ b/arch/arm/mach-at91/generic.h
-@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
- extern void __init at91_aic_init(unsigned int priority[]);
- extern int __init at91_aic_of_init(struct device_node *node,
- struct device_node *parent);
-+extern int __init at91_aic5_of_init(struct device_node *node,
-+ struct device_node *parent);
-
-
- /* Timer */
-diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
-index fd42a85..eaea661 100644
---- a/arch/arm/mach-at91/include/mach/at91_aic.h
-+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
-@@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base;
-
- /* Number of irq lines managed by AIC */
- #define NR_AIC_IRQS 32
-+#define NR_AIC5_IRQS 128
-+
-+#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */
-+#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */
-
- #define AT91_AIC_IRQ_MIN_PRIORITY 0
- #define AT91_AIC_IRQ_MAX_PRIORITY 7
-
- #define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
-+#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */
- #define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
- #define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
- #define AT91_AIC_SRCTYPE_LOW (0 << 5)
-@@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base;
- #define AT91_AIC_SRCTYPE_RISING (3 << 5)
-
- #define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */
-+#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */
- #define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */
-+#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */
- #define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */
-+#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */
- #define AT91_AIC_ISR 0x108 /* Interrupt Status Register */
-+#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */
- #define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */
-
- #define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */
-+#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */
-+#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */
-+#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */
-+#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */
- #define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */
-+#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */
- #define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */
-+#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */
- #define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */
- #define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */
-
- #define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */
-+#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */
- #define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */
-+#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */
- #define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */
-+#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */
- #define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */
-+#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */
- #define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */
-+#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */
- #define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */
-+#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */
- #define AT91_AIC_DCR 0x138 /* Debug Control Register */
-+#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */
- #define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */
- #define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */
-
- #define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */
-+#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */
- #define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
-+#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */
- #define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
-+#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */
-
- void at91_aic_handle_irq(struct pt_regs *regs);
-+void at91_aic5_handle_irq(struct pt_regs *regs);
-
- #endif
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index 75ca2f4..c5eaaa0 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -23,6 +23,7 @@
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/mm.h>
-+#include <linux/bitmap.h>
- #include <linux/types.h>
- #include <linux/irq.h>
- #include <linux/of.h>
-@@ -46,9 +47,116 @@
- void __iomem *at91_aic_base;
- static struct irq_domain *at91_aic_domain;
- static struct device_node *at91_aic_np;
-+static unsigned int n_irqs = NR_AIC_IRQS;
-+static unsigned long at91_aic_caps = 0;
- static unsigned int *at91_aic_irq_priorities;
-
--asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
-+/* AIC5 introduces a Source Select Register */
-+#define AT91_AIC_CAP_AIC5 (1 << 0)
-+#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5)
-+
-+#ifdef CONFIG_PM
-+
-+static unsigned long *wakeups;
-+static unsigned long *backups;
-+
-+#define set_backup(bit) set_bit(bit, backups)
-+#define clear_backup(bit) clear_bit(bit, backups)
-+
-+static int at91_aic_pm_init(void)
-+{
-+ backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
-+ if (!backups)
-+ return -ENOMEM;
-+
-+ wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
-+ if (!wakeups) {
-+ kfree(backups);
-+ return -ENOMEM;
-+ }
-+
-+ return 0;
-+}
-+
-+static int at91_aic_set_wake(struct irq_data *d, unsigned value)
-+{
-+ if (unlikely(d->hwirq >= n_irqs))
-+ return -EINVAL;
-+
-+ if (value)
-+ set_bit(d->hwirq, wakeups);
-+ else
-+ clear_bit(d->hwirq, wakeups);
-+
-+ return 0;
-+}
-+
-+void at91_irq_suspend(void)
-+{
-+ int i = 0, bit;
-+
-+ if (has_aic5()) {
-+ /* disable enabled irqs */
-+ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
-+ at91_aic_write(AT91_AIC5_SSR,
-+ bit & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IDCR, 1);
-+ i = bit;
-+ }
-+ /* enable wakeup irqs */
-+ i = 0;
-+ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
-+ at91_aic_write(AT91_AIC5_SSR,
-+ bit & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IECR, 1);
-+ i = bit;
-+ }
-+ } else {
-+ at91_aic_write(AT91_AIC_IDCR, *backups);
-+ at91_aic_write(AT91_AIC_IECR, *wakeups);
-+ }
-+}
-+
-+void at91_irq_resume(void)
-+{
-+ int i = 0, bit;
-+
-+ if (has_aic5()) {
-+ /* disable wakeup irqs */
-+ while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
-+ at91_aic_write(AT91_AIC5_SSR,
-+ bit & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IDCR, 1);
-+ i = bit;
-+ }
-+ /* enable irqs disabled for suspend */
-+ i = 0;
-+ while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
-+ at91_aic_write(AT91_AIC5_SSR,
-+ bit & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IECR, 1);
-+ i = bit;
-+ }
-+ } else {
-+ at91_aic_write(AT91_AIC_IDCR, *wakeups);
-+ at91_aic_write(AT91_AIC_IECR, *backups);
-+ }
-+}
-+
-+#else
-+static inline int at91_aic_pm_init(void)
-+{
-+ return 0;
-+}
-+
-+#define set_backup(bit)
-+#define clear_backup(bit)
-+#define at91_aic_set_wake NULL
-+
-+#endif /* CONFIG_PM */
-+
-+asmlinkage void __exception_irq_entry
-+at91_aic_handle_irq(struct pt_regs *regs)
- {
- u32 irqnr;
- u32 irqstat;
-@@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
- handle_IRQ(irqnr, regs);
- }
-
-+asmlinkage void __exception_irq_entry
-+at91_aic5_handle_irq(struct pt_regs *regs)
-+{
-+ u32 irqnr;
-+ u32 irqstat;
-+
-+ irqnr = at91_aic_read(AT91_AIC5_IVR);
-+ irqstat = at91_aic_read(AT91_AIC5_ISR);
-+
-+ if (!irqstat)
-+ at91_aic_write(AT91_AIC5_EOICR, 0);
-+ else
-+ handle_IRQ(irqnr, regs);
-+}
-+
- static void at91_aic_mask_irq(struct irq_data *d)
- {
- /* Disable interrupt on AIC */
- at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
-+ /* Update ISR cache */
-+ clear_backup(d->hwirq);
-+}
-+
-+static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
-+{
-+ /* Disable interrupt on AIC5 */
-+ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IDCR, 1);
-+ /* Update ISR cache */
-+ clear_backup(d->hwirq);
- }
-
- static void at91_aic_unmask_irq(struct irq_data *d)
- {
- /* Enable interrupt on AIC */
- at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
-+ /* Update ISR cache */
-+ set_backup(d->hwirq);
-+}
-+
-+static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
-+{
-+ /* Enable interrupt on AIC5 */
-+ at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IECR, 1);
-+ /* Update ISR cache */
-+ set_backup(d->hwirq);
- }
-
- static void at91_aic_eoi(struct irq_data *d)
-@@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d)
- at91_aic_write(AT91_AIC_EOICR, 0);
- }
-
--unsigned int at91_extern_irq;
-+static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
-+{
-+ at91_aic_write(AT91_AIC5_EOICR, 0);
-+}
-
--#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
-+unsigned long *at91_extern_irq;
-
--static int at91_aic_set_type(struct irq_data *d, unsigned type)
-+#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
-+
-+static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
- {
-- unsigned int smr, srctype;
-+ int srctype;
-
- switch (type) {
- case IRQ_TYPE_LEVEL_HIGH:
-@@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
- if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
- srctype = AT91_AIC_SRCTYPE_LOW;
- else
-- return -EINVAL;
-+ srctype = -EINVAL;
- break;
- case IRQ_TYPE_EDGE_FALLING:
- if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
- srctype = AT91_AIC_SRCTYPE_FALLING;
- else
-- return -EINVAL;
-+ srctype = -EINVAL;
- break;
- default:
-- return -EINVAL;
-+ srctype = -EINVAL;
- }
-
-- smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
-- at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
-- return 0;
-+ return srctype;
- }
-
--#ifdef CONFIG_PM
--
--static u32 wakeups;
--static u32 backups;
--
--static int at91_aic_set_wake(struct irq_data *d, unsigned value)
-+static int at91_aic_set_type(struct irq_data *d, unsigned type)
- {
-- if (unlikely(d->hwirq >= NR_AIC_IRQS))
-- return -EINVAL;
--
-- if (value)
-- wakeups |= (1 << d->hwirq);
-- else
-- wakeups &= ~(1 << d->hwirq);
-+ unsigned int smr;
-+ int srctype;
-+
-+ srctype = at91_aic_compute_srctype(d, type);
-+ if (srctype < 0)
-+ return srctype;
-+
-+ if (has_aic5()) {
-+ at91_aic_write(AT91_AIC5_SSR,
-+ d->hwirq & AT91_AIC5_INTSEL_MSK);
-+ smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
-+ at91_aic_write(AT91_AIC5_SMR, smr | srctype);
-+ } else {
-+ smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
-+ & ~AT91_AIC_SRCTYPE;
-+ at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
-+ }
-
- return 0;
- }
-
--void at91_irq_suspend(void)
--{
-- backups = at91_aic_read(AT91_AIC_IMR);
-- at91_aic_write(AT91_AIC_IDCR, backups);
-- at91_aic_write(AT91_AIC_IECR, wakeups);
--}
--
--void at91_irq_resume(void)
--{
-- at91_aic_write(AT91_AIC_IDCR, wakeups);
-- at91_aic_write(AT91_AIC_IECR, backups);
--}
--
--#else
--#define at91_aic_set_wake NULL
--#endif
--
- static struct irq_chip at91_aic_chip = {
- .name = "AIC",
- .irq_mask = at91_aic_mask_irq,
-@@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
- at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
- }
-
-+static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
-+{
-+ int i;
-+
-+ /*
-+ * Perform 8 End Of Interrupt Command to make sure AIC
-+ * will not Lock out nIRQ
-+ */
-+ for (i = 0; i < 8; i++)
-+ at91_aic_write(AT91_AIC5_EOICR, 0);
-+
-+ /*
-+ * Spurious Interrupt ID in Spurious Vector Register.
-+ * When there is no current interrupt, the IRQ Vector Register
-+ * reads the value stored in AIC_SPU
-+ */
-+ at91_aic_write(AT91_AIC5_SPU, spu_vector);
-+
-+ /* No debugging in AIC: Debug (Protect) Control Register */
-+ at91_aic_write(AT91_AIC5_DCR, 0);
-+
-+ /* Disable and clear all interrupts initially */
-+ for (i = 0; i < n_irqs; i++) {
-+ at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
-+ at91_aic_write(AT91_AIC5_IDCR, 1);
-+ at91_aic_write(AT91_AIC5_ICCR, 1);
-+ }
-+}
-+
- #if defined(CONFIG_OF)
- static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-@@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- return 0;
- }
-
-+static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
-+ irq_hw_number_t hw)
-+{
-+ at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
-+
-+ /* Put virq number in Source Vector Register */
-+ at91_aic_write(AT91_AIC5_SVR, virq);
-+
-+ /* Active Low interrupt, with priority */
-+ at91_aic_write(AT91_AIC5_SMR,
-+ AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
-+
-+ irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
-+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
-+
-+ return 0;
-+}
-+
- static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_type)
- {
- if (WARN_ON(intsize < 3))
- return -EINVAL;
-- if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
-+ if (WARN_ON(intspec[0] >= n_irqs))
- return -EINVAL;
- if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
- || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
-@@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = {
- .xlate = at91_aic_irq_domain_xlate,
- };
-
--int __init at91_aic_of_init(struct device_node *node,
-- struct device_node *parent)
-+int __init at91_aic_of_common_init(struct device_node *node,
-+ struct device_node *parent)
- {
- struct property *prop;
- const __be32 *p;
- u32 val;
-
-- at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
-+ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
-+ * sizeof(*at91_extern_irq), GFP_KERNEL);
-+ if (!at91_extern_irq)
-+ return -ENOMEM;
-+
-+ if (at91_aic_pm_init()) {
-+ kfree(at91_extern_irq);
-+ return -ENOMEM;
-+ }
-+
-+ at91_aic_irq_priorities = kzalloc(n_irqs
- * sizeof(*at91_aic_irq_priorities),
- GFP_KERNEL);
- if (!at91_aic_irq_priorities)
-@@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node,
- at91_aic_base = of_iomap(node, 0);
- at91_aic_np = node;
-
-- at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
-+ at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
- &at91_aic_irq_ops, NULL);
- if (!at91_aic_domain)
- panic("Unable to add AIC irq domain (DT)\n");
-
-- at91_extern_irq = 0;
- of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
-- if (val > 31)
-- pr_warn("AIC: external irq %d > 31 skip it\n", val);
-+ if (val >= n_irqs)
-+ pr_warn("AIC: external irq %d >= %d skip it\n",
-+ val, n_irqs);
- else
-- at91_extern_irq |= (1 << val);
-+ set_bit(val, at91_extern_irq);
- }
-
- irq_set_default_host(at91_aic_domain);
-
-- at91_aic_hw_init(NR_AIC_IRQS);
-+ return 0;
-+}
-+
-+int __init at91_aic_of_init(struct device_node *node,
-+ struct device_node *parent)
-+{
-+ int err;
-+
-+ err = at91_aic_of_common_init(node, parent);
-+ if (err)
-+ return err;
-+
-+ at91_aic_hw_init(n_irqs);
-+
-+ return 0;
-+}
-+
-+int __init at91_aic5_of_init(struct device_node *node,
-+ struct device_node *parent)
-+{
-+ int err;
-+
-+ at91_aic_caps |= AT91_AIC_CAP_AIC5;
-+ n_irqs = NR_AIC5_IRQS;
-+ at91_aic_chip.irq_ack = at91_aic5_mask_irq;
-+ at91_aic_chip.irq_mask = at91_aic5_mask_irq;
-+ at91_aic_chip.irq_unmask = at91_aic5_unmask_irq;
-+ at91_aic_chip.irq_eoi = at91_aic5_eoi;
-+ at91_aic_irq_ops.map = at91_aic5_irq_map;
-+
-+ err = at91_aic_of_common_init(node, parent);
-+ if (err)
-+ return err;
-+
-+ at91_aic5_hw_init(n_irqs);
-
- return 0;
- }
-@@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node,
- /*
- * Initialize the AIC interrupt controller.
- */
--void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
-+void __init at91_aic_init(unsigned int *priority)
- {
- unsigned int i;
- int irq_base;
-
-+ if (at91_aic_pm_init())
-+ panic("Unable to allocate bit maps\n");
-+
- at91_aic_base = ioremap(AT91_AIC, 512);
- if (!at91_aic_base)
- panic("Unable to ioremap AIC registers\n");
-
- /* Add irq domain for AIC */
-- irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
-+ irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
- if (irq_base < 0) {
- WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
- irq_base = 0;
- }
-- at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
-+ at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
- irq_base, 0,
- &irq_domain_simple_ops, NULL);
-
-@@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
- * The IVR is used by macro get_irqnr_and_base to read and verify.
- * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
- */
-- for (i = 0; i < NR_AIC_IRQS; i++) {
-+ for (i = 0; i < n_irqs; i++) {
- /* Put hardware irq number in Source Vector Register: */
- at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
- /* Active Low interrupt, with the specified priority */
- at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
--
- irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-
-- at91_aic_hw_init(NR_AIC_IRQS);
-+ at91_aic_hw_init(n_irqs);
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 269418c20b0c2e0aaa9da1e46b110a4c9f4b90f9 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 4 Apr 2012 09:27:46 -0600
+Subject: dt: add property iteration helpers
+
+commit c541adc637066407d4cda9db14dcb0e618966a4c upstream.
+
+This patch adds macros of_property_for_each_u32() and
+of_property_for_each_string(), which iterate over an array of values
+within a device-tree property. Usage is for example:
+
+struct property *prop;
+const __be32 *p;
+u32 u;
+of_property_for_each_u32(np, "propname", prop, p, u)
+ printk("U32 value: %x\n", u);
+
+struct property *prop;
+const char *s;
+of_property_for_each_string(np, "propname", prop, s)
+ printk("String value: %s\n", s);
+
+Based on work by Rob Herring <robherring2@gmail.com>
+
+Cc: Grant Likely <grant.likely@secretlab.ca>
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Acked-by: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/of/base.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/of.h | 35 +++++++++++++++++++++++++++++++++++
+ 2 files changed, 76 insertions(+)
+
+--- a/drivers/of/base.c
++++ b/drivers/of/base.c
+@@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *
+ return id;
+ }
+ EXPORT_SYMBOL_GPL(of_alias_get_id);
++
++const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
++ u32 *pu)
++{
++ const void *curv = cur;
++
++ if (!prop)
++ return NULL;
++
++ if (!cur) {
++ curv = prop->value;
++ goto out_val;
++ }
++
++ curv += sizeof(*cur);
++ if (curv >= prop->value + prop->length)
++ return NULL;
++
++out_val:
++ *pu = be32_to_cpup(curv);
++ return curv;
++}
++EXPORT_SYMBOL_GPL(of_prop_next_u32);
++
++const char *of_prop_next_string(struct property *prop, const char *cur)
++{
++ const void *curv = cur;
++
++ if (!prop)
++ return NULL;
++
++ if (!cur)
++ return prop->value;
++
++ curv += strlen(cur) + 1;
++ if (curv >= prop->value + prop->length)
++ return NULL;
++
++ return curv;
++}
++EXPORT_SYMBOL_GPL(of_prop_next_string);
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -260,6 +260,37 @@ extern void of_detach_node(struct device
+ #endif
+
+ #define of_match_ptr(_ptr) (_ptr)
++
++/*
++ * struct property *prop;
++ * const __be32 *p;
++ * u32 u;
++ *
++ * of_property_for_each_u32(np, "propname", prop, p, u)
++ * printk("U32 value: %x\n", u);
++ */
++const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
++ u32 *pu);
++#define of_property_for_each_u32(np, propname, prop, p, u) \
++ for (prop = of_find_property(np, propname, NULL), \
++ p = of_prop_next_u32(prop, NULL, &u); \
++ p; \
++ p = of_prop_next_u32(prop, p, &u))
++
++/*
++ * struct property *prop;
++ * const char *s;
++ *
++ * of_property_for_each_string(np, "propname", prop, s)
++ * printk("String value: %s\n", s);
++ */
++const char *of_prop_next_string(struct property *prop, const char *cur);
++#define of_property_for_each_string(np, propname, prop, s) \
++ for (prop = of_find_property(np, propname, NULL), \
++ s = of_prop_next_string(prop, NULL); \
++ s; \
++ s = of_prop_next_string(prop, s))
++
+ #else /* CONFIG_OF */
+
+ static inline const char* of_node_full_name(struct device_node *np)
+@@ -355,6 +386,10 @@ static inline int of_machine_is_compatib
+
+ #define of_match_ptr(_ptr) NULL
+ #define of_match_node(_matches, _node) NULL
++#define of_property_for_each_u32(np, propname, prop, p, u) \
++ while (0)
++#define of_property_for_each_string(np, propname, prop, s) \
++ while (0)
+ #endif /* CONFIG_OF */
+
+ #ifndef of_node_to_nid
--- /dev/null
+From b6a60e81276efc7c6aa5f37f50f52ac0d8391187 Mon Sep 17 00:00:00 2001
+From: Arnd Bergmann <arnd@arndb.de>
+Date: Wed, 4 Jul 2012 07:45:16 +0000
+Subject: ARM: at91: fix new build errors
+
+commit 14070ade02cc378bc30dae383532768a94805988 upstream.
+
+MULTI_IRQ_HANDLER and SPARSE_IRQ are now required everywhere because
+mach/irqs.h and mach/entry-macros.S are gone but the symbols are
+only selected for AT91SAM9, not for the NOMMU parts.
+
+A few files now need to include linux/io.h directly, which used to
+be included through other headers that have changed.
+
+The new at91_aic_irq_priorities variable is only used with CONFIG_OF
+enabled and should not be visible otherwise.
+
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 4 ++++
+ arch/arm/mach-at91/at91x40.c | 1 +
+ arch/arm/mach-at91/irq.c | 3 ++-
+ drivers/rtc/rtc-at91rm9200.c | 1 +
+ 4 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index 7d0c40a..c8050b1 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -37,6 +37,8 @@ config SOC_AT91SAM9
+ config SOC_AT91RM9200
+ bool "AT91RM9200"
+ select CPU_ARM920T
++ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select GENERIC_CLOCKEVENTS
+ select HAVE_AT91_DBGU0
+
+@@ -142,6 +144,8 @@ config ARCH_AT91SAM9G45
+ config ARCH_AT91X40
+ bool "AT91x40"
+ depends on !MMU
++ select MULTI_IRQ_HANDLER
++ select SPARSE_IRQ
+ select ARCH_USES_GETTIMEOFFSET
+
+ endchoice
+diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
+index 4c0f5fd..46090e6 100644
+--- a/arch/arm/mach-at91/at91x40.c
++++ b/arch/arm/mach-at91/at91x40.c
+@@ -13,6 +13,7 @@
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/irq.h>
++#include <linux/io.h>
+ #include <asm/proc-fns.h>
+ #include <asm/system_misc.h>
+ #include <asm/mach/arch.h>
+diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
+index c5eaaa0..1e02c0e 100644
+--- a/arch/arm/mach-at91/irq.c
++++ b/arch/arm/mach-at91/irq.c
+@@ -49,7 +49,6 @@ static struct irq_domain *at91_aic_domain;
+ static struct device_node *at91_aic_np;
+ static unsigned int n_irqs = NR_AIC_IRQS;
+ static unsigned long at91_aic_caps = 0;
+-static unsigned int *at91_aic_irq_priorities;
+
+ /* AIC5 introduces a Source Select Register */
+ #define AT91_AIC_CAP_AIC5 (1 << 0)
+@@ -359,6 +358,8 @@ static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
+ }
+
+ #if defined(CONFIG_OF)
++static unsigned int *at91_aic_irq_priorities;
++
+ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+ {
+diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
+index f02acb0..a4c78c0 100644
+--- a/drivers/rtc/rtc-at91rm9200.c
++++ b/drivers/rtc/rtc-at91rm9200.c
+@@ -27,6 +27,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioctl.h>
+ #include <linux/completion.h>
++#include <linux/io.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From b0a2eb064f2171838c4562f34eb1e492ce0361d5 Mon Sep 17 00:00:00 2001
-From: Stephen Warren <swarren@nvidia.com>
-Date: Wed, 4 Apr 2012 09:27:46 -0600
-Subject: dt: add property iteration helpers
-
-This patch adds macros of_property_for_each_u32() and
-of_property_for_each_string(), which iterate over an array of values
-within a device-tree property. Usage is for example:
-
-struct property *prop;
-const __be32 *p;
-u32 u;
-of_property_for_each_u32(np, "propname", prop, p, u)
- printk("U32 value: %x\n", u);
-
-struct property *prop;
-const char *s;
-of_property_for_each_string(np, "propname", prop, s)
- printk("String value: %s\n", s);
-
-Based on work by Rob Herring <robherring2@gmail.com>
-
-Cc: Grant Likely <grant.likely@secretlab.ca>
-Signed-off-by: Stephen Warren <swarren@nvidia.com>
-Acked-by: Rob Herring <rob.herring@calxeda.com>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/of/base.c | 41 +++++++++++++++++++++++++++++++++++++++++
- include/linux/of.h | 35 +++++++++++++++++++++++++++++++++++
- 2 files changed, 76 insertions(+)
-
---- a/drivers/of/base.c
-+++ b/drivers/of/base.c
-@@ -1260,3 +1260,44 @@ int of_alias_get_id(struct device_node *
- return id;
- }
- EXPORT_SYMBOL_GPL(of_alias_get_id);
-+
-+const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
-+ u32 *pu)
-+{
-+ const void *curv = cur;
-+
-+ if (!prop)
-+ return NULL;
-+
-+ if (!cur) {
-+ curv = prop->value;
-+ goto out_val;
-+ }
-+
-+ curv += sizeof(*cur);
-+ if (curv >= prop->value + prop->length)
-+ return NULL;
-+
-+out_val:
-+ *pu = be32_to_cpup(curv);
-+ return curv;
-+}
-+EXPORT_SYMBOL_GPL(of_prop_next_u32);
-+
-+const char *of_prop_next_string(struct property *prop, const char *cur)
-+{
-+ const void *curv = cur;
-+
-+ if (!prop)
-+ return NULL;
-+
-+ if (!cur)
-+ return prop->value;
-+
-+ curv += strlen(cur) + 1;
-+ if (curv >= prop->value + prop->length)
-+ return NULL;
-+
-+ return curv;
-+}
-+EXPORT_SYMBOL_GPL(of_prop_next_string);
---- a/include/linux/of.h
-+++ b/include/linux/of.h
-@@ -260,6 +260,37 @@ extern void of_detach_node(struct device
- #endif
-
- #define of_match_ptr(_ptr) (_ptr)
-+
-+/*
-+ * struct property *prop;
-+ * const __be32 *p;
-+ * u32 u;
-+ *
-+ * of_property_for_each_u32(np, "propname", prop, p, u)
-+ * printk("U32 value: %x\n", u);
-+ */
-+const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
-+ u32 *pu);
-+#define of_property_for_each_u32(np, propname, prop, p, u) \
-+ for (prop = of_find_property(np, propname, NULL), \
-+ p = of_prop_next_u32(prop, NULL, &u); \
-+ p; \
-+ p = of_prop_next_u32(prop, p, &u))
-+
-+/*
-+ * struct property *prop;
-+ * const char *s;
-+ *
-+ * of_property_for_each_string(np, "propname", prop, s)
-+ * printk("String value: %s\n", s);
-+ */
-+const char *of_prop_next_string(struct property *prop, const char *cur);
-+#define of_property_for_each_string(np, propname, prop, s) \
-+ for (prop = of_find_property(np, propname, NULL), \
-+ s = of_prop_next_string(prop, NULL); \
-+ s; \
-+ s = of_prop_next_string(prop, s))
-+
- #else /* CONFIG_OF */
-
- static inline const char* of_node_full_name(struct device_node *np)
-@@ -355,6 +386,10 @@ static inline int of_machine_is_compatib
-
- #define of_match_ptr(_ptr) NULL
- #define of_match_node(_matches, _node) NULL
-+#define of_property_for_each_u32(np, propname, prop, p, u) \
-+ while (0)
-+#define of_property_for_each_string(np, propname, prop, s) \
-+ while (0)
- #endif /* CONFIG_OF */
-
- #ifndef of_node_to_nid
+++ /dev/null
-From a00b0ccc24fe0904fa187dd320709da1b6f44c90 Mon Sep 17 00:00:00 2001
-From: Arnd Bergmann <arnd@arndb.de>
-Date: Wed, 4 Jul 2012 07:45:16 +0000
-Subject: ARM: at91: fix new build errors
-
-MULTI_IRQ_HANDLER and SPARSE_IRQ are now required everywhere because
-mach/irqs.h and mach/entry-macros.S are gone but the symbols are
-only selected for AT91SAM9, not for the NOMMU parts.
-
-A few files now need to include linux/io.h directly, which used to
-be included through other headers that have changed.
-
-The new at91_aic_irq_priorities variable is only used with CONFIG_OF
-enabled and should not be visible otherwise.
-
-Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/Kconfig | 4 ++++
- arch/arm/mach-at91/at91x40.c | 1 +
- arch/arm/mach-at91/irq.c | 3 ++-
- drivers/rtc/rtc-at91rm9200.c | 1 +
- 4 files changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
-index 7d0c40a..c8050b1 100644
---- a/arch/arm/mach-at91/Kconfig
-+++ b/arch/arm/mach-at91/Kconfig
-@@ -37,6 +37,8 @@ config SOC_AT91SAM9
- config SOC_AT91RM9200
- bool "AT91RM9200"
- select CPU_ARM920T
-+ select MULTI_IRQ_HANDLER
-+ select SPARSE_IRQ
- select GENERIC_CLOCKEVENTS
- select HAVE_AT91_DBGU0
-
-@@ -142,6 +144,8 @@ config ARCH_AT91SAM9G45
- config ARCH_AT91X40
- bool "AT91x40"
- depends on !MMU
-+ select MULTI_IRQ_HANDLER
-+ select SPARSE_IRQ
- select ARCH_USES_GETTIMEOFFSET
-
- endchoice
-diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
-index 4c0f5fd..46090e6 100644
---- a/arch/arm/mach-at91/at91x40.c
-+++ b/arch/arm/mach-at91/at91x40.c
-@@ -13,6 +13,7 @@
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/irq.h>
-+#include <linux/io.h>
- #include <asm/proc-fns.h>
- #include <asm/system_misc.h>
- #include <asm/mach/arch.h>
-diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
-index c5eaaa0..1e02c0e 100644
---- a/arch/arm/mach-at91/irq.c
-+++ b/arch/arm/mach-at91/irq.c
-@@ -49,7 +49,6 @@ static struct irq_domain *at91_aic_domain;
- static struct device_node *at91_aic_np;
- static unsigned int n_irqs = NR_AIC_IRQS;
- static unsigned long at91_aic_caps = 0;
--static unsigned int *at91_aic_irq_priorities;
-
- /* AIC5 introduces a Source Select Register */
- #define AT91_AIC_CAP_AIC5 (1 << 0)
-@@ -359,6 +358,8 @@ static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
- }
-
- #if defined(CONFIG_OF)
-+static unsigned int *at91_aic_irq_priorities;
-+
- static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
- {
-diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
-index f02acb0..a4c78c0 100644
---- a/drivers/rtc/rtc-at91rm9200.c
-+++ b/drivers/rtc/rtc-at91rm9200.c
-@@ -27,6 +27,7 @@
- #include <linux/interrupt.h>
- #include <linux/ioctl.h>
- #include <linux/completion.h>
-+#include <linux/io.h>
-
- #include <asm/io.h>
- #include <asm/uaccess.h>
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8784aa5855d4f4ebc018df2ee43a143c7560ba37 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:39 +0200
+Subject: dmaengine: at_hdmac: remove some at_dma_slave comments
+
+commit b89a9cb4027a498de7dad12a68b06ae1b254042c upstream.
+
+These comments were covering removed struct at_dma_slave fields.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ arch/arm/mach-at91/include/mach/at_hdmac.h | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
+index fff48d1..810a13e 100644
+--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
++++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
+@@ -26,11 +26,6 @@ struct at_dma_platform_data {
+ /**
+ * struct at_dma_slave - Controller-specific information about a slave
+ * @dma_dev: required DMA master device
+- * @tx_reg: physical address of data register used for
+- * memory-to-peripheral transfers
+- * @rx_reg: physical address of data register used for
+- * peripheral-to-memory transfers
+- * @reg_width: peripheral register width
+ * @cfg: Platform-specific initializer for the CFG register
+ * @ctrla: Platform-specific initializer for the CTRLA register
+ */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 7d5ebe64bdd79c895951ec7d72425f7806b14fbd Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:40 +0200
+Subject: dmaengine: at_hdmac: remove ATC_DEFAULT_CTRLA constant
+
+commit b409ebfb14a71b64e11b156dc82ede698480397e upstream.
+
+Not needed constant that was set to 0.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ drivers/dma/at_hdmac.c | 12 +++++-------
+ 1 file changed, 5 insertions(+), 7 deletions(-)
+
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -39,7 +39,6 @@
+ */
+
+ #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
+-#define ATC_DEFAULT_CTRLA (0)
+ #define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \
+ |ATC_DIF(AT_DMA_MEM_IF))
+
+@@ -574,7 +573,6 @@ atc_prep_dma_memcpy(struct dma_chan *cha
+ return NULL;
+ }
+
+- ctrla = ATC_DEFAULT_CTRLA;
+ ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN
+ | ATC_SRC_ADDR_MODE_INCR
+ | ATC_DST_ADDR_MODE_INCR
+@@ -585,13 +583,13 @@ atc_prep_dma_memcpy(struct dma_chan *cha
+ * of the most common optimization.
+ */
+ if (!((src | dest | len) & 3)) {
+- ctrla |= ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
++ ctrla = ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
+ src_width = dst_width = 2;
+ } else if (!((src | dest | len) & 1)) {
+- ctrla |= ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
++ ctrla = ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
+ src_width = dst_width = 1;
+ } else {
+- ctrla |= ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
++ ctrla = ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
+ src_width = dst_width = 0;
+ }
+
+@@ -668,7 +666,7 @@ atc_prep_slave_sg(struct dma_chan *chan,
+ return NULL;
+ }
+
+- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
++ ctrla = atslave->ctrla;
+ ctrlb = ATC_IEN;
+
+ switch (direction) {
+@@ -812,7 +810,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan
+ u32 ctrla;
+
+ /* prepare common CRTLA value */
+- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
++ ctrla = atslave->ctrla
+ | ATC_DST_WIDTH(reg_width)
+ | ATC_SRC_WIDTH(reg_width)
+ | period_len >> reg_width;
+++ /dev/null
-From 0144b540ede14f0e1c1f3d084e4d48552a347b6a Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 10 May 2012 12:17:39 +0200
-Subject: dmaengine: at_hdmac: remove some at_dma_slave comments
-
-These comments were covering removed struct at_dma_slave fields.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
----
- arch/arm/mach-at91/include/mach/at_hdmac.h | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/arch/arm/mach-at91/include/mach/at_hdmac.h b/arch/arm/mach-at91/include/mach/at_hdmac.h
-index fff48d1..810a13e 100644
---- a/arch/arm/mach-at91/include/mach/at_hdmac.h
-+++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
-@@ -26,11 +26,6 @@ struct at_dma_platform_data {
- /**
- * struct at_dma_slave - Controller-specific information about a slave
- * @dma_dev: required DMA master device
-- * @tx_reg: physical address of data register used for
-- * memory-to-peripheral transfers
-- * @rx_reg: physical address of data register used for
-- * peripheral-to-memory transfers
-- * @reg_width: peripheral register width
- * @cfg: Platform-specific initializer for the CFG register
- * @ctrla: Platform-specific initializer for the CTRLA register
- */
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 6a24ecd4c954856980e2c5be94c85d97bf6a47d6 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 10 May 2012 12:17:40 +0200
-Subject: dmaengine: at_hdmac: remove ATC_DEFAULT_CTRLA constant
-
-Not needed constant that was set to 0.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
----
- drivers/dma/at_hdmac.c | 12 +++++-------
- 1 file changed, 5 insertions(+), 7 deletions(-)
-
---- a/drivers/dma/at_hdmac.c
-+++ b/drivers/dma/at_hdmac.c
-@@ -39,7 +39,6 @@
- */
-
- #define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
--#define ATC_DEFAULT_CTRLA (0)
- #define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \
- |ATC_DIF(AT_DMA_MEM_IF))
-
-@@ -574,7 +573,6 @@ atc_prep_dma_memcpy(struct dma_chan *cha
- return NULL;
- }
-
-- ctrla = ATC_DEFAULT_CTRLA;
- ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN
- | ATC_SRC_ADDR_MODE_INCR
- | ATC_DST_ADDR_MODE_INCR
-@@ -585,13 +583,13 @@ atc_prep_dma_memcpy(struct dma_chan *cha
- * of the most common optimization.
- */
- if (!((src | dest | len) & 3)) {
-- ctrla |= ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
-+ ctrla = ATC_SRC_WIDTH_WORD | ATC_DST_WIDTH_WORD;
- src_width = dst_width = 2;
- } else if (!((src | dest | len) & 1)) {
-- ctrla |= ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
-+ ctrla = ATC_SRC_WIDTH_HALFWORD | ATC_DST_WIDTH_HALFWORD;
- src_width = dst_width = 1;
- } else {
-- ctrla |= ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
-+ ctrla = ATC_SRC_WIDTH_BYTE | ATC_DST_WIDTH_BYTE;
- src_width = dst_width = 0;
- }
-
-@@ -668,7 +666,7 @@ atc_prep_slave_sg(struct dma_chan *chan,
- return NULL;
- }
-
-- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla;
-+ ctrla = atslave->ctrla;
- ctrlb = ATC_IEN;
-
- switch (direction) {
-@@ -812,7 +810,7 @@ atc_dma_cyclic_fill_desc(struct dma_chan
- u32 ctrla;
-
- /* prepare common CRTLA value */
-- ctrla = ATC_DEFAULT_CTRLA | atslave->ctrla
-+ ctrla = atslave->ctrla
- | ATC_DST_WIDTH(reg_width)
- | ATC_SRC_WIDTH(reg_width)
- | period_len >> reg_width;
--- /dev/null
+From dc894a3e43407b912568b2c3a1fc83585994be14 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 10 May 2012 12:17:41 +0200
+Subject: dmaengine: at_hdmac: take maxburst from slave configuration
+
+commit 1dd1ea8eb46a71201943148cc0ed3182cd04e288 upstream.
+
+The maxburst/chunk size was taken from the private slave DMA data structure.
+Use the common API provided by DMA_SLAVE_CONFIG to setup src/dst maxburst
+values.
+The ctrla field is not needed anymore in the slave private structure nor the
+header constants that were located in an architecture specific directory.
+The at91sam9g45_devices.c file that was using this platform data is also
+modified to remove this now useless data.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 1 -
+ arch/arm/mach-at91/include/mach/at_hdmac.h | 21 ---------------------
+ drivers/dma/at_hdmac.c | 7 ++++---
+ drivers/dma/at_hdmac_regs.h | 21 ++++++++++++++++++++-
+ 4 files changed, 24 insertions(+), 26 deletions(-)
+
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -433,7 +433,6 @@ void __init at91_add_device_mci(short mm
+ atslave->dma_dev = &at_hdmac_device.dev;
+ atslave->cfg = ATC_FIFOCFG_HALFFIFO
+ | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
+- atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
+ if (mmc_id == 0) /* MCI0 */
+ atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
+ | ATC_DST_PER(AT_DMA_ID_MCI0);
+--- a/arch/arm/mach-at91/include/mach/at_hdmac.h
++++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
+@@ -27,12 +27,10 @@ struct at_dma_platform_data {
+ * struct at_dma_slave - Controller-specific information about a slave
+ * @dma_dev: required DMA master device
+ * @cfg: Platform-specific initializer for the CFG register
+- * @ctrla: Platform-specific initializer for the CTRLA register
+ */
+ struct at_dma_slave {
+ struct device *dma_dev;
+ u32 cfg;
+- u32 ctrla;
+ };
+
+
+@@ -59,24 +57,5 @@ struct at_dma_slave {
+ #define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
+ #define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28)
+
+-/* Platform-configurable bits in CTRLA */
+-#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
+-#define ATC_SCSIZE_1 (0x0 << 16)
+-#define ATC_SCSIZE_4 (0x1 << 16)
+-#define ATC_SCSIZE_8 (0x2 << 16)
+-#define ATC_SCSIZE_16 (0x3 << 16)
+-#define ATC_SCSIZE_32 (0x4 << 16)
+-#define ATC_SCSIZE_64 (0x5 << 16)
+-#define ATC_SCSIZE_128 (0x6 << 16)
+-#define ATC_SCSIZE_256 (0x7 << 16)
+-#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
+-#define ATC_DCSIZE_1 (0x0 << 20)
+-#define ATC_DCSIZE_4 (0x1 << 20)
+-#define ATC_DCSIZE_8 (0x2 << 20)
+-#define ATC_DCSIZE_16 (0x3 << 20)
+-#define ATC_DCSIZE_32 (0x4 << 20)
+-#define ATC_DCSIZE_64 (0x5 << 20)
+-#define ATC_DCSIZE_128 (0x6 << 20)
+-#define ATC_DCSIZE_256 (0x7 << 20)
+
+ #endif /* AT_HDMAC_H */
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -666,7 +666,8 @@ atc_prep_slave_sg(struct dma_chan *chan,
+ return NULL;
+ }
+
+- ctrla = atslave->ctrla;
++ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
++ | ATC_DCSIZE(sconfig->dst_maxburst);
+ ctrlb = ATC_IEN;
+
+ switch (direction) {
+@@ -805,12 +806,12 @@ atc_dma_cyclic_fill_desc(struct dma_chan
+ enum dma_transfer_direction direction)
+ {
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+- struct at_dma_slave *atslave = chan->private;
+ struct dma_slave_config *sconfig = &atchan->dma_sconfig;
+ u32 ctrla;
+
+ /* prepare common CRTLA value */
+- ctrla = atslave->ctrla
++ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
++ | ATC_DCSIZE(sconfig->dst_maxburst)
+ | ATC_DST_WIDTH(reg_width)
+ | ATC_SRC_WIDTH(reg_width)
+ | period_len >> reg_width;
+--- a/drivers/dma/at_hdmac_regs.h
++++ b/drivers/dma/at_hdmac_regs.h
+@@ -87,7 +87,26 @@
+ /* Bitfields in CTRLA */
+ #define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */
+ #define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
+-/* Chunck Tranfer size definitions are in at_hdmac.h */
++#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
++#define ATC_SCSIZE(x) (ATC_SCSIZE_MASK & ((x) << 16))
++#define ATC_SCSIZE_1 (0x0 << 16)
++#define ATC_SCSIZE_4 (0x1 << 16)
++#define ATC_SCSIZE_8 (0x2 << 16)
++#define ATC_SCSIZE_16 (0x3 << 16)
++#define ATC_SCSIZE_32 (0x4 << 16)
++#define ATC_SCSIZE_64 (0x5 << 16)
++#define ATC_SCSIZE_128 (0x6 << 16)
++#define ATC_SCSIZE_256 (0x7 << 16)
++#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
++#define ATC_DCSIZE(x) (ATC_DCSIZE_MASK & ((x) << 20))
++#define ATC_DCSIZE_1 (0x0 << 20)
++#define ATC_DCSIZE_4 (0x1 << 20)
++#define ATC_DCSIZE_8 (0x2 << 20)
++#define ATC_DCSIZE_16 (0x3 << 20)
++#define ATC_DCSIZE_32 (0x4 << 20)
++#define ATC_DCSIZE_64 (0x5 << 20)
++#define ATC_DCSIZE_128 (0x6 << 20)
++#define ATC_DCSIZE_256 (0x7 << 20)
+ #define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */
+ #define ATC_SRC_WIDTH(x) ((x) << 24)
+ #define ATC_SRC_WIDTH_BYTE (0x0 << 24)
+++ /dev/null
-From a692d1243e4c2513c96f00b9be1ab36fb65d2992 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 10 May 2012 12:17:41 +0200
-Subject: dmaengine: at_hdmac: take maxburst from slave configuration
-
-The maxburst/chunk size was taken from the private slave DMA data structure.
-Use the common API provided by DMA_SLAVE_CONFIG to setup src/dst maxburst
-values.
-The ctrla field is not needed anymore in the slave private structure nor the
-header constants that were located in an architecture specific directory.
-The at91sam9g45_devices.c file that was using this platform data is also
-modified to remove this now useless data.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
----
- arch/arm/mach-at91/at91sam9g45_devices.c | 1 -
- arch/arm/mach-at91/include/mach/at_hdmac.h | 21 ---------------------
- drivers/dma/at_hdmac.c | 7 ++++---
- drivers/dma/at_hdmac_regs.h | 21 ++++++++++++++++++++-
- 4 files changed, 24 insertions(+), 26 deletions(-)
-
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -433,7 +433,6 @@ void __init at91_add_device_mci(short mm
- atslave->dma_dev = &at_hdmac_device.dev;
- atslave->cfg = ATC_FIFOCFG_HALFFIFO
- | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
-- atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16;
- if (mmc_id == 0) /* MCI0 */
- atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
- | ATC_DST_PER(AT_DMA_ID_MCI0);
---- a/arch/arm/mach-at91/include/mach/at_hdmac.h
-+++ b/arch/arm/mach-at91/include/mach/at_hdmac.h
-@@ -27,12 +27,10 @@ struct at_dma_platform_data {
- * struct at_dma_slave - Controller-specific information about a slave
- * @dma_dev: required DMA master device
- * @cfg: Platform-specific initializer for the CFG register
-- * @ctrla: Platform-specific initializer for the CTRLA register
- */
- struct at_dma_slave {
- struct device *dma_dev;
- u32 cfg;
-- u32 ctrla;
- };
-
-
-@@ -59,24 +57,5 @@ struct at_dma_slave {
- #define ATC_FIFOCFG_HALFFIFO (0x1 << 28)
- #define ATC_FIFOCFG_ENOUGHSPACE (0x2 << 28)
-
--/* Platform-configurable bits in CTRLA */
--#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
--#define ATC_SCSIZE_1 (0x0 << 16)
--#define ATC_SCSIZE_4 (0x1 << 16)
--#define ATC_SCSIZE_8 (0x2 << 16)
--#define ATC_SCSIZE_16 (0x3 << 16)
--#define ATC_SCSIZE_32 (0x4 << 16)
--#define ATC_SCSIZE_64 (0x5 << 16)
--#define ATC_SCSIZE_128 (0x6 << 16)
--#define ATC_SCSIZE_256 (0x7 << 16)
--#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
--#define ATC_DCSIZE_1 (0x0 << 20)
--#define ATC_DCSIZE_4 (0x1 << 20)
--#define ATC_DCSIZE_8 (0x2 << 20)
--#define ATC_DCSIZE_16 (0x3 << 20)
--#define ATC_DCSIZE_32 (0x4 << 20)
--#define ATC_DCSIZE_64 (0x5 << 20)
--#define ATC_DCSIZE_128 (0x6 << 20)
--#define ATC_DCSIZE_256 (0x7 << 20)
-
- #endif /* AT_HDMAC_H */
---- a/drivers/dma/at_hdmac.c
-+++ b/drivers/dma/at_hdmac.c
-@@ -666,7 +666,8 @@ atc_prep_slave_sg(struct dma_chan *chan,
- return NULL;
- }
-
-- ctrla = atslave->ctrla;
-+ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
-+ | ATC_DCSIZE(sconfig->dst_maxburst);
- ctrlb = ATC_IEN;
-
- switch (direction) {
-@@ -805,12 +806,12 @@ atc_dma_cyclic_fill_desc(struct dma_chan
- enum dma_transfer_direction direction)
- {
- struct at_dma_chan *atchan = to_at_dma_chan(chan);
-- struct at_dma_slave *atslave = chan->private;
- struct dma_slave_config *sconfig = &atchan->dma_sconfig;
- u32 ctrla;
-
- /* prepare common CRTLA value */
-- ctrla = atslave->ctrla
-+ ctrla = ATC_SCSIZE(sconfig->src_maxburst)
-+ | ATC_DCSIZE(sconfig->dst_maxburst)
- | ATC_DST_WIDTH(reg_width)
- | ATC_SRC_WIDTH(reg_width)
- | period_len >> reg_width;
---- a/drivers/dma/at_hdmac_regs.h
-+++ b/drivers/dma/at_hdmac_regs.h
-@@ -87,7 +87,26 @@
- /* Bitfields in CTRLA */
- #define ATC_BTSIZE_MAX 0xFFFFUL /* Maximum Buffer Transfer Size */
- #define ATC_BTSIZE(x) (ATC_BTSIZE_MAX & (x)) /* Buffer Transfer Size */
--/* Chunck Tranfer size definitions are in at_hdmac.h */
-+#define ATC_SCSIZE_MASK (0x7 << 16) /* Source Chunk Transfer Size */
-+#define ATC_SCSIZE(x) (ATC_SCSIZE_MASK & ((x) << 16))
-+#define ATC_SCSIZE_1 (0x0 << 16)
-+#define ATC_SCSIZE_4 (0x1 << 16)
-+#define ATC_SCSIZE_8 (0x2 << 16)
-+#define ATC_SCSIZE_16 (0x3 << 16)
-+#define ATC_SCSIZE_32 (0x4 << 16)
-+#define ATC_SCSIZE_64 (0x5 << 16)
-+#define ATC_SCSIZE_128 (0x6 << 16)
-+#define ATC_SCSIZE_256 (0x7 << 16)
-+#define ATC_DCSIZE_MASK (0x7 << 20) /* Destination Chunk Transfer Size */
-+#define ATC_DCSIZE(x) (ATC_DCSIZE_MASK & ((x) << 20))
-+#define ATC_DCSIZE_1 (0x0 << 20)
-+#define ATC_DCSIZE_4 (0x1 << 20)
-+#define ATC_DCSIZE_8 (0x2 << 20)
-+#define ATC_DCSIZE_16 (0x3 << 20)
-+#define ATC_DCSIZE_32 (0x4 << 20)
-+#define ATC_DCSIZE_64 (0x5 << 20)
-+#define ATC_DCSIZE_128 (0x6 << 20)
-+#define ATC_DCSIZE_256 (0x7 << 20)
- #define ATC_SRC_WIDTH_MASK (0x3 << 24) /* Source Single Transfer Size */
- #define ATC_SRC_WIDTH(x) ((x) << 24)
- #define ATC_SRC_WIDTH_BYTE (0x0 << 24)
--- /dev/null
+From cbf60a8fc3f77c39c2612d91a86797c4153ce4fe Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 12 Jun 2012 10:34:52 +0200
+Subject: dmaengine: at_hdmac: trivial: fix comment in header
+
+commit 9102d8715e5c10db37d81ab75285a2f6746360b2 upstream.
+
+Not all Atmel SoCs were pointed out in header comment which was bringing
+confusion. Remove the truncated list of supported devices, replace by the
+only one that is not supported.
+
+Reported-by: Elen Song <elen.song@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/dma/at_hdmac.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
+index 7292aa8..bb16013 100644
+--- a/drivers/dma/at_hdmac.c
++++ b/drivers/dma/at_hdmac.c
+@@ -9,10 +9,9 @@
+ * (at your option) any later version.
+ *
+ *
+- * This supports the Atmel AHB DMA Controller,
+- *
+- * The driver has currently been tested with the Atmel AT91SAM9RL
+- * and AT91SAM9G45 series.
++ * This supports the Atmel AHB DMA Controller found in several Atmel SoCs.
++ * The only Atmel DMA Controller that is not covered by this driver is the one
++ * found on AT91SAM9263.
+ */
+
+ #include <linux/clk.h>
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From e7d260949873bedcc9fe6cd9f60eb1d99359d119 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 12 Jun 2012 10:34:52 +0200
-Subject: dmaengine: at_hdmac: trivial: fix comment in header
-
-Not all Atmel SoCs were pointed out in header comment which was bringing
-confusion. Remove the truncated list of supported devices, replace by the
-only one that is not supported.
-
-Reported-by: Elen Song <elen.song@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/dma/at_hdmac.c | 7 +++----
- 1 file changed, 3 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
-index 7292aa8..bb16013 100644
---- a/drivers/dma/at_hdmac.c
-+++ b/drivers/dma/at_hdmac.c
-@@ -9,10 +9,9 @@
- * (at your option) any later version.
- *
- *
-- * This supports the Atmel AHB DMA Controller,
-- *
-- * The driver has currently been tested with the Atmel AT91SAM9RL
-- * and AT91SAM9G45 series.
-+ * This supports the Atmel AHB DMA Controller found in several Atmel SoCs.
-+ * The only Atmel DMA Controller that is not covered by this driver is the one
-+ * found on AT91SAM9263.
- */
-
- #include <linux/clk.h>
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 667d21c53f93478f575a888a3258187d401b4305 Mon Sep 17 00:00:00 2001
+From: Andrew Victor <avictor.za@gmail.com>
+Date: Thu, 26 Apr 2012 00:30:42 +0000
+Subject: AT91: Remove fixed mapping for AT91RM9200 ethernet
+
+commit c5f0f83c3be4c965c40c78d52000db30c0ceab5d upstream.
+
+The AT91RM9200 Ethernet controller still has a fixed IO mapping.
+So:
+* Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
+* Pass the physical base-address via platform-resources to the driver.
+* Convert at91_ether.c driver to perform an ioremap().
+* Ethernet PHY detection needs to be performed during the driver
+initialization process, it can no longer be done first.
+
+Signed-off-by: Andrew Victor <linux@maxim.org.za>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ arch/arm/mach-at91/at91rm9200.c | 10 -
+ arch/arm/mach-at91/at91rm9200_devices.c | 4 +-
+ arch/arm/mach-at91/include/mach/hardware.h | 1 -
+ drivers/net/ethernet/cadence/at91_ether.c | 527 ++++++++++++++++-------------
+ drivers/net/ethernet/cadence/at91_ether.h | 1 +
+ 5 files changed, 287 insertions(+), 256 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 801c30b..6f50c67 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -27,15 +27,6 @@
+ #include "clock.h"
+ #include "sam9_smc.h"
+
+-static struct map_desc at91rm9200_io_desc[] __initdata = {
+- {
+- .virtual = AT91_VA_BASE_EMAC,
+- .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC),
+- .length = SZ_16K,
+- .type = MT_DEVICE,
+- },
+-};
+-
+ /* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+@@ -304,7 +295,6 @@ static void __init at91rm9200_map_io(void)
+ {
+ /* Map peripherals */
+ at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
+- iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+ }
+
+ static void __init at91rm9200_ioremap_registers(void)
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 04d69d3..01fb732 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -140,8 +140,8 @@ static struct macb_platform_data eth_data;
+
+ static struct resource eth_resources[] = {
+ [0] = {
+- .start = AT91_VA_BASE_EMAC,
+- .end = AT91_VA_BASE_EMAC + SZ_16K - 1,
++ .start = AT91RM9200_BASE_EMAC,
++ .end = AT91RM9200_BASE_EMAC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
+index 24b46bd..09242b6 100644
+--- a/arch/arm/mach-at91/include/mach/hardware.h
++++ b/arch/arm/mach-at91/include/mach/hardware.h
+@@ -85,7 +85,6 @@
+ * Virtual to Physical Address mapping for IO devices.
+ */
+ #define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS)
+-#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+
+ /* Internal SRAM is mapped below the IO devices */
+ #define AT91_SRAM_MAX SZ_1M
+diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
+index 9061170..62761e1 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.c
++++ b/drivers/net/ethernet/cadence/at91_ether.c
+@@ -30,6 +30,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/clk.h>
+ #include <linux/gfp.h>
++#include <linux/phy.h>
+
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+@@ -51,21 +52,17 @@
+ /*
+ * Read from a EMAC register.
+ */
+-static inline unsigned long at91_emac_read(unsigned int reg)
++static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
+ {
+- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+-
+- return __raw_readl(emac_base + reg);
++ return __raw_readl(lp->emac_base + reg);
+ }
+
+ /*
+ * Write to a EMAC register.
+ */
+-static inline void at91_emac_write(unsigned int reg, unsigned long value)
++static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
+ {
+- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
+-
+- __raw_writel(value, emac_base + reg);
++ __raw_writel(value, lp->emac_base + reg);
+ }
+
+ /* ........................... PHY INTERFACE ........................... */
+@@ -75,32 +72,33 @@ static inline void at91_emac_write(unsigned int reg, unsigned long value)
+ * When not called from an interrupt-handler, access to the PHY must be
+ * protected by a spinlock.
+ */
+-static void enable_mdi(void)
++static void enable_mdi(struct at91_private *lp)
+ {
+ unsigned long ctl;
+
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
+ }
+
+ /*
+ * Disable the MDIO bit in the MAC control register
+ */
+-static void disable_mdi(void)
++static void disable_mdi(struct at91_private *lp)
+ {
+ unsigned long ctl;
+
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
+ }
+
+ /*
+ * Wait until the PHY operation is complete.
+ */
+-static inline void at91_phy_wait(void) {
++static inline void at91_phy_wait(struct at91_private *lp)
++{
+ unsigned long timeout = jiffies + 2;
+
+- while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
++ while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
+ if (time_after(jiffies, timeout)) {
+ printk("at91_ether: MIO timeout\n");
+ break;
+@@ -113,28 +111,28 @@ static inline void at91_phy_wait(void) {
+ * Write value to the a PHY register
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+-static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
++static void write_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int value)
+ {
+- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
++ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
+ | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+- at91_phy_wait();
++ at91_phy_wait(lp);
+ }
+
+ /*
+ * Read value stored in a PHY register.
+ * Note: MDI interface is assumed to already have been enabled.
+ */
+-static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
++static void read_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int *value)
+ {
+- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
++ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
+ | ((phy_addr & 0x1f) << 23) | (address << 18));
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+- at91_phy_wait();
++ at91_phy_wait(lp);
+
+- *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
++ *value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
+ }
+
+ /* ........................... PHY MANAGEMENT .......................... */
+@@ -158,13 +156,13 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ }
+
+ /* Link up, or auto-negotiation still in progress */
+- read_phy(lp->phy_address, MII_BMSR, &bmsr);
+- read_phy(lp->phy_address, MII_BMCR, &bmcr);
++ read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
++ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
+ if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */
+ if (!(bmsr & BMSR_ANEGCOMPLETE))
+ return; /* Do nothing - another interrupt generated when negotiation complete */
+
+- read_phy(lp->phy_address, MII_LPA, &lpa);
++ read_phy(lp, lp->phy_address, MII_LPA, &lpa);
+ if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
+ else speed = SPEED_10;
+ if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
+@@ -175,7 +173,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ }
+
+ /* Update the MAC */
+- mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
++ mac_cfg = at91_emac_read(lp, AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
+ if (speed == SPEED_100) {
+ if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
+ mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
+@@ -186,7 +184,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
+ mac_cfg |= AT91_EMAC_FD;
+ else {} /* 10 Half Duplex */
+ }
+- at91_emac_write(AT91_EMAC_CFG, mac_cfg);
++ at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
+
+ if (!silent)
+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+@@ -207,34 +205,34 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
+ * level-triggering. We therefore have to check if the PHY actually has
+ * an IRQ pending.
+ */
+- enable_mdi();
++ enable_mdi(lp);
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+- read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
+ if (!(phy & (1 << 0)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) {
+- read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
++ read_phy(lp, lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
+ if (!(phy & (1 << 2)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) {
+- read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
++ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
+ if (!(phy & (1 << 0)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_KS8721_ID) {
+- read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
++ read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
+ if (!(phy & ((1 << 2) | 1)))
+ goto done;
+ }
+- else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
++ else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
+ if (!(phy & ((1 << 2) | 1)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_DP83848_ID) {
+- read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
++ read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
+ if (!(phy & (1 << 7)))
+ goto done;
+ }
+@@ -242,7 +240,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
+ update_linkspeed(dev, 0);
+
+ done:
+- disable_mdi();
++ disable_mdi(lp);
+
+ return IRQ_HANDLED;
+ }
+@@ -273,41 +271,41 @@ static void enable_phyirq(struct net_device *dev)
+ }
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
+- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
+ dsintr = dsintr & ~0xf00; /* clear bits 8..11 */
+- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
+- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
+ dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */
+- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
+ dsintr = (1 << 15) | ( 1 << 14);
+- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
+ dsintr = (1 << 10) | ( 1 << 8);
+- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
++ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
+ }
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr | 0x500; /* set bits 8, 10 */
+- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr | 0x3c; /* set bits 2..5 */
+- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr | 0x3; /* set bits 0,1 */
+- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
+ }
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ }
+
+@@ -326,43 +324,43 @@ static void disable_phyirq(struct net_device *dev)
+ }
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
+- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
+ dsintr = dsintr | 0xf00; /* set bits 8..11 */
+- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
+- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
+ dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */
+- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
+- read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
+ dsintr = ~(1 << 14);
+- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
+- read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
++ read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
+ dsintr = ~((1 << 10) | (1 << 8));
+- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
++ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
+ }
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr & ~0x500; /* clear bits 8, 10 */
+- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr & ~0x3; /* clear bits 0, 1 */
+- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
++ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr & ~0x3c; /* clear bits 2..5 */
+- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
++ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
+ }
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ irq_number = lp->board_data.phy_irq_pin;
+@@ -379,17 +377,17 @@ static void reset_phy(struct net_device *dev)
+ unsigned int bmcr;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ /* Perform PHY reset */
+- write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
++ write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
+
+ /* Wait until PHY reset is complete */
+ do {
+- read_phy(lp->phy_address, MII_BMCR, &bmcr);
++ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
+ } while (!(bmcr & BMCR_RESET));
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ }
+ #endif
+@@ -399,13 +397,37 @@ static void at91ether_check_link(unsigned long dev_id)
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct at91_private *lp = netdev_priv(dev);
+
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 1);
+- disable_mdi();
++ disable_mdi(lp);
+
+ mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
+ }
+
++/*
++ * Perform any PHY-specific initialization.
++ */
++static void __init initialize_phy(struct at91_private *lp)
++{
++ unsigned int val;
++
++ spin_lock_irq(&lp->lock);
++ enable_mdi(lp);
++
++ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
++ read_phy(lp, lp->phy_address, MII_DSCR_REG, &val);
++ if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
++ lp->phy_media = PORT_FIBRE;
++ } else if (machine_is_csb337()) {
++ /* mix link activity status into LED2 link state */
++ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
++ } else if (machine_is_ecbat91())
++ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
++
++ disable_mdi(lp);
++ spin_unlock_irq(&lp->lock);
++}
++
+ /* ......................... ADDRESS MANAGEMENT ........................ */
+
+ /*
+@@ -454,17 +476,19 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
+ */
+ static void __init get_mac_address(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
++
+ /* Check Specific-Address 1 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, AT91_EMAC_SA1L)))
+ return;
+ /* Check Specific-Address 2 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, AT91_EMAC_SA2L)))
+ return;
+ /* Check Specific-Address 3 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, AT91_EMAC_SA3L)))
+ return;
+ /* Check Specific-Address 4 */
+- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
++ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
+ return;
+
+ printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
+@@ -475,11 +499,13 @@ static void __init get_mac_address(struct net_device *dev)
+ */
+ static void update_mac_address(struct net_device *dev)
+ {
+- at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
+- at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
++ struct at91_private *lp = netdev_priv(dev);
+
+- at91_emac_write(AT91_EMAC_SA2L, 0);
+- at91_emac_write(AT91_EMAC_SA2H, 0);
++ at91_emac_write(lp, AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
++ at91_emac_write(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
++
++ at91_emac_write(lp, AT91_EMAC_SA2L, 0);
++ at91_emac_write(lp, AT91_EMAC_SA2H, 0);
+ }
+
+ /*
+@@ -559,6 +585,7 @@ static int hash_get_index(__u8 *addr)
+ */
+ static void at91ether_sethashtable(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ unsigned long mc_filter[2];
+ unsigned int bitnr;
+@@ -570,8 +597,8 @@ static void at91ether_sethashtable(struct net_device *dev)
+ mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+ }
+
+- at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
+- at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
++ at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
++ at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
+ }
+
+ /*
+@@ -579,9 +606,10 @@ static void at91ether_sethashtable(struct net_device *dev)
+ */
+ static void at91ether_set_multicast_list(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ unsigned long cfg;
+
+- cfg = at91_emac_read(AT91_EMAC_CFG);
++ cfg = at91_emac_read(lp, AT91_EMAC_CFG);
+
+ if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */
+ cfg |= AT91_EMAC_CAF;
+@@ -589,34 +617,37 @@ static void at91ether_set_multicast_list(struct net_device *dev)
+ cfg &= ~AT91_EMAC_CAF;
+
+ if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */
+- at91_emac_write(AT91_EMAC_HSH, -1);
+- at91_emac_write(AT91_EMAC_HSL, -1);
++ at91_emac_write(lp, AT91_EMAC_HSH, -1);
++ at91_emac_write(lp, AT91_EMAC_HSL, -1);
+ cfg |= AT91_EMAC_MTI;
+ } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */
+ at91ether_sethashtable(dev);
+ cfg |= AT91_EMAC_MTI;
+ } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */
+- at91_emac_write(AT91_EMAC_HSH, 0);
+- at91_emac_write(AT91_EMAC_HSL, 0);
++ at91_emac_write(lp, AT91_EMAC_HSH, 0);
++ at91_emac_write(lp, AT91_EMAC_HSL, 0);
+ cfg &= ~AT91_EMAC_MTI;
+ }
+
+- at91_emac_write(AT91_EMAC_CFG, cfg);
++ at91_emac_write(lp, AT91_EMAC_CFG, cfg);
+ }
+
+ /* ......................... ETHTOOL SUPPORT ........................... */
+
+ static int mdio_read(struct net_device *dev, int phy_id, int location)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ unsigned int value;
+
+- read_phy(phy_id, location, &value);
++ read_phy(lp, phy_id, location, &value);
+ return value;
+ }
+
+ static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+ {
+- write_phy(phy_id, location, value);
++ struct at91_private *lp = netdev_priv(dev);
++
++ write_phy(lp, phy_id, location, value);
+ }
+
+ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+@@ -625,11 +656,11 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_ethtool_gset(&lp->mii, cmd);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */
+@@ -646,11 +677,11 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_ethtool_sset(&lp->mii, cmd);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return ret;
+@@ -662,11 +693,11 @@ static int at91ether_nwayreset(struct net_device *dev)
+ int ret;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+
+ ret = mii_nway_restart(&lp->mii);
+
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return ret;
+@@ -696,9 +727,9 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ return res;
+@@ -731,11 +762,11 @@ static void at91ether_start(struct net_device *dev)
+ lp->rxBuffIndex = 0;
+
+ /* Program address of descriptor list in Rx Buffer Queue register */
+- at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
++ at91_emac_write(lp, AT91_EMAC_RBQP, (unsigned long) dlist_phys);
+
+ /* Enable Receive and Transmit */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
+ }
+
+ /*
+@@ -752,8 +783,8 @@ static int at91ether_open(struct net_device *dev)
+ clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
+
+ /* Clear internal statistics */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
+
+ /* Update the MAC address (incase user has changed it) */
+ update_mac_address(dev);
+@@ -762,15 +793,15 @@ static int at91ether_open(struct net_device *dev)
+ enable_phyirq(dev);
+
+ /* Enable MAC interrupts */
+- at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
++ at91_emac_write(lp, AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+ | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+ | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+ /* Determine current link speed */
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 0);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+ at91ether_start(dev);
+@@ -787,14 +818,14 @@ static int at91ether_close(struct net_device *dev)
+ unsigned long ctl;
+
+ /* Disable Receiver and Transmitter */
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
+
+ /* Disable PHY interrupt */
+ disable_phyirq(dev);
+
+ /* Disable MAC interrupts */
+- at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
++ at91_emac_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
+ | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
+ | AT91_EMAC_ROVR | AT91_EMAC_ABT);
+
+@@ -812,7 +843,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct at91_private *lp = netdev_priv(dev);
+
+- if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
++ if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
+ netif_stop_queue(dev);
+
+ /* Store packet information (to free when Tx completed) */
+@@ -822,9 +853,9 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ dev->stats.tx_bytes += skb->len;
+
+ /* Set address of the data in the Transmit Address register */
+- at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
++ at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
+ /* Set length of the packet in the Transmit Control register */
+- at91_emac_write(AT91_EMAC_TCR, skb->len);
++ at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
+
+ } else {
+ printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
+@@ -841,31 +872,32 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ */
+ static struct net_device_stats *at91ether_stats(struct net_device *dev)
+ {
++ struct at91_private *lp = netdev_priv(dev);
+ int ale, lenerr, seqe, lcol, ecol;
+
+ if (netif_running(dev)) {
+- dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */
+- ale = at91_emac_read(AT91_EMAC_ALE);
++ dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK); /* Good frames received */
++ ale = at91_emac_read(lp, AT91_EMAC_ALE);
+ dev->stats.rx_frame_errors += ale; /* Alignment errors */
+- lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
++ lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
+ dev->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */
+- seqe = at91_emac_read(AT91_EMAC_SEQE);
++ seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
+ dev->stats.rx_crc_errors += seqe; /* CRC error */
+- dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */
++ dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
+ dev->stats.rx_errors += (ale + lenerr + seqe
+- + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
++ + at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
+
+- dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */
+- dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */
+- dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */
+- dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
++ dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA); /* Frames successfully transmitted */
++ dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE); /* Transmit FIFO underruns */
++ dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE); /* Carrier Sense errors */
++ dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
+
+- lcol = at91_emac_read(AT91_EMAC_LCOL);
+- ecol = at91_emac_read(AT91_EMAC_ECOL);
++ lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
++ ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
+ dev->stats.tx_window_errors += lcol; /* Late collisions */
+ dev->stats.tx_aborted_errors += ecol; /* 16 collisions */
+
+- dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
++ dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
+ }
+ return &dev->stats;
+ }
+@@ -922,7 +954,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
+
+ /* MAC Interrupt Status register indicates what interrupts are pending.
+ It is automatically cleared once read. */
+- intstatus = at91_emac_read(AT91_EMAC_ISR);
++ intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
+
+ if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
+ at91ether_rx(dev);
+@@ -942,9 +974,9 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
+
+ /* Work-around for Errata #11 */
+ if (intstatus & AT91_EMAC_RBNA) {
+- ctl = at91_emac_read(AT91_EMAC_CTL);
+- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
+- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
++ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
++ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
+ }
+
+ if (intstatus & AT91_EMAC_ROVR)
+@@ -980,189 +1012,199 @@ static const struct net_device_ops at91ether_netdev_ops = {
+ };
+
+ /*
+- * Initialize the ethernet interface
++ * Detect the PHY type, and its address.
+ */
+-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
+- struct platform_device *pdev, struct clk *ether_clk)
++static int __init at91ether_phy_detect(struct at91_private *lp)
++{
++ unsigned int phyid1, phyid2;
++ unsigned long phy_id;
++ unsigned short phy_address = 0;
++
++ while (phy_address < PHY_MAX_ADDR) {
++ /* Read the PHY ID registers */
++ enable_mdi(lp);
++ read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
++ read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
++ disable_mdi(lp);
++
++ phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
++ switch (phy_id) {
++ case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
++ case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
++ case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
++ case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
++ case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
++ case MII_DP83847_ID: /* National Semiconductor DP83847: */
++ case MII_DP83848_ID: /* National Semiconductor DP83848: */
++ case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
++ case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
++ case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
++ case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
++ /* store detected values */
++ lp->phy_type = phy_id; /* Type of PHY connected */
++ lp->phy_address = phy_address; /* MDI address of PHY */
++ return 1;
++ }
++
++ phy_address++;
++ }
++
++ return 0; /* not detected */
++}
++
++
++/*
++ * Detect MAC & PHY and perform ethernet interface initialization
++ */
++static int __init at91ether_probe(struct platform_device *pdev)
+ {
+ struct macb_platform_data *board_data = pdev->dev.platform_data;
++ struct resource *regs;
+ struct net_device *dev;
+ struct at91_private *lp;
+- unsigned int val;
+ int res;
+
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs)
++ return -ENOENT;
++
+ dev = alloc_etherdev(sizeof(struct at91_private));
+ if (!dev)
+ return -ENOMEM;
+
+- dev->base_addr = AT91_VA_BASE_EMAC;
+- dev->irq = AT91RM9200_ID_EMAC;
++ lp = netdev_priv(dev);
++ lp->board_data = *board_data;
++ spin_lock_init(&lp->lock);
++
++ dev->base_addr = regs->start; /* physical base address */
++ lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
++ if (!lp->emac_base) {
++ res = -ENOMEM;
++ goto err_free_dev;
++ }
++
++ /* Clock */
++ lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
++ if (IS_ERR(lp->ether_clk)) {
++ res = -ENODEV;
++ goto err_ioumap;
++ }
++ clk_enable(lp->ether_clk);
+
+ /* Install the interrupt handler */
++ dev->irq = platform_get_irq(pdev, 0);
+ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
+- free_netdev(dev);
+- return -EBUSY;
++ res = -EBUSY;
++ goto err_disable_clock;
+ }
+
+ /* Allocate memory for DMA Receive descriptors */
+- lp = netdev_priv(dev);
+ lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
+ if (lp->dlist == NULL) {
+- free_irq(dev->irq, dev);
+- free_netdev(dev);
+- return -ENOMEM;
++ res = -ENOMEM;
++ goto err_free_irq;
+ }
+- lp->board_data = *board_data;
+- lp->ether_clk = ether_clk;
+- platform_set_drvdata(pdev, dev);
+-
+- spin_lock_init(&lp->lock);
+
+ ether_setup(dev);
+ dev->netdev_ops = &at91ether_netdev_ops;
+ dev->ethtool_ops = &at91ether_ethtool_ops;
+-
++ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */
+ update_mac_address(dev); /* Program ethernet address into MAC */
+
+- at91_emac_write(AT91_EMAC_CTL, 0);
++ at91_emac_write(lp, AT91_EMAC_CTL, 0);
+
+- if (lp->board_data.is_rmii)
+- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
++ if (board_data->is_rmii)
++ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
+ else
+- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
++ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
+
+- /* Perform PHY-specific initialization */
+- spin_lock_irq(&lp->lock);
+- enable_mdi();
+- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
+- read_phy(phy_address, MII_DSCR_REG, &val);
+- if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
+- lp->phy_media = PORT_FIBRE;
+- } else if (machine_is_csb337()) {
+- /* mix link activity status into LED2 link state */
+- write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
+- } else if (machine_is_ecbat91())
+- write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
++ /* Detect PHY */
++ if (!at91ether_phy_detect(lp)) {
++ printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
++ res = -ENODEV;
++ goto err_free_dmamem;
++ }
+
+- disable_mdi();
+- spin_unlock_irq(&lp->lock);
++ initialize_phy(lp);
+
+ lp->mii.dev = dev; /* Support for ethtool */
+ lp->mii.mdio_read = mdio_read;
+ lp->mii.mdio_write = mdio_write;
+- lp->mii.phy_id = phy_address;
++ lp->mii.phy_id = lp->phy_address;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
+
+- lp->phy_type = phy_type; /* Type of PHY connected */
+- lp->phy_address = phy_address; /* MDI address of PHY */
+-
+ /* Register the network interface */
+ res = register_netdev(dev);
+- if (res) {
+- free_irq(dev->irq, dev);
+- free_netdev(dev);
+- dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
+- return res;
+- }
++ if (res)
++ goto err_free_dmamem;
+
+ /* Determine current link speed */
+ spin_lock_irq(&lp->lock);
+- enable_mdi();
++ enable_mdi(lp);
+ update_linkspeed(dev, 0);
+- disable_mdi();
++ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+ netif_carrier_off(dev); /* will be enabled in open() */
+
+ /* If board has no PHY IRQ, use a timer to poll the PHY */
+- if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
++ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
++ gpio_request(board_data->phy_irq_pin, "ethernet_phy");
++ } else {
++ /* If board has no PHY IRQ, use a timer to poll the PHY */
+ init_timer(&lp->check_timer);
+ lp->check_timer.data = (unsigned long)dev;
+ lp->check_timer.function = at91ether_check_link;
+- } else if (lp->board_data.phy_irq_pin >= 32)
+- gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
++ }
+
+ /* Display ethernet banner */
+ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n",
+ dev->name, (uint) dev->base_addr, dev->irq,
+- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
++ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
++ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+ dev->dev_addr);
+- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
++ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
+ printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+- else if (phy_type == MII_LXT971A_ID)
++ else if (lp->phy_type == MII_LXT971A_ID)
+ printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
+- else if (phy_type == MII_RTL8201_ID)
++ else if (lp->phy_type == MII_RTL8201_ID)
+ printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
+- else if (phy_type == MII_BCM5221_ID)
++ else if (lp->phy_type == MII_BCM5221_ID)
+ printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
+- else if (phy_type == MII_DP83847_ID)
++ else if (lp->phy_type == MII_DP83847_ID)
+ printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+- else if (phy_type == MII_DP83848_ID)
++ else if (lp->phy_type == MII_DP83848_ID)
+ printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
+- else if (phy_type == MII_AC101L_ID)
++ else if (lp->phy_type == MII_AC101L_ID)
+ printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
+- else if (phy_type == MII_KS8721_ID)
++ else if (lp->phy_type == MII_KS8721_ID)
+ printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+- else if (phy_type == MII_T78Q21x3_ID)
++ else if (lp->phy_type == MII_T78Q21x3_ID)
+ printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
+- else if (phy_type == MII_LAN83C185_ID)
++ else if (lp->phy_type == MII_LAN83C185_ID)
+ printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
+
+- return 0;
+-}
+-
+-/*
+- * Detect MAC and PHY and perform initialization
+- */
+-static int __init at91ether_probe(struct platform_device *pdev)
+-{
+- unsigned int phyid1, phyid2;
+- int detected = -1;
+- unsigned long phy_id;
+- unsigned short phy_address = 0;
+- struct clk *ether_clk;
+-
+- ether_clk = clk_get(&pdev->dev, "ether_clk");
+- if (IS_ERR(ether_clk)) {
+- printk(KERN_ERR "at91_ether: no clock defined\n");
+- return -ENODEV;
+- }
+- clk_enable(ether_clk); /* Enable Peripheral clock */
+-
+- while ((detected != 0) && (phy_address < 32)) {
+- /* Read the PHY ID registers */
+- enable_mdi();
+- read_phy(phy_address, MII_PHYSID1, &phyid1);
+- read_phy(phy_address, MII_PHYSID2, &phyid2);
+- disable_mdi();
+-
+- phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
+- switch (phy_id) {
+- case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
+- case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
+- case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
+- case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
+- case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
+- case MII_DP83847_ID: /* National Semiconductor DP83847: */
+- case MII_DP83848_ID: /* National Semiconductor DP83848: */
+- case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
+- case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+- case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
+- case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
+- detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
+- break;
+- }
++ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
+
+- phy_address++;
+- }
++ return 0;
+
+- clk_disable(ether_clk); /* Disable Peripheral clock */
+
+- return detected;
++err_free_dmamem:
++ platform_set_drvdata(pdev, NULL);
++ dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
++err_free_irq:
++ free_irq(dev->irq, dev);
++err_disable_clock:
++ clk_disable(lp->ether_clk);
++ clk_put(lp->ether_clk);
++err_ioumap:
++ iounmap(lp->emac_base);
++err_free_dev:
++ free_netdev(dev);
++ return res;
+ }
+
+ static int __devexit at91ether_remove(struct platform_device *pdev)
+@@ -1170,8 +1212,7 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct at91_private *lp = netdev_priv(dev);
+
+- if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
+- lp->board_data.phy_irq_pin >= 32)
++ if (gpio_is_valid(lp->board_data.phy_irq_pin))
+ gpio_free(lp->board_data.phy_irq_pin);
+
+ unregister_netdev(dev);
+diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
+index 3725fbb0..0ef6328 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.h
++++ b/drivers/net/ethernet/cadence/at91_ether.h
+@@ -88,6 +88,7 @@ struct at91_private
+ struct macb_platform_data board_data; /* board-specific
+ * configuration (shared with
+ * macb for common data */
++ void __iomem *emac_base; /* base register address */
+ struct clk *ether_clk; /* clock */
+
+ /* PHY */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 272e7886507edd10614cdb998e2374afd122149e Mon Sep 17 00:00:00 2001
-From: Andrew Victor <avictor.za@gmail.com>
-Date: Thu, 26 Apr 2012 00:30:42 +0000
-Subject: AT91: Remove fixed mapping for AT91RM9200 ethernet
-
-The AT91RM9200 Ethernet controller still has a fixed IO mapping.
-So:
-* Remove the fixed IO mapping and AT91_VA_BASE_EMAC definition.
-* Pass the physical base-address via platform-resources to the driver.
-* Convert at91_ether.c driver to perform an ioremap().
-* Ethernet PHY detection needs to be performed during the driver
-initialization process, it can no longer be done first.
-
-Signed-off-by: Andrew Victor <linux@maxim.org.za>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- arch/arm/mach-at91/at91rm9200.c | 10 -
- arch/arm/mach-at91/at91rm9200_devices.c | 4 +-
- arch/arm/mach-at91/include/mach/hardware.h | 1 -
- drivers/net/ethernet/cadence/at91_ether.c | 527 ++++++++++++++++-------------
- drivers/net/ethernet/cadence/at91_ether.h | 1 +
- 5 files changed, 287 insertions(+), 256 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
-index 801c30b..6f50c67 100644
---- a/arch/arm/mach-at91/at91rm9200.c
-+++ b/arch/arm/mach-at91/at91rm9200.c
-@@ -27,15 +27,6 @@
- #include "clock.h"
- #include "sam9_smc.h"
-
--static struct map_desc at91rm9200_io_desc[] __initdata = {
-- {
-- .virtual = AT91_VA_BASE_EMAC,
-- .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC),
-- .length = SZ_16K,
-- .type = MT_DEVICE,
-- },
--};
--
- /* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-@@ -304,7 +295,6 @@ static void __init at91rm9200_map_io(void)
- {
- /* Map peripherals */
- at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
-- iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
- }
-
- static void __init at91rm9200_ioremap_registers(void)
-diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
-index 04d69d3..01fb732 100644
---- a/arch/arm/mach-at91/at91rm9200_devices.c
-+++ b/arch/arm/mach-at91/at91rm9200_devices.c
-@@ -140,8 +140,8 @@ static struct macb_platform_data eth_data;
-
- static struct resource eth_resources[] = {
- [0] = {
-- .start = AT91_VA_BASE_EMAC,
-- .end = AT91_VA_BASE_EMAC + SZ_16K - 1,
-+ .start = AT91RM9200_BASE_EMAC,
-+ .end = AT91RM9200_BASE_EMAC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
-index 24b46bd..09242b6 100644
---- a/arch/arm/mach-at91/include/mach/hardware.h
-+++ b/arch/arm/mach-at91/include/mach/hardware.h
-@@ -85,7 +85,6 @@
- * Virtual to Physical Address mapping for IO devices.
- */
- #define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS)
--#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91RM9200_BASE_EMAC)
-
- /* Internal SRAM is mapped below the IO devices */
- #define AT91_SRAM_MAX SZ_1M
-diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
-index 9061170..62761e1 100644
---- a/drivers/net/ethernet/cadence/at91_ether.c
-+++ b/drivers/net/ethernet/cadence/at91_ether.c
-@@ -30,6 +30,7 @@
- #include <linux/platform_device.h>
- #include <linux/clk.h>
- #include <linux/gfp.h>
-+#include <linux/phy.h>
-
- #include <asm/io.h>
- #include <asm/uaccess.h>
-@@ -51,21 +52,17 @@
- /*
- * Read from a EMAC register.
- */
--static inline unsigned long at91_emac_read(unsigned int reg)
-+static inline unsigned long at91_emac_read(struct at91_private *lp, unsigned int reg)
- {
-- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
--
-- return __raw_readl(emac_base + reg);
-+ return __raw_readl(lp->emac_base + reg);
- }
-
- /*
- * Write to a EMAC register.
- */
--static inline void at91_emac_write(unsigned int reg, unsigned long value)
-+static inline void at91_emac_write(struct at91_private *lp, unsigned int reg, unsigned long value)
- {
-- void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC;
--
-- __raw_writel(value, emac_base + reg);
-+ __raw_writel(value, lp->emac_base + reg);
- }
-
- /* ........................... PHY INTERFACE ........................... */
-@@ -75,32 +72,33 @@ static inline void at91_emac_write(unsigned int reg, unsigned long value)
- * When not called from an interrupt-handler, access to the PHY must be
- * protected by a spinlock.
- */
--static void enable_mdi(void)
-+static void enable_mdi(struct at91_private *lp)
- {
- unsigned long ctl;
-
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */
- }
-
- /*
- * Disable the MDIO bit in the MAC control register
- */
--static void disable_mdi(void)
-+static void disable_mdi(struct at91_private *lp)
- {
- unsigned long ctl;
-
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */
- }
-
- /*
- * Wait until the PHY operation is complete.
- */
--static inline void at91_phy_wait(void) {
-+static inline void at91_phy_wait(struct at91_private *lp)
-+{
- unsigned long timeout = jiffies + 2;
-
-- while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
-+ while (!(at91_emac_read(lp, AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) {
- if (time_after(jiffies, timeout)) {
- printk("at91_ether: MIO timeout\n");
- break;
-@@ -113,28 +111,28 @@ static inline void at91_phy_wait(void) {
- * Write value to the a PHY register
- * Note: MDI interface is assumed to already have been enabled.
- */
--static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value)
-+static void write_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int value)
- {
-- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
-+ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W
- | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA));
-
- /* Wait until IDLE bit in Network Status register is cleared */
-- at91_phy_wait();
-+ at91_phy_wait(lp);
- }
-
- /*
- * Read value stored in a PHY register.
- * Note: MDI interface is assumed to already have been enabled.
- */
--static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value)
-+static void read_phy(struct at91_private *lp, unsigned char phy_addr, unsigned char address, unsigned int *value)
- {
-- at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
-+ at91_emac_write(lp, AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R
- | ((phy_addr & 0x1f) << 23) | (address << 18));
-
- /* Wait until IDLE bit in Network Status register is cleared */
-- at91_phy_wait();
-+ at91_phy_wait(lp);
-
-- *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA;
-+ *value = at91_emac_read(lp, AT91_EMAC_MAN) & AT91_EMAC_DATA;
- }
-
- /* ........................... PHY MANAGEMENT .......................... */
-@@ -158,13 +156,13 @@ static void update_linkspeed(struct net_device *dev, int silent)
- }
-
- /* Link up, or auto-negotiation still in progress */
-- read_phy(lp->phy_address, MII_BMSR, &bmsr);
-- read_phy(lp->phy_address, MII_BMCR, &bmcr);
-+ read_phy(lp, lp->phy_address, MII_BMSR, &bmsr);
-+ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
- if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */
- if (!(bmsr & BMSR_ANEGCOMPLETE))
- return; /* Do nothing - another interrupt generated when negotiation complete */
-
-- read_phy(lp->phy_address, MII_LPA, &lpa);
-+ read_phy(lp, lp->phy_address, MII_LPA, &lpa);
- if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
- else speed = SPEED_10;
- if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
-@@ -175,7 +173,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
- }
-
- /* Update the MAC */
-- mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
-+ mac_cfg = at91_emac_read(lp, AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
- if (speed == SPEED_100) {
- if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
- mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
-@@ -186,7 +184,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
- mac_cfg |= AT91_EMAC_FD;
- else {} /* 10 Half Duplex */
- }
-- at91_emac_write(AT91_EMAC_CFG, mac_cfg);
-+ at91_emac_write(lp, AT91_EMAC_CFG, mac_cfg);
-
- if (!silent)
- printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
-@@ -207,34 +205,34 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
- * level-triggering. We therefore have to check if the PHY actually has
- * an IRQ pending.
- */
-- enable_mdi();
-+ enable_mdi(lp);
- if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
-- read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
-+ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */
- if (!(phy & (1 << 0)))
- goto done;
- }
- else if (lp->phy_type == MII_LXT971A_ID) {
-- read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
-+ read_phy(lp, lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */
- if (!(phy & (1 << 2)))
- goto done;
- }
- else if (lp->phy_type == MII_BCM5221_ID) {
-- read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
-+ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */
- if (!(phy & (1 << 0)))
- goto done;
- }
- else if (lp->phy_type == MII_KS8721_ID) {
-- read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
-+ read_phy(lp, lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */
- if (!(phy & ((1 << 2) | 1)))
- goto done;
- }
-- else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
-- read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
-+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
-+ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &phy);
- if (!(phy & ((1 << 2) | 1)))
- goto done;
- }
- else if (lp->phy_type == MII_DP83848_ID) {
-- read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
-+ read_phy(lp, lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
- if (!(phy & (1 << 7)))
- goto done;
- }
-@@ -242,7 +240,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
- update_linkspeed(dev, 0);
-
- done:
-- disable_mdi();
-+ disable_mdi(lp);
-
- return IRQ_HANDLED;
- }
-@@ -273,41 +271,41 @@ static void enable_phyirq(struct net_device *dev)
- }
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
-- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
- dsintr = dsintr & ~0xf00; /* clear bits 8..11 */
-- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
- }
- else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
-- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
- dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */
-- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
- }
- else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
- dsintr = (1 << 15) | ( 1 << 14);
-- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
- }
- else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
- dsintr = (1 << 10) | ( 1 << 8);
-- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
-+ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
- }
- else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
-- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
- dsintr = dsintr | 0x500; /* set bits 8, 10 */
-- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
- }
- else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
-- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
- dsintr = dsintr | 0x3c; /* set bits 2..5 */
-- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
-- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
-+ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
-+ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
- dsintr = dsintr | 0x3; /* set bits 0,1 */
-- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
- }
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
- }
-
-@@ -326,43 +324,43 @@ static void disable_phyirq(struct net_device *dev)
- }
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */
-- read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_DSINTR_REG, &dsintr);
- dsintr = dsintr | 0xf00; /* set bits 8..11 */
-- write_phy(lp->phy_address, MII_DSINTR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_DSINTR_REG, dsintr);
- }
- else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */
-- read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_ISINTE_REG, &dsintr);
- dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */
-- write_phy(lp->phy_address, MII_ISINTE_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_ISINTE_REG, dsintr);
- }
- else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */
-- read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_BCMINTR_REG, &dsintr);
- dsintr = ~(1 << 14);
-- write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_BCMINTR_REG, dsintr);
- }
- else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */
-- read_phy(lp->phy_address, MII_TPISTATUS, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_TPISTATUS, &dsintr);
- dsintr = ~((1 << 10) | (1 << 8));
-- write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
-+ write_phy(lp, lp->phy_address, MII_TPISTATUS, dsintr);
- }
- else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
-- read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_T78Q21INT_REG, &dsintr);
- dsintr = dsintr & ~0x500; /* clear bits 8, 10 */
-- write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_T78Q21INT_REG, dsintr);
- }
- else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
-- read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
-+ read_phy(lp, lp->phy_address, MII_DPMICR_REG, &dsintr);
- dsintr = dsintr & ~0x3; /* clear bits 0, 1 */
-- write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
-- read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
-+ write_phy(lp, lp->phy_address, MII_DPMICR_REG, dsintr);
-+ read_phy(lp, lp->phy_address, MII_DPMISR_REG, &dsintr);
- dsintr = dsintr & ~0x3c; /* clear bits 2..5 */
-- write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
-+ write_phy(lp, lp->phy_address, MII_DPMISR_REG, dsintr);
- }
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- irq_number = lp->board_data.phy_irq_pin;
-@@ -379,17 +377,17 @@ static void reset_phy(struct net_device *dev)
- unsigned int bmcr;
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- /* Perform PHY reset */
-- write_phy(lp->phy_address, MII_BMCR, BMCR_RESET);
-+ write_phy(lp, lp->phy_address, MII_BMCR, BMCR_RESET);
-
- /* Wait until PHY reset is complete */
- do {
-- read_phy(lp->phy_address, MII_BMCR, &bmcr);
-+ read_phy(lp, lp->phy_address, MII_BMCR, &bmcr);
- } while (!(bmcr & BMCR_RESET));
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
- }
- #endif
-@@ -399,13 +397,37 @@ static void at91ether_check_link(unsigned long dev_id)
- struct net_device *dev = (struct net_device *) dev_id;
- struct at91_private *lp = netdev_priv(dev);
-
-- enable_mdi();
-+ enable_mdi(lp);
- update_linkspeed(dev, 1);
-- disable_mdi();
-+ disable_mdi(lp);
-
- mod_timer(&lp->check_timer, jiffies + LINK_POLL_INTERVAL);
- }
-
-+/*
-+ * Perform any PHY-specific initialization.
-+ */
-+static void __init initialize_phy(struct at91_private *lp)
-+{
-+ unsigned int val;
-+
-+ spin_lock_irq(&lp->lock);
-+ enable_mdi(lp);
-+
-+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
-+ read_phy(lp, lp->phy_address, MII_DSCR_REG, &val);
-+ if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
-+ lp->phy_media = PORT_FIBRE;
-+ } else if (machine_is_csb337()) {
-+ /* mix link activity status into LED2 link state */
-+ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x0d22);
-+ } else if (machine_is_ecbat91())
-+ write_phy(lp, lp->phy_address, MII_LEDCTRL_REG, 0x156A);
-+
-+ disable_mdi(lp);
-+ spin_unlock_irq(&lp->lock);
-+}
-+
- /* ......................... ADDRESS MANAGEMENT ........................ */
-
- /*
-@@ -454,17 +476,19 @@ static short __init unpack_mac_address(struct net_device *dev, unsigned int hi,
- */
- static void __init get_mac_address(struct net_device *dev)
- {
-+ struct at91_private *lp = netdev_priv(dev);
-+
- /* Check Specific-Address 1 */
-- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L)))
-+ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA1H), at91_emac_read(lp, AT91_EMAC_SA1L)))
- return;
- /* Check Specific-Address 2 */
-- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L)))
-+ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA2H), at91_emac_read(lp, AT91_EMAC_SA2L)))
- return;
- /* Check Specific-Address 3 */
-- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L)))
-+ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA3H), at91_emac_read(lp, AT91_EMAC_SA3L)))
- return;
- /* Check Specific-Address 4 */
-- if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L)))
-+ if (unpack_mac_address(dev, at91_emac_read(lp, AT91_EMAC_SA4H), at91_emac_read(lp, AT91_EMAC_SA4L)))
- return;
-
- printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n");
-@@ -475,11 +499,13 @@ static void __init get_mac_address(struct net_device *dev)
- */
- static void update_mac_address(struct net_device *dev)
- {
-- at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
-- at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
-+ struct at91_private *lp = netdev_priv(dev);
-
-- at91_emac_write(AT91_EMAC_SA2L, 0);
-- at91_emac_write(AT91_EMAC_SA2H, 0);
-+ at91_emac_write(lp, AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]));
-+ at91_emac_write(lp, AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4]));
-+
-+ at91_emac_write(lp, AT91_EMAC_SA2L, 0);
-+ at91_emac_write(lp, AT91_EMAC_SA2H, 0);
- }
-
- /*
-@@ -559,6 +585,7 @@ static int hash_get_index(__u8 *addr)
- */
- static void at91ether_sethashtable(struct net_device *dev)
- {
-+ struct at91_private *lp = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- unsigned long mc_filter[2];
- unsigned int bitnr;
-@@ -570,8 +597,8 @@ static void at91ether_sethashtable(struct net_device *dev)
- mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
- }
-
-- at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
-- at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
-+ at91_emac_write(lp, AT91_EMAC_HSL, mc_filter[0]);
-+ at91_emac_write(lp, AT91_EMAC_HSH, mc_filter[1]);
- }
-
- /*
-@@ -579,9 +606,10 @@ static void at91ether_sethashtable(struct net_device *dev)
- */
- static void at91ether_set_multicast_list(struct net_device *dev)
- {
-+ struct at91_private *lp = netdev_priv(dev);
- unsigned long cfg;
-
-- cfg = at91_emac_read(AT91_EMAC_CFG);
-+ cfg = at91_emac_read(lp, AT91_EMAC_CFG);
-
- if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */
- cfg |= AT91_EMAC_CAF;
-@@ -589,34 +617,37 @@ static void at91ether_set_multicast_list(struct net_device *dev)
- cfg &= ~AT91_EMAC_CAF;
-
- if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */
-- at91_emac_write(AT91_EMAC_HSH, -1);
-- at91_emac_write(AT91_EMAC_HSL, -1);
-+ at91_emac_write(lp, AT91_EMAC_HSH, -1);
-+ at91_emac_write(lp, AT91_EMAC_HSL, -1);
- cfg |= AT91_EMAC_MTI;
- } else if (!netdev_mc_empty(dev)) { /* Enable specific multicasts */
- at91ether_sethashtable(dev);
- cfg |= AT91_EMAC_MTI;
- } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */
-- at91_emac_write(AT91_EMAC_HSH, 0);
-- at91_emac_write(AT91_EMAC_HSL, 0);
-+ at91_emac_write(lp, AT91_EMAC_HSH, 0);
-+ at91_emac_write(lp, AT91_EMAC_HSL, 0);
- cfg &= ~AT91_EMAC_MTI;
- }
-
-- at91_emac_write(AT91_EMAC_CFG, cfg);
-+ at91_emac_write(lp, AT91_EMAC_CFG, cfg);
- }
-
- /* ......................... ETHTOOL SUPPORT ........................... */
-
- static int mdio_read(struct net_device *dev, int phy_id, int location)
- {
-+ struct at91_private *lp = netdev_priv(dev);
- unsigned int value;
-
-- read_phy(phy_id, location, &value);
-+ read_phy(lp, phy_id, location, &value);
- return value;
- }
-
- static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
- {
-- write_phy(phy_id, location, value);
-+ struct at91_private *lp = netdev_priv(dev);
-+
-+ write_phy(lp, phy_id, location, value);
- }
-
- static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-@@ -625,11 +656,11 @@ static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cm
- int ret;
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- ret = mii_ethtool_gset(&lp->mii, cmd);
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */
-@@ -646,11 +677,11 @@ static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cm
- int ret;
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- ret = mii_ethtool_sset(&lp->mii, cmd);
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- return ret;
-@@ -662,11 +693,11 @@ static int at91ether_nwayreset(struct net_device *dev)
- int ret;
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
-
- ret = mii_nway_restart(&lp->mii);
-
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- return ret;
-@@ -696,9 +727,9 @@ static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- return -EINVAL;
-
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
- res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- return res;
-@@ -731,11 +762,11 @@ static void at91ether_start(struct net_device *dev)
- lp->rxBuffIndex = 0;
-
- /* Program address of descriptor list in Rx Buffer Queue register */
-- at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys);
-+ at91_emac_write(lp, AT91_EMAC_RBQP, (unsigned long) dlist_phys);
-
- /* Enable Receive and Transmit */
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE);
- }
-
- /*
-@@ -752,8 +783,8 @@ static int at91ether_open(struct net_device *dev)
- clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
-
- /* Clear internal statistics */
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_CSR);
-
- /* Update the MAC address (incase user has changed it) */
- update_mac_address(dev);
-@@ -762,15 +793,15 @@ static int at91ether_open(struct net_device *dev)
- enable_phyirq(dev);
-
- /* Enable MAC interrupts */
-- at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
-+ at91_emac_write(lp, AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA
- | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
- | AT91_EMAC_ROVR | AT91_EMAC_ABT);
-
- /* Determine current link speed */
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
- update_linkspeed(dev, 0);
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
- at91ether_start(dev);
-@@ -787,14 +818,14 @@ static int at91ether_close(struct net_device *dev)
- unsigned long ctl;
-
- /* Disable Receiver and Transmitter */
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE));
-
- /* Disable PHY interrupt */
- disable_phyirq(dev);
-
- /* Disable MAC interrupts */
-- at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
-+ at91_emac_write(lp, AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA
- | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM
- | AT91_EMAC_ROVR | AT91_EMAC_ABT);
-
-@@ -812,7 +843,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct at91_private *lp = netdev_priv(dev);
-
-- if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
-+ if (at91_emac_read(lp, AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) {
- netif_stop_queue(dev);
-
- /* Store packet information (to free when Tx completed) */
-@@ -822,9 +853,9 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
- dev->stats.tx_bytes += skb->len;
-
- /* Set address of the data in the Transmit Address register */
-- at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
-+ at91_emac_write(lp, AT91_EMAC_TAR, lp->skb_physaddr);
- /* Set length of the packet in the Transmit Control register */
-- at91_emac_write(AT91_EMAC_TCR, skb->len);
-+ at91_emac_write(lp, AT91_EMAC_TCR, skb->len);
-
- } else {
- printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
-@@ -841,31 +872,32 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
- */
- static struct net_device_stats *at91ether_stats(struct net_device *dev)
- {
-+ struct at91_private *lp = netdev_priv(dev);
- int ale, lenerr, seqe, lcol, ecol;
-
- if (netif_running(dev)) {
-- dev->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */
-- ale = at91_emac_read(AT91_EMAC_ALE);
-+ dev->stats.rx_packets += at91_emac_read(lp, AT91_EMAC_OK); /* Good frames received */
-+ ale = at91_emac_read(lp, AT91_EMAC_ALE);
- dev->stats.rx_frame_errors += ale; /* Alignment errors */
-- lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
-+ lenerr = at91_emac_read(lp, AT91_EMAC_ELR) + at91_emac_read(lp, AT91_EMAC_USF);
- dev->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */
-- seqe = at91_emac_read(AT91_EMAC_SEQE);
-+ seqe = at91_emac_read(lp, AT91_EMAC_SEQE);
- dev->stats.rx_crc_errors += seqe; /* CRC error */
-- dev->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */
-+ dev->stats.rx_fifo_errors += at91_emac_read(lp, AT91_EMAC_DRFC);/* Receive buffer not available */
- dev->stats.rx_errors += (ale + lenerr + seqe
-- + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
-+ + at91_emac_read(lp, AT91_EMAC_CDE) + at91_emac_read(lp, AT91_EMAC_RJB));
-
-- dev->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */
-- dev->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */
-- dev->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */
-- dev->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
-+ dev->stats.tx_packets += at91_emac_read(lp, AT91_EMAC_FRA); /* Frames successfully transmitted */
-+ dev->stats.tx_fifo_errors += at91_emac_read(lp, AT91_EMAC_TUE); /* Transmit FIFO underruns */
-+ dev->stats.tx_carrier_errors += at91_emac_read(lp, AT91_EMAC_CSE); /* Carrier Sense errors */
-+ dev->stats.tx_heartbeat_errors += at91_emac_read(lp, AT91_EMAC_SQEE);/* Heartbeat error */
-
-- lcol = at91_emac_read(AT91_EMAC_LCOL);
-- ecol = at91_emac_read(AT91_EMAC_ECOL);
-+ lcol = at91_emac_read(lp, AT91_EMAC_LCOL);
-+ ecol = at91_emac_read(lp, AT91_EMAC_ECOL);
- dev->stats.tx_window_errors += lcol; /* Late collisions */
- dev->stats.tx_aborted_errors += ecol; /* 16 collisions */
-
-- dev->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
-+ dev->stats.collisions += (at91_emac_read(lp, AT91_EMAC_SCOL) + at91_emac_read(lp, AT91_EMAC_MCOL) + lcol + ecol);
- }
- return &dev->stats;
- }
-@@ -922,7 +954,7 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
-
- /* MAC Interrupt Status register indicates what interrupts are pending.
- It is automatically cleared once read. */
-- intstatus = at91_emac_read(AT91_EMAC_ISR);
-+ intstatus = at91_emac_read(lp, AT91_EMAC_ISR);
-
- if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
- at91ether_rx(dev);
-@@ -942,9 +974,9 @@ static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
-
- /* Work-around for Errata #11 */
- if (intstatus & AT91_EMAC_RBNA) {
-- ctl = at91_emac_read(AT91_EMAC_CTL);
-- at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
-- at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
-+ ctl = at91_emac_read(lp, AT91_EMAC_CTL);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE);
-+ at91_emac_write(lp, AT91_EMAC_CTL, ctl | AT91_EMAC_RE);
- }
-
- if (intstatus & AT91_EMAC_ROVR)
-@@ -980,189 +1012,199 @@ static const struct net_device_ops at91ether_netdev_ops = {
- };
-
- /*
-- * Initialize the ethernet interface
-+ * Detect the PHY type, and its address.
- */
--static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
-- struct platform_device *pdev, struct clk *ether_clk)
-+static int __init at91ether_phy_detect(struct at91_private *lp)
-+{
-+ unsigned int phyid1, phyid2;
-+ unsigned long phy_id;
-+ unsigned short phy_address = 0;
-+
-+ while (phy_address < PHY_MAX_ADDR) {
-+ /* Read the PHY ID registers */
-+ enable_mdi(lp);
-+ read_phy(lp, phy_address, MII_PHYSID1, &phyid1);
-+ read_phy(lp, phy_address, MII_PHYSID2, &phyid2);
-+ disable_mdi(lp);
-+
-+ phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
-+ switch (phy_id) {
-+ case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
-+ case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
-+ case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
-+ case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
-+ case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
-+ case MII_DP83847_ID: /* National Semiconductor DP83847: */
-+ case MII_DP83848_ID: /* National Semiconductor DP83848: */
-+ case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
-+ case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
-+ case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
-+ case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
-+ /* store detected values */
-+ lp->phy_type = phy_id; /* Type of PHY connected */
-+ lp->phy_address = phy_address; /* MDI address of PHY */
-+ return 1;
-+ }
-+
-+ phy_address++;
-+ }
-+
-+ return 0; /* not detected */
-+}
-+
-+
-+/*
-+ * Detect MAC & PHY and perform ethernet interface initialization
-+ */
-+static int __init at91ether_probe(struct platform_device *pdev)
- {
- struct macb_platform_data *board_data = pdev->dev.platform_data;
-+ struct resource *regs;
- struct net_device *dev;
- struct at91_private *lp;
-- unsigned int val;
- int res;
-
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!regs)
-+ return -ENOENT;
-+
- dev = alloc_etherdev(sizeof(struct at91_private));
- if (!dev)
- return -ENOMEM;
-
-- dev->base_addr = AT91_VA_BASE_EMAC;
-- dev->irq = AT91RM9200_ID_EMAC;
-+ lp = netdev_priv(dev);
-+ lp->board_data = *board_data;
-+ spin_lock_init(&lp->lock);
-+
-+ dev->base_addr = regs->start; /* physical base address */
-+ lp->emac_base = ioremap(regs->start, regs->end - regs->start + 1);
-+ if (!lp->emac_base) {
-+ res = -ENOMEM;
-+ goto err_free_dev;
-+ }
-+
-+ /* Clock */
-+ lp->ether_clk = clk_get(&pdev->dev, "ether_clk");
-+ if (IS_ERR(lp->ether_clk)) {
-+ res = -ENODEV;
-+ goto err_ioumap;
-+ }
-+ clk_enable(lp->ether_clk);
-
- /* Install the interrupt handler */
-+ dev->irq = platform_get_irq(pdev, 0);
- if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
-- free_netdev(dev);
-- return -EBUSY;
-+ res = -EBUSY;
-+ goto err_disable_clock;
- }
-
- /* Allocate memory for DMA Receive descriptors */
-- lp = netdev_priv(dev);
- lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL);
- if (lp->dlist == NULL) {
-- free_irq(dev->irq, dev);
-- free_netdev(dev);
-- return -ENOMEM;
-+ res = -ENOMEM;
-+ goto err_free_irq;
- }
-- lp->board_data = *board_data;
-- lp->ether_clk = ether_clk;
-- platform_set_drvdata(pdev, dev);
--
-- spin_lock_init(&lp->lock);
-
- ether_setup(dev);
- dev->netdev_ops = &at91ether_netdev_ops;
- dev->ethtool_ops = &at91ether_ethtool_ops;
--
-+ platform_set_drvdata(pdev, dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
-
- get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */
- update_mac_address(dev); /* Program ethernet address into MAC */
-
-- at91_emac_write(AT91_EMAC_CTL, 0);
-+ at91_emac_write(lp, AT91_EMAC_CTL, 0);
-
-- if (lp->board_data.is_rmii)
-- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
-+ if (board_data->is_rmii)
-+ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII);
- else
-- at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
-+ at91_emac_write(lp, AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG);
-
-- /* Perform PHY-specific initialization */
-- spin_lock_irq(&lp->lock);
-- enable_mdi();
-- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) {
-- read_phy(phy_address, MII_DSCR_REG, &val);
-- if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */
-- lp->phy_media = PORT_FIBRE;
-- } else if (machine_is_csb337()) {
-- /* mix link activity status into LED2 link state */
-- write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22);
-- } else if (machine_is_ecbat91())
-- write_phy(phy_address, MII_LEDCTRL_REG, 0x156A);
-+ /* Detect PHY */
-+ if (!at91ether_phy_detect(lp)) {
-+ printk(KERN_ERR "at91_ether: Could not detect ethernet PHY\n");
-+ res = -ENODEV;
-+ goto err_free_dmamem;
-+ }
-
-- disable_mdi();
-- spin_unlock_irq(&lp->lock);
-+ initialize_phy(lp);
-
- lp->mii.dev = dev; /* Support for ethtool */
- lp->mii.mdio_read = mdio_read;
- lp->mii.mdio_write = mdio_write;
-- lp->mii.phy_id = phy_address;
-+ lp->mii.phy_id = lp->phy_address;
- lp->mii.phy_id_mask = 0x1f;
- lp->mii.reg_num_mask = 0x1f;
-
-- lp->phy_type = phy_type; /* Type of PHY connected */
-- lp->phy_address = phy_address; /* MDI address of PHY */
--
- /* Register the network interface */
- res = register_netdev(dev);
-- if (res) {
-- free_irq(dev->irq, dev);
-- free_netdev(dev);
-- dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
-- return res;
-- }
-+ if (res)
-+ goto err_free_dmamem;
-
- /* Determine current link speed */
- spin_lock_irq(&lp->lock);
-- enable_mdi();
-+ enable_mdi(lp);
- update_linkspeed(dev, 0);
-- disable_mdi();
-+ disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
- netif_carrier_off(dev); /* will be enabled in open() */
-
- /* If board has no PHY IRQ, use a timer to poll the PHY */
-- if (!gpio_is_valid(lp->board_data.phy_irq_pin)) {
-+ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
-+ gpio_request(board_data->phy_irq_pin, "ethernet_phy");
-+ } else {
-+ /* If board has no PHY IRQ, use a timer to poll the PHY */
- init_timer(&lp->check_timer);
- lp->check_timer.data = (unsigned long)dev;
- lp->check_timer.function = at91ether_check_link;
-- } else if (lp->board_data.phy_irq_pin >= 32)
-- gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy");
-+ }
-
- /* Display ethernet banner */
- printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n",
- dev->name, (uint) dev->base_addr, dev->irq,
-- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
-- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
-+ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
-+ at91_emac_read(lp, AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
- dev->dev_addr);
-- if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
-+ if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
- printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
-- else if (phy_type == MII_LXT971A_ID)
-+ else if (lp->phy_type == MII_LXT971A_ID)
- printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
-- else if (phy_type == MII_RTL8201_ID)
-+ else if (lp->phy_type == MII_RTL8201_ID)
- printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name);
-- else if (phy_type == MII_BCM5221_ID)
-+ else if (lp->phy_type == MII_BCM5221_ID)
- printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
-- else if (phy_type == MII_DP83847_ID)
-+ else if (lp->phy_type == MII_DP83847_ID)
- printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
-- else if (phy_type == MII_DP83848_ID)
-+ else if (lp->phy_type == MII_DP83848_ID)
- printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
-- else if (phy_type == MII_AC101L_ID)
-+ else if (lp->phy_type == MII_AC101L_ID)
- printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
-- else if (phy_type == MII_KS8721_ID)
-+ else if (lp->phy_type == MII_KS8721_ID)
- printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
-- else if (phy_type == MII_T78Q21x3_ID)
-+ else if (lp->phy_type == MII_T78Q21x3_ID)
- printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
-- else if (phy_type == MII_LAN83C185_ID)
-+ else if (lp->phy_type == MII_LAN83C185_ID)
- printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
-
-- return 0;
--}
--
--/*
-- * Detect MAC and PHY and perform initialization
-- */
--static int __init at91ether_probe(struct platform_device *pdev)
--{
-- unsigned int phyid1, phyid2;
-- int detected = -1;
-- unsigned long phy_id;
-- unsigned short phy_address = 0;
-- struct clk *ether_clk;
--
-- ether_clk = clk_get(&pdev->dev, "ether_clk");
-- if (IS_ERR(ether_clk)) {
-- printk(KERN_ERR "at91_ether: no clock defined\n");
-- return -ENODEV;
-- }
-- clk_enable(ether_clk); /* Enable Peripheral clock */
--
-- while ((detected != 0) && (phy_address < 32)) {
-- /* Read the PHY ID registers */
-- enable_mdi();
-- read_phy(phy_address, MII_PHYSID1, &phyid1);
-- read_phy(phy_address, MII_PHYSID2, &phyid2);
-- disable_mdi();
--
-- phy_id = (phyid1 << 16) | (phyid2 & 0xfff0);
-- switch (phy_id) {
-- case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */
-- case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */
-- case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
-- case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
-- case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
-- case MII_DP83847_ID: /* National Semiconductor DP83847: */
-- case MII_DP83848_ID: /* National Semiconductor DP83848: */
-- case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
-- case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
-- case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
-- case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
-- detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
-- break;
-- }
-+ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
-
-- phy_address++;
-- }
-+ return 0;
-
-- clk_disable(ether_clk); /* Disable Peripheral clock */
-
-- return detected;
-+err_free_dmamem:
-+ platform_set_drvdata(pdev, NULL);
-+ dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
-+err_free_irq:
-+ free_irq(dev->irq, dev);
-+err_disable_clock:
-+ clk_disable(lp->ether_clk);
-+ clk_put(lp->ether_clk);
-+err_ioumap:
-+ iounmap(lp->emac_base);
-+err_free_dev:
-+ free_netdev(dev);
-+ return res;
- }
-
- static int __devexit at91ether_remove(struct platform_device *pdev)
-@@ -1170,8 +1212,7 @@ static int __devexit at91ether_remove(struct platform_device *pdev)
- struct net_device *dev = platform_get_drvdata(pdev);
- struct at91_private *lp = netdev_priv(dev);
-
-- if (gpio_is_valid(lp->board_data.phy_irq_pin) &&
-- lp->board_data.phy_irq_pin >= 32)
-+ if (gpio_is_valid(lp->board_data.phy_irq_pin))
- gpio_free(lp->board_data.phy_irq_pin);
-
- unregister_netdev(dev);
-diff --git a/drivers/net/ethernet/cadence/at91_ether.h b/drivers/net/ethernet/cadence/at91_ether.h
-index 3725fbb0..0ef6328 100644
---- a/drivers/net/ethernet/cadence/at91_ether.h
-+++ b/drivers/net/ethernet/cadence/at91_ether.h
-@@ -88,6 +88,7 @@ struct at91_private
- struct macb_platform_data board_data; /* board-specific
- * configuration (shared with
- * macb for common data */
-+ void __iomem *emac_base; /* base register address */
- struct clk *ether_clk; /* clock */
-
- /* PHY */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8d5bf013fc624b1abb36240dd06dc5b43201e2a9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 26 Apr 2012 00:30:43 +0000
+Subject: net/at91_ether: use gpio_to_irq for phy IRQ line
+
+commit 86cc070eb19640d42941d3074e42c761d4c1c59c upstream.
+
+Use the gpio_to_irq() function to retrieve the phy IRQ line
+from the GPIO pin specification.
+This fix is needed now that we have moved to irqdomains on AT91.
+
+Reported-by: Jamie Iles <jamie@jamieiles.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Andrew Victor <avictor.za@gmail.com>
+Cc: David S. Miller <davem@davemloft.net>
+Cc: netdev@vger.kernel.org
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/cadence/at91_ether.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
+index 62761e1..7788419 100644
+--- a/drivers/net/ethernet/cadence/at91_ether.c
++++ b/drivers/net/ethernet/cadence/at91_ether.c
+@@ -263,7 +263,7 @@ static void enable_phyirq(struct net_device *dev)
+ return;
+ }
+
+- irq_number = lp->board_data.phy_irq_pin;
++ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
+ status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
+ if (status) {
+ printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
+@@ -363,7 +363,7 @@ static void disable_phyirq(struct net_device *dev)
+ disable_mdi(lp);
+ spin_unlock_irq(&lp->lock);
+
+- irq_number = lp->board_data.phy_irq_pin;
++ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
+ free_irq(irq_number, dev); /* Free interrupt handler */
+ }
+
+@@ -1234,7 +1234,7 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
+
+ if (netif_running(net_dev)) {
+ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
+- int phy_irq = lp->board_data.phy_irq_pin;
++ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
+ disable_irq(phy_irq);
+ }
+
+@@ -1258,7 +1258,7 @@ static int at91ether_resume(struct platform_device *pdev)
+ netif_start_queue(net_dev);
+
+ if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
+- int phy_irq = lp->board_data.phy_irq_pin;
++ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
+ enable_irq(phy_irq);
+ }
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 4c7f53afde86fed3bbc8cb4583b46e0b154ca01f Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 26 Apr 2012 00:30:43 +0000
-Subject: net/at91_ether: use gpio_to_irq for phy IRQ line
-
-Use the gpio_to_irq() function to retrieve the phy IRQ line
-from the GPIO pin specification.
-This fix is needed now that we have moved to irqdomains on AT91.
-
-Reported-by: Jamie Iles <jamie@jamieiles.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Cc: Andrew Victor <avictor.za@gmail.com>
-Cc: David S. Miller <davem@davemloft.net>
-Cc: netdev@vger.kernel.org
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/ethernet/cadence/at91_ether.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
-index 62761e1..7788419 100644
---- a/drivers/net/ethernet/cadence/at91_ether.c
-+++ b/drivers/net/ethernet/cadence/at91_ether.c
-@@ -263,7 +263,7 @@ static void enable_phyirq(struct net_device *dev)
- return;
- }
-
-- irq_number = lp->board_data.phy_irq_pin;
-+ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
- status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
- if (status) {
- printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
-@@ -363,7 +363,7 @@ static void disable_phyirq(struct net_device *dev)
- disable_mdi(lp);
- spin_unlock_irq(&lp->lock);
-
-- irq_number = lp->board_data.phy_irq_pin;
-+ irq_number = gpio_to_irq(lp->board_data.phy_irq_pin);
- free_irq(irq_number, dev); /* Free interrupt handler */
- }
-
-@@ -1234,7 +1234,7 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
-
- if (netif_running(net_dev)) {
- if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
-- int phy_irq = lp->board_data.phy_irq_pin;
-+ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
- disable_irq(phy_irq);
- }
-
-@@ -1258,7 +1258,7 @@ static int at91ether_resume(struct platform_device *pdev)
- netif_start_queue(net_dev);
-
- if (gpio_is_valid(lp->board_data.phy_irq_pin)) {
-- int phy_irq = lp->board_data.phy_irq_pin;
-+ int phy_irq = gpio_to_irq(lp->board_data.phy_irq_pin);
- enable_irq(phy_irq);
- }
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From df5dbd6c7571a36641c5ec724afb595ba2d9fa82 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 3 Jul 2012 23:14:13 +0000
+Subject: net/macb: manage carrier state with call to netif_carrier_{on|off}()
+
+commit 03fc4721cd96753696a988a2ba563f9f08ad4e9f upstream.
+
+OFF carrier state is setup in probe() open() and suspend() functions.
+The carrier ON state is managed in macb_handle_link_change().
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/ethernet/cadence/macb.c | 13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index c4834c2..6100b85 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -179,13 +179,16 @@ static void macb_handle_link_change(struct net_device *dev)
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ if (status_change) {
+- if (phydev->link)
++ if (phydev->link) {
++ netif_carrier_on(dev);
+ netdev_info(dev, "link up (%d/%s)\n",
+ phydev->speed,
+ phydev->duplex == DUPLEX_FULL ?
+ "Full" : "Half");
+- else
++ } else {
++ netif_carrier_off(dev);
+ netdev_info(dev, "link down\n");
++ }
+ }
+ }
+
+@@ -1033,6 +1036,9 @@ static int macb_open(struct net_device *dev)
+
+ netdev_dbg(bp->dev, "open\n");
+
++ /* carrier starts down */
++ netif_carrier_off(dev);
++
+ /* if the phy is not yet register, retry later*/
+ if (!bp->phy_dev)
+ return -EAGAIN;
+@@ -1405,6 +1411,8 @@ static int __init macb_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, dev);
+
++ netif_carrier_off(dev);
++
+ netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n",
+ macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr,
+ dev->irq, dev->dev_addr);
+@@ -1468,6 +1476,7 @@ static int macb_suspend(struct platform_device *pdev, pm_message_t state)
+ struct net_device *netdev = platform_get_drvdata(pdev);
+ struct macb *bp = netdev_priv(netdev);
+
++ netif_carrier_off(netdev);
+ netif_device_detach(netdev);
+
+ clk_disable(bp->hclk);
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From ff53d26da93227bae1309bfd9c404d17fd5baf8b Mon Sep 17 00:00:00 2001
+From: Bo Shen <voice.shen@atmel.com>
+Date: Fri, 11 May 2012 17:39:28 +0800
+Subject: ALSA: atmel/ac97c: correct the unexpected behavior when using
+ uninitial value for reset pin
+
+commit b2522f9262539fc328b4b9344f8a2f7ef2cb18d5 upstream.
+
+When pdata->reset_pin is passed with a negative value (means gpio
+is invalid), then chip->reset_pin will not be assigned to a vaule,
+it will use default value 0. This will cause unexpected behavior.
+
+So, add this patch to correct.
+
+Signed-off-by: Bo Shen <voice.shen@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+---
+ sound/atmel/ac97c.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
+index 115313e..f5ded64 100644
+--- a/sound/atmel/ac97c.c
++++ b/sound/atmel/ac97c.c
+@@ -991,6 +991,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
+ gpio_direction_output(pdata->reset_pin, 1);
+ chip->reset_pin = pdata->reset_pin;
+ }
++ } else {
++ chip->reset_pin = -EINVAL;
+ }
+
+ snd_card_set_dev(card, &pdev->dev);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 7753ed0e33522a318f41773a78c2900a038c23be Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 3 Jul 2012 23:14:13 +0000
-Subject: net/macb: manage carrier state with call to netif_carrier_{on|off}()
-
-OFF carrier state is setup in probe() open() and suspend() functions.
-The carrier ON state is managed in macb_handle_link_change().
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/ethernet/cadence/macb.c | 13 +++++++++++--
- 1 file changed, 11 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index c4834c2..6100b85 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -179,13 +179,16 @@ static void macb_handle_link_change(struct net_device *dev)
- spin_unlock_irqrestore(&bp->lock, flags);
-
- if (status_change) {
-- if (phydev->link)
-+ if (phydev->link) {
-+ netif_carrier_on(dev);
- netdev_info(dev, "link up (%d/%s)\n",
- phydev->speed,
- phydev->duplex == DUPLEX_FULL ?
- "Full" : "Half");
-- else
-+ } else {
-+ netif_carrier_off(dev);
- netdev_info(dev, "link down\n");
-+ }
- }
- }
-
-@@ -1033,6 +1036,9 @@ static int macb_open(struct net_device *dev)
-
- netdev_dbg(bp->dev, "open\n");
-
-+ /* carrier starts down */
-+ netif_carrier_off(dev);
-+
- /* if the phy is not yet register, retry later*/
- if (!bp->phy_dev)
- return -EAGAIN;
-@@ -1405,6 +1411,8 @@ static int __init macb_probe(struct platform_device *pdev)
-
- platform_set_drvdata(pdev, dev);
-
-+ netif_carrier_off(dev);
-+
- netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n",
- macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr,
- dev->irq, dev->dev_addr);
-@@ -1468,6 +1476,7 @@ static int macb_suspend(struct platform_device *pdev, pm_message_t state)
- struct net_device *netdev = platform_get_drvdata(pdev);
- struct macb *bp = netdev_priv(netdev);
-
-+ netif_carrier_off(netdev);
- netif_device_detach(netdev);
-
- clk_disable(bp->hclk);
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From dbbe3702cb9bf1aa4e07dc6fe2cce479f75ab39e Mon Sep 17 00:00:00 2001
-From: Bo Shen <voice.shen@atmel.com>
-Date: Fri, 11 May 2012 17:39:28 +0800
-Subject: ALSA: atmel/ac97c: correct the unexpected behavior when using
- uninitial value for reset pin
-
-When pdata->reset_pin is passed with a negative value (means gpio
-is invalid), then chip->reset_pin will not be assigned to a vaule,
-it will use default value 0. This will cause unexpected behavior.
-
-So, add this patch to correct.
-
-Signed-off-by: Bo Shen <voice.shen@atmel.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
----
- sound/atmel/ac97c.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
-index 115313e..f5ded64 100644
---- a/sound/atmel/ac97c.c
-+++ b/sound/atmel/ac97c.c
-@@ -991,6 +991,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
- gpio_direction_output(pdata->reset_pin, 1);
- chip->reset_pin = pdata->reset_pin;
- }
-+ } else {
-+ chip->reset_pin = -EINVAL;
- }
-
- snd_card_set_dev(card, &pdev->dev);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From a1ac896220cc6517c99b449fee4b98618cf4d4d2 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Thu, 31 May 2012 18:09:20 +0800
+Subject: MTD: at91: extract hw ecc initialization to one function
+
+commit 3dfe41a4c705223c66373968327407e11c2fb1a1 upstream.
+
+This patch moves hw ecc initialization code to one function.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 127 ++++++++++++++++++++++--------------------
+ 1 file changed, 66 insertions(+), 61 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 2165576..4ea0a04 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -523,6 +523,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ }
+ #endif
+
++static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *nand_chip = &host->nand_chip;
++ struct resource *regs;
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs) {
++ dev_err(host->dev,
++ "Can't get I/O resource regs, use software ECC\n");
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ host->ecc = ioremap(regs->start, resource_size(regs));
++ if (host->ecc == NULL) {
++ dev_err(host->dev, "ioremap failed\n");
++ return -EIO;
++ }
++
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 512:
++ nand_chip->ecc.layout = &atmel_oobinfo_small;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
++ break;
++ case 1024:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
++ break;
++ case 2048:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
++ break;
++ case 4096:
++ nand_chip->ecc.layout = &atmel_oobinfo_large;
++ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
++ break;
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ /* set up for HW ECC */
++ nand_chip->ecc.calculate = atmel_nand_calculate;
++ nand_chip->ecc.correct = atmel_nand_correct;
++ nand_chip->ecc.hwctl = atmel_nand_hwctl;
++ nand_chip->ecc.read_page = atmel_nand_read_page;
++ nand_chip->ecc.bytes = 4;
++ nand_chip->ecc.strength = 1;
++
++ return 0;
++}
++
+ /*
+ * Probe for the NAND device.
+ */
+@@ -531,7 +591,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ struct atmel_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+- struct resource *regs;
+ struct resource *mem;
+ struct mtd_part_parser_data ppdata = {};
+ int res;
+@@ -583,29 +642,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ nand_chip->dev_ready = atmel_nand_device_ready;
+
+ nand_chip->ecc.mode = host->board.ecc_mode;
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
+- printk(KERN_ERR "atmel_nand: can't get I/O resource "
+- "regs\nFalling back on software ECC\n");
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- }
+-
+- if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- host->ecc = ioremap(regs->start, resource_size(regs));
+- if (host->ecc == NULL) {
+- printk(KERN_ERR "atmel_nand: ioremap failed\n");
+- res = -EIO;
+- goto err_ecc_ioremap;
+- }
+- nand_chip->ecc.calculate = atmel_nand_calculate;
+- nand_chip->ecc.correct = atmel_nand_correct;
+- nand_chip->ecc.hwctl = atmel_nand_hwctl;
+- nand_chip->ecc.read_page = atmel_nand_read_page;
+- nand_chip->ecc.bytes = 4;
+- nand_chip->ecc.strength = 1;
+- }
+-
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ if (host->board.bus_width_16) /* 16-bit bus width */
+@@ -657,40 +693,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ }
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- /* ECC is calculated for the whole page (1 step) */
+- nand_chip->ecc.size = mtd->writesize;
+-
+- /* set ECC page size and oob layout */
+- switch (mtd->writesize) {
+- case 512:
+- nand_chip->ecc.layout = &atmel_oobinfo_small;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+- break;
+- case 1024:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+- break;
+- case 2048:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+- break;
+- case 4096:
+- nand_chip->ecc.layout = &atmel_oobinfo_large;
+- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+- break;
+- default:
+- /* page size not handled by HW ECC */
+- /* switching back to soft ECC */
+- nand_chip->ecc.mode = NAND_ECC_SOFT;
+- nand_chip->ecc.calculate = NULL;
+- nand_chip->ecc.correct = NULL;
+- nand_chip->ecc.hwctl = NULL;
+- nand_chip->ecc.read_page = NULL;
+- nand_chip->ecc.postpad = 0;
+- nand_chip->ecc.prepad = 0;
+- nand_chip->ecc.bytes = 0;
+- break;
+- }
++ res = atmel_hw_nand_init_params(pdev, host);
++ if (res != 0)
++ goto err_hw_ecc;
+ }
+
+ /* second phase scan */
+@@ -707,15 +712,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ return res;
+
+ err_scan_tail:
++ if (host->ecc)
++ iounmap(host->ecc);
++err_hw_ecc:
+ err_scan_ident:
+ err_no_card:
+ atmel_nand_disable(host);
+ platform_set_drvdata(pdev, NULL);
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
+- if (host->ecc)
+- iounmap(host->ecc);
+-err_ecc_ioremap:
+ iounmap(host->io_base);
+ err_nand_ioremap:
+ kfree(host);
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 0ac83ef70e787b4309088615a0375d7318bdcd8f Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 26 Jun 2012 17:42:22 +0800
+Subject: MTD: at91: add dt parameters for Atmel PMECC
+
+commit a41b51a1f7c15a1b00f30a3ad2d0373ad51b883d upstream.
+
+Add DT support for PMECC parameters.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ .../devicetree/bindings/mtd/atmel-nand.txt | 40 ++++++++++++++++-
+ drivers/mtd/nand/atmel_nand.c | 52 +++++++++++++++++++++-
+ 2 files changed, 90 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+index a200695..d555421 100644
+--- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
++++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
+@@ -3,7 +3,9 @@ Atmel NAND flash
+ Required properties:
+ - compatible : "atmel,at91rm9200-nand".
+ - reg : should specify localbus address and size used for the chip,
+- and if availlable the ECC.
++ and hardware ECC controller if available.
++ If the hardware ECC is PMECC, it should contain address and size for
++ PMECC, PMECC Error Location controller and ROM which has lookup tables.
+ - atmel,nand-addr-offset : offset for the address latch.
+ - atmel,nand-cmd-offset : offset for the command latch.
+ - #address-cells, #size-cells : Must be present if the device has sub-nodes
+@@ -16,6 +18,15 @@ Optional properties:
+ - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
+ Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
+ "soft_bch".
++- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
++ Only supported by at91sam9x5 or later sam9 product.
++- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
++ Controller. Supported values are: 2, 4, 8, 12, 24.
++- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
++ are: 512, 1024.
++- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
++ for different sector size. First one is for sector size 512, the next is for
++ sector size 1024.
+ - nand-bus-width : 8 or 16 bus width if not present 8
+ - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+
+@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
+ ...
+ };
+ };
++
++/* for PMECC supported chips */
++nand0: nand@40000000 {
++ compatible = "atmel,at91rm9200-nand";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ reg = < 0x40000000 0x10000000 /* bus addr & size */
++ 0xffffe000 0x00000600 /* PMECC addr & size */
++ 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */
++ 0x00100000 0x00100000 /* ROM addr & size */
++ >;
++ atmel,nand-addr-offset = <21>; /* ale */
++ atmel,nand-cmd-offset = <22>; /* cle */
++ nand-on-flash-bbt;
++ nand-ecc-mode = "hw";
++ atmel,has-pmecc; /* enable PMECC */
++ atmel,pmecc-cap = <2>;
++ atmel,pmecc-sector-size = <512>;
++ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
++ gpios = <&pioD 5 0 /* rdy */
++ &pioD 4 0 /* nce */
++ 0 /* cd */
++ >;
++ partition@0 {
++ ...
++ };
++};
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 4ea0a04..712a705 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -93,6 +93,11 @@ struct atmel_nand_host {
+
+ struct completion comp;
+ struct dma_chan *dma_chan;
++
++ bool has_pmecc;
++ u8 pmecc_corr_cap;
++ u16 pmecc_sector_size;
++ u32 pmecc_lookup_table_offset;
+ };
+
+ static int cpu_has_dma(void)
+@@ -477,7 +482,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
+ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ struct device_node *np)
+ {
+- u32 val;
++ u32 val, table_offset;
++ u32 offset[2];
+ int ecc_mode;
+ struct atmel_nand_data *board = &host->board;
+ enum of_gpio_flags flags;
+@@ -513,6 +519,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
+ board->enable_pin = of_get_gpio(np, 1);
+ board->det_pin = of_get_gpio(np, 2);
+
++ host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
++
++ if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
++ return 0; /* Not using PMECC */
++
++ /* use PMECC, get correction capability, sector size and lookup
++ * table offset.
++ */
++ if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
++ dev_err(host->dev, "Cannot decide PMECC Capability\n");
++ return -EINVAL;
++ } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
++ (val != 24)) {
++ dev_err(host->dev,
++ "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
++ val);
++ return -EINVAL;
++ }
++ host->pmecc_corr_cap = (u8)val;
++
++ if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
++ dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
++ return -EINVAL;
++ } else if ((val != 512) && (val != 1024)) {
++ dev_err(host->dev,
++ "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
++ val);
++ return -EINVAL;
++ }
++ host->pmecc_sector_size = (u16)val;
++
++ if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
++ offset, 2) != 0) {
++ dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
++ return -EINVAL;
++ }
++ table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
++
++ if (!table_offset) {
++ dev_err(host->dev, "Invalid PMECC lookup table offset\n");
++ return -EINVAL;
++ }
++ host->pmecc_lookup_table_offset = table_offset;
++
+ return 0;
+ }
+ #else
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 37a9c14614a63c3e5fed9d6cb18638d765a65f80 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Thu, 31 May 2012 18:09:20 +0800
-Subject: MTD: at91: extract hw ecc initialization to one function
-
-This patch moves hw ecc initialization code to one function.
-
-Signed-off-by: Hong Xu <hong.xu@atmel.com>
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 127 ++++++++++++++++++++++--------------------
- 1 file changed, 66 insertions(+), 61 deletions(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 2165576..4ea0a04 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -523,6 +523,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
- }
- #endif
-
-+static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
-+ struct atmel_nand_host *host)
-+{
-+ struct mtd_info *mtd = &host->mtd;
-+ struct nand_chip *nand_chip = &host->nand_chip;
-+ struct resource *regs;
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (!regs) {
-+ dev_err(host->dev,
-+ "Can't get I/O resource regs, use software ECC\n");
-+ nand_chip->ecc.mode = NAND_ECC_SOFT;
-+ return 0;
-+ }
-+
-+ host->ecc = ioremap(regs->start, resource_size(regs));
-+ if (host->ecc == NULL) {
-+ dev_err(host->dev, "ioremap failed\n");
-+ return -EIO;
-+ }
-+
-+ /* ECC is calculated for the whole page (1 step) */
-+ nand_chip->ecc.size = mtd->writesize;
-+
-+ /* set ECC page size and oob layout */
-+ switch (mtd->writesize) {
-+ case 512:
-+ nand_chip->ecc.layout = &atmel_oobinfo_small;
-+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
-+ break;
-+ case 1024:
-+ nand_chip->ecc.layout = &atmel_oobinfo_large;
-+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
-+ break;
-+ case 2048:
-+ nand_chip->ecc.layout = &atmel_oobinfo_large;
-+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
-+ break;
-+ case 4096:
-+ nand_chip->ecc.layout = &atmel_oobinfo_large;
-+ ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
-+ break;
-+ default:
-+ /* page size not handled by HW ECC */
-+ /* switching back to soft ECC */
-+ nand_chip->ecc.mode = NAND_ECC_SOFT;
-+ return 0;
-+ }
-+
-+ /* set up for HW ECC */
-+ nand_chip->ecc.calculate = atmel_nand_calculate;
-+ nand_chip->ecc.correct = atmel_nand_correct;
-+ nand_chip->ecc.hwctl = atmel_nand_hwctl;
-+ nand_chip->ecc.read_page = atmel_nand_read_page;
-+ nand_chip->ecc.bytes = 4;
-+ nand_chip->ecc.strength = 1;
-+
-+ return 0;
-+}
-+
- /*
- * Probe for the NAND device.
- */
-@@ -531,7 +591,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- struct atmel_nand_host *host;
- struct mtd_info *mtd;
- struct nand_chip *nand_chip;
-- struct resource *regs;
- struct resource *mem;
- struct mtd_part_parser_data ppdata = {};
- int res;
-@@ -583,29 +642,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- nand_chip->dev_ready = atmel_nand_device_ready;
-
- nand_chip->ecc.mode = host->board.ecc_mode;
--
-- regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-- if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
-- printk(KERN_ERR "atmel_nand: can't get I/O resource "
-- "regs\nFalling back on software ECC\n");
-- nand_chip->ecc.mode = NAND_ECC_SOFT;
-- }
--
-- if (nand_chip->ecc.mode == NAND_ECC_HW) {
-- host->ecc = ioremap(regs->start, resource_size(regs));
-- if (host->ecc == NULL) {
-- printk(KERN_ERR "atmel_nand: ioremap failed\n");
-- res = -EIO;
-- goto err_ecc_ioremap;
-- }
-- nand_chip->ecc.calculate = atmel_nand_calculate;
-- nand_chip->ecc.correct = atmel_nand_correct;
-- nand_chip->ecc.hwctl = atmel_nand_hwctl;
-- nand_chip->ecc.read_page = atmel_nand_read_page;
-- nand_chip->ecc.bytes = 4;
-- nand_chip->ecc.strength = 1;
-- }
--
- nand_chip->chip_delay = 20; /* 20us command delay time */
-
- if (host->board.bus_width_16) /* 16-bit bus width */
-@@ -657,40 +693,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- }
-
- if (nand_chip->ecc.mode == NAND_ECC_HW) {
-- /* ECC is calculated for the whole page (1 step) */
-- nand_chip->ecc.size = mtd->writesize;
--
-- /* set ECC page size and oob layout */
-- switch (mtd->writesize) {
-- case 512:
-- nand_chip->ecc.layout = &atmel_oobinfo_small;
-- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
-- break;
-- case 1024:
-- nand_chip->ecc.layout = &atmel_oobinfo_large;
-- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
-- break;
-- case 2048:
-- nand_chip->ecc.layout = &atmel_oobinfo_large;
-- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
-- break;
-- case 4096:
-- nand_chip->ecc.layout = &atmel_oobinfo_large;
-- ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
-- break;
-- default:
-- /* page size not handled by HW ECC */
-- /* switching back to soft ECC */
-- nand_chip->ecc.mode = NAND_ECC_SOFT;
-- nand_chip->ecc.calculate = NULL;
-- nand_chip->ecc.correct = NULL;
-- nand_chip->ecc.hwctl = NULL;
-- nand_chip->ecc.read_page = NULL;
-- nand_chip->ecc.postpad = 0;
-- nand_chip->ecc.prepad = 0;
-- nand_chip->ecc.bytes = 0;
-- break;
-- }
-+ res = atmel_hw_nand_init_params(pdev, host);
-+ if (res != 0)
-+ goto err_hw_ecc;
- }
-
- /* second phase scan */
-@@ -707,15 +712,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- return res;
-
- err_scan_tail:
-+ if (host->ecc)
-+ iounmap(host->ecc);
-+err_hw_ecc:
- err_scan_ident:
- err_no_card:
- atmel_nand_disable(host);
- platform_set_drvdata(pdev, NULL);
- if (host->dma_chan)
- dma_release_channel(host->dma_chan);
-- if (host->ecc)
-- iounmap(host->ecc);
--err_ecc_ioremap:
- iounmap(host->io_base);
- err_nand_ioremap:
- kfree(host);
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 7f3d2c9c00b937d2932b337fe259dd4f56c048b7 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Tue, 26 Jun 2012 17:42:22 +0800
-Subject: MTD: at91: add dt parameters for Atmel PMECC
-
-Add DT support for PMECC parameters.
-
-Signed-off-by: Hong Xu <hong.xu@atmel.com>
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- .../devicetree/bindings/mtd/atmel-nand.txt | 40 ++++++++++++++++-
- drivers/mtd/nand/atmel_nand.c | 52 +++++++++++++++++++++-
- 2 files changed, 90 insertions(+), 2 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/mtd/atmel-nand.txt b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
-index a200695..d555421 100644
---- a/Documentation/devicetree/bindings/mtd/atmel-nand.txt
-+++ b/Documentation/devicetree/bindings/mtd/atmel-nand.txt
-@@ -3,7 +3,9 @@ Atmel NAND flash
- Required properties:
- - compatible : "atmel,at91rm9200-nand".
- - reg : should specify localbus address and size used for the chip,
-- and if availlable the ECC.
-+ and hardware ECC controller if available.
-+ If the hardware ECC is PMECC, it should contain address and size for
-+ PMECC, PMECC Error Location controller and ROM which has lookup tables.
- - atmel,nand-addr-offset : offset for the address latch.
- - atmel,nand-cmd-offset : offset for the command latch.
- - #address-cells, #size-cells : Must be present if the device has sub-nodes
-@@ -16,6 +18,15 @@ Optional properties:
- - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
- Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
- "soft_bch".
-+- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
-+ Only supported by at91sam9x5 or later sam9 product.
-+- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
-+ Controller. Supported values are: 2, 4, 8, 12, 24.
-+- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
-+ are: 512, 1024.
-+- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
-+ for different sector size. First one is for sector size 512, the next is for
-+ sector size 1024.
- - nand-bus-width : 8 or 16 bus width if not present 8
- - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
-
-@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
- ...
- };
- };
-+
-+/* for PMECC supported chips */
-+nand0: nand@40000000 {
-+ compatible = "atmel,at91rm9200-nand";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ reg = < 0x40000000 0x10000000 /* bus addr & size */
-+ 0xffffe000 0x00000600 /* PMECC addr & size */
-+ 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */
-+ 0x00100000 0x00100000 /* ROM addr & size */
-+ >;
-+ atmel,nand-addr-offset = <21>; /* ale */
-+ atmel,nand-cmd-offset = <22>; /* cle */
-+ nand-on-flash-bbt;
-+ nand-ecc-mode = "hw";
-+ atmel,has-pmecc; /* enable PMECC */
-+ atmel,pmecc-cap = <2>;
-+ atmel,pmecc-sector-size = <512>;
-+ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
-+ gpios = <&pioD 5 0 /* rdy */
-+ &pioD 4 0 /* nce */
-+ 0 /* cd */
-+ >;
-+ partition@0 {
-+ ...
-+ };
-+};
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 4ea0a04..712a705 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -93,6 +93,11 @@ struct atmel_nand_host {
-
- struct completion comp;
- struct dma_chan *dma_chan;
-+
-+ bool has_pmecc;
-+ u8 pmecc_corr_cap;
-+ u16 pmecc_sector_size;
-+ u32 pmecc_lookup_table_offset;
- };
-
- static int cpu_has_dma(void)
-@@ -477,7 +482,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
- static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
- struct device_node *np)
- {
-- u32 val;
-+ u32 val, table_offset;
-+ u32 offset[2];
- int ecc_mode;
- struct atmel_nand_data *board = &host->board;
- enum of_gpio_flags flags;
-@@ -513,6 +519,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
- board->enable_pin = of_get_gpio(np, 1);
- board->det_pin = of_get_gpio(np, 2);
-
-+ host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
-+
-+ if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
-+ return 0; /* Not using PMECC */
-+
-+ /* use PMECC, get correction capability, sector size and lookup
-+ * table offset.
-+ */
-+ if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
-+ dev_err(host->dev, "Cannot decide PMECC Capability\n");
-+ return -EINVAL;
-+ } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
-+ (val != 24)) {
-+ dev_err(host->dev,
-+ "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ host->pmecc_corr_cap = (u8)val;
-+
-+ if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
-+ dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
-+ return -EINVAL;
-+ } else if ((val != 512) && (val != 1024)) {
-+ dev_err(host->dev,
-+ "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ host->pmecc_sector_size = (u16)val;
-+
-+ if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
-+ offset, 2) != 0) {
-+ dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
-+ return -EINVAL;
-+ }
-+ table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
-+
-+ if (!table_offset) {
-+ dev_err(host->dev, "Invalid PMECC lookup table offset\n");
-+ return -EINVAL;
-+ }
-+ host->pmecc_lookup_table_offset = table_offset;
-+
- return 0;
- }
- #else
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 095fbbb23efb47cf006720652a877ffefe50c609 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Fri, 29 Jun 2012 15:29:21 +0800
+Subject: MTD: at91: atmel_nand: Update driver to support Programmable Multibit
+ ECC controller
+
+Is seen as commit 6dc4ff786c62fa34390607264d4d3ec54e22d5b7 upstream.
+
+The Programmable Multibit ECC (PMECC) controller is a programmable binary
+BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller
+can be used to support both SLC and MLC NAND Flash devices. It supports to
+generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data.
+
+To use PMECC in this driver, the user needs to set the address and size of
+PMECC, PMECC error location controllers and ROM. And also needs to pass the
+correction capability, the sector size and ROM lookup table offsets via dt.
+
+This driver has been tested on AT91SAM9X5-EK and AT91SAM9N12-EK with JFFS2,
+YAFFS2, UBIFS and mtd-utils.
+
+Signed-off-by: Hong Xu <hong.xu@atmel.com>
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Tested-by: Richard Genoud <richard.genoud@gmail.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 747 +++++++++++++++++++++++++++++++++++++-
+ drivers/mtd/nand/atmel_nand_ecc.h | 114 +++++-
+ 2 files changed, 859 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 712a705..42b64fb 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -15,6 +15,8 @@
+ * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
+ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
++ * Add Programmable Multibit ECC support for various AT91 SoC
++ * (C) Copyright 2012 ATMEL, Hong Xu
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+@@ -98,8 +100,31 @@ struct atmel_nand_host {
+ u8 pmecc_corr_cap;
+ u16 pmecc_sector_size;
+ u32 pmecc_lookup_table_offset;
++
++ int pmecc_bytes_per_sector;
++ int pmecc_sector_number;
++ int pmecc_degree; /* Degree of remainders */
++ int pmecc_cw_len; /* Length of codeword */
++
++ void __iomem *pmerrloc_base;
++ void __iomem *pmecc_rom_base;
++
++ /* lookup table for alpha_to and index_of */
++ void __iomem *pmecc_alpha_to;
++ void __iomem *pmecc_index_of;
++
++ /* data for pmecc computation */
++ int16_t *pmecc_partial_syn;
++ int16_t *pmecc_si;
++ int16_t *pmecc_smu; /* Sigma table */
++ int16_t *pmecc_lmu; /* polynomal order */
++ int *pmecc_mu;
++ int *pmecc_dmu;
++ int *pmecc_delta;
+ };
+
++static struct nand_ecclayout atmel_pmecc_oobinfo;
++
+ static int cpu_has_dma(void)
+ {
+ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
+@@ -293,6 +318,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
+ }
+
+ /*
++ * Return number of ecc bytes per sector according to sector size and
++ * correction capability
++ *
++ * Following table shows what at91 PMECC supported:
++ * Correction Capability Sector_512_bytes Sector_1024_bytes
++ * ===================== ================ =================
++ * 2-bits 4-bytes 4-bytes
++ * 4-bits 7-bytes 7-bytes
++ * 8-bits 13-bytes 14-bytes
++ * 12-bits 20-bytes 21-bytes
++ * 24-bits 39-bytes 42-bytes
++ */
++static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
++{
++ int m = 12 + sector_size / 512;
++ return (m * cap + 7) / 8;
++}
++
++static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
++ int oobsize, int ecc_len)
++{
++ int i;
++
++ layout->eccbytes = ecc_len;
++
++ /* ECC will occupy the last ecc_len bytes continuously */
++ for (i = 0; i < ecc_len; i++)
++ layout->eccpos[i] = oobsize - ecc_len + i;
++
++ layout->oobfree[0].offset = 2;
++ layout->oobfree[0].length =
++ oobsize - ecc_len - layout->oobfree[0].offset;
++}
++
++static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
++{
++ int table_size;
++
++ table_size = host->pmecc_sector_size == 512 ?
++ PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
++
++ return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
++ table_size * sizeof(int16_t);
++}
++
++static void pmecc_data_free(struct atmel_nand_host *host)
++{
++ kfree(host->pmecc_partial_syn);
++ kfree(host->pmecc_si);
++ kfree(host->pmecc_lmu);
++ kfree(host->pmecc_smu);
++ kfree(host->pmecc_mu);
++ kfree(host->pmecc_dmu);
++ kfree(host->pmecc_delta);
++}
++
++static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
++{
++ const int cap = host->pmecc_corr_cap;
++
++ host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
++ GFP_KERNEL);
++ host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
++ host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
++ host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
++ GFP_KERNEL);
++ host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++ host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++ host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
++
++ if (host->pmecc_partial_syn &&
++ host->pmecc_si &&
++ host->pmecc_lmu &&
++ host->pmecc_smu &&
++ host->pmecc_mu &&
++ host->pmecc_dmu &&
++ host->pmecc_delta)
++ return 0;
++
++ /* error happened */
++ pmecc_data_free(host);
++ return -ENOMEM;
++}
++
++static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i;
++ uint32_t value;
++
++ /* Fill odd syndromes */
++ for (i = 0; i < host->pmecc_corr_cap; i++) {
++ value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
++ if (i & 1)
++ value >>= 16;
++ value &= 0xffff;
++ host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
++ }
++}
++
++static void pmecc_substitute(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
++ int16_t __iomem *index_of = host->pmecc_index_of;
++ int16_t *partial_syn = host->pmecc_partial_syn;
++ const int cap = host->pmecc_corr_cap;
++ int16_t *si;
++ int i, j;
++
++ /* si[] is a table that holds the current syndrome value,
++ * an element of that table belongs to the field
++ */
++ si = host->pmecc_si;
++
++ memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
++
++ /* Computation 2t syndromes based on S(x) */
++ /* Odd syndromes */
++ for (i = 1; i < 2 * cap; i += 2) {
++ for (j = 0; j < host->pmecc_degree; j++) {
++ if (partial_syn[i] & ((unsigned short)0x1 << j))
++ si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
++ }
++ }
++ /* Even syndrome = (Odd syndrome) ** 2 */
++ for (i = 2, j = 1; j <= cap; i = ++j << 1) {
++ if (si[j] == 0) {
++ si[i] = 0;
++ } else {
++ int16_t tmp;
++
++ tmp = readw_relaxed(index_of + si[j]);
++ tmp = (tmp * 2) % host->pmecc_cw_len;
++ si[i] = readw_relaxed(alpha_to + tmp);
++ }
++ }
++
++ return;
++}
++
++static void pmecc_get_sigma(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++
++ int16_t *lmu = host->pmecc_lmu;
++ int16_t *si = host->pmecc_si;
++ int *mu = host->pmecc_mu;
++ int *dmu = host->pmecc_dmu; /* Discrepancy */
++ int *delta = host->pmecc_delta; /* Delta order */
++ int cw_len = host->pmecc_cw_len;
++ const int16_t cap = host->pmecc_corr_cap;
++ const int num = 2 * cap + 1;
++ int16_t __iomem *index_of = host->pmecc_index_of;
++ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
++ int i, j, k;
++ uint32_t dmu_0_count, tmp;
++ int16_t *smu = host->pmecc_smu;
++
++ /* index of largest delta */
++ int ro;
++ int largest;
++ int diff;
++
++ dmu_0_count = 0;
++
++ /* First Row */
++
++ /* Mu */
++ mu[0] = -1;
++
++ memset(smu, 0, sizeof(int16_t) * num);
++ smu[0] = 1;
++
++ /* discrepancy set to 1 */
++ dmu[0] = 1;
++ /* polynom order set to 0 */
++ lmu[0] = 0;
++ delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
++
++ /* Second Row */
++
++ /* Mu */
++ mu[1] = 0;
++ /* Sigma(x) set to 1 */
++ memset(&smu[num], 0, sizeof(int16_t) * num);
++ smu[num] = 1;
++
++ /* discrepancy set to S1 */
++ dmu[1] = si[1];
++
++ /* polynom order set to 0 */
++ lmu[1] = 0;
++
++ delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
++
++ /* Init the Sigma(x) last row */
++ memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
++
++ for (i = 1; i <= cap; i++) {
++ mu[i + 1] = i << 1;
++ /* Begin Computing Sigma (Mu+1) and L(mu) */
++ /* check if discrepancy is set to 0 */
++ if (dmu[i] == 0) {
++ dmu_0_count++;
++
++ tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
++ if ((cap - (lmu[i] >> 1) - 1) & 0x1)
++ tmp += 2;
++ else
++ tmp += 1;
++
++ if (dmu_0_count == tmp) {
++ for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
++ smu[(cap + 1) * num + j] =
++ smu[i * num + j];
++
++ lmu[cap + 1] = lmu[i];
++ return;
++ }
++
++ /* copy polynom */
++ for (j = 0; j <= lmu[i] >> 1; j++)
++ smu[(i + 1) * num + j] = smu[i * num + j];
++
++ /* copy previous polynom order to the next */
++ lmu[i + 1] = lmu[i];
++ } else {
++ ro = 0;
++ largest = -1;
++ /* find largest delta with dmu != 0 */
++ for (j = 0; j < i; j++) {
++ if ((dmu[j]) && (delta[j] > largest)) {
++ largest = delta[j];
++ ro = j;
++ }
++ }
++
++ /* compute difference */
++ diff = (mu[i] - mu[ro]);
++
++ /* Compute degree of the new smu polynomial */
++ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
++ lmu[i + 1] = lmu[i];
++ else
++ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
++
++ /* Init smu[i+1] with 0 */
++ for (k = 0; k < num; k++)
++ smu[(i + 1) * num + k] = 0;
++
++ /* Compute smu[i+1] */
++ for (k = 0; k <= lmu[ro] >> 1; k++) {
++ int16_t a, b, c;
++
++ if (!(smu[ro * num + k] && dmu[i]))
++ continue;
++ a = readw_relaxed(index_of + dmu[i]);
++ b = readw_relaxed(index_of + dmu[ro]);
++ c = readw_relaxed(index_of + smu[ro * num + k]);
++ tmp = a + (cw_len - b) + c;
++ a = readw_relaxed(alpha_to + tmp % cw_len);
++ smu[(i + 1) * num + (k + diff)] = a;
++ }
++
++ for (k = 0; k <= lmu[i] >> 1; k++)
++ smu[(i + 1) * num + k] ^= smu[i * num + k];
++ }
++
++ /* End Computing Sigma (Mu+1) and L(mu) */
++ /* In either case compute delta */
++ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
++
++ /* Do not compute discrepancy for the last iteration */
++ if (i >= cap)
++ continue;
++
++ for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
++ tmp = 2 * (i - 1);
++ if (k == 0) {
++ dmu[i + 1] = si[tmp + 3];
++ } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
++ int16_t a, b, c;
++ a = readw_relaxed(index_of +
++ smu[(i + 1) * num + k]);
++ b = si[2 * (i - 1) + 3 - k];
++ c = readw_relaxed(index_of + b);
++ tmp = a + c;
++ tmp %= cw_len;
++ dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
++ dmu[i + 1];
++ }
++ }
++ }
++
++ return;
++}
++
++static int pmecc_err_location(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ unsigned long end_time;
++ const int cap = host->pmecc_corr_cap;
++ const int num = 2 * cap + 1;
++ int sector_size = host->pmecc_sector_size;
++ int err_nbr = 0; /* number of error */
++ int roots_nbr; /* number of roots */
++ int i;
++ uint32_t val;
++ int16_t *smu = host->pmecc_smu;
++
++ pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
++
++ for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
++ pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
++ smu[(cap + 1) * num + i]);
++ err_nbr++;
++ }
++
++ val = (err_nbr - 1) << 16;
++ if (sector_size == 1024)
++ val |= 1;
++
++ pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
++ pmerrloc_writel(host->pmerrloc_base, ELEN,
++ sector_size * 8 + host->pmecc_degree * cap);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
++ & PMERRLOC_CALC_DONE)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
++ return -1;
++ }
++ cpu_relax();
++ }
++
++ roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
++ & PMERRLOC_ERR_NUM_MASK) >> 8;
++ /* Number of roots == degree of smu hence <= cap */
++ if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
++ return err_nbr - 1;
++
++ /* Number of roots does not match the degree of smu
++ * unable to correct error */
++ return -1;
++}
++
++static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
++ int sector_num, int extra_bytes, int err_nbr)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i = 0;
++ int byte_pos, bit_pos, sector_size, pos;
++ uint32_t tmp;
++ uint8_t err_byte;
++
++ sector_size = host->pmecc_sector_size;
++
++ while (err_nbr) {
++ tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
++ byte_pos = tmp / 8;
++ bit_pos = tmp % 8;
++
++ if (byte_pos >= (sector_size + extra_bytes))
++ BUG(); /* should never happen */
++
++ if (byte_pos < sector_size) {
++ err_byte = *(buf + byte_pos);
++ *(buf + byte_pos) ^= (1 << bit_pos);
++
++ pos = sector_num * host->pmecc_sector_size + byte_pos;
++ dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
++ pos, bit_pos, err_byte, *(buf + byte_pos));
++ } else {
++ /* Bit flip in OOB area */
++ tmp = sector_num * host->pmecc_bytes_per_sector
++ + (byte_pos - sector_size);
++ err_byte = ecc[tmp];
++ ecc[tmp] ^= (1 << bit_pos);
++
++ pos = tmp + nand_chip->ecc.layout->eccpos[0];
++ dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
++ pos, bit_pos, err_byte, ecc[tmp]);
++ }
++
++ i++;
++ err_nbr--;
++ }
++
++ return;
++}
++
++static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
++ u8 *ecc)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ int i, err_nbr, eccbytes;
++ uint8_t *buf_pos;
++
++ eccbytes = nand_chip->ecc.bytes;
++ for (i = 0; i < eccbytes; i++)
++ if (ecc[i] != 0xff)
++ goto normal_check;
++ /* Erased page, return OK */
++ return 0;
++
++normal_check:
++ for (i = 0; i < host->pmecc_sector_number; i++) {
++ err_nbr = 0;
++ if (pmecc_stat & 0x1) {
++ buf_pos = buf + i * host->pmecc_sector_size;
++
++ pmecc_gen_syndrome(mtd, i);
++ pmecc_substitute(mtd);
++ pmecc_get_sigma(mtd);
++
++ err_nbr = pmecc_err_location(mtd);
++ if (err_nbr == -1) {
++ dev_err(host->dev, "PMECC: Too many errors\n");
++ mtd->ecc_stats.failed++;
++ return -EIO;
++ } else {
++ pmecc_correct_data(mtd, buf_pos, ecc, i,
++ host->pmecc_bytes_per_sector, err_nbr);
++ mtd->ecc_stats.corrected += err_nbr;
++ }
++ }
++ pmecc_stat >>= 1;
++ }
++
++ return 0;
++}
++
++static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
++ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++{
++ struct atmel_nand_host *host = chip->priv;
++ int eccsize = chip->ecc.size;
++ uint8_t *oob = chip->oob_poi;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ uint32_t stat;
++ unsigned long end_time;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
++ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->read_buf(mtd, buf, eccsize);
++ chip->read_buf(mtd, oob, mtd->oobsize);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to get error status.\n");
++ return -EIO;
++ }
++ cpu_relax();
++ }
++
++ stat = pmecc_readl_relaxed(host->ecc, ISR);
++ if (stat != 0)
++ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
++ return -EIO;
++
++ return 0;
++}
++
++static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf, int oob_required)
++{
++ struct atmel_nand_host *host = chip->priv;
++ uint32_t *eccpos = chip->ecc.layout->eccpos;
++ int i, j;
++ unsigned long end_time;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
++ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
++
++ chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
++
++ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
++ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
++ if (unlikely(time_after(jiffies, end_time))) {
++ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
++ return -EIO;
++ }
++ cpu_relax();
++ }
++
++ for (i = 0; i < host->pmecc_sector_number; i++) {
++ for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
++ int pos;
++
++ pos = i * host->pmecc_bytes_per_sector + j;
++ chip->oob_poi[eccpos[pos]] =
++ pmecc_readb_ecc_relaxed(host->ecc, i, j);
++ }
++ }
++ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
++}
++
++static void atmel_pmecc_core_init(struct mtd_info *mtd)
++{
++ struct nand_chip *nand_chip = mtd->priv;
++ struct atmel_nand_host *host = nand_chip->priv;
++ uint32_t val = 0;
++ struct nand_ecclayout *ecc_layout;
++
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++
++ switch (host->pmecc_corr_cap) {
++ case 2:
++ val = PMECC_CFG_BCH_ERR2;
++ break;
++ case 4:
++ val = PMECC_CFG_BCH_ERR4;
++ break;
++ case 8:
++ val = PMECC_CFG_BCH_ERR8;
++ break;
++ case 12:
++ val = PMECC_CFG_BCH_ERR12;
++ break;
++ case 24:
++ val = PMECC_CFG_BCH_ERR24;
++ break;
++ }
++
++ if (host->pmecc_sector_size == 512)
++ val |= PMECC_CFG_SECTOR512;
++ else if (host->pmecc_sector_size == 1024)
++ val |= PMECC_CFG_SECTOR1024;
++
++ switch (host->pmecc_sector_number) {
++ case 1:
++ val |= PMECC_CFG_PAGE_1SECTOR;
++ break;
++ case 2:
++ val |= PMECC_CFG_PAGE_2SECTORS;
++ break;
++ case 4:
++ val |= PMECC_CFG_PAGE_4SECTORS;
++ break;
++ case 8:
++ val |= PMECC_CFG_PAGE_8SECTORS;
++ break;
++ }
++
++ val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
++ | PMECC_CFG_AUTO_DISABLE);
++ pmecc_writel(host->ecc, CFG, val);
++
++ ecc_layout = nand_chip->ecc.layout;
++ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
++ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
++ pmecc_writel(host->ecc, EADDR,
++ ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
++ /* See datasheet about PMECC Clock Control Register */
++ pmecc_writel(host->ecc, CLK, 2);
++ pmecc_writel(host->ecc, IDR, 0xff);
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
++}
++
++static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
++ struct atmel_nand_host *host)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *nand_chip = &host->nand_chip;
++ struct resource *regs, *regs_pmerr, *regs_rom;
++ int cap, sector_size, err_no;
++
++ cap = host->pmecc_corr_cap;
++ sector_size = host->pmecc_sector_size;
++ dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
++ cap, sector_size);
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!regs) {
++ dev_warn(host->dev,
++ "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ host->ecc = ioremap(regs->start, resource_size(regs));
++ if (host->ecc == NULL) {
++ dev_err(host->dev, "ioremap failed\n");
++ err_no = -EIO;
++ goto err_pmecc_ioremap;
++ }
++
++ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
++ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
++ if (regs_pmerr && regs_rom) {
++ host->pmerrloc_base = ioremap(regs_pmerr->start,
++ resource_size(regs_pmerr));
++ host->pmecc_rom_base = ioremap(regs_rom->start,
++ resource_size(regs_rom));
++ }
++
++ if (!host->pmerrloc_base || !host->pmecc_rom_base) {
++ dev_err(host->dev,
++ "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
++ err_no = -EIO;
++ goto err_pmloc_ioremap;
++ }
++
++ /* ECC is calculated for the whole page (1 step) */
++ nand_chip->ecc.size = mtd->writesize;
++
++ /* set ECC page size and oob layout */
++ switch (mtd->writesize) {
++ case 2048:
++ host->pmecc_degree = PMECC_GF_DIMENSION_13;
++ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
++ host->pmecc_sector_number = mtd->writesize / sector_size;
++ host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
++ cap, sector_size);
++ host->pmecc_alpha_to = pmecc_get_alpha_to(host);
++ host->pmecc_index_of = host->pmecc_rom_base +
++ host->pmecc_lookup_table_offset;
++
++ nand_chip->ecc.steps = 1;
++ nand_chip->ecc.strength = cap;
++ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
++ host->pmecc_sector_number;
++ if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
++ dev_err(host->dev, "No room for ECC bytes\n");
++ err_no = -EINVAL;
++ goto err_no_ecc_room;
++ }
++ pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
++ mtd->oobsize,
++ nand_chip->ecc.bytes);
++ nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
++ break;
++ case 512:
++ case 1024:
++ case 4096:
++ /* TODO */
++ dev_warn(host->dev,
++ "Unsupported page size for PMECC, use Software ECC\n");
++ default:
++ /* page size not handled by HW ECC */
++ /* switching back to soft ECC */
++ nand_chip->ecc.mode = NAND_ECC_SOFT;
++ return 0;
++ }
++
++ /* Allocate data for PMECC computation */
++ err_no = pmecc_data_alloc(host);
++ if (err_no) {
++ dev_err(host->dev,
++ "Cannot allocate memory for PMECC computation!\n");
++ goto err_pmecc_data_alloc;
++ }
++
++ nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
++ nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
++
++ atmel_pmecc_core_init(mtd);
++
++ return 0;
++
++err_pmecc_data_alloc:
++err_no_ecc_room:
++err_pmloc_ioremap:
++ iounmap(host->ecc);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
++err_pmecc_ioremap:
++ return err_no;
++}
++
++/*
+ * Calculate HW ECC
+ *
+ * function called after a write
+@@ -743,7 +1465,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ }
+
+ if (nand_chip->ecc.mode == NAND_ECC_HW) {
+- res = atmel_hw_nand_init_params(pdev, host);
++ if (host->has_pmecc)
++ res = atmel_pmecc_nand_init_params(pdev, host);
++ else
++ res = atmel_hw_nand_init_params(pdev, host);
++
+ if (res != 0)
+ goto err_hw_ecc;
+ }
+@@ -762,8 +1488,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ return res;
+
+ err_scan_tail:
++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmecc_data_free(host);
++ }
+ if (host->ecc)
+ iounmap(host->ecc);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
+ err_hw_ecc:
+ err_scan_ident:
+ err_no_card:
+@@ -789,8 +1523,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
+
+ atmel_nand_disable(host);
+
++ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
++ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
++ pmerrloc_writel(host->pmerrloc_base, ELDIS,
++ PMERRLOC_DISABLE);
++ pmecc_data_free(host);
++ }
++
+ if (host->ecc)
+ iounmap(host->ecc);
++ if (host->pmecc_rom_base)
++ iounmap(host->pmecc_rom_base);
++ if (host->pmerrloc_base)
++ iounmap(host->pmerrloc_base);
+
+ if (host->dma_chan)
+ dma_release_channel(host->dma_chan);
+diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
+index 578c776..8a1e9a6 100644
+--- a/drivers/mtd/nand/atmel_nand_ecc.h
++++ b/drivers/mtd/nand/atmel_nand_ecc.h
+@@ -3,7 +3,7 @@
+ * Based on AT91SAM9260 datasheet revision B.
+ *
+ * Copyright (C) 2007 Andrew Victor
+- * Copyright (C) 2007 Atmel Corporation.
++ * Copyright (C) 2007 - 2012 Atmel Corporation.
+ *
+ * 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
+@@ -36,4 +36,116 @@
+ #define ATMEL_ECC_NPR 0x10 /* NParity register */
+ #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
+
++/* PMECC Register Definitions */
++#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
++#define PMECC_CFG_BCH_ERR2 (0 << 0)
++#define PMECC_CFG_BCH_ERR4 (1 << 0)
++#define PMECC_CFG_BCH_ERR8 (2 << 0)
++#define PMECC_CFG_BCH_ERR12 (3 << 0)
++#define PMECC_CFG_BCH_ERR24 (4 << 0)
++
++#define PMECC_CFG_SECTOR512 (0 << 4)
++#define PMECC_CFG_SECTOR1024 (1 << 4)
++
++#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
++#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
++#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
++#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
++
++#define PMECC_CFG_READ_OP (0 << 12)
++#define PMECC_CFG_WRITE_OP (1 << 12)
++
++#define PMECC_CFG_SPARE_ENABLE (1 << 16)
++#define PMECC_CFG_SPARE_DISABLE (0 << 16)
++
++#define PMECC_CFG_AUTO_ENABLE (1 << 20)
++#define PMECC_CFG_AUTO_DISABLE (0 << 20)
++
++#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
++#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
++#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
++#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
++#define PMECC_CLK_133MHZ (2 << 0)
++
++#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
++#define PMECC_CTRL_RST (1 << 0)
++#define PMECC_CTRL_DATA (1 << 1)
++#define PMECC_CTRL_USER (1 << 2)
++#define PMECC_CTRL_ENABLE (1 << 4)
++#define PMECC_CTRL_DISABLE (1 << 5)
++
++#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
++#define PMECC_SR_BUSY (1 << 0)
++#define PMECC_SR_ENABLE (1 << 4)
++
++#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
++#define PMECC_IER_ENABLE (1 << 0)
++#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
++#define PMECC_IER_DISABLE (1 << 0)
++#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
++#define PMECC_IER_MASK (1 << 0)
++#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
++#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
++#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
++
++/* PMERRLOC Register Definitions */
++#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
++#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
++#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
++#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
++
++#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
++#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
++#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
++#define PMERRLOC_DISABLE (1 << 0)
++
++#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
++#define PMERRLOC_ELSR_BUSY (1 << 0)
++#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
++#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
++#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
++#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
++#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
++#define PMERRLOC_CALC_DONE (1 << 0)
++#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
++#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
++
++/* Register access macros for PMECC */
++#define pmecc_readl_relaxed(addr, reg) \
++ readl_relaxed((addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_writel(addr, reg, value) \
++ writel((value), (addr) + ATMEL_PMECC_##reg)
++
++#define pmecc_readb_ecc_relaxed(addr, sector, n) \
++ readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
++
++#define pmecc_readl_rem_relaxed(addr, sector, n) \
++ readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
++
++#define pmerrloc_readl_relaxed(addr, reg) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel(addr, reg, value) \
++ writel((value), (addr) + ATMEL_PMERRLOC_##reg)
++
++#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
++ writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_sigma_relaxed(addr, n) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
++
++#define pmerrloc_readl_el_relaxed(addr, n) \
++ readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
++
++/* Galois field dimension */
++#define PMECC_GF_DIMENSION_13 13
++#define PMECC_GF_DIMENSION_14 14
++
++#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
++#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
++
++/* Time out value for reading PMECC status register */
++#define PMECC_MAX_TIMEOUT_MS 100
++
+ #endif
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 6dc4ff786c62fa34390607264d4d3ec54e22d5b7 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Fri, 29 Jun 2012 15:29:21 +0800
-Subject: MTD: at91: atmel_nand: Update driver to support Programmable Multibit
- ECC controller
-
-The Programmable Multibit ECC (PMECC) controller is a programmable binary
-BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller
-can be used to support both SLC and MLC NAND Flash devices. It supports to
-generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data.
-
-To use PMECC in this driver, the user needs to set the address and size of
-PMECC, PMECC error location controllers and ROM. And also needs to pass the
-correction capability, the sector size and ROM lookup table offsets via dt.
-
-This driver has been tested on AT91SAM9X5-EK and AT91SAM9N12-EK with JFFS2,
-YAFFS2, UBIFS and mtd-utils.
-
-Signed-off-by: Hong Xu <hong.xu@atmel.com>
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
-Tested-by: Richard Genoud <richard.genoud@gmail.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 747 +++++++++++++++++++++++++++++++++++++-
- drivers/mtd/nand/atmel_nand_ecc.h | 114 +++++-
- 2 files changed, 859 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 712a705..42b64fb 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -15,6 +15,8 @@
- * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
- *
-+ * Add Programmable Multibit ECC support for various AT91 SoC
-+ * (C) Copyright 2012 ATMEL, Hong Xu
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
-@@ -98,8 +100,31 @@ struct atmel_nand_host {
- u8 pmecc_corr_cap;
- u16 pmecc_sector_size;
- u32 pmecc_lookup_table_offset;
-+
-+ int pmecc_bytes_per_sector;
-+ int pmecc_sector_number;
-+ int pmecc_degree; /* Degree of remainders */
-+ int pmecc_cw_len; /* Length of codeword */
-+
-+ void __iomem *pmerrloc_base;
-+ void __iomem *pmecc_rom_base;
-+
-+ /* lookup table for alpha_to and index_of */
-+ void __iomem *pmecc_alpha_to;
-+ void __iomem *pmecc_index_of;
-+
-+ /* data for pmecc computation */
-+ int16_t *pmecc_partial_syn;
-+ int16_t *pmecc_si;
-+ int16_t *pmecc_smu; /* Sigma table */
-+ int16_t *pmecc_lmu; /* polynomal order */
-+ int *pmecc_mu;
-+ int *pmecc_dmu;
-+ int *pmecc_delta;
- };
-
-+static struct nand_ecclayout atmel_pmecc_oobinfo;
-+
- static int cpu_has_dma(void)
- {
- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
-@@ -293,6 +318,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
- }
-
- /*
-+ * Return number of ecc bytes per sector according to sector size and
-+ * correction capability
-+ *
-+ * Following table shows what at91 PMECC supported:
-+ * Correction Capability Sector_512_bytes Sector_1024_bytes
-+ * ===================== ================ =================
-+ * 2-bits 4-bytes 4-bytes
-+ * 4-bits 7-bytes 7-bytes
-+ * 8-bits 13-bytes 14-bytes
-+ * 12-bits 20-bytes 21-bytes
-+ * 24-bits 39-bytes 42-bytes
-+ */
-+static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
-+{
-+ int m = 12 + sector_size / 512;
-+ return (m * cap + 7) / 8;
-+}
-+
-+static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
-+ int oobsize, int ecc_len)
-+{
-+ int i;
-+
-+ layout->eccbytes = ecc_len;
-+
-+ /* ECC will occupy the last ecc_len bytes continuously */
-+ for (i = 0; i < ecc_len; i++)
-+ layout->eccpos[i] = oobsize - ecc_len + i;
-+
-+ layout->oobfree[0].offset = 2;
-+ layout->oobfree[0].length =
-+ oobsize - ecc_len - layout->oobfree[0].offset;
-+}
-+
-+static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
-+{
-+ int table_size;
-+
-+ table_size = host->pmecc_sector_size == 512 ?
-+ PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
-+
-+ return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
-+ table_size * sizeof(int16_t);
-+}
-+
-+static void pmecc_data_free(struct atmel_nand_host *host)
-+{
-+ kfree(host->pmecc_partial_syn);
-+ kfree(host->pmecc_si);
-+ kfree(host->pmecc_lmu);
-+ kfree(host->pmecc_smu);
-+ kfree(host->pmecc_mu);
-+ kfree(host->pmecc_dmu);
-+ kfree(host->pmecc_delta);
-+}
-+
-+static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
-+{
-+ const int cap = host->pmecc_corr_cap;
-+
-+ host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
-+ GFP_KERNEL);
-+ host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
-+ host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
-+ host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
-+ GFP_KERNEL);
-+ host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-+ host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-+ host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-+
-+ if (host->pmecc_partial_syn &&
-+ host->pmecc_si &&
-+ host->pmecc_lmu &&
-+ host->pmecc_smu &&
-+ host->pmecc_mu &&
-+ host->pmecc_dmu &&
-+ host->pmecc_delta)
-+ return 0;
-+
-+ /* error happened */
-+ pmecc_data_free(host);
-+ return -ENOMEM;
-+}
-+
-+static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ int i;
-+ uint32_t value;
-+
-+ /* Fill odd syndromes */
-+ for (i = 0; i < host->pmecc_corr_cap; i++) {
-+ value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
-+ if (i & 1)
-+ value >>= 16;
-+ value &= 0xffff;
-+ host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
-+ }
-+}
-+
-+static void pmecc_substitute(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
-+ int16_t __iomem *index_of = host->pmecc_index_of;
-+ int16_t *partial_syn = host->pmecc_partial_syn;
-+ const int cap = host->pmecc_corr_cap;
-+ int16_t *si;
-+ int i, j;
-+
-+ /* si[] is a table that holds the current syndrome value,
-+ * an element of that table belongs to the field
-+ */
-+ si = host->pmecc_si;
-+
-+ memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
-+
-+ /* Computation 2t syndromes based on S(x) */
-+ /* Odd syndromes */
-+ for (i = 1; i < 2 * cap; i += 2) {
-+ for (j = 0; j < host->pmecc_degree; j++) {
-+ if (partial_syn[i] & ((unsigned short)0x1 << j))
-+ si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
-+ }
-+ }
-+ /* Even syndrome = (Odd syndrome) ** 2 */
-+ for (i = 2, j = 1; j <= cap; i = ++j << 1) {
-+ if (si[j] == 0) {
-+ si[i] = 0;
-+ } else {
-+ int16_t tmp;
-+
-+ tmp = readw_relaxed(index_of + si[j]);
-+ tmp = (tmp * 2) % host->pmecc_cw_len;
-+ si[i] = readw_relaxed(alpha_to + tmp);
-+ }
-+ }
-+
-+ return;
-+}
-+
-+static void pmecc_get_sigma(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+
-+ int16_t *lmu = host->pmecc_lmu;
-+ int16_t *si = host->pmecc_si;
-+ int *mu = host->pmecc_mu;
-+ int *dmu = host->pmecc_dmu; /* Discrepancy */
-+ int *delta = host->pmecc_delta; /* Delta order */
-+ int cw_len = host->pmecc_cw_len;
-+ const int16_t cap = host->pmecc_corr_cap;
-+ const int num = 2 * cap + 1;
-+ int16_t __iomem *index_of = host->pmecc_index_of;
-+ int16_t __iomem *alpha_to = host->pmecc_alpha_to;
-+ int i, j, k;
-+ uint32_t dmu_0_count, tmp;
-+ int16_t *smu = host->pmecc_smu;
-+
-+ /* index of largest delta */
-+ int ro;
-+ int largest;
-+ int diff;
-+
-+ dmu_0_count = 0;
-+
-+ /* First Row */
-+
-+ /* Mu */
-+ mu[0] = -1;
-+
-+ memset(smu, 0, sizeof(int16_t) * num);
-+ smu[0] = 1;
-+
-+ /* discrepancy set to 1 */
-+ dmu[0] = 1;
-+ /* polynom order set to 0 */
-+ lmu[0] = 0;
-+ delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
-+
-+ /* Second Row */
-+
-+ /* Mu */
-+ mu[1] = 0;
-+ /* Sigma(x) set to 1 */
-+ memset(&smu[num], 0, sizeof(int16_t) * num);
-+ smu[num] = 1;
-+
-+ /* discrepancy set to S1 */
-+ dmu[1] = si[1];
-+
-+ /* polynom order set to 0 */
-+ lmu[1] = 0;
-+
-+ delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
-+
-+ /* Init the Sigma(x) last row */
-+ memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
-+
-+ for (i = 1; i <= cap; i++) {
-+ mu[i + 1] = i << 1;
-+ /* Begin Computing Sigma (Mu+1) and L(mu) */
-+ /* check if discrepancy is set to 0 */
-+ if (dmu[i] == 0) {
-+ dmu_0_count++;
-+
-+ tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
-+ if ((cap - (lmu[i] >> 1) - 1) & 0x1)
-+ tmp += 2;
-+ else
-+ tmp += 1;
-+
-+ if (dmu_0_count == tmp) {
-+ for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
-+ smu[(cap + 1) * num + j] =
-+ smu[i * num + j];
-+
-+ lmu[cap + 1] = lmu[i];
-+ return;
-+ }
-+
-+ /* copy polynom */
-+ for (j = 0; j <= lmu[i] >> 1; j++)
-+ smu[(i + 1) * num + j] = smu[i * num + j];
-+
-+ /* copy previous polynom order to the next */
-+ lmu[i + 1] = lmu[i];
-+ } else {
-+ ro = 0;
-+ largest = -1;
-+ /* find largest delta with dmu != 0 */
-+ for (j = 0; j < i; j++) {
-+ if ((dmu[j]) && (delta[j] > largest)) {
-+ largest = delta[j];
-+ ro = j;
-+ }
-+ }
-+
-+ /* compute difference */
-+ diff = (mu[i] - mu[ro]);
-+
-+ /* Compute degree of the new smu polynomial */
-+ if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
-+ lmu[i + 1] = lmu[i];
-+ else
-+ lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
-+
-+ /* Init smu[i+1] with 0 */
-+ for (k = 0; k < num; k++)
-+ smu[(i + 1) * num + k] = 0;
-+
-+ /* Compute smu[i+1] */
-+ for (k = 0; k <= lmu[ro] >> 1; k++) {
-+ int16_t a, b, c;
-+
-+ if (!(smu[ro * num + k] && dmu[i]))
-+ continue;
-+ a = readw_relaxed(index_of + dmu[i]);
-+ b = readw_relaxed(index_of + dmu[ro]);
-+ c = readw_relaxed(index_of + smu[ro * num + k]);
-+ tmp = a + (cw_len - b) + c;
-+ a = readw_relaxed(alpha_to + tmp % cw_len);
-+ smu[(i + 1) * num + (k + diff)] = a;
-+ }
-+
-+ for (k = 0; k <= lmu[i] >> 1; k++)
-+ smu[(i + 1) * num + k] ^= smu[i * num + k];
-+ }
-+
-+ /* End Computing Sigma (Mu+1) and L(mu) */
-+ /* In either case compute delta */
-+ delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
-+
-+ /* Do not compute discrepancy for the last iteration */
-+ if (i >= cap)
-+ continue;
-+
-+ for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
-+ tmp = 2 * (i - 1);
-+ if (k == 0) {
-+ dmu[i + 1] = si[tmp + 3];
-+ } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
-+ int16_t a, b, c;
-+ a = readw_relaxed(index_of +
-+ smu[(i + 1) * num + k]);
-+ b = si[2 * (i - 1) + 3 - k];
-+ c = readw_relaxed(index_of + b);
-+ tmp = a + c;
-+ tmp %= cw_len;
-+ dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
-+ dmu[i + 1];
-+ }
-+ }
-+ }
-+
-+ return;
-+}
-+
-+static int pmecc_err_location(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ unsigned long end_time;
-+ const int cap = host->pmecc_corr_cap;
-+ const int num = 2 * cap + 1;
-+ int sector_size = host->pmecc_sector_size;
-+ int err_nbr = 0; /* number of error */
-+ int roots_nbr; /* number of roots */
-+ int i;
-+ uint32_t val;
-+ int16_t *smu = host->pmecc_smu;
-+
-+ pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
-+
-+ for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
-+ pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
-+ smu[(cap + 1) * num + i]);
-+ err_nbr++;
-+ }
-+
-+ val = (err_nbr - 1) << 16;
-+ if (sector_size == 1024)
-+ val |= 1;
-+
-+ pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
-+ pmerrloc_writel(host->pmerrloc_base, ELEN,
-+ sector_size * 8 + host->pmecc_degree * cap);
-+
-+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
-+ while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
-+ & PMERRLOC_CALC_DONE)) {
-+ if (unlikely(time_after(jiffies, end_time))) {
-+ dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
-+ return -1;
-+ }
-+ cpu_relax();
-+ }
-+
-+ roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
-+ & PMERRLOC_ERR_NUM_MASK) >> 8;
-+ /* Number of roots == degree of smu hence <= cap */
-+ if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
-+ return err_nbr - 1;
-+
-+ /* Number of roots does not match the degree of smu
-+ * unable to correct error */
-+ return -1;
-+}
-+
-+static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
-+ int sector_num, int extra_bytes, int err_nbr)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ int i = 0;
-+ int byte_pos, bit_pos, sector_size, pos;
-+ uint32_t tmp;
-+ uint8_t err_byte;
-+
-+ sector_size = host->pmecc_sector_size;
-+
-+ while (err_nbr) {
-+ tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
-+ byte_pos = tmp / 8;
-+ bit_pos = tmp % 8;
-+
-+ if (byte_pos >= (sector_size + extra_bytes))
-+ BUG(); /* should never happen */
-+
-+ if (byte_pos < sector_size) {
-+ err_byte = *(buf + byte_pos);
-+ *(buf + byte_pos) ^= (1 << bit_pos);
-+
-+ pos = sector_num * host->pmecc_sector_size + byte_pos;
-+ dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
-+ pos, bit_pos, err_byte, *(buf + byte_pos));
-+ } else {
-+ /* Bit flip in OOB area */
-+ tmp = sector_num * host->pmecc_bytes_per_sector
-+ + (byte_pos - sector_size);
-+ err_byte = ecc[tmp];
-+ ecc[tmp] ^= (1 << bit_pos);
-+
-+ pos = tmp + nand_chip->ecc.layout->eccpos[0];
-+ dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
-+ pos, bit_pos, err_byte, ecc[tmp]);
-+ }
-+
-+ i++;
-+ err_nbr--;
-+ }
-+
-+ return;
-+}
-+
-+static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
-+ u8 *ecc)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ int i, err_nbr, eccbytes;
-+ uint8_t *buf_pos;
-+
-+ eccbytes = nand_chip->ecc.bytes;
-+ for (i = 0; i < eccbytes; i++)
-+ if (ecc[i] != 0xff)
-+ goto normal_check;
-+ /* Erased page, return OK */
-+ return 0;
-+
-+normal_check:
-+ for (i = 0; i < host->pmecc_sector_number; i++) {
-+ err_nbr = 0;
-+ if (pmecc_stat & 0x1) {
-+ buf_pos = buf + i * host->pmecc_sector_size;
-+
-+ pmecc_gen_syndrome(mtd, i);
-+ pmecc_substitute(mtd);
-+ pmecc_get_sigma(mtd);
-+
-+ err_nbr = pmecc_err_location(mtd);
-+ if (err_nbr == -1) {
-+ dev_err(host->dev, "PMECC: Too many errors\n");
-+ mtd->ecc_stats.failed++;
-+ return -EIO;
-+ } else {
-+ pmecc_correct_data(mtd, buf_pos, ecc, i,
-+ host->pmecc_bytes_per_sector, err_nbr);
-+ mtd->ecc_stats.corrected += err_nbr;
-+ }
-+ }
-+ pmecc_stat >>= 1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
-+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
-+{
-+ struct atmel_nand_host *host = chip->priv;
-+ int eccsize = chip->ecc.size;
-+ uint8_t *oob = chip->oob_poi;
-+ uint32_t *eccpos = chip->ecc.layout->eccpos;
-+ uint32_t stat;
-+ unsigned long end_time;
-+
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-+ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
-+ & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
-+
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
-+
-+ chip->read_buf(mtd, buf, eccsize);
-+ chip->read_buf(mtd, oob, mtd->oobsize);
-+
-+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
-+ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
-+ if (unlikely(time_after(jiffies, end_time))) {
-+ dev_err(host->dev, "PMECC: Timeout to get error status.\n");
-+ return -EIO;
-+ }
-+ cpu_relax();
-+ }
-+
-+ stat = pmecc_readl_relaxed(host->ecc, ISR);
-+ if (stat != 0)
-+ if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
-+ return -EIO;
-+
-+ return 0;
-+}
-+
-+static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
-+{
-+ struct atmel_nand_host *host = chip->priv;
-+ uint32_t *eccpos = chip->ecc.layout->eccpos;
-+ int i, j;
-+ unsigned long end_time;
-+
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-+
-+ pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
-+ PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
-+
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
-+
-+ chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
-+
-+ end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
-+ while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
-+ if (unlikely(time_after(jiffies, end_time))) {
-+ dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
-+ return -EIO;
-+ }
-+ cpu_relax();
-+ }
-+
-+ for (i = 0; i < host->pmecc_sector_number; i++) {
-+ for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
-+ int pos;
-+
-+ pos = i * host->pmecc_bytes_per_sector + j;
-+ chip->oob_poi[eccpos[pos]] =
-+ pmecc_readb_ecc_relaxed(host->ecc, i, j);
-+ }
-+ }
-+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+
-+ return 0;
-+}
-+
-+static void atmel_pmecc_core_init(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct atmel_nand_host *host = nand_chip->priv;
-+ uint32_t val = 0;
-+ struct nand_ecclayout *ecc_layout;
-+
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-+
-+ switch (host->pmecc_corr_cap) {
-+ case 2:
-+ val = PMECC_CFG_BCH_ERR2;
-+ break;
-+ case 4:
-+ val = PMECC_CFG_BCH_ERR4;
-+ break;
-+ case 8:
-+ val = PMECC_CFG_BCH_ERR8;
-+ break;
-+ case 12:
-+ val = PMECC_CFG_BCH_ERR12;
-+ break;
-+ case 24:
-+ val = PMECC_CFG_BCH_ERR24;
-+ break;
-+ }
-+
-+ if (host->pmecc_sector_size == 512)
-+ val |= PMECC_CFG_SECTOR512;
-+ else if (host->pmecc_sector_size == 1024)
-+ val |= PMECC_CFG_SECTOR1024;
-+
-+ switch (host->pmecc_sector_number) {
-+ case 1:
-+ val |= PMECC_CFG_PAGE_1SECTOR;
-+ break;
-+ case 2:
-+ val |= PMECC_CFG_PAGE_2SECTORS;
-+ break;
-+ case 4:
-+ val |= PMECC_CFG_PAGE_4SECTORS;
-+ break;
-+ case 8:
-+ val |= PMECC_CFG_PAGE_8SECTORS;
-+ break;
-+ }
-+
-+ val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
-+ | PMECC_CFG_AUTO_DISABLE);
-+ pmecc_writel(host->ecc, CFG, val);
-+
-+ ecc_layout = nand_chip->ecc.layout;
-+ pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
-+ pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
-+ pmecc_writel(host->ecc, EADDR,
-+ ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
-+ /* See datasheet about PMECC Clock Control Register */
-+ pmecc_writel(host->ecc, CLK, 2);
-+ pmecc_writel(host->ecc, IDR, 0xff);
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-+}
-+
-+static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
-+ struct atmel_nand_host *host)
-+{
-+ struct mtd_info *mtd = &host->mtd;
-+ struct nand_chip *nand_chip = &host->nand_chip;
-+ struct resource *regs, *regs_pmerr, *regs_rom;
-+ int cap, sector_size, err_no;
-+
-+ cap = host->pmecc_corr_cap;
-+ sector_size = host->pmecc_sector_size;
-+ dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
-+ cap, sector_size);
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (!regs) {
-+ dev_warn(host->dev,
-+ "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
-+ nand_chip->ecc.mode = NAND_ECC_SOFT;
-+ return 0;
-+ }
-+
-+ host->ecc = ioremap(regs->start, resource_size(regs));
-+ if (host->ecc == NULL) {
-+ dev_err(host->dev, "ioremap failed\n");
-+ err_no = -EIO;
-+ goto err_pmecc_ioremap;
-+ }
-+
-+ regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-+ regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-+ if (regs_pmerr && regs_rom) {
-+ host->pmerrloc_base = ioremap(regs_pmerr->start,
-+ resource_size(regs_pmerr));
-+ host->pmecc_rom_base = ioremap(regs_rom->start,
-+ resource_size(regs_rom));
-+ }
-+
-+ if (!host->pmerrloc_base || !host->pmecc_rom_base) {
-+ dev_err(host->dev,
-+ "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
-+ err_no = -EIO;
-+ goto err_pmloc_ioremap;
-+ }
-+
-+ /* ECC is calculated for the whole page (1 step) */
-+ nand_chip->ecc.size = mtd->writesize;
-+
-+ /* set ECC page size and oob layout */
-+ switch (mtd->writesize) {
-+ case 2048:
-+ host->pmecc_degree = PMECC_GF_DIMENSION_13;
-+ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
-+ host->pmecc_sector_number = mtd->writesize / sector_size;
-+ host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
-+ cap, sector_size);
-+ host->pmecc_alpha_to = pmecc_get_alpha_to(host);
-+ host->pmecc_index_of = host->pmecc_rom_base +
-+ host->pmecc_lookup_table_offset;
-+
-+ nand_chip->ecc.steps = 1;
-+ nand_chip->ecc.strength = cap;
-+ nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
-+ host->pmecc_sector_number;
-+ if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
-+ dev_err(host->dev, "No room for ECC bytes\n");
-+ err_no = -EINVAL;
-+ goto err_no_ecc_room;
-+ }
-+ pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
-+ mtd->oobsize,
-+ nand_chip->ecc.bytes);
-+ nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
-+ break;
-+ case 512:
-+ case 1024:
-+ case 4096:
-+ /* TODO */
-+ dev_warn(host->dev,
-+ "Unsupported page size for PMECC, use Software ECC\n");
-+ default:
-+ /* page size not handled by HW ECC */
-+ /* switching back to soft ECC */
-+ nand_chip->ecc.mode = NAND_ECC_SOFT;
-+ return 0;
-+ }
-+
-+ /* Allocate data for PMECC computation */
-+ err_no = pmecc_data_alloc(host);
-+ if (err_no) {
-+ dev_err(host->dev,
-+ "Cannot allocate memory for PMECC computation!\n");
-+ goto err_pmecc_data_alloc;
-+ }
-+
-+ nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
-+ nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
-+
-+ atmel_pmecc_core_init(mtd);
-+
-+ return 0;
-+
-+err_pmecc_data_alloc:
-+err_no_ecc_room:
-+err_pmloc_ioremap:
-+ iounmap(host->ecc);
-+ if (host->pmerrloc_base)
-+ iounmap(host->pmerrloc_base);
-+ if (host->pmecc_rom_base)
-+ iounmap(host->pmecc_rom_base);
-+err_pmecc_ioremap:
-+ return err_no;
-+}
-+
-+/*
- * Calculate HW ECC
- *
- * function called after a write
-@@ -743,7 +1465,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- }
-
- if (nand_chip->ecc.mode == NAND_ECC_HW) {
-- res = atmel_hw_nand_init_params(pdev, host);
-+ if (host->has_pmecc)
-+ res = atmel_pmecc_nand_init_params(pdev, host);
-+ else
-+ res = atmel_hw_nand_init_params(pdev, host);
-+
- if (res != 0)
- goto err_hw_ecc;
- }
-@@ -762,8 +1488,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- return res;
-
- err_scan_tail:
-+ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-+ pmecc_data_free(host);
-+ }
- if (host->ecc)
- iounmap(host->ecc);
-+ if (host->pmerrloc_base)
-+ iounmap(host->pmerrloc_base);
-+ if (host->pmecc_rom_base)
-+ iounmap(host->pmecc_rom_base);
- err_hw_ecc:
- err_scan_ident:
- err_no_card:
-@@ -789,8 +1523,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
-
- atmel_nand_disable(host);
-
-+ if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
-+ pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-+ pmerrloc_writel(host->pmerrloc_base, ELDIS,
-+ PMERRLOC_DISABLE);
-+ pmecc_data_free(host);
-+ }
-+
- if (host->ecc)
- iounmap(host->ecc);
-+ if (host->pmecc_rom_base)
-+ iounmap(host->pmecc_rom_base);
-+ if (host->pmerrloc_base)
-+ iounmap(host->pmerrloc_base);
-
- if (host->dma_chan)
- dma_release_channel(host->dma_chan);
-diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h
-index 578c776..8a1e9a6 100644
---- a/drivers/mtd/nand/atmel_nand_ecc.h
-+++ b/drivers/mtd/nand/atmel_nand_ecc.h
-@@ -3,7 +3,7 @@
- * Based on AT91SAM9260 datasheet revision B.
- *
- * Copyright (C) 2007 Andrew Victor
-- * Copyright (C) 2007 Atmel Corporation.
-+ * Copyright (C) 2007 - 2012 Atmel Corporation.
- *
- * 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
-@@ -36,4 +36,116 @@
- #define ATMEL_ECC_NPR 0x10 /* NParity register */
- #define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */
-
-+/* PMECC Register Definitions */
-+#define ATMEL_PMECC_CFG 0x000 /* Configuration Register */
-+#define PMECC_CFG_BCH_ERR2 (0 << 0)
-+#define PMECC_CFG_BCH_ERR4 (1 << 0)
-+#define PMECC_CFG_BCH_ERR8 (2 << 0)
-+#define PMECC_CFG_BCH_ERR12 (3 << 0)
-+#define PMECC_CFG_BCH_ERR24 (4 << 0)
-+
-+#define PMECC_CFG_SECTOR512 (0 << 4)
-+#define PMECC_CFG_SECTOR1024 (1 << 4)
-+
-+#define PMECC_CFG_PAGE_1SECTOR (0 << 8)
-+#define PMECC_CFG_PAGE_2SECTORS (1 << 8)
-+#define PMECC_CFG_PAGE_4SECTORS (2 << 8)
-+#define PMECC_CFG_PAGE_8SECTORS (3 << 8)
-+
-+#define PMECC_CFG_READ_OP (0 << 12)
-+#define PMECC_CFG_WRITE_OP (1 << 12)
-+
-+#define PMECC_CFG_SPARE_ENABLE (1 << 16)
-+#define PMECC_CFG_SPARE_DISABLE (0 << 16)
-+
-+#define PMECC_CFG_AUTO_ENABLE (1 << 20)
-+#define PMECC_CFG_AUTO_DISABLE (0 << 20)
-+
-+#define ATMEL_PMECC_SAREA 0x004 /* Spare area size */
-+#define ATMEL_PMECC_SADDR 0x008 /* PMECC starting address */
-+#define ATMEL_PMECC_EADDR 0x00c /* PMECC ending address */
-+#define ATMEL_PMECC_CLK 0x010 /* PMECC clock control */
-+#define PMECC_CLK_133MHZ (2 << 0)
-+
-+#define ATMEL_PMECC_CTRL 0x014 /* PMECC control register */
-+#define PMECC_CTRL_RST (1 << 0)
-+#define PMECC_CTRL_DATA (1 << 1)
-+#define PMECC_CTRL_USER (1 << 2)
-+#define PMECC_CTRL_ENABLE (1 << 4)
-+#define PMECC_CTRL_DISABLE (1 << 5)
-+
-+#define ATMEL_PMECC_SR 0x018 /* PMECC status register */
-+#define PMECC_SR_BUSY (1 << 0)
-+#define PMECC_SR_ENABLE (1 << 4)
-+
-+#define ATMEL_PMECC_IER 0x01c /* PMECC interrupt enable */
-+#define PMECC_IER_ENABLE (1 << 0)
-+#define ATMEL_PMECC_IDR 0x020 /* PMECC interrupt disable */
-+#define PMECC_IER_DISABLE (1 << 0)
-+#define ATMEL_PMECC_IMR 0x024 /* PMECC interrupt mask */
-+#define PMECC_IER_MASK (1 << 0)
-+#define ATMEL_PMECC_ISR 0x028 /* PMECC interrupt status */
-+#define ATMEL_PMECC_ECCx 0x040 /* PMECC ECC x */
-+#define ATMEL_PMECC_REMx 0x240 /* PMECC REM x */
-+
-+/* PMERRLOC Register Definitions */
-+#define ATMEL_PMERRLOC_ELCFG 0x000 /* Error location config */
-+#define PMERRLOC_ELCFG_SECTOR_512 (0 << 0)
-+#define PMERRLOC_ELCFG_SECTOR_1024 (1 << 0)
-+#define PMERRLOC_ELCFG_NUM_ERRORS(n) ((n) << 16)
-+
-+#define ATMEL_PMERRLOC_ELPRIM 0x004 /* Error location primitive */
-+#define ATMEL_PMERRLOC_ELEN 0x008 /* Error location enable */
-+#define ATMEL_PMERRLOC_ELDIS 0x00c /* Error location disable */
-+#define PMERRLOC_DISABLE (1 << 0)
-+
-+#define ATMEL_PMERRLOC_ELSR 0x010 /* Error location status */
-+#define PMERRLOC_ELSR_BUSY (1 << 0)
-+#define ATMEL_PMERRLOC_ELIER 0x014 /* Error location int enable */
-+#define ATMEL_PMERRLOC_ELIDR 0x018 /* Error location int disable */
-+#define ATMEL_PMERRLOC_ELIMR 0x01c /* Error location int mask */
-+#define ATMEL_PMERRLOC_ELISR 0x020 /* Error location int status */
-+#define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
-+#define PMERRLOC_CALC_DONE (1 << 0)
-+#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
-+#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
-+
-+/* Register access macros for PMECC */
-+#define pmecc_readl_relaxed(addr, reg) \
-+ readl_relaxed((addr) + ATMEL_PMECC_##reg)
-+
-+#define pmecc_writel(addr, reg, value) \
-+ writel((value), (addr) + ATMEL_PMECC_##reg)
-+
-+#define pmecc_readb_ecc_relaxed(addr, sector, n) \
-+ readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
-+
-+#define pmecc_readl_rem_relaxed(addr, sector, n) \
-+ readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
-+
-+#define pmerrloc_readl_relaxed(addr, reg) \
-+ readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
-+
-+#define pmerrloc_writel(addr, reg, value) \
-+ writel((value), (addr) + ATMEL_PMERRLOC_##reg)
-+
-+#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
-+ writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
-+
-+#define pmerrloc_readl_sigma_relaxed(addr, n) \
-+ readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
-+
-+#define pmerrloc_readl_el_relaxed(addr, n) \
-+ readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
-+
-+/* Galois field dimension */
-+#define PMECC_GF_DIMENSION_13 13
-+#define PMECC_GF_DIMENSION_14 14
-+
-+#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
-+#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
-+
-+/* Time out value for reading PMECC status register */
-+#define PMECC_MAX_TIMEOUT_MS 100
-+
- #endif
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8a6cf5507a3070841f8b4636af42d847d885f50d Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 25 Jun 2012 15:15:54 +0800
+Subject: MTD: nand: add return value for write_page()/write_page_raw()
+ functions in structure of nand_ecc_ctrl.
+
+Is the equivalent of commit fdbad98dff8007f2b8bee6698b5d25ebba0471c9 upstream.
+
+There is an implemention of hardware ECC write page function which may return an
+error indication.
+For instance, using Atmel HW PMECC to write one page into a nand flash, the hardware
+engine will compute the BCH ecc code for this page. so we need read a the
+status register to theck whether the ecc code is generated.
+But we cannot assume the status register always can be ready, for example,
+incorrect hardware configuration or hardware issue, in such case we need
+write_page() to return a error code.
+
+Since the definition of 'write_page' function in struct nand_ecc_ctrl is 'void'.
+So this patch will:
+ 1. add return 'int' value for 'write_page' function.
+ 2. to be consitent, add return 'int' value for 'write_page_raw' fuctions too.
+ 3. add code to test the return value, and if negative, indicate an
+ error happend when write page with ECC.
+ 4. fix the compile warning in all impacted nand flash driver.
+
+Note: I couldn't compile-test all of these easily, as some had ARCH dependencies.
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++--------
+ include/linux/mtd/nand.h | 4 ++--
+ 2 files changed, 21 insertions(+), 10 deletions(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -1922,11 +1922,13 @@ out:
+ *
+ * Not for syndrome calculating ECC controllers, which use a special oob layout.
+ */
+-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
+ }
+
+ /**
+@@ -1937,7 +1939,7 @@ static void nand_write_page_raw(struct m
+ *
+ * We need a special oob layout and handling even when ECC isn't checked.
+ */
+-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
++static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+@@ -1967,6 +1969,8 @@ static void nand_write_page_raw_syndrome
+ size = mtd->oobsize - (oob - chip->oob_poi);
+ if (size)
+ chip->write_buf(mtd, oob, size);
++
++ return 0;
+ }
+ /**
+ * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
+@@ -1974,7 +1978,7 @@ static void nand_write_page_raw_syndrome
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -1991,7 +1995,7 @@ static void nand_write_page_swecc(struct
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+- chip->ecc.write_page_raw(mtd, chip, buf);
++ return chip->ecc.write_page_raw(mtd, chip, buf);
+ }
+
+ /**
+@@ -2000,7 +2004,7 @@ static void nand_write_page_swecc(struct
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
++static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -2020,6 +2024,8 @@ static void nand_write_page_hwecc(struct
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
++
++ return 0;
+ }
+
+ /**
+@@ -2031,7 +2037,7 @@ static void nand_write_page_hwecc(struct
+ * The hw generator calculates the error syndrome automatically. Therefore we
+ * need a special oob layout and handling.
+ */
+-static void nand_write_page_syndrome(struct mtd_info *mtd,
++static int nand_write_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+ {
+ int i, eccsize = chip->ecc.size;
+@@ -2064,6 +2070,8 @@ static void nand_write_page_syndrome(str
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->write_buf(mtd, oob, i);
++
++ return 0;
+ }
+
+ /**
+@@ -2083,9 +2091,12 @@ static int nand_write_page(struct mtd_in
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+ if (unlikely(raw))
+- chip->ecc.write_page_raw(mtd, chip, buf);
++ status = chip->ecc.write_page_raw(mtd, chip, buf);
+ else
+- chip->ecc.write_page(mtd, chip, buf);
++ status = chip->ecc.write_page(mtd, chip, buf);
++
++ if (status < 0)
++ return status;
+
+ /*
+ * Cached progamming disabled for now. Not sure if it's worth the
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -361,13 +361,13 @@ struct nand_ecc_ctrl {
+ uint8_t *calc_ecc);
+ int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+- void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
++ int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+ int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page);
+ int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
+ uint32_t offs, uint32_t len, uint8_t *buf);
+- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
++ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+ int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+ int page);
--- /dev/null
+From b9401beeb6444e9e2bc4de97b1efc2ac9491a34f Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 13:20:22 +0800
+Subject: MTD: atmel nand: fix gpio missing request
+
+commit 28446acb1f8268cda4b2076f72519534f84d6a36 upstream.
+
+without this the gpio will not be muxed as a gpio by the current custom pinmux
+or later by the pinctrl
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 50 ++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 49 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index 42b64fb..c512bba 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1410,8 +1410,41 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ nand_chip->IO_ADDR_W = host->io_base;
+ nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+
+- if (gpio_is_valid(host->board.rdy_pin))
++ if (gpio_is_valid(host->board.rdy_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.rdy_pin, "nand_rdy");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request rdy gpio %d\n", host->board.rdy_pin);
++ goto err_ecc_ioremap;
++ }
++
++ res = gpio_direction_input(host->board.rdy_pin);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request input direction rdy gpio %d\n", host->board.rdy_pin);
++ goto err_ecc_ioremap;
++ }
++
+ nand_chip->dev_ready = atmel_nand_device_ready;
++ }
++
++ if (gpio_is_valid(host->board.enable_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.enable_pin, "nand_enable");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request enable gpio %d\n", host->board.enable_pin);
++ goto err_ecc_ioremap;
++ }
++
++ res = gpio_direction_output(host->board.enable_pin, 1);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request output direction enable gpio %d\n", host->board.enable_pin);
++ goto err_ecc_ioremap;
++ }
++ }
+
+ nand_chip->ecc.mode = host->board.ecc_mode;
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+@@ -1426,6 +1459,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ atmel_nand_enable(host);
+
+ if (gpio_is_valid(host->board.det_pin)) {
++ res = devm_gpio_request(&pdev->dev,
++ host->board.det_pin, "nand_det");
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request det gpio %d\n", host->board.det_pin);
++ goto err_no_card;
++ }
++
++ res = gpio_direction_input(host->board.det_pin);
++ if (res < 0) {
++ dev_err(&pdev->dev,
++ "can't request input direction det gpio %d\n", host->board.det_pin);
++ goto err_no_card;
++ }
++
+ if (gpio_get_value(host->board.det_pin)) {
+ printk(KERN_INFO "No SmartMedia card inserted.\n");
+ res = -ENXIO;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From c00279166e428d885fd658d0be8d2419acc87d18 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Mon, 25 Jun 2012 15:15:54 +0800
-Subject: MTD: nand: add return value for write_page()/write_page_raw()
- functions in structure of nand_ecc_ctrl.
-
-There is an implemention of hardware ECC write page function which may return an
-error indication.
-For instance, using Atmel HW PMECC to write one page into a nand flash, the hardware
-engine will compute the BCH ecc code for this page. so we need read a the
-status register to theck whether the ecc code is generated.
-But we cannot assume the status register always can be ready, for example,
-incorrect hardware configuration or hardware issue, in such case we need
-write_page() to return a error code.
-
-Since the definition of 'write_page' function in struct nand_ecc_ctrl is 'void'.
-So this patch will:
- 1. add return 'int' value for 'write_page' function.
- 2. to be consitent, add return 'int' value for 'write_page_raw' fuctions too.
- 3. add code to test the return value, and if negative, indicate an
- error happend when write page with ECC.
- 4. fix the compile warning in all impacted nand flash driver.
-
-Note: I couldn't compile-test all of these easily, as some had ARCH dependencies.
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++--------
- include/linux/mtd/nand.h | 4 ++--
- 2 files changed, 21 insertions(+), 10 deletions(-)
-
---- a/drivers/mtd/nand/nand_base.c
-+++ b/drivers/mtd/nand/nand_base.c
-@@ -1922,11 +1922,13 @@ out:
- *
- * Not for syndrome calculating ECC controllers, which use a special oob layout.
- */
--static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
- {
- chip->write_buf(mtd, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+
-+ return 0;
- }
-
- /**
-@@ -1937,7 +1939,7 @@ static void nand_write_page_raw(struct m
- *
- * We need a special oob layout and handling even when ECC isn't checked.
- */
--static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
-+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip,
- const uint8_t *buf)
- {
-@@ -1967,6 +1969,8 @@ static void nand_write_page_raw_syndrome
- size = mtd->oobsize - (oob - chip->oob_poi);
- if (size)
- chip->write_buf(mtd, oob, size);
-+
-+ return 0;
- }
- /**
- * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
-@@ -1974,7 +1978,7 @@ static void nand_write_page_raw_syndrome
- * @chip: nand chip info structure
- * @buf: data buffer
- */
--static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
-+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
- {
- int i, eccsize = chip->ecc.size;
-@@ -1991,7 +1995,7 @@ static void nand_write_page_swecc(struct
- for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
-- chip->ecc.write_page_raw(mtd, chip, buf);
-+ return chip->ecc.write_page_raw(mtd, chip, buf);
- }
-
- /**
-@@ -2000,7 +2004,7 @@ static void nand_write_page_swecc(struct
- * @chip: nand chip info structure
- * @buf: data buffer
- */
--static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
- {
- int i, eccsize = chip->ecc.size;
-@@ -2020,6 +2024,8 @@ static void nand_write_page_hwecc(struct
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-+
-+ return 0;
- }
-
- /**
-@@ -2031,7 +2037,7 @@ static void nand_write_page_hwecc(struct
- * The hw generator calculates the error syndrome automatically. Therefore we
- * need a special oob layout and handling.
- */
--static void nand_write_page_syndrome(struct mtd_info *mtd,
-+static int nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf)
- {
- int i, eccsize = chip->ecc.size;
-@@ -2064,6 +2070,8 @@ static void nand_write_page_syndrome(str
- i = mtd->oobsize - (oob - chip->oob_poi);
- if (i)
- chip->write_buf(mtd, oob, i);
-+
-+ return 0;
- }
-
- /**
-@@ -2083,9 +2091,12 @@ static int nand_write_page(struct mtd_in
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
- if (unlikely(raw))
-- chip->ecc.write_page_raw(mtd, chip, buf);
-+ status = chip->ecc.write_page_raw(mtd, chip, buf);
- else
-- chip->ecc.write_page(mtd, chip, buf);
-+ status = chip->ecc.write_page(mtd, chip, buf);
-+
-+ if (status < 0)
-+ return status;
-
- /*
- * Cached progamming disabled for now. Not sure if it's worth the
---- a/include/linux/mtd/nand.h
-+++ b/include/linux/mtd/nand.h
-@@ -361,13 +361,13 @@ struct nand_ecc_ctrl {
- uint8_t *calc_ecc);
- int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page);
-- void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
-+ int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf);
- int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf, int page);
- int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
- uint32_t offs, uint32_t len, uint8_t *buf);
-- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
-+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf);
- int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
- int page);
+++ /dev/null
-From 7d92178b306bf2b8020da2a5c53077885e6239f9 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Fri, 21 Sep 2012 15:49:29 +0200
-Subject: MTD: atmel_nand: revet the oob_required parameter in
- ecc.read/write_page
-
-Only for v3.4 compatibility. Do not propagate upstream
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 42b64fb..ec0745e 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -759,7 +759,7 @@ normal_check:
- }
-
- static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
-- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
-+ struct nand_chip *chip, uint8_t *buf, int page)
- {
- struct atmel_nand_host *host = chip->priv;
- int eccsize = chip->ecc.size;
-@@ -797,7 +797,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
- }
-
- static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
-- struct nand_chip *chip, const uint8_t *buf, int oob_required)
-+ struct nand_chip *chip, const uint8_t *buf)
- {
- struct atmel_nand_host *host = chip->priv;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 0e4179bc4720ad2cc938df8eda49685e84be6e91 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Date: Fri, 7 Sep 2012 14:54:25 +0800
+Subject: usb: gadget: at91_udc: move the dereference below the NULL test
+
+commit 162ca3ca613e02e115ec9c5273f94bd22dad0af2 upstream.
+
+The dereference should be moved below the NULL test.
+
+spatch with a semantic match is used to found this.
+(http://coccinelle.lip6.fr/)
+
+Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
+Signed-off-by: Felipe Balbi <balbi@ti.com>
+---
+ drivers/usb/gadget/at91_udc.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index 9d7bcd9..d6249f0 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -469,7 +469,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+ {
+ struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
+- struct at91_udc *udc = ep->udc;
++ struct at91_udc *udc;
+ u16 maxpacket;
+ u32 tmp;
+ unsigned long flags;
+@@ -484,6 +484,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
+ return -EINVAL;
+ }
+
++ udc = ep->udc;
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ DBG("bogus device state\n");
+ return -ESHUTDOWN;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ddee6570ee156ed3d758fbfb0931054d77da29c5 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 24 Sep 2012 14:57:08 +0200
-Subject: MTD: atmel_nand: add 9x5 to list of SoC with DMA
-
-Temporary: may have to be replaced by a device-tree property.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index ec0745e..a5c184e 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -127,7 +127,7 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
-
- static int cpu_has_dma(void)
- {
-- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
-+ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() || cpu_is_at91sam9x5();
- }
-
- /*
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 3efc10bd73879d566ad573e6ce4419fb79d9eda0 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 24 Sep 2012 15:07:06 +0200
-Subject: MTD: atmel_nand: POI fall back is not an issue: change log
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index a5c184e..17ef011 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -281,7 +281,7 @@ err_dma:
- dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
- err_buf:
- if (err != 0)
-- dev_warn(host->dev, "Fall back to CPU I/O\n");
-+ dev_dbg(host->dev, "Fall back to CPU I/O\n");
- return err;
- }
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2b2b3800d382a683216a2e0fc6a27ba480716f2a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 29 Aug 2012 11:49:18 +0200
+Subject: USB: ohci-at91: fix PIO handling in relation with number of ports
+
+commit 6fffb77c8393151b0cf8cef1b9c2ba90587dd2e8 upstream.
+
+If the number of ports present on the SoC/board is not the maximum
+and that the platform data is not filled with all data, there is
+an easy way to mess the PIO setup for this interface.
+This quick fix addresses mis-configuration in USB host platform data
+that is common in at91 boards since commit 0ee6d1e (USB: ohci-at91:
+change maximum number of ports) that did not modified the associatd
+board files.
+
+Reported-by: Klaus Falkner <klaus.falkner@solectrix.de>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Stable <stable@vger.kernel.org> [3.4+]
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ohci-at91.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -647,6 +647,16 @@ static int __devexit ohci_hcd_at91_drv_r
+
+ if (pdata) {
+ at91_for_each_port(i) {
++ /*
++ * do not configure PIO if not in relation with
++ * real USB port on board
++ */
++ if (i >= pdata->ports) {
++ pdata->vbus_pin[i] = -EINVAL;
++ pdata->overcurrent_pin[i] = -EINVAL;
++ break;
++ }
++
+ if (!gpio_is_valid(pdata->vbus_pin[i]))
+ continue;
+ ohci_at91_usb_set_power(pdata, i, 0);
+++ /dev/null
-From 6d16ae9b0f776651f60af120bb799d77504a2703 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 8 Oct 2012 16:55:29 +0200
-Subject: MTD: atmel_nand: add 9n12 to list of SoC with DMA
-
-Temporary: may have to be replaced by a device-tree property.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mtd/nand/atmel_nand.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 17ef011..b1158b4 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -127,7 +127,8 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
-
- static int cpu_has_dma(void)
- {
-- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() || cpu_is_at91sam9x5();
-+ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
-+ || cpu_is_at91sam9x5() || cpu_is_at91sam9n12();
- }
-
- /*
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 620f6b0ce1071fd027a1882a21e41143d8bb5d95 Mon Sep 17 00:00:00 2001
+From: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
+Date: Tue, 26 Jun 2012 11:27:12 -0300
+Subject: usb: gadget: at91_udc: Propagate devicetree to gadget drivers
+
+commit 65c84ea18b1b4b8c03fb67c3bea023ed1446bd2e upstream.
+
+Fill dev.of_node of gadget drivers, so they can use devicetree
+
+Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
+Signed-off-by: Felipe Balbi <balbi@ti.com>
+---
+ drivers/usb/gadget/at91_udc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
+index ffb46bc..ddeaadb 100644
+--- a/drivers/usb/gadget/at91_udc.c
++++ b/drivers/usb/gadget/at91_udc.c
+@@ -1650,6 +1650,7 @@ static int at91_start(struct usb_gadget_driver *driver,
+
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
++ udc->gadget.dev.of_node = udc->pdev->dev.of_node;
+ dev_set_drvdata(&udc->gadget.dev, &driver->driver);
+ udc->enabled = 1;
+ udc->selfpowered = 1;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 5f66b12556f296e2aa31268877ad5c2961a073f4 Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Fri, 27 Apr 2012 11:24:39 -0700
+Subject: USB: ohci-at91.c: remove err() usage
+
+commit 2418d5f979fa424c401654f0f1e1d6abffecc379 upstream.
+
+err() was a very old USB-specific macro that I thought had
+gone away. This patch removes it from being used in the
+driver and uses dev_err() instead.
+
+CC: Alan Stern <stern@rowland.harvard.edu>
+CC: Grant Likely <grant.likely@secretlab.ca>
+CC: Rob Herring <rob.herring@calxeda.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/host/ohci-at91.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index 5dfea46..aaa8d2b 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -243,7 +243,8 @@ ohci_at91_start (struct usb_hcd *hcd)
+ int ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+- err("can't start %s", hcd->self.bus_name);
++ dev_err(hcd->self.controller, "can't start %s\n",
++ hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 205e3ae2e153f8cd611e980d02c5ca629e726f06 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Wed, 17 Nov 2010 12:28:13 +0100
-Subject: input: atmel_tsadcc: add support for ARCH_AT91SAM9X5
-
-XXX: split header creation in a new patch (or don't do it)
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 150 ++++++++++++----------------
- drivers/input/touchscreen/atmel_tsadcc.h | 162 +++++++++++++++++++++++++++++++
- 2 files changed, 222 insertions(+), 90 deletions(-)
- create mode 100644 drivers/input/touchscreen/atmel_tsadcc.h
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index 201b2d2..a0e8d52 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -25,74 +25,9 @@
- #include <mach/board.h>
- #include <mach/cpu.h>
-
--/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
--
--#define ATMEL_TSADCC_CR 0x00 /* Control register */
--#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
--#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
--
--#define ATMEL_TSADCC_MR 0x04 /* Mode register */
--#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
--#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
--#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
--#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
--#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
--#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
--#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
--#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
--#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
--#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
--#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
--#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
--
--#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
--#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
--#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
--#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
--#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
--#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
--#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
--#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
--#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
--#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
--
--#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
--#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
--#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
--
--#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
--#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
--#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
--#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
--
--#define ATMEL_TSADCC_SR 0x1C /* Status register */
--#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
--#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
--#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
--#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
--#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
--#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
--#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
--#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
--
--#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
--#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
--
--#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
--#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
--#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
--#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
--#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
--#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
--#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
--#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
--#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
--
--#define ATMEL_TSADCC_XPOS 0x50
--#define ATMEL_TSADCC_Z1DAT 0x54
--#define ATMEL_TSADCC_Z2DAT 0x58
--
--#define PRESCALER_VAL(x) ((x) >> 8)
-+#include "atmel_tsadcc.h"
-+
-+#define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
-
- #define ADC_DEFAULT_CLOCK 100000
-
-@@ -124,12 +59,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
-
- if (status & ATMEL_TSADCC_NOCNT) {
- /* Contact lost */
-- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
--
-- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
-+ if (cpu_has_9x5_adc()) {
-+ /* 9X5 using TSMR to set PENDBC time */
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
-+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
-+ } else {
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
-+ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
-+ }
- atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
- atmel_tsadcc_write(ATMEL_TSADCC_IDR,
-- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
-+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
- atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
-
- input_report_key(input_dev, BTN_TOUCH, 0);
-@@ -138,23 +78,31 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
-
- } else if (status & ATMEL_TSADCC_PENCNT) {
- /* Pen detected */
-- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
-- reg &= ~ATMEL_TSADCC_PENDBC;
-+ if (cpu_has_9x5_adc()) {
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR);
-+ reg &= ~ATMEL_TSADCC_PENDBC;
-+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
-+ } else {
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
-+ reg &= ~ATMEL_TSADCC_PENDBC;
-+ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
-+ }
-
- atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
-- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
- atmel_tsadcc_write(ATMEL_TSADCC_IER,
-- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
-+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
- atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
- ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
-
-- } else if (status & ATMEL_TSADCC_EOC(3)) {
-+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
- /* Conversion finished */
-
- if (ts_dev->bufferedmeasure) {
- /* Last measurement is always discarded, since it can
- * be erroneous.
- * Always report previous measurement */
-+ dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
-+ ts_dev->prev_absx, ts_dev->prev_absy);
- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
- input_report_key(input_dev, BTN_TOUCH, 1);
-@@ -163,11 +111,16 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- ts_dev->bufferedmeasure = 1;
-
- /* Now make new measurement */
-- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
-- ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
--
-- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
-- ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
-+ if (cpu_has_9x5_adc()) {
-+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
-+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
-+ } else {
-+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
-+ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
-+
-+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
-+ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
-+ }
- }
-
- return IRQ_HANDLED;
-@@ -284,18 +237,35 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
-
- dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
-
-- reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
-- ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
-- ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
-- (prsc << 8) |
-- ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
-- ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
-+ if (cpu_has_9x5_adc()) {
-+ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
-+ (prsc << 8) |
-+ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
-+ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
-+ } else {
-+ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
-+ ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
-+ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
-+ (prsc << 8) |
-+ ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
-+ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
-+ }
-
- atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
- atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
-- atmel_tsadcc_write(ATMEL_TSADCC_TSR,
-- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
-+
-+ if (cpu_has_9x5_adc()) {
-+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
-+ ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
-+ ATMEL_TSADCC_NOTSDMA |
-+ ATMEL_TSADCC_PENDET_ENA |
-+ (pdata->pendet_debounce << 28) |
-+ (0x0 << 8));
-+ } else {
-+ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
-+ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
-+ }
-
- atmel_tsadcc_read(ATMEL_TSADCC_SR);
- atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
-new file mode 100644
-index 0000000..5918c20
---- /dev/null
-+++ b/drivers/input/touchscreen/atmel_tsadcc.h
-@@ -0,0 +1,162 @@
-+/*
-+ * Header file for AT91/AT32 ADC + touchscreen Controller
-+ *
-+ * Data structure and register user interface
-+ *
-+ * Copyright (C) 2010 Atmel Corporation
-+ *
-+ * 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.
-+ *
-+ * This program 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 General Public License for more details.
-+ *
-+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ATMEL_TSADCC_H__
-+#define __ATMEL_TSADCC_H__
-+
-+/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
-+#define ATMEL_TSADCC_CR 0x00 /* Control register */
-+#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
-+#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
-+
-+#define ATMEL_TSADCC_MR 0x04 /* Mode register */
-+#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
-+#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
-+#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
-+#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
-+#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
-+#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
-+#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
-+#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
-+#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
-+#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
-+#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
-+#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
-+
-+#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
-+#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
-+#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
-+#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
-+#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
-+#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
-+#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
-+#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
-+#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
-+#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
-+
-+#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
-+#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
-+#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
-+
-+#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
-+#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
-+#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
-+#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
-+
-+#define ATMEL_TSADCC_SR 0x1C /* Status register */
-+#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
-+#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
-+#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
-+#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
-+#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
-+#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
-+#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
-+#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
-+
-+#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
-+#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
-+
-+#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
-+#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
-+#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
-+#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
-+#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
-+#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
-+#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
-+#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
-+#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
-+
-+#define ATMEL_TSADCC_XPOS 0x50
-+#define ATMEL_TSADCC_Z1DAT 0x54
-+#define ATMEL_TSADCC_Z2DAT 0x58
-+
-+#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_EOC(3))
-+
-+/* Register definitions based on AT91SAM9X5 preliminary draft datasheet */
-+#define ATMEL_TSADCC_TRACKTIM (0x0f << 24) /* Tracking Time */
-+
-+#define ATMEL_TSADCC_ISR 0x30 /* Interrupt Status register */
-+#define ATMEL_TSADCC_XRDY (1 << 20) /* Measure XPOS Ready */
-+#define ATMEL_TSADCC_YRDY (1 << 21) /* Measure YPOS Ready */
-+#define ATMEL_TSADCC_PRDY (1 << 22) /* Measure Pressure Ready */
-+#define ATMEL_TSADCC_COMPE (1 << 26) /* Comparison Event */
-+#define ATMEL_TSADCC_PEN (1 << 29) /* Pen Contact */
-+#define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
-+#define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
-+
-+#define ATMEL_TSADCC_TSMR 0xb0
-+#define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
-+#define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
-+#define ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS (1 << 0) /* 4-wire Touch Screen without pressure measurement */
-+#define ATMEL_TSADCC_TSMODE_4WIRE_PRESS (2 << 0) /* 4-wire Touch Screen with pressure measurement */
-+#define ATMEL_TSADCC_TSMODE_5WIRE (3 << 0) /* 5-wire Touch Screen */
-+#define ATMEL_TSADCC_TSAV (3 << 4) /* Touch Screen Average */
-+#define ATMEL_TSADCC_TSAV_1 (0 << 4) /* No filtering. Only one conversion ADC per measure */
-+#define ATMEL_TSADCC_TSAV_2 (1 << 4) /* Averages 2 ADC conversions */
-+#define ATMEL_TSADCC_TSAV_4 (2 << 4) /* Averages 4 ADC conversions */
-+#define ATMEL_TSADCC_TSAV_8 (3 << 4) /* Averages 8 ADC conversions */
-+#define ATMEL_TSADCC_TSSCTIM (0x0f << 16) /* Touch Screen switches closure time */
-+
-+#define ATMEL_TSADCC_NOTSDMA (1 << 22) /* No Touchscreen DMA */
-+#define ATMEL_TSADCC_PENDET_DIS (0 << 24) /* Pen contact detection disable */
-+#define ATMEL_TSADCC_PENDET_ENA (1 << 24) /* Pen contact detection enable */
-+
-+#define ATMEL_TSADCC_XPOSR 0xb4
-+#define ATMEL_TSADCC_XSCALE (0x3ff << 16) /* Scale of X Position */
-+
-+#define ATMEL_TSADCC_YPOSR 0xb8
-+#define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
-+#define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
-+
-+/* 9x5 ADC registers which conflict with previous definition */
-+#ifdef CONFIG_ARCH_AT91SAM9X5
-+#undef ATMEL_TSADCC_TRGR
-+#undef ATMEL_TSADCC_SR
-+#define ATMEL_TSADCC_SR ATMEL_TSADCC_ISR
-+#define ATMEL_TSADCC_TRGR 0xc0
-+
-+/* For code compatiable, redefine with 9x5 value */
-+#undef ATMEL_TSADCC_STARTUP
-+#define ATMEL_TSADCC_STARTUP (0x0f << 16) /* Startup Time */
-+#undef ATMEL_TSADCC_DRDY
-+#define ATMEL_TSADCC_DRDY (1 << 24) /* Data Ready */
-+#undef ATMEL_TSADCC_GOVRE
-+#define ATMEL_TSADCC_GOVRE (1 << 25) /* General Overrun */
-+#undef ATMEL_TSADCC_TSFREQ
-+#define ATMEL_TSADCC_TSFREQ (0x0f << 8) /* Touch Screen Frequency */
-+#undef ATMEL_TSADCC_PENDET
-+#define ATMEL_TSADCC_PENDET (1 << 24) /* Pen Contact Detection Enable */
-+#undef ATMEL_TSADCC_XPOS
-+#define ATMEL_TSADCC_XPOS (0x3ff << 0) /* X Position */
-+
-+#undef ATMEL_TSADCC_NOCNT
-+#define ATMEL_TSADCC_NOCNT ATMEL_TSADCC_NOPEN
-+#undef ATMEL_TSADCC_PENCNT
-+#define ATMEL_TSADCC_PENCNT ATMEL_TSADCC_PEN
-+#undef ATMEL_TSADCC_CONVERSION_END
-+#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_XRDY | ATMEL_TSADCC_YRDY | ATMEL_TSADCC_PRDY)
-+
-+#endif
-+
-+/* Retrieve prescaler value */
-+#define PRESCALER_VAL(x) ((x) >> 8)
-+
-+#endif /* __ATMEL_TSADCC_H__ */
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From f924876dcc5572639dbb81e2e148cc84066f9571 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Wed, 17 Nov 2010 13:12:11 +0100
-Subject: input: atmel_tsadcc: add touch screen pressure measurement
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 26 +++++++++++++++++++++++---
- drivers/input/touchscreen/atmel_tsadcc.h | 4 ++++
- 2 files changed, 27 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index a0e8d52..b6a1630 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -38,6 +38,7 @@ struct atmel_tsadcc {
- int irq;
- unsigned int prev_absx;
- unsigned int prev_absy;
-+ unsigned int prev_absz;
- unsigned char bufferedmeasure;
- };
-
-@@ -53,6 +54,9 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
-
- unsigned int status;
- unsigned int reg;
-+ unsigned int z1, z2;
-+ unsigned int Rxp = 1;
-+ unsigned int factor = 1000;
-
- status = atmel_tsadcc_read(ATMEL_TSADCC_SR);
- status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);
-@@ -101,11 +105,15 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- /* Last measurement is always discarded, since it can
- * be erroneous.
- * Always report previous measurement */
-- dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
-- ts_dev->prev_absx, ts_dev->prev_absy);
-+ dev_dbg(&input_dev->dev,
-+ "x = %d, y = %d, pressure = %d\n",
-+ ts_dev->prev_absx, ts_dev->prev_absy,
-+ ts_dev->prev_absz);
- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
- input_report_key(input_dev, BTN_TOUCH, 1);
-+ if (cpu_has_9x5_adc())
-+ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
- input_sync(input_dev);
- } else
- ts_dev->bufferedmeasure = 1;
-@@ -114,6 +122,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- if (cpu_has_9x5_adc()) {
- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
-+
-+ /* calculate the pressure */
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
-+ z1 = reg & ATMEL_TSADCC_PRESSR_Z1;
-+ z2 = (reg & ATMEL_TSADCC_PRESSR_Z2) >> 16;
-+
-+ if (z1 != 0)
-+ ts_dev->prev_absz = Rxp * (ts_dev->prev_absx * factor / 1024) * (z2 * factor / z1 - factor) / factor;
-+ else
-+ ts_dev->prev_absz = 0;
-+
- } else {
- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
- ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
-@@ -209,6 +228,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- __set_bit(EV_ABS, input_dev->evbit);
- input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
-+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xffffff, 0, 0);
-
- input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
-
-@@ -257,7 +277,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
-
- if (cpu_has_9x5_adc()) {
- atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
-- ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
-+ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
- ATMEL_TSADCC_NOTSDMA |
- ATMEL_TSADCC_PENDET_ENA |
- (pdata->pendet_debounce << 28) |
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
-index 5918c20..231497e 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.h
-+++ b/drivers/input/touchscreen/atmel_tsadcc.h
-@@ -126,6 +126,10 @@
- #define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
- #define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
-
-+#define ATMEL_TSADCC_PRESSR 0xbc /* Touchscreen Pressure Register */
-+#define ATMEL_TSADCC_PRESSR_Z1 (0x3ff << 0) /* Data of Z1 Measurement */
-+#define ATMEL_TSADCC_PRESSR_Z2 (0x3ff << 16) /* Data of Z2 Measurement */
-+
- /* 9x5 ADC registers which conflict with previous definition */
- #ifdef CONFIG_ARCH_AT91SAM9X5
- #undef ATMEL_TSADCC_TRGR
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 736d87b6261c8fee4399f3d2605609fd97b43f5e Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 21 Sep 2012 15:49:29 +0200
+Subject: MTD: atmel_nand: revet the oob_required parameter in
+ ecc.read/write_page
+
+Only for v3.4 compatibility. Do not propagate upstream
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index c512bba..b5e5a76 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -759,7 +759,7 @@ normal_check:
+ }
+
+ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+- struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
++ struct nand_chip *chip, uint8_t *buf, int page)
+ {
+ struct atmel_nand_host *host = chip->priv;
+ int eccsize = chip->ecc.size;
+@@ -797,7 +797,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+ }
+
+ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+- struct nand_chip *chip, const uint8_t *buf, int oob_required)
++ struct nand_chip *chip, const uint8_t *buf)
+ {
+ struct atmel_nand_host *host = chip->priv;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From c331326e3dcab10a8930f9f685bec700ec0d604a Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 5 Apr 2011 17:30:03 +0200
-Subject: input: atmel_tsadcc: enable touchscreen averaging and add fast wake
- up
-
-Enable the touchscreen average to improve the resulting events. For this
-to work the trigger period needs to be reduced.
-
-This puts a field into at91_tsadcc_data to allow platforms to specify
-the number of conversions to average over.
-
-XXX: should the trigger period passed by the platform, too, as this
-depends on the number of conversions?
-XXX: seperate fast wake up into a seperate patch? What does it?
-XXX: don't use bare constants
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 14 ++++++++------
- drivers/input/touchscreen/atmel_tsadcc.h | 1 +
- 2 files changed, 9 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index b6a1630..48faecb 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -96,7 +96,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- atmel_tsadcc_write(ATMEL_TSADCC_IER,
- ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
- atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
-- ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
-+ ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
-
- } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
- /* Conversion finished */
-@@ -259,6 +259,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
-
- if (cpu_has_9x5_adc()) {
- reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
-+ ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
- (prsc << 8) |
- ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
- ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
-@@ -277,11 +278,12 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
-
- if (cpu_has_9x5_adc()) {
- atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
-- ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
-- ATMEL_TSADCC_NOTSDMA |
-- ATMEL_TSADCC_PENDET_ENA |
-- (pdata->pendet_debounce << 28) |
-- (0x0 << 8));
-+ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
-+ (pdata->filtering_average << 4) | /* Touchscreen average */
-+ ATMEL_TSADCC_NOTSDMA |
-+ ATMEL_TSADCC_PENDET_ENA |
-+ (pdata->pendet_debounce << 28) |
-+ (0x3 << 8)); /* Touchscreen freq */
- } else {
- atmel_tsadcc_write(ATMEL_TSADCC_TSR,
- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
-index 231497e..572770a 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.h
-+++ b/drivers/input/touchscreen/atmel_tsadcc.h
-@@ -34,6 +34,7 @@
- #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
- #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
- #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
-+#define ATMEL_TSADCC_FWUP (1 << 6) /* Fast Wake Up selection (5series) */
- #define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
- #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
- #define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From b0b4d9808e0c71070375befa5b06707eb91c3a2a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 19 Jun 2012 13:14:10 +0200
+Subject: USB: Kconfig: add Atmel usba driver entry
+
+Allow the USBA entry to be selected for every AT91 SoC.
+Will allow to select driver for newer SoCs.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/usb/gadget/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 2633f75..10fea8b 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -150,7 +150,7 @@ config USB_AT91
+ config USB_ATMEL_USBA
+ tristate "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+- depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
++ depends on AVR32 || ARCH_AT91
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From bb2bbaa1312891063aed730f0fd3eeddf77f95cb Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 6 May 2011 17:54:45 +0200
-Subject: input: atmel_tsadcc: add ACR register and change trigger period value
-
-Add ACR register which allows to configure internal ADC resistor, that should
-prevent from adding resistor on display module. Furthermore increase
-trigger period which seems to be related with resistor value. A Too small
-value causes continuous irq.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 30 +++++++++++++++++++++++++++++-
- drivers/input/touchscreen/atmel_tsadcc.h | 3 +++
- 2 files changed, 32 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index 48faecb..20154ba 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -47,6 +47,17 @@ static void __iomem *tsc_base;
- #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg))
- #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg))
-
-+static void atmel_tsadcc_dump_conf(struct platform_device *pdev)
-+{
-+ dev_info(&pdev->dev, "--- configuration ---\n");
-+ dev_info(&pdev->dev, "Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_MR));
-+ dev_info(&pdev->dev, "Trigger Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TRGR));
-+ dev_info(&pdev->dev, "Touchscreen Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TSMR));
-+ dev_info(&pdev->dev, "Analog Control Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_ACR));
-+ dev_info(&pdev->dev, "ADC Channel Status Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_CHSR));
-+ dev_info(&pdev->dev, "---------------------\n");
-+}
-+
- static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- {
- struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
-@@ -95,8 +106,14 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
- atmel_tsadcc_write(ATMEL_TSADCC_IER,
- ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
-+ /* this value is related to the resistor bits value of
-+ * ACR register and R64. If internal resistor value is
-+ * increased then this value has to be increased. This
-+ * behavior seems to happen only with averaging on 8
-+ * values
-+ */
- atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
-- ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
-+ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FF << 16));
-
- } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
- /* Conversion finished */
-@@ -289,9 +306,20 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
- }
-
-+ /* Change adc internal resistor value for better pen detection,
-+ * default value is 100 kOhm.
-+ * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
-+ * option only available on ES2 and higher
-+ */
-+ if (cpu_has_9x5_adc()) {
-+ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
-+ }
-+
- atmel_tsadcc_read(ATMEL_TSADCC_SR);
- atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
-
-+ /* atmel_tsadcc_dump_conf(pdev); */
-+
- /* All went ok, so register to the input system */
- err = input_register_device(input_dev);
- if (err)
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
-index 572770a..fe74506 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.h
-+++ b/drivers/input/touchscreen/atmel_tsadcc.h
-@@ -103,6 +103,9 @@
- #define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
- #define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
-
-+#define ATMEL_TSADCC_ACR 0x94 /* Analog Control Register */
-+#define ATMEL_TSADCC_PENDET_SENSITIVITY (0x3 << 0) /* ADC internal resistor */
-+
- #define ATMEL_TSADCC_TSMR 0xb0
- #define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
- #define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From dd05003395a5ae175e64b5ae8d78f6867d5d7398 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 16 Jun 2011 19:24:04 +0200
-Subject: AT91/input: atmel_tsadcc: rework irq infrastructure and parameters
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 70 ++++++++++++++++++--------------
- 1 file changed, 40 insertions(+), 30 deletions(-)
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index 20154ba..397d17a 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -30,6 +30,7 @@
- #define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
-
- #define ADC_DEFAULT_CLOCK 100000
-+#define ZTHRESHOLD 3200
-
- struct atmel_tsadcc {
- struct input_dev *input;
-@@ -39,7 +40,6 @@ struct atmel_tsadcc {
- unsigned int prev_absx;
- unsigned int prev_absy;
- unsigned int prev_absz;
-- unsigned char bufferedmeasure;
- };
-
- static void __iomem *tsc_base;
-@@ -62,6 +62,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- {
- struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
- struct input_dev *input_dev = ts_dev->input;
-+ struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data;
-
- unsigned int status;
- unsigned int reg;
-@@ -76,7 +77,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- /* Contact lost */
- if (cpu_has_9x5_adc()) {
- /* 9X5 using TSMR to set PENDBC time */
-- reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
- atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
- } else {
- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
-@@ -88,7 +89,6 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
-
- input_report_key(input_dev, BTN_TOUCH, 0);
-- ts_dev->bufferedmeasure = 0;
- input_sync(input_dev);
-
- } else if (status & ATMEL_TSADCC_PENCNT) {
-@@ -118,27 +118,20 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
- /* Conversion finished */
-
-- if (ts_dev->bufferedmeasure) {
-- /* Last measurement is always discarded, since it can
-- * be erroneous.
-- * Always report previous measurement */
-- dev_dbg(&input_dev->dev,
-- "x = %d, y = %d, pressure = %d\n",
-- ts_dev->prev_absx, ts_dev->prev_absy,
-- ts_dev->prev_absz);
-- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
-- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
-- input_report_key(input_dev, BTN_TOUCH, 1);
-- if (cpu_has_9x5_adc())
-- input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
-- input_sync(input_dev);
-- } else
-- ts_dev->bufferedmeasure = 1;
--
-- /* Now make new measurement */
-+ /* make new measurement */
- if (cpu_has_9x5_adc()) {
-- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
-- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
-+ unsigned int xscale, yscale;
-+
-+ /* calculate position */
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR);
-+ ts_dev->prev_absx = (reg & ATMEL_TSADCC_XPOS) << 10;
-+ xscale = (reg & ATMEL_TSADCC_XSCALE) >> 16;
-+ ts_dev->prev_absx /= xscale ? xscale: 1;
-+
-+ reg = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR);
-+ ts_dev->prev_absy = (reg & ATMEL_TSADCC_YPOS) << 10;
-+ yscale = (reg & ATMEL_TSADCC_YSCALE) >> 16;
-+ ts_dev->prev_absy /= yscale ? yscale: 1 << 10;
-
- /* calculate the pressure */
- reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
-@@ -157,6 +150,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
- ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
- }
-+
-+ /* report measurement to input layer */
-+ if (ts_dev->prev_absz < ZTHRESHOLD) {
-+ dev_dbg(&input_dev->dev,
-+ "x = %d, y = %d, pressure = %d\n",
-+ ts_dev->prev_absx, ts_dev->prev_absy,
-+ ts_dev->prev_absz);
-+ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
-+ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
-+ if (cpu_has_9x5_adc())
-+ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
-+ input_report_key(input_dev, BTN_TOUCH, 1);
-+ input_sync(input_dev);
-+ } else {
-+ dev_dbg(&input_dev->dev,
-+ "pressure too low: not reporting\n");
-+ }
- }
-
- return IRQ_HANDLED;
-@@ -233,7 +243,6 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- }
-
- ts_dev->input = input_dev;
-- ts_dev->bufferedmeasure = 0;
-
- snprintf(ts_dev->phys, sizeof(ts_dev->phys),
- "%s/input0", dev_name(&pdev->dev));
-@@ -275,10 +284,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
-
- if (cpu_has_9x5_adc()) {
-- reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
-- ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
-+ reg = ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* no Sleep Mode */
-+ ((0x00 << 6) & ATMEL_TSADCC_FWUP) | /* no Fast Wake Up needed */
- (prsc << 8) |
-- ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
-+ ((0x4 << 16) & ATMEL_TSADCC_STARTUP) |
- ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
- } else {
- reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
-@@ -296,10 +305,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- if (cpu_has_9x5_adc()) {
- atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
- ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
-- (pdata->filtering_average << 4) | /* Touchscreen average */
-+ ((pdata->filtering_average << 4) & ATMEL_TSADCC_TSAV) | /* Touchscreen average */
- ATMEL_TSADCC_NOTSDMA |
- ATMEL_TSADCC_PENDET_ENA |
-- (pdata->pendet_debounce << 28) |
-+ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC) |
- (0x3 << 8)); /* Touchscreen freq */
- } else {
- atmel_tsadcc_write(ATMEL_TSADCC_TSR,
-@@ -312,7 +321,8 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- * option only available on ES2 and higher
- */
- if (cpu_has_9x5_adc()) {
-- atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
-+ if (pdata->pendet_sensitivity <= ATMEL_TSADCC_PENDET_SENSITIVITY)
-+ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
- }
-
- atmel_tsadcc_read(ATMEL_TSADCC_SR);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 76cbb89fa9ac0f8a422bdd44f6deb0dd3566c960 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@wwwdotorg.org>
+Date: Fri, 23 Mar 2012 10:29:46 -0600
+Subject: pinctrl: core device tree mapping table parsing support
+
+commit 57291ce295c0aca738dd284c4a9c591c09ebee71 upstream.
+
+During pinctrl_get(), if the client device has a device tree node, look
+for the common pinctrl properties there. If found, parse the referenced
+device tree nodes, with the help of the pinctrl drivers, and generate
+mapping table entries from them.
+
+During pinctrl_put(), free any results of device tree parsing.
+
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Makefile | 1 +
+ drivers/pinctrl/core.c | 72 +++++++++---
+ drivers/pinctrl/core.h | 11 +-
+ drivers/pinctrl/devicetree.c | 249 ++++++++++++++++++++++++++++++++++++++++
+ drivers/pinctrl/devicetree.h | 35 ++++++
+ include/linux/pinctrl/pinctrl.h | 7 ++
+ 6 files changed, 357 insertions(+), 18 deletions(-)
+ create mode 100644 drivers/pinctrl/devicetree.c
+ create mode 100644 drivers/pinctrl/devicetree.h
+
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 6d4150b..049c9fb 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
+ obj-$(CONFIG_PINCTRL) += core.o
+ obj-$(CONFIG_PINMUX) += pinmux.o
+ obj-$(CONFIG_PINCONF) += pinconf.o
++obj-$(CONFIG_OF) += devicetree.o
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index df6296c..832f71d 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -26,6 +26,7 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/pinctrl/machine.h>
+ #include "core.h"
++#include "devicetree.h"
+ #include "pinmux.h"
+ #include "pinconf.h"
+
+@@ -45,7 +46,7 @@ struct pinctrl_maps {
+ DEFINE_MUTEX(pinctrl_mutex);
+
+ /* Global list of pin control devices (struct pinctrl_dev) */
+-static LIST_HEAD(pinctrldev_list);
++LIST_HEAD(pinctrldev_list);
+
+ /* List of pin controller handles (struct pinctrl) */
+ static LIST_HEAD(pinctrl_list);
+@@ -579,6 +580,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
+ }
+ p->dev = dev;
+ INIT_LIST_HEAD(&p->states);
++ INIT_LIST_HEAD(&p->dt_maps);
++
++ ret = pinctrl_dt_to_map(p);
++ if (ret < 0) {
++ kfree(p);
++ return ERR_PTR(ret);
++ }
+
+ devname = dev_name(dev);
+
+@@ -662,6 +670,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
+ kfree(state);
+ }
+
++ pinctrl_dt_free_maps(p);
++
+ if (inlist)
+ list_del(&p->node);
+ kfree(p);
+@@ -787,15 +797,8 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_select_state);
+
+-/**
+- * pinctrl_register_mappings() - register a set of pin controller mappings
+- * @maps: the pincontrol mappings table to register. This should probably be
+- * marked with __initdata so it can be discarded after boot. This
+- * function will perform a shallow copy for the mapping entries.
+- * @num_maps: the number of maps in the mapping table
+- */
+-int pinctrl_register_mappings(struct pinctrl_map const *maps,
+- unsigned num_maps)
++int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
++ bool dup, bool locked)
+ {
+ int i, ret;
+ struct pinctrl_maps *maps_node;
+@@ -851,20 +854,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
+ }
+
+ maps_node->num_maps = num_maps;
+- maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
+- if (!maps_node->maps) {
+- pr_err("failed to duplicate mapping table\n");
+- kfree(maps_node);
+- return -ENOMEM;
++ if (dup) {
++ maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
++ GFP_KERNEL);
++ if (!maps_node->maps) {
++ pr_err("failed to duplicate mapping table\n");
++ kfree(maps_node);
++ return -ENOMEM;
++ }
++ } else {
++ maps_node->maps = maps;
+ }
+
+- mutex_lock(&pinctrl_mutex);
++ if (!locked)
++ mutex_lock(&pinctrl_mutex);
+ list_add_tail(&maps_node->node, &pinctrl_maps);
+- mutex_unlock(&pinctrl_mutex);
++ if (!locked)
++ mutex_unlock(&pinctrl_mutex);
+
+ return 0;
+ }
+
++/**
++ * pinctrl_register_mappings() - register a set of pin controller mappings
++ * @maps: the pincontrol mappings table to register. This should probably be
++ * marked with __initdata so it can be discarded after boot. This
++ * function will perform a shallow copy for the mapping entries.
++ * @num_maps: the number of maps in the mapping table
++ */
++int pinctrl_register_mappings(struct pinctrl_map const *maps,
++ unsigned num_maps)
++{
++ return pinctrl_register_map(maps, num_maps, true, false);
++}
++
++void pinctrl_unregister_map(struct pinctrl_map const *map)
++{
++ struct pinctrl_maps *maps_node;
++
++ list_for_each_entry(maps_node, &pinctrl_maps, node) {
++ if (maps_node->maps == map) {
++ list_del(&maps_node->node);
++ return;
++ }
++ }
++}
++
+ #ifdef CONFIG_DEBUG_FS
+
+ static int pinctrl_pins_show(struct seq_file *s, void *what)
+@@ -1231,6 +1266,9 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
+ !ops->get_group_pins)
+ return -EINVAL;
+
++ if (ops->dt_node_to_map && !ops->dt_free_map)
++ return -EINVAL;
++
+ return 0;
+ }
+
+diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
+index 17ecf65..98ae808 100644
+--- a/drivers/pinctrl/core.h
++++ b/drivers/pinctrl/core.h
+@@ -52,12 +52,15 @@ struct pinctrl_dev {
+ * @dev: the device using this pin control handle
+ * @states: a list of states for this device
+ * @state: the current state
++ * @dt_maps: the mapping table chunks dynamically parsed from device tree for
++ * this device, if any
+ */
+ struct pinctrl {
+ struct list_head node;
+ struct device *dev;
+ struct list_head states;
+ struct pinctrl_state *state;
++ struct list_head dt_maps;
+ };
+
+ /**
+@@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
+ * struct pinctrl_setting - an individual mux or config setting
+ * @node: list node for struct pinctrl_settings's @settings field
+ * @type: the type of setting
+- * @pctldev: pin control device handling to be programmed
++ * @pctldev: pin control device handling to be programmed. Not used for
++ * PIN_MAP_TYPE_DUMMY_STATE.
+ * @data: Data specific to the setting type
+ */
+ struct pinctrl_setting {
+@@ -153,4 +157,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
+ return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
+ }
+
++int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
++ bool dup, bool locked);
++void pinctrl_unregister_map(struct pinctrl_map const *map);
++
+ extern struct mutex pinctrl_mutex;
++extern struct list_head pinctrldev_list;
+diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
+new file mode 100644
+index 0000000..5ef2feb
+--- /dev/null
++++ b/drivers/pinctrl/devicetree.c
+@@ -0,0 +1,249 @@
++/*
++ * Device tree integration for the pin control subsystem
++ *
++ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <linux/device.h>
++#include <linux/of.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/slab.h>
++
++#include "core.h"
++#include "devicetree.h"
++
++/**
++ * struct pinctrl_dt_map - mapping table chunk parsed from device tree
++ * @node: list node for struct pinctrl's @dt_maps field
++ * @pctldev: the pin controller that allocated this struct, and will free it
++ * @maps: the mapping table entries
++ */
++struct pinctrl_dt_map {
++ struct list_head node;
++ struct pinctrl_dev *pctldev;
++ struct pinctrl_map *map;
++ unsigned num_maps;
++};
++
++static void dt_free_map(struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++ if (pctldev) {
++ struct pinctrl_ops *ops = pctldev->desc->pctlops;
++ ops->dt_free_map(pctldev, map, num_maps);
++ } else {
++ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
++ kfree(map);
++ }
++}
++
++void pinctrl_dt_free_maps(struct pinctrl *p)
++{
++ struct pinctrl_dt_map *dt_map, *n1;
++
++ list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
++ pinctrl_unregister_map(dt_map->map);
++ list_del(&dt_map->node);
++ dt_free_map(dt_map->pctldev, dt_map->map,
++ dt_map->num_maps);
++ kfree(dt_map);
++ }
++
++ of_node_put(p->dev->of_node);
++}
++
++static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
++ struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++ int i;
++ struct pinctrl_dt_map *dt_map;
++
++ /* Initialize common mapping table entry fields */
++ for (i = 0; i < num_maps; i++) {
++ map[i].dev_name = dev_name(p->dev);
++ map[i].name = statename;
++ if (pctldev)
++ map[i].ctrl_dev_name = dev_name(pctldev->dev);
++ }
++
++ /* Remember the converted mapping table entries */
++ dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
++ if (!dt_map) {
++ dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
++ dt_free_map(pctldev, map, num_maps);
++ return -ENOMEM;
++ }
++
++ dt_map->pctldev = pctldev;
++ dt_map->map = map;
++ dt_map->num_maps = num_maps;
++ list_add_tail(&dt_map->node, &p->dt_maps);
++
++ return pinctrl_register_map(map, num_maps, false, true);
++}
++
++static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
++{
++ struct pinctrl_dev *pctldev;
++
++ list_for_each_entry(pctldev, &pinctrldev_list, node)
++ if (pctldev->dev->of_node == np)
++ return pctldev;
++
++ return NULL;
++}
++
++static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
++ struct device_node *np_config)
++{
++ struct device_node *np_pctldev;
++ struct pinctrl_dev *pctldev;
++ struct pinctrl_ops *ops;
++ int ret;
++ struct pinctrl_map *map;
++ unsigned num_maps;
++
++ /* Find the pin controller containing np_config */
++ np_pctldev = of_node_get(np_config);
++ for (;;) {
++ np_pctldev = of_get_next_parent(np_pctldev);
++ if (!np_pctldev || of_node_is_root(np_pctldev)) {
++ dev_err(p->dev, "could not find pctldev for node %s\n",
++ np_config->full_name);
++ of_node_put(np_pctldev);
++ /* FIXME: This should trigger deferrered probe */
++ return -ENODEV;
++ }
++ pctldev = find_pinctrl_by_of_node(np_pctldev);
++ if (pctldev)
++ break;
++ }
++ of_node_put(np_pctldev);
++
++ /*
++ * Call pinctrl driver to parse device tree node, and
++ * generate mapping table entries
++ */
++ ops = pctldev->desc->pctlops;
++ if (!ops->dt_node_to_map) {
++ dev_err(p->dev, "pctldev %s doesn't support DT\n",
++ dev_name(pctldev->dev));
++ return -ENODEV;
++ }
++ ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
++ if (ret < 0)
++ return ret;
++
++ /* Stash the mapping table chunk away for later use */
++ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
++}
++
++static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
++{
++ struct pinctrl_map *map;
++
++ map = kzalloc(sizeof(*map), GFP_KERNEL);
++ if (!map) {
++ dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
++ return -ENOMEM;
++ }
++
++ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
++ map->type = PIN_MAP_TYPE_DUMMY_STATE;
++
++ return dt_remember_or_free_map(p, statename, NULL, map, 1);
++}
++
++int pinctrl_dt_to_map(struct pinctrl *p)
++{
++ struct device_node *np = p->dev->of_node;
++ int state, ret;
++ char *propname;
++ struct property *prop;
++ const char *statename;
++ const __be32 *list;
++ int size, config;
++ phandle phandle;
++ struct device_node *np_config;
++
++ /* CONFIG_OF enabled, p->dev not instantiated from DT */
++ if (!np) {
++ dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
++ return 0;
++ }
++
++ /* We may store pointers to property names within the node */
++ of_node_get(np);
++
++ /* For each defined state ID */
++ for (state = 0; ; state++) {
++ /* Retrieve the pinctrl-* property */
++ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
++ prop = of_find_property(np, propname, &size);
++ kfree(propname);
++ if (!prop)
++ break;
++ list = prop->value;
++ size /= sizeof(*list);
++
++ /* Determine whether pinctrl-names property names the state */
++ ret = of_property_read_string_index(np, "pinctrl-names",
++ state, &statename);
++ /*
++ * If not, statename is just the integer state ID. But rather
++ * than dynamically allocate it and have to free it later,
++ * just point part way into the property name for the string.
++ */
++ if (ret < 0) {
++ /* strlen("pinctrl-") == 8 */
++ statename = prop->name + 8;
++ }
++
++ /* For every referenced pin configuration node in it */
++ for (config = 0; config < size; config++) {
++ phandle = be32_to_cpup(list++);
++
++ /* Look up the pin configuration node */
++ np_config = of_find_node_by_phandle(phandle);
++ if (!np_config) {
++ dev_err(p->dev,
++ "prop %s index %i invalid phandle\n",
++ prop->name, config);
++ ret = -EINVAL;
++ goto err;
++ }
++
++ /* Parse the node */
++ ret = dt_to_map_one_config(p, statename, np_config);
++ of_node_put(np_config);
++ if (ret < 0)
++ goto err;
++ }
++
++ /* No entries in DT? Generate a dummy state table entry */
++ if (!size) {
++ ret = dt_remember_dummy_state(p, statename);
++ if (ret < 0)
++ goto err;
++ }
++ }
++
++ return 0;
++
++err:
++ pinctrl_dt_free_maps(p);
++ return ret;
++}
+diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
+new file mode 100644
+index 0000000..760bc49
+--- /dev/null
++++ b/drivers/pinctrl/devicetree.h
+@@ -0,0 +1,35 @@
++/*
++ * Internal interface to pinctrl device tree integration
++ *
++ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ * more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifdef CONFIG_OF
++
++void pinctrl_dt_free_maps(struct pinctrl *p);
++int pinctrl_dt_to_map(struct pinctrl *p);
++
++#else
++
++static inline int pinctrl_dt_to_map(struct pinctrl *p)
++{
++ return 0;
++}
++
++static inline void pinctrl_dt_free_maps(struct pinctrl *p)
++{
++}
++
++#endif
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index 4e9f078..aa92cde 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -21,9 +21,11 @@
+
+ struct device;
+ struct pinctrl_dev;
++struct pinctrl_map;
+ struct pinmux_ops;
+ struct pinconf_ops;
+ struct gpio_chip;
++struct device_node;
+
+ /**
+ * struct pinctrl_pin_desc - boards/machines provide information on their
+@@ -83,6 +85,11 @@ struct pinctrl_ops {
+ unsigned *num_pins);
+ void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset);
++ int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
++ struct device_node *np_config,
++ struct pinctrl_map **map, unsigned *num_maps);
++ void (*dt_free_map) (struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps);
+ };
+
+ /**
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 6fa3817bddf46d9e1fc43a6a217826ec84ededa4 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Thu, 7 Jun 2012 14:19:11 +0800
-Subject: input: at91: add tsadcc_data for 9x5
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- arch/arm/mach-at91/include/mach/board.h | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
-index 369afc2..726e5f3 100644
---- a/arch/arm/mach-at91/include/mach/board.h
-+++ b/arch/arm/mach-at91/include/mach/board.h
-@@ -175,7 +175,9 @@ extern void __init at91_add_device_isi(struct isi_platform_data *data,
- /* Touchscreen Controller */
- struct at91_tsadcc_data {
- unsigned int adc_clock;
-+ u8 filtering_average;
- u8 pendet_debounce;
-+ u8 pendet_sensitivity;
- u8 ts_sample_hold_time;
- };
- extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From e159086ce1559954a5f30e4b42feab3934459208 Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Tue, 3 Apr 2012 21:53:56 -0600
+Subject: pinctrl: fix build when CONFIG_OF && !CONFIG_PINCTRL
+
+commit eafeb7a44aa8f79c992b9d557ede740c739f4b25 upstream.
+
+pinctrl/devicetree.c won't compile when !CONFIG_PINCTRL, since the
+pinctrl headers don't declare some types when !PINCTRL. Make sure
+pinctrl/Makefile only attempts to compile devicetree.c when OF &&
+PINCTRL.
+
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Makefile | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 049c9fb..8e3c95a 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -5,7 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
+ obj-$(CONFIG_PINCTRL) += core.o
+ obj-$(CONFIG_PINMUX) += pinmux.o
+ obj-$(CONFIG_PINCONF) += pinconf.o
+-obj-$(CONFIG_OF) += devicetree.o
++ifeq ($(CONFIG_OF),y)
++obj-$(CONFIG_PINCTRL) += devicetree.o
++endif
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 9dec1a67c24abf90346706d2fb3172c14d0fbcdf Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Wed, 13 Jun 2012 17:28:40 +0800
-Subject: input: at91: add dt support for atmel touch screen adc controller.
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- drivers/input/touchscreen/atmel_tsadcc.c | 86 ++++++++++++++++++++++++++++++--
- 1 file changed, 82 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
-index 397d17a..021f87e 100644
---- a/drivers/input/touchscreen/atmel_tsadcc.c
-+++ b/drivers/input/touchscreen/atmel_tsadcc.c
-@@ -40,6 +40,8 @@ struct atmel_tsadcc {
- unsigned int prev_absx;
- unsigned int prev_absy;
- unsigned int prev_absz;
-+
-+ struct at91_tsadcc_data board;
- };
-
- static void __iomem *tsc_base;
-@@ -62,7 +64,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- {
- struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
- struct input_dev *input_dev = ts_dev->input;
-- struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data;
-+ struct at91_tsadcc_data *pdata = &ts_dev->board;
-
- unsigned int status;
- unsigned int reg;
-@@ -172,6 +174,63 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
- return IRQ_HANDLED;
- }
-
-+#if defined(CONFIG_OF)
-+static int __devinit atmel_of_init_tsadcc(struct device_node *np,
-+ struct at91_tsadcc_data *pdata,
-+ struct platform_device *pdev)
-+{
-+ u32 val;
-+
-+ if (of_property_read_u32(np, "atmel,tsadcc_clock", &val) == 0)
-+ pdata->adc_clock = val;
-+
-+ if (of_property_read_u32(np, "atmel,filtering_average", &val) == 0) {
-+ if (val > 0x03) {
-+ dev_err(&pdev->dev, "invalid touch average setting, 0x%02x\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ pdata->filtering_average = (u8)val;
-+ }
-+
-+ if (of_property_read_u32(np, "atmel,pendet_debounce", &val) == 0) {
-+ if (val > 0x0f) {
-+ dev_err(&pdev->dev, "invalid pen detect debounce, 0x%02x\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ pdata->pendet_debounce = (u8)val;
-+ }
-+
-+ if (of_property_read_u32(np, "atmel,pendet_sensitivity", &val) == 0) {
-+ if (val > 0x03) {
-+ dev_err(&pdev->dev, "invalid pen detective sensitivity setting, 0x%02x\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ pdata->pendet_sensitivity = (u8)val;
-+ }
-+
-+ if (of_property_read_u32(np, "atmel,ts_sample_hold_time", &val) == 0) {
-+ if (val > 0x0f) {
-+ dev_err(&pdev->dev, "invalid ts sample hold time, 0x%02x\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ pdata->ts_sample_hold_time = (u8)val;
-+ }
-+
-+ return 0;
-+}
-+#else
-+static int __devinit atmel_of_init_tsadcc(struct device_node *np,
-+ struct at91_tsadcc_data *pdata,
-+ struct platform_device *pdev)
-+{
-+ return -EINVAL;
-+}
-+#endif
-+
- /*
- * The functions for inserting/removing us as a module.
- */
-@@ -181,7 +240,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- struct atmel_tsadcc *ts_dev;
- struct input_dev *input_dev;
- struct resource *res;
-- struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
-+ struct at91_tsadcc_data *pdata;
- int err = 0;
- unsigned int prsc;
- unsigned int reg;
-@@ -199,6 +258,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- return -ENOMEM;
- }
- platform_set_drvdata(pdev, ts_dev);
-+ pdata = &ts_dev->board;
-
- input_dev = input_allocate_device();
- if (!input_dev) {
-@@ -264,8 +324,16 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
- prsc = clk_get_rate(ts_dev->clk);
- dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
-
-- if (!pdata)
-- goto err_fail;
-+ if (pdev->dev.of_node) {
-+ err = atmel_of_init_tsadcc(pdev->dev.of_node, pdata, pdev);
-+ if (err)
-+ goto err_fail;
-+ } else {
-+ if (!pdev->dev.platform_data)
-+ goto err_fail;
-+ else
-+ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
-+ }
-
- if (!pdata->adc_clock)
- pdata->adc_clock = ADC_DEFAULT_CLOCK;
-@@ -374,11 +442,21 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
- return 0;
- }
-
-+#if defined(CONFIG_OF)
-+static const struct of_device_id atmel_tsaddcc_dt_ids[] = {
-+ { .compatible = "atmel,at91sam9x5-tsadcc"},
-+ { /* sentinel */ }
-+}
-+
-+MODULE_DEVICE_TABLE(of, atmel_tsaddcc_dt_ids);
-+#endif
-+
- static struct platform_driver atmel_tsadcc_driver = {
- .probe = atmel_tsadcc_probe,
- .remove = __devexit_p(atmel_tsadcc_remove),
- .driver = {
- .name = "atmel_tsadcc",
-+ .of_match_table = of_match_ptr(atmel_tsaddcc_dt_ids),
- },
- };
- module_platform_driver(atmel_tsadcc_driver);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 1a5a72c0a928388e178aca6290fd866b67b045d8 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 24 Apr 2012 15:20:02 +0200
+Subject: pinctrl: fix dangling comment
+
+commit dd5127010afa560b1cfde7e2cffeadabdd20885d upstream.
+
+This comment was referring to an older PINMUX define, it should
+be PINCTRL now.
+
+Reported-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ include/linux/pinctrl/machine.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
+index e4d1de7..9c4a198 100644
+--- a/include/linux/pinctrl/machine.h
++++ b/include/linux/pinctrl/machine.h
+@@ -163,5 +163,5 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+ return 0;
+ }
+
+-#endif /* !CONFIG_PINMUX */
++#endif /* !CONFIG_PINCTRL */
+ #endif
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5c2ed1407b5a897a7bd9c9ba0bb6dbc550c71d64 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 6 Sep 2012 14:55:37 +0200
-Subject: net/macb: Add support for Gigabit Ethernet mode
-
-Add Gigabit Ethernet mode to GEM cadence IP and enable RGMII connection.
-
-Signed-off-by: Patrice Vilchez <patrice.vilchez@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 15 ++++++++++++---
- drivers/net/ethernet/cadence/macb.h | 4 ++++
- 2 files changed, 16 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 6100b85..e9b909a 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -152,13 +152,17 @@ static void macb_handle_link_change(struct net_device *dev)
-
- reg = macb_readl(bp, NCFGR);
- reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
-+ if (macb_is_gem(bp))
-+ reg &= ~GEM_BIT(GBE);
-
- if (phydev->duplex)
- reg |= MACB_BIT(FD);
- if (phydev->speed == SPEED_100)
- reg |= MACB_BIT(SPD);
-+ if (phydev->speed == SPEED_1000)
-+ reg |= GEM_BIT(GBE);
-
-- macb_writel(bp, NCFGR, reg);
-+ macb_or_gem_writel(bp, NCFGR, reg);
-
- bp->speed = phydev->speed;
- bp->duplex = phydev->duplex;
-@@ -216,7 +220,10 @@ static int macb_mii_probe(struct net_device *dev)
- }
-
- /* mask with MAC supported features */
-- phydev->supported &= PHY_BASIC_FEATURES;
-+ if (macb_is_gem(bp))
-+ phydev->supported &= PHY_GBIT_FEATURES;
-+ else
-+ phydev->supported &= PHY_BASIC_FEATURES;
-
- phydev->advertising = phydev->supported;
-
-@@ -1383,7 +1390,9 @@ static int __init macb_probe(struct platform_device *pdev)
- bp->phy_interface = err;
- }
-
-- if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
-+ if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII)
-+ macb_or_gem_writel(bp, USRIO, GEM_BIT(RGMII));
-+ else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
- #if defined(CONFIG_ARCH_AT91)
- macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) |
- MACB_BIT(CLKEN)));
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index 335e288..f69ceef 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -145,6 +145,8 @@
- #define MACB_IRXFCS_SIZE 1
-
- /* GEM specific NCFGR bitfields. */
-+#define GEM_GBE_OFFSET 10
-+#define GEM_GBE_SIZE 1
- #define GEM_CLK_OFFSET 18
- #define GEM_CLK_SIZE 3
- #define GEM_DBW_OFFSET 21
-@@ -246,6 +248,8 @@
- /* Bitfields in USRIO (AT91) */
- #define MACB_RMII_OFFSET 0
- #define MACB_RMII_SIZE 1
-+#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
-+#define GEM_RGMII_SIZE 1
- #define MACB_CLKEN_OFFSET 1
- #define MACB_CLKEN_SIZE 1
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6697baae87bbd04741c77c498d560a16edceb42a Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Mon, 16 Apr 2012 10:51:00 -0600
+Subject: pinctrl: implement devm_pinctrl_get()/put()
+
+commit 6d4ca1fb467932773da7b808c52f3d7ef4461ba0 upstream.
+
+These functions allow the driver core to automatically clean up any
+allocations made by drivers, thus leading to simplified drivers.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/driver-model/devres.txt | 4 +++
+ Documentation/pinctrl.txt | 48 ++++++++++++++++++------------
+ drivers/pinctrl/core.c | 56 +++++++++++++++++++++++++++++++++++
+ include/linux/pinctrl/consumer.h | 44 +++++++++++++++++++++++++++
+ 4 files changed, 133 insertions(+), 19 deletions(-)
+
+diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
+index 2a596a4..ef4fa7b 100644
+--- a/Documentation/driver-model/devres.txt
++++ b/Documentation/driver-model/devres.txt
+@@ -276,3 +276,7 @@ REGULATOR
+ devm_regulator_get()
+ devm_regulator_put()
+ devm_regulator_bulk_get()
++
++PINCTRL
++ devm_pinctrl_get()
++ devm_pinctrl_put()
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index d97bccf..fa829f1 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -952,13 +952,13 @@ case), we define a mapping like this:
+ The result of grabbing this mapping from the device with something like
+ this (see next paragraph):
+
+- p = pinctrl_get(dev);
++ p = devm_pinctrl_get(dev);
+ s = pinctrl_lookup_state(p, "8bit");
+ ret = pinctrl_select_state(p, s);
+
+ or more simply:
+
+- p = pinctrl_get_select(dev, "8bit");
++ p = devm_pinctrl_get_select(dev, "8bit");
+
+ Will be that you activate all the three bottom records in the mapping at
+ once. Since they share the same name, pin controller device, function and
+@@ -992,7 +992,7 @@ foo_probe()
+ /* Allocate a state holder named "foo" etc */
+ struct foo_state *foo = ...;
+
+- foo->p = pinctrl_get(&device);
++ foo->p = devm_pinctrl_get(&device);
+ if (IS_ERR(foo->p)) {
+ /* FIXME: clean up "foo" here */
+ return PTR_ERR(foo->p);
+@@ -1000,24 +1000,17 @@ foo_probe()
+
+ foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(foo->s)) {
+- pinctrl_put(foo->p);
+ /* FIXME: clean up "foo" here */
+ return PTR_ERR(s);
+ }
+
+ ret = pinctrl_select_state(foo->s);
+ if (ret < 0) {
+- pinctrl_put(foo->p);
+ /* FIXME: clean up "foo" here */
+ return ret;
+ }
+ }
+
+-foo_remove()
+-{
+- pinctrl_put(state->p);
+-}
+-
+ This get/lookup/select/put sequence can just as well be handled by bus drivers
+ if you don't want each and every driver to handle it and you know the
+ arrangement on your bus.
+@@ -1029,6 +1022,11 @@ The semantics of the pinctrl APIs are:
+ kernel memory to hold the pinmux state. All mapping table parsing or similar
+ slow operations take place within this API.
+
++- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put()
++ to be called automatically on the retrieved pointer when the associated
++ device is removed. It is recommended to use this function over plain
++ pinctrl_get().
++
+ - pinctrl_lookup_state() is called in process context to obtain a handle to a
+ specific state for a the client device. This operation may be slow too.
+
+@@ -1041,14 +1039,25 @@ The semantics of the pinctrl APIs are:
+
+ - pinctrl_put() frees all information associated with a pinctrl handle.
+
++- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to
++ explicitly destroy a pinctrl object returned by devm_pinctrl_get().
++ However, use of this function will be rare, due to the automatic cleanup
++ that will occur even without calling it.
++
++ pinctrl_get() must be paired with a plain pinctrl_put().
++ pinctrl_get() may not be paired with devm_pinctrl_put().
++ devm_pinctrl_get() can optionally be paired with devm_pinctrl_put().
++ devm_pinctrl_get() may not be paired with plain pinctrl_put().
++
+ Usually the pin control core handled the get/put pair and call out to the
+ device drivers bookkeeping operations, like checking available functions and
+ the associated pins, whereas the enable/disable pass on to the pin controller
+ driver which takes care of activating and/or deactivating the mux setting by
+ quickly poking some registers.
+
+-The pins are allocated for your device when you issue the pinctrl_get() call,
+-after this you should be able to see this in the debugfs listing of all pins.
++The pins are allocated for your device when you issue the devm_pinctrl_get()
++call, after this you should be able to see this in the debugfs listing of all
++pins.
+
+
+ System pin control hogging
+@@ -1094,13 +1103,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
+
+ #include <linux/pinctrl/consumer.h>
+
+-foo_switch()
+-{
+- struct pinctrl *p;
+- struct pinctrl_state *s1, *s2;
++struct pinctrl *p;
++struct pinctrl_state *s1, *s2;
+
++foo_probe()
++{
+ /* Setup */
+- p = pinctrl_get(&device);
++ p = devm_pinctrl_get(&device);
+ if (IS_ERR(p))
+ ...
+
+@@ -1111,7 +1120,10 @@ foo_switch()
+ s2 = pinctrl_lookup_state(foo->p, "pos-B");
+ if (IS_ERR(s2))
+ ...
++}
+
++foo_switch()
++{
+ /* Enable on position A */
+ ret = pinctrl_select_state(s1);
+ if (ret < 0)
+@@ -1125,8 +1137,6 @@ foo_switch()
+ ...
+
+ ...
+-
+- pinctrl_put(p);
+ }
+
+ The above has to be done from process context.
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 832f71d..f4544f4 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -23,6 +23,7 @@
+ #include <linux/sysfs.h>
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
++#include <linux/pinctrl/consumer.h>
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/pinctrl/machine.h>
+ #include "core.h"
+@@ -797,6 +798,61 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_select_state);
+
++static void devm_pinctrl_release(struct device *dev, void *res)
++{
++ pinctrl_put(*(struct pinctrl **)res);
++}
++
++/**
++ * struct devm_pinctrl_get() - Resource managed pinctrl_get()
++ * @dev: the device to obtain the handle for
++ *
++ * If there is a need to explicitly destroy the returned struct pinctrl,
++ * devm_pinctrl_put() should be used, rather than plain pinctrl_put().
++ */
++struct pinctrl *devm_pinctrl_get(struct device *dev)
++{
++ struct pinctrl **ptr, *p;
++
++ ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return ERR_PTR(-ENOMEM);
++
++ p = pinctrl_get(dev);
++ if (!IS_ERR(p)) {
++ *ptr = p;
++ devres_add(dev, ptr);
++ } else {
++ devres_free(ptr);
++ }
++
++ return p;
++}
++EXPORT_SYMBOL_GPL(devm_pinctrl_get);
++
++static int devm_pinctrl_match(struct device *dev, void *res, void *data)
++{
++ struct pinctrl **p = res;
++
++ return *p == data;
++}
++
++/**
++ * devm_pinctrl_put() - Resource managed pinctrl_put()
++ * @p: the pinctrl handle to release
++ *
++ * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
++ * this function will not need to be called and the resource management
++ * code will ensure that the resource is freed.
++ */
++void devm_pinctrl_put(struct pinctrl *p)
++{
++ WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
++ devm_pinctrl_match, p));
++ pinctrl_put(p);
++}
++EXPORT_SYMBOL_GPL(devm_pinctrl_put);
++
+ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ bool dup, bool locked)
+ {
+diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
+index 191e726..6dd96fb 100644
+--- a/include/linux/pinctrl/consumer.h
++++ b/include/linux/pinctrl/consumer.h
+@@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
+ const char *name);
+ extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
+
++extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
++extern void devm_pinctrl_put(struct pinctrl *p);
++
+ #else /* !CONFIG_PINCTRL */
+
+ static inline int pinctrl_request_gpio(unsigned gpio)
+@@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
+ return 0;
+ }
+
++static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
++{
++ return NULL;
++}
++
++static inline void devm_pinctrl_put(struct pinctrl *p)
++{
++}
++
+ #endif /* CONFIG_PINCTRL */
+
+ static inline struct pinctrl * __must_check pinctrl_get_select(
+@@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default(
+ return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
+ }
+
++static inline struct pinctrl * __must_check devm_pinctrl_get_select(
++ struct device *dev, const char *name)
++{
++ struct pinctrl *p;
++ struct pinctrl_state *s;
++ int ret;
++
++ p = devm_pinctrl_get(dev);
++ if (IS_ERR(p))
++ return p;
++
++ s = pinctrl_lookup_state(p, name);
++ if (IS_ERR(s)) {
++ devm_pinctrl_put(p);
++ return ERR_PTR(PTR_ERR(s));
++ }
++
++ ret = pinctrl_select_state(p, s);
++ if (ret < 0) {
++ devm_pinctrl_put(p);
++ return ERR_PTR(ret);
++ }
++
++ return p;
++}
++
++static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
++ struct device *dev)
++{
++ return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
++}
++
+ #ifdef CONFIG_PINCONF
+
+ extern int pin_config_get(const char *dev_name, const char *name,
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From fe758f5a6775fb6b71fdf086c07e5247cafd53f3 Mon Sep 17 00:00:00 2001
-From: Havard Skinnemoen <havard@skinnemoen.net>
-Date: Fri, 28 May 2010 17:13:33 +0200
-Subject: net/macb: memory barriers cleanup
-
-Remove a couple of unneeded barriers and document the remaining ones.
-
-Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
-[nicolas.ferre@atmel.com: split patch in topics]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 18 ++++++++++++++----
- 1 file changed, 14 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index e9b909a..a4dcd11 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -372,7 +372,9 @@ static void macb_tx(struct macb *bp)
-
- BUG_ON(skb == NULL);
-
-+ /* Make hw descriptor updates visible to CPU */
- rmb();
-+
- bufstat = bp->tx_ring[tail].ctrl;
-
- if (!(bufstat & MACB_BIT(TX_USED)))
-@@ -415,7 +417,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- if (frag == last_frag)
- break;
- }
-+
-+ /* Make descriptor updates visible to hardware */
- wmb();
-+
- return 1;
- }
-
-@@ -436,12 +441,14 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- frag_len);
- offset += RX_BUFFER_SIZE;
- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
-- wmb();
-
- if (frag == last_frag)
- break;
- }
-
-+ /* Make descriptor updates visible to hardware */
-+ wmb();
-+
- skb->protocol = eth_type_trans(skb, bp->dev);
-
- bp->stats.rx_packets++;
-@@ -461,6 +468,8 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
-
- for (frag = begin; frag != end; frag = NEXT_RX(frag))
- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
-+
-+ /* Make descriptor updates visible to hardware */
- wmb();
-
- /*
-@@ -479,7 +488,9 @@ static int macb_rx(struct macb *bp, int budget)
- for (; budget > 0; tail = NEXT_RX(tail)) {
- u32 addr, ctrl;
-
-+ /* Make hw descriptor updates visible to CPU */
- rmb();
-+
- addr = bp->rx_ring[tail].addr;
- ctrl = bp->rx_ring[tail].ctrl;
-
-@@ -674,6 +685,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
-
- bp->tx_ring[entry].addr = mapping;
- bp->tx_ring[entry].ctrl = ctrl;
-+
-+ /* Make newly initialized descriptor visible to hardware */
- wmb();
-
- entry = NEXT_TX(entry);
-@@ -782,9 +795,6 @@ static void macb_init_rings(struct macb *bp)
-
- static void macb_reset_hw(struct macb *bp)
- {
-- /* Make sure we have the write buffer for ourselves */
-- wmb();
--
- /*
- * Disable RX and TX (XXX: Should we halt the transmission
- * more gracefully?)
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 1329721ec7c0898aea3607ac6c02fb8d68b42fea Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Thu, 26 Apr 2012 16:15:50 +0800
+Subject: pinctrl: add pinctrl_provide_dummies interface for platforms to use
+
+commit 5b3aa5f7c6287b1a0698950a91e94546888e553b upstream.
+
+Add a interface pinctrl_provide_dummies for platform to indicate
+whether it needs use pinctrl dummy state.
+
+ChangeLog v3->v4:
+* remove dummy gpio support in pinctrl subsystem.
+ Let gpio driver decide whether it wants to use pinctrl gpio mux
+ function.
+ChangeLog v2->v3:
+* Also changed the missed pinctrl gpio APIs in v1.
+ChangeLog v1->v2:
+* Based on sascha's suggestion, drop using kconfig since it will hide
+ pinctrl errors on all other boards.
+ See: https://lkml.org/lkml/2012/4/18/282
+ It seemed both Linus and Stephen agreed with this way, so i'm ok
+ with it too.
+* Add dummy gpio support.
+ pinctrl gpio in the same situation as state.
+* Patch name changed.
+ Original is pinctrl: handle dummy state in core.
+* Split removing old dt dummy interface into a separate patch
+
+Cc: Linus Walleij <linus.walleij@linaro.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 29 +++++++++++++++++++++++++++--
+ include/linux/pinctrl/machine.h | 5 ++++-
+ 2 files changed, 31 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index f4544f4..2b6363c5 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -43,6 +43,8 @@ struct pinctrl_maps {
+ unsigned num_maps;
+ };
+
++static bool pinctrl_dummy_state;
++
+ /* Mutex taken by all entry points */
+ DEFINE_MUTEX(pinctrl_mutex);
+
+@@ -61,6 +63,19 @@ static LIST_HEAD(pinctrl_maps);
+ _i_ < _maps_node_->num_maps; \
+ i++, _map_ = &_maps_node_->maps[_i_])
+
++/**
++ * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
++ *
++ * Usually this function is called by platforms without pinctrl driver support
++ * but run with some shared drivers using pinctrl APIs.
++ * After calling this function, the pinctrl core will return successfully
++ * with creating a dummy state for the driver to keep going smoothly.
++ */
++void pinctrl_provide_dummies(void)
++{
++ pinctrl_dummy_state = true;
++}
++
+ const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
+ {
+ /* We're not allowed to register devices without name */
+@@ -696,8 +711,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
+ struct pinctrl_state *state;
+
+ state = find_state(p, name);
+- if (!state)
+- return ERR_PTR(-ENODEV);
++ if (!state) {
++ if (pinctrl_dummy_state) {
++ /* create dummy state */
++ dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
++ name);
++ state = create_state(p, name);
++ if (IS_ERR(state))
++ return state;
++ } else {
++ return ERR_PTR(-ENODEV);
++ }
++ }
+
+ return state;
+ }
+diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
+index 9c4a198..7d22ab0 100644
+--- a/include/linux/pinctrl/machine.h
++++ b/include/linux/pinctrl/machine.h
+@@ -154,7 +154,7 @@ struct pinctrl_map {
+
+ extern int pinctrl_register_mappings(struct pinctrl_map const *map,
+ unsigned num_maps);
+-
++extern void pinctrl_provide_dummies(void);
+ #else
+
+ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+@@ -163,5 +163,8 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
+ return 0;
+ }
+
++static inline void pinctrl_provide_dummies(void)
++{
++}
+ #endif /* !CONFIG_PINCTRL */
+ #endif
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 7dd52f7f7728c264880ed982dcc5cebeb2ee76c0 Mon Sep 17 00:00:00 2001
-From: Havard Skinnemoen <havard@skinnemoen.net>
-Date: Fri, 28 May 2010 17:45:43 +0200
-Subject: net/macb: change debugging messages
-
-Convert some noisy netdev_dbg() statements to netdev_vdbg(). Defining
-DEBUG will no longer fill up the logs; VERBOSE_DEBUG still does.
-Add one more verbose debug for ISR status.
-
-Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
-[nicolas.ferre@atmel.com: split patch in topics, add ISR status]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 22 ++++++++++++----------
- 1 file changed, 12 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index a4dcd11..ce1f558 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
- status = macb_readl(bp, TSR);
- macb_writel(bp, TSR, status);
-
-- netdev_dbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
-+ netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
-
- if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
- int i;
-@@ -380,7 +380,7 @@ static void macb_tx(struct macb *bp)
- if (!(bufstat & MACB_BIT(TX_USED)))
- break;
-
-- netdev_dbg(bp->dev, "skb %u (data %p) TX complete\n",
-+ netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
- tail, skb->data);
- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
- DMA_TO_DEVICE);
-@@ -406,7 +406,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
-
- len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
-
-- netdev_dbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
-+ netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
- first_frag, last_frag, len);
-
- skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
-@@ -453,7 +453,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
-
- bp->stats.rx_packets++;
- bp->stats.rx_bytes += len;
-- netdev_dbg(bp->dev, "received skb of length %u, csum: %08x\n",
-+ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
- skb->len, skb->csum);
- netif_receive_skb(skb);
-
-@@ -535,7 +535,7 @@ static int macb_poll(struct napi_struct *napi, int budget)
-
- work_done = 0;
-
-- netdev_dbg(bp->dev, "poll: status = %08lx, budget = %d\n",
-+ netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
- (unsigned long)status, budget);
-
- work_done = macb_rx(bp, budget);
-@@ -574,6 +574,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
- break;
- }
-
-+ netdev_vdbg(bp->dev, "isr = 0x%08lx\n", (unsigned long)status);
-+
- if (status & MACB_RX_INT_FLAGS) {
- /*
- * There's no point taking any more interrupts
-@@ -585,7 +587,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
- macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
-
- if (napi_schedule_prep(&bp->napi)) {
-- netdev_dbg(bp->dev, "scheduling RX softirq\n");
-+ netdev_vdbg(bp->dev, "scheduling RX softirq\n");
- __napi_schedule(&bp->napi);
- }
- }
-@@ -647,8 +649,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- u32 ctrl;
- unsigned long flags;
-
--#ifdef DEBUG
-- netdev_dbg(bp->dev,
-+#if defined(DEBUG) && defined(VERBOSE_DEBUG)
-+ netdev_vdbg(bp->dev,
- "start_xmit: len %u head %p data %p tail %p end %p\n",
- skb->len, skb->head, skb->data,
- skb_tail_pointer(skb), skb_end_pointer(skb));
-@@ -670,12 +672,12 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- }
-
- entry = bp->tx_head;
-- netdev_dbg(bp->dev, "Allocated ring entry %u\n", entry);
-+ netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
- mapping = dma_map_single(&bp->pdev->dev, skb->data,
- len, DMA_TO_DEVICE);
- bp->tx_skb[entry].skb = skb;
- bp->tx_skb[entry].mapping = mapping;
-- netdev_dbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
-+ netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
- skb->data, (unsigned long)mapping);
-
- ctrl = MACB_BF(TX_FRMLEN, len);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 87d3596781005abbbadb4b5acc43c0820f80a112 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 23 May 2012 21:22:40 +0800
+Subject: pinctrl: remove pinctrl_remove_gpio_range
+
+commit 5d589b092ab212bbcc27828167e1c036e7fc77d2 upstream.
+
+The gpio ranges will be automatically removed when the pinctrl
+driver is unregistered.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 19 +++++--------------
+ drivers/pinctrl/pinctrl-tegra.c | 1 -
+ drivers/pinctrl/pinctrl-u300.c | 2 --
+ include/linux/pinctrl/pinctrl.h | 2 --
+ 4 files changed, 5 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 2b6363c5..7b3fc93 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -313,20 +313,6 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
+
+ /**
+- * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+- * @pctldev: pin controller device to remove the range from
+- * @range: the GPIO range to remove
+- */
+-void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+- struct pinctrl_gpio_range *range)
+-{
+- mutex_lock(&pinctrl_mutex);
+- list_del(&range->node);
+- mutex_unlock(&pinctrl_mutex);
+-}
+-EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+-
+-/**
+ * pinctrl_get_group_selector() - returns the group selector for a group
+ * @pctldev: the pin controller handling the group
+ * @pin_group: the pin group to look up
+@@ -1456,6 +1442,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
+ */
+ void pinctrl_unregister(struct pinctrl_dev *pctldev)
+ {
++ struct pinctrl_gpio_range *range, *n;
+ if (pctldev == NULL)
+ return;
+
+@@ -1471,6 +1458,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
+ /* Destroy descriptor tree */
+ pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
+ pctldev->desc->npins);
++ /* remove gpio ranges map */
++ list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
++ list_del(&range->node);
++
+ kfree(pctldev);
+
+ mutex_unlock(&pinctrl_mutex);
+diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
+index 9b32968..0b3c02f 100644
+--- a/drivers/pinctrl/pinctrl-tegra.c
++++ b/drivers/pinctrl/pinctrl-tegra.c
+@@ -525,7 +525,6 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+ {
+ struct tegra_pmx *pmx = platform_get_drvdata(pdev);
+
+- pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
+ pinctrl_unregister(pmx->pctl);
+
+ return 0;
+diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
+index 26eb8cc..9ff6207 100644
+--- a/drivers/pinctrl/pinctrl-u300.c
++++ b/drivers/pinctrl/pinctrl-u300.c
+@@ -1185,8 +1185,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
+ struct u300_pmx *upmx = platform_get_drvdata(pdev);
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
+- pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
+ pinctrl_unregister(upmx->pctl);
+ iounmap(upmx->virtbase);
+ release_mem_region(upmx->phybase, upmx->physize);
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index aa92cde..6e30132 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -124,8 +124,6 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+ extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
+ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
+-extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+- struct pinctrl_gpio_range *range);
+ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+ extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+ #else
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 93c3f8300d6da2e5a670ac681548509d4aa3b020 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 6 Sep 2012 15:23:47 +0200
-Subject: net/macb: remove macb_get_drvinfo()
-
-This function has little meaning so remove it altogether and
-let ethtool core fill in the fields automatically.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 11 -----------
- 1 file changed, 11 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index ce1f558..dc34ff1 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -1223,20 +1223,9 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
- return phy_ethtool_sset(phydev, cmd);
- }
-
--static void macb_get_drvinfo(struct net_device *dev,
-- struct ethtool_drvinfo *info)
--{
-- struct macb *bp = netdev_priv(dev);
--
-- strcpy(info->driver, bp->pdev->dev.driver->name);
-- strcpy(info->version, "$Revision: 1.14 $");
-- strcpy(info->bus_info, dev_name(&bp->pdev->dev));
--}
--
- static const struct ethtool_ops macb_ethtool_ops = {
- .get_settings = macb_get_settings,
- .set_settings = macb_set_settings,
-- .get_drvinfo = macb_get_drvinfo,
- .get_link = ethtool_op_get_link,
- };
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From a41052a3f24aebed6c1adb152bba379c729693e0 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 23 May 2012 21:22:41 +0800
+Subject: pinctrl: add pinctrl_add_gpio_ranges function
+
+commit 3e5e00b654997aa2c3998d30f7213b9611eb23d7 upstream.
+
+Often GPIO ranges are added in batch, so create a special
+function for that.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 11 +++++++++++
+ include/linux/pinctrl/pinctrl.h | 3 +++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 7b3fc93..fa8a440 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -312,6 +312,17 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
+
++void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *ranges,
++ unsigned nranges)
++{
++ int i;
++
++ for (i = 0; i < nranges; i++)
++ pinctrl_add_gpio_range(pctldev, &ranges[i]);
++}
++EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
++
+ /**
+ * pinctrl_get_group_selector() - returns the group selector for a group
+ * @pctldev: the pin controller handling the group
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index 6e30132..e162710 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -124,6 +124,9 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
+ extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
+ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
++extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *ranges,
++ unsigned nranges);
+ extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
+ extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
+ #else
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 69eb5ddf7b65fe255a87b7613360c17fc8db2bbc Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 3 Sep 2012 17:52:09 +0200
-Subject: net/macb: tx status is more than 8 bits now
-
-On some revision of GEM, TSR status register has more information.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index dc34ff1..4e05a29 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
- status = macb_readl(bp, TSR);
- macb_writel(bp, TSR, status);
-
-- netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
-+ netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
-
- if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
- int i;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 0de7501c1c0b0fa626a51fecb9af7487e128c1fe Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Wed, 25 Apr 2012 19:38:13 +0800
+Subject: pinctrl: support gpio request deferred probing
+
+commit 4650b7cbea4db73f459181f67f939b510e3a17b2 upstream.
+
+As pinctrl handles, it may be possible the pinctrl gpio ranges
+are still not got registered when user call pinctrl_gpio_request.
+Thus, add defer support for it too.
+
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index fa8a440..c9c74dc 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -272,7 +272,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
+ *
+ * Find the pin controller handling a certain GPIO pin from the pinspace of
+ * the GPIO subsystem, return the device and the matching GPIO range. Returns
+- * negative if the GPIO range could not be found in any device.
++ * -EPROBE_DEFER if the GPIO range could not be found in any device since it
++ * may still have not been registered.
+ */
+ static int pinctrl_get_device_gpio_range(unsigned gpio,
+ struct pinctrl_dev **outdev,
+@@ -292,7 +293,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
+ }
+ }
+
+- return -EINVAL;
++ return -EPROBE_DEFER;
+ }
+
+ /**
+@@ -374,7 +375,7 @@ int pinctrl_request_gpio(unsigned gpio)
+ ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
+ if (ret) {
+ mutex_unlock(&pinctrl_mutex);
+- return -EINVAL;
++ return ret;
+ }
+
+ /* Convert to the pin controllers number space */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5c7c8fe88a651f0e3313e644a952d40f83ce8dee Mon Sep 17 00:00:00 2001
-From: Havard Skinnemoen <havard@skinnemoen.net>
-Date: Mon, 21 Jun 2010 18:56:29 +0200
-Subject: net/macb: clean up ring buffer logic
-
-Instead of masking head and tail every time we increment them, just let them
-wrap through UINT_MAX and mask them when subscripting. Add simple accessor
-functions to do the subscripting properly to minimize the chances of messing
-this up.
-
-This makes the code slightly smaller, and hopefully faster as well. Also,
-doing the ring buffer management this way will simplify things a lot when
-making the ring sizes configurable in the future.
-
-Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
-[nicolas.ferre@atmel.com: split patch in topics, adapt to newer kernel]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 168 +++++++++++++++++++++++-------------
- drivers/net/ethernet/cadence/macb.h | 22 +++--
- 2 files changed, 122 insertions(+), 68 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 4e05a29..2554354 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -31,24 +31,13 @@
-
- #define RX_BUFFER_SIZE 128
- #define RX_RING_SIZE 512
--#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
-+#define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
-
- /* Make the IP header word-aligned (the ethernet header is 14 bytes) */
- #define RX_OFFSET 2
-
- #define TX_RING_SIZE 128
--#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1)
--#define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE)
--
--#define TX_RING_GAP(bp) \
-- (TX_RING_SIZE - (bp)->tx_pending)
--#define TX_BUFFS_AVAIL(bp) \
-- (((bp)->tx_tail <= (bp)->tx_head) ? \
-- (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \
-- (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp))
--#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1))
--
--#define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1))
-+#define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
-
- /* minimum number of free TX descriptors before waking up TX process */
- #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4)
-@@ -56,6 +45,51 @@
- #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
- | MACB_BIT(ISR_ROVR))
-
-+/* Ring buffer accessors */
-+static unsigned int macb_tx_ring_wrap(unsigned int index)
-+{
-+ return index & (TX_RING_SIZE - 1);
-+}
-+
-+static unsigned int macb_tx_ring_avail(struct macb *bp)
-+{
-+ return TX_RING_SIZE - (bp->tx_head - bp->tx_tail);
-+}
-+
-+static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index)
-+{
-+ return &bp->tx_ring[macb_tx_ring_wrap(index)];
-+}
-+
-+static struct macb_tx_skb *macb_tx_skb(struct macb *bp, unsigned int index)
-+{
-+ return &bp->tx_skb[macb_tx_ring_wrap(index)];
-+}
-+
-+static dma_addr_t macb_tx_dma(struct macb *bp, unsigned int index)
-+{
-+ dma_addr_t offset;
-+
-+ offset = macb_tx_ring_wrap(index) * sizeof(struct macb_dma_desc);
-+
-+ return bp->tx_ring_dma + offset;
-+}
-+
-+static unsigned int macb_rx_ring_wrap(unsigned int index)
-+{
-+ return index & (RX_RING_SIZE - 1);
-+}
-+
-+static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
-+{
-+ return &bp->rx_ring[macb_rx_ring_wrap(index)];
-+}
-+
-+static void *macb_rx_buffer(struct macb *bp, unsigned int index)
-+{
-+ return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
-+}
-+
- static void __macb_set_hwaddr(struct macb *bp)
- {
- u32 bottom;
-@@ -335,17 +369,18 @@ static void macb_tx(struct macb *bp)
- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
-
- /* free transmit buffer in upper layer*/
-- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
-- struct ring_info *rp = &bp->tx_skb[tail];
-- struct sk_buff *skb = rp->skb;
--
-- BUG_ON(skb == NULL);
-+ for (tail = bp->tx_tail; tail != head; tail++) {
-+ struct macb_tx_skb *tx_skb;
-+ struct sk_buff *skb;
-
- rmb();
-
-- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
-- DMA_TO_DEVICE);
-- rp->skb = NULL;
-+ tx_skb = macb_tx_skb(bp, tail);
-+ skb = tx_skb->skb;
-+
-+ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
-+ skb->len, DMA_TO_DEVICE);
-+ tx_skb->skb = NULL;
- dev_kfree_skb_irq(skb);
- }
-
-@@ -365,34 +400,38 @@ static void macb_tx(struct macb *bp)
- return;
-
- head = bp->tx_head;
-- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
-- struct ring_info *rp = &bp->tx_skb[tail];
-- struct sk_buff *skb = rp->skb;
-- u32 bufstat;
-+ for (tail = bp->tx_tail; tail != head; tail++) {
-+ struct macb_tx_skb *tx_skb;
-+ struct sk_buff *skb;
-+ struct macb_dma_desc *desc;
-+ u32 ctrl;
-
-- BUG_ON(skb == NULL);
-+ desc = macb_tx_desc(bp, tail);
-
- /* Make hw descriptor updates visible to CPU */
- rmb();
-
-- bufstat = bp->tx_ring[tail].ctrl;
-+ ctrl = desc->ctrl;
-
-- if (!(bufstat & MACB_BIT(TX_USED)))
-+ if (!(ctrl & MACB_BIT(TX_USED)))
- break;
-
-+ tx_skb = macb_tx_skb(bp, tail);
-+ skb = tx_skb->skb;
-+
- netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
-- tail, skb->data);
-- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
-+ macb_tx_ring_wrap(tail), skb->data);
-+ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
- DMA_TO_DEVICE);
- bp->stats.tx_packets++;
- bp->stats.tx_bytes += skb->len;
-- rp->skb = NULL;
-+ tx_skb->skb = NULL;
- dev_kfree_skb_irq(skb);
- }
-
- bp->tx_tail = tail;
-- if (netif_queue_stopped(bp->dev) &&
-- TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH)
-+ if (netif_queue_stopped(bp->dev)
-+ && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH)
- netif_wake_queue(bp->dev);
- }
-
-@@ -403,17 +442,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- unsigned int frag;
- unsigned int offset = 0;
- struct sk_buff *skb;
-+ struct macb_dma_desc *desc;
-
-- len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
-+ desc = macb_rx_desc(bp, last_frag);
-+ len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
-
- netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
-- first_frag, last_frag, len);
-+ macb_rx_ring_wrap(first_frag),
-+ macb_rx_ring_wrap(last_frag), len);
-
- skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
- if (!skb) {
- bp->stats.rx_dropped++;
-- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
-- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
-+ for (frag = first_frag; ; frag++) {
-+ desc = macb_rx_desc(bp, frag);
-+ desc->addr &= ~MACB_BIT(RX_USED);
- if (frag == last_frag)
- break;
- }
-@@ -428,7 +471,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- skb_checksum_none_assert(skb);
- skb_put(skb, len);
-
-- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
-+ for (frag = first_frag; ; frag++) {
- unsigned int frag_len = RX_BUFFER_SIZE;
-
- if (offset + frag_len > len) {
-@@ -436,11 +479,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- frag_len = len - offset;
- }
- skb_copy_to_linear_data_offset(skb, offset,
-- (bp->rx_buffers +
-- (RX_BUFFER_SIZE * frag)),
-- frag_len);
-+ macb_rx_buffer(bp, frag), frag_len);
- offset += RX_BUFFER_SIZE;
-- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
-+ desc = macb_rx_desc(bp, frag);
-+ desc->addr &= ~MACB_BIT(RX_USED);
-
- if (frag == last_frag)
- break;
-@@ -466,8 +508,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
- {
- unsigned int frag;
-
-- for (frag = begin; frag != end; frag = NEXT_RX(frag))
-- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
-+ for (frag = begin; frag != end; frag++) {
-+ struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
-+ desc->addr &= ~MACB_BIT(RX_USED);
-+ }
-
- /* Make descriptor updates visible to hardware */
- wmb();
-@@ -482,17 +526,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
- static int macb_rx(struct macb *bp, int budget)
- {
- int received = 0;
-- unsigned int tail = bp->rx_tail;
-+ unsigned int tail;
- int first_frag = -1;
-
-- for (; budget > 0; tail = NEXT_RX(tail)) {
-+ for (tail = bp->rx_tail; budget > 0; tail++) {
-+ struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
- u32 addr, ctrl;
-
- /* Make hw descriptor updates visible to CPU */
- rmb();
-
-- addr = bp->rx_ring[tail].addr;
-- ctrl = bp->rx_ring[tail].ctrl;
-+ addr = desc->addr;
-+ ctrl = desc->ctrl;
-
- if (!(addr & MACB_BIT(RX_USED)))
- break;
-@@ -646,6 +691,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- struct macb *bp = netdev_priv(dev);
- dma_addr_t mapping;
- unsigned int len, entry;
-+ struct macb_dma_desc *desc;
-+ struct macb_tx_skb *tx_skb;
- u32 ctrl;
- unsigned long flags;
-
-@@ -662,7 +709,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- spin_lock_irqsave(&bp->lock, flags);
-
- /* This is a hard error, log it. */
-- if (TX_BUFFS_AVAIL(bp) < 1) {
-+ if (macb_tx_ring_avail(bp) < 1) {
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&bp->lock, flags);
- netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
-@@ -671,12 +718,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- return NETDEV_TX_BUSY;
- }
-
-- entry = bp->tx_head;
-+ entry = macb_tx_ring_wrap(bp->tx_head);
-+ bp->tx_head++;
- netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
- mapping = dma_map_single(&bp->pdev->dev, skb->data,
- len, DMA_TO_DEVICE);
-- bp->tx_skb[entry].skb = skb;
-- bp->tx_skb[entry].mapping = mapping;
-+
-+ tx_skb = &bp->tx_skb[entry];
-+ tx_skb->skb = skb;
-+ tx_skb->mapping = mapping;
- netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
- skb->data, (unsigned long)mapping);
-
-@@ -685,20 +735,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- if (entry == (TX_RING_SIZE - 1))
- ctrl |= MACB_BIT(TX_WRAP);
-
-- bp->tx_ring[entry].addr = mapping;
-- bp->tx_ring[entry].ctrl = ctrl;
-+ desc = &bp->tx_ring[entry];
-+ desc->addr = mapping;
-+ desc->ctrl = ctrl;
-
- /* Make newly initialized descriptor visible to hardware */
- wmb();
-
-- entry = NEXT_TX(entry);
-- bp->tx_head = entry;
--
- skb_tx_timestamp(skb);
-
- macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
-
-- if (TX_BUFFS_AVAIL(bp) < 1)
-+ if (macb_tx_ring_avail(bp) < 1)
- netif_stop_queue(dev);
-
- spin_unlock_irqrestore(&bp->lock, flags);
-@@ -734,7 +782,7 @@ static int macb_alloc_consistent(struct macb *bp)
- {
- int size;
-
-- size = TX_RING_SIZE * sizeof(struct ring_info);
-+ size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
- bp->tx_skb = kmalloc(size, GFP_KERNEL);
- if (!bp->tx_skb)
- goto out_err;
-@@ -1407,8 +1455,6 @@ static int __init macb_probe(struct platform_device *pdev)
- macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
- #endif
-
-- bp->tx_pending = DEF_TX_RING_PENDING;
--
- err = register_netdev(dev);
- if (err) {
- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index f69ceef..8a4ee2f 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -356,7 +356,12 @@
- __v; \
- })
-
--struct dma_desc {
-+/**
-+ * struct macb_dma_desc - Hardware DMA descriptor
-+ * @addr: DMA address of data buffer
-+ * @ctrl: Control and status bits
-+ */
-+struct macb_dma_desc {
- u32 addr;
- u32 ctrl;
- };
-@@ -421,7 +426,12 @@ struct dma_desc {
- #define MACB_TX_USED_OFFSET 31
- #define MACB_TX_USED_SIZE 1
-
--struct ring_info {
-+/**
-+ * struct macb_tx_skb - data about an skb which is being transmitted
-+ * @skb: skb currently being transmitted
-+ * @mapping: DMA address of the skb's data buffer
-+ */
-+struct macb_tx_skb {
- struct sk_buff *skb;
- dma_addr_t mapping;
- };
-@@ -506,12 +516,12 @@ struct macb {
- void __iomem *regs;
-
- unsigned int rx_tail;
-- struct dma_desc *rx_ring;
-+ struct macb_dma_desc *rx_ring;
- void *rx_buffers;
-
- unsigned int tx_head, tx_tail;
-- struct dma_desc *tx_ring;
-- struct ring_info *tx_skb;
-+ struct macb_dma_desc *tx_ring;
-+ struct macb_tx_skb *tx_skb;
-
- spinlock_t lock;
- struct platform_device *pdev;
-@@ -529,8 +539,6 @@ struct macb {
- dma_addr_t tx_ring_dma;
- dma_addr_t rx_buffers_dma;
-
-- unsigned int rx_pending, tx_pending;
--
- struct mii_bus *mii_bus;
- struct phy_device *phy_dev;
- unsigned int link;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From e9c7b63720ebd0869e642f4aae9f4ff1a53c349c Mon Sep 17 00:00:00 2001
+From: Stephen Warren <swarren@nvidia.com>
+Date: Wed, 25 Apr 2012 10:32:16 -0600
+Subject: pinctrl: propagate map validation errors
+
+commit fde04f419a230fb7f7dc018a9deca6f5d431831e upstream.
+
+pinctrl_register_map() was returning early if pinmux_validate_map() or
+pinconf_validate_map() failed, but was not actually returning the error
+code.
+
+Signed-off-by: Stephen Warren <swarren@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index c9c74dc..6ae3a33 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -911,13 +911,13 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
+ case PIN_MAP_TYPE_MUX_GROUP:
+ ret = pinmux_validate_map(&maps[i], i);
+ if (ret < 0)
+- return 0;
++ return ret;
+ break;
+ case PIN_MAP_TYPE_CONFIGS_PIN:
+ case PIN_MAP_TYPE_CONFIGS_GROUP:
+ ret = pinconf_validate_map(&maps[i], i);
+ if (ret < 0)
+- return 0;
++ return ret;
+ break;
+ default:
+ pr_err("failed to register map %s (%d): invalid type given\n",
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 07007d3c709662f4cc5e186cb8dd0596e8b0d769 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 3 Sep 2012 17:56:18 +0200
-Subject: net/macb: ethtool interface: add register dump feature
-
-Add macb_get_regs() ethtool function and its helper function:
-macb_get_regs_len().
-The version field is deduced from the IP revision which gives the
-"MACB or GEM" information. An additional version field is reserved.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
----
- drivers/net/ethernet/cadence/macb.c | 40 +++++++++++++++++++++++++++++++++++++
- drivers/net/ethernet/cadence/macb.h | 3 +++
- 2 files changed, 43 insertions(+)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 2554354..6486a56 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -1271,9 +1271,49 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
- return phy_ethtool_sset(phydev, cmd);
- }
-
-+static int macb_get_regs_len(struct net_device *netdev)
-+{
-+ return MACB_GREGS_NBR * sizeof(u32);
-+}
-+
-+static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
-+ void *p)
-+{
-+ struct macb *bp = netdev_priv(dev);
-+ unsigned int tail, head;
-+ u32 *regs_buff = p;
-+
-+ regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1))
-+ | MACB_GREGS_VERSION;
-+
-+ tail = macb_tx_ring_wrap(bp->tx_tail);
-+ head = macb_tx_ring_wrap(bp->tx_head);
-+
-+ regs_buff[0] = macb_readl(bp, NCR);
-+ regs_buff[1] = macb_or_gem_readl(bp, NCFGR);
-+ regs_buff[2] = macb_readl(bp, NSR);
-+ regs_buff[3] = macb_readl(bp, TSR);
-+ regs_buff[4] = macb_readl(bp, RBQP);
-+ regs_buff[5] = macb_readl(bp, TBQP);
-+ regs_buff[6] = macb_readl(bp, RSR);
-+ regs_buff[7] = macb_readl(bp, IMR);
-+
-+ regs_buff[8] = tail;
-+ regs_buff[9] = head;
-+ regs_buff[10] = macb_tx_dma(bp, tail);
-+ regs_buff[11] = macb_tx_dma(bp, head);
-+
-+ if (macb_is_gem(bp)) {
-+ regs_buff[12] = gem_readl(bp, USRIO);
-+ regs_buff[13] = gem_readl(bp, DMACFG);
-+ }
-+}
-+
- static const struct ethtool_ops macb_ethtool_ops = {
- .get_settings = macb_get_settings,
- .set_settings = macb_set_settings,
-+ .get_regs_len = macb_get_regs_len,
-+ .get_regs = macb_get_regs,
- .get_link = ethtool_op_get_link,
- };
-
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index 8a4ee2f..5be5900 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -10,6 +10,9 @@
- #ifndef _MACB_H
- #define _MACB_H
-
-+#define MACB_GREGS_NBR 16
-+#define MACB_GREGS_VERSION 1
-+
- /* MACB register offsets */
- #define MACB_NCR 0x0000
- #define MACB_NCFGR 0x0004
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 7b9faf9925d33fe49a04ccad79dbb7ca08a8cc67 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Thu, 12 Apr 2012 19:48:42 +0200
+Subject: pinctrl: mark non-EXPERIMENTAL
+
+commit 630e2d0494f001cc3c435cac374f92e4bde0f518 upstream.
+
+With the finalization of the external driver API and the device
+tree support, this subsystem is now mature and can be promoted to
+non-experimental status.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/Kconfig | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
+index abfb964..f73a5ea 100644
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -4,7 +4,6 @@
+
+ config PINCTRL
+ bool
+- depends on EXPERIMENTAL
+
+ if PINCTRL
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 950c22b78992b706fd8f446efbabb695e2fa2ac1 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 22 Jun 2010 18:38:26 +0200
-Subject: net/macb: better manage tx errors
-
-Handle all TX errors, not only underruns. TX error management is
-deferred to a dedicated workqueue.
-Reinitialize the TX ring after treating all remaining frames, and
-restart the controller when everything has been cleaned up properly.
-Napi is not stopped during this task as the driver only handles
-napi for RX for now.
-With this sequence, we do not need a special check during the xmit
-method as the packets will be caught by TX disable during workqueue
-execution.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 166 ++++++++++++++++++++++++------------
- drivers/net/ethernet/cadence/macb.h | 1 +
- 2 files changed, 113 insertions(+), 54 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 6486a56..cd24ce6 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -44,6 +44,16 @@
-
- #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
- | MACB_BIT(ISR_ROVR))
-+#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \
-+ | MACB_BIT(ISR_RLE) \
-+ | MACB_BIT(TXERR))
-+#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP))
-+
-+/*
-+ * Graceful stop timeouts in us. We should allow up to
-+ * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
-+ */
-+#define MACB_HALT_TIMEOUT 1230
-
- /* Ring buffer accessors */
- static unsigned int macb_tx_ring_wrap(unsigned int index)
-@@ -338,66 +348,113 @@ static void macb_update_stats(struct macb *bp)
- *p += __raw_readl(reg);
- }
-
--static void macb_tx(struct macb *bp)
-+static int macb_halt_tx(struct macb *bp)
- {
-- unsigned int tail;
-- unsigned int head;
-- u32 status;
-+ unsigned long halt_time, timeout;
-+ u32 status;
-
-- status = macb_readl(bp, TSR);
-- macb_writel(bp, TSR, status);
-+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));
-
-- netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
-+ timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT);
-+ do {
-+ halt_time = jiffies;
-+ status = macb_readl(bp, TSR);
-+ if (!(status & MACB_BIT(TGO)))
-+ return 0;
-
-- if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
-- int i;
-- netdev_err(bp->dev, "TX %s, resetting buffers\n",
-- status & MACB_BIT(UND) ?
-- "underrun" : "retry limit exceeded");
-+ usleep_range(10, 250);
-+ } while (time_before(halt_time, timeout));
-
-- /* Transfer ongoing, disable transmitter, to avoid confusion */
-- if (status & MACB_BIT(TGO))
-- macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE));
-+ return -ETIMEDOUT;
-+}
-
-- head = bp->tx_head;
-+static void macb_tx_error_task(struct work_struct *work)
-+{
-+ struct macb *bp = container_of(work, struct macb, tx_error_task);
-+ struct macb_tx_skb *tx_skb;
-+ struct sk_buff *skb;
-+ unsigned int tail;
-
-- /*Mark all the buffer as used to avoid sending a lost buffer*/
-- for (i = 0; i < TX_RING_SIZE; i++)
-- bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
-+ netdev_vdbg(bp->dev, "macb_tx_error_task: t = %u, h = %u\n",
-+ bp->tx_tail, bp->tx_head);
-
-- /* Add wrap bit */
-- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
-+ /* Make sure nobody is trying to queue up new packets */
-+ netif_stop_queue(bp->dev);
-
-- /* free transmit buffer in upper layer*/
-- for (tail = bp->tx_tail; tail != head; tail++) {
-- struct macb_tx_skb *tx_skb;
-- struct sk_buff *skb;
-+ /*
-+ * Stop transmission now
-+ * (in case we have just queued new packets)
-+ */
-+ if (macb_halt_tx(bp))
-+ /* Just complain for now, reinitializing TX path can be good */
-+ netdev_err(bp->dev, "BUG: halt tx timed out\n");
-
-- rmb();
-+ /* No need for the lock here as nobody will interrupt us anymore */
-
-- tx_skb = macb_tx_skb(bp, tail);
-- skb = tx_skb->skb;
-+ /*
-+ * Treat frames in TX queue including the ones that caused the error.
-+ * Free transmit buffers in upper layer.
-+ */
-+ for (tail = bp->tx_tail; tail != bp->tx_head; tail++) {
-+ struct macb_dma_desc *desc;
-+ u32 ctrl;
-
-- dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
-- skb->len, DMA_TO_DEVICE);
-- tx_skb->skb = NULL;
-- dev_kfree_skb_irq(skb);
-- }
-+ desc = macb_tx_desc(bp, tail);
-+ ctrl = desc->ctrl;
-+ tx_skb = macb_tx_skb(bp, tail);
-+ skb = tx_skb->skb;
-
-- bp->tx_head = bp->tx_tail = 0;
-+ if (ctrl & MACB_BIT(TX_USED)) {
-+ netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
-+ macb_tx_ring_wrap(tail), skb->data);
-+ bp->stats.tx_packets++;
-+ bp->stats.tx_bytes += skb->len;
-+ } else {
-+ /*
-+ * "Buffers exhausted mid-frame" errors may only happen
-+ * if the driver is buggy, so complain loudly about those.
-+ * Statistics are updated by hardware.
-+ */
-+ if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
-+ netdev_err(bp->dev,
-+ "BUG: TX buffers exhausted mid-frame\n");
-
-- /* Enable the transmitter again */
-- if (status & MACB_BIT(TGO))
-- macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE));
-+ desc->ctrl = ctrl | MACB_BIT(TX_USED);
-+ }
-+
-+ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
-+ DMA_TO_DEVICE);
-+ tx_skb->skb = NULL;
-+ dev_kfree_skb(skb);
- }
-
-- if (!(status & MACB_BIT(COMP)))
-- /*
-- * This may happen when a buffer becomes complete
-- * between reading the ISR and scanning the
-- * descriptors. Nothing to worry about.
-- */
-- return;
-+ /* Make descriptor updates visible to hardware */
-+ wmb();
-+
-+ /* Reinitialize the TX desc queue */
-+ macb_writel(bp, TBQP, bp->tx_ring_dma);
-+ /* Make TX ring reflect state of hardware */
-+ bp->tx_head = bp->tx_tail = 0;
-+
-+ /* Now we are ready to start transmission again */
-+ netif_wake_queue(bp->dev);
-+
-+ /* Housework before enabling TX IRQ */
-+ macb_writel(bp, TSR, macb_readl(bp, TSR));
-+ macb_writel(bp, IER, MACB_TX_INT_FLAGS);
-+}
-+
-+static void macb_tx_interrupt(struct macb *bp)
-+{
-+ unsigned int tail;
-+ unsigned int head;
-+ u32 status;
-+
-+ status = macb_readl(bp, TSR);
-+ macb_writel(bp, TSR, status);
-+
-+ netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
-+ (unsigned long)status);
-
- head = bp->tx_head;
- for (tail = bp->tx_tail; tail != head; tail++) {
-@@ -637,9 +694,14 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
- }
- }
-
-- if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND) |
-- MACB_BIT(ISR_RLE)))
-- macb_tx(bp);
-+ if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
-+ macb_writel(bp, IDR, MACB_TX_INT_FLAGS);
-+ schedule_work(&bp->tx_error_task);
-+ break;
-+ }
-+
-+ if (status & MACB_BIT(TCOMP))
-+ macb_tx_interrupt(bp);
-
- /*
- * Link change detection isn't possible with RMII, so we'll
-@@ -969,13 +1031,8 @@ static void macb_init_hw(struct macb *bp)
- macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
-
- /* Enable interrupts */
-- macb_writel(bp, IER, (MACB_BIT(RCOMP)
-- | MACB_BIT(RXUBR)
-- | MACB_BIT(ISR_TUND)
-- | MACB_BIT(ISR_RLE)
-- | MACB_BIT(TXERR)
-- | MACB_BIT(TCOMP)
-- | MACB_BIT(ISR_ROVR)
-+ macb_writel(bp, IER, (MACB_RX_INT_FLAGS
-+ | MACB_TX_INT_FLAGS
- | MACB_BIT(HRESP)));
-
- }
-@@ -1423,6 +1480,7 @@ static int __init macb_probe(struct platform_device *pdev)
- bp->dev = dev;
-
- spin_lock_init(&bp->lock);
-+ INIT_WORK(&bp->tx_error_task, macb_tx_error_task);
-
- bp->pclk = clk_get(&pdev->dev, "pclk");
- if (IS_ERR(bp->pclk)) {
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index 5be5900..bfab8ef 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -532,6 +532,7 @@ struct macb {
- struct clk *hclk;
- struct net_device *dev;
- struct napi_struct napi;
-+ struct work_struct tx_error_task;
- struct net_device_stats stats;
- union {
- struct macb_stats macb;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From ca7138a65812dda79268a64d765335279d4f917c Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Tue, 10 Apr 2012 10:00:38 +0200
+Subject: pinctrl: implement pinctrl deferred probing
+
+commit c05127c4e2c6e7d9949347a76fd05c337bcd5e84 upstream.
+
+If drivers try to obtain pinctrl handles for a pin controller that
+has not yet registered to the subsystem, we need to be able to
+back out and retry with deferred probing. So let's return
+-EPROBE_DEFER whenever this location fails. Also downgrade the
+errors to info, maybe we will even set them to debug once the
+deferred probing is commonplace.
+
+Cc: Arnd Bergmann <arnd@arndb.de>
+Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/pinctrl.txt | 5 +++++
+ drivers/pinctrl/core.c | 9 ++++++---
+ drivers/pinctrl/devicetree.c | 6 +++---
+ 3 files changed, 14 insertions(+), 6 deletions(-)
+
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index fa829f1..b85f0bd 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -1059,6 +1059,11 @@ The pins are allocated for your device when you issue the devm_pinctrl_get()
+ call, after this you should be able to see this in the debugfs listing of all
+ pins.
+
++NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
++requested pinctrl handles, for example if the pinctrl driver has not yet
++registered. Thus make sure that the error path in your driver gracefully
++cleans up and is ready to retry the probing later in the startup process.
++
+
+ System pin control hogging
+ ==========================
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 6ae3a33..ff78028 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -531,11 +531,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
+
+ setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
+ if (setting->pctldev == NULL) {
+- dev_err(p->dev, "unknown pinctrl device %s in map entry",
++ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
+ map->ctrl_dev_name);
+ kfree(setting);
+- /* Eventually, this should trigger deferred probe */
+- return -ENODEV;
++ /*
++ * OK let us guess that the driver is not there yet, and
++ * let's defer obtaining this pinctrl handle to later...
++ */
++ return -EPROBE_DEFER;
+ }
+
+ switch (map->type) {
+diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
+index 5ef2feb..fcb1de4 100644
+--- a/drivers/pinctrl/devicetree.c
++++ b/drivers/pinctrl/devicetree.c
+@@ -121,11 +121,11 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
+ for (;;) {
+ np_pctldev = of_get_next_parent(np_pctldev);
+ if (!np_pctldev || of_node_is_root(np_pctldev)) {
+- dev_err(p->dev, "could not find pctldev for node %s\n",
++ dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
+ np_config->full_name);
+ of_node_put(np_pctldev);
+- /* FIXME: This should trigger deferrered probe */
+- return -ENODEV;
++ /* OK let's just assume this will appear later then */
++ return -EPROBE_DEFER;
+ }
+ pctldev = find_pinctrl_by_of_node(np_pctldev);
+ if (pctldev)
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ebff9d35a64e87d3a6c6d05421b7be4ceedbb589 Mon Sep 17 00:00:00 2001
-From: Havard Skinnemoen <havard@skinnemoen.net>
-Date: Tue, 24 Mar 2009 10:45:18 +0100
-Subject: net/macb: Offset first RX buffer by two bytes
-
-Make the ethernet frame payload word-aligned, possibly making the
-memcpy into the skb a bit faster. This will be even more important
-after we eliminate the copy altogether.
-
-Also eliminate the redundant RX_OFFSET constant -- it has the same
-definition and purpose as NET_IP_ALIGN.
-
-Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
-[nicolas.ferre@atmel.com: adapt to newer kernel]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 23 ++++++++++++++++-------
- 1 file changed, 16 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index cd24ce6..88a1d20 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -33,9 +33,6 @@
- #define RX_RING_SIZE 512
- #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
-
--/* Make the IP header word-aligned (the ethernet header is 14 bytes) */
--#define RX_OFFSET 2
--
- #define TX_RING_SIZE 128
- #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
-
-@@ -497,7 +494,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- {
- unsigned int len;
- unsigned int frag;
-- unsigned int offset = 0;
-+ unsigned int offset;
- struct sk_buff *skb;
- struct macb_dma_desc *desc;
-
-@@ -508,7 +505,16 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- macb_rx_ring_wrap(first_frag),
- macb_rx_ring_wrap(last_frag), len);
-
-- skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
-+ /*
-+ * The ethernet header starts NET_IP_ALIGN bytes into the
-+ * first buffer. Since the header is 14 bytes, this makes the
-+ * payload word-aligned.
-+ *
-+ * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy
-+ * the two padding bytes into the skb so that we avoid hitting
-+ * the slowpath in memcpy(), and pull them off afterwards.
-+ */
-+ skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN);
- if (!skb) {
- bp->stats.rx_dropped++;
- for (frag = first_frag; ; frag++) {
-@@ -524,7 +530,8 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- return 1;
- }
-
-- skb_reserve(skb, RX_OFFSET);
-+ offset = 0;
-+ len += NET_IP_ALIGN;
- skb_checksum_none_assert(skb);
- skb_put(skb, len);
-
-@@ -548,10 +555,11 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- /* Make descriptor updates visible to hardware */
- wmb();
-
-+ __skb_pull(skb, NET_IP_ALIGN);
- skb->protocol = eth_type_trans(skb, bp->dev);
-
- bp->stats.rx_packets++;
-- bp->stats.rx_bytes += len;
-+ bp->stats.rx_bytes += skb->len;
- netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
- skb->len, skb->csum);
- netif_receive_skb(skb);
-@@ -1011,6 +1019,7 @@ static void macb_init_hw(struct macb *bp)
- __macb_set_hwaddr(bp);
-
- config = macb_mdc_clk_div(bp);
-+ config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */
- config |= MACB_BIT(PAE); /* PAuse Enable */
- config |= MACB_BIT(DRFCS); /* Discard Rx FCS */
- config |= MACB_BIT(BIG); /* Receive oversized frames */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 9ef4d54b79f8a5da7112864968dcf12cb1bcedb4 Mon Sep 17 00:00:00 2001
+From: Viresh Kumar <viresh.kumar@st.com>
+Date: Fri, 30 Mar 2012 11:25:40 +0530
+Subject: pinctrl: replace list_*() with get_*_count()
+
+commit d1e90e9e7467dbfe521b25ba79f520bf676ebc36 upstream.
+
+Most of the SoC drivers implement list_groups() and list_functions()
+routines for pinctrl and pinmux. These routines continue returning
+zero until the selector argument is greater than total count of
+available groups or functions.
+
+This patch replaces these list_*() routines with get_*_count()
+routines, which returns the number of available selection for SoC
+driver. pinctrl layer will use this value to check the range it can
+choose.
+
+This patch fixes all user drivers for this change. There are other
+routines in user drivers, which have checks to check validity of
+selector passed to them. It is also no more required and hence
+removed.
+
+Documentation updated as well.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
+[Folded in fix and fixed a minor merge artifact manually]
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ Documentation/pinctrl.txt | 37 +++++++++++++++----------------------
+ drivers/pinctrl/core.c | 10 ++++++----
+ drivers/pinctrl/pinconf.c | 3 ++-
+ drivers/pinctrl/pinctrl-pxa3xx.c | 24 ++++++++++--------------
+ drivers/pinctrl/pinctrl-sirf.c | 20 ++++++--------------
+ drivers/pinctrl/pinctrl-tegra.c | 40 ++++++----------------------------------
+ drivers/pinctrl/pinctrl-u300.c | 20 ++++++--------------
+ drivers/pinctrl/pinmux.c | 11 +++++++----
+ include/linux/pinctrl/pinctrl.h | 6 ++----
+ include/linux/pinctrl/pinmux.h | 7 +++----
+ 10 files changed, 63 insertions(+), 115 deletions(-)
+
+diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
+index b85f0bd..f5add79 100644
+--- a/Documentation/pinctrl.txt
++++ b/Documentation/pinctrl.txt
+@@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = {
+ };
+
+
+-static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int foo_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_groups);
+ }
+
+ static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+@@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinctrl_ops foo_pctrl_ops = {
+- .list_groups = foo_list_groups,
++ .get_groups_count = foo_get_groups_count,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+ };
+@@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = {
+ .pctlops = &foo_pctrl_ops,
+ };
+
+-The pin control subsystem will call the .list_groups() function repeatedly
+-beginning on 0 until it returns non-zero to determine legal selectors, then
+-it will call the other functions to retrieve the name and pins of the group.
+-Maintaining the data structure of the groups is up to the driver, this is
+-just a simple example - in practice you may need more entries in your group
+-structure, for example specific register ranges associated with each group
+-and so on.
++The pin control subsystem will call the .get_groups_count() function to
++determine total number of legal selectors, then it will call the other functions
++to retrieve the name and pins of the group. Maintaining the data structure of
++the groups is up to the driver, this is just a simple example - in practice you
++may need more entries in your group structure, for example specific register
++ranges associated with each group and so on.
+
+
+ Pin configuration
+@@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = {
+ };
+
+
+-static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int foo_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_groups);
+ }
+
+ static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
+@@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinctrl_ops foo_pctrl_ops = {
+- .list_groups = foo_list_groups,
++ .get_groups_count = foo_get_groups_count,
+ .get_group_name = foo_get_group_name,
+ .get_group_pins = foo_get_group_pins,
+ };
+@@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = {
+ },
+ };
+
+-int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
++int foo_get_functions_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(foo_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(foo_functions);
+ }
+
+ const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
+@@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ struct pinmux_ops foo_pmxops = {
+- .list_functions = foo_list_funcs,
++ .get_functions_count = foo_get_functions_count,
+ .get_function_name = foo_get_fname,
+ .get_function_groups = foo_get_groups,
+ .enable = foo_enable,
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index ff78028..c70ae2d 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -333,9 +333,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
+ const char *pin_group)
+ {
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
++ unsigned ngroups = pctlops->get_groups_count(pctldev);
+ unsigned group_selector = 0;
+
+- while (pctlops->list_groups(pctldev, group_selector) >= 0) {
++ while (group_selector < ngroups) {
+ const char *gname = pctlops->get_group_name(pctldev,
+ group_selector);
+ if (!strcmp(gname, pin_group)) {
+@@ -1023,12 +1024,13 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ {
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+- unsigned selector = 0;
++ unsigned ngroups, selector = 0;
+
++ ngroups = ops->get_groups_count(pctldev);
+ mutex_lock(&pinctrl_mutex);
+
+ seq_puts(s, "registered pin groups:\n");
+- while (ops->list_groups(pctldev, selector) >= 0) {
++ while (selector < ngroups) {
+ const unsigned *pins;
+ unsigned num_pins;
+ const char *gname = ops->get_group_name(pctldev, selector);
+@@ -1343,7 +1345,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
+
+ if (!ops ||
+- !ops->list_groups ||
++ !ops->get_groups_count ||
+ !ops->get_group_name ||
+ !ops->get_group_pins)
+ return -EINVAL;
+diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
+index 7321e86..eb3a14f4 100644
+--- a/drivers/pinctrl/pinconf.c
++++ b/drivers/pinctrl/pinconf.c
+@@ -495,6 +495,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
+ const struct pinconf_ops *ops = pctldev->desc->confops;
++ unsigned ngroups = pctlops->get_groups_count(pctldev);
+ unsigned selector = 0;
+
+ if (!ops || !ops->pin_config_group_get)
+@@ -505,7 +506,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
+
+ mutex_lock(&pinctrl_mutex);
+
+- while (pctlops->list_groups(pctldev, selector) >= 0) {
++ while (selector < ngroups) {
+ const char *gname = pctlops->get_group_name(pctldev, selector);
+
+ seq_printf(s, "%u (%s):", selector, gname);
+diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
+index 079dce0..7644e42 100644
+--- a/drivers/pinctrl/pinctrl-pxa3xx.c
++++ b/drivers/pinctrl/pinctrl-pxa3xx.c
+@@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
+ .pin_base = 0,
+ };
+
+-static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
++static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return -EINVAL;
+- return 0;
++
++ return info->num_grps;
+ }
+
+ static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
+ unsigned selector)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return NULL;
++
+ return info->grps[selector].name;
+ }
+
+@@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
+ unsigned *num_pins)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (selector >= info->num_grps)
+- return -EINVAL;
++
+ *pins = info->grps[selector].pins;
+ *num_pins = info->grps[selector].npins;
+ return 0;
+ }
+
+ static struct pinctrl_ops pxa3xx_pctrl_ops = {
+- .list_groups = pxa3xx_list_groups,
++ .get_groups_count = pxa3xx_get_groups_count,
+ .get_group_name = pxa3xx_get_group_name,
+ .get_group_pins = pxa3xx_get_group_pins,
+ };
+
+-static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
++static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
+ {
+ struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+- if (func >= info->num_funcs)
+- return -EINVAL;
+- return 0;
++
++ return info->num_funcs;
+ }
+
+ static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
+@@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
+ }
+
+ static struct pinmux_ops pxa3xx_pmx_ops = {
+- .list_functions = pxa3xx_pmx_list_func,
++ .get_functions_count = pxa3xx_pmx_get_funcs_count,
+ .get_function_name = pxa3xx_pmx_get_func_name,
+ .get_function_groups = pxa3xx_pmx_get_groups,
+ .enable = pxa3xx_pmx_enable,
+diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
+index 6b3534c..ba15b1a 100644
+--- a/drivers/pinctrl/pinctrl-sirf.c
++++ b/drivers/pinctrl/pinctrl-sirf.c
+@@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
+ SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
+ };
+
+-static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(sirfsoc_pin_groups);
+ }
+
+ static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return NULL;
+ return sirfsoc_pin_groups[selector].name;
+ }
+
+@@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
+ const unsigned **pins,
+ unsigned *num_pins)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
+- return -EINVAL;
+ *pins = sirfsoc_pin_groups[selector].pins;
+ *num_pins = sirfsoc_pin_groups[selector].num_pins;
+ return 0;
+@@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
+ }
+
+ static struct pinctrl_ops sirfsoc_pctrl_ops = {
+- .list_groups = sirfsoc_list_groups,
++ .get_groups_count = sirfsoc_get_groups_count,
+ .get_group_name = sirfsoc_get_group_name,
+ .get_group_pins = sirfsoc_get_group_pins,
+ .pin_dbg_show = sirfsoc_pin_dbg_show,
+@@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
+ sirfsoc_pinmux_endisable(spmx, selector, false);
+ }
+
+-static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
++static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
+ {
+- if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(sirfsoc_pmx_functions);
+ }
+
+ static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+@@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
+ }
+
+ static struct pinmux_ops sirfsoc_pinmux_ops = {
+- .list_functions = sirfsoc_pinmux_list_funcs,
+ .enable = sirfsoc_pinmux_enable,
+ .disable = sirfsoc_pinmux_disable,
++ .get_functions_count = sirfsoc_pinmux_get_funcs_count,
+ .get_function_name = sirfsoc_pinmux_get_func_name,
+ .get_function_groups = sirfsoc_pinmux_get_groups,
+ .gpio_request_enable = sirfsoc_pinmux_request_gpio,
+diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
+index 0b3c02f..c4c47c5 100644
+--- a/drivers/pinctrl/pinctrl-tegra.c
++++ b/drivers/pinctrl/pinctrl-tegra.c
+@@ -53,15 +53,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
+ writel(val, pmx->regs[bank] + reg);
+ }
+
+-static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
+- unsigned group)
++static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+-
+- return 0;
++ return pmx->soc->ngroups;
+ }
+
+ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+@@ -69,9 +65,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return NULL;
+-
+ return pmx->soc->groups[group].name;
+ }
+
+@@ -82,9 +75,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+-
+ *pins = pmx->soc->groups[group].pins;
+ *num_pins = pmx->soc->groups[group].npins;
+
+@@ -99,21 +89,17 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ }
+
+ static struct pinctrl_ops tegra_pinctrl_ops = {
+- .list_groups = tegra_pinctrl_list_groups,
++ .get_groups_count = tegra_pinctrl_get_groups_count,
+ .get_group_name = tegra_pinctrl_get_group_name,
+ .get_group_pins = tegra_pinctrl_get_group_pins,
+ .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+ };
+
+-static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
+- unsigned function)
++static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return -EINVAL;
+-
+- return 0;
++ return pmx->soc->nfunctions;
+ }
+
+ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+@@ -121,9 +107,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return NULL;
+-
+ return pmx->soc->functions[function].name;
+ }
+
+@@ -134,9 +117,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ {
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+- if (function >= pmx->soc->nfunctions)
+- return -EINVAL;
+-
+ *groups = pmx->soc->functions[function].groups;
+ *num_groups = pmx->soc->functions[function].ngroups;
+
+@@ -151,8 +131,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+ int i;
+ u32 val;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ if (g->mux_reg < 0)
+@@ -180,8 +158,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
+ const struct tegra_pingroup *g;
+ u32 val;
+
+- if (group >= pmx->soc->ngroups)
+- return;
+ g = &pmx->soc->groups[group];
+
+ if (g->mux_reg < 0)
+@@ -194,7 +170,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
+ }
+
+ static struct pinmux_ops tegra_pinmux_ops = {
+- .list_functions = tegra_pinctrl_list_funcs,
++ .get_functions_count = tegra_pinctrl_get_funcs_count,
+ .get_function_name = tegra_pinctrl_get_func_name,
+ .get_function_groups = tegra_pinctrl_get_func_groups,
+ .enable = tegra_pinctrl_enable,
+@@ -324,8 +300,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
+ s16 reg;
+ u32 val, mask;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
+@@ -353,8 +327,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
+ s16 reg;
+ u32 val, mask;
+
+- if (group >= pmx->soc->ngroups)
+- return -EINVAL;
+ g = &pmx->soc->groups[group];
+
+ ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
+diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
+index 9ff6207..10de43c 100644
+--- a/drivers/pinctrl/pinctrl-u300.c
++++ b/drivers/pinctrl/pinctrl-u300.c
+@@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
+ },
+ };
+
+-static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
++static int u300_get_groups_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(u300_pin_groups);
+ }
+
+ static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return NULL;
+ return u300_pin_groups[selector].name;
+ }
+
+@@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+ {
+- if (selector >= ARRAY_SIZE(u300_pin_groups))
+- return -EINVAL;
+ *pins = u300_pin_groups[selector].pins;
+ *num_pins = u300_pin_groups[selector].num_pins;
+ return 0;
+@@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ }
+
+ static struct pinctrl_ops u300_pctrl_ops = {
+- .list_groups = u300_list_groups,
++ .get_groups_count = u300_get_groups_count,
+ .get_group_name = u300_get_group_name,
+ .get_group_pins = u300_get_group_pins,
+ .pin_dbg_show = u300_pin_dbg_show,
+@@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ u300_pmx_endisable(upmx, selector, false);
+ }
+
+-static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
++static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+ {
+- if (selector >= ARRAY_SIZE(u300_pmx_functions))
+- return -EINVAL;
+- return 0;
++ return ARRAY_SIZE(u300_pmx_functions);
+ }
+
+ static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
+@@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ }
+
+ static struct pinmux_ops u300_pmx_ops = {
+- .list_functions = u300_pmx_list_funcs,
++ .get_functions_count = u300_pmx_get_funcs_count,
+ .get_function_name = u300_pmx_get_func_name,
+ .get_function_groups = u300_pmx_get_groups,
+ .enable = u300_pmx_enable,
+diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
+index 4e62783..375b214 100644
+--- a/drivers/pinctrl/pinmux.c
++++ b/drivers/pinctrl/pinmux.c
+@@ -33,10 +33,11 @@
+ int pinmux_check_ops(struct pinctrl_dev *pctldev)
+ {
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
++ unsigned nfuncs = ops->get_functions_count(pctldev);
+ unsigned selector = 0;
+
+ /* Check that we implement required operations */
+- if (!ops->list_functions ||
++ if (!ops->get_functions_count ||
+ !ops->get_function_name ||
+ !ops->get_function_groups ||
+ !ops->enable ||
+@@ -44,7 +45,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev)
+ return -EINVAL;
+
+ /* Check that all functions registered have names */
+- while (ops->list_functions(pctldev, selector) >= 0) {
++ while (selector < nfuncs) {
+ const char *fname = ops->get_function_name(pctldev,
+ selector);
+ if (!fname) {
+@@ -287,10 +288,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
+ const char *function)
+ {
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
++ unsigned nfuncs = ops->get_functions_count(pctldev);
+ unsigned selector = 0;
+
+ /* See if this pctldev has this function */
+- while (ops->list_functions(pctldev, selector) >= 0) {
++ while (selector < nfuncs) {
+ const char *fname = ops->get_function_name(pctldev,
+ selector);
+
+@@ -477,11 +479,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
+ {
+ struct pinctrl_dev *pctldev = s->private;
+ const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
++ unsigned nfuncs = pmxops->get_functions_count(pctldev);
+ unsigned func_selector = 0;
+
+ mutex_lock(&pinctrl_mutex);
+
+- while (pmxops->list_functions(pctldev, func_selector) >= 0) {
++ while (func_selector < nfuncs) {
+ const char *func = pmxops->get_function_name(pctldev,
+ func_selector);
+ const char * const *groups;
+diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
+index e162710..ba08516 100644
+--- a/include/linux/pinctrl/pinctrl.h
++++ b/include/linux/pinctrl/pinctrl.h
+@@ -66,9 +66,7 @@ struct pinctrl_gpio_range {
+ /**
+ * struct pinctrl_ops - global pin control operations, to be implemented by
+ * pin controller drivers.
+- * @list_groups: list the number of selectable named groups available
+- * in this pinmux driver, the core will begin on 0 and call this
+- * repeatedly as long as it returns >= 0 to enumerate the groups
++ * @get_groups_count: Returns the count of total number of groups registered.
+ * @get_group_name: return the group name of the pin group
+ * @get_group_pins: return an array of pins corresponding to a certain
+ * group selector @pins, and the size of the array in @num_pins
+@@ -76,7 +74,7 @@ struct pinctrl_gpio_range {
+ * info for a certain pin in debugfs
+ */
+ struct pinctrl_ops {
+- int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector);
++ int (*get_groups_count) (struct pinctrl_dev *pctldev);
+ const char *(*get_group_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_group_pins) (struct pinctrl_dev *pctldev,
+diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
+index 47e9237..dd7bef6 100644
+--- a/include/linux/pinctrl/pinmux.h
++++ b/include/linux/pinctrl/pinmux.h
+@@ -29,9 +29,8 @@ struct pinctrl_dev;
+ * is allowed to answer "no" by returning a negative error code
+ * @free: the reverse function of the request() callback, frees a pin after
+ * being requested
+- * @list_functions: list the number of selectable named functions available
+- * in this pinmux driver, the core will begin on 0 and call this
+- * repeatedly as long as it returns >= 0 to enumerate mux settings
++ * @get_functions_count: returns number of selectable named functions available
++ * in this pinmux driver
+ * @get_function_name: return the function name of the muxing selector,
+ * called by the core to figure out which mux setting it shall map a
+ * certain device to
+@@ -62,7 +61,7 @@ struct pinctrl_dev;
+ struct pinmux_ops {
+ int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
+ int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
+- int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector);
++ int (*get_functions_count) (struct pinctrl_dev *pctldev);
+ const char *(*get_function_name) (struct pinctrl_dev *pctldev,
+ unsigned selector);
+ int (*get_function_groups) (struct pinctrl_dev *pctldev,
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5d30336b8a420e0a8b24572d3fbc7458477e2a2e Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Wed, 19 Sep 2012 15:14:34 +0200
-Subject: net/macb: GEM DMA configuration register update
-
-Add information to the DMA Configuration Register to
-maximize system performance:
-- rx/tx packet buffer full memory size
-- allow possibility to use INCR16 if supported
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 10 ++++++++--
- drivers/net/ethernet/cadence/macb.h | 11 +++++++++++
- 2 files changed, 19 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 88a1d20..56bab3c 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -997,8 +997,12 @@ static u32 macb_dbw(struct macb *bp)
- }
-
- /*
-- * Configure the receive DMA engine to use the correct receive buffer size.
-- * This is a configurable parameter for GEM.
-+ * Configure the receive DMA engine
-+ * - use the correct receive buffer size
-+ * - set the possibility to use INCR16 bursts
-+ * (if not supported by FIFO, it will fallback to default)
-+ * - set both rx/tx packet buffers to full memory size
-+ * These are configurable parameters for GEM.
- */
- static void macb_configure_dma(struct macb *bp)
- {
-@@ -1007,6 +1011,8 @@ static void macb_configure_dma(struct macb *bp)
- if (macb_is_gem(bp)) {
- dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
- dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64);
-+ dmacfg |= GEM_BF(FBLDO, 16);
-+ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
- gem_writel(bp, DMACFG, dmacfg);
- }
- }
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index bfab8ef..256559d 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -161,8 +161,19 @@
- #define GEM_DBW128 2
-
- /* Bitfields in DMACFG. */
-+#define GEM_FBLDO_OFFSET 0
-+#define GEM_FBLDO_SIZE 5
-+#define GEM_RXBMS_OFFSET 8
-+#define GEM_RXBMS_SIZE 2
-+#define GEM_TXPBMS_OFFSET 10
-+#define GEM_TXPBMS_SIZE 1
-+#define GEM_TXCOEN_OFFSET 11
-+#define GEM_TXCOEN_SIZE 1
- #define GEM_RXBS_OFFSET 16
- #define GEM_RXBS_SIZE 8
-+#define GEM_DDRP_OFFSET 24
-+#define GEM_DDRP_SIZE 1
-+
-
- /* Bitfields in NSR */
- #define MACB_NSR_LINK_OFFSET 0
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 063384f9528680eae1564f69f66bbb240c6398ea Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Tue, 17 Apr 2012 15:00:45 +0800
+Subject: pinctrl: show pin name when request pins
+
+commit d0bd8df56ebffe4a5ca42e27aca2a1243c70ed53 upstream.
+
+Pin name is more useful to users.
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/pinmux.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
+index 375b214..d6f6823 100644
+--- a/drivers/pinctrl/pinmux.c
++++ b/drivers/pinctrl/pinmux.c
+@@ -86,8 +86,6 @@ static int pin_request(struct pinctrl_dev *pctldev,
+ const struct pinmux_ops *ops = pctldev->desc->pmxops;
+ int status = -EINVAL;
+
+- dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
+-
+ desc = pin_desc_get(pctldev, pin);
+ if (desc == NULL) {
+ dev_err(pctldev->dev,
+@@ -95,6 +93,9 @@ static int pin_request(struct pinctrl_dev *pctldev,
+ goto out;
+ }
+
++ dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
++ pin, desc->name, owner);
++
+ if (gpio_range) {
+ /* There's no need to support multiple GPIO requests */
+ if (desc->gpio_owner) {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From d753b91290e2caf097dcb0d216710fcce4208327 Mon Sep 17 00:00:00 2001
-From: Havard Skinnemoen <havard@skinnemoen.net>
-Date: Tue, 24 Mar 2009 10:45:19 +0100
-Subject: net/macb: Use non-coherent memory for rx buffers
-
-Allocate regular pages to use as backing for the RX ring and use the
-DMA API to sync the caches. This should give a bit better performance
-since it allows the CPU to do burst transfers from memory. It is also
-a necessary step on the way to reduce the amount of copying done by
-the driver.
-
-Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
-[nicolas.ferre@atmel.com: adapt to newer kernel]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/ethernet/cadence/macb.c | 206 +++++++++++++++++++++++-------------
- drivers/net/ethernet/cadence/macb.h | 20 +++-
- 2 files changed, 148 insertions(+), 78 deletions(-)
-
-diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
-index 56bab3c..e3168bf 100644
---- a/drivers/net/ethernet/cadence/macb.c
-+++ b/drivers/net/ethernet/cadence/macb.c
-@@ -10,6 +10,7 @@
-
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include <linux/clk.h>
-+#include <linux/highmem.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
-@@ -32,6 +33,8 @@
- #define RX_BUFFER_SIZE 128
- #define RX_RING_SIZE 512
- #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
-+#define RX_BUFFERS_PER_PAGE (PAGE_SIZE / RX_BUFFER_SIZE)
-+#define RX_RING_PAGES (RX_RING_SIZE / RX_BUFFERS_PER_PAGE)
-
- #define TX_RING_SIZE 128
- #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
-@@ -92,9 +95,16 @@ static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
- return &bp->rx_ring[macb_rx_ring_wrap(index)];
- }
-
--static void *macb_rx_buffer(struct macb *bp, unsigned int index)
-+static struct macb_rx_page *macb_rx_page(struct macb *bp, unsigned int index)
- {
-- return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
-+ unsigned int entry = macb_rx_ring_wrap(index);
-+
-+ return &bp->rx_page[entry / RX_BUFFERS_PER_PAGE];
-+}
-+
-+static unsigned int macb_rx_page_offset(struct macb *bp, unsigned int index)
-+{
-+ return (index % RX_BUFFERS_PER_PAGE) * RX_BUFFER_SIZE;
- }
-
- static void __macb_set_hwaddr(struct macb *bp)
-@@ -492,11 +502,15 @@ static void macb_tx_interrupt(struct macb *bp)
- static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- unsigned int last_frag)
- {
-- unsigned int len;
-- unsigned int frag;
-- unsigned int offset;
-- struct sk_buff *skb;
-- struct macb_dma_desc *desc;
-+ unsigned int len;
-+ unsigned int frag;
-+ unsigned int skb_offset;
-+ unsigned int pg_offset;
-+ struct macb_rx_page *rx_page;
-+ dma_addr_t phys;
-+ void *buf;
-+ struct sk_buff *skb;
-+ struct macb_dma_desc *desc;
-
- desc = macb_rx_desc(bp, last_frag);
- len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
-@@ -530,7 +544,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- return 1;
- }
-
-- offset = 0;
-+ skb_offset = 0;
- len += NET_IP_ALIGN;
- skb_checksum_none_assert(skb);
- skb_put(skb, len);
-@@ -538,13 +552,28 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
- for (frag = first_frag; ; frag++) {
- unsigned int frag_len = RX_BUFFER_SIZE;
-
-- if (offset + frag_len > len) {
-+ if (skb_offset + frag_len > len) {
- BUG_ON(frag != last_frag);
-- frag_len = len - offset;
-+ frag_len = len - skb_offset;
- }
-- skb_copy_to_linear_data_offset(skb, offset,
-- macb_rx_buffer(bp, frag), frag_len);
-- offset += RX_BUFFER_SIZE;
-+
-+ rx_page = macb_rx_page(bp, frag);
-+ pg_offset = macb_rx_page_offset(bp, frag);
-+ phys = rx_page->phys;
-+
-+ dma_sync_single_range_for_cpu(&bp->pdev->dev, phys,
-+ pg_offset, frag_len, DMA_FROM_DEVICE);
-+
-+ buf = kmap_atomic(rx_page->page);
-+ skb_copy_to_linear_data_offset(skb, skb_offset,
-+ buf + pg_offset, frag_len);
-+ kunmap_atomic(buf);
-+
-+ skb_offset += frag_len;
-+
-+ dma_sync_single_range_for_device(&bp->pdev->dev, phys,
-+ pg_offset, frag_len, DMA_FROM_DEVICE);
-+
- desc = macb_rx_desc(bp, frag);
- desc->addr &= ~MACB_BIT(RX_USED);
-
-@@ -824,86 +853,90 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
- return NETDEV_TX_OK;
- }
-
--static void macb_free_consistent(struct macb *bp)
-+static void macb_free_rings(struct macb *bp)
- {
-- if (bp->tx_skb) {
-- kfree(bp->tx_skb);
-- bp->tx_skb = NULL;
-- }
-- if (bp->rx_ring) {
-- dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES,
-- bp->rx_ring, bp->rx_ring_dma);
-- bp->rx_ring = NULL;
-- }
-- if (bp->tx_ring) {
-- dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES,
-- bp->tx_ring, bp->tx_ring_dma);
-- bp->tx_ring = NULL;
-- }
-- if (bp->rx_buffers) {
-- dma_free_coherent(&bp->pdev->dev,
-- RX_RING_SIZE * RX_BUFFER_SIZE,
-- bp->rx_buffers, bp->rx_buffers_dma);
-- bp->rx_buffers = NULL;
-+ int i;
-+
-+ for (i = 0; i < RX_RING_PAGES; i++) {
-+ struct macb_rx_page *rx_page = &bp->rx_page[i];
-+
-+ if (!rx_page->page)
-+ continue;
-+
-+ dma_unmap_page(&bp->pdev->dev, rx_page->phys,
-+ PAGE_SIZE, DMA_FROM_DEVICE);
-+ put_page(rx_page->page);
-+ rx_page->page = NULL;
- }
-+
-+ kfree(bp->tx_skb);
-+ kfree(bp->rx_page);
-+ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
-+ bp->tx_ring_dma);
-+ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
-+ bp->rx_ring_dma);
- }
-
--static int macb_alloc_consistent(struct macb *bp)
-+static int macb_init_rings(struct macb *bp)
- {
-- int size;
-+ struct page *page;
-+ dma_addr_t phys;
-+ unsigned int page_idx;
-+ unsigned int ring_idx;
-+ unsigned int i;
-
-- size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
-- bp->tx_skb = kmalloc(size, GFP_KERNEL);
-- if (!bp->tx_skb)
-- goto out_err;
--
-- size = RX_RING_BYTES;
-- bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
-+ bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, RX_RING_BYTES,
- &bp->rx_ring_dma, GFP_KERNEL);
- if (!bp->rx_ring)
-- goto out_err;
-+ goto err_alloc_rx_ring;
-+
- netdev_dbg(bp->dev,
- "Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
-- size, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
-+ RX_RING_BYTES, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
-
-- size = TX_RING_BYTES;
-- bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
-+ bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, TX_RING_BYTES,
- &bp->tx_ring_dma, GFP_KERNEL);
- if (!bp->tx_ring)
-- goto out_err;
-- netdev_dbg(bp->dev,
-- "Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
-- size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
--
-- size = RX_RING_SIZE * RX_BUFFER_SIZE;
-- bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
-- &bp->rx_buffers_dma, GFP_KERNEL);
-- if (!bp->rx_buffers)
-- goto out_err;
-+ goto err_alloc_tx_ring;
-+
- netdev_dbg(bp->dev,
-- "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
-- size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers);
-+ "Allocated TX ring of %d bytes at 0x%08lx (mapped %p)\n",
-+ TX_RING_BYTES, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
-
-- return 0;
-+ bp->rx_page = kcalloc(RX_RING_PAGES, sizeof(struct macb_rx_page),
-+ GFP_KERNEL);
-+ if (!bp->rx_page)
-+ goto err_alloc_rx_page;
-
--out_err:
-- macb_free_consistent(bp);
-- return -ENOMEM;
--}
-+ bp->tx_skb = kcalloc(TX_RING_SIZE, sizeof(struct macb_tx_skb),
-+ GFP_KERNEL);
-+ if (!bp->tx_skb)
-+ goto err_alloc_tx_skb;
-
--static void macb_init_rings(struct macb *bp)
--{
-- int i;
-- dma_addr_t addr;
-+ for (page_idx = 0, ring_idx = 0; page_idx < RX_RING_PAGES; page_idx++) {
-+ page = alloc_page(GFP_KERNEL);
-+ if (!page)
-+ goto err_alloc_page;
-+
-+ phys = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
-+ DMA_FROM_DEVICE);
-+ if (dma_mapping_error(&bp->pdev->dev, phys))
-+ goto err_map_page;
-+
-+ bp->rx_page[page_idx].page = page;
-+ bp->rx_page[page_idx].phys = phys;
-
-- addr = bp->rx_buffers_dma;
-- for (i = 0; i < RX_RING_SIZE; i++) {
-- bp->rx_ring[i].addr = addr;
-- bp->rx_ring[i].ctrl = 0;
-- addr += RX_BUFFER_SIZE;
-+ for (i = 0; i < RX_BUFFERS_PER_PAGE; i++, ring_idx++) {
-+ bp->rx_ring[ring_idx].addr = phys;
-+ bp->rx_ring[ring_idx].ctrl = 0;
-+ phys += RX_BUFFER_SIZE;
-+ }
- }
- bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
-
-+ netdev_dbg(bp->dev, "Allocated %u RX buffers (%lu pages)\n",
-+ RX_RING_SIZE, RX_RING_PAGES);
-+
- for (i = 0; i < TX_RING_SIZE; i++) {
- bp->tx_ring[i].addr = 0;
- bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
-@@ -911,6 +944,28 @@ static void macb_init_rings(struct macb *bp)
- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
-
- bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
-+
-+ return 0;
-+
-+err_map_page:
-+ __free_page(page);
-+err_alloc_page:
-+ while (page_idx--) {
-+ dma_unmap_page(&bp->pdev->dev, bp->rx_page[page_idx].phys,
-+ PAGE_SIZE, DMA_FROM_DEVICE);
-+ __free_page(bp->rx_page[page_idx].page);
-+ }
-+ kfree(bp->tx_skb);
-+err_alloc_tx_skb:
-+ kfree(bp->rx_page);
-+err_alloc_rx_page:
-+ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
-+ bp->tx_ring_dma);
-+err_alloc_tx_ring:
-+ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
-+ bp->rx_ring_dma);
-+err_alloc_rx_ring:
-+ return -ENOMEM;
- }
-
- static void macb_reset_hw(struct macb *bp)
-@@ -1185,16 +1240,15 @@ static int macb_open(struct net_device *dev)
- if (!is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
-
-- err = macb_alloc_consistent(bp);
-+ err = macb_init_rings(bp);
- if (err) {
-- netdev_err(dev, "Unable to allocate DMA memory (error %d)\n",
-+ netdev_err(dev, "Unable to allocate DMA rings (error %d)\n",
- err);
- return err;
- }
-
- napi_enable(&bp->napi);
-
-- macb_init_rings(bp);
- macb_init_hw(bp);
-
- /* schedule a link state check */
-@@ -1221,7 +1275,7 @@ static int macb_close(struct net_device *dev)
- netif_carrier_off(dev);
- spin_unlock_irqrestore(&bp->lock, flags);
-
-- macb_free_consistent(bp);
-+ macb_free_rings(bp);
-
- return 0;
- }
-diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
-index 256559d..01aecea 100644
---- a/drivers/net/ethernet/cadence/macb.h
-+++ b/drivers/net/ethernet/cadence/macb.h
-@@ -441,6 +441,23 @@ struct macb_dma_desc {
- #define MACB_TX_USED_SIZE 1
-
- /**
-+ * struct macb_rx_page - data associated with a page used as RX buffers
-+ * @page: Physical page used as storage for the buffers
-+ * @phys: DMA address of the page
-+ *
-+ * Each page is used to provide %MACB_RX_BUFFERS_PER_PAGE RX buffers.
-+ * The page gets an initial reference when it is inserted into the
-+ * ring, and an additional reference each time it is passed up the
-+ * stack as a fragment. When all the buffers have been used, we drop
-+ * the initial reference and allocate a new page. Any additional
-+ * references are dropped when the higher layers free the skb.
-+ */
-+struct macb_rx_page {
-+ struct page *page;
-+ dma_addr_t phys;
-+};
-+
-+/**
- * struct macb_tx_skb - data about an skb which is being transmitted
- * @skb: skb currently being transmitted
- * @mapping: DMA address of the skb's data buffer
-@@ -531,7 +548,7 @@ struct macb {
-
- unsigned int rx_tail;
- struct macb_dma_desc *rx_ring;
-- void *rx_buffers;
-+ struct macb_rx_page *rx_page;
-
- unsigned int tx_head, tx_tail;
- struct macb_dma_desc *tx_ring;
-@@ -552,7 +569,6 @@ struct macb {
-
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
-- dma_addr_t rx_buffers_dma;
-
- struct mii_bus *mii_bus;
- struct phy_device *phy_dev;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 98e0834df26052480b71e183d23b6cc38d51d7a0 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Tue, 17 Apr 2012 15:00:46 +0800
+Subject: pinctrl: show pin name for pingroups in sysfs
+
+commit dcb5dbc305b975cccf40942feba40964069541d3 upstream.
+
+Pin name is more useful to users.
+
+After change, when cat pingroups in sysfs, it becomes:
+root@freescale /sys/kernel/debug/pinctrl/20e0000.iomuxc$ cat pingroups
+registered pin groups:
+group: uart4grp-1
+pin 219 (MX6Q_PAD_KEY_ROW0)
+pin 218 (MX6Q_PAD_KEY_COL0)
+
+group: usdhc4grp-1
+pin 305 (MX6Q_PAD_SD4_CMD)
+pin 306 (MX6Q_PAD_SD4_CLK)
+pin 315 (MX6Q_PAD_SD4_DAT0)
+pin 316 (MX6Q_PAD_SD4_DAT1)
+pin 317 (MX6Q_PAD_SD4_DAT2)
+pin 318 (MX6Q_PAD_SD4_DAT3)
+pin 319 (MX6Q_PAD_SD4_DAT4)
+pin 320 (MX6Q_PAD_SD4_DAT5)
+pin 321 (MX6Q_PAD_SD4_DAT6)
+pin 322 (MX6Q_PAD_SD4_DAT7)
+
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ drivers/pinctrl/core.c | 32 ++++++++++++++++++++++++++++----
+ drivers/pinctrl/core.h | 1 +
+ 2 files changed, 29 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index c70ae2d..5f8a7d2 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -141,6 +141,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
+ }
+
+ /**
++ * pin_get_name_from_id() - look up a pin name from a pin id
++ * @pctldev: the pin control device to lookup the pin on
++ * @name: the name of the pin to look up
++ */
++const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
++{
++ const struct pin_desc *desc;
++
++ desc = pin_desc_get(pctldev, pin);
++ if (desc == NULL) {
++ dev_err(pctldev->dev, "failed to get pin(%d) name\n",
++ pin);
++ return NULL;
++ }
++
++ return desc->name;
++}
++
++/**
+ * pin_is_valid() - check if pin exists on controller
+ * @pctldev: the pin control device to check the pin on
+ * @pin: pin to check, use the local pin controller index number
+@@ -1034,6 +1053,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ const unsigned *pins;
+ unsigned num_pins;
+ const char *gname = ops->get_group_name(pctldev, selector);
++ const char *pname;
+ int ret;
+ int i;
+
+@@ -1043,10 +1063,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
+ seq_printf(s, "%s [ERROR GETTING PINS]\n",
+ gname);
+ else {
+- seq_printf(s, "group: %s, pins = [ ", gname);
+- for (i = 0; i < num_pins; i++)
+- seq_printf(s, "%d ", pins[i]);
+- seq_puts(s, "]\n");
++ seq_printf(s, "group: %s\n", gname);
++ for (i = 0; i < num_pins; i++) {
++ pname = pin_get_name(pctldev, pins[i]);
++ if (WARN_ON(!pname))
++ return -EINVAL;
++ seq_printf(s, "pin %d (%s)\n", pins[i], pname);
++ }
++ seq_puts(s, "\n");
+ }
+ selector++;
+ }
+diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
+index 98ae808..1f40ff6 100644
+--- a/drivers/pinctrl/core.h
++++ b/drivers/pinctrl/core.h
+@@ -148,6 +148,7 @@ struct pin_desc {
+
+ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
+ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
++const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
+ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
+ const char *pin_group);
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From c71effdb46261af0b8304ed628c0f2d97e9b56d6 Mon Sep 17 00:00:00 2001
+From: Dong Aisheng <dong.aisheng@linaro.org>
+Date: Fri, 27 Apr 2012 11:36:20 +0800
+Subject: dt: add of_get_child_count helper function
+
+commit 183f1d0c6450ee032d97a2d01ed5eb00e0dbaa49 upstream.
+
+Currently most code to get child count in kernel are almost same,
+add a helper to implement this function for dt to use.
+
+Cc: Grant Likely <grant.likely@secretlab.ca>
+Acked-by: Rob Herring <rob.herring@calxeda.com>
+Acked-by: Stephen Warren <swarren@wwwdotorg.org>
+Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ include/linux/of.h | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/include/linux/of.h
++++ b/include/linux/of.h
+@@ -194,6 +194,17 @@ extern struct device_node *of_get_next_c
+ for (child = of_get_next_child(parent, NULL); child != NULL; \
+ child = of_get_next_child(parent, child))
+
++static inline int of_get_child_count(const struct device_node *np)
++{
++ struct device_node *child;
++ int num = 0;
++
++ for_each_child_of_node(np, child)
++ num++;
++
++ return num;
++}
++
+ extern struct device_node *of_find_node_with_property(
+ struct device_node *from, const char *prop_name);
+ #define for_each_node_with_property(dn, prop_name) \
+@@ -306,6 +317,11 @@ static inline bool of_have_populated_dt(
+ #define for_each_child_of_node(parent, child) \
+ while (0)
+
++static inline int of_get_child_count(const struct device_node *np)
++{
++ return 0;
++}
++
+ static inline int of_device_is_compatible(const struct device_node *device,
+ const char *name)
+ {
+++ /dev/null
-From 0a488fbfdd0525849b8a67cc8158523643aaba7e Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 26 Jun 2012 11:07:32 +0200
-Subject: phy/micrel: Use proper phy in gmac
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/net/phy/micrel.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
-index 590f902..cc7f75b 100644
---- a/drivers/net/phy/micrel.c
-+++ b/drivers/net/phy/micrel.c
-@@ -191,6 +191,7 @@ static int __init ksphy_init(void)
- {
- int ret;
-
-+#if 0
- ret = phy_driver_register(&ks8001_driver);
- if (ret)
- goto err1;
-@@ -208,9 +209,15 @@ static int __init ksphy_init(void)
- ret = phy_driver_register(&ks8051_driver);
- if (ret)
- goto err5;
-+#endif
-+
-+ ret = phy_driver_register(&ksz9021_driver);
-+ if (ret)
-+ goto err1;
-
- return 0;
-
-+#if 0
- err5:
- phy_driver_unregister(&ks8041_driver);
- err4:
-@@ -219,6 +226,7 @@ err3:
- phy_driver_unregister(&ksz9021_driver);
- err2:
- phy_driver_unregister(&ks8001_driver);
-+#endif
- err1:
- return ret;
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8eaef7cd81925116f062014a50057edf8b24ebc3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 14:57:08 +0200
+Subject: MTD: atmel_nand: add 9x5 to list of SoC with DMA
+
+Temporary: may have to be replaced by a device-tree property.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index b5e5a76..a1b5468 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -127,7 +127,7 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
+
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() || cpu_is_at91sam9x5();
+ }
+
+ /*
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From db4349884ad9dd53c6a3e866aefd00a78532907f Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 10 Jul 2012 12:03:54 +0200
-Subject: phy/micrel: we need to register ks8051 phy for emac
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/net/phy/micrel.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
-index cc7f75b..2d80e01 100644
---- a/drivers/net/phy/micrel.c
-+++ b/drivers/net/phy/micrel.c
-@@ -206,10 +206,10 @@ static int __init ksphy_init(void)
- ret = phy_driver_register(&ks8041_driver);
- if (ret)
- goto err4;
-+#endif
- ret = phy_driver_register(&ks8051_driver);
- if (ret)
-- goto err5;
--#endif
-+ goto err2;
-
- ret = phy_driver_register(&ksz9021_driver);
- if (ret)
-@@ -227,6 +227,8 @@ err3:
- err2:
- phy_driver_unregister(&ks8001_driver);
- #endif
-+err2:
-+ phy_driver_unregister(&ks8051_driver);
- err1:
- return ret;
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 7e46312721b0ed2c4a893b2b38cca0fcd39c1cc5 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 15:07:06 +0200
+Subject: MTD: atmel_nand: POI fall back is not an issue: change log
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index a1b5468..cacccba 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -281,7 +281,7 @@ err_dma:
+ dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
+ err_buf:
+ if (err != 0)
+- dev_warn(host->dev, "Fall back to CPU I/O\n");
++ dev_dbg(host->dev, "Fall back to CPU I/O\n");
+ return err;
+ }
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ae50ff05ab833b25bb7d581dd0beaeec1ab830da Mon Sep 17 00:00:00 2001
-From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
-Date: Fri, 7 Sep 2012 14:54:25 +0800
-Subject: usb: gadget: at91_udc: move the dereference below the NULL test
-
-The dereference should be moved below the NULL test.
-
-spatch with a semantic match is used to found this.
-(http://coccinelle.lip6.fr/)
-
-Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
-Signed-off-by: Felipe Balbi <balbi@ti.com>
----
- drivers/usb/gadget/at91_udc.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
-index 9d7bcd9..d6249f0 100644
---- a/drivers/usb/gadget/at91_udc.c
-+++ b/drivers/usb/gadget/at91_udc.c
-@@ -469,7 +469,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
- {
- struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
-- struct at91_udc *udc = ep->udc;
-+ struct at91_udc *udc;
- u16 maxpacket;
- u32 tmp;
- unsigned long flags;
-@@ -484,6 +484,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
- return -EINVAL;
- }
-
-+ udc = ep->udc;
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
- DBG("bogus device state\n");
- return -ESHUTDOWN;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From bfa303b459025a62eae939042183bb3b78fe5107 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 8 Oct 2012 16:55:29 +0200
+Subject: MTD: atmel_nand: add 9n12 to list of SoC with DMA
+
+Temporary: may have to be replaced by a device-tree property.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mtd/nand/atmel_nand.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index cacccba..a92f603 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -127,7 +127,8 @@ static struct nand_ecclayout atmel_pmecc_oobinfo;
+
+ static int cpu_has_dma(void)
+ {
+- return cpu_is_at91sam9rl() || cpu_is_at91sam9g45() || cpu_is_at91sam9x5();
++ return cpu_is_at91sam9rl() || cpu_is_at91sam9g45()
++ || cpu_is_at91sam9x5() || cpu_is_at91sam9n12();
+ }
+
+ /*
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 42e76043636c925fe4de3223092e587d12a1be2a Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Wed, 29 Aug 2012 11:49:18 +0200
-Subject: USB: ohci-at91: fix PIO handling in relation with number of ports
-
-If the number of ports present on the SoC/board is not the maximum
-and that the platform data is not filled with all data, there is
-an easy way to mess the PIO setup for this interface.
-This quick fix addresses mis-configuration in USB host platform data
-that is common in at91 boards since commit 0ee6d1e (USB: ohci-at91:
-change maximum number of ports) that did not modified the associatd
-board files.
-
-Reported-by: Klaus Falkner <klaus.falkner@solectrix.de>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Cc: Stable <stable@vger.kernel.org> [3.4+]
-Acked-by: Alan Stern <stern@rowland.harvard.edu>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/usb/host/ohci-at91.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/usb/host/ohci-at91.c
-+++ b/drivers/usb/host/ohci-at91.c
-@@ -647,6 +647,16 @@ static int __devexit ohci_hcd_at91_drv_r
-
- if (pdata) {
- at91_for_each_port(i) {
-+ /*
-+ * do not configure PIO if not in relation with
-+ * real USB port on board
-+ */
-+ if (i >= pdata->ports) {
-+ pdata->vbus_pin[i] = -EINVAL;
-+ pdata->overcurrent_pin[i] = -EINVAL;
-+ break;
-+ }
-+
- if (!gpio_is_valid(pdata->vbus_pin[i]))
- continue;
- ohci_at91_usb_set_power(pdata, i, 0);
--- /dev/null
+From 1fe1424112c1385a4f3b89fb8944150692279ba9 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 12:28:13 +0100
+Subject: input: atmel_tsadcc: add support for ARCH_AT91SAM9X5
+
+XXX: split header creation in a new patch (or don't do it)
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 150 ++++++++++++----------------
+ drivers/input/touchscreen/atmel_tsadcc.h | 162 +++++++++++++++++++++++++++++++
+ 2 files changed, 222 insertions(+), 90 deletions(-)
+ create mode 100644 drivers/input/touchscreen/atmel_tsadcc.h
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 201b2d2..a0e8d52 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -25,74 +25,9 @@
+ #include <mach/board.h>
+ #include <mach/cpu.h>
+
+-/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
+-
+-#define ATMEL_TSADCC_CR 0x00 /* Control register */
+-#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
+-#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
+-
+-#define ATMEL_TSADCC_MR 0x04 /* Mode register */
+-#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
+-#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
+-#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
+-#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
+-#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
+-#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
+-#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
+-#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
+-#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
+-#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
+-#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
+-#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
+-
+-#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
+-#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
+-#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
+-#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
+-#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
+-#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
+-#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
+-#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
+-
+-#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
+-#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
+-#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
+-
+-#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
+-#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
+-#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
+-#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
+-
+-#define ATMEL_TSADCC_SR 0x1C /* Status register */
+-#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
+-#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
+-#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
+-#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
+-#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
+-#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
+-#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
+-#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
+-
+-#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
+-#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
+-
+-#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
+-#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
+-#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
+-#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
+-#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
+-#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
+-#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
+-#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
+-#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
+-
+-#define ATMEL_TSADCC_XPOS 0x50
+-#define ATMEL_TSADCC_Z1DAT 0x54
+-#define ATMEL_TSADCC_Z2DAT 0x58
+-
+-#define PRESCALER_VAL(x) ((x) >> 8)
++#include "atmel_tsadcc.h"
++
++#define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
+
+ #define ADC_DEFAULT_CLOCK 100000
+
+@@ -124,12 +59,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ if (status & ATMEL_TSADCC_NOCNT) {
+ /* Contact lost */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
+-
+- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ if (cpu_has_9x5_adc()) {
++ /* 9X5 using TSMR to set PENDBC time */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
++ } else {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ }
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR,
+- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+@@ -138,23 +78,31 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ } else if (status & ATMEL_TSADCC_PENCNT) {
+ /* Pen detected */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
+- reg &= ~ATMEL_TSADCC_PENDBC;
++ if (cpu_has_9x5_adc()) {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR);
++ reg &= ~ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
++ } else {
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR);
++ reg &= ~ATMEL_TSADCC_PENDBC;
++ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
++ }
+
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
+- atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+- ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT);
++ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
+
+- } else if (status & ATMEL_TSADCC_EOC(3)) {
++ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+
+ if (ts_dev->bufferedmeasure) {
+ /* Last measurement is always discarded, since it can
+ * be erroneous.
+ * Always report previous measurement */
++ dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy);
+ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+@@ -163,11 +111,16 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ ts_dev->bufferedmeasure = 1;
+
+ /* Now make new measurement */
+- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+- ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+-
+- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+- ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
++ if (cpu_has_9x5_adc()) {
++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++ } else {
++ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
++ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
++
++ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
++ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
++ }
+ }
+
+ return IRQ_HANDLED;
+@@ -284,18 +237,35 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
+
+- reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
+- ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
+- ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
+- (prsc << 8) |
+- ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
+- ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
++ if (cpu_has_9x5_adc()) {
++ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
++ (prsc << 8) |
++ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
++ } else {
++ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
++ ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */
++ ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */
++ (prsc << 8) |
++ ((0x26 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
++ }
+
+ atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST);
+ atmel_tsadcc_write(ATMEL_TSADCC_MR, reg);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE);
+- atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+- (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
++
++ if (cpu_has_9x5_adc()) {
++ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
++ ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
++ ATMEL_TSADCC_NOTSDMA |
++ ATMEL_TSADCC_PENDET_ENA |
++ (pdata->pendet_debounce << 28) |
++ (0x0 << 8));
++ } else {
++ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
++ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
++ }
+
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+new file mode 100644
+index 0000000..5918c20
+--- /dev/null
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -0,0 +1,162 @@
++/*
++ * Header file for AT91/AT32 ADC + touchscreen Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2010 Atmel Corporation
++ *
++ * 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.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef __ATMEL_TSADCC_H__
++#define __ATMEL_TSADCC_H__
++
++/* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */
++#define ATMEL_TSADCC_CR 0x00 /* Control register */
++#define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/
++#define ATMEL_TSADCC_START (1 << 1) /* Start conversion */
++
++#define ATMEL_TSADCC_MR 0x04 /* Mode register */
++#define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */
++#define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */
++#define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */
++#define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
++#define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
++#define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
++#define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
++#define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
++#define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
++#define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */
++#define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */
++#define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */
++
++#define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */
++#define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */
++#define ATMEL_TSADCC_TRGMOD_NONE (0 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0)
++#define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0)
++#define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0)
++#define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0)
++#define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0)
++#define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */
++
++#define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */
++#define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */
++#define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */
++
++#define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */
++#define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */
++#define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */
++#define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */
++
++#define ATMEL_TSADCC_SR 0x1C /* Status register */
++#define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */
++#define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */
++#define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */
++#define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */
++#define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */
++#define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */
++#define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */
++#define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */
++
++#define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */
++#define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */
++
++#define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */
++#define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */
++#define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */
++#define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */
++#define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */
++#define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */
++#define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */
++#define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */
++#define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */
++
++#define ATMEL_TSADCC_XPOS 0x50
++#define ATMEL_TSADCC_Z1DAT 0x54
++#define ATMEL_TSADCC_Z2DAT 0x58
++
++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_EOC(3))
++
++/* Register definitions based on AT91SAM9X5 preliminary draft datasheet */
++#define ATMEL_TSADCC_TRACKTIM (0x0f << 24) /* Tracking Time */
++
++#define ATMEL_TSADCC_ISR 0x30 /* Interrupt Status register */
++#define ATMEL_TSADCC_XRDY (1 << 20) /* Measure XPOS Ready */
++#define ATMEL_TSADCC_YRDY (1 << 21) /* Measure YPOS Ready */
++#define ATMEL_TSADCC_PRDY (1 << 22) /* Measure Pressure Ready */
++#define ATMEL_TSADCC_COMPE (1 << 26) /* Comparison Event */
++#define ATMEL_TSADCC_PEN (1 << 29) /* Pen Contact */
++#define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
++#define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
++
++#define ATMEL_TSADCC_TSMR 0xb0
++#define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
++#define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
++#define ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS (1 << 0) /* 4-wire Touch Screen without pressure measurement */
++#define ATMEL_TSADCC_TSMODE_4WIRE_PRESS (2 << 0) /* 4-wire Touch Screen with pressure measurement */
++#define ATMEL_TSADCC_TSMODE_5WIRE (3 << 0) /* 5-wire Touch Screen */
++#define ATMEL_TSADCC_TSAV (3 << 4) /* Touch Screen Average */
++#define ATMEL_TSADCC_TSAV_1 (0 << 4) /* No filtering. Only one conversion ADC per measure */
++#define ATMEL_TSADCC_TSAV_2 (1 << 4) /* Averages 2 ADC conversions */
++#define ATMEL_TSADCC_TSAV_4 (2 << 4) /* Averages 4 ADC conversions */
++#define ATMEL_TSADCC_TSAV_8 (3 << 4) /* Averages 8 ADC conversions */
++#define ATMEL_TSADCC_TSSCTIM (0x0f << 16) /* Touch Screen switches closure time */
++
++#define ATMEL_TSADCC_NOTSDMA (1 << 22) /* No Touchscreen DMA */
++#define ATMEL_TSADCC_PENDET_DIS (0 << 24) /* Pen contact detection disable */
++#define ATMEL_TSADCC_PENDET_ENA (1 << 24) /* Pen contact detection enable */
++
++#define ATMEL_TSADCC_XPOSR 0xb4
++#define ATMEL_TSADCC_XSCALE (0x3ff << 16) /* Scale of X Position */
++
++#define ATMEL_TSADCC_YPOSR 0xb8
++#define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
++#define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
++
++/* 9x5 ADC registers which conflict with previous definition */
++#ifdef CONFIG_ARCH_AT91SAM9X5
++#undef ATMEL_TSADCC_TRGR
++#undef ATMEL_TSADCC_SR
++#define ATMEL_TSADCC_SR ATMEL_TSADCC_ISR
++#define ATMEL_TSADCC_TRGR 0xc0
++
++/* For code compatiable, redefine with 9x5 value */
++#undef ATMEL_TSADCC_STARTUP
++#define ATMEL_TSADCC_STARTUP (0x0f << 16) /* Startup Time */
++#undef ATMEL_TSADCC_DRDY
++#define ATMEL_TSADCC_DRDY (1 << 24) /* Data Ready */
++#undef ATMEL_TSADCC_GOVRE
++#define ATMEL_TSADCC_GOVRE (1 << 25) /* General Overrun */
++#undef ATMEL_TSADCC_TSFREQ
++#define ATMEL_TSADCC_TSFREQ (0x0f << 8) /* Touch Screen Frequency */
++#undef ATMEL_TSADCC_PENDET
++#define ATMEL_TSADCC_PENDET (1 << 24) /* Pen Contact Detection Enable */
++#undef ATMEL_TSADCC_XPOS
++#define ATMEL_TSADCC_XPOS (0x3ff << 0) /* X Position */
++
++#undef ATMEL_TSADCC_NOCNT
++#define ATMEL_TSADCC_NOCNT ATMEL_TSADCC_NOPEN
++#undef ATMEL_TSADCC_PENCNT
++#define ATMEL_TSADCC_PENCNT ATMEL_TSADCC_PEN
++#undef ATMEL_TSADCC_CONVERSION_END
++#define ATMEL_TSADCC_CONVERSION_END (ATMEL_TSADCC_XRDY | ATMEL_TSADCC_YRDY | ATMEL_TSADCC_PRDY)
++
++#endif
++
++/* Retrieve prescaler value */
++#define PRESCALER_VAL(x) ((x) >> 8)
++
++#endif /* __ATMEL_TSADCC_H__ */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 2cdc659b4c98955fbd33065c56c468b494129321 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 17 Nov 2010 13:12:11 +0100
+Subject: input: atmel_tsadcc: add touch screen pressure measurement
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 26 +++++++++++++++++++++++---
+ drivers/input/touchscreen/atmel_tsadcc.h | 4 ++++
+ 2 files changed, 27 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index a0e8d52..b6a1630 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -38,6 +38,7 @@ struct atmel_tsadcc {
+ int irq;
+ unsigned int prev_absx;
+ unsigned int prev_absy;
++ unsigned int prev_absz;
+ unsigned char bufferedmeasure;
+ };
+
+@@ -53,6 +54,9 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+
+ unsigned int status;
+ unsigned int reg;
++ unsigned int z1, z2;
++ unsigned int Rxp = 1;
++ unsigned int factor = 1000;
+
+ status = atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR);
+@@ -101,11 +105,15 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ /* Last measurement is always discarded, since it can
+ * be erroneous.
+ * Always report previous measurement */
+- dev_dbg(&input_dev->dev, "x = %d, y = %d\n",
+- ts_dev->prev_absx, ts_dev->prev_absy);
++ dev_dbg(&input_dev->dev,
++ "x = %d, y = %d, pressure = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy,
++ ts_dev->prev_absz);
+ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+ input_report_key(input_dev, BTN_TOUCH, 1);
++ if (cpu_has_9x5_adc())
++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
+ input_sync(input_dev);
+ } else
+ ts_dev->bufferedmeasure = 1;
+@@ -114,6 +122,17 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ if (cpu_has_9x5_adc()) {
+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++
++ /* calculate the pressure */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
++ z1 = reg & ATMEL_TSADCC_PRESSR_Z1;
++ z2 = (reg & ATMEL_TSADCC_PRESSR_Z2) >> 16;
++
++ if (z1 != 0)
++ ts_dev->prev_absz = Rxp * (ts_dev->prev_absx * factor / 1024) * (z2 * factor / z1 - factor) / factor;
++ else
++ ts_dev->prev_absz = 0;
++
+ } else {
+ ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
+ ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
+@@ -209,6 +228,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xffffff, 0, 0);
+
+ input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
+
+@@ -257,7 +277,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+- ATMEL_TSADCC_TSMODE_4WIRE_NO_PRESS |
++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+ ATMEL_TSADCC_NOTSDMA |
+ ATMEL_TSADCC_PENDET_ENA |
+ (pdata->pendet_debounce << 28) |
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 5918c20..231497e 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -126,6 +126,10 @@
+ #define ATMEL_TSADCC_YPOS (0x3ff << 0) /* Y Position */
+ #define ATMEL_TSADCC_YSCALE (0x3ff << 16) /* Scale of Y Position */
+
++#define ATMEL_TSADCC_PRESSR 0xbc /* Touchscreen Pressure Register */
++#define ATMEL_TSADCC_PRESSR_Z1 (0x3ff << 0) /* Data of Z1 Measurement */
++#define ATMEL_TSADCC_PRESSR_Z2 (0x3ff << 16) /* Data of Z2 Measurement */
++
+ /* 9x5 ADC registers which conflict with previous definition */
+ #ifdef CONFIG_ARCH_AT91SAM9X5
+ #undef ATMEL_TSADCC_TRGR
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 3be7e4694db4d894b3bbb2252d033a58a8805cf0 Mon Sep 17 00:00:00 2001
-From: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
-Date: Tue, 26 Jun 2012 11:27:12 -0300
-Subject: usb: gadget: at91_udc: Propagate devicetree to gadget drivers
-
-Fill dev.of_node of gadget drivers, so they can use devicetree
-
-Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
-Signed-off-by: Felipe Balbi <balbi@ti.com>
----
- drivers/usb/gadget/at91_udc.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
-index ffb46bc..ddeaadb 100644
---- a/drivers/usb/gadget/at91_udc.c
-+++ b/drivers/usb/gadget/at91_udc.c
-@@ -1650,6 +1650,7 @@ static int at91_start(struct usb_gadget_driver *driver,
-
- udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
-+ udc->gadget.dev.of_node = udc->pdev->dev.of_node;
- dev_set_drvdata(&udc->gadget.dev, &driver->driver);
- udc->enabled = 1;
- udc->selfpowered = 1;
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 3b08384658865b98f31a74f07550ac0a562887e8 Mon Sep 17 00:00:00 2001
-From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Date: Fri, 27 Apr 2012 11:24:39 -0700
-Subject: USB: ohci-at91.c: remove err() usage
-
-err() was a very old USB-specific macro that I thought had
-gone away. This patch removes it from being used in the
-driver and uses dev_err() instead.
-
-CC: Alan Stern <stern@rowland.harvard.edu>
-CC: Grant Likely <grant.likely@secretlab.ca>
-CC: Rob Herring <rob.herring@calxeda.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/usb/host/ohci-at91.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
-index 5dfea46..aaa8d2b 100644
---- a/drivers/usb/host/ohci-at91.c
-+++ b/drivers/usb/host/ohci-at91.c
-@@ -243,7 +243,8 @@ ohci_at91_start (struct usb_hcd *hcd)
- int ret;
-
- if ((ret = ohci_run(ohci)) < 0) {
-- err("can't start %s", hcd->self.bus_name);
-+ dev_err(hcd->self.controller, "can't start %s\n",
-+ hcd->self.bus_name);
- ohci_stop(hcd);
- return ret;
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 647050060bff19f002e3c0aef95410ab0915dfe1 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 5 Apr 2011 17:30:03 +0200
+Subject: input: atmel_tsadcc: enable touchscreen averaging and add fast wake
+ up
+
+Enable the touchscreen average to improve the resulting events. For this
+to work the trigger period needs to be reduced.
+
+This puts a field into at91_tsadcc_data to allow platforms to specify
+the number of conversions to average over.
+
+XXX: should the trigger period passed by the platform, too, as this
+depends on the number of conversions?
+XXX: seperate fast wake up into a seperate patch? What does it?
+XXX: don't use bare constants
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 14 ++++++++------
+ drivers/input/touchscreen/atmel_tsadcc.h | 1 +
+ 2 files changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index b6a1630..48faecb 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -96,7 +96,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+- ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16));
++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
+
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+@@ -259,6 +259,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
++ ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
+ (prsc << 8) |
+ ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
+ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
+@@ -277,11 +278,12 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+- ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+- ATMEL_TSADCC_NOTSDMA |
+- ATMEL_TSADCC_PENDET_ENA |
+- (pdata->pendet_debounce << 28) |
+- (0x0 << 8));
++ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
++ (pdata->filtering_average << 4) | /* Touchscreen average */
++ ATMEL_TSADCC_NOTSDMA |
++ ATMEL_TSADCC_PENDET_ENA |
++ (pdata->pendet_debounce << 28) |
++ (0x3 << 8)); /* Touchscreen freq */
+ } else {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 231497e..572770a 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -34,6 +34,7 @@
+ #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */
+ #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */
+ #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */
++#define ATMEL_TSADCC_FWUP (1 << 6) /* Fast Wake Up selection (5series) */
+ #define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */
+ #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
+ #define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 93e19b757f18fdf8b8a00999046b3abd4ea9b4a6 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 6 May 2011 17:54:45 +0200
+Subject: input: atmel_tsadcc: add ACR register and change trigger period value
+
+Add ACR register which allows to configure internal ADC resistor, that should
+prevent from adding resistor on display module. Furthermore increase
+trigger period which seems to be related with resistor value. A Too small
+value causes continuous irq.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 30 +++++++++++++++++++++++++++++-
+ drivers/input/touchscreen/atmel_tsadcc.h | 3 +++
+ 2 files changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 48faecb..20154ba 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -47,6 +47,17 @@ static void __iomem *tsc_base;
+ #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg))
+ #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg))
+
++static void atmel_tsadcc_dump_conf(struct platform_device *pdev)
++{
++ dev_info(&pdev->dev, "--- configuration ---\n");
++ dev_info(&pdev->dev, "Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_MR));
++ dev_info(&pdev->dev, "Trigger Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TRGR));
++ dev_info(&pdev->dev, "Touchscreen Mode Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_TSMR));
++ dev_info(&pdev->dev, "Analog Control Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_ACR));
++ dev_info(&pdev->dev, "ADC Channel Status Register: %#x\n", atmel_tsadcc_read(ATMEL_TSADCC_CHSR));
++ dev_info(&pdev->dev, "---------------------\n");
++}
++
+ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ {
+ struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
+@@ -95,8 +106,14 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER,
+ ATMEL_TSADCC_CONVERSION_END | ATMEL_TSADCC_NOCNT);
++ /* this value is related to the resistor bits value of
++ * ACR register and R64. If internal resistor value is
++ * increased then this value has to be increased. This
++ * behavior seems to happen only with averaging on 8
++ * values
++ */
+ atmel_tsadcc_write(ATMEL_TSADCC_TRGR,
+- ATMEL_TSADCC_TRGMOD_PERIOD | (0x00D0 << 16));
++ ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FF << 16));
+
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+@@ -289,9 +306,20 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM);
+ }
+
++ /* Change adc internal resistor value for better pen detection,
++ * default value is 100 kOhm.
++ * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
++ * option only available on ES2 and higher
++ */
++ if (cpu_has_9x5_adc()) {
++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
++ }
++
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
++ /* atmel_tsadcc_dump_conf(pdev); */
++
+ /* All went ok, so register to the input system */
+ err = input_register_device(input_dev);
+ if (err)
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.h b/drivers/input/touchscreen/atmel_tsadcc.h
+index 572770a..fe74506 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.h
++++ b/drivers/input/touchscreen/atmel_tsadcc.h
+@@ -103,6 +103,9 @@
+ #define ATMEL_TSADCC_NOPEN (1 << 30) /* No Pen Contact */
+ #define ATMEL_TSADCC_PENDET_STATUS (1 << 31) /* Pen Detect Status (not interrupt source) */
+
++#define ATMEL_TSADCC_ACR 0x94 /* Analog Control Register */
++#define ATMEL_TSADCC_PENDET_SENSITIVITY (0x3 << 0) /* ADC internal resistor */
++
+ #define ATMEL_TSADCC_TSMR 0xb0
+ #define ATMEL_TSADCC_TSMODE (3 << 0) /* Touch Screen Mode */
+ #define ATMEL_TSADCC_TSMODE_NO (0 << 0) /* No Touch Screen */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 385b5e2f9342fcf20ad97d4bf788e5e60635d542 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 16 Jun 2011 19:24:04 +0200
+Subject: AT91/input: atmel_tsadcc: rework irq infrastructure and parameters
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 70 ++++++++++++++++++--------------
+ 1 file changed, 40 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 20154ba..397d17a 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -30,6 +30,7 @@
+ #define cpu_has_9x5_adc() (cpu_is_at91sam9x5())
+
+ #define ADC_DEFAULT_CLOCK 100000
++#define ZTHRESHOLD 3200
+
+ struct atmel_tsadcc {
+ struct input_dev *input;
+@@ -39,7 +40,6 @@ struct atmel_tsadcc {
+ unsigned int prev_absx;
+ unsigned int prev_absy;
+ unsigned int prev_absz;
+- unsigned char bufferedmeasure;
+ };
+
+ static void __iomem *tsc_base;
+@@ -62,6 +62,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ {
+ struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
+ struct input_dev *input_dev = ts_dev->input;
++ struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data;
+
+ unsigned int status;
+ unsigned int reg;
+@@ -76,7 +77,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ /* Contact lost */
+ if (cpu_has_9x5_adc()) {
+ /* 9X5 using TSMR to set PENDBC time */
+- reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ATMEL_TSADCC_PENDBC;
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_TSMR) | ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC);
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR, reg);
+ } else {
+ reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC;
+@@ -88,7 +89,6 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+- ts_dev->bufferedmeasure = 0;
+ input_sync(input_dev);
+
+ } else if (status & ATMEL_TSADCC_PENCNT) {
+@@ -118,27 +118,20 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ } else if ((status & ATMEL_TSADCC_CONVERSION_END) == ATMEL_TSADCC_CONVERSION_END) {
+ /* Conversion finished */
+
+- if (ts_dev->bufferedmeasure) {
+- /* Last measurement is always discarded, since it can
+- * be erroneous.
+- * Always report previous measurement */
+- dev_dbg(&input_dev->dev,
+- "x = %d, y = %d, pressure = %d\n",
+- ts_dev->prev_absx, ts_dev->prev_absy,
+- ts_dev->prev_absz);
+- input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
+- input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
+- input_report_key(input_dev, BTN_TOUCH, 1);
+- if (cpu_has_9x5_adc())
+- input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
+- input_sync(input_dev);
+- } else
+- ts_dev->bufferedmeasure = 1;
+-
+- /* Now make new measurement */
++ /* make new measurement */
+ if (cpu_has_9x5_adc()) {
+- ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR) & 0xffff;
+- ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR) & 0xffff;
++ unsigned int xscale, yscale;
++
++ /* calculate position */
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_XPOSR);
++ ts_dev->prev_absx = (reg & ATMEL_TSADCC_XPOS) << 10;
++ xscale = (reg & ATMEL_TSADCC_XSCALE) >> 16;
++ ts_dev->prev_absx /= xscale ? xscale: 1;
++
++ reg = atmel_tsadcc_read(ATMEL_TSADCC_YPOSR);
++ ts_dev->prev_absy = (reg & ATMEL_TSADCC_YPOS) << 10;
++ yscale = (reg & ATMEL_TSADCC_YSCALE) >> 16;
++ ts_dev->prev_absy /= yscale ? yscale: 1 << 10;
+
+ /* calculate the pressure */
+ reg = atmel_tsadcc_read(ATMEL_TSADCC_PRESSR);
+@@ -157,6 +150,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
+ ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
+ }
++
++ /* report measurement to input layer */
++ if (ts_dev->prev_absz < ZTHRESHOLD) {
++ dev_dbg(&input_dev->dev,
++ "x = %d, y = %d, pressure = %d\n",
++ ts_dev->prev_absx, ts_dev->prev_absy,
++ ts_dev->prev_absz);
++ input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
++ input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
++ if (cpu_has_9x5_adc())
++ input_report_abs(input_dev, ABS_PRESSURE, ts_dev->prev_absz);
++ input_report_key(input_dev, BTN_TOUCH, 1);
++ input_sync(input_dev);
++ } else {
++ dev_dbg(&input_dev->dev,
++ "pressure too low: not reporting\n");
++ }
+ }
+
+ return IRQ_HANDLED;
+@@ -233,7 +243,6 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ }
+
+ ts_dev->input = input_dev;
+- ts_dev->bufferedmeasure = 0;
+
+ snprintf(ts_dev->phys, sizeof(ts_dev->phys),
+ "%s/input0", dev_name(&pdev->dev));
+@@ -275,10 +284,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc);
+
+ if (cpu_has_9x5_adc()) {
+- reg = ((0x01 << 5) & ATMEL_TSADCC_SLEEP) | /* Sleep Mode */
+- ((0x01 << 6) & ATMEL_TSADCC_FWUP) | /* Fast Wake Up */
++ reg = ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* no Sleep Mode */
++ ((0x00 << 6) & ATMEL_TSADCC_FWUP) | /* no Fast Wake Up needed */
+ (prsc << 8) |
+- ((0x8 << 16) & ATMEL_TSADCC_STARTUP) |
++ ((0x4 << 16) & ATMEL_TSADCC_STARTUP) |
+ ((pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TRACKTIM);
+ } else {
+ reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE |
+@@ -296,10 +305,10 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ if (cpu_has_9x5_adc()) {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSMR,
+ ATMEL_TSADCC_TSMODE_4WIRE_PRESS |
+- (pdata->filtering_average << 4) | /* Touchscreen average */
++ ((pdata->filtering_average << 4) & ATMEL_TSADCC_TSAV) | /* Touchscreen average */
+ ATMEL_TSADCC_NOTSDMA |
+ ATMEL_TSADCC_PENDET_ENA |
+- (pdata->pendet_debounce << 28) |
++ ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC) |
+ (0x3 << 8)); /* Touchscreen freq */
+ } else {
+ atmel_tsadcc_write(ATMEL_TSADCC_TSR,
+@@ -312,7 +321,8 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ * option only available on ES2 and higher
+ */
+ if (cpu_has_9x5_adc()) {
+- atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
++ if (pdata->pendet_sensitivity <= ATMEL_TSADCC_PENDET_SENSITIVITY)
++ atmel_tsadcc_write(ATMEL_TSADCC_ACR, pdata->pendet_sensitivity);
+ }
+
+ atmel_tsadcc_read(ATMEL_TSADCC_SR);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 705b4b4645cf6f31bc1e267e193388a82b7f2df3 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Fri, 10 Jun 2011 17:21:28 +0200
-Subject: media/video: atmel-isi: add dumb set_parm()
-
-Add dumb set_parm() & get_parm() function to struct soc_camera_host_ops.
-Needed for ffmpeg to be able to capture frames from ISI driver.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/media/video/atmel-isi.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
-index ec3f6a0..7a44df4 100644
---- a/drivers/media/video/atmel-isi.c
-+++ b/drivers/media/video/atmel-isi.c
-@@ -893,6 +893,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
- return 0;
- }
-
-+
-+static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_streamparm *parm)
-+{
-+ return 0;
-+}
-+
- static struct soc_camera_host_ops isi_soc_camera_host_ops = {
- .owner = THIS_MODULE,
- .add = isi_camera_add_device,
-@@ -904,6 +910,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
- .poll = isi_camera_poll,
- .querycap = isi_camera_querycap,
- .set_bus_param = isi_camera_set_bus_param,
-+ .set_parm = isi_camera_set_parm,
-+ .get_parm = isi_camera_set_parm,
- };
-
- /* -----------------------------------------------------------------------*/
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 08f2a486546d5837c09535727250b2c03832c063 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Thu, 7 Jun 2012 14:19:11 +0800
+Subject: input: at91: add tsadcc_data for 9x5
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/board.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
+index 369afc2..726e5f3 100644
+--- a/arch/arm/mach-at91/include/mach/board.h
++++ b/arch/arm/mach-at91/include/mach/board.h
+@@ -175,7 +175,9 @@ extern void __init at91_add_device_isi(struct isi_platform_data *data,
+ /* Touchscreen Controller */
+ struct at91_tsadcc_data {
+ unsigned int adc_clock;
++ u8 filtering_average;
+ u8 pendet_debounce;
++ u8 pendet_sensitivity;
+ u8 ts_sample_hold_time;
+ };
+ extern void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5c29a55f144400febf2dfcdc327253b813113c07 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Mon, 1 Nov 2010 16:38:41 +0800
-Subject: video/atmel_lcdfb: add support for AT91SAM9x5
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
-Signed-off-by: Dan Liang <dan.liang@atmel.com>
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-[ukleinek: forward-port to 2.6.39-rcish]
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-
-Conflicts:
-
- drivers/video/atmel_lcdfb.c
----
- arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 865 +++++++++++++++++++++++++
- drivers/video/atmel_lcdfb.c | 668 ++++++++++++++-----
- include/video/atmel_lcdc.h | 15 +
- 3 files changed, 1389 insertions(+), 159 deletions(-)
- create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
-
-diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
-new file mode 100644
-index 0000000..a57b79b
---- /dev/null
-+++ b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
-@@ -0,0 +1,865 @@
-+/*
-+ * Header file for AT91 High end LCD Controller
-+ *
-+ * Data structure and register user interface
-+ *
-+ * Copyright (C) 2010 Atmel Corporation
-+ *
-+ * 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.
-+ *
-+ * This program 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 PUROFFSETE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ATMEL_HLCD_H__
-+#define __ATMEL_HLCD_H__
-+
-+/* Lcdc hardware registers */
-+#define ATMEL_LCDC_LCDCFG0 0x0000
-+#define LCDC_LCDCFG0_CLKPOL (0x1 << 0)
-+#define LCDC_LCDCFG0_CLKSEL (0x1 << 2)
-+#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
-+#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
-+#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
-+#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
-+#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
-+#define LCDC_LCDCFG0_CLKDIV_OFFSET 16
-+#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG1 0x0004
-+#define LCDC_LCDCFG1_HSPW_OFFSET 0
-+#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET)
-+#define LCDC_LCDCFG1_VSPW_OFFSET 16
-+#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG2 0x0008
-+#define LCDC_LCDCFG2_VFPW_OFFSET 0
-+#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET)
-+#define LCDC_LCDCFG2_VBPW_OFFSET 16
-+#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG3 0x000C
-+#define LCDC_LCDCFG3_HFPW_OFFSET 0
-+#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
-+#define LCDC_LCDCFG3_HBPW_OFFSET 16
-+#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG4 0x0010
-+#define LCDC_LCDCFG4_PPL_OFFSET 0
-+#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET)
-+#define LCDC_LCDCFG4_RPF_OFFSET 16
-+#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG5 0x0014
-+#define LCDC_LCDCFG5_HSPOL (0x1 << 0)
-+#define LCDC_LCDCFG5_VSPOL (0x1 << 1)
-+#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2)
-+#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3)
-+#define LCDC_LCDCFG5_DISPPOL (0x1 << 4)
-+#define LCDC_LCDCFG5_SERIAL (0x1 << 5)
-+#define LCDC_LCDCFG5_DITHER (0x1 << 6)
-+#define LCDC_LCDCFG5_DISPDLY (0x1 << 7)
-+#define LCDC_LCDCFG5_MODE_OFFSET 8
-+#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET)
-+#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8)
-+#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
-+#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
-+#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
-+#define LCDC_LCDCFG5_VSPSU (0x1 << 12)
-+#define LCDC_LCDCFG5_VSPHO (0x1 << 13)
-+#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
-+#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET)
-+
-+#define ATMEL_LCDC_LCDCFG6 0x0018
-+#define LCDC_LCDCFG6_PWMPS_OFFSET 0
-+#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET)
-+#define LCDC_LCDCFG6_PWMPOL (0x1 << 4)
-+#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8
-+#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET)
-+
-+#define ATMEL_LCDC_LCDEN 0x0020
-+#define LCDC_LCDEN_CLKEN (0x1 << 0)
-+#define LCDC_LCDEN_SYNCEN (0x1 << 1)
-+#define LCDC_LCDEN_DISPEN (0x1 << 2)
-+#define LCDC_LCDEN_PWMEN (0x1 << 3)
-+
-+#define ATMEL_LCDC_LCDDIS 0x0024
-+#define LCDC_LCDDIS_CLKDIS (0x1 << 0)
-+#define LCDC_LCDDIS_SYNCDIS (0x1 << 1)
-+#define LCDC_LCDDIS_DISPDIS (0x1 << 2)
-+#define LCDC_LCDDIS_PWMDIS (0x1 << 3)
-+#define LCDC_LCDDIS_CLKRST (0x1 << 8)
-+#define LCDC_LCDDIS_SYNCRST (0x1 << 9)
-+#define LCDC_LCDDIS_DISPRST (0x1 << 10)
-+#define LCDC_LCDDIS_PWMRST (0x1 << 11)
-+
-+#define ATMEL_LCDC_LCDSR 0x0028
-+#define LCDC_LCDSR_CLKSTS (0x1 << 0)
-+#define LCDC_LCDSR_LCDSTS (0x1 << 1)
-+#define LCDC_LCDSR_DISPSTS (0x1 << 2)
-+#define LCDC_LCDSR_PWMSTS (0x1 << 3)
-+#define LCDC_LCDSR_SIPSTS (0x1 << 4)
-+
-+#define ATMEL_LCDC_LCDIER 0x002C
-+#define LCDC_LCDIER_SOFIE (0x1 << 0)
-+#define LCDC_LCDIER_DISIE (0x1 << 1)
-+#define LCDC_LCDIER_DISPIE (0x1 << 2)
-+#define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
-+#define LCDC_LCDIER_BASEIE (0x1 << 8)
-+#define LCDC_LCDIER_OVR1IE (0x1 << 9)
-+#define LCDC_LCDIER_HEOIE (0x1 << 11)
-+#define LCDC_LCDIER_HCRIE (0x1 << 12)
-+
-+#define ATMEL_LCDC_LCDIDR 0x0030
-+#define LCDC_LCDIDR_SOFID (0x1 << 0)
-+#define LCDC_LCDIDR_DISID (0x1 << 1)
-+#define LCDC_LCDIDR_DISPID (0x1 << 2)
-+#define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
-+#define LCDC_LCDIDR_BASEID (0x1 << 8)
-+#define LCDC_LCDIDR_OVR1ID (0x1 << 9)
-+#define LCDC_LCDIDR_HEOID (0x1 << 11)
-+#define LCDC_LCDIDR_HCRID (0x1 << 12)
-+
-+#define ATMEL_LCDC_LCDIMR 0x0034
-+#define LCDC_LCDIMR_SOFIM (0x1 << 0)
-+#define LCDC_LCDIMR_DISIM (0x1 << 1)
-+#define LCDC_LCDIMR_DISPIM (0x1 << 2)
-+#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
-+#define LCDC_LCDIMR_BASEIM (0x1 << 8)
-+#define LCDC_LCDIMR_OVR1IM (0x1 << 9)
-+#define LCDC_LCDIMR_HEOIM (0x1 << 11)
-+#define LCDC_LCDIMR_HCRIM (0x1 << 12)
-+
-+#define ATMEL_LCDC_LCDISR 0x0038
-+#define LCDC_LCDISR_SOF (0x1 << 0)
-+#define LCDC_LCDISR_DIS (0x1 << 1)
-+#define LCDC_LCDISR_DISP (0x1 << 2)
-+#define LCDC_LCDISR_FIFOERR (0x1 << 4)
-+#define LCDC_LCDISR_BASE (0x1 << 8)
-+#define LCDC_LCDISR_OVR1 (0x1 << 9)
-+#define LCDC_LCDISR_HEO (0x1 << 11)
-+#define LCDC_LCDISR_HCR (0x1 << 12)
-+
-+#define ATMEL_LCDC_BASECHER 0x0040
-+#define LCDC_BASECHER_CHEN (0x1 << 0)
-+#define LCDC_BASECHER_UPDATEEN (0x1 << 1)
-+#define LCDC_BASECHER_A2QEN (0x1 << 2)
-+
-+#define ATMEL_LCDC_BASECHDR 0x0044
-+#define LCDC_BASECHDR_CHDIS (0x1 << 0)
-+#define LCDC_BASECHDR_CHRST (0x1 << 8)
-+
-+#define ATMEL_LCDC_BASECHSR 0x0048
-+#define LCDC_BASECHSR_CHSR (0x1 << 0)
-+#define LCDC_BASECHSR_UPDATESR (0x1 << 1)
-+#define LCDC_BASECHSR_A2QSR (0x1 << 2)
-+
-+#define ATMEL_LCDC_BASEIER 0x004C
-+#define LCDC_BASEIER_DMA (0x1 << 2)
-+#define LCDC_BASEIER_DSCR (0x1 << 3)
-+#define LCDC_BASEIER_ADD (0x1 << 4)
-+#define LCDC_BASEIER_DONE (0x1 << 5)
-+#define LCDC_BASEIER_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_BASEIDR 0x0050
-+#define LCDC_BASEIDR_DMA (0x1 << 2)
-+#define LCDC_BASEIDR_DSCR (0x1 << 3)
-+#define LCDC_BASEIDR_ADD (0x1 << 4)
-+#define LCDC_BASEIDR_DONE (0x1 << 5)
-+#define LCDC_BASEIDR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_BASEIMR 0x0054
-+#define LCDC_BASEIMR_DMA (0x1 << 2)
-+#define LCDC_BASEIMR_DSCR (0x1 << 3)
-+#define LCDC_BASEIMR_ADD (0x1 << 4)
-+#define LCDC_BASEIMR_DONE (0x1 << 5)
-+#define LCDC_BASEIMR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_BASEISR 0x0058
-+#define LCDC_BASEISR_DMA (0x1 << 2)
-+#define LCDC_BASEISR_DSCR (0x1 << 3)
-+#define LCDC_BASEISR_ADD (0x1 << 4)
-+#define LCDC_BASEISR_DONE (0x1 << 5)
-+#define LCDC_BASEISR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_BASEHEAD 0x005C
-+
-+#define ATMEL_LCDC_BASEADDR 0x0060
-+
-+#define ATMEL_LCDC_BASECTRL 0x0064
-+#define LCDC_BASECTRL_DFETCH (0x1 << 0)
-+#define LCDC_BASECTRL_LFETCH (0x1 << 1)
-+#define LCDC_BASECTRL_DMAIEN (0x1 << 2)
-+#define LCDC_BASECTRL_DSCRIEN (0x1 << 3)
-+#define LCDC_BASECTRL_ADDIEN (0x1 << 4)
-+#define LCDC_BASECTRL_DONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_BASENEXT 0x0068
-+
-+#define ATMEL_LCDC_BASECFG0 0x006C
-+#define LCDC_BASECFG0_BLEN_OFFSET 4
-+#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
-+#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
-+#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4)
-+#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4)
-+#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4)
-+#define LCDC_BASECFG0_DLBO (0x1 << 8)
-+
-+#define ATMEL_LCDC_BASECFG1 0x0070
-+#define LCDC_BASECFG1_CLUTEN (0x1 << 0)
-+#define LCDC_BASECFG1_RGBMODE_OFFSET 4
-+#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET)
-+#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
-+#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
-+#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
-+#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
-+#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
-+#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
-+#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
-+#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
-+#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
-+#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
-+#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
-+#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
-+#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
-+#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
-+#define LCDC_BASECFG1_CLUTMODE_OFFSET 8
-+#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET)
-+#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8)
-+#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8)
-+#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8)
-+#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8)
-+
-+#define ATMEL_LCDC_BASECFG2 0x0074
-+
-+#define ATMEL_LCDC_BASECFG3 0x0078
-+#define LCDC_BASECFG3_BDEF_OFFSET 0
-+#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET)
-+#define LCDC_BASECFG3_GDEF_OFFSET 8
-+#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET)
-+#define LCDC_BASECFG3_RDEF_OFFSET 16
-+#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET)
-+
-+#define ATMEL_LCDC_BASECFG4 0x007C
-+#define LCDC_BASECFG4_DMA (0x1 << 8)
-+#define LCDC_BASECFG4_REP (0x1 << 9)
-+
-+#define ATMEL_LCDC_OVRCHER1 0x0100
-+#define LCDC_OVRCHER1_CHEN (0x1 << 0)
-+#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
-+#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
-+
-+#define ATMEL_LCDC_OVRCHDR1 0x0104
-+#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
-+#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
-+
-+#define ATMEL_LCDC_OVRCHSR1 0x0108
-+#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
-+#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
-+#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
-+
-+#define ATMEL_LCDC_OVRIER1 0x010C
-+#define LCDC_OVRIER1_DMA (0x1 << 2)
-+#define LCDC_OVRIER1_DSCR (0x1 << 3)
-+#define LCDC_OVRIER1_ADD (0x1 << 4)
-+#define LCDC_OVRIER1_DONE (0x1 << 5)
-+#define LCDC_OVRIER1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRIDR1 0x0110
-+#define LCDC_OVRIDR1_DMA (0x1 << 2)
-+#define LCDC_OVRIDR1_DSCR (0x1 << 3)
-+#define LCDC_OVRIDR1_ADD (0x1 << 4)
-+#define LCDC_OVRIDR1_DONE (0x1 << 5)
-+#define LCDC_OVRIDR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRIMR1 0x0114
-+#define LCDC_OVRIMR1_DMA (0x1 << 2)
-+#define LCDC_OVRIMR1_DSCR (0x1 << 3)
-+#define LCDC_OVRIMR1_ADD (0x1 << 4)
-+#define LCDC_OVRIMR1_DONE (0x1 << 5)
-+#define LCDC_OVRIMR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRISR1 0x0118
-+#define LCDC_OVRISR1_DMA (0x1 << 2)
-+#define LCDC_OVRISR1_DSCR (0x1 << 3)
-+#define LCDC_OVRISR1_ADD (0x1 << 4)
-+#define LCDC_OVRISR1_DONE (0x1 << 5)
-+#define LCDC_OVRISR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRHEAD1 0x011C
-+
-+#define ATMEL_LCDC_OVRADDR1 0x0120
-+
-+#define ATMEL_LCDC_OVRCTRL1 0x0124
-+#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
-+#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
-+#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
-+#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
-+#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
-+#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_OVRNEXT1 0x0128
-+
-+#define ATMEL_LCDC_OVR1CFG0 0x012C
-+#define LCDC_OVR1CFG0_BLEN_OFFSET 4
-+#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
-+#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
-+#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
-+#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
-+#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
-+
-+#define ATMEL_LCDC_OVR1CFG1 0x0130
-+#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
-+#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
-+#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
-+#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
-+#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
-+#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
-+#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
-+
-+#define ATMEL_LCDC_OVR1CFG2 0x0134
-+#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
-+#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
-+#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
-+#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG3 0x0138
-+#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
-+#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
-+#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
-+#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG4 0x013C
-+
-+#define ATMEL_LCDC_OVR1CFG5 0x0140
-+
-+#define ATMEL_LCDC_OVR1CFG6 0x0144
-+#define LCDC_OVR1CFG6_BDEF_OFFSET 0
-+#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
-+#define LCDC_OVR1CFG6_GDEF_OFFSET 8
-+#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
-+#define LCDC_OVR1CFG6_RDEF_OFFSET 16
-+#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG7 0x0148
-+#define LCDC_OVR1CFG7_BKEY_OFFSET 0
-+#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
-+#define LCDC_OVR1CFG7_GKEY_OFFSET 8
-+#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
-+#define LCDC_OVR1CFG7_RKEY_OFFSET 16
-+#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG8 0x014C
-+#define LCDC_OVR1CFG8_BMASK_OFFSET 0
-+#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
-+#define LCDC_OVR1CFG8_GMASK_OFFSET 8
-+#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
-+#define LCDC_OVR1CFG8_RMASK_OFFSET 16
-+#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG9 0x0150
-+#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
-+#define LCDC_OVR1CFG9_INV (0x1 << 1)
-+#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
-+#define LCDC_OVR1CFG9_ITER (0x1 << 3)
-+#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
-+#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
-+#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
-+#define LCDC_OVR1CFG9_OVR (0x1 << 7)
-+#define LCDC_OVR1CFG9_DMA (0x1 << 8)
-+#define LCDC_OVR1CFG9_REP (0x1 << 9)
-+#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
-+#define LCDC_OVR1CFG9_GA_OFFSET 16
-+#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCHER 0x0280
-+#define LCDC_HEOCHER_CHEN (0x1 << 0)
-+#define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
-+#define LCDC_HEOCHER_A2QEN (0x1 << 2)
-+
-+#define ATMEL_LCDC_HEOCHDR 0x0284
-+#define LCDC_HEOCHDR_CHDIS (0x1 << 0)
-+#define LCDC_HEOCHDR_CHRST (0x1 << 8)
-+
-+#define ATMEL_LCDC_HEOCHSR 0x0288
-+#define LCDC_HEOCHSR_CHSR (0x1 << 0)
-+#define LCDC_HEOCHSR_UPDATESR (0x1 << 1)
-+#define LCDC_HEOCHSR_A2QSR (0x1 << 2)
-+
-+#define ATMEL_LCDC_HEOIER 0x028C
-+#define LCDC_HEOIER_DMA (0x1 << 2)
-+#define LCDC_HEOIER_DSCR (0x1 << 3)
-+#define LCDC_HEOIER_ADD (0x1 << 4)
-+#define LCDC_HEOIER_DONE (0x1 << 5)
-+#define LCDC_HEOIER_OVR (0x1 << 6)
-+#define LCDC_HEOIER_UDMA (0x1 << 10)
-+#define LCDC_HEOIER_UDSCR (0x1 << 11)
-+#define LCDC_HEOIER_UADD (0x1 << 12)
-+#define LCDC_HEOIER_UDONE (0x1 << 13)
-+#define LCDC_HEOIER_UOVR (0x1 << 14)
-+#define LCDC_HEOIER_VDMA (0x1 << 18)
-+#define LCDC_HEOIER_VDSCR (0x1 << 19)
-+#define LCDC_HEOIER_VADD (0x1 << 20)
-+#define LCDC_HEOIER_VDONE (0x1 << 21)
-+#define LCDC_HEOIER_VOVR (0x1 << 22)
-+
-+#define ATMEL_LCDC_HEOIDR 0x0290
-+#define LCDC_HEOIDR_DMA (0x1 << 2)
-+#define LCDC_HEOIDR_DSCR (0x1 << 3)
-+#define LCDC_HEOIDR_ADD (0x1 << 4)
-+#define LCDC_HEOIDR_DONE (0x1 << 5)
-+#define LCDC_HEOIDR_OVR (0x1 << 6)
-+#define LCDC_HEOIDR_UDMA (0x1 << 10)
-+#define LCDC_HEOIDR_UDSCR (0x1 << 11)
-+#define LCDC_HEOIDR_UADD (0x1 << 12)
-+#define LCDC_HEOIDR_UDONE (0x1 << 13)
-+#define LCDC_HEOIDR_UOVR (0x1 << 14)
-+#define LCDC_HEOIDR_VDMA (0x1 << 18)
-+#define LCDC_HEOIDR_VDSCR (0x1 << 19)
-+#define LCDC_HEOIDR_VADD (0x1 << 20)
-+#define LCDC_HEOIDR_VDONE (0x1 << 21)
-+#define LCDC_HEOIDR_VOVR (0x1 << 22)
-+
-+#define ATMEL_LCDC_HEOIMR 0x0294
-+#define LCDC_HEOIMR_DMA (0x1 << 2)
-+#define LCDC_HEOIMR_DSCR (0x1 << 3)
-+#define LCDC_HEOIMR_ADD (0x1 << 4)
-+#define LCDC_HEOIMR_DONE (0x1 << 5)
-+#define LCDC_HEOIMR_OVR (0x1 << 6)
-+#define LCDC_HEOIMR_UDMA (0x1 << 10)
-+#define LCDC_HEOIMR_UDSCR (0x1 << 11)
-+#define LCDC_HEOIMR_UADD (0x1 << 12)
-+#define LCDC_HEOIMR_UDONE (0x1 << 13)
-+#define LCDC_HEOIMR_UOVR (0x1 << 14)
-+#define LCDC_HEOIMR_VDMA (0x1 << 18)
-+#define LCDC_HEOIMR_VDSCR (0x1 << 19)
-+#define LCDC_HEOIMR_VADD (0x1 << 20)
-+#define LCDC_HEOIMR_VDONE (0x1 << 21)
-+#define LCDC_HEOIMR_VOVR (0x1 << 22)
-+
-+#define ATMEL_LCDC_HEOISR 0x0298
-+#define LCDC_HEOISR_DMA (0x1 << 2)
-+#define LCDC_HEOISR_DSCR (0x1 << 3)
-+#define LCDC_HEOISR_ADD (0x1 << 4)
-+#define LCDC_HEOISR_DONE (0x1 << 5)
-+#define LCDC_HEOISR_OVR (0x1 << 6)
-+#define LCDC_HEOISR_UDMA (0x1 << 10)
-+#define LCDC_HEOISR_UDSCR (0x1 << 11)
-+#define LCDC_HEOISR_UADD (0x1 << 12)
-+#define LCDC_HEOISR_UDONE (0x1 << 13)
-+#define LCDC_HEOISR_UOVR (0x1 << 14)
-+#define LCDC_HEOISR_VDMA (0x1 << 18)
-+#define LCDC_HEOISR_VDSCR (0x1 << 19)
-+#define LCDC_HEOISR_VADD (0x1 << 20)
-+#define LCDC_HEOISR_VDONE (0x1 << 21)
-+#define LCDC_HEOISR_VOVR (0x1 << 22)
-+
-+#define ATMEL_LCDC_HEOHEAD 0x029C
-+
-+#define ATMEL_LCDC_HEOADDR 0x02A0
-+
-+#define ATMEL_LCDC_HEOCTRL 0x02A4
-+#define LCDC_HEOCTRL_DFETCH (0x1 << 0)
-+#define LCDC_HEOCTRL_LFETCH (0x1 << 1)
-+#define LCDC_HEOCTRL_DMAIEN (0x1 << 2)
-+#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3)
-+#define LCDC_HEOCTRL_ADDIEN (0x1 << 4)
-+#define LCDC_HEOCTRL_DONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_HEONEXT 0x02A8
-+
-+#define ATMEL_LCDC_HEOUHEAD 0x02AC
-+
-+#define ATMEL_LCDC_HEOUADDR 0x02B0
-+
-+#define ATMEL_LCDC_HEOUCTRL 0x02B4
-+#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0)
-+#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2)
-+#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3)
-+#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4)
-+#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_HEOUNEXT 0x02B8
-+
-+#define ATMEL_LCDC_HEOVHEAD 0x02BC
-+
-+#define ATMEL_LCDC_HEOVADDR 0x02C0
-+
-+#define ATMEL_LCDC_HEOVCTRL 0x02C4
-+#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0)
-+#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2)
-+#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3)
-+#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4)
-+#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_HEOVNEXT 0x02C8
-+
-+#define ATMEL_LCDC_HEOCFG0 0x02CC
-+#define LCDC_HEOCFG0_BLEN_OFFSET 4
-+#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET)
-+#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4)
-+#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4)
-+#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4)
-+#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4)
-+#define LCDC_HEOCFG0_BLENUV_OFFSET 6
-+#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET)
-+#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6)
-+#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6)
-+#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6)
-+#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6)
-+#define LCDC_HEOCFG0_DLBO (0x1 << 8)
-+#define LCDC_HEOCFG0_ROTDIS (0x1 << 12)
-+#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13)
-+
-+#define ATMEL_LCDC_HEOCFG1 0x02D0
-+#define LCDC_HEOCFG1_CLUTEN (0x1 << 0)
-+#define LCDC_HEOCFG1_YUVEN (0x1 << 1)
-+#define LCDC_HEOCFG1_RGBMODE_OFFSET 4
-+#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET)
-+#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
-+#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
-+#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
-+#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
-+#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
-+#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8
-+#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET)
-+#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8)
-+#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8)
-+#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8)
-+#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8)
-+#define LCDC_HEOCFG1_YUVMODE_OFFSET 12
-+#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET)
-+#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12)
-+#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12)
-+#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16)
-+#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17)
-+
-+#define ATMEL_LCDC_HEOCFG2 0x02D4
-+#define LCDC_HEOCFG2_XOFFSET_OFFSET 0
-+#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET)
-+#define LCDC_HEOCFG2_YOFFSET_OFFSET 16
-+#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG3 0x02D8
-+#define LCDC_HEOCFG3_XSIZE_OFFSET 0
-+#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET)
-+#define LCDC_HEOCFG3_YSIZE_OFFSET 16
-+#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG4 0x02DC
-+#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0
-+#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET)
-+#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16
-+#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG5 0x02E0
-+
-+#define ATMEL_LCDC_HEOCFG6 0x02E4
-+
-+#define ATMEL_LCDC_HEOCFG7 0x02E8
-+
-+#define ATMEL_LCDC_HEOCFG8 0x02EC
-+
-+#define ATMEL_LCDC_HEOCFG9 0x02F0
-+#define LCDC_HEOCFG9_BDEF_OFFSET 0
-+#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET)
-+#define LCDC_HEOCFG9_GDEF_OFFSET 8
-+#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET)
-+#define LCDC_HEOCFG9_RDEF_OFFSET 16
-+#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG10 0x02F4
-+#define LCDC_HEOCFG10_BKEY_OFFSET 0
-+#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET)
-+#define LCDC_HEOCFG10_GKEY_OFFSET 8
-+#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET)
-+#define LCDC_HEOCFG10_RKEY_OFFSET 16
-+#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG11 0x02F8
-+#define LCDC_HEOCFG11_BMASK_OFFSET 0
-+#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET)
-+#define LCDC_HEOCFG11_GMASK_OFFSET 8
-+#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET)
-+#define LCDC_HEOCFG11_RMASK_OFFSET 16
-+#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG12 0x02FC
-+#define LCDC_HEOCFG12_CRKEY (0x1 << 0)
-+#define LCDC_HEOCFG12_INV (0x1 << 1)
-+#define LCDC_HEOCFG12_ITER2BL (0x1 << 2)
-+#define LCDC_HEOCFG12_ITER (0x1 << 3)
-+#define LCDC_HEOCFG12_REVALPHA (0x1 << 4)
-+#define LCDC_HEOCFG12_GAEN (0x1 << 5)
-+#define LCDC_HEOCFG12_LAEN (0x1 << 6)
-+#define LCDC_HEOCFG12_OVR (0x1 << 7)
-+#define LCDC_HEOCFG12_DMA (0x1 << 8)
-+#define LCDC_HEOCFG12_REP (0x1 << 9)
-+#define LCDC_HEOCFG12_DSTKEY (0x1 << 10)
-+#define LCDC_HEOCFG12_VIDPRI (0x1 << 12)
-+#define LCDC_HEOCFG12_GA_OFFSET 16
-+#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCFG13 0x0300
-+#define LCDC_HEOCFG13_XFACTOR_OFFSET 0
-+#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET)
-+#define LCDC_HEOCFG13_YFACTOR_OFFSET 16
-+#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET)
-+#define LCDC_HEOCFG13_SCALEN (0x1 << 31)
-+
-+#define ATMEL_LCDC_HEOCFG14 0x0304
-+#define LCDC_HEOCFG14_CSCRY_OFFSET 0
-+#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET)
-+#define LCDC_HEOCFG14_CSCRU_OFFSET 10
-+#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET)
-+#define LCDC_HEOCFG14_CSCRV_OFFSET 20
-+#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET)
-+#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30)
-+
-+#define ATMEL_LCDC_HEOCFG15 0x0308
-+#define LCDC_HEOCFG15_CSCGY_OFFSET 0
-+#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET)
-+#define LCDC_HEOCFG15_CSCGU_OFFSET 10
-+#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET)
-+#define LCDC_HEOCFG15_CSCGV_OFFSET 20
-+#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET)
-+#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30)
-+
-+#define ATMEL_LCDC_HEOCFG16 0x030C
-+#define LCDC_HEOCFG16_CSCBY_OFFSET 0
-+#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET)
-+#define LCDC_HEOCFG16_CSCBU_OFFSET 10
-+#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET)
-+#define LCDC_HEOCFG16_CSCBV_OFFSET 20
-+#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET)
-+#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30)
-+
-+#define ATMEL_LCDC_HCRCHER 0x0340
-+#define LCDC_HCRCHER_CHEN (0x1 << 0)
-+#define LCDC_HCRCHER_UPDATEEN (0x1 << 1)
-+#define LCDC_HCRCHER_A2QEN (0x1 << 2)
-+
-+#define ATMEL_LCDC_HCRCHDR 0x0344
-+#define LCDC_HCRCHDR_CHDIS (0x1 << 0)
-+#define LCDC_HCRCHDR_CHRST (0x1 << 8)
-+
-+#define ATMEL_LCDC_HCRCHSR 0x0348
-+#define LCDC_HCRCHSR_CHSR (0x1 << 0)
-+#define LCDC_HCRCHSR_UPDATESR (0x1 << 1)
-+#define LCDC_HCRCHSR_A2QSR (0x1 << 2)
-+
-+#define ATMEL_LCDC_HCRIER 0x034C
-+#define LCDC_HCRIER_DMA (0x1 << 2)
-+#define LCDC_HCRIER_DSCR (0x1 << 3)
-+#define LCDC_HCRIER_ADD (0x1 << 4)
-+#define LCDC_HCRIER_DONE (0x1 << 5)
-+#define LCDC_HCRIER_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_HCRIDR 0x0350
-+#define LCDC_HCRIDR_DMA (0x1 << 2)
-+#define LCDC_HCRIDR_DSCR (0x1 << 3)
-+#define LCDC_HCRIDR_ADD (0x1 << 4)
-+#define LCDC_HCRIDR_DONE (0x1 << 5)
-+#define LCDC_HCRIDR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_HCRIMR 0x0354
-+#define LCDC_HCRIMR_DMA (0x1 << 2)
-+#define LCDC_HCRIMR_DSCR (0x1 << 3)
-+#define LCDC_HCRIMR_ADD (0x1 << 4)
-+#define LCDC_HCRIMR_DONE (0x1 << 5)
-+#define LCDC_HCRIMR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_HCRISR 0x0358
-+#define LCDC_HCRISR_DMA (0x1 << 2)
-+#define LCDC_HCRISR_DSCR (0x1 << 3)
-+#define LCDC_HCRISR_ADD (0x1 << 4)
-+#define LCDC_HCRISR_DONE (0x1 << 5)
-+#define LCDC_HCRISR_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_HCRHEAD 0x035C
-+
-+#define ATMEL_LCDC_HCRADDR 0x0360
-+
-+#define ATMEL_LCDC_HCRCTRL 0x0364
-+#define LCDC_HCRCTRL_DFETCH (0x1 << 0)
-+#define LCDC_HCRCTRL_LFETCH (0x1 << 1)
-+#define LCDC_HCRCTRL_DMAIEN (0x1 << 2)
-+#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3)
-+#define LCDC_HCRCTRL_ADDIEN (0x1 << 4)
-+#define LCDC_HCRCTRL_DONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_HCRNEXT 0x0368
-+
-+#define ATMEL_LCDC_HCRCFG0 0x036C
-+#define LCDC_HCRCFG0_BLEN_OFFSET 4
-+#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET)
-+#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4)
-+#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4)
-+#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4)
-+#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4)
-+#define LCDC_HCRCFG0_DLBO (0x1 << 8)
-+
-+#define ATMEL_LCDC_HCRCFG1 0x0370
-+#define LCDC_HCRCFG1_CLUTEN (0x1 << 0)
-+#define LCDC_HCRCFG1_RGBMODE_OFFSET 4
-+#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET)
-+#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
-+#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
-+#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
-+#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
-+#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
-+#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8
-+#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET)
-+#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8)
-+#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8)
-+#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8)
-+#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8)
-+
-+#define ATMEL_LCDC_HCRCFG2 0x0374
-+#define LCDC_HCRCFG2_XOFFSET_OFFSET 0
-+#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET)
-+#define LCDC_HCRCFG2_YOFFSET_OFFSET 16
-+#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCFG3 0x0378
-+#define LCDC_HCRCFG3_XSIZE_OFFSET 0
-+#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET)
-+#define LCDC_HCRCFG3_YSIZE_OFFSET 16
-+#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCFG4 0x037C
-+
-+#define ATMEL_LCDC_HCRCFG6 0x0384
-+#define LCDC_HCRCFG6_BDEF_OFFSET 0
-+#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET)
-+#define LCDC_HCRCFG6_GDEF_OFFSET 8
-+#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET)
-+#define LCDC_HCRCFG6_RDEF_OFFSET 16
-+#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCFG7 0x0388
-+#define LCDC_HCRCFG7_BKEY_OFFSET 0
-+#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET)
-+#define LCDC_HCRCFG7_GKEY_OFFSET 8
-+#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET)
-+#define LCDC_HCRCFG7_RKEY_OFFSET 16
-+#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCFG8 0x038C
-+#define LCDC_HCRCFG8_BMASK_OFFSET 0
-+#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET)
-+#define LCDC_HCRCFG8_GMASK_OFFSET 8
-+#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET)
-+#define LCDC_HCRCFG8_RMASK_OFFSET 16
-+#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCFG9 0x0390
-+#define LCDC_HCRCFG9_CRKEY (0x1 << 0)
-+#define LCDC_HCRCFG9_INV (0x1 << 1)
-+#define LCDC_HCRCFG9_ITER2BL (0x1 << 2)
-+#define LCDC_HCRCFG9_ITER (0x1 << 3)
-+#define LCDC_HCRCFG9_REVALPHA (0x1 << 4)
-+#define LCDC_HCRCFG9_GAEN (0x1 << 5)
-+#define LCDC_HCRCFG9_LAEN (0x1 << 6)
-+#define LCDC_HCRCFG9_OVR (0x1 << 7)
-+#define LCDC_HCRCFG9_DMA (0x1 << 8)
-+#define LCDC_HCRCFG9_REP (0x1 << 9)
-+#define LCDC_HCRCFG9_DSTKEY (0x1 << 10)
-+#define LCDC_HCRCFG9_GA_OFFSET 16
-+#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
-+
-+#define ATMEL_LCDC_BASECLUT 0x400
-+#define LCDC_BASECLUT_BCLUT_OFFSET 0
-+#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
-+#define LCDC_BASECLUT_GCLUT_OFFSET 8
-+#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET)
-+#define LCDC_BASECLUT_RCLUT_OFFSET 16
-+#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CLUT 0x800
-+#define LCDC_OVR1CLUT_BCLUT_OFFSET 0
-+#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
-+#define LCDC_OVR1CLUT_GCLUT_OFFSET 8
-+#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET)
-+#define LCDC_OVR1CLUT_RCLUT_OFFSET 16
-+#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET)
-+#define LCDC_OVR1CLUT_ACLUT_OFFSET 24
-+#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
-+
-+#define ATMEL_LCDC_HEOCLUT 0x1000
-+#define LCDC_HEOCLUT_BCLUT_OFFSET 0
-+#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
-+#define LCDC_HEOCLUT_GCLUT_OFFSET 8
-+#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET)
-+#define LCDC_HEOCLUT_RCLUT_OFFSET 16
-+#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET)
-+#define LCDC_HEOCLUT_ACLUT_OFFSET 24
-+#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
-+
-+#define ATMEL_LCDC_HCRCLUT 0x1400
-+#define LCDC_HCRCLUT_BCLUT_OFFSET 0
-+#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
-+#define LCDC_HCRCLUT_GCLUT_OFFSET 8
-+#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET)
-+#define LCDC_HCRCLUT_RCLUT_OFFSET 16
-+#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET)
-+#define LCDC_HCRCLUT_ACLUT_OFFSET 24
-+#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
-+
-+/* Base layer CLUT */
-+#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
-+
-+
-+#endif /* __ATMEL_HLCDC4_H__ */
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index d99505b..c35f5c7 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -1,7 +1,7 @@
- /*
- * Driver for AT91/AT32 LCD Controller
- *
-- * Copyright (C) 2007 Atmel Corporation
-+ * Copyright (C) 2007-2010 Atmel Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
-@@ -25,6 +25,7 @@
- #include <asm/gpio.h>
-
- #include <video/atmel_lcdc.h>
-+#include <mach/atmel_hlcdfb.h>
-
- #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
- #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
-@@ -76,6 +77,9 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
- | ATMEL_LCDC_POL_POSITIVE
- | ATMEL_LCDC_ENA_PWMENABLE;
-
-+static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
-+ | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
-+
- #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-
- /* some bl->props field just changed */
-@@ -84,6 +88,7 @@ static int atmel_bl_update_status(struct backlight_device *bl)
- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
- int power = sinfo->bl_power;
- int brightness = bl->props.brightness;
-+ u32 reg;
-
- /* REVISIT there may be a meaningful difference between
- * fb_blank and power ... there seem to be some cases
-@@ -94,17 +99,28 @@ static int atmel_bl_update_status(struct backlight_device *bl)
- else if (bl->props.power != sinfo->bl_power)
- power = bl->props.power;
-
-- if (brightness < 0 && power == FB_BLANK_UNBLANK)
-- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-- else if (power != FB_BLANK_UNBLANK)
-+ if (brightness < 0 && power == FB_BLANK_UNBLANK) {
-+ if (cpu_is_at91sam9x5())
-+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
-+ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+ else
-+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ } else if (power != FB_BLANK_UNBLANK) {
- brightness = 0;
-+ }
-
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-- brightness ? contrast_ctr : 0);
-- else
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+ if (cpu_is_at91sam9x5()) {
-+ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
-+ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
-+ } else {
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-+ if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-+ brightness ? contrast_ctr : 0);
-+ else
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+ }
-
- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
-
-@@ -115,7 +131,10 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
- {
- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-
-- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ if (cpu_is_at91sam9x5())
-+ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+ else
-+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
- }
-
- static const struct backlight_ops atmel_lcdc_bl_ops = {
-@@ -171,14 +190,17 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-
- static void init_contrast(struct atmel_lcdfb_info *sinfo)
- {
-- /* contrast pwm can be 'inverted' */
-- if (sinfo->lcdcon_pol_negative)
-- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
--
-- /* have some default contrast/backlight settings */
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
--
-+ if (cpu_is_at91sam9x5()) {
-+ /* have some default contrast/backlight settings */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
-+ } else {
-+ /* contrast pwm can be 'inverted' */
-+ if (sinfo->lcdcon_pol_negative)
-+ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
-+ /* have some default contrast/backlight settings */
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
-+ }
- if (sinfo->lcdcon_is_backlight)
- init_backlight(sinfo);
- }
-@@ -220,32 +242,78 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
-
- static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
- {
-- /* Turn off the LCD controller and the DMA controller */
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-+ if (cpu_is_at91sam9x5()) {
-+ /* Disable DISP signal */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-+ msleep(1);
-+ /* Disable synchronization */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-+ msleep(1);
-+ /* Disable pixel clock */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-+ msleep(1);
-+ /* Disable PWM */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-+ msleep(1);
-+ } else {
-+ /* Turn off the LCD controller and the DMA controller */
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-
-- /* Wait for the LCDC core to become idle */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-- msleep(10);
-+ /* Wait for the LCDC core to become idle */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-+ msleep(10);
-
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-+ }
- }
-
- static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
- {
- atmel_lcdfb_stop_nowait(sinfo);
-
-- /* Wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
-+ if (cpu_is_at91sam9x5()) {
-+ /* Wait for the end of DMA transfer */
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
-+ msleep(10);
-+ } else {
-+ /* Wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+ }
- }
-
- static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
- {
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-- | ATMEL_LCDC_PWR);
-+ u32 value;
-+
-+ if (cpu_is_at91sam9x5()) {
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-+ msleep(1);
-+ } else {
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-+ | ATMEL_LCDC_PWR);
-+ }
- }
-
- static void atmel_lcdfb_update_dma(struct fb_info *info,
-@@ -254,14 +322,31 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
- struct atmel_lcdfb_info *sinfo = info->par;
- struct fb_fix_screeninfo *fix = &info->fix;
- unsigned long dma_addr;
-+ struct lcd_dma_desc *desc;
-
- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
- + var->xoffset * info->var.bits_per_pixel / 8);
-
- dma_addr &= ~3UL;
-
-- /* Set framebuffer DMA base address and pixel offset */
-- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-+ if (cpu_is_at91sam9x5()) {
-+ /* Setup the DMA descriptor, this descriptor will loop to itself */
-+ desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
-+
-+ desc->address = dma_addr;
-+ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
-+ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
-+ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
-+ desc->next = sinfo->dma_desc_phys;
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
-+ } else {
-+ /* Set framebuffer DMA base address and pixel offset */
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-+ }
-
- atmel_lcdfb_update_dma2d(sinfo, var, info);
- }
-@@ -272,12 +357,18 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
-
- dma_free_writecombine(info->device, info->fix.smem_len,
- info->screen_base, info->fix.smem_start);
-+
-+ if (cpu_is_at91sam9x5()) {
-+ if (sinfo->p_dma_desc)
-+ dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
-+ sinfo->p_dma_desc, sinfo->dma_desc_phys);
-+ }
- }
-
- /**
- * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
- * @sinfo: the frame buffer to allocate memory for
-- *
-+ *
- * This function is called only from the atmel_lcdfb_probe()
- * so no locking by fb_info->mm_lock around smem_len setting is needed.
- */
-@@ -300,6 +391,19 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
-
- memset(info->screen_base, 0, info->fix.smem_len);
-
-+ if (cpu_is_at91sam9x5()) {
-+ sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
-+ sizeof(struct lcd_dma_desc),
-+ (dma_addr_t *)&(sinfo->dma_desc_phys),
-+ GFP_KERNEL);
-+
-+ if (!sinfo->p_dma_desc) {
-+ dma_free_writecombine(info->device, info->fix.smem_len,
-+ info->screen_base, info->fix.smem_start);
-+ return -ENOMEM;
-+ }
-+ }
-+
- return 0;
- }
-
-@@ -393,18 +497,33 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
- }
-
- /* Saturate vertical and horizontal timings at maximum values */
-- var->vsync_len = min_t(u32, var->vsync_len,
-- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-- var->upper_margin = min_t(u32, var->upper_margin,
-- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-- var->lower_margin = min_t(u32, var->lower_margin,
-- ATMEL_LCDC_VFP);
-- var->right_margin = min_t(u32, var->right_margin,
-- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-- var->hsync_len = min_t(u32, var->hsync_len,
-- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-- var->left_margin = min_t(u32, var->left_margin,
-- ATMEL_LCDC_HBP + 1);
-+ if (cpu_is_at91sam9x5()) {
-+ var->vsync_len = min_t(u32, var->vsync_len,
-+ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
-+ var->upper_margin = min_t(u32, var->upper_margin,
-+ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
-+ var->lower_margin = min_t(u32, var->lower_margin,
-+ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
-+ var->right_margin = min_t(u32, var->right_margin,
-+ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
-+ var->hsync_len = min_t(u32, var->hsync_len,
-+ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
-+ var->left_margin = min_t(u32, var->left_margin,
-+ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-+ } else {
-+ var->vsync_len = min_t(u32, var->vsync_len,
-+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-+ var->upper_margin = min_t(u32, var->upper_margin,
-+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-+ var->lower_margin = min_t(u32, var->lower_margin,
-+ ATMEL_LCDC_VFP);
-+ var->right_margin = min_t(u32, var->right_margin,
-+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-+ var->hsync_len = min_t(u32, var->hsync_len,
-+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-+ var->left_margin = min_t(u32, var->left_margin,
-+ ATMEL_LCDC_HBP + 1);
-+ }
-
- /* Some parameters can't be zero */
- var->vsync_len = max_t(u32, var->vsync_len, 1);
-@@ -419,9 +538,53 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
- case 8:
- var->red.offset = var->green.offset = var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length
-- = var->bits_per_pixel;
-+ = var->bits_per_pixel;
-+ break;
-+ case 12:
-+ if (cpu_is_at91sam9x5()) {
-+ /* RGB:444 mode */
-+ var->red.offset = 8;
-+ var->blue.offset = 0;
-+ var->green.offset = 4;
-+ var->red.length = var->green.length = var->blue.length = 4;
-+ } else {
-+ /*TODO: rework*/
-+ BUG();
-+ }
-+ break;
-+ case 15:
-+ if (cpu_is_at91sam9x5()) {
-+ /* RGB:555 mode */
-+ var->red.offset = 10;
-+ var->blue.offset = 0;
-+ var->green.length = 5;
-+ var->red.length = var->green.length = var->blue.length = 5;
-+ } else {
-+ /*TODO: rework*/
-+ BUG();
-+ }
- break;
- case 16:
-+ if (cpu_is_at91sam9x5()) {
-+ if (sinfo->alpha_enabled) {
-+ /* ARGB:4444 mode */
-+ var->red.offset = 8;
-+ var->blue.offset = 0;
-+ var->green.offset = 4;
-+ var->transp.offset = 12;
-+ var->red.length = var->green.length
-+ = var->blue.length
-+ = var->transp.length = 4;
-+ } else {
-+ /* RGB:565 mode */
-+ var->red.offset = 11;
-+ var->blue.offset = 0;
-+ var->green.offset = 5;
-+ var->green.length = 6;
-+ var->red.length = var->blue.length = 5;
-+ }
-+ break;
-+ }
- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
- /* RGB:565 mode */
- var->red.offset = 11;
-@@ -436,6 +599,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
- var->red.length = var->blue.length = 5;
- break;
- case 32:
-+ /* TODO 32 & 24 modes */
- var->transp.offset = 24;
- var->transp.length = 8;
- /* fall through */
-@@ -472,6 +636,252 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
- atmel_lcdfb_start(sinfo);
- }
-
-+static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long value;
-+ unsigned long clk_value_khz;
-+
-+ dev_dbg(info->device, "%s:\n", __func__);
-+ /* Set pixel clock */
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+
-+ if (value < 1) {
-+ dev_notice(info->device, "using system clock as pixel clock\n");
-+ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-+ } else {
-+ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
-+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-+ PICOS2KHZ(info->var.pixclock));
-+ value = value - 2;
-+ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
-+ value);
-+ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
-+ | LCDC_LCDCFG0_CLKPOL
-+ | LCDC_LCDCFG0_CGDISBASE;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-+ }
-+
-+ /* Initialize control register 5 */
-+ value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
-+ | LCDC_LCDCFG5_DISPDLY
-+ | LCDC_LCDCFG5_VSPDLYS;
-+
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ value |= LCDC_LCDCFG5_HSPOL;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ value |= LCDC_LCDCFG5_VSPOL;
-+
-+ switch (info->var.bits_per_pixel) {
-+ case 12:
-+ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
-+ break;
-+ case 16:
-+ if (info->var.transp.offset != 0)
-+ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
-+ else
-+ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
-+ break;
-+ case 18:
-+ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
-+ break;
-+ case 24:
-+ case 32:
-+ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
-+
-+ /* Vertical & Horizontal Timing */
-+ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
-+ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
-+
-+ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
-+ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
-+
-+ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
-+ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
-+
-+ /* Display size */
-+ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
-+ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
-+ switch (info->var.bits_per_pixel) {
-+ case 12:
-+ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
-+ break;
-+ case 16:
-+ if (info->var.transp.offset != 0)
-+ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
-+ else
-+ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
-+ break;
-+ case 18:
-+ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
-+ break;
-+ case 24:
-+ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
-+ break;
-+ case 32:
-+ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
-+
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-+ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
-+
-+ return 0;
-+}
-+
-+static int atmel_lcdfb_setup_core(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long hozval_linesz;
-+ unsigned long value;
-+ unsigned long clk_value_khz;
-+ unsigned long pix_factor = 2;
-+
-+ if (cpu_is_at91sam9x5()) {
-+ return atmel_lcdfb_setup_9x5_core(info);
-+ } else {
-+ /* ...set frame size and burst length = 8 words (?) */
-+ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-+ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
-+
-+ /* Set pixel clock */
-+ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-+ pix_factor = 1;
-+
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+
-+ if (value < pix_factor) {
-+ dev_notice(info->device, "Bypassing pixel clock divider\n");
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-+ } else {
-+ value = (value / pix_factor) - 1;
-+ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-+ value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-+ value << ATMEL_LCDC_CLKVAL_OFFSET);
-+ info->var.pixclock =
-+ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-+ PICOS2KHZ(info->var.pixclock));
-+ }
-+
-+
-+ /* Initialize control register 2 */
-+ value = sinfo->default_lcdcon2;
-+
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVLINE_INVERTED;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVFRAME_INVERTED;
-+
-+ switch (info->var.bits_per_pixel) {
-+ case 1:
-+ value |= ATMEL_LCDC_PIXELSIZE_1;
-+ break;
-+ case 2:
-+ value |= ATMEL_LCDC_PIXELSIZE_2;
-+ break;
-+ case 4:
-+ value |= ATMEL_LCDC_PIXELSIZE_4;
-+ break;
-+ case 8:
-+ value |= ATMEL_LCDC_PIXELSIZE_8;
-+ break;
-+ case 15: /* fall through */
-+ case 16:
-+ value |= ATMEL_LCDC_PIXELSIZE_16;
-+ break;
-+ case 24:
-+ value |= ATMEL_LCDC_PIXELSIZE_24;
-+ break;
-+ case 32:
-+ value |= ATMEL_LCDC_PIXELSIZE_32;
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
-+
-+ /* Vertical timing */
-+ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-+ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-+ value |= info->var.lower_margin;
-+ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
-+
-+ /* Horizontal timing */
-+ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-+ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-+ value |= (info->var.left_margin - 1);
-+ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
-+
-+ /* Horizontal value (aka line size) */
-+ hozval_linesz = compute_hozval(info->var.xres,
-+ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
-+
-+ /* Display size */
-+ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-+ value |= info->var.yres - 1;
-+ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
-+
-+ /* FIFO Threshold: Use formula from data sheet */
-+ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-+ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
-+
-+ /* Toggle LCD_MODE every frame */
-+ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
-+
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+ /* Enable FIFO & DMA errors */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-+
-+ /* ...wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+
-+ return 0;
-+ }
-+}
-+
- /**
- * atmel_lcdfb_set_par - Alters the hardware state.
- * @info: frame buffer structure that represents a single frame buffer
-@@ -489,11 +899,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
- static int atmel_lcdfb_set_par(struct fb_info *info)
- {
- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long hozval_linesz;
-- unsigned long value;
-- unsigned long clk_value_khz;
- unsigned long bits_per_line;
-- unsigned long pix_factor = 2;
-
- might_sleep();
-
-@@ -518,98 +924,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
- dev_dbg(info->device, " * update DMA engine\n");
- atmel_lcdfb_update_dma(info, &info->var);
-
-- /* ...set frame size and burst length = 8 words (?) */
-- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
--
- /* Now, the LCDC core... */
--
-- /* Set pixel clock */
-- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-- pix_factor = 1;
--
-- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
--
-- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
--
-- if (value < pix_factor) {
-- dev_notice(info->device, "Bypassing pixel clock divider\n");
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-- } else {
-- value = (value / pix_factor) - 1;
-- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-- value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-- value << ATMEL_LCDC_CLKVAL_OFFSET);
-- info->var.pixclock =
-- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-- PICOS2KHZ(info->var.pixclock));
-- }
--
--
-- /* Initialize control register 2 */
-- value = sinfo->default_lcdcon2;
--
-- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-- value |= ATMEL_LCDC_INVLINE_INVERTED;
-- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-- value |= ATMEL_LCDC_INVFRAME_INVERTED;
--
-- switch (info->var.bits_per_pixel) {
-- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
-- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
-- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
-- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
-- case 15: /* fall through */
-- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
-- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
-- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
-- default: BUG(); break;
-- }
-- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
--
-- /* Vertical timing */
-- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-- value |= info->var.lower_margin;
-- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
--
-- /* Horizontal timing */
-- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-- value |= (info->var.left_margin - 1);
-- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
--
-- /* Horizontal value (aka line size) */
-- hozval_linesz = compute_hozval(info->var.xres,
-- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
--
-- /* Display size */
-- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-- value |= info->var.yres - 1;
-- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
--
-- /* FIFO Threshold: Use formula from data sheet */
-- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
--
-- /* Toggle LCD_MODE every frame */
-- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
--
-- /* Disable all interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-- /* Enable FIFO & DMA errors */
-- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
--
-- /* ...wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
-+ atmel_lcdfb_setup_core(info);
-
- atmel_lcdfb_start(sinfo);
-
-@@ -772,14 +1088,32 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
- struct fb_info *info = dev_id;
- struct atmel_lcdfb_info *sinfo = info->par;
- u32 status;
-+ u32 baselayer_status;
-+
-+ if (cpu_is_at91sam9x5()) {
-+ /* Check for error status via interrupt.*/
-+ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
-+ if (status & LCDC_LCDISR_FIFOERR) {
-+ dev_warn(info->device, "FIFO underflow %#x\n", status);
-+ } else if (status & LCDC_LCDISR_BASE) {
-+ /* Check base layer's overflow error. */
-+ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
-+
-+ if (baselayer_status & LCDC_BASEISR_OVR)
-+ dev_warn(info->device, "base layer overflow %#x\n",
-+ baselayer_status);
-
-- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-- if (status & ATMEL_LCDC_UFLWI) {
-- dev_warn(info->device, "FIFO underflow %#x\n", status);
-- /* reset DMA and FIFO to avoid screen shifting */
-- schedule_work(&sinfo->task);
-+ }
-+ } else {
-+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-+ if (status & ATMEL_LCDC_UFLWI) {
-+ dev_warn(info->device, "FIFO underflow %#x\n", status);
-+ /* reset DMA and FIFO to avoid screen shifting */
-+ schedule_work(&sinfo->task);
-+ }
-+ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
- }
-- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
-+
- return IRQ_HANDLED;
- }
-
-@@ -920,6 +1254,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-
- /* Initialize video memory */
- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ sinfo->p_dma_desc = NULL;
-+ sinfo->dma_desc_phys = 0;
- if (map) {
- /* use a pre-allocated memory buffer */
- info->fix.smem_start = map->start;
-@@ -1030,7 +1366,7 @@ unmap_mmio:
- exit_backlight(sinfo);
- iounmap(sinfo->mmio);
- release_mem:
-- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
- free_fb:
- if (map)
- iounmap(info->screen_base);
-@@ -1075,7 +1411,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
- fb_dealloc_cmap(&info->cmap);
- free_irq(sinfo->irq_base, info);
- iounmap(sinfo->mmio);
-- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
- iounmap(info->screen_base);
- release_mem_region(info->fix.smem_start, info->fix.smem_len);
-@@ -1100,10 +1436,17 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
- * We don't want to handle interrupts while the clock is
- * stopped. It may take forever.
- */
-- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+ if (cpu_is_at91sam9x5()) {
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-+ } else {
-+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+
-+ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
-+ }
-
-- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
- if (sinfo->atmel_lcdfb_power_control)
- sinfo->atmel_lcdfb_power_control(0);
-
-@@ -1122,11 +1465,18 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
- atmel_lcdfb_start(sinfo);
- if (sinfo->atmel_lcdfb_power_control)
- sinfo->atmel_lcdfb_power_control(1);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
-
-- /* Enable FIFO & DMA errors */
-- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
-- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-+ if (cpu_is_at91sam9x5()) {
-+ /* Enable fifo error & BASE LAYER overflow interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
-+ } else {
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
-+
-+ /* Enable FIFO & DMA errors */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
-+ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-+ }
-
- return 0;
- }
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 28447f1..5183ab7 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -47,12 +47,16 @@ struct atmel_lcdfb_info {
- struct clk *bus_clk;
- struct clk *lcdc_clk;
-
-+ struct lcd_dma_desc *p_dma_desc;
-+ dma_addr_t dma_desc_phys;
-+
- #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
- struct backlight_device *backlight;
- u8 bl_power;
- #endif
- bool lcdcon_is_backlight;
- bool lcdcon_pol_negative;
-+ bool alpha_enabled;
- u8 saved_lcdcon;
-
- u8 default_bpp;
-@@ -64,6 +68,12 @@ struct atmel_lcdfb_info {
- u32 pseudo_palette[16];
- };
-
-+struct lcd_dma_desc {
-+ u32 address;
-+ u32 control;
-+ u32 next;
-+};
-+
- #define ATMEL_LCDC_DMABADDR1 0x00
- #define ATMEL_LCDC_DMABADDR2 0x04
- #define ATMEL_LCDC_DMAFRMPT1 0x08
-@@ -214,6 +224,11 @@ struct atmel_lcdfb_info {
- #define ATMEL_LCDC_OWRI (1 << 5)
- #define ATMEL_LCDC_MERI (1 << 6)
-
-+#if !defined(CONFIG_ARCH_AT91SAM9X5)
- #define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
-+#else
-+/* Base layer CLUT */
-+#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
-+#endif
-
- #endif /* __ATMEL_LCDC_H__ */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6d6f92eb0c26eabf7a8716e282252abdddebb108 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 13 Jun 2012 17:28:40 +0800
+Subject: input: at91: add dt support for atmel touch screen adc controller.
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ drivers/input/touchscreen/atmel_tsadcc.c | 86 ++++++++++++++++++++++++++++++--
+ 1 file changed, 82 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
+index 397d17a..021f87e 100644
+--- a/drivers/input/touchscreen/atmel_tsadcc.c
++++ b/drivers/input/touchscreen/atmel_tsadcc.c
+@@ -40,6 +40,8 @@ struct atmel_tsadcc {
+ unsigned int prev_absx;
+ unsigned int prev_absy;
+ unsigned int prev_absz;
++
++ struct at91_tsadcc_data board;
+ };
+
+ static void __iomem *tsc_base;
+@@ -62,7 +64,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ {
+ struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
+ struct input_dev *input_dev = ts_dev->input;
+- struct at91_tsadcc_data *pdata = input_dev->dev.parent->platform_data;
++ struct at91_tsadcc_data *pdata = &ts_dev->board;
+
+ unsigned int status;
+ unsigned int reg;
+@@ -172,6 +174,63 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
+ return IRQ_HANDLED;
+ }
+
++#if defined(CONFIG_OF)
++static int __devinit atmel_of_init_tsadcc(struct device_node *np,
++ struct at91_tsadcc_data *pdata,
++ struct platform_device *pdev)
++{
++ u32 val;
++
++ if (of_property_read_u32(np, "atmel,tsadcc_clock", &val) == 0)
++ pdata->adc_clock = val;
++
++ if (of_property_read_u32(np, "atmel,filtering_average", &val) == 0) {
++ if (val > 0x03) {
++ dev_err(&pdev->dev, "invalid touch average setting, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->filtering_average = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,pendet_debounce", &val) == 0) {
++ if (val > 0x0f) {
++ dev_err(&pdev->dev, "invalid pen detect debounce, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->pendet_debounce = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,pendet_sensitivity", &val) == 0) {
++ if (val > 0x03) {
++ dev_err(&pdev->dev, "invalid pen detective sensitivity setting, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->pendet_sensitivity = (u8)val;
++ }
++
++ if (of_property_read_u32(np, "atmel,ts_sample_hold_time", &val) == 0) {
++ if (val > 0x0f) {
++ dev_err(&pdev->dev, "invalid ts sample hold time, 0x%02x\n",
++ val);
++ return -EINVAL;
++ }
++ pdata->ts_sample_hold_time = (u8)val;
++ }
++
++ return 0;
++}
++#else
++static int __devinit atmel_of_init_tsadcc(struct device_node *np,
++ struct at91_tsadcc_data *pdata,
++ struct platform_device *pdev)
++{
++ return -EINVAL;
++}
++#endif
++
+ /*
+ * The functions for inserting/removing us as a module.
+ */
+@@ -181,7 +240,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ struct atmel_tsadcc *ts_dev;
+ struct input_dev *input_dev;
+ struct resource *res;
+- struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
++ struct at91_tsadcc_data *pdata;
+ int err = 0;
+ unsigned int prsc;
+ unsigned int reg;
+@@ -199,6 +258,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, ts_dev);
++ pdata = &ts_dev->board;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+@@ -264,8 +324,16 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+ prsc = clk_get_rate(ts_dev->clk);
+ dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
+
+- if (!pdata)
+- goto err_fail;
++ if (pdev->dev.of_node) {
++ err = atmel_of_init_tsadcc(pdev->dev.of_node, pdata, pdev);
++ if (err)
++ goto err_fail;
++ } else {
++ if (!pdev->dev.platform_data)
++ goto err_fail;
++ else
++ memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
++ }
+
+ if (!pdata->adc_clock)
+ pdata->adc_clock = ADC_DEFAULT_CLOCK;
+@@ -374,11 +442,21 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_tsaddcc_dt_ids[] = {
++ { .compatible = "atmel,at91sam9x5-tsadcc"},
++ { /* sentinel */ }
++}
++
++MODULE_DEVICE_TABLE(of, atmel_tsaddcc_dt_ids);
++#endif
++
+ static struct platform_driver atmel_tsadcc_driver = {
+ .probe = atmel_tsadcc_probe,
+ .remove = __devexit_p(atmel_tsadcc_remove),
+ .driver = {
+ .name = "atmel_tsadcc",
++ .of_match_table = of_match_ptr(atmel_tsaddcc_dt_ids),
+ },
+ };
+ module_platform_driver(atmel_tsadcc_driver);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 08626997ca3446eab14d17f0c422c4835d6da2d7 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Wed, 9 Mar 2011 11:21:51 +0800
-Subject: video/atmel_lcdfb: The output bpp should not change according to
- memory bpp
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The 9x5-ek using 24 bits output for its connection to LCD screen.
-The output bpp can now be configurated in board file.
-
-XXX: these are two different changes?
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 25 +++----------------------
- 1 file changed, 3 insertions(+), 22 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index c35f5c7..ae0e8e9 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -666,7 +666,9 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
- }
-
- /* Initialize control register 5 */
-- value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
-+ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
-+ value = sinfo->default_lcdcon2;
-+ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
- | LCDC_LCDCFG5_DISPDLY
- | LCDC_LCDCFG5_VSPDLYS;
-
-@@ -675,27 +677,6 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
- value |= LCDC_LCDCFG5_VSPOL;
-
-- switch (info->var.bits_per_pixel) {
-- case 12:
-- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
-- break;
-- case 16:
-- if (info->var.transp.offset != 0)
-- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
-- else
-- value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
-- break;
-- case 18:
-- value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
-- break;
-- case 24:
-- case 32:
-- value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
-- break;
-- default:
-- BUG();
-- break;
-- }
- dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From bef13f58287044dc0ab7f04707daa3344d54592d Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 6 Sep 2012 14:55:37 +0200
+Subject: net/macb: Add support for Gigabit Ethernet mode
+
+Add Gigabit Ethernet mode to GEM cadence IP and enable RGMII connection.
+
+Signed-off-by: Patrice Vilchez <patrice.vilchez@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 15 ++++++++++++---
+ drivers/net/ethernet/cadence/macb.h | 4 ++++
+ 2 files changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 6100b85..e9b909a 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -152,13 +152,17 @@ static void macb_handle_link_change(struct net_device *dev)
+
+ reg = macb_readl(bp, NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
++ if (macb_is_gem(bp))
++ reg &= ~GEM_BIT(GBE);
+
+ if (phydev->duplex)
+ reg |= MACB_BIT(FD);
+ if (phydev->speed == SPEED_100)
+ reg |= MACB_BIT(SPD);
++ if (phydev->speed == SPEED_1000)
++ reg |= GEM_BIT(GBE);
+
+- macb_writel(bp, NCFGR, reg);
++ macb_or_gem_writel(bp, NCFGR, reg);
+
+ bp->speed = phydev->speed;
+ bp->duplex = phydev->duplex;
+@@ -216,7 +220,10 @@ static int macb_mii_probe(struct net_device *dev)
+ }
+
+ /* mask with MAC supported features */
+- phydev->supported &= PHY_BASIC_FEATURES;
++ if (macb_is_gem(bp))
++ phydev->supported &= PHY_GBIT_FEATURES;
++ else
++ phydev->supported &= PHY_BASIC_FEATURES;
+
+ phydev->advertising = phydev->supported;
+
+@@ -1383,7 +1390,9 @@ static int __init macb_probe(struct platform_device *pdev)
+ bp->phy_interface = err;
+ }
+
+- if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
++ if (bp->phy_interface == PHY_INTERFACE_MODE_RGMII)
++ macb_or_gem_writel(bp, USRIO, GEM_BIT(RGMII));
++ else if (bp->phy_interface == PHY_INTERFACE_MODE_RMII)
+ #if defined(CONFIG_ARCH_AT91)
+ macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) |
+ MACB_BIT(CLKEN)));
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 335e288..f69ceef 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -145,6 +145,8 @@
+ #define MACB_IRXFCS_SIZE 1
+
+ /* GEM specific NCFGR bitfields. */
++#define GEM_GBE_OFFSET 10
++#define GEM_GBE_SIZE 1
+ #define GEM_CLK_OFFSET 18
+ #define GEM_CLK_SIZE 3
+ #define GEM_DBW_OFFSET 21
+@@ -246,6 +248,8 @@
+ /* Bitfields in USRIO (AT91) */
+ #define MACB_RMII_OFFSET 0
+ #define MACB_RMII_SIZE 1
++#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
++#define GEM_RGMII_SIZE 1
+ #define MACB_CLKEN_OFFSET 1
+ #define MACB_CLKEN_SIZE 1
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5613e37ca48a7ff009aa3d86325e44d68803fed4 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Thu, 19 May 2011 09:42:55 +0200
-Subject: video: atmelfb: initially split atmelfb into a driver and library
- part
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-
-Conflicts:
-
- drivers/video/atmel_lcdfb.c
----
- drivers/video/Makefile | 2 +-
- drivers/video/atmel_lcdfb.c | 1427 +-------------------------------------
- drivers/video/atmel_lcdfb_core.c | 1077 ++++++++++++++++++++++++++++
- include/video/atmel_lcdc.h | 17 +-
- 4 files changed, 1104 insertions(+), 1419 deletions(-)
- create mode 100644 drivers/video/atmel_lcdfb_core.c
-
-diff --git a/drivers/video/Makefile b/drivers/video/Makefile
-index 9356add..37c5625 100644
---- a/drivers/video/Makefile
-+++ b/drivers/video/Makefile
-@@ -95,7 +95,7 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
- obj-$(CONFIG_FB_SA1100) += sa1100fb.o
- obj-$(CONFIG_FB_HIT) += hitfb.o
- obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
--obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
-+obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
- obj-$(CONFIG_FB_PVR2) += pvr2fb.o
- obj-$(CONFIG_FB_VOODOO1) += sstfb.o
- obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index ae0e8e9..4e1454c 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -10,1401 +10,12 @@
-
- #include <linux/kernel.h>
- #include <linux/platform_device.h>
--#include <linux/dma-mapping.h>
- #include <linux/interrupt.h>
--#include <linux/clk.h>
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/delay.h>
--#include <linux/backlight.h>
--#include <linux/gfp.h>
--#include <linux/module.h>
--
--#include <mach/board.h>
--#include <mach/cpu.h>
--#include <asm/gpio.h>
-
- #include <video/atmel_lcdc.h>
--#include <mach/atmel_hlcdfb.h>
--
--#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
--#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
--
--/* configurable parameters */
--#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
--#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
--#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
--
--#if defined(CONFIG_ARCH_AT91)
--#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-- | FBINFO_PARTIAL_PAN_OK \
-- | FBINFO_HWACCEL_YPAN)
--
--static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-- struct fb_var_screeninfo *var,
-- struct fb_info *info)
--{
--
--}
--#elif defined(CONFIG_AVR32)
--#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-- | FBINFO_PARTIAL_PAN_OK \
-- | FBINFO_HWACCEL_XPAN \
-- | FBINFO_HWACCEL_YPAN)
--
--static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-- struct fb_var_screeninfo *var,
-- struct fb_info *info)
--{
-- u32 dma2dcfg;
-- u32 pixeloff;
--
-- pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
--
-- dma2dcfg = (info->var.xres_virtual - info->var.xres)
-- * info->var.bits_per_pixel / 8;
-- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
-- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
--
-- /* Update configuration */
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
-- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
-- | ATMEL_LCDC_DMAUPDT);
--}
--#endif
--
--static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
-- | ATMEL_LCDC_POL_POSITIVE
-- | ATMEL_LCDC_ENA_PWMENABLE;
--
--static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
-- | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
--
--#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
--
--/* some bl->props field just changed */
--static int atmel_bl_update_status(struct backlight_device *bl)
--{
-- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-- int power = sinfo->bl_power;
-- int brightness = bl->props.brightness;
-- u32 reg;
--
-- /* REVISIT there may be a meaningful difference between
-- * fb_blank and power ... there seem to be some cases
-- * this doesn't handle correctly.
-- */
-- if (bl->props.fb_blank != sinfo->bl_power)
-- power = bl->props.fb_blank;
-- else if (bl->props.power != sinfo->bl_power)
-- power = bl->props.power;
--
-- if (brightness < 0 && power == FB_BLANK_UNBLANK) {
-- if (cpu_is_at91sam9x5())
-- brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
-- >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-- else
-- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-- } else if (power != FB_BLANK_UNBLANK) {
-- brightness = 0;
-- }
--
-- if (cpu_is_at91sam9x5()) {
-- reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
-- reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
-- } else {
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-- brightness ? contrast_ctr : 0);
-- else
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-- }
--
-- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
--
-- return 0;
--}
--
--static int atmel_bl_get_brightness(struct backlight_device *bl)
--{
-- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
--
-- if (cpu_is_at91sam9x5())
-- return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-- else
-- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
--}
--
--static const struct backlight_ops atmel_lcdc_bl_ops = {
-- .update_status = atmel_bl_update_status,
-- .get_brightness = atmel_bl_get_brightness,
--};
--
--static void init_backlight(struct atmel_lcdfb_info *sinfo)
--{
-- struct backlight_properties props;
-- struct backlight_device *bl;
--
-- sinfo->bl_power = FB_BLANK_UNBLANK;
--
-- if (sinfo->backlight)
-- return;
--
-- memset(&props, 0, sizeof(struct backlight_properties));
-- props.type = BACKLIGHT_RAW;
-- props.max_brightness = 0xff;
-- bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
-- &atmel_lcdc_bl_ops, &props);
-- if (IS_ERR(bl)) {
-- dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
-- PTR_ERR(bl));
-- return;
-- }
-- sinfo->backlight = bl;
--
-- bl->props.power = FB_BLANK_UNBLANK;
-- bl->props.fb_blank = FB_BLANK_UNBLANK;
-- bl->props.brightness = atmel_bl_get_brightness(bl);
--}
--
--static void exit_backlight(struct atmel_lcdfb_info *sinfo)
--{
-- if (sinfo->backlight)
-- backlight_device_unregister(sinfo->backlight);
--}
--
--#else
--
--static void init_backlight(struct atmel_lcdfb_info *sinfo)
--{
-- dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
--}
--
--static void exit_backlight(struct atmel_lcdfb_info *sinfo)
--{
--}
--
--#endif
--
--static void init_contrast(struct atmel_lcdfb_info *sinfo)
--{
-- if (cpu_is_at91sam9x5()) {
-- /* have some default contrast/backlight settings */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
-- } else {
-- /* contrast pwm can be 'inverted' */
-- if (sinfo->lcdcon_pol_negative)
-- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
-- /* have some default contrast/backlight settings */
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
-- }
-- if (sinfo->lcdcon_is_backlight)
-- init_backlight(sinfo);
--}
--
--
--static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
-- .type = FB_TYPE_PACKED_PIXELS,
-- .visual = FB_VISUAL_TRUECOLOR,
-- .xpanstep = 0,
-- .ypanstep = 1,
-- .ywrapstep = 0,
-- .accel = FB_ACCEL_NONE,
--};
--
--static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
--{
-- unsigned long value;
--
-- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-- || cpu_is_at32ap7000()))
-- return xres;
--
-- value = xres;
-- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
-- /* STN display */
-- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
-- value *= 3;
-- }
-- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
-- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
-- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
-- value = DIV_ROUND_UP(value, 4);
-- else
-- value = DIV_ROUND_UP(value, 8);
-- }
--
-- return value;
--}
--
--static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
--{
-- if (cpu_is_at91sam9x5()) {
-- /* Disable DISP signal */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
-- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-- msleep(1);
-- /* Disable synchronization */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
-- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-- msleep(1);
-- /* Disable pixel clock */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
-- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-- msleep(1);
-- /* Disable PWM */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
-- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-- msleep(1);
-- } else {
-- /* Turn off the LCD controller and the DMA controller */
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
--
-- /* Wait for the LCDC core to become idle */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-- msleep(10);
--
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-- }
--}
--
--static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
--{
-- atmel_lcdfb_stop_nowait(sinfo);
--
-- if (cpu_is_at91sam9x5()) {
-- /* Wait for the end of DMA transfer */
-- while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
-- msleep(10);
-- } else {
-- /* Wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
-- }
--}
--
--static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
--{
-- u32 value;
--
-- if (cpu_is_at91sam9x5()) {
-- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
-- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-- msleep(1);
-- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
-- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-- msleep(1);
-- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
-- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-- msleep(1);
-- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
-- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-- msleep(1);
-- } else {
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-- | ATMEL_LCDC_PWR);
-- }
--}
--
--static void atmel_lcdfb_update_dma(struct fb_info *info,
-- struct fb_var_screeninfo *var)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- struct fb_fix_screeninfo *fix = &info->fix;
-- unsigned long dma_addr;
-- struct lcd_dma_desc *desc;
--
-- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-- + var->xoffset * info->var.bits_per_pixel / 8);
--
-- dma_addr &= ~3UL;
--
-- if (cpu_is_at91sam9x5()) {
-- /* Setup the DMA descriptor, this descriptor will loop to itself */
-- desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
--
-- desc->address = dma_addr;
-- /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
-- desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
-- | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
-- desc->next = sinfo->dma_desc_phys;
--
-- lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
-- } else {
-- /* Set framebuffer DMA base address and pixel offset */
-- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-- }
--
-- atmel_lcdfb_update_dma2d(sinfo, var, info);
--}
--
--static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
--{
-- struct fb_info *info = sinfo->info;
--
-- dma_free_writecombine(info->device, info->fix.smem_len,
-- info->screen_base, info->fix.smem_start);
--
-- if (cpu_is_at91sam9x5()) {
-- if (sinfo->p_dma_desc)
-- dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
-- sinfo->p_dma_desc, sinfo->dma_desc_phys);
-- }
--}
--
--/**
-- * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
-- * @sinfo: the frame buffer to allocate memory for
-- *
-- * This function is called only from the atmel_lcdfb_probe()
-- * so no locking by fb_info->mm_lock around smem_len setting is needed.
-- */
--static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
--{
-- struct fb_info *info = sinfo->info;
-- struct fb_var_screeninfo *var = &info->var;
-- unsigned int smem_len;
--
-- smem_len = (var->xres_virtual * var->yres_virtual
-- * ((var->bits_per_pixel + 7) / 8));
-- info->fix.smem_len = max(smem_len, sinfo->smem_len);
--
-- info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
-- (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
--
-- if (!info->screen_base) {
-- return -ENOMEM;
-- }
--
-- memset(info->screen_base, 0, info->fix.smem_len);
--
-- if (cpu_is_at91sam9x5()) {
-- sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
-- sizeof(struct lcd_dma_desc),
-- (dma_addr_t *)&(sinfo->dma_desc_phys),
-- GFP_KERNEL);
--
-- if (!sinfo->p_dma_desc) {
-- dma_free_writecombine(info->device, info->fix.smem_len,
-- info->screen_base, info->fix.smem_start);
-- return -ENOMEM;
-- }
-- }
--
-- return 0;
--}
--
--static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
-- struct fb_info *info)
--{
-- struct fb_videomode varfbmode;
-- const struct fb_videomode *fbmode = NULL;
--
-- fb_var_to_videomode(&varfbmode, var);
-- fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
-- if (fbmode)
-- fb_videomode_to_var(var, fbmode);
-- return fbmode;
--}
--
--
--/**
-- * atmel_lcdfb_check_var - Validates a var passed in.
-- * @var: frame buffer variable screen structure
-- * @info: frame buffer structure that represents a single frame buffer
-- *
-- * Checks to see if the hardware supports the state requested by
-- * var passed in. This function does not alter the hardware
-- * state!!! This means the data stored in struct fb_info and
-- * struct atmel_lcdfb_info do not change. This includes the var
-- * inside of struct fb_info. Do NOT change these. This function
-- * can be called on its own if we intent to only test a mode and
-- * not actually set it. The stuff in modedb.c is a example of
-- * this. If the var passed in is slightly off by what the
-- * hardware can support then we alter the var PASSED in to what
-- * we can do. If the hardware doesn't support mode change a
-- * -EINVAL will be returned by the upper layers. You don't need
-- * to implement this function then. If you hardware doesn't
-- * support changing the resolution then this function is not
-- * needed. In this case the driver would just provide a var that
-- * represents the static state the screen is in.
-- *
-- * Returns negative errno on error, or zero on success.
-- */
--static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
-- struct fb_info *info)
--{
-- struct device *dev = info->device;
-- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long clk_value_khz;
--
-- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
--
-- dev_dbg(dev, "%s:\n", __func__);
--
-- if (!(var->pixclock && var->bits_per_pixel)) {
-- /* choose a suitable mode if possible */
-- if (!atmel_lcdfb_choose_mode(var, info)) {
-- dev_err(dev, "needed value not specified\n");
-- return -EINVAL;
-- }
-- }
--
-- dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
-- dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
-- dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
-- dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
--
-- if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
-- dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
-- return -EINVAL;
-- }
--
-- /* Do not allow to have real resoulution larger than virtual */
-- if (var->xres > var->xres_virtual)
-- var->xres_virtual = var->xres;
--
-- if (var->yres > var->yres_virtual)
-- var->yres_virtual = var->yres;
--
-- /* Force same alignment for each line */
-- var->xres = (var->xres + 3) & ~3UL;
-- var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
--
-- var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
-- var->transp.msb_right = 0;
-- var->transp.offset = var->transp.length = 0;
-- var->xoffset = var->yoffset = 0;
--
-- if (info->fix.smem_len) {
-- unsigned int smem_len = (var->xres_virtual * var->yres_virtual
-- * ((var->bits_per_pixel + 7) / 8));
-- if (smem_len > info->fix.smem_len)
-- return -EINVAL;
-- }
--
-- /* Saturate vertical and horizontal timings at maximum values */
-- if (cpu_is_at91sam9x5()) {
-- var->vsync_len = min_t(u32, var->vsync_len,
-- (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
-- var->upper_margin = min_t(u32, var->upper_margin,
-- (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
-- var->lower_margin = min_t(u32, var->lower_margin,
-- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
-- var->right_margin = min_t(u32, var->right_margin,
-- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
-- var->hsync_len = min_t(u32, var->hsync_len,
-- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
-- var->left_margin = min_t(u32, var->left_margin,
-- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-- } else {
-- var->vsync_len = min_t(u32, var->vsync_len,
-- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-- var->upper_margin = min_t(u32, var->upper_margin,
-- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-- var->lower_margin = min_t(u32, var->lower_margin,
-- ATMEL_LCDC_VFP);
-- var->right_margin = min_t(u32, var->right_margin,
-- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-- var->hsync_len = min_t(u32, var->hsync_len,
-- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-- var->left_margin = min_t(u32, var->left_margin,
-- ATMEL_LCDC_HBP + 1);
-- }
--
-- /* Some parameters can't be zero */
-- var->vsync_len = max_t(u32, var->vsync_len, 1);
-- var->right_margin = max_t(u32, var->right_margin, 1);
-- var->hsync_len = max_t(u32, var->hsync_len, 1);
-- var->left_margin = max_t(u32, var->left_margin, 1);
--
-- switch (var->bits_per_pixel) {
-- case 1:
-- case 2:
-- case 4:
-- case 8:
-- var->red.offset = var->green.offset = var->blue.offset = 0;
-- var->red.length = var->green.length = var->blue.length
-- = var->bits_per_pixel;
-- break;
-- case 12:
-- if (cpu_is_at91sam9x5()) {
-- /* RGB:444 mode */
-- var->red.offset = 8;
-- var->blue.offset = 0;
-- var->green.offset = 4;
-- var->red.length = var->green.length = var->blue.length = 4;
-- } else {
-- /*TODO: rework*/
-- BUG();
-- }
-- break;
-- case 15:
-- if (cpu_is_at91sam9x5()) {
-- /* RGB:555 mode */
-- var->red.offset = 10;
-- var->blue.offset = 0;
-- var->green.length = 5;
-- var->red.length = var->green.length = var->blue.length = 5;
-- } else {
-- /*TODO: rework*/
-- BUG();
-- }
-- break;
-- case 16:
-- if (cpu_is_at91sam9x5()) {
-- if (sinfo->alpha_enabled) {
-- /* ARGB:4444 mode */
-- var->red.offset = 8;
-- var->blue.offset = 0;
-- var->green.offset = 4;
-- var->transp.offset = 12;
-- var->red.length = var->green.length
-- = var->blue.length
-- = var->transp.length = 4;
-- } else {
-- /* RGB:565 mode */
-- var->red.offset = 11;
-- var->blue.offset = 0;
-- var->green.offset = 5;
-- var->green.length = 6;
-- var->red.length = var->blue.length = 5;
-- }
-- break;
-- }
-- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
-- /* RGB:565 mode */
-- var->red.offset = 11;
-- var->blue.offset = 0;
-- } else {
-- /* BGR:565 mode */
-- var->red.offset = 0;
-- var->blue.offset = 11;
-- }
-- var->green.offset = 5;
-- var->green.length = 6;
-- var->red.length = var->blue.length = 5;
-- break;
-- case 32:
-- /* TODO 32 & 24 modes */
-- var->transp.offset = 24;
-- var->transp.length = 8;
-- /* fall through */
-- case 24:
-- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
-- /* RGB:888 mode */
-- var->red.offset = 16;
-- var->blue.offset = 0;
-- } else {
-- /* BGR:888 mode */
-- var->red.offset = 0;
-- var->blue.offset = 16;
-- }
-- var->green.offset = 8;
-- var->red.length = var->green.length = var->blue.length = 8;
-- break;
-- default:
-- dev_err(dev, "color depth %d not supported\n",
-- var->bits_per_pixel);
-- return -EINVAL;
-- }
--
-- return 0;
--}
--
--/*
-- * LCD reset sequence
-- */
--static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
--{
-- might_sleep();
--
-- atmel_lcdfb_stop(sinfo);
-- atmel_lcdfb_start(sinfo);
--}
--
--static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long value;
-- unsigned long clk_value_khz;
--
-- dev_dbg(info->device, "%s:\n", __func__);
-- /* Set pixel clock */
-- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
--
-- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
--
-- if (value < 1) {
-- dev_notice(info->device, "using system clock as pixel clock\n");
-- value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-- } else {
-- info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
-- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-- PICOS2KHZ(info->var.pixclock));
-- value = value - 2;
-- dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
-- value);
-- value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
-- | LCDC_LCDCFG0_CLKPOL
-- | LCDC_LCDCFG0_CGDISBASE;
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-- }
--
-- /* Initialize control register 5 */
-- /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
-- value = sinfo->default_lcdcon2;
-- value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
-- | LCDC_LCDCFG5_DISPDLY
-- | LCDC_LCDCFG5_VSPDLYS;
--
-- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-- value |= LCDC_LCDCFG5_HSPOL;
-- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-- value |= LCDC_LCDCFG5_VSPOL;
--
-- dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
--
-- /* Vertical & Horizontal Timing */
-- value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
-- value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
-- dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
--
-- value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
-- value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
-- dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
--
-- value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
-- value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
-- dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
--
-- /* Display size */
-- value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
-- value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
-- dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
--
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
-- switch (info->var.bits_per_pixel) {
-- case 12:
-- value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
-- break;
-- case 16:
-- if (info->var.transp.offset != 0)
-- value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
-- else
-- value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
-- break;
-- case 18:
-- value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
-- break;
-- case 24:
-- value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
-- break;
-- case 32:
-- value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
-- break;
-- default:
-- BUG();
-- break;
-- }
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
-- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
--
-- /* Disable all interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-- /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
-- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
--
-- return 0;
--}
--
--static int atmel_lcdfb_setup_core(struct fb_info *info)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long hozval_linesz;
-- unsigned long value;
-- unsigned long clk_value_khz;
-- unsigned long pix_factor = 2;
--
-- if (cpu_is_at91sam9x5()) {
-- return atmel_lcdfb_setup_9x5_core(info);
-- } else {
-- /* ...set frame size and burst length = 8 words (?) */
-- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
--
-- /* Set pixel clock */
-- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-- pix_factor = 1;
--
-- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
--
-- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
--
-- if (value < pix_factor) {
-- dev_notice(info->device, "Bypassing pixel clock divider\n");
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-- } else {
-- value = (value / pix_factor) - 1;
-- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-- value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-- value << ATMEL_LCDC_CLKVAL_OFFSET);
-- info->var.pixclock =
-- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-- PICOS2KHZ(info->var.pixclock));
-- }
--
--
-- /* Initialize control register 2 */
-- value = sinfo->default_lcdcon2;
--
-- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-- value |= ATMEL_LCDC_INVLINE_INVERTED;
-- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-- value |= ATMEL_LCDC_INVFRAME_INVERTED;
--
-- switch (info->var.bits_per_pixel) {
-- case 1:
-- value |= ATMEL_LCDC_PIXELSIZE_1;
-- break;
-- case 2:
-- value |= ATMEL_LCDC_PIXELSIZE_2;
-- break;
-- case 4:
-- value |= ATMEL_LCDC_PIXELSIZE_4;
-- break;
-- case 8:
-- value |= ATMEL_LCDC_PIXELSIZE_8;
-- break;
-- case 15: /* fall through */
-- case 16:
-- value |= ATMEL_LCDC_PIXELSIZE_16;
-- break;
-- case 24:
-- value |= ATMEL_LCDC_PIXELSIZE_24;
-- break;
-- case 32:
-- value |= ATMEL_LCDC_PIXELSIZE_32;
-- break;
-- default:
-- BUG();
-- break;
-- }
-- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
--
-- /* Vertical timing */
-- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-- value |= info->var.lower_margin;
-- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
--
-- /* Horizontal timing */
-- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-- value |= (info->var.left_margin - 1);
-- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
--
-- /* Horizontal value (aka line size) */
-- hozval_linesz = compute_hozval(info->var.xres,
-- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
--
-- /* Display size */
-- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-- value |= info->var.yres - 1;
-- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
--
-- /* FIFO Threshold: Use formula from data sheet */
-- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
--
-- /* Toggle LCD_MODE every frame */
-- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
--
-- /* Disable all interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-- /* Enable FIFO & DMA errors */
-- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
--
-- /* ...wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
--
-- return 0;
-- }
--}
--
--/**
-- * atmel_lcdfb_set_par - Alters the hardware state.
-- * @info: frame buffer structure that represents a single frame buffer
-- *
-- * Using the fb_var_screeninfo in fb_info we set the resolution
-- * of the this particular framebuffer. This function alters the
-- * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
-- * not alter var in fb_info since we are using that data. This
-- * means we depend on the data in var inside fb_info to be
-- * supported by the hardware. atmel_lcdfb_check_var is always called
-- * before atmel_lcdfb_set_par to ensure this. Again if you can't
-- * change the resolution you don't need this function.
-- *
-- */
--static int atmel_lcdfb_set_par(struct fb_info *info)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long bits_per_line;
--
-- might_sleep();
--
-- dev_dbg(info->device, "%s:\n", __func__);
-- dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
-- info->var.xres, info->var.yres,
-- info->var.xres_virtual, info->var.yres_virtual);
--
-- atmel_lcdfb_stop_nowait(sinfo);
--
-- if (info->var.bits_per_pixel == 1)
-- info->fix.visual = FB_VISUAL_MONO01;
-- else if (info->var.bits_per_pixel <= 8)
-- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-- else
-- info->fix.visual = FB_VISUAL_TRUECOLOR;
--
-- bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
-- info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
--
-- /* Re-initialize the DMA engine... */
-- dev_dbg(info->device, " * update DMA engine\n");
-- atmel_lcdfb_update_dma(info, &info->var);
--
-- /* Now, the LCDC core... */
-- atmel_lcdfb_setup_core(info);
--
-- atmel_lcdfb_start(sinfo);
--
-- dev_dbg(info->device, " * DONE\n");
--
-- return 0;
--}
--
--static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
--{
-- chan &= 0xffff;
-- chan >>= 16 - bf->length;
-- return chan << bf->offset;
--}
--
--/**
-- * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
-- * @regno: Which register in the CLUT we are programming
-- * @red: The red value which can be up to 16 bits wide
-- * @green: The green value which can be up to 16 bits wide
-- * @blue: The blue value which can be up to 16 bits wide.
-- * @transp: If supported the alpha value which can be up to 16 bits wide.
-- * @info: frame buffer info structure
-- *
-- * Set a single color register. The values supplied have a 16 bit
-- * magnitude which needs to be scaled in this function for the hardware.
-- * Things to take into consideration are how many color registers, if
-- * any, are supported with the current color visual. With truecolor mode
-- * no color palettes are supported. Here a pseudo palette is created
-- * which we store the value in pseudo_palette in struct fb_info. For
-- * pseudocolor mode we have a limited color palette. To deal with this
-- * we can program what color is displayed for a particular pixel value.
-- * DirectColor is similar in that we can program each color field. If
-- * we have a static colormap we don't need to implement this function.
-- *
-- * Returns negative errno on error, or zero on success. In an
-- * ideal world, this would have been the case, but as it turns
-- * out, the other drivers return 1 on failure, so that's what
-- * we're going to do.
-- */
--static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
-- unsigned int green, unsigned int blue,
-- unsigned int transp, struct fb_info *info)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned int val;
-- u32 *pal;
-- int ret = 1;
--
-- if (info->var.grayscale)
-- red = green = blue = (19595 * red + 38470 * green
-- + 7471 * blue) >> 16;
--
-- switch (info->fix.visual) {
-- case FB_VISUAL_TRUECOLOR:
-- if (regno < 16) {
-- pal = info->pseudo_palette;
--
-- val = chan_to_field(red, &info->var.red);
-- val |= chan_to_field(green, &info->var.green);
-- val |= chan_to_field(blue, &info->var.blue);
--
-- pal[regno] = val;
-- ret = 0;
-- }
-- break;
--
-- case FB_VISUAL_PSEUDOCOLOR:
-- if (regno < 256) {
-- if (cpu_is_at91sam9261() || cpu_is_at91sam9263()
-- || cpu_is_at91sam9rl()) {
-- /* old style I+BGR:555 */
-- val = ((red >> 11) & 0x001f);
-- val |= ((green >> 6) & 0x03e0);
-- val |= ((blue >> 1) & 0x7c00);
--
-- /*
-- * TODO: intensity bit. Maybe something like
-- * ~(red[10] ^ green[10] ^ blue[10]) & 1
-- */
-- } else {
-- /* new style BGR:565 / RGB:565 */
-- if (sinfo->lcd_wiring_mode ==
-- ATMEL_LCDC_WIRING_RGB) {
-- val = ((blue >> 11) & 0x001f);
-- val |= ((red >> 0) & 0xf800);
-- } else {
-- val = ((red >> 11) & 0x001f);
-- val |= ((blue >> 0) & 0xf800);
-- }
--
-- val |= ((green >> 5) & 0x07e0);
-- }
--
-- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-- ret = 0;
-- }
-- break;
--
-- case FB_VISUAL_MONO01:
-- if (regno < 2) {
-- val = (regno == 0) ? 0x00 : 0x1F;
-- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-- ret = 0;
-- }
-- break;
--
-- }
--
-- return ret;
--}
--
--static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
-- struct fb_info *info)
--{
-- dev_dbg(info->device, "%s\n", __func__);
--
-- atmel_lcdfb_update_dma(info, var);
--
-- return 0;
--}
--
--static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
--
-- switch (blank_mode) {
-- case FB_BLANK_UNBLANK:
-- case FB_BLANK_NORMAL:
-- atmel_lcdfb_start(sinfo);
-- break;
-- case FB_BLANK_VSYNC_SUSPEND:
-- case FB_BLANK_HSYNC_SUSPEND:
-- break;
-- case FB_BLANK_POWERDOWN:
-- atmel_lcdfb_stop(sinfo);
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- /* let fbcon do a soft blank for us */
-- return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
--}
--
--static struct fb_ops atmel_lcdfb_ops = {
-- .owner = THIS_MODULE,
-- .fb_check_var = atmel_lcdfb_check_var,
-- .fb_set_par = atmel_lcdfb_set_par,
-- .fb_setcolreg = atmel_lcdfb_setcolreg,
-- .fb_blank = atmel_lcdfb_blank,
-- .fb_pan_display = atmel_lcdfb_pan_display,
-- .fb_fillrect = cfb_fillrect,
-- .fb_copyarea = cfb_copyarea,
-- .fb_imageblit = cfb_imageblit,
--};
--
--static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
--{
-- struct fb_info *info = dev_id;
-- struct atmel_lcdfb_info *sinfo = info->par;
-- u32 status;
-- u32 baselayer_status;
--
-- if (cpu_is_at91sam9x5()) {
-- /* Check for error status via interrupt.*/
-- status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
-- if (status & LCDC_LCDISR_FIFOERR) {
-- dev_warn(info->device, "FIFO underflow %#x\n", status);
-- } else if (status & LCDC_LCDISR_BASE) {
-- /* Check base layer's overflow error. */
-- baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
--
-- if (baselayer_status & LCDC_BASEISR_OVR)
-- dev_warn(info->device, "base layer overflow %#x\n",
-- baselayer_status);
--
-- }
-- } else {
-- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-- if (status & ATMEL_LCDC_UFLWI) {
-- dev_warn(info->device, "FIFO underflow %#x\n", status);
-- /* reset DMA and FIFO to avoid screen shifting */
-- schedule_work(&sinfo->task);
-- }
-- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
-- }
--
-- return IRQ_HANDLED;
--}
--
--/*
-- * LCD controller task (to reset the LCD)
-- */
--static void atmel_lcdfb_task(struct work_struct *work)
--{
-- struct atmel_lcdfb_info *sinfo =
-- container_of(work, struct atmel_lcdfb_info, task);
--
-- atmel_lcdfb_reset(sinfo);
--}
--
--static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
--{
-- struct fb_info *info = sinfo->info;
-- int ret = 0;
--
-- info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
--
-- dev_info(info->device,
-- "%luKiB frame buffer at %08lx (mapped at %p)\n",
-- (unsigned long)info->fix.smem_len / 1024,
-- (unsigned long)info->fix.smem_start,
-- info->screen_base);
--
-- /* Allocate colormap */
-- ret = fb_alloc_cmap(&info->cmap, 256, 0);
-- if (ret < 0)
-- dev_err(info->device, "Alloc color map failed\n");
--
-- return ret;
--}
--
--static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
--{
-- if (sinfo->bus_clk)
-- clk_enable(sinfo->bus_clk);
-- clk_enable(sinfo->lcdc_clk);
--}
--
--static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
--{
-- if (sinfo->bus_clk)
-- clk_disable(sinfo->bus_clk);
-- clk_disable(sinfo->lcdc_clk);
--}
--
--
--static int __init atmel_lcdfb_probe(struct platform_device *pdev)
--{
-- struct device *dev = &pdev->dev;
-- struct fb_info *info;
-- struct atmel_lcdfb_info *sinfo;
-- struct atmel_lcdfb_info *pdata_sinfo;
-- struct fb_videomode fbmode;
-- struct resource *regs = NULL;
-- struct resource *map = NULL;
-- int ret;
--
-- dev_dbg(dev, "%s BEGIN\n", __func__);
--
-- ret = -ENOMEM;
-- info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
-- if (!info) {
-- dev_err(dev, "cannot allocate memory\n");
-- goto out;
-- }
--
-- sinfo = info->par;
--
-- if (dev->platform_data) {
-- pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
-- sinfo->default_bpp = pdata_sinfo->default_bpp;
-- sinfo->default_dmacon = pdata_sinfo->default_dmacon;
-- sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
-- sinfo->default_monspecs = pdata_sinfo->default_monspecs;
-- sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
-- sinfo->guard_time = pdata_sinfo->guard_time;
-- sinfo->smem_len = pdata_sinfo->smem_len;
-- sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
-- sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
-- sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
-- } else {
-- dev_err(dev, "cannot get default configuration\n");
-- goto free_info;
-- }
-- sinfo->info = info;
-- sinfo->pdev = pdev;
--
-- strcpy(info->fix.id, sinfo->pdev->name);
-- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
-- info->pseudo_palette = sinfo->pseudo_palette;
-- info->fbops = &atmel_lcdfb_ops;
--
-- memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
-- info->fix = atmel_lcdfb_fix;
--
-- /* Enable LCDC Clocks */
-- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-- || cpu_is_at32ap7000()) {
-- sinfo->bus_clk = clk_get(dev, "hck1");
-- if (IS_ERR(sinfo->bus_clk)) {
-- ret = PTR_ERR(sinfo->bus_clk);
-- goto free_info;
-- }
-- }
-- sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
-- if (IS_ERR(sinfo->lcdc_clk)) {
-- ret = PTR_ERR(sinfo->lcdc_clk);
-- goto put_bus_clk;
-- }
-- atmel_lcdfb_start_clock(sinfo);
--
-- ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
-- info->monspecs.modedb_len, info->monspecs.modedb,
-- sinfo->default_bpp);
-- if (!ret) {
-- dev_err(dev, "no suitable video mode found\n");
-- goto stop_clk;
-- }
--
--
-- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- if (!regs) {
-- dev_err(dev, "resources unusable\n");
-- ret = -ENXIO;
-- goto stop_clk;
-- }
--
-- sinfo->irq_base = platform_get_irq(pdev, 0);
-- if (sinfo->irq_base < 0) {
-- dev_err(dev, "unable to get irq\n");
-- ret = sinfo->irq_base;
-- goto stop_clk;
-- }
--
-- /* Initialize video memory */
-- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-- sinfo->p_dma_desc = NULL;
-- sinfo->dma_desc_phys = 0;
-- if (map) {
-- /* use a pre-allocated memory buffer */
-- info->fix.smem_start = map->start;
-- info->fix.smem_len = resource_size(map);
-- if (!request_mem_region(info->fix.smem_start,
-- info->fix.smem_len, pdev->name)) {
-- ret = -EBUSY;
-- goto stop_clk;
-- }
--
-- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-- if (!info->screen_base)
-- goto release_intmem;
--
-- /*
-- * Don't clear the framebuffer -- someone may have set
-- * up a splash image.
-- */
-- } else {
-- /* alocate memory buffer */
-- ret = atmel_lcdfb_alloc_video_memory(sinfo);
-- if (ret < 0) {
-- dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
-- goto stop_clk;
-- }
-- }
--
-- /* LCDC registers */
-- info->fix.mmio_start = regs->start;
-- info->fix.mmio_len = resource_size(regs);
--
-- if (!request_mem_region(info->fix.mmio_start,
-- info->fix.mmio_len, pdev->name)) {
-- ret = -EBUSY;
-- goto free_fb;
-- }
--
-- sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
-- if (!sinfo->mmio) {
-- dev_err(dev, "cannot map LCDC registers\n");
-- goto release_mem;
-- }
--
-- /* Initialize PWM for contrast or backlight ("off") */
-- init_contrast(sinfo);
--
-- /* interrupt */
-- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
-- if (ret) {
-- dev_err(dev, "request_irq failed: %d\n", ret);
-- goto unmap_mmio;
-- }
--
-- /* Some operations on the LCDC might sleep and
-- * require a preemptible task context */
-- INIT_WORK(&sinfo->task, atmel_lcdfb_task);
--
-- ret = atmel_lcdfb_init_fbinfo(sinfo);
-- if (ret < 0) {
-- dev_err(dev, "init fbinfo failed: %d\n", ret);
-- goto unregister_irqs;
-- }
--
-- /*
-- * This makes sure that our colour bitfield
-- * descriptors are correctly initialised.
-- */
-- atmel_lcdfb_check_var(&info->var, info);
--
-- ret = fb_set_var(info, &info->var);
-- if (ret) {
-- dev_warn(dev, "unable to set display parameters\n");
-- goto free_cmap;
-- }
--
-- dev_set_drvdata(dev, info);
--
-- /*
-- * Tell the world that we're ready to go
-- */
-- ret = register_framebuffer(info);
-- if (ret < 0) {
-- dev_err(dev, "failed to register framebuffer device: %d\n", ret);
-- goto reset_drvdata;
-- }
--
-- /* add selected videomode to modelist */
-- fb_var_to_videomode(&fbmode, &info->var);
-- fb_add_videomode(&fbmode, &info->modelist);
--
-- /* Power up the LCDC screen */
-- if (sinfo->atmel_lcdfb_power_control)
-- sinfo->atmel_lcdfb_power_control(1);
--
-- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
-- info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
--
-- return 0;
--
--reset_drvdata:
-- dev_set_drvdata(dev, NULL);
--free_cmap:
-- fb_dealloc_cmap(&info->cmap);
--unregister_irqs:
-- cancel_work_sync(&sinfo->task);
-- free_irq(sinfo->irq_base, info);
--unmap_mmio:
-- exit_backlight(sinfo);
-- iounmap(sinfo->mmio);
--release_mem:
-- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
--free_fb:
-- if (map)
-- iounmap(info->screen_base);
-- else
-- atmel_lcdfb_free_video_memory(sinfo);
--
--release_intmem:
-- if (map)
-- release_mem_region(info->fix.smem_start, info->fix.smem_len);
--stop_clk:
-- atmel_lcdfb_stop_clock(sinfo);
-- clk_put(sinfo->lcdc_clk);
--put_bus_clk:
-- if (sinfo->bus_clk)
-- clk_put(sinfo->bus_clk);
--free_info:
-- framebuffer_release(info);
--out:
-- dev_dbg(dev, "%s FAILED\n", __func__);
-- return ret;
--}
--
--static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
--{
-- struct device *dev = &pdev->dev;
-- struct fb_info *info = dev_get_drvdata(dev);
-- struct atmel_lcdfb_info *sinfo;
--
-- if (!info || !info->par)
-- return 0;
-- sinfo = info->par;
--
-- cancel_work_sync(&sinfo->task);
-- exit_backlight(sinfo);
-- if (sinfo->atmel_lcdfb_power_control)
-- sinfo->atmel_lcdfb_power_control(0);
-- unregister_framebuffer(info);
-- atmel_lcdfb_stop_clock(sinfo);
-- clk_put(sinfo->lcdc_clk);
-- if (sinfo->bus_clk)
-- clk_put(sinfo->bus_clk);
-- fb_dealloc_cmap(&info->cmap);
-- free_irq(sinfo->irq_base, info);
-- iounmap(sinfo->mmio);
-- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
-- iounmap(info->screen_base);
-- release_mem_region(info->fix.smem_start, info->fix.smem_len);
-- } else {
-- atmel_lcdfb_free_video_memory(sinfo);
-- }
--
-- dev_set_drvdata(dev, NULL);
-- framebuffer_release(info);
--
-- return 0;
--}
-
- #ifdef CONFIG_PM
-
-@@ -1417,16 +28,10 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
- * We don't want to handle interrupts while the clock is
- * stopped. It may take forever.
- */
-- if (cpu_is_at91sam9x5()) {
-- /* Disable all interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-- } else {
-- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-
-- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
-- }
-+ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
-
- if (sinfo->atmel_lcdfb_power_control)
- sinfo->atmel_lcdfb_power_control(0);
-@@ -1447,17 +52,11 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
- if (sinfo->atmel_lcdfb_power_control)
- sinfo->atmel_lcdfb_power_control(1);
-
-- if (cpu_is_at91sam9x5()) {
-- /* Enable fifo error & BASE LAYER overflow interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
-- } else {
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
-
-- /* Enable FIFO & DMA errors */
-- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
-- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-- }
-+ /* Enable FIFO & DMA errors */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
-+ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-
- return 0;
- }
-@@ -1467,6 +66,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
- #define atmel_lcdfb_resume NULL
- #endif
-
-+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-+{
-+ return __atmel_lcdfb_probe(pdev);
-+}
-+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
-+{
-+ return __atmel_lcdfb_remove(pdev);
-+}
-+
- static struct platform_driver atmel_lcdfb_driver = {
- .remove = __exit_p(atmel_lcdfb_remove),
- .suspend = atmel_lcdfb_suspend,
-@@ -1482,13 +90,12 @@ static int __init atmel_lcdfb_init(void)
- {
- return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
- }
-+module_init(atmel_lcdfb_init);
-
- static void __exit atmel_lcdfb_exit(void)
- {
- platform_driver_unregister(&atmel_lcdfb_driver);
- }
--
--module_init(atmel_lcdfb_init);
- module_exit(atmel_lcdfb_exit);
-
- MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-new file mode 100644
-index 0000000..54bdbcb
---- /dev/null
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -0,0 +1,1077 @@
-+/*
-+ * Driver for AT91/AT32 LCD Controller
-+ *
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/interrupt.h>
-+#include <linux/clk.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/backlight.h>
-+#include <linux/gfp.h>
-+
-+#include <mach/board.h>
-+#include <mach/cpu.h>
-+#include <mach/gpio.h>
-+
-+#include <video/atmel_lcdc.h>
-+
-+/* configurable parameters */
-+#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
-+#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
-+#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
-+
-+#if defined(CONFIG_ARCH_AT91)
-+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-+ | FBINFO_PARTIAL_PAN_OK \
-+ | FBINFO_HWACCEL_YPAN)
-+
-+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-+ struct fb_var_screeninfo *var)
-+{
-+
-+}
-+#elif defined(CONFIG_AVR32)
-+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-+ | FBINFO_PARTIAL_PAN_OK \
-+ | FBINFO_HWACCEL_XPAN \
-+ | FBINFO_HWACCEL_YPAN)
-+
-+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-+ struct fb_var_screeninfo *var)
-+{
-+ u32 dma2dcfg;
-+ u32 pixeloff;
-+
-+ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
-+
-+ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
-+ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
-+
-+ /* Update configuration */
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
-+ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
-+ | ATMEL_LCDC_DMAUPDT);
-+}
-+#endif
-+
-+static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
-+ | ATMEL_LCDC_POL_POSITIVE
-+ | ATMEL_LCDC_ENA_PWMENABLE;
-+
-+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-+
-+/* some bl->props field just changed */
-+static int atmel_bl_update_status(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+ int power = sinfo->bl_power;
-+ int brightness = bl->props.brightness;
-+
-+ /* REVISIT there may be a meaningful difference between
-+ * fb_blank and power ... there seem to be some cases
-+ * this doesn't handle correctly.
-+ */
-+ if (bl->props.fb_blank != sinfo->bl_power)
-+ power = bl->props.fb_blank;
-+ else if (bl->props.power != sinfo->bl_power)
-+ power = bl->props.power;
-+
-+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
-+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ else if (power != FB_BLANK_UNBLANK)
-+ brightness = 0;
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-+ brightness ? contrast_ctr : 0);
-+
-+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
-+
-+ return 0;
-+}
-+
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+
-+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+}
-+
-+static const struct backlight_ops atmel_lcdc_bl_ops = {
-+ .update_status = atmel_bl_update_status,
-+ .get_brightness = atmel_bl_get_brightness,
-+};
-+
-+static void init_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+ struct backlight_properties props;
-+ struct backlight_device *bl;
-+
-+ sinfo->bl_power = FB_BLANK_UNBLANK;
-+
-+ if (sinfo->backlight)
-+ return;
-+
-+ memset(&props, 0, sizeof(struct backlight_properties));
-+ props.type = BACKLIGHT_RAW;
-+ props.max_brightness = 0xff;
-+ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
-+ &atmel_lcdc_bl_ops, &props);
-+ if (IS_ERR(bl)) {
-+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
-+ PTR_ERR(bl));
-+ return;
-+ }
-+ sinfo->backlight = bl;
-+
-+ bl->props.power = FB_BLANK_UNBLANK;
-+ bl->props.fb_blank = FB_BLANK_UNBLANK;
-+ bl->props.brightness = atmel_bl_get_brightness(bl);
-+}
-+
-+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+ if (sinfo->backlight)
-+ backlight_device_unregister(sinfo->backlight);
-+}
-+
-+#else
-+
-+static void init_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
-+}
-+
-+static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-+{
-+}
-+
-+#endif
-+
-+static void init_contrast(struct atmel_lcdfb_info *sinfo)
-+{
-+ /* contrast pwm can be 'inverted' */
-+ if (sinfo->lcdcon_pol_negative)
-+ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
-+
-+ /* have some default contrast/backlight settings */
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
-+
-+ if (sinfo->lcdcon_is_backlight)
-+ init_backlight(sinfo);
-+}
-+
-+
-+static struct fb_fix_screeninfo atmel_lcdfb_fix = {
-+ .type = FB_TYPE_PACKED_PIXELS,
-+ .visual = FB_VISUAL_TRUECOLOR,
-+ .xpanstep = 0,
-+ .ypanstep = 1,
-+ .ywrapstep = 0,
-+ .accel = FB_ACCEL_NONE,
-+};
-+
-+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
-+{
-+ unsigned long value;
-+
-+ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-+ || cpu_is_at32ap7000()))
-+ return xres;
-+
-+ value = xres;
-+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
-+ /* STN display */
-+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
-+ value *= 3;
-+ }
-+ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
-+ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
-+ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
-+ value = DIV_ROUND_UP(value, 4);
-+ else
-+ value = DIV_ROUND_UP(value, 8);
-+ }
-+
-+ return value;
-+}
-+
-+static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
-+{
-+ /* Turn off the LCD controller and the DMA controller */
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-+
-+ /* Wait for the LCDC core to become idle */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-+ msleep(10);
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-+}
-+
-+void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
-+{
-+ atmel_lcdfb_stop_nowait(sinfo);
-+
-+ /* Wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+}
-+EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
-+
-+void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
-+{
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-+ | ATMEL_LCDC_PWR);
-+}
-+EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
-+
-+static void atmel_lcdfb_update_dma(struct fb_info *info,
-+ struct fb_var_screeninfo *var)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ struct fb_fix_screeninfo *fix = &info->fix;
-+ unsigned long dma_addr;
-+
-+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-+ + var->xoffset * var->bits_per_pixel / 8);
-+
-+ dma_addr &= ~3UL;
-+
-+ /* Set framebuffer DMA base address and pixel offset */
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-+
-+ atmel_lcdfb_update_dma2d(sinfo, var);
-+}
-+
-+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
-+{
-+ struct fb_info *info = sinfo->info;
-+
-+ dma_free_writecombine(info->device, info->fix.smem_len,
-+ info->screen_base, info->fix.smem_start);
-+}
-+
-+/**
-+ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
-+ * @sinfo: the frame buffer to allocate memory for
-+ *
-+ * This function is called only from the atmel_lcdfb_probe()
-+ * so no locking by fb_info->mm_lock around smem_len setting is needed.
-+ */
-+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
-+{
-+ struct fb_info *info = sinfo->info;
-+ struct fb_var_screeninfo *var = &info->var;
-+ unsigned int smem_len;
-+
-+ smem_len = (var->xres_virtual * var->yres_virtual
-+ * ((var->bits_per_pixel + 7) / 8));
-+ info->fix.smem_len = max(smem_len, sinfo->smem_len);
-+
-+ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
-+ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
-+
-+ if (!info->screen_base) {
-+ return -ENOMEM;
-+ }
-+
-+ memset(info->screen_base, 0, info->fix.smem_len);
-+
-+ return 0;
-+}
-+
-+static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ struct fb_videomode varfbmode;
-+ const struct fb_videomode *fbmode = NULL;
-+
-+ fb_var_to_videomode(&varfbmode, var);
-+ fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
-+ if (fbmode)
-+ fb_videomode_to_var(var, fbmode);
-+ return fbmode;
-+}
-+
-+
-+/**
-+ * atmel_lcdfb_check_var - Validates a var passed in.
-+ * @var: frame buffer variable screen structure
-+ * @info: frame buffer structure that represents a single frame buffer
-+ *
-+ * Checks to see if the hardware supports the state requested by
-+ * var passed in. This function does not alter the hardware
-+ * state!!! This means the data stored in struct fb_info and
-+ * struct atmel_lcdfb_info do not change. This includes the var
-+ * inside of struct fb_info. Do NOT change these. This function
-+ * can be called on its own if we intent to only test a mode and
-+ * not actually set it. The stuff in modedb.c is a example of
-+ * this. If the var passed in is slightly off by what the
-+ * hardware can support then we alter the var PASSED in to what
-+ * we can do. If the hardware doesn't support mode change a
-+ * -EINVAL will be returned by the upper layers. You don't need
-+ * to implement this function then. If you hardware doesn't
-+ * support changing the resolution then this function is not
-+ * needed. In this case the driver would just provide a var that
-+ * represents the static state the screen is in.
-+ *
-+ * Returns negative errno on error, or zero on success.
-+ */
-+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ struct device *dev = info->device;
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long clk_value_khz;
-+
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ dev_dbg(dev, "%s:\n", __func__);
-+
-+ if (!(var->pixclock && var->bits_per_pixel)) {
-+ /* choose a suitable mode if possible */
-+ if (!atmel_lcdfb_choose_mode(var, info)) {
-+ dev_err(dev, "needed value not specified\n");
-+ return -EINVAL;
-+ }
-+ }
-+
-+ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
-+ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
-+ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
-+ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
-+
-+ if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
-+ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
-+ return -EINVAL;
-+ }
-+
-+ /* Do not allow to have real resoulution larger than virtual */
-+ if (var->xres > var->xres_virtual)
-+ var->xres_virtual = var->xres;
-+
-+ if (var->yres > var->yres_virtual)
-+ var->yres_virtual = var->yres;
-+
-+ /* Force same alignment for each line */
-+ var->xres = (var->xres + 3) & ~3UL;
-+ var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
-+
-+ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
-+ var->transp.msb_right = 0;
-+ var->transp.offset = var->transp.length = 0;
-+ var->xoffset = var->yoffset = 0;
-+
-+ if (info->fix.smem_len) {
-+ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
-+ * ((var->bits_per_pixel + 7) / 8));
-+ if (smem_len > info->fix.smem_len)
-+ return -EINVAL;
-+ }
-+
-+ /* Saturate vertical and horizontal timings at maximum values */
-+ var->vsync_len = min_t(u32, var->vsync_len,
-+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-+ var->upper_margin = min_t(u32, var->upper_margin,
-+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-+ var->lower_margin = min_t(u32, var->lower_margin,
-+ ATMEL_LCDC_VFP);
-+ var->right_margin = min_t(u32, var->right_margin,
-+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-+ var->hsync_len = min_t(u32, var->hsync_len,
-+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-+ var->left_margin = min_t(u32, var->left_margin,
-+ ATMEL_LCDC_HBP + 1);
-+
-+ /* Some parameters can't be zero */
-+ var->vsync_len = max_t(u32, var->vsync_len, 1);
-+ var->right_margin = max_t(u32, var->right_margin, 1);
-+ var->hsync_len = max_t(u32, var->hsync_len, 1);
-+ var->left_margin = max_t(u32, var->left_margin, 1);
-+
-+ switch (var->bits_per_pixel) {
-+ case 1:
-+ case 2:
-+ case 4:
-+ case 8:
-+ var->red.offset = var->green.offset = var->blue.offset = 0;
-+ var->red.length = var->green.length = var->blue.length
-+ = var->bits_per_pixel;
-+ break;
-+ case 15:
-+ case 16:
-+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
-+ /* RGB:565 mode */
-+ var->red.offset = 11;
-+ var->blue.offset = 0;
-+ var->green.length = 6;
-+ } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
-+ var->red.offset = 10;
-+ var->blue.offset = 0;
-+ var->green.length = 5;
-+ } else {
-+ /* BGR:555 mode */
-+ var->red.offset = 0;
-+ var->blue.offset = 10;
-+ var->green.length = 5;
-+ }
-+ var->green.offset = 5;
-+ var->red.length = var->blue.length = 5;
-+ break;
-+ case 32:
-+ var->transp.offset = 24;
-+ var->transp.length = 8;
-+ /* fall through */
-+ case 24:
-+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
-+ /* RGB:888 mode */
-+ var->red.offset = 16;
-+ var->blue.offset = 0;
-+ } else {
-+ /* BGR:888 mode */
-+ var->red.offset = 0;
-+ var->blue.offset = 16;
-+ }
-+ var->green.offset = 8;
-+ var->red.length = var->green.length = var->blue.length = 8;
-+ break;
-+ default:
-+ dev_err(dev, "color depth %d not supported\n",
-+ var->bits_per_pixel);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * LCD reset sequence
-+ */
-+static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
-+{
-+ might_sleep();
-+
-+ atmel_lcdfb_stop(sinfo);
-+ atmel_lcdfb_start(sinfo);
-+}
-+
-+/**
-+ * atmel_lcdfb_set_par - Alters the hardware state.
-+ * @info: frame buffer structure that represents a single frame buffer
-+ *
-+ * Using the fb_var_screeninfo in fb_info we set the resolution
-+ * of the this particular framebuffer. This function alters the
-+ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
-+ * not alter var in fb_info since we are using that data. This
-+ * means we depend on the data in var inside fb_info to be
-+ * supported by the hardware. atmel_lcdfb_check_var is always called
-+ * before atmel_lcdfb_set_par to ensure this. Again if you can't
-+ * change the resolution you don't need this function.
-+ *
-+ */
-+static int atmel_lcdfb_set_par(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long hozval_linesz;
-+ unsigned long value;
-+ unsigned long clk_value_khz;
-+ unsigned long bits_per_line;
-+ unsigned long pix_factor = 2;
-+
-+ might_sleep();
-+
-+ dev_dbg(info->device, "%s:\n", __func__);
-+ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
-+ info->var.xres, info->var.yres,
-+ info->var.xres_virtual, info->var.yres_virtual);
-+
-+ atmel_lcdfb_stop_nowait(sinfo);
-+
-+ if (info->var.bits_per_pixel == 1)
-+ info->fix.visual = FB_VISUAL_MONO01;
-+ else if (info->var.bits_per_pixel <= 8)
-+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-+ else
-+ info->fix.visual = FB_VISUAL_TRUECOLOR;
-+
-+ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
-+ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
-+
-+ /* Re-initialize the DMA engine... */
-+ dev_dbg(info->device, " * update DMA engine\n");
-+ atmel_lcdfb_update_dma(info, &info->var);
-+
-+ /* ...set frame size and burst length = 8 words (?) */
-+ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-+ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
-+
-+ /* Now, the LCDC core... */
-+
-+ /* Set pixel clock */
-+ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-+ pix_factor = 1;
-+
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+
-+ if (value < pix_factor) {
-+ dev_notice(info->device, "Bypassing pixel clock divider\n");
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-+ } else {
-+ value = (value / pix_factor) - 1;
-+ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-+ value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-+ value << ATMEL_LCDC_CLKVAL_OFFSET);
-+ info->var.pixclock =
-+ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-+ PICOS2KHZ(info->var.pixclock));
-+ }
-+
-+
-+ /* Initialize control register 2 */
-+ value = sinfo->default_lcdcon2;
-+
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVLINE_INVERTED;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVFRAME_INVERTED;
-+
-+ switch (info->var.bits_per_pixel) {
-+ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
-+ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
-+ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
-+ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
-+ case 15: /* fall through */
-+ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
-+ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
-+ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
-+ default: BUG(); break;
-+ }
-+ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
-+
-+ /* Vertical timing */
-+ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-+ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-+ value |= info->var.lower_margin;
-+ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
-+
-+ /* Horizontal timing */
-+ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-+ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-+ value |= (info->var.left_margin - 1);
-+ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
-+
-+ /* Horizontal value (aka line size) */
-+ hozval_linesz = compute_hozval(info->var.xres,
-+ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
-+
-+ /* Display size */
-+ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-+ value |= info->var.yres - 1;
-+ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
-+
-+ /* FIFO Threshold: Use formula from data sheet */
-+ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-+ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
-+
-+ /* Toggle LCD_MODE every frame */
-+ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
-+
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+ /* Enable FIFO & DMA errors */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-+
-+ /* ...wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+
-+ atmel_lcdfb_start(sinfo);
-+
-+ dev_dbg(info->device, " * DONE\n");
-+
-+ return 0;
-+}
-+
-+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
-+{
-+ chan &= 0xffff;
-+ chan >>= 16 - bf->length;
-+ return chan << bf->offset;
-+}
-+
-+/**
-+ * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
-+ * @regno: Which register in the CLUT we are programming
-+ * @red: The red value which can be up to 16 bits wide
-+ * @green: The green value which can be up to 16 bits wide
-+ * @blue: The blue value which can be up to 16 bits wide.
-+ * @transp: If supported the alpha value which can be up to 16 bits wide.
-+ * @info: frame buffer info structure
-+ *
-+ * Set a single color register. The values supplied have a 16 bit
-+ * magnitude which needs to be scaled in this function for the hardware.
-+ * Things to take into consideration are how many color registers, if
-+ * any, are supported with the current color visual. With truecolor mode
-+ * no color palettes are supported. Here a pseudo palette is created
-+ * which we store the value in pseudo_palette in struct fb_info. For
-+ * pseudocolor mode we have a limited color palette. To deal with this
-+ * we can program what color is displayed for a particular pixel value.
-+ * DirectColor is similar in that we can program each color field. If
-+ * we have a static colormap we don't need to implement this function.
-+ *
-+ * Returns negative errno on error, or zero on success. In an
-+ * ideal world, this would have been the case, but as it turns
-+ * out, the other drivers return 1 on failure, so that's what
-+ * we're going to do.
-+ */
-+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
-+ unsigned int green, unsigned int blue,
-+ unsigned int transp, struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned int val;
-+ u32 *pal;
-+ int ret = 1;
-+
-+ if (info->var.grayscale)
-+ red = green = blue = (19595 * red + 38470 * green
-+ + 7471 * blue) >> 16;
-+
-+ switch (info->fix.visual) {
-+ case FB_VISUAL_TRUECOLOR:
-+ if (regno < 16) {
-+ pal = info->pseudo_palette;
-+
-+ val = chan_to_field(red, &info->var.red);
-+ val |= chan_to_field(green, &info->var.green);
-+ val |= chan_to_field(blue, &info->var.blue);
-+
-+ pal[regno] = val;
-+ ret = 0;
-+ }
-+ break;
-+
-+ case FB_VISUAL_PSEUDOCOLOR:
-+ if (regno < 256) {
-+ val = ((red >> 11) & 0x001f);
-+ val |= ((green >> 6) & 0x03e0);
-+ val |= ((blue >> 1) & 0x7c00);
-+
-+ /*
-+ * TODO: intensity bit. Maybe something like
-+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
-+ */
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-+ ret = 0;
-+ }
-+ break;
-+
-+ case FB_VISUAL_MONO01:
-+ if (regno < 2) {
-+ val = (regno == 0) ? 0x00 : 0x1F;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-+ ret = 0;
-+ }
-+ break;
-+
-+ }
-+
-+ return ret;
-+}
-+
-+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ dev_dbg(info->device, "%s\n", __func__);
-+
-+ atmel_lcdfb_update_dma(info, var);
-+
-+ return 0;
-+}
-+
-+static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+
-+ switch (blank_mode) {
-+ case FB_BLANK_UNBLANK:
-+ case FB_BLANK_NORMAL:
-+ atmel_lcdfb_start(sinfo);
-+ break;
-+ case FB_BLANK_VSYNC_SUSPEND:
-+ case FB_BLANK_HSYNC_SUSPEND:
-+ break;
-+ case FB_BLANK_POWERDOWN:
-+ atmel_lcdfb_stop(sinfo);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ /* let fbcon do a soft blank for us */
-+ return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
-+}
-+
-+static struct fb_ops atmel_lcdfb_ops = {
-+ .owner = THIS_MODULE,
-+ .fb_check_var = atmel_lcdfb_check_var,
-+ .fb_set_par = atmel_lcdfb_set_par,
-+ .fb_setcolreg = atmel_lcdfb_setcolreg,
-+ .fb_blank = atmel_lcdfb_blank,
-+ .fb_pan_display = atmel_lcdfb_pan_display,
-+ .fb_fillrect = cfb_fillrect,
-+ .fb_copyarea = cfb_copyarea,
-+ .fb_imageblit = cfb_imageblit,
-+};
-+
-+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
-+{
-+ struct fb_info *info = dev_id;
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ u32 status;
-+
-+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-+ if (status & ATMEL_LCDC_UFLWI) {
-+ dev_warn(info->device, "FIFO underflow %#x\n", status);
-+ /* reset DMA and FIFO to avoid screen shifting */
-+ schedule_work(&sinfo->task);
-+ }
-+ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
-+ return IRQ_HANDLED;
-+}
-+
-+/*
-+ * LCD controller task (to reset the LCD)
-+ */
-+static void atmel_lcdfb_task(struct work_struct *work)
-+{
-+ struct atmel_lcdfb_info *sinfo =
-+ container_of(work, struct atmel_lcdfb_info, task);
-+
-+ atmel_lcdfb_reset(sinfo);
-+}
-+
-+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
-+{
-+ struct fb_info *info = sinfo->info;
-+ int ret = 0;
-+
-+ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
-+
-+ dev_info(info->device,
-+ "%luKiB frame buffer at %08lx (mapped at %p)\n",
-+ (unsigned long)info->fix.smem_len / 1024,
-+ (unsigned long)info->fix.smem_start,
-+ info->screen_base);
-+
-+ /* Allocate colormap */
-+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
-+ if (ret < 0)
-+ dev_err(info->device, "Alloc color map failed\n");
-+
-+ return ret;
-+}
-+
-+void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
-+{
-+ if (sinfo->bus_clk)
-+ clk_enable(sinfo->bus_clk);
-+ clk_enable(sinfo->lcdc_clk);
-+}
-+EXPORT_SYMBOL_GPL(atmel_lcdfb_start_clock);
-+
-+void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
-+{
-+ if (sinfo->bus_clk)
-+ clk_disable(sinfo->bus_clk);
-+ clk_disable(sinfo->lcdc_clk);
-+}
-+EXPORT_SYMBOL_GPL(atmel_lcdfb_stop_clock);
-+
-+
-+int __atmel_lcdfb_probe(struct platform_device *pdev,
-+ struct atmel_lcdfb_devdata *dev_data)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct fb_info *info;
-+ struct atmel_lcdfb_info *sinfo;
-+ struct atmel_lcdfb_info *pdata_sinfo;
-+ struct fb_videomode fbmode;
-+ struct resource *regs = NULL;
-+ struct resource *map = NULL;
-+ int ret;
-+
-+ dev_dbg(dev, "%s BEGIN\n", __func__);
-+
-+ ret = -ENOMEM;
-+ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
-+ if (!info) {
-+ dev_err(dev, "cannot allocate memory\n");
-+ goto out;
-+ }
-+
-+ sinfo = info->par;
-+
-+ if (dev->platform_data) {
-+ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
-+ sinfo->default_bpp = pdata_sinfo->default_bpp;
-+ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
-+ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
-+ sinfo->default_monspecs = pdata_sinfo->default_monspecs;
-+ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
-+ sinfo->guard_time = pdata_sinfo->guard_time;
-+ sinfo->smem_len = pdata_sinfo->smem_len;
-+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
-+ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
-+ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
-+ } else {
-+ dev_err(dev, "cannot get default configuration\n");
-+ goto free_info;
-+ }
-+ sinfo->info = info;
-+ sinfo->pdev = pdev;
-+
-+ strcpy(info->fix.id, sinfo->pdev->name);
-+ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
-+ info->pseudo_palette = sinfo->pseudo_palette;
-+ info->fbops = &atmel_lcdfb_ops;
-+
-+ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
-+ info->fix = atmel_lcdfb_fix;
-+
-+ /* Enable LCDC Clocks */
-+ if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-+ || cpu_is_at32ap7000()) {
-+ sinfo->bus_clk = clk_get(dev, "hck1");
-+ if (IS_ERR(sinfo->bus_clk)) {
-+ ret = PTR_ERR(sinfo->bus_clk);
-+ goto free_info;
-+ }
-+ }
-+ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
-+ if (IS_ERR(sinfo->lcdc_clk)) {
-+ ret = PTR_ERR(sinfo->lcdc_clk);
-+ goto put_bus_clk;
-+ }
-+ atmel_lcdfb_start_clock(sinfo);
-+
-+ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
-+ info->monspecs.modedb_len, info->monspecs.modedb,
-+ sinfo->default_bpp);
-+ if (!ret) {
-+ dev_err(dev, "no suitable video mode found\n");
-+ goto stop_clk;
-+ }
-+
-+
-+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!regs) {
-+ dev_err(dev, "resources unusable\n");
-+ ret = -ENXIO;
-+ goto stop_clk;
-+ }
-+
-+ sinfo->irq_base = platform_get_irq(pdev, 0);
-+ if (sinfo->irq_base < 0) {
-+ dev_err(dev, "unable to get irq\n");
-+ ret = sinfo->irq_base;
-+ goto stop_clk;
-+ }
-+
-+ /* Initialize video memory */
-+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (map) {
-+ /* use a pre-allocated memory buffer */
-+ info->fix.smem_start = map->start;
-+ info->fix.smem_len = map->end - map->start + 1;
-+ if (!request_mem_region(info->fix.smem_start,
-+ info->fix.smem_len, pdev->name)) {
-+ ret = -EBUSY;
-+ goto stop_clk;
-+ }
-+
-+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-+ if (!info->screen_base)
-+ goto release_intmem;
-+
-+ /*
-+ * Don't clear the framebuffer -- someone may have set
-+ * up a splash image.
-+ */
-+ } else {
-+ /* alocate memory buffer */
-+ ret = atmel_lcdfb_alloc_video_memory(sinfo);
-+ if (ret < 0) {
-+ dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
-+ goto stop_clk;
-+ }
-+ }
-+
-+ /* LCDC registers */
-+ info->fix.mmio_start = regs->start;
-+ info->fix.mmio_len = regs->end - regs->start + 1;
-+
-+ if (!request_mem_region(info->fix.mmio_start,
-+ info->fix.mmio_len, pdev->name)) {
-+ ret = -EBUSY;
-+ goto free_fb;
-+ }
-+
-+ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
-+ if (!sinfo->mmio) {
-+ dev_err(dev, "cannot map LCDC registers\n");
-+ goto release_mem;
-+ }
-+
-+ /* Initialize PWM for contrast or backlight ("off") */
-+ init_contrast(sinfo);
-+
-+ /* interrupt */
-+ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
-+ if (ret) {
-+ dev_err(dev, "request_irq failed: %d\n", ret);
-+ goto unmap_mmio;
-+ }
-+
-+ /* Some operations on the LCDC might sleep and
-+ * require a preemptible task context */
-+ INIT_WORK(&sinfo->task, atmel_lcdfb_task);
-+
-+ ret = atmel_lcdfb_init_fbinfo(sinfo);
-+ if (ret < 0) {
-+ dev_err(dev, "init fbinfo failed: %d\n", ret);
-+ goto unregister_irqs;
-+ }
-+
-+ /*
-+ * This makes sure that our colour bitfield
-+ * descriptors are correctly initialised.
-+ */
-+ atmel_lcdfb_check_var(&info->var, info);
-+
-+ ret = fb_set_var(info, &info->var);
-+ if (ret) {
-+ dev_warn(dev, "unable to set display parameters\n");
-+ goto free_cmap;
-+ }
-+
-+ dev_set_drvdata(dev, info);
-+
-+ /*
-+ * Tell the world that we're ready to go
-+ */
-+ ret = register_framebuffer(info);
-+ if (ret < 0) {
-+ dev_err(dev, "failed to register framebuffer device: %d\n", ret);
-+ goto reset_drvdata;
-+ }
-+
-+ /* add selected videomode to modelist */
-+ fb_var_to_videomode(&fbmode, &info->var);
-+ fb_add_videomode(&fbmode, &info->modelist);
-+
-+ /* Power up the LCDC screen */
-+ if (sinfo->atmel_lcdfb_power_control)
-+ sinfo->atmel_lcdfb_power_control(1);
-+
-+ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
-+ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
-+
-+ return 0;
-+
-+reset_drvdata:
-+ dev_set_drvdata(dev, NULL);
-+free_cmap:
-+ fb_dealloc_cmap(&info->cmap);
-+unregister_irqs:
-+ cancel_work_sync(&sinfo->task);
-+ free_irq(sinfo->irq_base, info);
-+unmap_mmio:
-+ exit_backlight(sinfo);
-+ iounmap(sinfo->mmio);
-+release_mem:
-+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-+free_fb:
-+ if (map)
-+ iounmap(info->screen_base);
-+ else
-+ atmel_lcdfb_free_video_memory(sinfo);
-+
-+release_intmem:
-+ if (map)
-+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
-+stop_clk:
-+ atmel_lcdfb_stop_clock(sinfo);
-+ clk_put(sinfo->lcdc_clk);
-+put_bus_clk:
-+ if (sinfo->bus_clk)
-+ clk_put(sinfo->bus_clk);
-+free_info:
-+ framebuffer_release(info);
-+out:
-+ dev_dbg(dev, "%s FAILED\n", __func__);
-+ return ret;
-+}
-+EXPORT_SYMBOL_GPL(__atmel_lcdfb_probe);
-+
-+int __atmel_lcdfb_remove(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct fb_info *info = dev_get_drvdata(dev);
-+ struct atmel_lcdfb_info *sinfo;
-+
-+ if (!info || !info->par)
-+ return 0;
-+ sinfo = info->par;
-+
-+ cancel_work_sync(&sinfo->task);
-+ exit_backlight(sinfo);
-+ if (sinfo->atmel_lcdfb_power_control)
-+ sinfo->atmel_lcdfb_power_control(0);
-+ unregister_framebuffer(info);
-+ atmel_lcdfb_stop_clock(sinfo);
-+ clk_put(sinfo->lcdc_clk);
-+ if (sinfo->bus_clk)
-+ clk_put(sinfo->bus_clk);
-+ fb_dealloc_cmap(&info->cmap);
-+ free_irq(sinfo->irq_base, info);
-+ iounmap(sinfo->mmio);
-+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
-+ iounmap(info->screen_base);
-+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
-+ } else {
-+ atmel_lcdfb_free_video_memory(sinfo);
-+ }
-+
-+ dev_set_drvdata(dev, NULL);
-+ framebuffer_release(info);
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove);
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 5183ab7..4fa084b 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -32,6 +32,13 @@
- #define ATMEL_LCDC_WIRING_RGB 1
- #define ATMEL_LCDC_WIRING_RGB555 2
-
-+extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
-+extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
-+extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
-+extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
-+
-+extern int __atmel_lcdfb_probe(struct platform_device *pdev);
-+extern int __atmel_lcdfb_remove(struct platform_device *pdev);
-
- /* LCD Controller info data structure, stored in device platform_data */
- struct atmel_lcdfb_info {
-@@ -47,9 +54,6 @@ struct atmel_lcdfb_info {
- struct clk *bus_clk;
- struct clk *lcdc_clk;
-
-- struct lcd_dma_desc *p_dma_desc;
-- dma_addr_t dma_desc_phys;
--
- #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
- struct backlight_device *backlight;
- u8 bl_power;
-@@ -68,11 +72,8 @@ struct atmel_lcdfb_info {
- u32 pseudo_palette[16];
- };
-
--struct lcd_dma_desc {
-- u32 address;
-- u32 control;
-- u32 next;
--};
-+#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
-+#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
-
- #define ATMEL_LCDC_DMABADDR1 0x00
- #define ATMEL_LCDC_DMABADDR2 0x04
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From ae87461f10e59a207038af4df8944fabc8c9ac55 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Fri, 28 May 2010 17:13:33 +0200
+Subject: net/macb: memory barriers cleanup
+
+Remove a couple of unneeded barriers and document the remaining ones.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 18 ++++++++++++++----
+ 1 file changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index e9b909a..a4dcd11 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -372,7 +372,9 @@ static void macb_tx(struct macb *bp)
+
+ BUG_ON(skb == NULL);
+
++ /* Make hw descriptor updates visible to CPU */
+ rmb();
++
+ bufstat = bp->tx_ring[tail].ctrl;
+
+ if (!(bufstat & MACB_BIT(TX_USED)))
+@@ -415,7 +417,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ if (frag == last_frag)
+ break;
+ }
++
++ /* Make descriptor updates visible to hardware */
+ wmb();
++
+ return 1;
+ }
+
+@@ -436,12 +441,14 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ frag_len);
+ offset += RX_BUFFER_SIZE;
+ bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
+- wmb();
+
+ if (frag == last_frag)
+ break;
+ }
+
++ /* Make descriptor updates visible to hardware */
++ wmb();
++
+ skb->protocol = eth_type_trans(skb, bp->dev);
+
+ bp->stats.rx_packets++;
+@@ -461,6 +468,8 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+
+ for (frag = begin; frag != end; frag = NEXT_RX(frag))
+ bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++
++ /* Make descriptor updates visible to hardware */
+ wmb();
+
+ /*
+@@ -479,7 +488,9 @@ static int macb_rx(struct macb *bp, int budget)
+ for (; budget > 0; tail = NEXT_RX(tail)) {
+ u32 addr, ctrl;
+
++ /* Make hw descriptor updates visible to CPU */
+ rmb();
++
+ addr = bp->rx_ring[tail].addr;
+ ctrl = bp->rx_ring[tail].ctrl;
+
+@@ -674,6 +685,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+ bp->tx_ring[entry].addr = mapping;
+ bp->tx_ring[entry].ctrl = ctrl;
++
++ /* Make newly initialized descriptor visible to hardware */
+ wmb();
+
+ entry = NEXT_TX(entry);
+@@ -782,9 +795,6 @@ static void macb_init_rings(struct macb *bp)
+
+ static void macb_reset_hw(struct macb *bp)
+ {
+- /* Make sure we have the write buffer for ourselves */
+- wmb();
+-
+ /*
+ * Disable RX and TX (XXX: Should we halt the transmission
+ * more gracefully?)
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 4a211d9df5fc6bfabb2a85f1bbf9610bee0eef32 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Thu, 19 May 2011 14:29:36 +0200
-Subject: video: atmelfb: refactor core setup
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 158 ++++++++++++++++++++++++++++++++++++++-
- drivers/video/atmel_lcdfb_core.c | 126 +------------------------------
- include/video/atmel_lcdc.h | 8 +-
- 3 files changed, 166 insertions(+), 126 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 4e1454c..85063d6 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -12,12 +12,162 @@
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/fb.h>
-+#include <linux/clk.h>
- #include <linux/init.h>
- #include <linux/delay.h>
-
-+#include <mach/board.h>
-+#include <mach/cpu.h>
-+
- #include <video/atmel_lcdc.h>
-
--#ifdef CONFIG_PM
-+/* configurable parameters */
-+#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
-+#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
-+
-+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
-+{
-+ unsigned long value;
-+
-+ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-+ || cpu_is_at32ap7000()))
-+ return xres;
-+
-+ value = xres;
-+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
-+ /* STN display */
-+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
-+ value *= 3;
-+ }
-+ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
-+ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
-+ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
-+ value = DIV_ROUND_UP(value, 4);
-+ else
-+ value = DIV_ROUND_UP(value, 8);
-+ }
-+
-+ return value;
-+}
-+
-+static int atmel_lcdfb_setup_core(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long hozval_linesz;
-+ unsigned long value;
-+ unsigned long clk_value_khz;
-+ unsigned long pix_factor = 2;
-+
-+ /* ...set frame size and burst length = 8 words (?) */
-+ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-+ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
-+
-+ /* Set pixel clock */
-+ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-+ pix_factor = 1;
-+
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+
-+ if (value < pix_factor) {
-+ dev_notice(info->device, "Bypassing pixel clock divider\n");
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-+ } else {
-+ value = (value / pix_factor) - 1;
-+ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-+ value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-+ value << ATMEL_LCDC_CLKVAL_OFFSET);
-+ info->var.pixclock =
-+ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-+ PICOS2KHZ(info->var.pixclock));
-+ }
-+
-+
-+ /* Initialize control register 2 */
-+ value = sinfo->default_lcdcon2;
-+
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVLINE_INVERTED;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ value |= ATMEL_LCDC_INVFRAME_INVERTED;
-+
-+ switch (info->var.bits_per_pixel) {
-+ case 1:
-+ value |= ATMEL_LCDC_PIXELSIZE_1;
-+ break;
-+ case 2:
-+ value |= ATMEL_LCDC_PIXELSIZE_2;
-+ break;
-+ case 4:
-+ value |= ATMEL_LCDC_PIXELSIZE_4;
-+ break;
-+ case 8:
-+ value |= ATMEL_LCDC_PIXELSIZE_8;
-+ break;
-+ case 15: /* fall through */
-+ case 16:
-+ value |= ATMEL_LCDC_PIXELSIZE_16;
-+ break;
-+ case 24:
-+ value |= ATMEL_LCDC_PIXELSIZE_24;
-+ break;
-+ case 32:
-+ value |= ATMEL_LCDC_PIXELSIZE_32;
-+ break;
-+ default:
-+ BUG();
-+ break;
-+ }
-+ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
-+
-+ /* Vertical timing */
-+ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-+ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-+ value |= info->var.lower_margin;
-+ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
-+
-+ /* Horizontal timing */
-+ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-+ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-+ value |= (info->var.left_margin - 1);
-+ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
-+
-+ /* Horizontal value (aka line size) */
-+ hozval_linesz = compute_hozval(info->var.xres,
-+ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
-+
-+ /* Display size */
-+ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-+ value |= info->var.yres - 1;
-+ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
-+
-+ /* FIFO Threshold: Use formula from data sheet */
-+ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-+ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
-+
-+ /* Toggle LCD_MODE every frame */
-+ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
-+
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-+ /* Enable FIFO & DMA errors */
-+ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
-+
-+ /* ...wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+
-+ return 0;
-+}
-+
-
- static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
- {
-@@ -66,9 +216,13 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
- #define atmel_lcdfb_resume NULL
- #endif
-
-+static struct atmel_lcdfb_devdata dev_data = {
-+ .setup_core = atmel_lcdfb_setup_core,
-+};
-+
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
- {
-- return __atmel_lcdfb_probe(pdev);
-+ return __atmel_lcdfb_probe(pdev, &dev_data);
- }
- static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
- {
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 54bdbcb..9a7c5eb 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -27,8 +27,6 @@
-
- /* configurable parameters */
- #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
--#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
--#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
-
- #if defined(CONFIG_ARCH_AT91)
- #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-@@ -183,31 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
- .accel = FB_ACCEL_NONE,
- };
-
--static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
--{
-- unsigned long value;
--
-- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
-- || cpu_is_at32ap7000()))
-- return xres;
--
-- value = xres;
-- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
-- /* STN display */
-- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
-- value *= 3;
-- }
-- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
-- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
-- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
-- value = DIV_ROUND_UP(value, 4);
-- else
-- value = DIV_ROUND_UP(value, 8);
-- }
--
-- return value;
--}
--
- static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
- {
- /* Turn off the LCD controller and the DMA controller */
-@@ -487,11 +460,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
- static int atmel_lcdfb_set_par(struct fb_info *info)
- {
- struct atmel_lcdfb_info *sinfo = info->par;
-- unsigned long hozval_linesz;
-- unsigned long value;
-- unsigned long clk_value_khz;
- unsigned long bits_per_line;
-- unsigned long pix_factor = 2;
-
- might_sleep();
-
-@@ -516,98 +485,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
- dev_dbg(info->device, " * update DMA engine\n");
- atmel_lcdfb_update_dma(info, &info->var);
-
-- /* ...set frame size and burst length = 8 words (?) */
-- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
-- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
-- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
--
- /* Now, the LCDC core... */
--
-- /* Set pixel clock */
-- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
-- pix_factor = 1;
--
-- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
--
-- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
--
-- if (value < pix_factor) {
-- dev_notice(info->device, "Bypassing pixel clock divider\n");
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-- } else {
-- value = (value / pix_factor) - 1;
-- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
-- value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
-- value << ATMEL_LCDC_CLKVAL_OFFSET);
-- info->var.pixclock =
-- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
-- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-- PICOS2KHZ(info->var.pixclock));
-- }
--
--
-- /* Initialize control register 2 */
-- value = sinfo->default_lcdcon2;
--
-- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-- value |= ATMEL_LCDC_INVLINE_INVERTED;
-- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-- value |= ATMEL_LCDC_INVFRAME_INVERTED;
--
-- switch (info->var.bits_per_pixel) {
-- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
-- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
-- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
-- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
-- case 15: /* fall through */
-- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
-- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
-- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
-- default: BUG(); break;
-- }
-- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
--
-- /* Vertical timing */
-- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
-- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
-- value |= info->var.lower_margin;
-- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
--
-- /* Horizontal timing */
-- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
-- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
-- value |= (info->var.left_margin - 1);
-- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
--
-- /* Horizontal value (aka line size) */
-- hozval_linesz = compute_hozval(info->var.xres,
-- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
--
-- /* Display size */
-- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
-- value |= info->var.yres - 1;
-- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
-- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
--
-- /* FIFO Threshold: Use formula from data sheet */
-- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
-- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
--
-- /* Toggle LCD_MODE every frame */
-- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
--
-- /* Disable all interrupts */
-- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
-- /* Enable FIFO & DMA errors */
-- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
--
-- /* ...wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
-+ sinfo->dev_data->setup_core(info);
-
- atmel_lcdfb_start(sinfo);
-
-@@ -837,7 +716,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
-
- sinfo = info->par;
-
-- if (dev->platform_data) {
-+ if (dev->platform_data && dev_data) {
- pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
- sinfo->default_bpp = pdata_sinfo->default_bpp;
- sinfo->default_dmacon = pdata_sinfo->default_dmacon;
-@@ -849,6 +728,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
- sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
- sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
-+ sinfo->dev_data = dev_data;
- } else {
- dev_err(dev, "cannot get default configuration\n");
- goto free_info;
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 4fa084b..b1a5fad1 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -37,15 +37,21 @@ extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
- extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
- extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
-
--extern int __atmel_lcdfb_probe(struct platform_device *pdev);
-+extern int __atmel_lcdfb_probe(struct platform_device *pdev,
-+ struct atmel_lcdfb_devdata *devdata);
- extern int __atmel_lcdfb_remove(struct platform_device *pdev);
-
-+struct atmel_lcdfb_devdata {
-+ int (*setup_core)(struct fb_info *info);
-+};
-+
- /* LCD Controller info data structure, stored in device platform_data */
- struct atmel_lcdfb_info {
- spinlock_t lock;
- struct fb_info *info;
- void __iomem *mmio;
- int irq_base;
-+ struct atmel_lcdfb_devdata *dev_data;
- struct work_struct task;
-
- unsigned int guard_time;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 60a3639d4642fc21195f51f4875c07d7418c5097 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Fri, 28 May 2010 17:45:43 +0200
+Subject: net/macb: change debugging messages
+
+Convert some noisy netdev_dbg() statements to netdev_vdbg(). Defining
+DEBUG will no longer fill up the logs; VERBOSE_DEBUG still does.
+Add one more verbose debug for ISR status.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics, add ISR status]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 22 ++++++++++++----------
+ 1 file changed, 12 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index a4dcd11..ce1f558 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
+ status = macb_readl(bp, TSR);
+ macb_writel(bp, TSR, status);
+
+- netdev_dbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
++ netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
+
+ if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+ int i;
+@@ -380,7 +380,7 @@ static void macb_tx(struct macb *bp)
+ if (!(bufstat & MACB_BIT(TX_USED)))
+ break;
+
+- netdev_dbg(bp->dev, "skb %u (data %p) TX complete\n",
++ netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
+ tail, skb->data);
+ dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
+ DMA_TO_DEVICE);
+@@ -406,7 +406,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+
+ len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
+
+- netdev_dbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
++ netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
+ first_frag, last_frag, len);
+
+ skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
+@@ -453,7 +453,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+
+ bp->stats.rx_packets++;
+ bp->stats.rx_bytes += len;
+- netdev_dbg(bp->dev, "received skb of length %u, csum: %08x\n",
++ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
+ skb->len, skb->csum);
+ netif_receive_skb(skb);
+
+@@ -535,7 +535,7 @@ static int macb_poll(struct napi_struct *napi, int budget)
+
+ work_done = 0;
+
+- netdev_dbg(bp->dev, "poll: status = %08lx, budget = %d\n",
++ netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
+ (unsigned long)status, budget);
+
+ work_done = macb_rx(bp, budget);
+@@ -574,6 +574,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ break;
+ }
+
++ netdev_vdbg(bp->dev, "isr = 0x%08lx\n", (unsigned long)status);
++
+ if (status & MACB_RX_INT_FLAGS) {
+ /*
+ * There's no point taking any more interrupts
+@@ -585,7 +587,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
+
+ if (napi_schedule_prep(&bp->napi)) {
+- netdev_dbg(bp->dev, "scheduling RX softirq\n");
++ netdev_vdbg(bp->dev, "scheduling RX softirq\n");
+ __napi_schedule(&bp->napi);
+ }
+ }
+@@ -647,8 +649,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ u32 ctrl;
+ unsigned long flags;
+
+-#ifdef DEBUG
+- netdev_dbg(bp->dev,
++#if defined(DEBUG) && defined(VERBOSE_DEBUG)
++ netdev_vdbg(bp->dev,
+ "start_xmit: len %u head %p data %p tail %p end %p\n",
+ skb->len, skb->head, skb->data,
+ skb_tail_pointer(skb), skb_end_pointer(skb));
+@@ -670,12 +672,12 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ }
+
+ entry = bp->tx_head;
+- netdev_dbg(bp->dev, "Allocated ring entry %u\n", entry);
++ netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ len, DMA_TO_DEVICE);
+ bp->tx_skb[entry].skb = skb;
+ bp->tx_skb[entry].mapping = mapping;
+- netdev_dbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
++ netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
+ skb->data, (unsigned long)mapping);
+
+ ctrl = MACB_BF(TX_FRMLEN, len);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 93000ba8524c38cd973ad541bf8675a204cad07a Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Thu, 19 May 2011 15:12:30 +0200
-Subject: video: atmelfb: refactor start/stop
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 30 +++++++++++++++++++++++-
- drivers/video/atmel_lcdfb_core.c | 50 ++++++++++------------------------------
- include/video/atmel_lcdc.h | 9 +++++---
- 3 files changed, 47 insertions(+), 42 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 85063d6..422be1a 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -25,6 +25,32 @@
- #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
- #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
-
-+void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
-+{
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-+ | ATMEL_LCDC_PWR);
-+}
-+
-+static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
-+{
-+ /* Turn off the LCD controller and the DMA controller */
-+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-+ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
-+
-+ /* Wait for the LCDC core to become idle */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-+ msleep(10);
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
-+
-+ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
-+ /* Wait for DMA engine to become idle... */
-+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-+ msleep(10);
-+}
-+
- static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
- {
- unsigned long value;
-@@ -186,7 +212,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
- if (sinfo->atmel_lcdfb_power_control)
- sinfo->atmel_lcdfb_power_control(0);
-
-- atmel_lcdfb_stop(sinfo);
-+ atmel_lcdfb_stop(sinfo, 0);
- atmel_lcdfb_stop_clock(sinfo);
-
- return 0;
-@@ -218,6 +244,8 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
-
- static struct atmel_lcdfb_devdata dev_data = {
- .setup_core = atmel_lcdfb_setup_core,
-+ .start = atmel_lcdfb_start,
-+ .stop = atmel_lcdfb_stop,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 9a7c5eb..8413b76 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -181,38 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
- .accel = FB_ACCEL_NONE,
- };
-
--static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
--{
-- /* Turn off the LCD controller and the DMA controller */
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
--
-- /* Wait for the LCDC core to become idle */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
-- msleep(10);
--
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
--}
--
--void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
--{
-- atmel_lcdfb_stop_nowait(sinfo);
--
-- /* Wait for DMA engine to become idle... */
-- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
-- msleep(10);
--}
--EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
--
--void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
--{
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
-- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
-- | ATMEL_LCDC_PWR);
--}
--EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
--
- static void atmel_lcdfb_update_dma(struct fb_info *info,
- struct fb_var_screeninfo *var)
- {
-@@ -439,8 +407,10 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
- {
- might_sleep();
-
-- atmel_lcdfb_stop(sinfo);
-- atmel_lcdfb_start(sinfo);
-+ if (sinfo->dev_data->stop)
-+ sinfo->dev_data->stop(sinfo, 0);
-+ if (sinfo->dev_data->start)
-+ sinfo->dev_data->start(sinfo);
- }
-
- /**
-@@ -469,7 +439,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
- info->var.xres, info->var.yres,
- info->var.xres_virtual, info->var.yres_virtual);
-
-- atmel_lcdfb_stop_nowait(sinfo);
-+ if (sinfo->dev_data->stop)
-+ sinfo->dev_data->stop(sinfo, ATMEL_LCDC_STOP_NOWAIT);
-
- if (info->var.bits_per_pixel == 1)
- info->fix.visual = FB_VISUAL_MONO01;
-@@ -488,7 +459,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
- /* Now, the LCDC core... */
- sinfo->dev_data->setup_core(info);
-
-- atmel_lcdfb_start(sinfo);
-+ if (sinfo->dev_data->start)
-+ sinfo->dev_data->start(sinfo);
-
- dev_dbg(info->device, " * DONE\n");
-
-@@ -600,13 +572,15 @@ static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
- switch (blank_mode) {
- case FB_BLANK_UNBLANK:
- case FB_BLANK_NORMAL:
-- atmel_lcdfb_start(sinfo);
-+ if (sinfo->dev_data->start)
-+ sinfo->dev_data->start(sinfo);
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- break;
- case FB_BLANK_POWERDOWN:
-- atmel_lcdfb_stop(sinfo);
-+ if (sinfo->dev_data->stop)
-+ sinfo->dev_data->stop(sinfo, 0);
- break;
- default:
- return -EINVAL;
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index b1a5fad1..ea7ce31 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -32,17 +32,20 @@
- #define ATMEL_LCDC_WIRING_RGB 1
- #define ATMEL_LCDC_WIRING_RGB555 2
-
--extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
--extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
-+#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
-+
- extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
- extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
--
- extern int __atmel_lcdfb_probe(struct platform_device *pdev,
- struct atmel_lcdfb_devdata *devdata);
- extern int __atmel_lcdfb_remove(struct platform_device *pdev);
-
-+struct atmel_lcdfb_info;
-+
- struct atmel_lcdfb_devdata {
- int (*setup_core)(struct fb_info *info);
-+ void (*start)(struct atmel_lcdfb_info *sinfo);
-+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
- };
-
- /* LCD Controller info data structure, stored in device platform_data */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From d34b7418567147f5a2ea6a890328c41f3743b862 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 6 Sep 2012 15:23:47 +0200
+Subject: net/macb: remove macb_get_drvinfo()
+
+This function has little meaning so remove it altogether and
+let ethtool core fill in the fields automatically.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index ce1f558..dc34ff1 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -1223,20 +1223,9 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ return phy_ethtool_sset(phydev, cmd);
+ }
+
+-static void macb_get_drvinfo(struct net_device *dev,
+- struct ethtool_drvinfo *info)
+-{
+- struct macb *bp = netdev_priv(dev);
+-
+- strcpy(info->driver, bp->pdev->dev.driver->name);
+- strcpy(info->version, "$Revision: 1.14 $");
+- strcpy(info->bus_info, dev_name(&bp->pdev->dev));
+-}
+-
+ static const struct ethtool_ops macb_ethtool_ops = {
+ .get_settings = macb_get_settings,
+ .set_settings = macb_set_settings,
+- .get_drvinfo = macb_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ };
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 8043f427b2e8eb8f92e1193836809b0454c424e4 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Thu, 19 May 2011 15:37:12 +0200
-Subject: video: atmelfb: refactor isr
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++
- drivers/video/atmel_lcdfb_core.c | 39 ++++++++++++---------------------------
- include/video/atmel_lcdc.h | 2 ++
- 3 files changed, 32 insertions(+), 27 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 422be1a..3653e2a 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -194,6 +194,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
- return 0;
- }
-
-+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
-+{
-+ struct fb_info *info = dev_id;
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ u32 status;
-+
-+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-+ if (status & ATMEL_LCDC_UFLWI) {
-+ dev_warn(info->device, "FIFO underflow %#x\n", status);
-+ /* reset DMA and FIFO to avoid screen shifting */
-+ schedule_work(&sinfo->task);
-+ }
-+ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
-+ return IRQ_HANDLED;
-+}
-+
-+#ifdef CONFIG_PM
-
- static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
- {
-@@ -246,6 +263,7 @@ static struct atmel_lcdfb_devdata dev_data = {
- .setup_core = atmel_lcdfb_setup_core,
- .start = atmel_lcdfb_start,
- .stop = atmel_lcdfb_stop,
-+ .isr = atmel_lcdfb_interrupt,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 8413b76..eab4d88 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -602,22 +602,6 @@ static struct fb_ops atmel_lcdfb_ops = {
- .fb_imageblit = cfb_imageblit,
- };
-
--static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
--{
-- struct fb_info *info = dev_id;
-- struct atmel_lcdfb_info *sinfo = info->par;
-- u32 status;
--
-- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
-- if (status & ATMEL_LCDC_UFLWI) {
-- dev_warn(info->device, "FIFO underflow %#x\n", status);
-- /* reset DMA and FIFO to avoid screen shifting */
-- schedule_work(&sinfo->task);
-- }
-- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
-- return IRQ_HANDLED;
--}
--
- /*
- * LCD controller task (to reset the LCD)
- */
-@@ -750,12 +734,8 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- goto stop_clk;
- }
-
-+ /* No error checking, some devices can do without IRQ */
- sinfo->irq_base = platform_get_irq(pdev, 0);
-- if (sinfo->irq_base < 0) {
-- dev_err(dev, "unable to get irq\n");
-- ret = sinfo->irq_base;
-- goto stop_clk;
-- }
-
- /* Initialize video memory */
- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-@@ -806,10 +786,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- init_contrast(sinfo);
-
- /* interrupt */
-- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
-- if (ret) {
-- dev_err(dev, "request_irq failed: %d\n", ret);
-- goto unmap_mmio;
-+ if (sinfo->irq_base >= 0) {
-+ ret = request_irq(sinfo->irq_base, sinfo->dev_data->isr,
-+ IRQF_SHARED, pdev->name, info);
-+ if (ret) {
-+ dev_err(dev, "request_irq failed: %d\n", ret);
-+ goto unmap_mmio;
-+ }
- }
-
- /* Some operations on the LCDC might sleep and
-@@ -864,7 +847,8 @@ free_cmap:
- fb_dealloc_cmap(&info->cmap);
- unregister_irqs:
- cancel_work_sync(&sinfo->task);
-- free_irq(sinfo->irq_base, info);
-+ if (sinfo->irq_base >= 0)
-+ free_irq(sinfo->irq_base, info);
- unmap_mmio:
- exit_backlight(sinfo);
- iounmap(sinfo->mmio);
-@@ -913,7 +897,8 @@ int __atmel_lcdfb_remove(struct platform_device *pdev)
- if (sinfo->bus_clk)
- clk_put(sinfo->bus_clk);
- fb_dealloc_cmap(&info->cmap);
-- free_irq(sinfo->irq_base, info);
-+ if (sinfo->irq_base >= 0)
-+ free_irq(sinfo->irq_base, info);
- iounmap(sinfo->mmio);
- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index ea7ce31..14b5664 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -23,6 +23,7 @@
- #define __ATMEL_LCDC_H__
-
- #include <linux/workqueue.h>
-+#include <linux/interrupt.h>
-
- /* Way LCD wires are connected to the chip:
- * Some Atmel chips use BGR color mode (instead of standard RGB)
-@@ -46,6 +47,7 @@ struct atmel_lcdfb_devdata {
- int (*setup_core)(struct fb_info *info);
- void (*start)(struct atmel_lcdfb_info *sinfo);
- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
-+ irqreturn_t (*isr)(int irq, void *dev_id);
- };
-
- /* LCD Controller info data structure, stored in device platform_data */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From dab3e98e23315687f3aa67714b003f5ff96e3df2 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 3 Sep 2012 17:52:09 +0200
+Subject: net/macb: tx status is more than 8 bits now
+
+On some revision of GEM, TSR status register has more information.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index dc34ff1..4e05a29 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -313,7 +313,7 @@ static void macb_tx(struct macb *bp)
+ status = macb_readl(bp, TSR);
+ macb_writel(bp, TSR, status);
+
+- netdev_vdbg(bp->dev, "macb_tx status = %02lx\n", (unsigned long)status);
++ netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
+
+ if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+ int i;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From bf33aaec05fd4dc512ce1cc11de5562c8b5bfefc Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Thu, 19 May 2011 16:40:13 +0200
-Subject: video: atmelfb: refactor backlight routines
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 61 +++++++++++++++++++++++++++++++++
- drivers/video/atmel_lcdfb_core.c | 73 ++++------------------------------------
- include/video/atmel_lcdc.h | 3 ++
- 3 files changed, 71 insertions(+), 66 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 3653e2a..046e6c5 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -11,6 +11,7 @@
- #include <linux/kernel.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
-+#include <linux/backlight.h>
- #include <linux/fb.h>
- #include <linux/clk.h>
- #include <linux/init.h>
-@@ -22,9 +23,67 @@
- #include <video/atmel_lcdc.h>
-
- /* configurable parameters */
-+#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
- #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
- #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
-
-+static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
-+ | ATMEL_LCDC_POL_POSITIVE
-+ | ATMEL_LCDC_ENA_PWMENABLE;
-+
-+/* some bl->props field just changed */
-+static int atmel_bl_update_status(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+ int power = sinfo->bl_power;
-+ int brightness = bl->props.brightness;
-+
-+ /* REVISIT there may be a meaningful difference between
-+ * fb_blank and power ... there seem to be some cases
-+ * this doesn't handle correctly.
-+ */
-+ if (bl->props.fb_blank != sinfo->bl_power)
-+ power = bl->props.fb_blank;
-+ else if (bl->props.power != sinfo->bl_power)
-+ power = bl->props.power;
-+
-+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
-+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+ else if (power != FB_BLANK_UNBLANK)
-+ brightness = 0;
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-+ brightness ? contrast_ctr : 0);
-+
-+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
-+
-+ return 0;
-+}
-+
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+
-+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-+}
-+
-+static const struct backlight_ops atmel_lcdc_bl_ops = {
-+ .update_status = atmel_bl_update_status,
-+ .get_brightness = atmel_bl_get_brightness,
-+};
-+
-+static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
-+{
-+ /* contrast pwm can be 'inverted' */
-+ if (sinfo->lcdcon_pol_negative)
-+ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
-+
-+ /* have some default contrast/backlight settings */
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
-+}
-+
- void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
- {
- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
-@@ -264,6 +323,8 @@ static struct atmel_lcdfb_devdata dev_data = {
- .start = atmel_lcdfb_start,
- .stop = atmel_lcdfb_stop,
- .isr = atmel_lcdfb_interrupt,
-+ .bl_ops = &atmel_lcdc_bl_ops,
-+ .init_contrast = atmel_lcdfb_init_contrast,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index eab4d88..ef63996 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -16,7 +16,6 @@
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/delay.h>
--#include <linux/backlight.h>
- #include <linux/gfp.h>
-
- #include <mach/board.h>
-@@ -63,54 +62,8 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
- }
- #endif
-
--static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
-- | ATMEL_LCDC_POL_POSITIVE
-- | ATMEL_LCDC_ENA_PWMENABLE;
--
- #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-
--/* some bl->props field just changed */
--static int atmel_bl_update_status(struct backlight_device *bl)
--{
-- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-- int power = sinfo->bl_power;
-- int brightness = bl->props.brightness;
--
-- /* REVISIT there may be a meaningful difference between
-- * fb_blank and power ... there seem to be some cases
-- * this doesn't handle correctly.
-- */
-- if (bl->props.fb_blank != sinfo->bl_power)
-- power = bl->props.fb_blank;
-- else if (bl->props.power != sinfo->bl_power)
-- power = bl->props.power;
--
-- if (brightness < 0 && power == FB_BLANK_UNBLANK)
-- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
-- else if (power != FB_BLANK_UNBLANK)
-- brightness = 0;
--
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
-- brightness ? contrast_ctr : 0);
--
-- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
--
-- return 0;
--}
--
--static int atmel_bl_get_brightness(struct backlight_device *bl)
--{
-- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
--
-- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
--}
--
--static const struct backlight_ops atmel_lcdc_bl_ops = {
-- .update_status = atmel_bl_update_status,
-- .get_brightness = atmel_bl_get_brightness,
--};
--
- static void init_backlight(struct atmel_lcdfb_info *sinfo)
- {
- struct backlight_properties props;
-@@ -118,14 +71,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
-
- sinfo->bl_power = FB_BLANK_UNBLANK;
-
-- if (sinfo->backlight)
-+ if (sinfo->backlight || !sinfo->dev_data->bl_ops)
- return;
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = 0xff;
- bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
-- &atmel_lcdc_bl_ops, &props);
-+ sinfo->dev_data->bl_ops, &props);
- if (IS_ERR(bl)) {
- dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
- PTR_ERR(bl));
-@@ -135,7 +88,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
-
- bl->props.power = FB_BLANK_UNBLANK;
- bl->props.fb_blank = FB_BLANK_UNBLANK;
-- bl->props.brightness = atmel_bl_get_brightness(bl);
-+ bl->props.brightness = sinfo->dev_data->bl_ops->get_brightness(bl);
- }
-
- static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-@@ -157,21 +110,6 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
-
- #endif
-
--static void init_contrast(struct atmel_lcdfb_info *sinfo)
--{
-- /* contrast pwm can be 'inverted' */
-- if (sinfo->lcdcon_pol_negative)
-- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
--
-- /* have some default contrast/backlight settings */
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
-- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
--
-- if (sinfo->lcdcon_is_backlight)
-- init_backlight(sinfo);
--}
--
--
- static struct fb_fix_screeninfo atmel_lcdfb_fix = {
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_TRUECOLOR,
-@@ -783,7 +721,10 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- }
-
- /* Initialize PWM for contrast or backlight ("off") */
-- init_contrast(sinfo);
-+ if (sinfo->dev_data->init_contrast)
-+ sinfo->dev_data->init_contrast(sinfo);
-+ if (sinfo->lcdcon_is_backlight)
-+ init_backlight(sinfo);
-
- /* interrupt */
- if (sinfo->irq_base >= 0) {
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 14b5664..e7c0a3f 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -24,6 +24,7 @@
-
- #include <linux/workqueue.h>
- #include <linux/interrupt.h>
-+#include <linux/backlight.h>
-
- /* Way LCD wires are connected to the chip:
- * Some Atmel chips use BGR color mode (instead of standard RGB)
-@@ -48,6 +49,8 @@ struct atmel_lcdfb_devdata {
- void (*start)(struct atmel_lcdfb_info *sinfo);
- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
- irqreturn_t (*isr)(int irq, void *dev_id);
-+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
-+ const struct backlight_ops *bl_ops;
- };
-
- /* LCD Controller info data structure, stored in device platform_data */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f7d00d86af150d53a98b12fb609ac0b98d6044f6 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Mon, 21 Jun 2010 18:56:29 +0200
+Subject: net/macb: clean up ring buffer logic
+
+Instead of masking head and tail every time we increment them, just let them
+wrap through UINT_MAX and mask them when subscripting. Add simple accessor
+functions to do the subscripting properly to minimize the chances of messing
+this up.
+
+This makes the code slightly smaller, and hopefully faster as well. Also,
+doing the ring buffer management this way will simplify things a lot when
+making the ring sizes configurable in the future.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: split patch in topics, adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 168 +++++++++++++++++++++++-------------
+ drivers/net/ethernet/cadence/macb.h | 22 +++--
+ 2 files changed, 122 insertions(+), 68 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 4e05a29..2554354 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -31,24 +31,13 @@
+
+ #define RX_BUFFER_SIZE 128
+ #define RX_RING_SIZE 512
+-#define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE)
++#define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
+
+ /* Make the IP header word-aligned (the ethernet header is 14 bytes) */
+ #define RX_OFFSET 2
+
+ #define TX_RING_SIZE 128
+-#define DEF_TX_RING_PENDING (TX_RING_SIZE - 1)
+-#define TX_RING_BYTES (sizeof(struct dma_desc) * TX_RING_SIZE)
+-
+-#define TX_RING_GAP(bp) \
+- (TX_RING_SIZE - (bp)->tx_pending)
+-#define TX_BUFFS_AVAIL(bp) \
+- (((bp)->tx_tail <= (bp)->tx_head) ? \
+- (bp)->tx_tail + (bp)->tx_pending - (bp)->tx_head : \
+- (bp)->tx_tail - (bp)->tx_head - TX_RING_GAP(bp))
+-#define NEXT_TX(n) (((n) + 1) & (TX_RING_SIZE - 1))
+-
+-#define NEXT_RX(n) (((n) + 1) & (RX_RING_SIZE - 1))
++#define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+ /* minimum number of free TX descriptors before waking up TX process */
+ #define MACB_TX_WAKEUP_THRESH (TX_RING_SIZE / 4)
+@@ -56,6 +45,51 @@
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
+
++/* Ring buffer accessors */
++static unsigned int macb_tx_ring_wrap(unsigned int index)
++{
++ return index & (TX_RING_SIZE - 1);
++}
++
++static unsigned int macb_tx_ring_avail(struct macb *bp)
++{
++ return TX_RING_SIZE - (bp->tx_head - bp->tx_tail);
++}
++
++static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index)
++{
++ return &bp->tx_ring[macb_tx_ring_wrap(index)];
++}
++
++static struct macb_tx_skb *macb_tx_skb(struct macb *bp, unsigned int index)
++{
++ return &bp->tx_skb[macb_tx_ring_wrap(index)];
++}
++
++static dma_addr_t macb_tx_dma(struct macb *bp, unsigned int index)
++{
++ dma_addr_t offset;
++
++ offset = macb_tx_ring_wrap(index) * sizeof(struct macb_dma_desc);
++
++ return bp->tx_ring_dma + offset;
++}
++
++static unsigned int macb_rx_ring_wrap(unsigned int index)
++{
++ return index & (RX_RING_SIZE - 1);
++}
++
++static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
++{
++ return &bp->rx_ring[macb_rx_ring_wrap(index)];
++}
++
++static void *macb_rx_buffer(struct macb *bp, unsigned int index)
++{
++ return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
++}
++
+ static void __macb_set_hwaddr(struct macb *bp)
+ {
+ u32 bottom;
+@@ -335,17 +369,18 @@ static void macb_tx(struct macb *bp)
+ bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ /* free transmit buffer in upper layer*/
+- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
+- struct ring_info *rp = &bp->tx_skb[tail];
+- struct sk_buff *skb = rp->skb;
+-
+- BUG_ON(skb == NULL);
++ for (tail = bp->tx_tail; tail != head; tail++) {
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
+
+ rmb();
+
+- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
+- DMA_TO_DEVICE);
+- rp->skb = NULL;
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
++
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
++ skb->len, DMA_TO_DEVICE);
++ tx_skb->skb = NULL;
+ dev_kfree_skb_irq(skb);
+ }
+
+@@ -365,34 +400,38 @@ static void macb_tx(struct macb *bp)
+ return;
+
+ head = bp->tx_head;
+- for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) {
+- struct ring_info *rp = &bp->tx_skb[tail];
+- struct sk_buff *skb = rp->skb;
+- u32 bufstat;
++ for (tail = bp->tx_tail; tail != head; tail++) {
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
++ u32 ctrl;
+
+- BUG_ON(skb == NULL);
++ desc = macb_tx_desc(bp, tail);
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+- bufstat = bp->tx_ring[tail].ctrl;
++ ctrl = desc->ctrl;
+
+- if (!(bufstat & MACB_BIT(TX_USED)))
++ if (!(ctrl & MACB_BIT(TX_USED)))
+ break;
+
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
++
+ netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
+- tail, skb->data);
+- dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
++ macb_tx_ring_wrap(tail), skb->data);
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
+ DMA_TO_DEVICE);
+ bp->stats.tx_packets++;
+ bp->stats.tx_bytes += skb->len;
+- rp->skb = NULL;
++ tx_skb->skb = NULL;
+ dev_kfree_skb_irq(skb);
+ }
+
+ bp->tx_tail = tail;
+- if (netif_queue_stopped(bp->dev) &&
+- TX_BUFFS_AVAIL(bp) > MACB_TX_WAKEUP_THRESH)
++ if (netif_queue_stopped(bp->dev)
++ && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH)
+ netif_wake_queue(bp->dev);
+ }
+
+@@ -403,17 +442,21 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ unsigned int frag;
+ unsigned int offset = 0;
+ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
+
+- len = MACB_BFEXT(RX_FRMLEN, bp->rx_ring[last_frag].ctrl);
++ desc = macb_rx_desc(bp, last_frag);
++ len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
+
+ netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n",
+- first_frag, last_frag, len);
++ macb_rx_ring_wrap(first_frag),
++ macb_rx_ring_wrap(last_frag), len);
+
+ skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
+ if (!skb) {
+ bp->stats.rx_dropped++;
+- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ for (frag = first_frag; ; frag++) {
++ desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
+ if (frag == last_frag)
+ break;
+ }
+@@ -428,7 +471,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+
+- for (frag = first_frag; ; frag = NEXT_RX(frag)) {
++ for (frag = first_frag; ; frag++) {
+ unsigned int frag_len = RX_BUFFER_SIZE;
+
+ if (offset + frag_len > len) {
+@@ -436,11 +479,10 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ frag_len = len - offset;
+ }
+ skb_copy_to_linear_data_offset(skb, offset,
+- (bp->rx_buffers +
+- (RX_BUFFER_SIZE * frag)),
+- frag_len);
++ macb_rx_buffer(bp, frag), frag_len);
+ offset += RX_BUFFER_SIZE;
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
+
+ if (frag == last_frag)
+ break;
+@@ -466,8 +508,10 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+ {
+ unsigned int frag;
+
+- for (frag = begin; frag != end; frag = NEXT_RX(frag))
+- bp->rx_ring[frag].addr &= ~MACB_BIT(RX_USED);
++ for (frag = begin; frag != end; frag++) {
++ struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
++ desc->addr &= ~MACB_BIT(RX_USED);
++ }
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+@@ -482,17 +526,18 @@ static void discard_partial_frame(struct macb *bp, unsigned int begin,
+ static int macb_rx(struct macb *bp, int budget)
+ {
+ int received = 0;
+- unsigned int tail = bp->rx_tail;
++ unsigned int tail;
+ int first_frag = -1;
+
+- for (; budget > 0; tail = NEXT_RX(tail)) {
++ for (tail = bp->rx_tail; budget > 0; tail++) {
++ struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
+ u32 addr, ctrl;
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+- addr = bp->rx_ring[tail].addr;
+- ctrl = bp->rx_ring[tail].ctrl;
++ addr = desc->addr;
++ ctrl = desc->ctrl;
+
+ if (!(addr & MACB_BIT(RX_USED)))
+ break;
+@@ -646,6 +691,8 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ struct macb *bp = netdev_priv(dev);
+ dma_addr_t mapping;
+ unsigned int len, entry;
++ struct macb_dma_desc *desc;
++ struct macb_tx_skb *tx_skb;
+ u32 ctrl;
+ unsigned long flags;
+
+@@ -662,7 +709,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ spin_lock_irqsave(&bp->lock, flags);
+
+ /* This is a hard error, log it. */
+- if (TX_BUFFS_AVAIL(bp) < 1) {
++ if (macb_tx_ring_avail(bp) < 1) {
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&bp->lock, flags);
+ netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n");
+@@ -671,12 +718,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ return NETDEV_TX_BUSY;
+ }
+
+- entry = bp->tx_head;
++ entry = macb_tx_ring_wrap(bp->tx_head);
++ bp->tx_head++;
+ netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
+ mapping = dma_map_single(&bp->pdev->dev, skb->data,
+ len, DMA_TO_DEVICE);
+- bp->tx_skb[entry].skb = skb;
+- bp->tx_skb[entry].mapping = mapping;
++
++ tx_skb = &bp->tx_skb[entry];
++ tx_skb->skb = skb;
++ tx_skb->mapping = mapping;
+ netdev_vdbg(bp->dev, "Mapped skb data %p to DMA addr %08lx\n",
+ skb->data, (unsigned long)mapping);
+
+@@ -685,20 +735,18 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ if (entry == (TX_RING_SIZE - 1))
+ ctrl |= MACB_BIT(TX_WRAP);
+
+- bp->tx_ring[entry].addr = mapping;
+- bp->tx_ring[entry].ctrl = ctrl;
++ desc = &bp->tx_ring[entry];
++ desc->addr = mapping;
++ desc->ctrl = ctrl;
+
+ /* Make newly initialized descriptor visible to hardware */
+ wmb();
+
+- entry = NEXT_TX(entry);
+- bp->tx_head = entry;
+-
+ skb_tx_timestamp(skb);
+
+ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
+
+- if (TX_BUFFS_AVAIL(bp) < 1)
++ if (macb_tx_ring_avail(bp) < 1)
+ netif_stop_queue(dev);
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+@@ -734,7 +782,7 @@ static int macb_alloc_consistent(struct macb *bp)
+ {
+ int size;
+
+- size = TX_RING_SIZE * sizeof(struct ring_info);
++ size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
+ bp->tx_skb = kmalloc(size, GFP_KERNEL);
+ if (!bp->tx_skb)
+ goto out_err;
+@@ -1407,8 +1455,6 @@ static int __init macb_probe(struct platform_device *pdev)
+ macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
+ #endif
+
+- bp->tx_pending = DEF_TX_RING_PENDING;
+-
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index f69ceef..8a4ee2f 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -356,7 +356,12 @@
+ __v; \
+ })
+
+-struct dma_desc {
++/**
++ * struct macb_dma_desc - Hardware DMA descriptor
++ * @addr: DMA address of data buffer
++ * @ctrl: Control and status bits
++ */
++struct macb_dma_desc {
+ u32 addr;
+ u32 ctrl;
+ };
+@@ -421,7 +426,12 @@ struct dma_desc {
+ #define MACB_TX_USED_OFFSET 31
+ #define MACB_TX_USED_SIZE 1
+
+-struct ring_info {
++/**
++ * struct macb_tx_skb - data about an skb which is being transmitted
++ * @skb: skb currently being transmitted
++ * @mapping: DMA address of the skb's data buffer
++ */
++struct macb_tx_skb {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ };
+@@ -506,12 +516,12 @@ struct macb {
+ void __iomem *regs;
+
+ unsigned int rx_tail;
+- struct dma_desc *rx_ring;
++ struct macb_dma_desc *rx_ring;
+ void *rx_buffers;
+
+ unsigned int tx_head, tx_tail;
+- struct dma_desc *tx_ring;
+- struct ring_info *tx_skb;
++ struct macb_dma_desc *tx_ring;
++ struct macb_tx_skb *tx_skb;
+
+ spinlock_t lock;
+ struct platform_device *pdev;
+@@ -529,8 +539,6 @@ struct macb {
+ dma_addr_t tx_ring_dma;
+ dma_addr_t rx_buffers_dma;
+
+- unsigned int rx_pending, tx_pending;
+-
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ unsigned int link;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 8faef3934fa0d515e72eea2197f1d00d636deb23 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Fri, 20 May 2011 14:31:29 +0200
-Subject: video: atmelfb: refactor dma_update
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 55 ++++++++++++++++++++++++++++++++++++
- drivers/video/atmel_lcdfb_core.c | 61 ++++------------------------------------
- include/video/atmel_lcdc.h | 2 ++
- 3 files changed, 62 insertions(+), 56 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 046e6c5..cd6d22e 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -31,6 +31,59 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
- | ATMEL_LCDC_POL_POSITIVE
- | ATMEL_LCDC_ENA_PWMENABLE;
-
-+#if defined(CONFIG_ARCH_AT91)
-+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-+ | FBINFO_PARTIAL_PAN_OK \
-+ | FBINFO_HWACCEL_YPAN)
-+
-+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-+ struct fb_var_screeninfo *var)
-+{
-+
-+}
-+#elif defined(CONFIG_AVR32)
-+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-+ | FBINFO_PARTIAL_PAN_OK \
-+ | FBINFO_HWACCEL_XPAN \
-+ | FBINFO_HWACCEL_YPAN)
-+
-+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-+ struct fb_var_screeninfo *var)
-+{
-+ u32 dma2dcfg;
-+ u32 pixeloff;
-+
-+ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
-+
-+ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
-+ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
-+
-+ /* Update configuration */
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
-+ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
-+ | ATMEL_LCDC_DMAUPDT);
-+}
-+#endif
-+
-+static void atmel_lcdfb_update_dma(struct fb_info *info,
-+ struct fb_var_screeninfo *var)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ struct fb_fix_screeninfo *fix = &info->fix;
-+ unsigned long dma_addr;
-+
-+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-+ + var->xoffset * var->bits_per_pixel / 8);
-+
-+ dma_addr &= ~3UL;
-+
-+ /* Set framebuffer DMA base address and pixel offset */
-+ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
-+
-+ atmel_lcdfb_update_dma2d(sinfo, var);
-+}
-+
- /* some bl->props field just changed */
- static int atmel_bl_update_status(struct backlight_device *bl)
- {
-@@ -323,8 +376,10 @@ static struct atmel_lcdfb_devdata dev_data = {
- .start = atmel_lcdfb_start,
- .stop = atmel_lcdfb_stop,
- .isr = atmel_lcdfb_interrupt,
-+ .update_dma = atmel_lcdfb_update_dma,
- .bl_ops = &atmel_lcdc_bl_ops,
- .init_contrast = atmel_lcdfb_init_contrast,
-+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index ef63996..4146e9b 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -27,41 +27,6 @@
- /* configurable parameters */
- #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
-
--#if defined(CONFIG_ARCH_AT91)
--#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-- | FBINFO_PARTIAL_PAN_OK \
-- | FBINFO_HWACCEL_YPAN)
--
--static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-- struct fb_var_screeninfo *var)
--{
--
--}
--#elif defined(CONFIG_AVR32)
--#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-- | FBINFO_PARTIAL_PAN_OK \
-- | FBINFO_HWACCEL_XPAN \
-- | FBINFO_HWACCEL_YPAN)
--
--static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
-- struct fb_var_screeninfo *var)
--{
-- u32 dma2dcfg;
-- u32 pixeloff;
--
-- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
--
-- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
-- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
-- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
--
-- /* Update configuration */
-- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
-- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
-- | ATMEL_LCDC_DMAUPDT);
--}
--#endif
--
- #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-
- static void init_backlight(struct atmel_lcdfb_info *sinfo)
-@@ -119,24 +84,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
- .accel = FB_ACCEL_NONE,
- };
-
--static void atmel_lcdfb_update_dma(struct fb_info *info,
-- struct fb_var_screeninfo *var)
--{
-- struct atmel_lcdfb_info *sinfo = info->par;
-- struct fb_fix_screeninfo *fix = &info->fix;
-- unsigned long dma_addr;
--
-- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-- + var->xoffset * var->bits_per_pixel / 8);
--
-- dma_addr &= ~3UL;
--
-- /* Set framebuffer DMA base address and pixel offset */
-- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
--
-- atmel_lcdfb_update_dma2d(sinfo, var);
--}
--
- static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
- {
- struct fb_info *info = sinfo->info;
-@@ -392,7 +339,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
-
- /* Re-initialize the DMA engine... */
- dev_dbg(info->device, " * update DMA engine\n");
-- atmel_lcdfb_update_dma(info, &info->var);
-+ sinfo->dev_data->update_dma(info, &info->var);
-
- /* Now, the LCDC core... */
- sinfo->dev_data->setup_core(info);
-@@ -496,9 +443,11 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
- static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
- {
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+
- dev_dbg(info->device, "%s\n", __func__);
-
-- atmel_lcdfb_update_dma(info, var);
-+ sinfo->dev_data->update_dma(info, var);
-
- return 0;
- }
-@@ -633,7 +582,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- sinfo->pdev = pdev;
-
- strcpy(info->fix.id, sinfo->pdev->name);
-- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
-+ info->flags = dev_data->fbinfo_flags;
- info->pseudo_palette = sinfo->pseudo_palette;
- info->fbops = &atmel_lcdfb_ops;
-
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index e7c0a3f..866ab47 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -49,8 +49,10 @@ struct atmel_lcdfb_devdata {
- void (*start)(struct atmel_lcdfb_info *sinfo);
- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
- irqreturn_t (*isr)(int irq, void *dev_id);
-+ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
- const struct backlight_ops *bl_ops;
-+ int fbinfo_flags;
- };
-
- /* LCD Controller info data structure, stored in device platform_data */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 69edea954864a5d0aeed3be5171ac62889442043 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 3 Sep 2012 17:56:18 +0200
+Subject: net/macb: ethtool interface: add register dump feature
+
+Add macb_get_regs() ethtool function and its helper function:
+macb_get_regs_len().
+The version field is deduced from the IP revision which gives the
+"MACB or GEM" information. An additional version field is reserved.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Reviewed-by: Ben Hutchings <bhutchings@solarflare.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 40 +++++++++++++++++++++++++++++++++++++
+ drivers/net/ethernet/cadence/macb.h | 3 +++
+ 2 files changed, 43 insertions(+)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 2554354..6486a56 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -1271,9 +1271,49 @@ static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ return phy_ethtool_sset(phydev, cmd);
+ }
+
++static int macb_get_regs_len(struct net_device *netdev)
++{
++ return MACB_GREGS_NBR * sizeof(u32);
++}
++
++static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
++ void *p)
++{
++ struct macb *bp = netdev_priv(dev);
++ unsigned int tail, head;
++ u32 *regs_buff = p;
++
++ regs->version = (macb_readl(bp, MID) & ((1 << MACB_REV_SIZE) - 1))
++ | MACB_GREGS_VERSION;
++
++ tail = macb_tx_ring_wrap(bp->tx_tail);
++ head = macb_tx_ring_wrap(bp->tx_head);
++
++ regs_buff[0] = macb_readl(bp, NCR);
++ regs_buff[1] = macb_or_gem_readl(bp, NCFGR);
++ regs_buff[2] = macb_readl(bp, NSR);
++ regs_buff[3] = macb_readl(bp, TSR);
++ regs_buff[4] = macb_readl(bp, RBQP);
++ regs_buff[5] = macb_readl(bp, TBQP);
++ regs_buff[6] = macb_readl(bp, RSR);
++ regs_buff[7] = macb_readl(bp, IMR);
++
++ regs_buff[8] = tail;
++ regs_buff[9] = head;
++ regs_buff[10] = macb_tx_dma(bp, tail);
++ regs_buff[11] = macb_tx_dma(bp, head);
++
++ if (macb_is_gem(bp)) {
++ regs_buff[12] = gem_readl(bp, USRIO);
++ regs_buff[13] = gem_readl(bp, DMACFG);
++ }
++}
++
+ static const struct ethtool_ops macb_ethtool_ops = {
+ .get_settings = macb_get_settings,
+ .set_settings = macb_set_settings,
++ .get_regs_len = macb_get_regs_len,
++ .get_regs = macb_get_regs,
+ .get_link = ethtool_op_get_link,
+ };
+
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 8a4ee2f..5be5900 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -10,6 +10,9 @@
+ #ifndef _MACB_H
+ #define _MACB_H
+
++#define MACB_GREGS_NBR 16
++#define MACB_GREGS_VERSION 1
++
+ /* MACB register offsets */
+ #define MACB_NCR 0x0000
+ #define MACB_NCFGR 0x0004
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 8c0682446f887908ea3d93ed7e7dee05fb5fd911 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Fri, 20 May 2011 14:51:45 +0200
-Subject: video: atmelfb: refactor LUT
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 1 +
- drivers/video/atmel_lcdfb_core.c | 6 ++++--
- include/video/atmel_lcdc.h | 8 ++------
- 3 files changed, 7 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index cd6d22e..f8993cd 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -380,6 +380,7 @@ static struct atmel_lcdfb_devdata dev_data = {
- .bl_ops = &atmel_lcdc_bl_ops,
- .init_contrast = atmel_lcdfb_init_contrast,
- .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-+ .lut_base = ATMEL_LCDC_LUT,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 4146e9b..0edafb6 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -422,7 +422,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
- * ~(red[10] ^ green[10] ^ blue[10]) & 1
- */
-
-- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-+ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
-+ val);
- ret = 0;
- }
- break;
-@@ -430,7 +431,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
- case FB_VISUAL_MONO01:
- if (regno < 2) {
- val = (regno == 0) ? 0x00 : 0x1F;
-- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
-+ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
-+ val);
- ret = 0;
- }
- break;
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 866ab47..6c470c4 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -53,6 +53,7 @@ struct atmel_lcdfb_devdata {
- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
- const struct backlight_ops *bl_ops;
- int fbinfo_flags;
-+ u32 lut_base;
- };
-
- /* LCD Controller info data structure, stored in device platform_data */
-@@ -241,11 +242,6 @@ struct atmel_lcdfb_info {
- #define ATMEL_LCDC_OWRI (1 << 5)
- #define ATMEL_LCDC_MERI (1 << 6)
-
--#if !defined(CONFIG_ARCH_AT91SAM9X5)
--#define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
--#else
--/* Base layer CLUT */
--#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
--#endif
-+#define ATMEL_LCDC_LUT 0x0c00
-
- #endif /* __ATMEL_LCDC_H__ */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2d0de9104b7a27b8423f7a44c4fa45dc3508f25a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 22 Jun 2010 18:38:26 +0200
+Subject: net/macb: better manage tx errors
+
+Handle all TX errors, not only underruns. TX error management is
+deferred to a dedicated workqueue.
+Reinitialize the TX ring after treating all remaining frames, and
+restart the controller when everything has been cleaned up properly.
+Napi is not stopped during this task as the driver only handles
+napi for RX for now.
+With this sequence, we do not need a special check during the xmit
+method as the packets will be caught by TX disable during workqueue
+execution.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 166 ++++++++++++++++++++++++------------
+ drivers/net/ethernet/cadence/macb.h | 1 +
+ 2 files changed, 113 insertions(+), 54 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 6486a56..cd24ce6 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -44,6 +44,16 @@
+
+ #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \
+ | MACB_BIT(ISR_ROVR))
++#define MACB_TX_ERR_FLAGS (MACB_BIT(ISR_TUND) \
++ | MACB_BIT(ISR_RLE) \
++ | MACB_BIT(TXERR))
++#define MACB_TX_INT_FLAGS (MACB_TX_ERR_FLAGS | MACB_BIT(TCOMP))
++
++/*
++ * Graceful stop timeouts in us. We should allow up to
++ * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions)
++ */
++#define MACB_HALT_TIMEOUT 1230
+
+ /* Ring buffer accessors */
+ static unsigned int macb_tx_ring_wrap(unsigned int index)
+@@ -338,66 +348,113 @@ static void macb_update_stats(struct macb *bp)
+ *p += __raw_readl(reg);
+ }
+
+-static void macb_tx(struct macb *bp)
++static int macb_halt_tx(struct macb *bp)
+ {
+- unsigned int tail;
+- unsigned int head;
+- u32 status;
++ unsigned long halt_time, timeout;
++ u32 status;
+
+- status = macb_readl(bp, TSR);
+- macb_writel(bp, TSR, status);
++ macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(THALT));
+
+- netdev_vdbg(bp->dev, "macb_tx status = 0x%03lx\n", (unsigned long)status);
++ timeout = jiffies + usecs_to_jiffies(MACB_HALT_TIMEOUT);
++ do {
++ halt_time = jiffies;
++ status = macb_readl(bp, TSR);
++ if (!(status & MACB_BIT(TGO)))
++ return 0;
+
+- if (status & (MACB_BIT(UND) | MACB_BIT(TSR_RLE))) {
+- int i;
+- netdev_err(bp->dev, "TX %s, resetting buffers\n",
+- status & MACB_BIT(UND) ?
+- "underrun" : "retry limit exceeded");
++ usleep_range(10, 250);
++ } while (time_before(halt_time, timeout));
+
+- /* Transfer ongoing, disable transmitter, to avoid confusion */
+- if (status & MACB_BIT(TGO))
+- macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE));
++ return -ETIMEDOUT;
++}
+
+- head = bp->tx_head;
++static void macb_tx_error_task(struct work_struct *work)
++{
++ struct macb *bp = container_of(work, struct macb, tx_error_task);
++ struct macb_tx_skb *tx_skb;
++ struct sk_buff *skb;
++ unsigned int tail;
+
+- /*Mark all the buffer as used to avoid sending a lost buffer*/
+- for (i = 0; i < TX_RING_SIZE; i++)
+- bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
++ netdev_vdbg(bp->dev, "macb_tx_error_task: t = %u, h = %u\n",
++ bp->tx_tail, bp->tx_head);
+
+- /* Add wrap bit */
+- bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
++ /* Make sure nobody is trying to queue up new packets */
++ netif_stop_queue(bp->dev);
+
+- /* free transmit buffer in upper layer*/
+- for (tail = bp->tx_tail; tail != head; tail++) {
+- struct macb_tx_skb *tx_skb;
+- struct sk_buff *skb;
++ /*
++ * Stop transmission now
++ * (in case we have just queued new packets)
++ */
++ if (macb_halt_tx(bp))
++ /* Just complain for now, reinitializing TX path can be good */
++ netdev_err(bp->dev, "BUG: halt tx timed out\n");
+
+- rmb();
++ /* No need for the lock here as nobody will interrupt us anymore */
+
+- tx_skb = macb_tx_skb(bp, tail);
+- skb = tx_skb->skb;
++ /*
++ * Treat frames in TX queue including the ones that caused the error.
++ * Free transmit buffers in upper layer.
++ */
++ for (tail = bp->tx_tail; tail != bp->tx_head; tail++) {
++ struct macb_dma_desc *desc;
++ u32 ctrl;
+
+- dma_unmap_single(&bp->pdev->dev, tx_skb->mapping,
+- skb->len, DMA_TO_DEVICE);
+- tx_skb->skb = NULL;
+- dev_kfree_skb_irq(skb);
+- }
++ desc = macb_tx_desc(bp, tail);
++ ctrl = desc->ctrl;
++ tx_skb = macb_tx_skb(bp, tail);
++ skb = tx_skb->skb;
+
+- bp->tx_head = bp->tx_tail = 0;
++ if (ctrl & MACB_BIT(TX_USED)) {
++ netdev_vdbg(bp->dev, "txerr skb %u (data %p) TX complete\n",
++ macb_tx_ring_wrap(tail), skb->data);
++ bp->stats.tx_packets++;
++ bp->stats.tx_bytes += skb->len;
++ } else {
++ /*
++ * "Buffers exhausted mid-frame" errors may only happen
++ * if the driver is buggy, so complain loudly about those.
++ * Statistics are updated by hardware.
++ */
++ if (ctrl & MACB_BIT(TX_BUF_EXHAUSTED))
++ netdev_err(bp->dev,
++ "BUG: TX buffers exhausted mid-frame\n");
+
+- /* Enable the transmitter again */
+- if (status & MACB_BIT(TGO))
+- macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE));
++ desc->ctrl = ctrl | MACB_BIT(TX_USED);
++ }
++
++ dma_unmap_single(&bp->pdev->dev, tx_skb->mapping, skb->len,
++ DMA_TO_DEVICE);
++ tx_skb->skb = NULL;
++ dev_kfree_skb(skb);
+ }
+
+- if (!(status & MACB_BIT(COMP)))
+- /*
+- * This may happen when a buffer becomes complete
+- * between reading the ISR and scanning the
+- * descriptors. Nothing to worry about.
+- */
+- return;
++ /* Make descriptor updates visible to hardware */
++ wmb();
++
++ /* Reinitialize the TX desc queue */
++ macb_writel(bp, TBQP, bp->tx_ring_dma);
++ /* Make TX ring reflect state of hardware */
++ bp->tx_head = bp->tx_tail = 0;
++
++ /* Now we are ready to start transmission again */
++ netif_wake_queue(bp->dev);
++
++ /* Housework before enabling TX IRQ */
++ macb_writel(bp, TSR, macb_readl(bp, TSR));
++ macb_writel(bp, IER, MACB_TX_INT_FLAGS);
++}
++
++static void macb_tx_interrupt(struct macb *bp)
++{
++ unsigned int tail;
++ unsigned int head;
++ u32 status;
++
++ status = macb_readl(bp, TSR);
++ macb_writel(bp, TSR, status);
++
++ netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
++ (unsigned long)status);
+
+ head = bp->tx_head;
+ for (tail = bp->tx_tail; tail != head; tail++) {
+@@ -637,9 +694,14 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+ }
+ }
+
+- if (status & (MACB_BIT(TCOMP) | MACB_BIT(ISR_TUND) |
+- MACB_BIT(ISR_RLE)))
+- macb_tx(bp);
++ if (unlikely(status & (MACB_TX_ERR_FLAGS))) {
++ macb_writel(bp, IDR, MACB_TX_INT_FLAGS);
++ schedule_work(&bp->tx_error_task);
++ break;
++ }
++
++ if (status & MACB_BIT(TCOMP))
++ macb_tx_interrupt(bp);
+
+ /*
+ * Link change detection isn't possible with RMII, so we'll
+@@ -969,13 +1031,8 @@ static void macb_init_hw(struct macb *bp)
+ macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
+
+ /* Enable interrupts */
+- macb_writel(bp, IER, (MACB_BIT(RCOMP)
+- | MACB_BIT(RXUBR)
+- | MACB_BIT(ISR_TUND)
+- | MACB_BIT(ISR_RLE)
+- | MACB_BIT(TXERR)
+- | MACB_BIT(TCOMP)
+- | MACB_BIT(ISR_ROVR)
++ macb_writel(bp, IER, (MACB_RX_INT_FLAGS
++ | MACB_TX_INT_FLAGS
+ | MACB_BIT(HRESP)));
+
+ }
+@@ -1423,6 +1480,7 @@ static int __init macb_probe(struct platform_device *pdev)
+ bp->dev = dev;
+
+ spin_lock_init(&bp->lock);
++ INIT_WORK(&bp->tx_error_task, macb_tx_error_task);
+
+ bp->pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(bp->pclk)) {
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 5be5900..bfab8ef 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -532,6 +532,7 @@ struct macb {
+ struct clk *hclk;
+ struct net_device *dev;
+ struct napi_struct napi;
++ struct work_struct tx_error_task;
+ struct net_device_stats stats;
+ union {
+ struct macb_stats macb;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 00420e8e99b5d5ce4a1a461c01b2eb6750b734d7 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Fri, 20 May 2011 15:04:10 +0200
-Subject: video: atmelfb: refactor limit_screeninfo
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++
- drivers/video/atmel_lcdfb_core.c | 14 ++------------
- include/video/atmel_lcdc.h | 1 +
- 3 files changed, 21 insertions(+), 12 deletions(-)
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index f8993cd..7a48e9c 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -306,6 +306,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
- return 0;
- }
-
-+static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
-+{
-+ /* Saturate vertical and horizontal timings at maximum values */
-+ var->vsync_len = min_t(u32, var->vsync_len,
-+ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-+ var->upper_margin = min_t(u32, var->upper_margin,
-+ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-+ var->lower_margin = min_t(u32, var->lower_margin,
-+ ATMEL_LCDC_VFP);
-+ var->right_margin = min_t(u32, var->right_margin,
-+ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-+ var->hsync_len = min_t(u32, var->hsync_len,
-+ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-+ var->left_margin = min_t(u32, var->left_margin,
-+ ATMEL_LCDC_HBP + 1);
-+}
-+
- static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
- {
- struct fb_info *info = dev_id;
-@@ -379,6 +396,7 @@ static struct atmel_lcdfb_devdata dev_data = {
- .update_dma = atmel_lcdfb_update_dma,
- .bl_ops = &atmel_lcdc_bl_ops,
- .init_contrast = atmel_lcdfb_init_contrast,
-+ .limit_screeninfo = atmelfb_limit_screeninfo,
- .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
- .lut_base = ATMEL_LCDC_LUT,
- };
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 0edafb6..20a4e4f 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -211,18 +211,8 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
- }
-
- /* Saturate vertical and horizontal timings at maximum values */
-- var->vsync_len = min_t(u32, var->vsync_len,
-- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
-- var->upper_margin = min_t(u32, var->upper_margin,
-- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
-- var->lower_margin = min_t(u32, var->lower_margin,
-- ATMEL_LCDC_VFP);
-- var->right_margin = min_t(u32, var->right_margin,
-- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
-- var->hsync_len = min_t(u32, var->hsync_len,
-- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
-- var->left_margin = min_t(u32, var->left_margin,
-- ATMEL_LCDC_HBP + 1);
-+ if (sinfo->dev_data->limit_screeninfo)
-+ sinfo->dev_data->limit_screeninfo(var);
-
- /* Some parameters can't be zero */
- var->vsync_len = max_t(u32, var->vsync_len, 1);
-diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
-index 6c470c4..6031b5a 100644
---- a/include/video/atmel_lcdc.h
-+++ b/include/video/atmel_lcdc.h
-@@ -51,6 +51,7 @@ struct atmel_lcdfb_devdata {
- irqreturn_t (*isr)(int irq, void *dev_id);
- void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
-+ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
- const struct backlight_ops *bl_ops;
- int fbinfo_flags;
- u32 lut_base;
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From daafaa8acad56047c2805a29610eea22ee50b705 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 15:45:30 +0200
-Subject: arm: at91: refactor lcdc-includes
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Among others the HEO-ISR bit is fixed.
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
-
-Conflicts:
- arch/arm/mach-at91/board-neocore926.c
- arch/arm/mach-at91/board-sam9261ek.c
- arch/arm/mach-at91/board-sam9263ek.c
- arch/arm/mach-at91/board-sam9m10g45ek.c
- arch/arm/mach-at91/board-sam9rlek.c
----
- arch/arm/mach-at91/at91sam9261_devices.c | 4 +-
- arch/arm/mach-at91/at91sam9263_devices.c | 4 +-
- arch/arm/mach-at91/at91sam9g45_devices.c | 4 +-
- arch/arm/mach-at91/at91sam9rl_devices.c | 4 +-
- arch/arm/mach-at91/board-neocore926.c | 4 +-
- arch/arm/mach-at91/board-sam9261ek.c | 4 +-
- arch/arm/mach-at91/board-sam9263ek.c | 4 +-
- arch/arm/mach-at91/board-sam9m10g45ek.c | 4 +-
- arch/arm/mach-at91/board-sam9rlek.c | 4 +-
- .../include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} | 157 +--------------------
- arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h | 156 ++++++++++++++++++++
- .../arm/mach-at91/include/mach}/atmel_lcdc.h | 77 +---------
- drivers/video/atmel_lcdfb.c | 3 +-
- drivers/video/atmel_lcdfb_core.c | 2 +-
- include/video/atmel_lcdfb.h | 100 +++++++++++++
- 15 files changed, 294 insertions(+), 237 deletions(-)
- rename arch/arm/mach-at91/include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} (82%)
- create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
- rename {include/video => arch/arm/mach-at91/include/mach}/atmel_lcdc.h (73%)
- create mode 100644 include/video/atmel_lcdfb.h
-
-diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
-index 8df5c1b..1eecff8 100644
---- a/arch/arm/mach-at91/at91sam9261_devices.c
-+++ b/arch/arm/mach-at91/at91sam9261_devices.c
-@@ -19,9 +19,11 @@
- #include <linux/i2c-gpio.h>
-
- #include <linux/fb.h>
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <mach/board.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9261.h>
- #include <mach/at91sam9261_matrix.h>
- #include <mach/at91_matrix.h>
-diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
-index eb6bbf8..f0318e9 100644
---- a/arch/arm/mach-at91/at91sam9263_devices.c
-+++ b/arch/arm/mach-at91/at91sam9263_devices.c
-@@ -18,9 +18,11 @@
- #include <linux/i2c-gpio.h>
-
- #include <linux/fb.h>
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <mach/board.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9263.h>
- #include <mach/at91sam9263_matrix.h>
- #include <mach/at91_matrix.h>
-diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
-index 7ab7e06..73eb743 100644
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -20,9 +20,11 @@
- #include <linux/atmel-mci.h>
-
- #include <linux/fb.h>
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <mach/board.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9g45.h>
- #include <mach/at91sam9g45_matrix.h>
- #include <mach/at91_matrix.h>
-diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
-index f09fff9..0d1b76f 100644
---- a/arch/arm/mach-at91/at91sam9rl_devices.c
-+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
-@@ -15,9 +15,11 @@
- #include <linux/i2c-gpio.h>
-
- #include <linux/fb.h>
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <mach/board.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9rl.h>
- #include <mach/at91sam9rl_matrix.h>
- #include <mach/at91_matrix.h>
-diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
-index 18103c5d..5d3b4d6 100644
---- a/arch/arm/mach-at91/board-neocore926.c
-+++ b/arch/arm/mach-at91/board-neocore926.c
-@@ -32,7 +32,7 @@
- #include <linux/gpio_keys.h>
- #include <linux/input.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <asm/setup.h>
- #include <asm/mach-types.h>
-@@ -46,6 +46,8 @@
- #include <mach/hardware.h>
- #include <mach/board.h>
- #include <mach/at91_aic.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9_smc.h>
-
- #include "sam9_smc.h"
-diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
-index 2269be5..2e1c9c5 100644
---- a/arch/arm/mach-at91/board-sam9261ek.c
-+++ b/arch/arm/mach-at91/board-sam9261ek.c
-@@ -34,7 +34,7 @@
- #include <linux/gpio_keys.h>
- #include <linux/input.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <asm/setup.h>
- #include <asm/mach-types.h>
-@@ -47,6 +47,8 @@
- #include <mach/hardware.h>
- #include <mach/board.h>
- #include <mach/at91_aic.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
-index 82adf58..7c34908 100644
---- a/arch/arm/mach-at91/board-sam9263ek.c
-+++ b/arch/arm/mach-at91/board-sam9263ek.c
-@@ -33,7 +33,7 @@
- #include <linux/input.h>
- #include <linux/leds.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <asm/setup.h>
- #include <asm/mach-types.h>
-@@ -46,6 +46,8 @@
- #include <mach/hardware.h>
- #include <mach/board.h>
- #include <mach/at91_aic.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
-index d1882d5..78210f6 100644
---- a/arch/arm/mach-at91/board-sam9m10g45ek.c
-+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
-@@ -28,7 +28,7 @@
- #include <linux/delay.h>
-
- #include <mach/hardware.h>
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
- #include <media/soc_camera.h>
- #include <media/atmel-isi.h>
-
-@@ -42,6 +42,8 @@
-
- #include <mach/board.h>
- #include <mach/at91_aic.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
- #include <mach/system_rev.h>
-diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
-index e7dc3ea..81d82be 100644
---- a/arch/arm/mach-at91/board-sam9rlek.c
-+++ b/arch/arm/mach-at91/board-sam9rlek.c
-@@ -19,7 +19,7 @@
- #include <linux/input.h>
- #include <linux/gpio_keys.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- #include <asm/setup.h>
- #include <asm/mach-types.h>
-@@ -32,6 +32,8 @@
- #include <mach/hardware.h>
- #include <mach/board.h>
- #include <mach/at91_aic.h>
-+#include <mach/gpio.h>
-+#include <mach/atmel_lcdc.h>
- #include <mach/at91sam9_smc.h>
- #include <mach/at91_shdwc.h>
-
-diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-similarity index 82%
-rename from arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
-rename to arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-index a57b79b..9ed7e6e 100644
---- a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
-+++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-@@ -19,8 +19,8 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
--#ifndef __ATMEL_HLCD_H__
--#define __ATMEL_HLCD_H__
-+#ifndef __MACH_ATMEL_HLCD_H__
-+#define __MACH_ATMEL_HLCD_H__
-
- /* Lcdc hardware registers */
- #define ATMEL_LCDC_LCDCFG0 0x0000
-@@ -145,7 +145,7 @@
- #define LCDC_LCDISR_FIFOERR (0x1 << 4)
- #define LCDC_LCDISR_BASE (0x1 << 8)
- #define LCDC_LCDISR_OVR1 (0x1 << 9)
--#define LCDC_LCDISR_HEO (0x1 << 11)
-+#define LCDC_LCDISR_HEO (0x1 << 10)
- #define LCDC_LCDISR_HCR (0x1 << 12)
-
- #define ATMEL_LCDC_BASECHER 0x0040
-@@ -252,153 +252,6 @@
- #define LCDC_BASECFG4_DMA (0x1 << 8)
- #define LCDC_BASECFG4_REP (0x1 << 9)
-
--#define ATMEL_LCDC_OVRCHER1 0x0100
--#define LCDC_OVRCHER1_CHEN (0x1 << 0)
--#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
--#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
--
--#define ATMEL_LCDC_OVRCHDR1 0x0104
--#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
--#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
--
--#define ATMEL_LCDC_OVRCHSR1 0x0108
--#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
--#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
--#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
--
--#define ATMEL_LCDC_OVRIER1 0x010C
--#define LCDC_OVRIER1_DMA (0x1 << 2)
--#define LCDC_OVRIER1_DSCR (0x1 << 3)
--#define LCDC_OVRIER1_ADD (0x1 << 4)
--#define LCDC_OVRIER1_DONE (0x1 << 5)
--#define LCDC_OVRIER1_OVR (0x1 << 6)
--
--#define ATMEL_LCDC_OVRIDR1 0x0110
--#define LCDC_OVRIDR1_DMA (0x1 << 2)
--#define LCDC_OVRIDR1_DSCR (0x1 << 3)
--#define LCDC_OVRIDR1_ADD (0x1 << 4)
--#define LCDC_OVRIDR1_DONE (0x1 << 5)
--#define LCDC_OVRIDR1_OVR (0x1 << 6)
--
--#define ATMEL_LCDC_OVRIMR1 0x0114
--#define LCDC_OVRIMR1_DMA (0x1 << 2)
--#define LCDC_OVRIMR1_DSCR (0x1 << 3)
--#define LCDC_OVRIMR1_ADD (0x1 << 4)
--#define LCDC_OVRIMR1_DONE (0x1 << 5)
--#define LCDC_OVRIMR1_OVR (0x1 << 6)
--
--#define ATMEL_LCDC_OVRISR1 0x0118
--#define LCDC_OVRISR1_DMA (0x1 << 2)
--#define LCDC_OVRISR1_DSCR (0x1 << 3)
--#define LCDC_OVRISR1_ADD (0x1 << 4)
--#define LCDC_OVRISR1_DONE (0x1 << 5)
--#define LCDC_OVRISR1_OVR (0x1 << 6)
--
--#define ATMEL_LCDC_OVRHEAD1 0x011C
--
--#define ATMEL_LCDC_OVRADDR1 0x0120
--
--#define ATMEL_LCDC_OVRCTRL1 0x0124
--#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
--#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
--#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
--#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
--#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
--#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
--
--#define ATMEL_LCDC_OVRNEXT1 0x0128
--
--#define ATMEL_LCDC_OVR1CFG0 0x012C
--#define LCDC_OVR1CFG0_BLEN_OFFSET 4
--#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
--#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
--#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
--#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
--#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
--#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
--#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
--#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
--
--#define ATMEL_LCDC_OVR1CFG1 0x0130
--#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
--#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
--#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
--#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
--#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
--#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
--#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
--#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
--#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
--#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
--#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
--#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
--#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
--#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
--
--#define ATMEL_LCDC_OVR1CFG2 0x0134
--#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
--#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
--#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
--#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
--
--#define ATMEL_LCDC_OVR1CFG3 0x0138
--#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
--#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
--#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
--#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
--
--#define ATMEL_LCDC_OVR1CFG4 0x013C
--
--#define ATMEL_LCDC_OVR1CFG5 0x0140
--
--#define ATMEL_LCDC_OVR1CFG6 0x0144
--#define LCDC_OVR1CFG6_BDEF_OFFSET 0
--#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
--#define LCDC_OVR1CFG6_GDEF_OFFSET 8
--#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
--#define LCDC_OVR1CFG6_RDEF_OFFSET 16
--#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
--
--#define ATMEL_LCDC_OVR1CFG7 0x0148
--#define LCDC_OVR1CFG7_BKEY_OFFSET 0
--#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
--#define LCDC_OVR1CFG7_GKEY_OFFSET 8
--#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
--#define LCDC_OVR1CFG7_RKEY_OFFSET 16
--#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
--
--#define ATMEL_LCDC_OVR1CFG8 0x014C
--#define LCDC_OVR1CFG8_BMASK_OFFSET 0
--#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
--#define LCDC_OVR1CFG8_GMASK_OFFSET 8
--#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
--#define LCDC_OVR1CFG8_RMASK_OFFSET 16
--#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
--
--#define ATMEL_LCDC_OVR1CFG9 0x0150
--#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
--#define LCDC_OVR1CFG9_INV (0x1 << 1)
--#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
--#define LCDC_OVR1CFG9_ITER (0x1 << 3)
--#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
--#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
--#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
--#define LCDC_OVR1CFG9_OVR (0x1 << 7)
--#define LCDC_OVR1CFG9_DMA (0x1 << 8)
--#define LCDC_OVR1CFG9_REP (0x1 << 9)
--#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
--#define LCDC_OVR1CFG9_GA_OFFSET 16
--#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
--
- #define ATMEL_LCDC_HEOCHER 0x0280
- #define LCDC_HEOCHER_CHEN (0x1 << 0)
- #define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
-@@ -859,7 +712,7 @@
- #define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
-
- /* Base layer CLUT */
--#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
-+#define ATMEL_HLCDC_LUT 0x0400
-
-
--#endif /* __ATMEL_HLCDC4_H__ */
-+#endif /* __MACH_ATMEL_HLCDC4_H__ */
-diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
-new file mode 100644
-index 0000000..4416403
---- /dev/null
-+++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
-@@ -0,0 +1,156 @@
-+#ifndef __MACH_ATMEL_HLCD_OVL_H__
-+#define __MACH_ATMEL_HLCD_OVL_H__
-+
-+/*
-+ * OVL has a seperate resource which already starts at offset 0x100.
-+ * So, these defines start at 0x0. The manual will list them at 0x100.
-+ */
-+
-+#define ATMEL_LCDC_OVRCHER1 0x0000
-+#define LCDC_OVRCHER1_CHEN (0x1 << 0)
-+#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
-+#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
-+
-+#define ATMEL_LCDC_OVRCHDR1 0x0004
-+#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
-+#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
-+
-+#define ATMEL_LCDC_OVRCHSR1 0x0008
-+#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
-+#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
-+#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
-+
-+#define ATMEL_LCDC_OVRIER1 0x000C
-+#define LCDC_OVRIER1_DMA (0x1 << 2)
-+#define LCDC_OVRIER1_DSCR (0x1 << 3)
-+#define LCDC_OVRIER1_ADD (0x1 << 4)
-+#define LCDC_OVRIER1_DONE (0x1 << 5)
-+#define LCDC_OVRIER1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRIDR1 0x0010
-+#define LCDC_OVRIDR1_DMA (0x1 << 2)
-+#define LCDC_OVRIDR1_DSCR (0x1 << 3)
-+#define LCDC_OVRIDR1_ADD (0x1 << 4)
-+#define LCDC_OVRIDR1_DONE (0x1 << 5)
-+#define LCDC_OVRIDR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRIMR1 0x0014
-+#define LCDC_OVRIMR1_DMA (0x1 << 2)
-+#define LCDC_OVRIMR1_DSCR (0x1 << 3)
-+#define LCDC_OVRIMR1_ADD (0x1 << 4)
-+#define LCDC_OVRIMR1_DONE (0x1 << 5)
-+#define LCDC_OVRIMR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRISR1 0x0018
-+#define LCDC_OVRISR1_DMA (0x1 << 2)
-+#define LCDC_OVRISR1_DSCR (0x1 << 3)
-+#define LCDC_OVRISR1_ADD (0x1 << 4)
-+#define LCDC_OVRISR1_DONE (0x1 << 5)
-+#define LCDC_OVRISR1_OVR (0x1 << 6)
-+
-+#define ATMEL_LCDC_OVRHEAD1 0x001C
-+
-+#define ATMEL_LCDC_OVRADDR1 0x0020
-+
-+#define ATMEL_LCDC_OVRCTRL1 0x0024
-+#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
-+#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
-+#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
-+#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
-+#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
-+#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
-+
-+#define ATMEL_LCDC_OVRNEXT1 0x0028
-+
-+#define ATMEL_LCDC_OVR1CFG0 0x002C
-+#define LCDC_OVR1CFG0_BLEN_OFFSET 4
-+#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
-+#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
-+#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
-+#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
-+#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
-+#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
-+
-+#define ATMEL_LCDC_OVR1CFG1 0x0030
-+#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
-+#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
-+#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
-+#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
-+#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
-+#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
-+#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
-+#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
-+#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
-+
-+#define ATMEL_LCDC_OVR1CFG2 0x0034
-+#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
-+#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
-+#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
-+#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG3 0x0038
-+#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
-+#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
-+#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
-+#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG4 0x003C
-+
-+#define ATMEL_LCDC_OVR1CFG5 0x0040
-+
-+#define ATMEL_LCDC_OVR1CFG6 0x0044
-+#define LCDC_OVR1CFG6_BDEF_OFFSET 0
-+#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
-+#define LCDC_OVR1CFG6_GDEF_OFFSET 8
-+#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
-+#define LCDC_OVR1CFG6_RDEF_OFFSET 16
-+#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG7 0x0048
-+#define LCDC_OVR1CFG7_BKEY_OFFSET 0
-+#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
-+#define LCDC_OVR1CFG7_GKEY_OFFSET 8
-+#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
-+#define LCDC_OVR1CFG7_RKEY_OFFSET 16
-+#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG8 0x004C
-+#define LCDC_OVR1CFG8_BMASK_OFFSET 0
-+#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
-+#define LCDC_OVR1CFG8_GMASK_OFFSET 8
-+#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
-+#define LCDC_OVR1CFG8_RMASK_OFFSET 16
-+#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
-+
-+#define ATMEL_LCDC_OVR1CFG9 0x0050
-+#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
-+#define LCDC_OVR1CFG9_INV (0x1 << 1)
-+#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
-+#define LCDC_OVR1CFG9_ITER (0x1 << 3)
-+#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
-+#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
-+#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
-+#define LCDC_OVR1CFG9_OVR (0x1 << 7)
-+#define LCDC_OVR1CFG9_DMA (0x1 << 8)
-+#define LCDC_OVR1CFG9_REP (0x1 << 9)
-+#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
-+#define LCDC_OVR1CFG9_GA_OFFSET 16
-+#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
-+
-+#endif /* __MACH_ATMEL_HLCD_OVL_H__ */
-diff --git a/include/video/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
-similarity index 73%
-rename from include/video/atmel_lcdc.h
-rename to arch/arm/mach-at91/include/mach/atmel_lcdc.h
-index 6031b5a..248fed3 100644
---- a/include/video/atmel_lcdc.h
-+++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
-@@ -19,79 +19,8 @@
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
--#ifndef __ATMEL_LCDC_H__
--#define __ATMEL_LCDC_H__
--
--#include <linux/workqueue.h>
--#include <linux/interrupt.h>
--#include <linux/backlight.h>
--
--/* Way LCD wires are connected to the chip:
-- * Some Atmel chips use BGR color mode (instead of standard RGB)
-- * A swapped wiring onboard can bring to RGB mode.
-- */
--#define ATMEL_LCDC_WIRING_BGR 0
--#define ATMEL_LCDC_WIRING_RGB 1
--#define ATMEL_LCDC_WIRING_RGB555 2
--
--#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
--
--extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
--extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
--extern int __atmel_lcdfb_probe(struct platform_device *pdev,
-- struct atmel_lcdfb_devdata *devdata);
--extern int __atmel_lcdfb_remove(struct platform_device *pdev);
--
--struct atmel_lcdfb_info;
--
--struct atmel_lcdfb_devdata {
-- int (*setup_core)(struct fb_info *info);
-- void (*start)(struct atmel_lcdfb_info *sinfo);
-- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
-- irqreturn_t (*isr)(int irq, void *dev_id);
-- void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
-- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
-- void (*limit_screeninfo)(struct fb_var_screeninfo *var);
-- const struct backlight_ops *bl_ops;
-- int fbinfo_flags;
-- u32 lut_base;
--};
--
-- /* LCD Controller info data structure, stored in device platform_data */
--struct atmel_lcdfb_info {
-- spinlock_t lock;
-- struct fb_info *info;
-- void __iomem *mmio;
-- int irq_base;
-- struct atmel_lcdfb_devdata *dev_data;
-- struct work_struct task;
--
-- unsigned int guard_time;
-- unsigned int smem_len;
-- struct platform_device *pdev;
-- struct clk *bus_clk;
-- struct clk *lcdc_clk;
--
--#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-- struct backlight_device *backlight;
-- u8 bl_power;
--#endif
-- bool lcdcon_is_backlight;
-- bool lcdcon_pol_negative;
-- bool alpha_enabled;
-- u8 saved_lcdcon;
--
-- u8 default_bpp;
-- u8 lcd_wiring_mode;
-- unsigned int default_lcdcon2;
-- unsigned int default_dmacon;
-- void (*atmel_lcdfb_power_control)(int on);
-- struct fb_monspecs *default_monspecs;
-- u32 pseudo_palette[16];
--};
--
--#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
--#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
-+#ifndef __MACH_ATMEL_LCDC_H__
-+#define __MACH_ATMEL_LCDC_H__
-
- #define ATMEL_LCDC_DMABADDR1 0x00
- #define ATMEL_LCDC_DMABADDR2 0x04
-@@ -245,4 +174,4 @@ struct atmel_lcdfb_info {
-
- #define ATMEL_LCDC_LUT 0x0c00
-
--#endif /* __ATMEL_LCDC_H__ */
-+#endif /* __MACH_ATMEL_LCDC_H__ */
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 7a48e9c..8d7992c 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -19,8 +19,9 @@
-
- #include <mach/board.h>
- #include <mach/cpu.h>
-+#include <mach/atmel_lcdc.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- /* configurable parameters */
- #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 20a4e4f..060d41f 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -22,7 +22,7 @@
- #include <mach/cpu.h>
- #include <mach/gpio.h>
-
--#include <video/atmel_lcdc.h>
-+#include <video/atmel_lcdfb.h>
-
- /* configurable parameters */
- #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
-diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
-new file mode 100644
-index 0000000..3a0dfc7
---- /dev/null
-+++ b/include/video/atmel_lcdfb.h
-@@ -0,0 +1,100 @@
-+/*
-+ * Header file for AT91/AT32 LCD Controller
-+ *
-+ * Data structure and register user interface
-+ *
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * 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.
-+ *
-+ * This program 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 General Public License for more details.
-+ *
-+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ */
-+#ifndef __ATMEL_LCDC_H__
-+#define __ATMEL_LCDC_H__
-+
-+#include <linux/workqueue.h>
-+#include <linux/interrupt.h>
-+#include <linux/backlight.h>
-+
-+/* Way LCD wires are connected to the chip:
-+ * Some Atmel chips use BGR color mode (instead of standard RGB)
-+ * A swapped wiring onboard can bring to RGB mode.
-+ */
-+#define ATMEL_LCDC_WIRING_BGR 0
-+#define ATMEL_LCDC_WIRING_RGB 1
-+#define ATMEL_LCDC_WIRING_RGB555 2
-+
-+#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
-+
-+struct atmel_lcdfb_info;
-+
-+struct atmel_lcdfb_devdata {
-+ int (*setup_core)(struct fb_info *info);
-+ void (*start)(struct atmel_lcdfb_info *sinfo);
-+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
-+ irqreturn_t (*isr)(int irq, void *dev_id);
-+ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
-+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
-+ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
-+ const struct backlight_ops *bl_ops;
-+ int fbinfo_flags;
-+ u32 lut_base;
-+ int dma_desc_size;
-+};
-+
-+extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
-+extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
-+extern int __atmel_lcdfb_probe(struct platform_device *pdev,
-+ struct atmel_lcdfb_devdata *devdata);
-+extern int __atmel_lcdfb_remove(struct platform_device *pdev);
-+
-+ /* LCD Controller info data structure, stored in device platform_data */
-+struct atmel_lcdfb_info {
-+ spinlock_t lock;
-+ struct fb_info *info;
-+ void __iomem *mmio;
-+ int irq_base;
-+ struct atmel_lcdfb_devdata *dev_data;
-+ struct work_struct task;
-+
-+ void *dma_desc;
-+ dma_addr_t dma_desc_phys;
-+
-+ unsigned int guard_time;
-+ unsigned int smem_len;
-+ struct platform_device *pdev;
-+ struct clk *bus_clk;
-+ struct clk *lcdc_clk;
-+
-+#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
-+ struct backlight_device *backlight;
-+ u8 bl_power;
-+#endif
-+ bool lcdcon_is_backlight;
-+ bool lcdcon_pol_negative;
-+ bool alpha_enabled;
-+ u8 saved_lcdcon;
-+
-+ u8 default_bpp;
-+ u8 lcd_wiring_mode;
-+ unsigned int default_lcdcon2;
-+ unsigned int default_dmacon;
-+ void (*atmel_lcdfb_power_control)(int on);
-+ struct fb_monspecs *default_monspecs;
-+ u32 pseudo_palette[16];
-+};
-+
-+#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
-+#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
-+
-+#endif /* __ATMEL_LCDC_H__ */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 392c13a787ed77602e6dd398e5389aa82d157a0e Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Tue, 24 Mar 2009 10:45:18 +0100
+Subject: net/macb: Offset first RX buffer by two bytes
+
+Make the ethernet frame payload word-aligned, possibly making the
+memcpy into the skb a bit faster. This will be even more important
+after we eliminate the copy altogether.
+
+Also eliminate the redundant RX_OFFSET constant -- it has the same
+definition and purpose as NET_IP_ALIGN.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 23 ++++++++++++++++-------
+ 1 file changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index cd24ce6..88a1d20 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -33,9 +33,6 @@
+ #define RX_RING_SIZE 512
+ #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
+
+-/* Make the IP header word-aligned (the ethernet header is 14 bytes) */
+-#define RX_OFFSET 2
+-
+ #define TX_RING_SIZE 128
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+
+@@ -497,7 +494,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ {
+ unsigned int len;
+ unsigned int frag;
+- unsigned int offset = 0;
++ unsigned int offset;
+ struct sk_buff *skb;
+ struct macb_dma_desc *desc;
+
+@@ -508,7 +505,16 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ macb_rx_ring_wrap(first_frag),
+ macb_rx_ring_wrap(last_frag), len);
+
+- skb = netdev_alloc_skb(bp->dev, len + RX_OFFSET);
++ /*
++ * The ethernet header starts NET_IP_ALIGN bytes into the
++ * first buffer. Since the header is 14 bytes, this makes the
++ * payload word-aligned.
++ *
++ * Instead of calling skb_reserve(NET_IP_ALIGN), we just copy
++ * the two padding bytes into the skb so that we avoid hitting
++ * the slowpath in memcpy(), and pull them off afterwards.
++ */
++ skb = netdev_alloc_skb(bp->dev, len + NET_IP_ALIGN);
+ if (!skb) {
+ bp->stats.rx_dropped++;
+ for (frag = first_frag; ; frag++) {
+@@ -524,7 +530,8 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ return 1;
+ }
+
+- skb_reserve(skb, RX_OFFSET);
++ offset = 0;
++ len += NET_IP_ALIGN;
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+
+@@ -548,10 +555,11 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
++ __skb_pull(skb, NET_IP_ALIGN);
+ skb->protocol = eth_type_trans(skb, bp->dev);
+
+ bp->stats.rx_packets++;
+- bp->stats.rx_bytes += len;
++ bp->stats.rx_bytes += skb->len;
+ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
+ skb->len, skb->csum);
+ netif_receive_skb(skb);
+@@ -1011,6 +1019,7 @@ static void macb_init_hw(struct macb *bp)
+ __macb_set_hwaddr(bp);
+
+ config = macb_mdc_clk_div(bp);
++ config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */
+ config |= MACB_BIT(PAE); /* PAuse Enable */
+ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */
+ config |= MACB_BIT(BIG); /* Receive oversized frames */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 97a5734b38bdb9226e9806e766a3a2c2b80d1dd4 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 19 Sep 2012 15:14:34 +0200
+Subject: net/macb: GEM DMA configuration register update
+
+Add information to the DMA Configuration Register to
+maximize system performance:
+- rx/tx packet buffer full memory size
+- allow possibility to use INCR16 if supported
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 10 ++++++++--
+ drivers/net/ethernet/cadence/macb.h | 11 +++++++++++
+ 2 files changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 88a1d20..56bab3c 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -997,8 +997,12 @@ static u32 macb_dbw(struct macb *bp)
+ }
+
+ /*
+- * Configure the receive DMA engine to use the correct receive buffer size.
+- * This is a configurable parameter for GEM.
++ * Configure the receive DMA engine
++ * - use the correct receive buffer size
++ * - set the possibility to use INCR16 bursts
++ * (if not supported by FIFO, it will fallback to default)
++ * - set both rx/tx packet buffers to full memory size
++ * These are configurable parameters for GEM.
+ */
+ static void macb_configure_dma(struct macb *bp)
+ {
+@@ -1007,6 +1011,8 @@ static void macb_configure_dma(struct macb *bp)
+ if (macb_is_gem(bp)) {
+ dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
+ dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64);
++ dmacfg |= GEM_BF(FBLDO, 16);
++ dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+ gem_writel(bp, DMACFG, dmacfg);
+ }
+ }
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index bfab8ef..256559d 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -161,8 +161,19 @@
+ #define GEM_DBW128 2
+
+ /* Bitfields in DMACFG. */
++#define GEM_FBLDO_OFFSET 0
++#define GEM_FBLDO_SIZE 5
++#define GEM_RXBMS_OFFSET 8
++#define GEM_RXBMS_SIZE 2
++#define GEM_TXPBMS_OFFSET 10
++#define GEM_TXPBMS_SIZE 1
++#define GEM_TXCOEN_OFFSET 11
++#define GEM_TXCOEN_SIZE 1
+ #define GEM_RXBS_OFFSET 16
+ #define GEM_RXBS_SIZE 8
++#define GEM_DDRP_OFFSET 24
++#define GEM_DDRP_SIZE 1
++
+
+ /* Bitfields in NSR */
+ #define MACB_NSR_LINK_OFFSET 0
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ea87fdee7c94f994ebcb9b731a68c11ee065780b Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Mon, 23 May 2011 15:36:52 +0200
-Subject: video: atmel_hlcdfb: add new driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/Kconfig | 9 +
- drivers/video/Makefile | 1 +
- drivers/video/atmel_hlcdfb.c | 514 +++++++++++++++++++++++++++++++++++++++
- drivers/video/atmel_lcdfb_core.c | 15 ++
- 4 files changed, 539 insertions(+)
- create mode 100644 drivers/video/atmel_hlcdfb.c
-
-diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
-index a290be5..ceccaa3 100644
---- a/drivers/video/Kconfig
-+++ b/drivers/video/Kconfig
-@@ -1028,6 +1028,15 @@ config FB_ATMEL_STN
-
- If unsure, say N.
-
-+config FB_ATMEL_HLCD
-+ tristate "AT91 HLCD Controller support"
-+ depends on FB && HAVE_FB_ATMEL
-+ select FB_CFB_FILLRECT
-+ select FB_CFB_COPYAREA
-+ select FB_CFB_IMAGEBLIT
-+ help
-+ This enables support for the AT91 HLCD Controller.
-+
- config FB_NVIDIA
- tristate "nVidia Framebuffer Support"
- depends on FB && PCI
-diff --git a/drivers/video/Makefile b/drivers/video/Makefile
-index 37c5625..36320ea 100644
---- a/drivers/video/Makefile
-+++ b/drivers/video/Makefile
-@@ -96,6 +96,7 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
- obj-$(CONFIG_FB_HIT) += hitfb.o
- obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
- obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
-+obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
- obj-$(CONFIG_FB_PVR2) += pvr2fb.o
- obj-$(CONFIG_FB_VOODOO1) += sstfb.o
- obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-new file mode 100644
-index 0000000..b772841
---- /dev/null
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -0,0 +1,514 @@
-+/*
-+ * Driver for AT91/AT32 LCD Controller
-+ *
-+ * Copyright (C) 2007 Atmel Corporation
-+ *
-+ * This file is subject to the terms and conditions of the GNU General Public
-+ * License. See the file COPYING in the main directory of this archive for
-+ * more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/platform_device.h>
-+#include <linux/interrupt.h>
-+#include <linux/backlight.h>
-+#include <linux/fb.h>
-+#include <linux/clk.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+
-+#include <mach/board.h>
-+#include <mach/cpu.h>
-+#include <mach/atmel_hlcdc.h>
-+#include <mach/atmel_hlcdc_ovl.h>
-+
-+#include <video/atmel_lcdfb.h>
-+
-+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
-+ | FBINFO_PARTIAL_PAN_OK \
-+ | FBINFO_HWACCEL_YPAN)
-+
-+#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
-+
-+struct atmel_hlcd_dma_desc {
-+ u32 address;
-+ u32 control;
-+ u32 next;
-+};
-+
-+static void atmel_hlcdfb_update_dma_base(struct fb_info *info,
-+
-+ struct fb_var_screeninfo *var)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ struct fb_fix_screeninfo *fix = &info->fix;
-+ unsigned long dma_addr;
-+ struct atmel_hlcd_dma_desc *desc;
-+
-+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-+ + var->xoffset * var->bits_per_pixel / 8);
-+
-+ dma_addr &= ~3UL;
-+
-+ /* Setup the DMA descriptor, this descriptor will loop to itself */
-+ desc = sinfo->dma_desc;
-+
-+ desc->address = dma_addr;
-+ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
-+ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
-+ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
-+ desc->next = sinfo->dma_desc_phys;
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
-+}
-+
-+static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
-+ struct fb_var_screeninfo *var)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ struct fb_fix_screeninfo *fix = &info->fix;
-+ unsigned long dma_addr;
-+ struct atmel_hlcd_dma_desc *desc;
-+
-+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
-+ + var->xoffset * var->bits_per_pixel / 8);
-+
-+ dma_addr &= ~3UL;
-+
-+ /* Setup the DMA descriptor, this descriptor will loop to itself */
-+ desc = sinfo->dma_desc;
-+
-+ desc->address = dma_addr;
-+ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
-+ desc->control = LCDC_OVRCTRL1_ADDIEN | LCDC_OVRCTRL1_DSCRIEN
-+ | LCDC_OVRCTRL1_DMAIEN | LCDC_OVRCTRL1_DFETCH;
-+ desc->next = sinfo->dma_desc_phys;
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVRADDR1, dma_addr);
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVRCTRL1, desc->control);
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVRNEXT1, sinfo->dma_desc_phys);
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
-+}
-+
-+/* some bl->props field just changed */
-+static int atmel_bl_update_status(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+ int power = sinfo->bl_power;
-+ int brightness = bl->props.brightness;
-+ u32 reg;
-+
-+ /* REVISIT there may be a meaningful difference between
-+ * fb_blank and power ... there seem to be some cases
-+ * this doesn't handle correctly.
-+ */
-+ if (bl->props.fb_blank != sinfo->bl_power)
-+ power = bl->props.fb_blank;
-+ else if (bl->props.power != sinfo->bl_power)
-+ power = bl->props.power;
-+
-+ if (brightness < 0 && power == FB_BLANK_UNBLANK)
-+ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
-+ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+ else if (power != FB_BLANK_UNBLANK)
-+ brightness = 0;
-+
-+ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
-+ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
-+
-+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
-+
-+ return 0;
-+}
-+
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
-+{
-+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
-+
-+ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
-+}
-+
-+static const struct backlight_ops atmel_hlcdc_bl_ops = {
-+ .update_status = atmel_bl_update_status,
-+ .get_brightness = atmel_bl_get_brightness,
-+};
-+
-+static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
-+{
-+ /* have some default contrast/backlight settings */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL |
-+ (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET));
-+}
-+
-+void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
-+{
-+ u32 value;
-+
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-+ msleep(1);
-+ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-+ msleep(1);
-+}
-+
-+static void atmel_hlcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
-+{
-+ /* Disable DISP signal */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
-+ msleep(1);
-+ /* Disable synchronization */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
-+ msleep(1);
-+ /* Disable pixel clock */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
-+ msleep(1);
-+ /* Disable PWM */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
-+ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
-+ msleep(1);
-+
-+ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
-+ /* Wait for the end of DMA transfer */
-+ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
-+ msleep(10);
-+ //FIXME: OVL DMA?
-+}
-+
-+static u32 atmel_hlcdfb_get_rgbmode(struct fb_info *info)
-+{
-+ u32 value = 0;
-+
-+ switch (info->var.bits_per_pixel) {
-+ case 1:
-+ value = LCDC_BASECFG1_CLUTMODE_1BPP | LCDC_BASECFG1_CLUTEN;
-+ break;
-+ case 2:
-+ value = LCDC_BASECFG1_CLUTMODE_2BPP | LCDC_BASECFG1_CLUTEN;
-+ break;
-+ case 4:
-+ value = LCDC_BASECFG1_CLUTMODE_4BPP | LCDC_BASECFG1_CLUTEN;
-+ break;
-+ case 8:
-+ value = LCDC_BASECFG1_CLUTMODE_8BPP | LCDC_BASECFG1_CLUTEN;
-+ break;
-+ case 12:
-+ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
-+ break;
-+ case 16:
-+ if (info->var.transp.offset)
-+ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
-+ else
-+ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
-+ break;
-+ case 18:
-+ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
-+ break;
-+ case 24:
-+ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
-+ break;
-+ case 32:
-+ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
-+ break;
-+ default:
-+ dev_err(info->device, "Cannot set video mode for %dbpp\n",
-+ info->var.bits_per_pixel);
-+ break;
-+ }
-+
-+ return value;
-+}
-+
-+static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ unsigned long value;
-+ unsigned long clk_value_khz;
-+
-+ dev_dbg(info->device, "%s:\n", __func__);
-+ /* Set pixel clock */
-+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-+
-+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+
-+ if (value < 1) {
-+ dev_notice(info->device, "using system clock as pixel clock\n");
-+ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-+ } else {
-+ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
-+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
-+ PICOS2KHZ(info->var.pixclock));
-+ value = value - 2;
-+ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
-+ value);
-+ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
-+ | LCDC_LCDCFG0_CLKPOL
-+ | LCDC_LCDCFG0_CGDISBASE;
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
-+ }
-+
-+ /* Initialize control register 5 */
-+ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
-+ value = sinfo->default_lcdcon2;
-+ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
-+ | LCDC_LCDCFG5_DISPDLY
-+ | LCDC_LCDCFG5_VSPDLYS;
-+
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ value |= LCDC_LCDCFG5_HSPOL;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ value |= LCDC_LCDCFG5_VSPOL;
-+
-+ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
-+
-+ /* Vertical & Horizontal Timing */
-+ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
-+ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
-+
-+ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
-+ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
-+
-+ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
-+ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
-+
-+ /* Display size */
-+ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
-+ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
-+ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, atmel_hlcdfb_get_rgbmode(info));
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
-+
-+ /* Disable all interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-+ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-+ //FIXME: Let video-driver register a callback
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
-+ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
-+
-+ return 0;
-+}
-+
-+static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
-+{
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ u32 xpos, ypos, xres, yres, cfg9;
-+
-+ if (info->var.nonstd >> 31) {
-+ xpos = (info->var.nonstd >> 10) & 0x3ff;
-+ ypos = info->var.nonstd & 0x3ff;
-+ xres = info->var.xres ? info->var.xres - 1 : 0;
-+ yres = info->var.yres ? info->var.yres - 1 : 0;
-+ cfg9 = LCDC_OVR1CFG9_DMA | LCDC_OVR1CFG9_OVR |
-+ LCDC_OVR1CFG9_ITER | LCDC_OVR1CFG9_ITER2BL |
-+ LCDC_OVR1CFG9_REP;
-+ if (info->var.transp.offset)
-+ cfg9 |= LCDC_OVR1CFG9_LAEN;
-+ else
-+ cfg9 |= LCDC_OVR1CFG9_GAEN | LCDC_OVR1CFG9_GA;
-+ } else {
-+ xpos = ypos = yres = xres = cfg9 = 0;
-+ }
-+
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG0,
-+ LCDC_OVR1CFG0_BLEN_AHB_INCR4 | LCDC_OVR1CFG0_DLBO);
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG1,
-+ atmel_hlcdfb_get_rgbmode(info));
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG2, xpos |
-+ (ypos << LCDC_OVR1CFG2_YOFFSET_OFFSET));
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG3, xres |
-+ (yres << LCDC_OVR1CFG3_YSIZE_OFFSET));
-+ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG9, cfg9);
-+
-+ return 0;
-+}
-+static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
-+{
-+ /* Saturate vertical and horizontal timings at maximum values */
-+ var->vsync_len = min_t(u32, var->vsync_len,
-+ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
-+ var->upper_margin = min_t(u32, var->upper_margin,
-+ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
-+ var->lower_margin = min_t(u32, var->lower_margin,
-+ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
-+ var->right_margin = min_t(u32, var->right_margin,
-+ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
-+ var->hsync_len = min_t(u32, var->hsync_len,
-+ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
-+ var->left_margin = min_t(u32, var->left_margin,
-+ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-+
-+}
-+
-+static irqreturn_t atmel_hlcdfb_interrupt(int irq, void *dev_id)
-+{
-+ struct fb_info *info = dev_id;
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+ u32 status, baselayer_status;
-+
-+ /* Check for error status via interrupt.*/
-+ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
-+ if (status & LCDC_LCDISR_HEO)
-+ return IRQ_NONE;
-+
-+ if (status & LCDC_LCDISR_FIFOERR)
-+ dev_warn(info->device, "FIFO underflow %#x\n", status);
-+
-+ if (status & LCDC_LCDISR_BASE) {
-+ /* Check base layer's overflow error. */
-+ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
-+
-+ if (baselayer_status & LCDC_BASEISR_OVR)
-+ dev_warn(info->device, "base layer overflow %#x\n",
-+ baselayer_status);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int atmel_hlcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
-+{
-+ struct fb_info *info = platform_get_drvdata(pdev);
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+
-+ /*
-+ * We don't want to handle interrupts while the clock is
-+ * stopped. It may take forever.
-+ */
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
-+
-+ if (sinfo->atmel_lcdfb_power_control)
-+ sinfo->atmel_lcdfb_power_control(0);
-+
-+ atmel_hlcdfb_stop(sinfo, 0);
-+ atmel_lcdfb_stop_clock(sinfo);
-+
-+ return 0;
-+}
-+
-+static int atmel_hlcdfb_resume(struct platform_device *pdev)
-+{
-+ struct fb_info *info = platform_get_drvdata(pdev);
-+ struct atmel_lcdfb_info *sinfo = info->par;
-+
-+ atmel_lcdfb_start_clock(sinfo);
-+ atmel_hlcdfb_start(sinfo);
-+ if (sinfo->atmel_lcdfb_power_control)
-+ sinfo->atmel_lcdfb_power_control(1);
-+
-+ /* Enable fifo error & BASE LAYER overflow interrupts */
-+ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
-+ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
-+ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
-+
-+ return 0;
-+}
-+
-+#else
-+#define atmel_hlcdfb_suspend NULL
-+#define atmel_hlcdfb_resume NULL
-+#endif
-+
-+static struct atmel_lcdfb_devdata dev_data_base = {
-+ .setup_core = atmel_hlcdfb_setup_core_base,
-+ .start = atmel_hlcdfb_start,
-+ .stop = atmel_hlcdfb_stop,
-+ .isr = atmel_hlcdfb_interrupt,
-+ .update_dma = atmel_hlcdfb_update_dma_base,
-+ .bl_ops = &atmel_hlcdc_bl_ops,
-+ .init_contrast = atmel_hlcdfb_init_contrast,
-+ .limit_screeninfo = atmelfb_limit_screeninfo,
-+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-+ .lut_base = ATMEL_HLCDC_LUT,
-+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
-+};
-+
-+static struct atmel_lcdfb_devdata dev_data_ovl = {
-+ .setup_core = atmel_hlcdfb_setup_core_ovl,
-+ .update_dma = atmel_hlcdfb_update_dma_ovl,
-+ .limit_screeninfo = atmelfb_limit_screeninfo,
-+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-+ .lut_base = 0x800, //FIXME: add define
-+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
-+};
-+
-+static const struct platform_device_id atmelfb_dev_table[] = {
-+ { "atmel_hlcdfb_base", (kernel_ulong_t)&dev_data_base },
-+ { "atmel_hlcdfb_ovl", (kernel_ulong_t)&dev_data_ovl },
-+}
-+MODULE_DEVICE_TABLE(platform, atmelfb_dev_table);
-+
-+static int __init atmel_hlcdfb_probe(struct platform_device *pdev)
-+{
-+ const struct platform_device_id *id = platform_get_device_id(pdev);
-+
-+ return __atmel_lcdfb_probe(pdev, (struct atmel_lcdfb_devdata *)id->driver_data);
-+}
-+static int __exit atmel_hlcdfb_remove(struct platform_device *pdev)
-+{
-+ return __atmel_lcdfb_remove(pdev);
-+}
-+
-+static struct platform_driver atmel_hlcdfb_driver = {
-+ .remove = __exit_p(atmel_hlcdfb_remove),
-+ .suspend = atmel_hlcdfb_suspend,
-+ .resume = atmel_hlcdfb_resume,
-+
-+ .driver = {
-+ .name = "atmel_hlcdfb",
-+ .owner = THIS_MODULE,
-+ },
-+ .id_table = atmelfb_dev_table,
-+};
-+
-+static int __init atmel_hlcdfb_init(void)
-+{
-+ return platform_driver_probe(&atmel_hlcdfb_driver, atmel_hlcdfb_probe);
-+}
-+module_init(atmel_hlcdfb_init);
-+
-+static void __exit atmel_hlcdfb_exit(void)
-+{
-+ platform_driver_unregister(&atmel_hlcdfb_driver);
-+}
-+module_exit(atmel_hlcdfb_exit);
-+
-+MODULE_DESCRIPTION("AT91 HLCD Controller framebuffer driver");
-+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com> "
-+ "and Wolfram Sang <w.sang@pengutronix.de");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 060d41f..cd57361 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -90,6 +90,10 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
-
- dma_free_writecombine(info->device, info->fix.smem_len,
- info->screen_base, info->fix.smem_start);
-+
-+ if (sinfo->dev_data->dma_desc_size && sinfo->dma_desc)
-+ dma_free_writecombine(info->device, sinfo->dev_data->dma_desc_size,
-+ sinfo->dma_desc, sinfo->dma_desc_phys);
- }
-
- /**
-@@ -118,6 +122,17 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
-
- memset(info->screen_base, 0, info->fix.smem_len);
-
-+ if (sinfo->dev_data->dma_desc_size) {
-+ sinfo->dma_desc = dma_alloc_writecombine(info->device,
-+ sinfo->dev_data->dma_desc_size,
-+ &(sinfo->dma_desc_phys), GFP_KERNEL);
-+
-+ if (!sinfo->dma_desc) {
-+ dma_free_writecombine(info->device, info->fix.smem_len,
-+ info->screen_base, info->fix.smem_start);
-+ return -ENOMEM;
-+ }
-+ }
- return 0;
- }
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 952cff7d64d122e94ca17a2281fc170a8c73ec95 Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Mon, 30 May 2011 17:04:35 +0200
-Subject: WIP: add clut resource
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Warning: will currently break old AT91-boards!
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_hlcdfb.c | 2 --
- drivers/video/atmel_lcdfb.c | 1 -
- drivers/video/atmel_lcdfb_core.c | 35 ++++++++++++++++++++++++++---------
- include/video/atmel_lcdfb.h | 2 +-
- 4 files changed, 27 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-index b772841..346bb80 100644
---- a/drivers/video/atmel_hlcdfb.c
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -454,7 +454,6 @@ static struct atmel_lcdfb_devdata dev_data_base = {
- .init_contrast = atmel_hlcdfb_init_contrast,
- .limit_screeninfo = atmelfb_limit_screeninfo,
- .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-- .lut_base = ATMEL_HLCDC_LUT,
- .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
- };
-
-@@ -463,7 +462,6 @@ static struct atmel_lcdfb_devdata dev_data_ovl = {
- .update_dma = atmel_hlcdfb_update_dma_ovl,
- .limit_screeninfo = atmelfb_limit_screeninfo,
- .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-- .lut_base = 0x800, //FIXME: add define
- .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
- };
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 8d7992c..402cb24 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -399,7 +399,6 @@ static struct atmel_lcdfb_devdata dev_data = {
- .init_contrast = atmel_lcdfb_init_contrast,
- .limit_screeninfo = atmelfb_limit_screeninfo,
- .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
-- .lut_base = ATMEL_LCDC_LUT,
- };
-
- static int __init atmel_lcdfb_probe(struct platform_device *pdev)
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index cd57361..89d974a 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -426,9 +426,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
- * TODO: intensity bit. Maybe something like
- * ~(red[10] ^ green[10] ^ blue[10]) & 1
- */
--
-- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
-- val);
-+ writel(val, sinfo->clut + regno * 4);
- ret = 0;
- }
- break;
-@@ -436,8 +434,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
- case FB_VISUAL_MONO01:
- if (regno < 2) {
- val = (regno == 0) ? 0x00 : 0x1F;
-- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
-- val);
-+ writel(val, sinfo->clut + regno * 4);
- ret = 0;
- }
- break;
-@@ -553,7 +550,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- struct atmel_lcdfb_info *sinfo;
- struct atmel_lcdfb_info *pdata_sinfo;
- struct fb_videomode fbmode;
-- struct resource *regs = NULL;
-+ struct resource *regs = NULL, *clut = NULL;
- struct resource *map = NULL;
- int ret;
-
-@@ -628,11 +625,19 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- goto stop_clk;
- }
-
-+ clut = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ if (!clut) {
-+ dev_err(dev, "clut resources unusable\n");
-+ ret = -ENXIO;
-+ goto stop_clk;
-+ }
-+
- /* No error checking, some devices can do without IRQ */
- sinfo->irq_base = platform_get_irq(pdev, 0);
-
- /* Initialize video memory */
-- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-+ //FIXME: Fix LUTs for old platforms
-+ map = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- if (map) {
- /* use a pre-allocated memory buffer */
- info->fix.smem_start = map->start;
-@@ -676,6 +681,17 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- goto release_mem;
- }
-
-+ //FIXME: proper request_region and cleanup
-+ if (!request_mem_region(clut->start, resource_size(clut), pdev->name)) {
-+ ret = -EBUSY;
-+ goto unmap_mmio;
-+ }
-+ sinfo->clut = ioremap(clut->start, resource_size(clut));
-+ if (!sinfo->clut) {
-+ dev_err(dev, "cannot map CLUT\n");
-+ goto unmap_mmio;
-+ }
-+
- /* Initialize PWM for contrast or backlight ("off") */
- if (sinfo->dev_data->init_contrast)
- sinfo->dev_data->init_contrast(sinfo);
-@@ -688,7 +704,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
- IRQF_SHARED, pdev->name, info);
- if (ret) {
- dev_err(dev, "request_irq failed: %d\n", ret);
-- goto unmap_mmio;
-+ goto clear_backlight;
- }
- }
-
-@@ -746,8 +762,9 @@ unregister_irqs:
- cancel_work_sync(&sinfo->task);
- if (sinfo->irq_base >= 0)
- free_irq(sinfo->irq_base, info);
--unmap_mmio:
-+clear_backlight:
- exit_backlight(sinfo);
-+unmap_mmio:
- iounmap(sinfo->mmio);
- release_mem:
- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
-diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
-index 3a0dfc7..a9563b8 100644
---- a/include/video/atmel_lcdfb.h
-+++ b/include/video/atmel_lcdfb.h
-@@ -48,7 +48,6 @@ struct atmel_lcdfb_devdata {
- void (*limit_screeninfo)(struct fb_var_screeninfo *var);
- const struct backlight_ops *bl_ops;
- int fbinfo_flags;
-- u32 lut_base;
- int dma_desc_size;
- };
-
-@@ -63,6 +62,7 @@ struct atmel_lcdfb_info {
- spinlock_t lock;
- struct fb_info *info;
- void __iomem *mmio;
-+ void __iomem *clut;
- int irq_base;
- struct atmel_lcdfb_devdata *dev_data;
- struct work_struct task;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2013c10691d645778545505b7ea07fa539b8ae11 Mon Sep 17 00:00:00 2001
+From: Havard Skinnemoen <havard@skinnemoen.net>
+Date: Tue, 24 Mar 2009 10:45:19 +0100
+Subject: net/macb: Use non-coherent memory for rx buffers
+
+Allocate regular pages to use as backing for the RX ring and use the
+DMA API to sync the caches. This should give a bit better performance
+since it allows the CPU to do burst transfers from memory. It is also
+a necessary step on the way to reduce the amount of copying done by
+the driver.
+
+Signed-off-by: Havard Skinnemoen <havard@skinnemoen.net>
+[nicolas.ferre@atmel.com: adapt to newer kernel]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/ethernet/cadence/macb.c | 206 +++++++++++++++++++++++-------------
+ drivers/net/ethernet/cadence/macb.h | 20 +++-
+ 2 files changed, 148 insertions(+), 78 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
+index 56bab3c..e3168bf 100644
+--- a/drivers/net/ethernet/cadence/macb.c
++++ b/drivers/net/ethernet/cadence/macb.c
+@@ -10,6 +10,7 @@
+
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+ #include <linux/clk.h>
++#include <linux/highmem.h>
+ #include <linux/module.h>
+ #include <linux/moduleparam.h>
+ #include <linux/kernel.h>
+@@ -32,6 +33,8 @@
+ #define RX_BUFFER_SIZE 128
+ #define RX_RING_SIZE 512
+ #define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
++#define RX_BUFFERS_PER_PAGE (PAGE_SIZE / RX_BUFFER_SIZE)
++#define RX_RING_PAGES (RX_RING_SIZE / RX_BUFFERS_PER_PAGE)
+
+ #define TX_RING_SIZE 128
+ #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE)
+@@ -92,9 +95,16 @@ static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
+ return &bp->rx_ring[macb_rx_ring_wrap(index)];
+ }
+
+-static void *macb_rx_buffer(struct macb *bp, unsigned int index)
++static struct macb_rx_page *macb_rx_page(struct macb *bp, unsigned int index)
+ {
+- return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
++ unsigned int entry = macb_rx_ring_wrap(index);
++
++ return &bp->rx_page[entry / RX_BUFFERS_PER_PAGE];
++}
++
++static unsigned int macb_rx_page_offset(struct macb *bp, unsigned int index)
++{
++ return (index % RX_BUFFERS_PER_PAGE) * RX_BUFFER_SIZE;
+ }
+
+ static void __macb_set_hwaddr(struct macb *bp)
+@@ -492,11 +502,15 @@ static void macb_tx_interrupt(struct macb *bp)
+ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ unsigned int last_frag)
+ {
+- unsigned int len;
+- unsigned int frag;
+- unsigned int offset;
+- struct sk_buff *skb;
+- struct macb_dma_desc *desc;
++ unsigned int len;
++ unsigned int frag;
++ unsigned int skb_offset;
++ unsigned int pg_offset;
++ struct macb_rx_page *rx_page;
++ dma_addr_t phys;
++ void *buf;
++ struct sk_buff *skb;
++ struct macb_dma_desc *desc;
+
+ desc = macb_rx_desc(bp, last_frag);
+ len = MACB_BFEXT(RX_FRMLEN, desc->ctrl);
+@@ -530,7 +544,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ return 1;
+ }
+
+- offset = 0;
++ skb_offset = 0;
+ len += NET_IP_ALIGN;
+ skb_checksum_none_assert(skb);
+ skb_put(skb, len);
+@@ -538,13 +552,28 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
+ for (frag = first_frag; ; frag++) {
+ unsigned int frag_len = RX_BUFFER_SIZE;
+
+- if (offset + frag_len > len) {
++ if (skb_offset + frag_len > len) {
+ BUG_ON(frag != last_frag);
+- frag_len = len - offset;
++ frag_len = len - skb_offset;
+ }
+- skb_copy_to_linear_data_offset(skb, offset,
+- macb_rx_buffer(bp, frag), frag_len);
+- offset += RX_BUFFER_SIZE;
++
++ rx_page = macb_rx_page(bp, frag);
++ pg_offset = macb_rx_page_offset(bp, frag);
++ phys = rx_page->phys;
++
++ dma_sync_single_range_for_cpu(&bp->pdev->dev, phys,
++ pg_offset, frag_len, DMA_FROM_DEVICE);
++
++ buf = kmap_atomic(rx_page->page);
++ skb_copy_to_linear_data_offset(skb, skb_offset,
++ buf + pg_offset, frag_len);
++ kunmap_atomic(buf);
++
++ skb_offset += frag_len;
++
++ dma_sync_single_range_for_device(&bp->pdev->dev, phys,
++ pg_offset, frag_len, DMA_FROM_DEVICE);
++
+ desc = macb_rx_desc(bp, frag);
+ desc->addr &= ~MACB_BIT(RX_USED);
+
+@@ -824,86 +853,90 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ return NETDEV_TX_OK;
+ }
+
+-static void macb_free_consistent(struct macb *bp)
++static void macb_free_rings(struct macb *bp)
+ {
+- if (bp->tx_skb) {
+- kfree(bp->tx_skb);
+- bp->tx_skb = NULL;
+- }
+- if (bp->rx_ring) {
+- dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES,
+- bp->rx_ring, bp->rx_ring_dma);
+- bp->rx_ring = NULL;
+- }
+- if (bp->tx_ring) {
+- dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES,
+- bp->tx_ring, bp->tx_ring_dma);
+- bp->tx_ring = NULL;
+- }
+- if (bp->rx_buffers) {
+- dma_free_coherent(&bp->pdev->dev,
+- RX_RING_SIZE * RX_BUFFER_SIZE,
+- bp->rx_buffers, bp->rx_buffers_dma);
+- bp->rx_buffers = NULL;
++ int i;
++
++ for (i = 0; i < RX_RING_PAGES; i++) {
++ struct macb_rx_page *rx_page = &bp->rx_page[i];
++
++ if (!rx_page->page)
++ continue;
++
++ dma_unmap_page(&bp->pdev->dev, rx_page->phys,
++ PAGE_SIZE, DMA_FROM_DEVICE);
++ put_page(rx_page->page);
++ rx_page->page = NULL;
+ }
++
++ kfree(bp->tx_skb);
++ kfree(bp->rx_page);
++ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
++ bp->tx_ring_dma);
++ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
++ bp->rx_ring_dma);
+ }
+
+-static int macb_alloc_consistent(struct macb *bp)
++static int macb_init_rings(struct macb *bp)
+ {
+- int size;
++ struct page *page;
++ dma_addr_t phys;
++ unsigned int page_idx;
++ unsigned int ring_idx;
++ unsigned int i;
+
+- size = TX_RING_SIZE * sizeof(struct macb_tx_skb);
+- bp->tx_skb = kmalloc(size, GFP_KERNEL);
+- if (!bp->tx_skb)
+- goto out_err;
+-
+- size = RX_RING_BYTES;
+- bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
++ bp->rx_ring = dma_alloc_coherent(&bp->pdev->dev, RX_RING_BYTES,
+ &bp->rx_ring_dma, GFP_KERNEL);
+ if (!bp->rx_ring)
+- goto out_err;
++ goto err_alloc_rx_ring;
++
+ netdev_dbg(bp->dev,
+ "Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
++ RX_RING_BYTES, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
+
+- size = TX_RING_BYTES;
+- bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
++ bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, TX_RING_BYTES,
+ &bp->tx_ring_dma, GFP_KERNEL);
+ if (!bp->tx_ring)
+- goto out_err;
+- netdev_dbg(bp->dev,
+- "Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
+-
+- size = RX_RING_SIZE * RX_BUFFER_SIZE;
+- bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
+- &bp->rx_buffers_dma, GFP_KERNEL);
+- if (!bp->rx_buffers)
+- goto out_err;
++ goto err_alloc_tx_ring;
++
+ netdev_dbg(bp->dev,
+- "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
+- size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers);
++ "Allocated TX ring of %d bytes at 0x%08lx (mapped %p)\n",
++ TX_RING_BYTES, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
+
+- return 0;
++ bp->rx_page = kcalloc(RX_RING_PAGES, sizeof(struct macb_rx_page),
++ GFP_KERNEL);
++ if (!bp->rx_page)
++ goto err_alloc_rx_page;
+
+-out_err:
+- macb_free_consistent(bp);
+- return -ENOMEM;
+-}
++ bp->tx_skb = kcalloc(TX_RING_SIZE, sizeof(struct macb_tx_skb),
++ GFP_KERNEL);
++ if (!bp->tx_skb)
++ goto err_alloc_tx_skb;
+
+-static void macb_init_rings(struct macb *bp)
+-{
+- int i;
+- dma_addr_t addr;
++ for (page_idx = 0, ring_idx = 0; page_idx < RX_RING_PAGES; page_idx++) {
++ page = alloc_page(GFP_KERNEL);
++ if (!page)
++ goto err_alloc_page;
++
++ phys = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(&bp->pdev->dev, phys))
++ goto err_map_page;
++
++ bp->rx_page[page_idx].page = page;
++ bp->rx_page[page_idx].phys = phys;
+
+- addr = bp->rx_buffers_dma;
+- for (i = 0; i < RX_RING_SIZE; i++) {
+- bp->rx_ring[i].addr = addr;
+- bp->rx_ring[i].ctrl = 0;
+- addr += RX_BUFFER_SIZE;
++ for (i = 0; i < RX_BUFFERS_PER_PAGE; i++, ring_idx++) {
++ bp->rx_ring[ring_idx].addr = phys;
++ bp->rx_ring[ring_idx].ctrl = 0;
++ phys += RX_BUFFER_SIZE;
++ }
+ }
+ bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
+
++ netdev_dbg(bp->dev, "Allocated %u RX buffers (%lu pages)\n",
++ RX_RING_SIZE, RX_RING_PAGES);
++
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ bp->tx_ring[i].addr = 0;
+ bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+@@ -911,6 +944,28 @@ static void macb_init_rings(struct macb *bp)
+ bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
++
++ return 0;
++
++err_map_page:
++ __free_page(page);
++err_alloc_page:
++ while (page_idx--) {
++ dma_unmap_page(&bp->pdev->dev, bp->rx_page[page_idx].phys,
++ PAGE_SIZE, DMA_FROM_DEVICE);
++ __free_page(bp->rx_page[page_idx].page);
++ }
++ kfree(bp->tx_skb);
++err_alloc_tx_skb:
++ kfree(bp->rx_page);
++err_alloc_rx_page:
++ dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES, bp->tx_ring,
++ bp->tx_ring_dma);
++err_alloc_tx_ring:
++ dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES, bp->rx_ring,
++ bp->rx_ring_dma);
++err_alloc_rx_ring:
++ return -ENOMEM;
+ }
+
+ static void macb_reset_hw(struct macb *bp)
+@@ -1185,16 +1240,15 @@ static int macb_open(struct net_device *dev)
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
+
+- err = macb_alloc_consistent(bp);
++ err = macb_init_rings(bp);
+ if (err) {
+- netdev_err(dev, "Unable to allocate DMA memory (error %d)\n",
++ netdev_err(dev, "Unable to allocate DMA rings (error %d)\n",
+ err);
+ return err;
+ }
+
+ napi_enable(&bp->napi);
+
+- macb_init_rings(bp);
+ macb_init_hw(bp);
+
+ /* schedule a link state check */
+@@ -1221,7 +1275,7 @@ static int macb_close(struct net_device *dev)
+ netif_carrier_off(dev);
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+- macb_free_consistent(bp);
++ macb_free_rings(bp);
+
+ return 0;
+ }
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index 256559d..01aecea 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -441,6 +441,23 @@ struct macb_dma_desc {
+ #define MACB_TX_USED_SIZE 1
+
+ /**
++ * struct macb_rx_page - data associated with a page used as RX buffers
++ * @page: Physical page used as storage for the buffers
++ * @phys: DMA address of the page
++ *
++ * Each page is used to provide %MACB_RX_BUFFERS_PER_PAGE RX buffers.
++ * The page gets an initial reference when it is inserted into the
++ * ring, and an additional reference each time it is passed up the
++ * stack as a fragment. When all the buffers have been used, we drop
++ * the initial reference and allocate a new page. Any additional
++ * references are dropped when the higher layers free the skb.
++ */
++struct macb_rx_page {
++ struct page *page;
++ dma_addr_t phys;
++};
++
++/**
+ * struct macb_tx_skb - data about an skb which is being transmitted
+ * @skb: skb currently being transmitted
+ * @mapping: DMA address of the skb's data buffer
+@@ -531,7 +548,7 @@ struct macb {
+
+ unsigned int rx_tail;
+ struct macb_dma_desc *rx_ring;
+- void *rx_buffers;
++ struct macb_rx_page *rx_page;
+
+ unsigned int tx_head, tx_tail;
+ struct macb_dma_desc *tx_ring;
+@@ -552,7 +569,6 @@ struct macb {
+
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+- dma_addr_t rx_buffers_dma;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From e2086addb7f23c3aa497a3b9e36559efd6059e62 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 26 Jun 2012 11:07:32 +0200
+Subject: phy/micrel: Use proper phy in gmac
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/net/phy/micrel.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index 590f902..cc7f75b 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -191,6 +191,7 @@ static int __init ksphy_init(void)
+ {
+ int ret;
+
++#if 0
+ ret = phy_driver_register(&ks8001_driver);
+ if (ret)
+ goto err1;
+@@ -208,9 +209,15 @@ static int __init ksphy_init(void)
+ ret = phy_driver_register(&ks8051_driver);
+ if (ret)
+ goto err5;
++#endif
++
++ ret = phy_driver_register(&ksz9021_driver);
++ if (ret)
++ goto err1;
+
+ return 0;
+
++#if 0
+ err5:
+ phy_driver_unregister(&ks8041_driver);
+ err4:
+@@ -219,6 +226,7 @@ err3:
+ phy_driver_unregister(&ksz9021_driver);
+ err2:
+ phy_driver_unregister(&ks8001_driver);
++#endif
+ err1:
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 3df2f96a9b65c88f3caaba3ea667e3feffb14b0c Mon Sep 17 00:00:00 2001
-From: Wolfram Sang <w.sang@pengutronix.de>
-Date: Tue, 7 Jun 2011 12:58:36 +0200
-Subject: video: atmel_lcdfb: add error-msg when out of memory
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/video/atmel_lcdfb_core.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index 89d974a..ff84234 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -221,8 +221,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
- if (info->fix.smem_len) {
- unsigned int smem_len = (var->xres_virtual * var->yres_virtual
- * ((var->bits_per_pixel + 7) / 8));
-- if (smem_len > info->fix.smem_len)
-+ if (smem_len > info->fix.smem_len) {
-+ dev_err(dev, "not enough memory for this mode\n");
- return -EINVAL;
-+ }
- }
-
- /* Saturate vertical and horizontal timings at maximum values */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From af15c74766bcffe30022f7c27e477d2fce4b8471 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 10 Jul 2012 12:03:54 +0200
+Subject: phy/micrel: we need to register ks8051 phy for emac
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/net/phy/micrel.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
+index cc7f75b..2d80e01 100644
+--- a/drivers/net/phy/micrel.c
++++ b/drivers/net/phy/micrel.c
+@@ -206,10 +206,10 @@ static int __init ksphy_init(void)
+ ret = phy_driver_register(&ks8041_driver);
+ if (ret)
+ goto err4;
++#endif
+ ret = phy_driver_register(&ks8051_driver);
+ if (ret)
+- goto err5;
+-#endif
++ goto err2;
+
+ ret = phy_driver_register(&ksz9021_driver);
+ if (ret)
+@@ -227,6 +227,8 @@ err3:
+ err2:
+ phy_driver_unregister(&ks8001_driver);
+ #endif
++err2:
++ phy_driver_unregister(&ks8051_driver);
+ err1:
+ return ret;
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 21ab2ac12ae088515007d81868b9d3eb8446baad Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 17 Feb 2012 13:12:21 +0100
-Subject: video: atmel_lcdfb: HLCD modifications
-
-HAS TO BE REWORKED: break compatibility with previous LCD IP due to register
-map changes
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 43 +++++++++++++++++++++++++++
- drivers/video/atmel_hlcdfb.c | 5 ++--
- drivers/video/atmel_lcdfb.c | 1 +
- drivers/video/atmel_lcdfb_core.c | 1 +
- drivers/video/backlight/Kconfig | 4 +--
- 5 files changed, 50 insertions(+), 4 deletions(-)
-
-diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-index 9ed7e6e..738a853 100644
---- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-+++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-@@ -29,8 +29,10 @@
- #define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
- #define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
- #define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
-+#define LCDC_LCDCFG0_CGDISOVR2 (0x1 << 10)
- #define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
- #define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
-+#define LCDC_LCDCFG0_CGDISPP (0x1 << 13)
- #define LCDC_LCDCFG0_CLKDIV_OFFSET 16
- #define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
-
-@@ -49,8 +51,10 @@
- #define ATMEL_LCDC_LCDCFG3 0x000C
- #define LCDC_LCDCFG3_HFPW_OFFSET 0
- #define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
-+#define LCDC2_LCDCFG3_HFPW (0x1ff << LCDC_LCDCFG3_HFPW_OFFSET)
- #define LCDC_LCDCFG3_HBPW_OFFSET 16
- #define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
-+#define LCDC2_LCDCFG3_HBPW (0x1ff << LCDC_LCDCFG3_HBPW_OFFSET)
-
- #define ATMEL_LCDC_LCDCFG4 0x0010
- #define LCDC_LCDCFG4_PPL_OFFSET 0
-@@ -73,6 +77,7 @@
- #define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
- #define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
- #define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
-+#define LCDC_LCDCFG5_PP (0x1 << 10)
- #define LCDC_LCDCFG5_VSPSU (0x1 << 12)
- #define LCDC_LCDCFG5_VSPHO (0x1 << 13)
- #define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
-@@ -115,8 +120,10 @@
- #define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
- #define LCDC_LCDIER_BASEIE (0x1 << 8)
- #define LCDC_LCDIER_OVR1IE (0x1 << 9)
-+#define LCDC_LCDIER_OVR2IE (0x1 << 10)
- #define LCDC_LCDIER_HEOIE (0x1 << 11)
- #define LCDC_LCDIER_HCRIE (0x1 << 12)
-+#define LCDC_LCDIER_PPIE (0x1 << 13)
-
- #define ATMEL_LCDC_LCDIDR 0x0030
- #define LCDC_LCDIDR_SOFID (0x1 << 0)
-@@ -125,8 +132,10 @@
- #define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
- #define LCDC_LCDIDR_BASEID (0x1 << 8)
- #define LCDC_LCDIDR_OVR1ID (0x1 << 9)
-+#define LCDC_LCDIDR_OVR2ID (0x1 << 10)
- #define LCDC_LCDIDR_HEOID (0x1 << 11)
- #define LCDC_LCDIDR_HCRID (0x1 << 12)
-+#define LCDC_LCDIDR_PPID (0x1 << 13)
-
- #define ATMEL_LCDC_LCDIMR 0x0034
- #define LCDC_LCDIMR_SOFIM (0x1 << 0)
-@@ -135,8 +144,10 @@
- #define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
- #define LCDC_LCDIMR_BASEIM (0x1 << 8)
- #define LCDC_LCDIMR_OVR1IM (0x1 << 9)
-+#define LCDC_LCDIMR_OVR2IM (0x1 << 10)
- #define LCDC_LCDIMR_HEOIM (0x1 << 11)
- #define LCDC_LCDIMR_HCRIM (0x1 << 12)
-+#define LCDC_LCDIMR_PPIM (0x1 << 13)
-
- #define ATMEL_LCDC_LCDISR 0x0038
- #define LCDC_LCDISR_SOF (0x1 << 0)
-@@ -145,8 +156,11 @@
- #define LCDC_LCDISR_FIFOERR (0x1 << 4)
- #define LCDC_LCDISR_BASE (0x1 << 8)
- #define LCDC_LCDISR_OVR1 (0x1 << 9)
-+#define LCDC_LCDISR_OVR2 (0x1 << 10)
- #define LCDC_LCDISR_HEO (0x1 << 10)
-+#define LCDC2_LCDISR_HEO (0x1 << 11)
- #define LCDC_LCDISR_HCR (0x1 << 12)
-+#define LCDC_LCDISR_PP (0x1 << 13)
-
- #define ATMEL_LCDC_BASECHER 0x0040
- #define LCDC_BASECHER_CHEN (0x1 << 0)
-@@ -205,6 +219,7 @@
- #define ATMEL_LCDC_BASENEXT 0x0068
-
- #define ATMEL_LCDC_BASECFG0 0x006C
-+#define LCDC_BASECFG0_SIF (0x1 << 0)
- #define LCDC_BASECFG0_BLEN_OFFSET 4
- #define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
- #define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
-@@ -251,8 +266,22 @@
- #define ATMEL_LCDC_BASECFG4 0x007C
- #define LCDC_BASECFG4_DMA (0x1 << 8)
- #define LCDC_BASECFG4_REP (0x1 << 9)
-+#define LCDC_BASECFG4_DISCEN (0x1 << 11)
-+
-+#define ATMEL_LCDC_BASECFG5 0x0080
-+#define LCDC_BASECFG5_DISCXPOS_OFFSET 0
-+#define LCDC_BASECFG5_DISCXPOS (0x7ff << LCDC_BASECFG5_DISCXPOS_OFFSET)
-+#define LCDC_BASECFG5_DISCYPOS_OFFSET 16
-+#define LCDC_BASECFG5_DISCYPOS (0x7ff << LCDC_BASECFG5_DISCYPOS_OFFSET)
-+
-+#define ATMEL_LCDC_BASECFG6 0x0084
-+#define LCDC_BASECFG6_DISCXSIZE_OFFSET 0
-+#define LCDC_BASECFG6_DISCXSIZE (0x7ff << LCDC_BASECFG6_DISCXSIZE_OFFSET)
-+#define LCDC_BASECFG6_DISCYSIZE_OFFSET 16
-+#define LCDC_BASECFG6_DISCYSIZE (0x7ff << LCDC_BASECFG6_DISCYSIZE_OFFSET)
-
- #define ATMEL_LCDC_HEOCHER 0x0280
-+#define ATMEL_LCDC2_HEOCHER 0x0340
- #define LCDC_HEOCHER_CHEN (0x1 << 0)
- #define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
- #define LCDC_HEOCHER_A2QEN (0x1 << 2)
-@@ -674,6 +703,7 @@
- #define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
-
- #define ATMEL_LCDC_BASECLUT 0x400
-+#define ATMEL_LCDC2_BASECLUT 0x600
- #define LCDC_BASECLUT_BCLUT_OFFSET 0
- #define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
- #define LCDC_BASECLUT_GCLUT_OFFSET 8
-@@ -682,6 +712,7 @@
- #define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
-
- #define ATMEL_LCDC_OVR1CLUT 0x800
-+#define ATMEL_LCDC2_OVR1CLUT 0xa00
- #define LCDC_OVR1CLUT_BCLUT_OFFSET 0
- #define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
- #define LCDC_OVR1CLUT_GCLUT_OFFSET 8
-@@ -691,7 +722,18 @@
- #define LCDC_OVR1CLUT_ACLUT_OFFSET 24
- #define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
-
-+#define ATMEL_LCDC_OVR2CLUT 0xe00
-+#define LCDC_OVR2CLUT_BCLUT_OFFSET 0
-+#define LCDC_OVR2CLUT_BCLUT (0xff << LCDC_OVR2CLUT_BCLUT_OFFSET)
-+#define LCDC_OVR2CLUT_GCLUT_OFFSET 8
-+#define LCDC_OVR2CLUT_GCLUT (0xff << LCDC_OVR2CLUT_GCLUT_OFFSET)
-+#define LCDC_OVR2CLUT_RCLUT_OFFSET 16
-+#define LCDC_OVR2CLUT_RCLUT (0xff << LCDC_OVR2CLUT_RCLUT_OFFSET)
-+#define LCDC_OVR2CLUT_ACLUT_OFFSET 24
-+#define LCDC_OVR2CLUT_ACLUT (0xff << LCDC_OVR2CLUT_ACLUT_OFFSET)
-+
- #define ATMEL_LCDC_HEOCLUT 0x1000
-+#define ATMEL_LCDC2_HEOCLUT 0x1200
- #define LCDC_HEOCLUT_BCLUT_OFFSET 0
- #define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
- #define LCDC_HEOCLUT_GCLUT_OFFSET 8
-@@ -702,6 +744,7 @@
- #define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
-
- #define ATMEL_LCDC_HCRCLUT 0x1400
-+#define ATMEL_LCDC2_HCRCLUT 0x1600
- #define LCDC_HCRCLUT_BCLUT_OFFSET 0
- #define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
- #define LCDC_HCRCLUT_GCLUT_OFFSET 8
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-index 346bb80..c4c4559 100644
---- a/drivers/video/atmel_hlcdfb.c
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -9,6 +9,7 @@
- */
-
- #include <linux/kernel.h>
-+#include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/backlight.h>
-@@ -363,11 +364,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
- var->lower_margin = min_t(u32, var->lower_margin,
- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
- var->right_margin = min_t(u32, var->right_margin,
-- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
-+ (LCDC2_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
- var->hsync_len = min_t(u32, var->hsync_len,
- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
- var->left_margin = min_t(u32, var->left_margin,
-- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-+ (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-
- }
-
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 402cb24..86e3e32 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -9,6 +9,7 @@
- */
-
- #include <linux/kernel.h>
-+#include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/backlight.h>
-diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
-index ff84234..133d4ad 100644
---- a/drivers/video/atmel_lcdfb_core.c
-+++ b/drivers/video/atmel_lcdfb_core.c
-@@ -9,6 +9,7 @@
- */
-
- #include <linux/kernel.h>
-+#include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/dma-mapping.h>
- #include <linux/interrupt.h>
-diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
-index af16884..18d066b 100644
---- a/drivers/video/backlight/Kconfig
-+++ b/drivers/video/backlight/Kconfig
-@@ -144,8 +144,8 @@ if BACKLIGHT_CLASS_DEVICE
-
- config BACKLIGHT_ATMEL_LCDC
- bool "Atmel LCDC Contrast-as-Backlight control"
-- depends on FB_ATMEL
-- default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
-+ depends on FB_ATMEL || FB_ATMEL_HLCD
-+ default y
- help
- This provides a backlight control internal to the Atmel LCDC
- driver. If the LCD "contrast control" on your board is wired
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 61d28fa28e8249fea4d28589346eb68b022ccbfe Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Fri, 24 Jun 2011 13:03:29 +0200
-Subject: atmel_lcdfb: change pixel clock ratio calculation
-
-DIV_ROUND_UP() was used to calculate the pixel clock divider
-in atmel_hlcdfb_setup_core_base().
-But this rounding was producing a bigger divider each time it was called.
-We replace by DIV_ROUND_CLOSEST() to calculate it.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/video/atmel_hlcdfb.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-index c4c4559..a629dda 100644
---- a/drivers/video/atmel_hlcdfb.c
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -247,7 +247,7 @@ static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
- /* Set pixel clock */
- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
-
-- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-+ value = DIV_ROUND_CLOSEST(clk_value_khz, PICOS2KHZ(info->var.pixclock));
-
- if (value < 1) {
- dev_notice(info->device, "using system clock as pixel clock\n");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From e3cfccfee57c12157e38081fc11e0a2f2f5863f3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 10 Jun 2011 17:21:28 +0200
+Subject: media/video: atmel-isi: add dumb set_parm()
+
+Add dumb set_parm() & get_parm() function to struct soc_camera_host_ops.
+Needed for ffmpeg to be able to capture frames from ISI driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/atmel-isi.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
+index ec3f6a0..7a44df4 100644
+--- a/drivers/media/video/atmel-isi.c
++++ b/drivers/media/video/atmel-isi.c
+@@ -893,6 +893,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
+ return 0;
+ }
+
++
++static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_streamparm *parm)
++{
++ return 0;
++}
++
+ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = isi_camera_add_device,
+@@ -904,6 +910,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
+ .poll = isi_camera_poll,
+ .querycap = isi_camera_querycap,
+ .set_bus_param = isi_camera_set_bus_param,
++ .set_parm = isi_camera_set_parm,
++ .get_parm = isi_camera_set_parm,
+ };
+
+ /* -----------------------------------------------------------------------*/
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 05f008850856d65b80cc67cba9eb329e44c63cf1 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
-Date: Tue, 24 May 2011 23:45:21 +0200
-Subject: media/at91sam9x5-video: new driver for the high end overlay on
- at91sam9x5
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
----
- drivers/media/video/Kconfig | 8 +
- drivers/media/video/Makefile | 1 +
- drivers/media/video/at91sam9x5-video.c | 1441 ++++++++++++++++++++++++++++++++
- 3 files changed, 1450 insertions(+)
- create mode 100644 drivers/media/video/at91sam9x5-video.c
-
-diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
-index ce1e7ba..70a6a55 100644
---- a/drivers/media/video/Kconfig
-+++ b/drivers/media/video/Kconfig
-@@ -1163,6 +1163,14 @@ source "drivers/media/video/s5p-tv/Kconfig"
- endif # V4L_PLATFORM_DRIVERS
- endif # VIDEO_CAPTURE_DRIVERS
-
-+config VIDEO_AT91SAM9X5
-+ tristate "Support for AT91SAM9X5 Video"
-+ depends on ARCH_AT91
-+ depends on VIDEO_V4L2
-+ select VIDEOBUF2_DMA_CONTIG
-+ help
-+ support for the "High End Overlay" found in Atmel's AT91SAM9X5 SoCs.
-+
- menuconfig V4L_MEM2MEM_DRIVERS
- bool "Memory-to-memory multimedia devices"
- depends on VIDEO_V4L2
-diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
-index a6282a3..2b41c18 100644
---- a/drivers/media/video/Makefile
-+++ b/drivers/media/video/Makefile
-@@ -121,6 +121,7 @@ obj-$(CONFIG_VIDEO_MXB) += mxb.o
- obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
- obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
- obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
-+obj-$(CONFIG_VIDEO_AT91SAM9X5) += at91sam9x5-video.o
-
- obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
- obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
-diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
-new file mode 100644
-index 0000000..26ce376
---- /dev/null
-+++ b/drivers/media/video/at91sam9x5-video.c
-@@ -0,0 +1,1441 @@
-+/*
-+ * Copyright (C) 2011 Pengutronix
-+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it under
-+ * the terms of the GNU General Public License version 2 as published by the
-+ * Free Software Foundation.
-+ */
-+
-+/*
-+ * XXX:
-+ * - handle setting of global alpha
-+ * - handle more formats
-+ * - complete this list :-)
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+#include <media/v4l2-common.h>
-+#include <media/v4l2-dev.h>
-+#include <media/v4l2-ioctl.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#define debug(fmt, ...)
-+
-+#define DRIVER_NAME "at91sam9x5-video"
-+
-+#define REG_HEOCHER 0x00
-+#define REG_HEOCHER_CHEN 0x00000001
-+#define REG_HEOCHER_UPDATEEN 0x00000002
-+#define REG_HEOCHER_A2QEN 0x00000004
-+
-+#define REG_HEOCHDR 0x04
-+#define REG_HEOCHDR_CHDIS 0x00000001
-+#define REG_HEOCHDR_CHRST 0x00000100
-+
-+#define REG_HEOCHSR 0x08
-+#define REG_HEOCHSR_CHSR 0x00000001
-+#define REG_HEOCHSR_UPDATESR 0x00000002
-+#define REG_HEOCHSR_A2QSR 0x00000004
-+
-+#define REG_HEOIER 0x0c
-+#define REG_HEOIDR 0x10
-+#define REG_HEOIMR 0x14
-+#define REG_HEOISR 0x18
-+#define REG_HEOIxR_DMA 0x00000004
-+#define REG_HEOIxR_DSCR 0x00000008
-+#define REG_HEOIxR_ADD 0x00000010
-+#define REG_HEOIxR_DONE 0x00000020
-+#define REG_HEOIxR_OVR 0x00000040
-+#define REG_HEOIxR_UDMA 0x00000400
-+#define REG_HEOIxR_UDSCR 0x00000800
-+#define REG_HEOIxR_UADD 0x00001000
-+#define REG_HEOIxR_UDONE 0x00002000
-+#define REG_HEOIxR_UOVR 0x00004000
-+#define REG_HEOIxR_VDMA 0x00040000
-+#define REG_HEOIxR_VDSCR 0x00080000
-+#define REG_HEOIxR_VADD 0x00100000
-+#define REG_HEOIxR_VDONE 0x00200000
-+#define REG_HEOIxR_VOVR 0x00400000
-+
-+#define REG_HEOHEAD 0x1c
-+#define REG_HEOUHEAD 0x2c
-+#define REG_HEOVHEAD 0x3c
-+
-+#define REG_HEOADDR 0x20
-+#define REG_HEOUADDR 0x30
-+#define REG_HEOVADDR 0x40
-+
-+#define REG_HEOCTRL 0x24
-+#define REG_HEOUCTRL 0x34
-+#define REG_HEOVCTRL 0x44
-+#define REG_HEOxCTRL_DFETCH 0x00000001
-+#define REG_HEOCTRL_LFETCH 0x00000002
-+#define REG_HEOxCTRL_DMAIEN 0x00000004
-+#define REG_HEOxCTRL_DSCRIEN 0x00000008
-+#define REG_HEOxCTRL_ADDIEN 0x00000010
-+#define REG_HEOxCTRL_DONEIEN 0x00000020
-+
-+#define REG_HEONEXT 0x28
-+#define REG_HEOUNEXT 0x38
-+#define REG_HEOVNEXT 0x48
-+
-+#define REG_HEOCFG0 0x4c
-+#define REG_HEOCFG0_DLBO 0x00000100
-+#define REG_HEOCFG0_BLEN 0x00000030
-+#define REG_HEOCFG0_BLEN_INCR1 0x00000000
-+#define REG_HEOCFG0_BLEN_INCR4 0x00000010
-+#define REG_HEOCFG0_BLEN_INCR8 0x00000020
-+#define REG_HEOCFG0_BLEN_INCR16 0x00000030
-+#define REG_HEOCFG0_BLENUV 0x000000c0
-+#define REG_HEOCFG0_BLENUV_INCR1 0x00000000
-+#define REG_HEOCFG0_BLENUV_INCR4 0x00000040
-+#define REG_HEOCFG0_BLENUV_INCR8 0x00000080
-+#define REG_HEOCFG0_BLENUV_INCR16 0x000000c0
-+
-+#define REG_HEOCFG1 0x50
-+#define REG_HEOCFG1_CLUTEN 0x00000001
-+#define REG_HEOCFG1_YUVEN 0x00000002
-+#define REG_HEOCFG1_YUVMODE_12YCBCRP 0x00008000
-+
-+#define REG_HEOCFG2 0x54
-+#define REG_HEOCFG2_XPOS 0x000007ff
-+#define REG_HEOCFG2_YPOS 0x07ff0000
-+
-+#define REG_HEOCFG3 0x58
-+#define REG_HEOCFG3_XSIZE 0x000007ff
-+#define REG_HEOCFG3_YSIZE 0x07ff0000
-+
-+#define REG_HEOCFG4 0x5c
-+#define REG_HEOCFG4_XMEMSIZE 0x000007ff
-+#define REG_HEOCFG4_YMEMSIZE 0x07ff0000
-+
-+#define REG_HEOCFG5 0x60
-+#define REG_HEOCFG5_XSTRIDE 0xffffffff
-+
-+#define REG_HEOCFG6 0x64
-+#define REG_HEOCFG6_PSTRIDE 0xffffffff
-+
-+#define REG_HEOCFG7 0x68
-+#define REG_HEOCFG7_UVXSTRIDE 0xffffffff
-+
-+#define REG_HEOCFG8 0x6c
-+#define REG_HEOCFG8_UVPSTRIDE 0xffffffff
-+
-+#define REG_HEOCFG9 0x70
-+#define REG_HEOCFG10 0x74
-+#define REG_HEOCFG11 0x78
-+
-+#define REG_HEOCFG12 0x7c
-+#define REG_HEOCFG12_CRKEY 0x00000001
-+#define REG_HEOCFG12_INV 0x00000002
-+#define REG_HEOCFG12_ITER2BL 0x00000004
-+#define REG_HEOCFG12_ITER 0x00000008
-+#define REG_HEOCFG12_REVALPHA 0x00000010
-+#define REG_HEOCFG12_GAEN 0x00000020
-+#define REG_HEOCFG12_LAEN 0x00000040
-+#define REG_HEOCFG12_OVR 0x00000080
-+#define REG_HEOCFG12_DMA 0x00000100
-+#define REG_HEOCFG12_REP 0x00000200
-+#define REG_HEOCFG12_DSTKEY 0x00000400
-+#define REG_HEOCFG12_VIDPRI 0x00001000
-+#define REG_HEOCFG12_GA 0x00ff0000
-+
-+#define REG_HEOCFG13 0x80
-+#define REG_HEOCFG13_XFACTOR 0x00001fff
-+#define REG_HEOCFG13_YFACTOR 0x1fff0000
-+#define REG_HEOCFG13_SCALEN 0x80000000
-+
-+#define REG_HEOCFG14 0x84
-+#define REG_HEOCFG15 0x88
-+#define REG_HEOCFG16 0x8c
-+
-+#define valtomask(val, mask) (((val) << __ffs((mask))) & (mask))
-+#define valfrommask(val, mask) (((val) & (mask)) >> __ffs((mask)))
-+
-+struct at91sam9x5_video_pdata {
-+ u16 base_width;
-+ u16 base_height;
-+};
-+
-+struct at91sam9x5_video_bufinfo {
-+ struct vb2_buffer *vb;
-+ unsigned u_planeno, v_planeno;
-+ unsigned long plane_size[3];
-+};
-+
-+struct at91sam9x5_video_priv {
-+ struct platform_device *pdev;
-+
-+ /* framebuffer stuff */
-+ struct notifier_block fb_notifier;
-+ struct fb_info *fbinfo;
-+
-+ struct video_device *video_dev;
-+
-+ void __iomem *regbase;
-+ unsigned int irq;
-+
-+ struct vb2_queue queue;
-+ void *alloc_ctx;
-+
-+ struct at91sam9x5_video_bufinfo cur, next;
-+
-+ /* protects the members after lock and hardware access */
-+ spinlock_t lock;
-+
-+ enum {
-+ /* DMA not running */
-+ at91sam9x5_video_HW_IDLE,
-+ /* DMA running, unless cfgstate is BAD */
-+ at91sam9x5_video_HW_RUNNING,
-+ } hwstate;
-+
-+ enum {
-+ at91sam9x5_video_CFG_GOOD,
-+ /* the shadow registers need an update */
-+ at91sam9x5_video_CFG_GOOD_LATCH,
-+ at91sam9x5_video_CFG_BAD,
-+ } cfgstate;
-+
-+ /* if true the vid_out config in hardware doesn't match sw config */
-+ int cfgupdate;
-+
-+ int valid_config;
-+
-+ struct v4l2_pix_format fmt_vid_out_cur, fmt_vid_out_next;
-+
-+ int rotation;
-+
-+ struct v4l2_window fmt_vid_overlay;
-+
-+ /*
-+ * For YUV formats Y data is always in plane 0. U, V are either both in
-+ * 0, both in 1, or U in 1 or V in 2. -1 for formats that don't use U
-+ * and V.
-+ */
-+ int u_planeno, v_planeno;
-+
-+ unsigned long plane_size[3];
-+
-+ /*
-+ * These are the offsets into the buffers to start the hardware for.
-+ * Depending on rotation and overlay position this is more or less ugly
-+ * to calculate. (y_offset is used for rgb data, too.)
-+ */
-+ u32 y_offset, u_offset, v_offset;
-+
-+ u32 irqstat;
-+};
-+
-+static u32 at91sam9x5_video_read32(struct at91sam9x5_video_priv *priv,
-+ size_t offset)
-+{
-+ /* XXX: really use the __raw variants? */
-+ return __raw_readl(priv->regbase + offset);
-+}
-+
-+static void at91sam9x5_video_write32(struct at91sam9x5_video_priv *priv,
-+ size_t offset, u32 val)
-+{
-+ debug("$%x := %08x, $08 == %08x\n", offset, val,
-+ at91sam9x5_video_read32(priv, REG_HEOCHSR));
-+ __raw_writel(val, priv->regbase + offset);
-+ debug("$08 == %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
-+}
-+
-+static int __at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
-+ struct at91sam9x5_video_bufinfo *bi,
-+ size_t heoaddr_offset, unsigned planeno)
-+{
-+ if (planeno >= 0) {
-+ u32 heoaddr = at91sam9x5_video_read32(priv, heoaddr_offset);
-+ dma_addr_t plane_paddr =
-+ vb2_dma_contig_plane_dma_addr(bi->vb, planeno);
-+
-+ if (heoaddr - plane_paddr <= bi->plane_size[planeno])
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
-+ struct at91sam9x5_video_bufinfo *bi)
-+{
-+ if (__at91sam9x5_video_buf_in_use(priv, bi, REG_HEOADDR, 0))
-+ return 1;
-+ if (__at91sam9x5_video_buf_in_use(priv, bi,
-+ REG_HEOUADDR, bi->u_planeno))
-+ return 1;
-+ if (__at91sam9x5_video_buf_in_use(priv, bi,
-+ REG_HEOVADDR, bi->v_planeno))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+static u32 at91sam9x5_video_handle_irqstat(struct at91sam9x5_video_priv *priv)
-+{
-+ u32 heoisr = at91sam9x5_video_read32(priv, REG_HEOISR);
-+
-+ debug("cur=%p, next=%p, heoisr=%08x\n", priv->cur.vb,
-+ priv->next.vb, heoisr);
-+ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
-+ priv->cfgupdate, priv->hwstate, priv->cfgstate);
-+
-+ if (!priv->cur.vb) {
-+ priv->cur = priv->next;
-+ priv->next.vb = NULL;
-+ }
-+
-+ if (priv->hwstate == at91sam9x5_video_HW_IDLE &&
-+ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
-+ REG_HEOCHSR_CHSR)) {
-+ if (priv->cur.vb) {
-+ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
-+ priv->cur.vb = NULL;
-+ }
-+
-+ if (priv->next.vb) {
-+ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_DONE);
-+ priv->next.vb = NULL;
-+ }
-+
-+ at91sam9x5_video_write32(priv, REG_HEOIDR,
-+ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
-+ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
-+ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
-+
-+ } else if (priv->cur.vb && priv->next.vb) {
-+ int hwrunning = 1;
-+ if (priv->cfgstate == at91sam9x5_video_CFG_BAD &&
-+ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
-+ REG_HEOCHSR_CHSR))
-+ hwrunning = 0;
-+
-+ if (!hwrunning || !at91sam9x5_video_buf_in_use(priv,
-+ &priv->cur)) {
-+ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
-+ priv->cur = priv->next;
-+ priv->next.vb = NULL;
-+ }
-+ } else if (priv->next.vb) {
-+ priv->cur = priv->next;
-+ priv->next.vb = NULL;
-+ }
-+
-+ return heoisr;
-+}
-+
-+static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
-+{
-+ struct at91sam9x5_video_priv *priv = data;
-+ unsigned long flags;
-+ u32 handled, heoimr;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR);
-+ handled = at91sam9x5_video_handle_irqstat(priv);
-+
-+ debug("%x, HEOCHSR = %08x\n", handled,
-+ at91sam9x5_video_read32(priv, REG_HEOCHSR));
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ if (handled & heoimr)
-+ return IRQ_HANDLED;
-+ else
-+ return IRQ_NONE;
-+}
-+
-+static inline int sign(int x)
-+{
-+ if (x > 0)
-+ return 1;
-+ else if (x < 0)
-+ return -1;
-+ else
-+ return 0;
-+}
-+
-+static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
-+ struct vb2_buffer *vb)
-+{
-+ dma_addr_t buffer = vb2_dma_contig_plane_dma_addr(vb, 0);
-+ void *vaddr = vb2_plane_vaddr(vb, 0);
-+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
-+ /* XXX: format dependant */
-+ size_t offset_dmadesc = ALIGN(pix->width * pix->height +
-+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
-+ u32 *dmadesc = vaddr + offset_dmadesc;
-+ u32 heocher;
-+
-+ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) {
-+ heocher = REG_HEOCHER_UPDATEEN;
-+ priv->cfgstate = at91sam9x5_video_CFG_GOOD;
-+ } else {
-+ BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD);
-+ heocher = 0;
-+ }
-+
-+ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
-+
-+ dmadesc[0] = buffer + priv->y_offset;
-+ dmadesc[1] = REG_HEOxCTRL_DFETCH;
-+ dmadesc[2] = buffer + offset_dmadesc;
-+
-+ if (priv->u_planeno >= 0) {
-+ dmadesc[3] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
-+ priv->u_offset;
-+ dmadesc[4] = REG_HEOxCTRL_DFETCH;
-+ dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
-+ }
-+
-+ if (priv->v_planeno >= 0) {
-+ dmadesc[6] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
-+ priv->v_offset;
-+ dmadesc[7] = REG_HEOxCTRL_DFETCH;
-+ dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
-+ }
-+
-+
-+ debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
-+ if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) {
-+
-+ at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]);
-+
-+ if (priv->u_planeno >= 0)
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOUHEAD, dmadesc[5]);
-+
-+ if (priv->v_planeno >= 0)
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOVHEAD, dmadesc[8]);
-+
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
-+
-+ } else {
-+
-+ at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]);
-+ at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]);
-+ at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]);
-+
-+ if (priv->u_planeno >= 0) {
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOUADDR, dmadesc[3]);
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOUCTRL, dmadesc[4]);
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOUNEXT, dmadesc[5]);
-+ }
-+
-+ if (priv->v_planeno >= 0) {
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOVADDR, dmadesc[6]);
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOVCTRL, dmadesc[7]);
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOVNEXT, dmadesc[8]);
-+ }
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCHER,
-+ heocher | REG_HEOCHER_CHEN);
-+
-+ priv->hwstate = at91sam9x5_video_HW_RUNNING;
-+ }
-+
-+ if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) {
-+ if (priv->next.vb) {
-+ /* drop next; XXX: is this an error? */
-+ debug("drop %p\n", priv->next.vb);
-+ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR);
-+ }
-+ } else {
-+ if (priv->cur.vb)
-+ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
-+
-+ priv->cur = priv->next;
-+ }
-+ priv->next.vb = vb;
-+ priv->next.u_planeno = priv->u_planeno;
-+ priv->next.v_planeno = priv->v_planeno;
-+ priv->next.plane_size[0] = priv->plane_size[0];
-+ priv->next.plane_size[1] = priv->plane_size[1];
-+ priv->next.plane_size[2] = priv->plane_size[2];
-+}
-+
-+static int experimental;
-+module_param(experimental, bool, 0644);
-+MODULE_PARM_DESC(experimental, "enable experimental features");
-+
-+static void at91sam9x5_video_params(unsigned width, unsigned height,
-+ int rotation, u32 *xstride, u32 *pstride, u32 *tloffset)
-+{
-+/* offset of pixel at (x, y) in the buffer */
-+#define po(x, y) ((x) + width * (y))
-+
-+ /* offsets of the edges in counter-clockwise order */
-+ const unsigned e[] = {
-+ po(0, 0),
-+ po(0, height - 1),
-+ po(width - 1, height - 1),
-+ po(width - 1, 0),
-+ };
-+
-+ /*
-+ * offsets of the pixels next to the corresponding edges
-+ * If edge[i] goes to the top left corner, edge_neighbour[i] is
-+ * located just below of edge[i].
-+ */
-+ const unsigned en[] = {
-+ po(0, 1),
-+ po(1, height - 1),
-+ po(width - 1, height - 2),
-+ po(width - 2, 0),
-+ };
-+
-+#define ro(r) ((rotation + (r)) % 4)
-+
-+ *xstride = en[ro(0)] - e[ro(3)];
-+ *pstride = e[ro(3)] - en[ro(3)];
-+ *tloffset = e[ro(0)];
-+}
-+
-+static void at91sam9x5_video_update_config_real(
-+ struct at91sam9x5_video_priv *priv)
-+{
-+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
-+ struct v4l2_window *win = &priv->fmt_vid_overlay;
-+ struct v4l2_rect *rect = &win->w;
-+ /* XXX: check for overflow? */
-+ s32 right = rect->left + rect->width, bottom = rect->top + rect->height;
-+
-+ unsigned hwxpos, hwypos, hwxsize, hwysize;
-+ unsigned hwxmem_size, hwymem_size;
-+ s32 hwxstride, hwpstride;
-+ s32 hwuvxstride, hwuvpstride;
-+ s32 rotated_pixwidth, rotated_pixheight;
-+
-+ debug("vout=%ux%u, ovl=(%d,%d)+(%d,%d)\n", pix->width, pix->height,
-+ rect->left, rect->top, rect->width, rect->height);
-+
-+ if (!experimental && priv->rotation) {
-+ dev_info(&priv->video_dev->dev, "disable rotation\n");
-+ priv->rotation = 0;
-+ }
-+
-+ if (rect->left < 0)
-+ hwxpos = 0;
-+ else
-+ hwxpos = rect->left;
-+
-+ if (rect->top < 0)
-+ hwypos = 0;
-+ else
-+ hwypos = rect->top;
-+
-+ if (right > priv->fbinfo->var.xres)
-+ hwxsize = priv->fbinfo->var.xres - hwxpos;
-+ else
-+ hwxsize = right - hwxpos;
-+
-+ if (bottom > priv->fbinfo->var.yres)
-+ hwysize = priv->fbinfo->var.yres - hwypos;
-+ else
-+ hwysize = bottom - hwypos;
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG2,
-+ valtomask(hwxpos, REG_HEOCFG2_XPOS) |
-+ valtomask(hwypos, REG_HEOCFG2_YPOS));
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG3,
-+ valtomask(hwxsize - 1, REG_HEOCFG3_XSIZE) |
-+ valtomask(hwysize - 1, REG_HEOCFG3_YSIZE));
-+
-+ /* XXX:
-+ * - clipping
-+ */
-+ at91sam9x5_video_write32(priv, REG_HEOCFG1,
-+ REG_HEOCFG1_YUVMODE_12YCBCRP |
-+ REG_HEOCFG1_YUVEN);
-+ at91sam9x5_video_write32(priv, REG_HEOCFG12,
-+ REG_HEOCFG12_GAEN |
-+ REG_HEOCFG12_OVR |
-+ REG_HEOCFG12_DMA |
-+ REG_HEOCFG12_REP |
-+ REG_HEOCFG12_GA);
-+
-+#define vx(pos) xedge[(priv->rotation + pos) % 4]
-+#define vy(pos) yedge[(priv->rotation + pos) % 4]
-+
-+ if (priv->rotation & 1) {
-+ rotated_pixwidth = pix->height;
-+ rotated_pixheight = pix->width;
-+ } else {
-+ rotated_pixwidth = pix->width;
-+ rotated_pixheight = pix->height;
-+ }
-+
-+ hwxmem_size = rotated_pixwidth * hwxsize / rect->width;
-+ hwymem_size = rotated_pixheight * hwysize / rect->height;
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG4,
-+ valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) |
-+ valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE));
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG13,
-+ REG_HEOCFG13_SCALEN |
-+ valtomask(1024 * hwxmem_size / hwxsize,
-+ REG_HEOCFG13_XFACTOR) |
-+ valtomask(1024 * hwymem_size / hwysize,
-+ REG_HEOCFG13_YFACTOR));
-+
-+ at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
-+ &hwxstride, &hwpstride, &priv->y_offset);
-+
-+ /* XXX: format-dependant */
-+ at91sam9x5_video_params(DIV_ROUND_UP(pix->width, 2),
-+ DIV_ROUND_UP(pix->height, 2), priv->rotation,
-+ &hwuvxstride, &hwuvpstride, &priv->u_offset);
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG5,
-+ valtomask(hwxstride - 1, REG_HEOCFG5_XSTRIDE));
-+ at91sam9x5_video_write32(priv, REG_HEOCFG6,
-+ valtomask(hwpstride - 1, REG_HEOCFG6_PSTRIDE));
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG7,
-+ valtomask(hwuvxstride - 1, REG_HEOCFG7_UVXSTRIDE));
-+ at91sam9x5_video_write32(priv, REG_HEOCFG8,
-+ valtomask(hwuvpstride - 1, REG_HEOCFG8_UVPSTRIDE));
-+
-+ /* XXX: format dependant */
-+ priv->u_planeno = 0;
-+ priv->v_planeno = 0;
-+ priv->u_offset += pix->width * pix->height;
-+ priv->v_offset = priv->u_offset +
-+ DIV_ROUND_UP(pix->width, 2) * DIV_ROUND_UP(pix->height, 2);
-+
-+ /* XXX: evaluate pix->colorspace */
-+ at91sam9x5_video_write32(priv, REG_HEOCFG14, 0x4c900091);
-+ at91sam9x5_video_write32(priv, REG_HEOCFG15, 0x7a5f5090);
-+ at91sam9x5_video_write32(priv, REG_HEOCFG16, 0x40040890);
-+}
-+
-+static void at91sam9x5_video_update_config(struct at91sam9x5_video_priv *priv,
-+ int overlay_only)
-+{
-+ debug("cfgupdate=%d overlay_only=%d\n", priv->cfgupdate, overlay_only);
-+
-+ at91sam9x5_video_handle_irqstat(priv);
-+
-+ if (priv->cfgupdate || overlay_only) {
-+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
-+ struct v4l2_window *win = &priv->fmt_vid_overlay;
-+ struct v4l2_rect *rect = &win->w;
-+
-+ if (!overlay_only) {
-+ *pix = priv->fmt_vid_out_next;
-+ priv->cfgupdate = 0;
-+ }
-+
-+ /* XXX: handle clipping */
-+ if (rect->width <= 0 || rect->height <= 0 ||
-+ /* vid_out is set */
-+ pix->width <= 0 ||
-+ pix->height <= 0 ||
-+ /* window is partly invisible or too small */
-+ rect->left < 0 ||
-+ rect->top < 0 ||
-+ rect->left >= (int)priv->fbinfo->var.xres - 5 ||
-+ rect->top >= (int)priv->fbinfo->var.yres - 5 ||
-+ rect->left + rect->width >
-+ (int)priv->fbinfo->var.xres ||
-+ rect->top + rect->height >
-+ (int)priv->fbinfo->var.yres) {
-+
-+ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD ||
-+ priv->cfgstate ==
-+ at91sam9x5_video_CFG_GOOD_LATCH)
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOCHDR, REG_HEOCHDR_CHDIS);
-+
-+ priv->cfgstate = at91sam9x5_video_CFG_BAD;
-+ } else {
-+ at91sam9x5_video_update_config_real(priv);
-+
-+ debug("hwstate=%d cfgstate=%d\n",
-+ priv->hwstate, priv->cfgstate);
-+ if (overlay_only && priv->hwstate ==
-+ at91sam9x5_video_HW_RUNNING) {
-+ if (priv->cfgstate ==
-+ at91sam9x5_video_CFG_BAD) {
-+ priv->cfgstate =
-+ at91sam9x5_video_CFG_GOOD_LATCH;
-+ priv->hwstate =
-+ at91sam9x5_video_HW_IDLE;
-+
-+ at91sam9x5_video_show_buf(priv,
-+ priv->cur.vb);
-+ } else
-+ at91sam9x5_video_write32(priv,
-+ REG_HEOCHER,
-+ REG_HEOCHER_UPDATEEN);
-+ } else
-+ priv->cfgstate =
-+ at91sam9x5_video_CFG_GOOD_LATCH;
-+ }
-+
-+ }
-+}
-+
-+static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
-+ const struct v4l2_format *fmt,
-+ unsigned int *num_buffers, unsigned int *num_planes,
-+ unsigned int sizes[], void *alloc_ctxs[])
-+{
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(q, struct at91sam9x5_video_priv, queue);
-+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_next;
-+
-+ debug("vout=%ux%u\n", pix->width, pix->height);
-+
-+ /* XXX */
-+ *num_planes = 1;
-+
-+ /*
-+ * The last 9 (aligned) words are used for the 3 dma descriptors (3
-+ * 32-bit words each). The additional 32 bits are for alignment.
-+ * XXX: is that allowed and done right?
-+ * XXX: format-dependant
-+ */
-+ sizes[0] = pix->width * pix->height +
-+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
-+ 10 * 32;
-+ priv->plane_size[0] = sizes[0];
-+
-+ alloc_ctxs[0] = priv->alloc_ctx;
-+
-+ return 0;
-+}
-+
-+static void at91sam9x5_video_vb_wait_prepare(struct vb2_queue *q)
-+{
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(q, struct at91sam9x5_video_priv, queue);
-+ unsigned long flags;
-+
-+ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
-+ priv->cfgupdate, priv->hwstate, priv->cfgstate);
-+ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ at91sam9x5_video_handle_irqstat(priv);
-+
-+ at91sam9x5_video_write32(priv, REG_HEOIER,
-+ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
-+ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
-+ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static void at91sam9x5_video_vb_wait_finish(struct vb2_queue *q)
-+{
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(q, struct at91sam9x5_video_priv, queue);
-+ unsigned long flags;
-+
-+ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
-+ priv->cfgupdate, priv->hwstate, priv->cfgstate);
-+ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ at91sam9x5_video_write32(priv, REG_HEOIDR,
-+ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
-+ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
-+ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
-+{
-+ struct vb2_queue *q = vb->vb2_queue;
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(q, struct at91sam9x5_video_priv, queue);
-+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ if (priv->cfgupdate)
-+ pix = &priv->fmt_vid_out_next;
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ debug("vout=%ux%u\n", pix->width, pix->height);
-+ debug("buflen=%u\n", vb->v4l2_planes[0].length);
-+
-+ /* XXX: format-dependant */
-+ if (vb->v4l2_planes[0].length < pix->width * pix->height +
-+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
-+ 10 * 32)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static void at91sam9x5_video_vb_buf_queue(struct vb2_buffer *vb)
-+{
-+ struct vb2_queue *q = vb->vb2_queue;
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(q, struct at91sam9x5_video_priv, queue);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ at91sam9x5_video_update_config(priv, 0);
-+
-+ switch (priv->cfgstate) {
-+ case at91sam9x5_video_CFG_GOOD:
-+ case at91sam9x5_video_CFG_GOOD_LATCH:
-+ /* show_buf takes care of the eventual hwstate update */
-+ at91sam9x5_video_show_buf(priv, vb);
-+ break;
-+
-+ case at91sam9x5_video_CFG_BAD:
-+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-+ priv->hwstate = at91sam9x5_video_HW_RUNNING;
-+ break;
-+ }
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+const struct vb2_ops at91sam9x5_video_vb_ops = {
-+ .queue_setup = at91sam9x5_video_vb_queue_setup,
-+
-+ .wait_prepare = at91sam9x5_video_vb_wait_prepare,
-+ .wait_finish = at91sam9x5_video_vb_wait_finish,
-+
-+ .buf_prepare = at91sam9x5_video_vb_buf_prepare,
-+ .buf_queue = at91sam9x5_video_vb_buf_queue,
-+};
-+
-+static int at91sam9x5_video_vidioc_querycap(struct file *filp,
-+ void *fh, struct v4l2_capability *cap)
-+{
-+ strcpy(cap->driver, DRIVER_NAME);
-+ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING |
-+ V4L2_CAP_VIDEO_OVERLAY;
-+
-+ /* XXX */
-+ cap->version = 0;
-+ cap->card[0] = '\0';
-+ cap->bus_info[0] = '\0';
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_g_fmt_vid_out(struct file *filp,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ unsigned long flags;
-+
-+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ return -EINVAL;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ f->fmt.pix = priv->fmt_vid_out_next;
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_s_fmt_vid_out(struct file *filp,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ struct v4l2_pix_format *pix = &f->fmt.pix;
-+ unsigned long flags;
-+
-+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-+ return -EINVAL;
-+
-+ if (pix->pixelformat != V4L2_PIX_FMT_YUV420)
-+ return -EINVAL;
-+
-+ debug("vout=%ux%u\n", pix->width, pix->height);
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ priv->fmt_vid_out_next = *pix;
-+
-+ priv->cfgupdate = 1;
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_g_fmt_vid_overlay(struct file *filp,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ unsigned long flags;
-+
-+ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+ return -EINVAL;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ f->fmt.win = priv->fmt_vid_overlay;
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_s_fmt_vid_overlay(struct file *filp,
-+ void *fh, struct v4l2_format *f)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ struct v4l2_window *win = &f->fmt.win;
-+ unsigned long flags;
-+
-+ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
-+ return -EINVAL;
-+
-+ debug("rect=(%d,%d)+(%d,%d)\n",
-+ win->w.left, win->w.top, win->w.width, win->w.height);
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ priv->fmt_vid_overlay = *win;
-+
-+ at91sam9x5_video_update_config(priv, 1);
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_enum_fmt_vid_out(struct file *filp,
-+ void *fh, struct v4l2_fmtdesc *f)
-+{
-+ /* XXX: support more formats */
-+ if (f->index > 0)
-+ return -EINVAL;
-+
-+ f->pixelformat = V4L2_PIX_FMT_YUV420;
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_vidioc_reqbufs(struct file *filp,
-+ void *fh, struct v4l2_requestbuffers *b)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ struct vb2_queue *q = &priv->queue;
-+
-+ if (b->type != q->type) {
-+ dev_err(&priv->pdev->dev, "invalid buffer type (%d != %d)\n",
-+ b->type, q->type);
-+ return -EINVAL;
-+ }
-+
-+ return vb2_reqbufs(q, b);
-+}
-+
-+static int at91sam9x5_video_vidioc_querybuf(struct file *filp,
-+ void *fh, struct v4l2_buffer *b)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+
-+ return vb2_querybuf(&priv->queue, b);
-+}
-+
-+static int at91sam9x5_video_vidioc_qbuf(struct file *filp,
-+ void *fh, struct v4l2_buffer *b)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+
-+ return vb2_qbuf(&priv->queue, b);
-+}
-+
-+static int at91sam9x5_video_vidioc_dqbuf(struct file *filp,
-+ void *fh, struct v4l2_buffer *b)
-+{
-+ struct video_device *vdev = filp->private_data;
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+
-+ return vb2_dqbuf(&priv->queue, b, filp->f_flags & O_NONBLOCK);
-+}
-+
-+static int at91sam9x5_video_vidioc_streamon(struct file *filp,
-+ void *fh, enum v4l2_buf_type type)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+
-+ return vb2_streamon(&priv->queue, type);
-+}
-+
-+static int at91sam9x5_video_vidioc_streamoff(struct file *filp,
-+ void *fh, enum v4l2_buf_type type)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ /* disable channel */
-+ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHDIS);
-+
-+ at91sam9x5_video_handle_irqstat(priv);
-+
-+ if (priv->cur.vb)
-+ at91sam9x5_video_write32(priv, REG_HEOIER,
-+ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
-+ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
-+ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
-+
-+ priv->hwstate = at91sam9x5_video_HW_IDLE;
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ return vb2_streamoff(&priv->queue, type);
-+}
-+
-+static int at91sam9x5_video_vidioc_queryctrl(struct file *filp, void *fh,
-+ struct v4l2_queryctrl *a)
-+{
-+ int ret;
-+
-+ switch (a->id) {
-+ case V4L2_CID_ROTATE:
-+ ret = v4l2_ctrl_query_fill(a, 0, 270, 90, 0);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int at91sam9x5_video_vidioc_g_ctrl(struct file *filp, void *fh,
-+ struct v4l2_control *a)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ int ret = 0;
-+
-+ switch (a->id) {
-+ case V4L2_CID_ROTATE:
-+ a->value = 90 * priv->rotation;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int at91sam9x5_video_vidioc_s_ctrl(struct file *filp, void *fh,
-+ struct v4l2_control *a)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+ int ret;
-+ unsigned long flags;
-+
-+ switch (a->id) {
-+ case V4L2_CID_ROTATE:
-+ if (a->value / 90 * 90 != a->value ||
-+ (a->value / 90) % 4 != a->value / 90) {
-+ ret = -EINVAL;
-+ } else {
-+ debug("rotation: %d\n", a->value);
-+ spin_lock_irqsave(&priv->lock, flags);
-+ priv->rotation = a->value / 90;
-+ at91sam9x5_video_update_config(priv, 1);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ }
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static const struct v4l2_ioctl_ops at91sam9x5_video_ioctl_ops = {
-+ .vidioc_querycap = at91sam9x5_video_vidioc_querycap,
-+ .vidioc_g_fmt_vid_out = at91sam9x5_video_vidioc_g_fmt_vid_out,
-+ .vidioc_s_fmt_vid_out = at91sam9x5_video_vidioc_s_fmt_vid_out,
-+ .vidioc_g_fmt_vid_overlay = at91sam9x5_video_vidioc_g_fmt_vid_overlay,
-+ .vidioc_s_fmt_vid_overlay = at91sam9x5_video_vidioc_s_fmt_vid_overlay,
-+ .vidioc_enum_fmt_vid_out = at91sam9x5_video_vidioc_enum_fmt_vid_out,
-+ .vidioc_reqbufs = at91sam9x5_video_vidioc_reqbufs,
-+ .vidioc_querybuf = at91sam9x5_video_vidioc_querybuf,
-+ .vidioc_qbuf = at91sam9x5_video_vidioc_qbuf,
-+ .vidioc_dqbuf = at91sam9x5_video_vidioc_dqbuf,
-+ .vidioc_streamon = at91sam9x5_video_vidioc_streamon,
-+ .vidioc_streamoff = at91sam9x5_video_vidioc_streamoff,
-+ .vidioc_queryctrl = at91sam9x5_video_vidioc_queryctrl,
-+ .vidioc_g_ctrl = at91sam9x5_video_vidioc_g_ctrl,
-+ .vidioc_s_ctrl = at91sam9x5_video_vidioc_s_ctrl,
-+};
-+
-+static int at91sam9x5_video_open(struct file *filp)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+
-+ /*
-+ * XXX: allow only one open? Or is that already enforced by the
-+ * framework?
-+ */
-+ filp->private_data = vdev;
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_release(struct file *filp)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+
-+ dev_dbg(&vdev->dev, "%s\n", __func__);
-+
-+ return 0;
-+}
-+
-+static int at91sam9x5_video_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+ struct video_device *vdev = video_devdata(filp);
-+ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
-+
-+ dev_dbg(&vdev->dev, "%s\n", __func__);
-+
-+ /* returning -EIO here makes gst-launch segfault */
-+ return vb2_mmap(&priv->queue, vma);
-+}
-+
-+static struct v4l2_file_operations at91sam9x5_video_fops = {
-+ .owner = THIS_MODULE,
-+ .open = at91sam9x5_video_open,
-+ .release = at91sam9x5_video_release,
-+ .ioctl = video_ioctl2,
-+ .mmap = at91sam9x5_video_mmap,
-+};
-+
-+static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
-+ struct fb_info *fbinfo)
-+{
-+ int ret = -ENOMEM;
-+ struct platform_device *pdev = priv->pdev;
-+ struct resource *res;
-+ const struct at91sam9x5_video_pdata *pdata =
-+ dev_get_platdata(&pdev->dev);
-+ struct vb2_queue *q = &priv->queue;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ if (priv->fbinfo) {
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ return -EBUSY;
-+ }
-+ priv->fbinfo = fbinfo;
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ /* XXX: this doesn't belong here, does it? */
-+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-+
-+ if (!pdata) {
-+ dev_err(&pdev->dev, "failed to get platform data\n");
-+ goto err_get_pdata;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ dev_err(&pdev->dev, "failed to get register base\n");
-+ goto err_get_regbase;
-+ }
-+
-+ priv->regbase = ioremap(res->start, resource_size(res));
-+ if (!priv->regbase) {
-+ dev_err(&pdev->dev, "failed to remap register base\n");
-+ goto err_ioremap;
-+ }
-+
-+ /*
-+ * XXX: video_device_alloc is just a kzalloc, so embedding struct
-+ * video_device into struct at91sam9x5_video_priv would work, too.
-+ * Is that allowed?
-+ */
-+ priv->video_dev = video_device_alloc();
-+ if (!priv->video_dev) {
-+ dev_err(&pdev->dev, "failed to alloc video device for %p\n",
-+ fbinfo);
-+ goto err_video_device_alloc;
-+ }
-+
-+ priv->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
-+ if (IS_ERR(priv->alloc_ctx)) {
-+ ret = PTR_ERR(priv->alloc_ctx);
-+ dev_err(&pdev->dev, "failed to init alloc_ctx (%d)\n", ret);
-+ goto err_init_ctx;
-+ }
-+
-+ q->ops = &at91sam9x5_video_vb_ops;
-+ q->mem_ops = &vb2_dma_contig_memops;
-+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
-+
-+ ret = vb2_queue_init(q);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to init queue (%d)\n", ret);
-+ goto err_queue_init;
-+ }
-+
-+ priv->video_dev->fops = &at91sam9x5_video_fops;
-+ priv->video_dev->ioctl_ops = &at91sam9x5_video_ioctl_ops;
-+ priv->video_dev->release = video_device_release;
-+
-+ video_set_drvdata(priv->video_dev, priv);
-+
-+ /* reset channel and clear status */
-+ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHRST);
-+ (void)at91sam9x5_video_read32(priv, REG_HEOISR);
-+
-+ /* set maximal bursting */
-+ at91sam9x5_video_write32(priv, REG_HEOCFG0,
-+ REG_HEOCFG0_BLEN_INCR16 |
-+ REG_HEOCFG0_BLENUV_INCR16);
-+
-+ ret = platform_get_irq(pdev, 0);
-+ if (ret <= 0) {
-+ dev_err(&pdev->dev, "failed to get irq from resources (%d)\n",
-+ ret);
-+ if (!ret)
-+ ret = -ENXIO;
-+ goto err_get_irq;
-+ }
-+ priv->irq = ret;
-+
-+ ret = request_irq(priv->irq, at91sam9x5_video_irq, IRQF_SHARED,
-+ DRIVER_NAME, priv);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
-+ goto err_request_irq;
-+ }
-+
-+ ret = video_register_device(priv->video_dev,
-+ /* XXX: really grabber? */ VFL_TYPE_GRABBER, -1);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register video device (%d)\n",
-+ ret);
-+
-+ free_irq(priv->irq, priv);
-+ err_request_irq:
-+ err_get_irq:
-+
-+ vb2_queue_release(q);
-+err_queue_init:
-+
-+ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
-+ err_init_ctx:
-+
-+ video_device_release(priv->video_dev);
-+ err_video_device_alloc:
-+
-+ iounmap(priv->regbase);
-+
-+ priv->fbinfo = NULL;
-+ }
-+ err_ioremap:
-+ err_get_regbase:
-+ err_get_pdata:
-+
-+ return ret;
-+}
-+
-+static void at91sam9x5_video_unregister(struct at91sam9x5_video_priv *priv)
-+{
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+
-+ if (!priv->fbinfo) {
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+ return;
-+ }
-+ /* XXX: handle fbinfo being NULL in various callbacks */
-+ priv->fbinfo = NULL;
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ /* silence DMA */
-+ at91sam9x5_video_write32(priv, REG_HEOIDR,
-+ REG_HEOIxR_ADD | REG_HEOIxR_DMA | REG_HEOIxR_UADD |
-+ REG_HEOIxR_UDMA | REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
-+
-+ video_unregister_device(priv->video_dev);
-+ free_irq(priv->irq, priv);
-+ vb2_queue_release(&priv->queue);
-+ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
-+ video_device_release(priv->video_dev);
-+ iounmap(priv->regbase);
-+}
-+
-+static int at91sam9x5_video_fb_event_notify(struct notifier_block *self,
-+ unsigned long action, void *data)
-+{
-+ struct at91sam9x5_video_priv *priv =
-+ container_of(self, struct at91sam9x5_video_priv, fb_notifier);
-+ struct fb_event *event = data;
-+ struct fb_info *fbinfo = event->info;
-+
-+ /* XXX: only do this for atmel_lcdfb devices! */
-+ switch (action) {
-+ case FB_EVENT_FB_REGISTERED:
-+ at91sam9x5_video_register(priv, fbinfo);
-+ break;
-+
-+ case FB_EVENT_FB_UNREGISTERED:
-+ at91sam9x5_video_unregister(priv);
-+ break;
-+ }
-+ return 0;
-+}
-+
-+static int __devinit at91sam9x5_video_probe(struct platform_device *pdev)
-+{
-+ int ret = -ENOMEM;
-+ size_t i;
-+ struct at91sam9x5_video_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-+
-+ if (!priv) {
-+ dev_err(&pdev->dev, "failed to allocate driver private data\n");
-+ goto err_alloc_priv;
-+ }
-+
-+ priv->pdev = pdev;
-+ priv->fb_notifier.notifier_call = at91sam9x5_video_fb_event_notify;
-+
-+ platform_set_drvdata(pdev, priv);
-+
-+ spin_lock_init(&priv->lock);
-+
-+ ret = fb_register_client(&priv->fb_notifier);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to register fb client (%d)\n", ret);
-+
-+ kfree(priv);
-+err_alloc_priv:
-+
-+ return ret;
-+ }
-+
-+ /* XXX: This is racy. If a new fb is registered then
-+ * at91sam9x5_video_register is called twice. This should be solved
-+ * somewhere in drivers/fb. priv->fbinfo is used to prevent multiple
-+ * registration.
-+ */
-+
-+ for (i = 0; i < ARRAY_SIZE(registered_fb); ++i)
-+ if (registered_fb[i])
-+ at91sam9x5_video_register(priv, registered_fb[i]);
-+
-+ return 0;
-+}
-+
-+int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
-+{
-+ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
-+
-+ fb_unregister_client(&priv->fb_notifier);
-+ at91sam9x5_video_unregister(priv);
-+ kfree(priv);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver at91sam9x5_video_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = at91sam9x5_video_probe,
-+ .remove = at91sam9x5_video_remove,
-+};
-+
-+static struct platform_device *at91sam9x5_video_device;
-+static int __init at91sam9x5_video_init(void)
-+{
-+ /* XXX: register the device in arch/arm/mach-at91 */
-+ int ret;
-+ const struct resource res[] = {
-+ {
-+ .start = 0xf8038280,
-+ .end = 0xf803833f,
-+ .flags = IORESOURCE_MEM,
-+ }, {
-+ .start = 25,
-+ .end = 25,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+ };
-+ const struct at91sam9x5_video_pdata pdata = {
-+ .base_width = 800,
-+ .base_height = 480,
-+ };
-+
-+ ret = platform_driver_register(&at91sam9x5_video_driver);
-+ if (ret) {
-+ pr_err("failed to register driver (%d)", ret);
-+ goto err_driver_register;
-+ }
-+
-+ at91sam9x5_video_device = platform_device_register_resndata(NULL,
-+ DRIVER_NAME, -1,
-+ res, ARRAY_SIZE(res), &pdata, sizeof(pdata));
-+ if (IS_ERR(at91sam9x5_video_device)) {
-+ ret = PTR_ERR(at91sam9x5_video_device);
-+ pr_err("failed to register device (%d)", ret);
-+ platform_driver_unregister(&at91sam9x5_video_driver);
-+ }
-+
-+ err_driver_register:
-+ return ret;
-+}
-+module_init(at91sam9x5_video_init);
-+
-+static void __exit at91sam9x5_video_exit(void)
-+{
-+ platform_device_unregister(at91sam9x5_video_device);
-+ platform_driver_unregister(&at91sam9x5_video_driver);
-+}
-+module_exit(at91sam9x5_video_exit);
-+
-+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
-+MODULE_LICENSE("GPL v2");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 53e09e8e36a22c3d0b7b0001f6c57ee9e750ee29 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 1 Nov 2010 16:38:41 +0800
+Subject: video/atmel_lcdfb: add support for AT91SAM9x5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Dan Liang <dan.liang@atmel.com>
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+[ukleinek: forward-port to 2.6.39-rcish]
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+Conflicts:
+
+ drivers/video/atmel_lcdfb.c
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdfb.h | 865 +++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb.c | 668 ++++++++++++++-----
+ include/video/atmel_lcdc.h | 15 +
+ 3 files changed, 1389 insertions(+), 159 deletions(-)
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+new file mode 100644
+index 0000000..a57b79b
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+@@ -0,0 +1,865 @@
++/*
++ * Header file for AT91 High end LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2010 Atmel Corporation
++ *
++ * 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.
++ *
++ * This program 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 PUROFFSETE. See the
++ * GNU General Public License for more details.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef __ATMEL_HLCD_H__
++#define __ATMEL_HLCD_H__
++
++/* Lcdc hardware registers */
++#define ATMEL_LCDC_LCDCFG0 0x0000
++#define LCDC_LCDCFG0_CLKPOL (0x1 << 0)
++#define LCDC_LCDCFG0_CLKSEL (0x1 << 2)
++#define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
++#define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
++#define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
++#define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
++#define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
++#define LCDC_LCDCFG0_CLKDIV_OFFSET 16
++#define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG1 0x0004
++#define LCDC_LCDCFG1_HSPW_OFFSET 0
++#define LCDC_LCDCFG1_HSPW (0x3f << LCDC_LCDCFG1_HSPW_OFFSET)
++#define LCDC_LCDCFG1_VSPW_OFFSET 16
++#define LCDC_LCDCFG1_VSPW (0x3f << LCDC_LCDCFG1_VSPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG2 0x0008
++#define LCDC_LCDCFG2_VFPW_OFFSET 0
++#define LCDC_LCDCFG2_VFPW (0x3f << LCDC_LCDCFG2_VFPW_OFFSET)
++#define LCDC_LCDCFG2_VBPW_OFFSET 16
++#define LCDC_LCDCFG2_VBPW (0x3f << LCDC_LCDCFG2_VBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG3 0x000C
++#define LCDC_LCDCFG3_HFPW_OFFSET 0
++#define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
++#define LCDC_LCDCFG3_HBPW_OFFSET 16
++#define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG4 0x0010
++#define LCDC_LCDCFG4_PPL_OFFSET 0
++#define LCDC_LCDCFG4_PPL (0x7ff << LCDC_LCDCFG4_PPL_OFFSET)
++#define LCDC_LCDCFG4_RPF_OFFSET 16
++#define LCDC_LCDCFG4_RPF (0x7ff << LCDC_LCDCFG4_RPF_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG5 0x0014
++#define LCDC_LCDCFG5_HSPOL (0x1 << 0)
++#define LCDC_LCDCFG5_VSPOL (0x1 << 1)
++#define LCDC_LCDCFG5_VSPDLYS (0x1 << 2)
++#define LCDC_LCDCFG5_VSPDLYE (0x1 << 3)
++#define LCDC_LCDCFG5_DISPPOL (0x1 << 4)
++#define LCDC_LCDCFG5_SERIAL (0x1 << 5)
++#define LCDC_LCDCFG5_DITHER (0x1 << 6)
++#define LCDC_LCDCFG5_DISPDLY (0x1 << 7)
++#define LCDC_LCDCFG5_MODE_OFFSET 8
++#define LCDC_LCDCFG5_MODE (0x3 << LCDC_LCDCFG5_MODE_OFFSET)
++#define LCDC_LCDCFG5_MODE_OUTPUT_12BPP (0x0 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
++#define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
++#define LCDC_LCDCFG5_VSPSU (0x1 << 12)
++#define LCDC_LCDCFG5_VSPHO (0x1 << 13)
++#define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
++#define LCDC_LCDCFG5_GUARDTIME (0x1f << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++
++#define ATMEL_LCDC_LCDCFG6 0x0018
++#define LCDC_LCDCFG6_PWMPS_OFFSET 0
++#define LCDC_LCDCFG6_PWMPS (0x7 << LCDC_LCDCFG6_PWMPS_OFFSET)
++#define LCDC_LCDCFG6_PWMPOL (0x1 << 4)
++#define LCDC_LCDCFG6_PWMCVAL_OFFSET 8
++#define LCDC_LCDCFG6_PWMCVAL (0xff << LCDC_LCDCFG6_PWMCVAL_OFFSET)
++
++#define ATMEL_LCDC_LCDEN 0x0020
++#define LCDC_LCDEN_CLKEN (0x1 << 0)
++#define LCDC_LCDEN_SYNCEN (0x1 << 1)
++#define LCDC_LCDEN_DISPEN (0x1 << 2)
++#define LCDC_LCDEN_PWMEN (0x1 << 3)
++
++#define ATMEL_LCDC_LCDDIS 0x0024
++#define LCDC_LCDDIS_CLKDIS (0x1 << 0)
++#define LCDC_LCDDIS_SYNCDIS (0x1 << 1)
++#define LCDC_LCDDIS_DISPDIS (0x1 << 2)
++#define LCDC_LCDDIS_PWMDIS (0x1 << 3)
++#define LCDC_LCDDIS_CLKRST (0x1 << 8)
++#define LCDC_LCDDIS_SYNCRST (0x1 << 9)
++#define LCDC_LCDDIS_DISPRST (0x1 << 10)
++#define LCDC_LCDDIS_PWMRST (0x1 << 11)
++
++#define ATMEL_LCDC_LCDSR 0x0028
++#define LCDC_LCDSR_CLKSTS (0x1 << 0)
++#define LCDC_LCDSR_LCDSTS (0x1 << 1)
++#define LCDC_LCDSR_DISPSTS (0x1 << 2)
++#define LCDC_LCDSR_PWMSTS (0x1 << 3)
++#define LCDC_LCDSR_SIPSTS (0x1 << 4)
++
++#define ATMEL_LCDC_LCDIER 0x002C
++#define LCDC_LCDIER_SOFIE (0x1 << 0)
++#define LCDC_LCDIER_DISIE (0x1 << 1)
++#define LCDC_LCDIER_DISPIE (0x1 << 2)
++#define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
++#define LCDC_LCDIER_BASEIE (0x1 << 8)
++#define LCDC_LCDIER_OVR1IE (0x1 << 9)
++#define LCDC_LCDIER_HEOIE (0x1 << 11)
++#define LCDC_LCDIER_HCRIE (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIDR 0x0030
++#define LCDC_LCDIDR_SOFID (0x1 << 0)
++#define LCDC_LCDIDR_DISID (0x1 << 1)
++#define LCDC_LCDIDR_DISPID (0x1 << 2)
++#define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
++#define LCDC_LCDIDR_BASEID (0x1 << 8)
++#define LCDC_LCDIDR_OVR1ID (0x1 << 9)
++#define LCDC_LCDIDR_HEOID (0x1 << 11)
++#define LCDC_LCDIDR_HCRID (0x1 << 12)
++
++#define ATMEL_LCDC_LCDIMR 0x0034
++#define LCDC_LCDIMR_SOFIM (0x1 << 0)
++#define LCDC_LCDIMR_DISIM (0x1 << 1)
++#define LCDC_LCDIMR_DISPIM (0x1 << 2)
++#define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
++#define LCDC_LCDIMR_BASEIM (0x1 << 8)
++#define LCDC_LCDIMR_OVR1IM (0x1 << 9)
++#define LCDC_LCDIMR_HEOIM (0x1 << 11)
++#define LCDC_LCDIMR_HCRIM (0x1 << 12)
++
++#define ATMEL_LCDC_LCDISR 0x0038
++#define LCDC_LCDISR_SOF (0x1 << 0)
++#define LCDC_LCDISR_DIS (0x1 << 1)
++#define LCDC_LCDISR_DISP (0x1 << 2)
++#define LCDC_LCDISR_FIFOERR (0x1 << 4)
++#define LCDC_LCDISR_BASE (0x1 << 8)
++#define LCDC_LCDISR_OVR1 (0x1 << 9)
++#define LCDC_LCDISR_HEO (0x1 << 11)
++#define LCDC_LCDISR_HCR (0x1 << 12)
++
++#define ATMEL_LCDC_BASECHER 0x0040
++#define LCDC_BASECHER_CHEN (0x1 << 0)
++#define LCDC_BASECHER_UPDATEEN (0x1 << 1)
++#define LCDC_BASECHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_BASECHDR 0x0044
++#define LCDC_BASECHDR_CHDIS (0x1 << 0)
++#define LCDC_BASECHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_BASECHSR 0x0048
++#define LCDC_BASECHSR_CHSR (0x1 << 0)
++#define LCDC_BASECHSR_UPDATESR (0x1 << 1)
++#define LCDC_BASECHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_BASEIER 0x004C
++#define LCDC_BASEIER_DMA (0x1 << 2)
++#define LCDC_BASEIER_DSCR (0x1 << 3)
++#define LCDC_BASEIER_ADD (0x1 << 4)
++#define LCDC_BASEIER_DONE (0x1 << 5)
++#define LCDC_BASEIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIDR 0x0050
++#define LCDC_BASEIDR_DMA (0x1 << 2)
++#define LCDC_BASEIDR_DSCR (0x1 << 3)
++#define LCDC_BASEIDR_ADD (0x1 << 4)
++#define LCDC_BASEIDR_DONE (0x1 << 5)
++#define LCDC_BASEIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEIMR 0x0054
++#define LCDC_BASEIMR_DMA (0x1 << 2)
++#define LCDC_BASEIMR_DSCR (0x1 << 3)
++#define LCDC_BASEIMR_ADD (0x1 << 4)
++#define LCDC_BASEIMR_DONE (0x1 << 5)
++#define LCDC_BASEIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEISR 0x0058
++#define LCDC_BASEISR_DMA (0x1 << 2)
++#define LCDC_BASEISR_DSCR (0x1 << 3)
++#define LCDC_BASEISR_ADD (0x1 << 4)
++#define LCDC_BASEISR_DONE (0x1 << 5)
++#define LCDC_BASEISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_BASEHEAD 0x005C
++
++#define ATMEL_LCDC_BASEADDR 0x0060
++
++#define ATMEL_LCDC_BASECTRL 0x0064
++#define LCDC_BASECTRL_DFETCH (0x1 << 0)
++#define LCDC_BASECTRL_LFETCH (0x1 << 1)
++#define LCDC_BASECTRL_DMAIEN (0x1 << 2)
++#define LCDC_BASECTRL_DSCRIEN (0x1 << 3)
++#define LCDC_BASECTRL_ADDIEN (0x1 << 4)
++#define LCDC_BASECTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_BASENEXT 0x0068
++
++#define ATMEL_LCDC_BASECFG0 0x006C
++#define LCDC_BASECFG0_BLEN_OFFSET 4
++#define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
++#define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_BASECFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_BASECFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_BASECFG1 0x0070
++#define LCDC_BASECFG1_CLUTEN (0x1 << 0)
++#define LCDC_BASECFG1_RGBMODE_OFFSET 4
++#define LCDC_BASECFG1_RGBMODE (0xf << LCDC_BASECFG1_RGBMODE_OFFSET)
++#define LCDC_BASECFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_BASECFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_BASECFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_BASECFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_BASECFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_BASECFG1_CLUTMODE_OFFSET 8
++#define LCDC_BASECFG1_CLUTMODE (0x3 << LCDC_BASECFG1_CLUTMODE_OFFSET)
++#define LCDC_BASECFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_BASECFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_BASECFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_BASECFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_BASECFG2 0x0074
++
++#define ATMEL_LCDC_BASECFG3 0x0078
++#define LCDC_BASECFG3_BDEF_OFFSET 0
++#define LCDC_BASECFG3_BDEF (0xff << LCDC_BASECFG3_BDEF_OFFSET)
++#define LCDC_BASECFG3_GDEF_OFFSET 8
++#define LCDC_BASECFG3_GDEF (0xff << LCDC_BASECFG3_GDEF_OFFSET)
++#define LCDC_BASECFG3_RDEF_OFFSET 16
++#define LCDC_BASECFG3_RDEF (0xff << LCDC_BASECFG3_RDEF_OFFSET)
++
++#define ATMEL_LCDC_BASECFG4 0x007C
++#define LCDC_BASECFG4_DMA (0x1 << 8)
++#define LCDC_BASECFG4_REP (0x1 << 9)
++
++#define ATMEL_LCDC_OVRCHER1 0x0100
++#define LCDC_OVRCHER1_CHEN (0x1 << 0)
++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
++#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_OVRCHDR1 0x0104
++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
++#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_OVRCHSR1 0x0108
++#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_OVRIER1 0x010C
++#define LCDC_OVRIER1_DMA (0x1 << 2)
++#define LCDC_OVRIER1_DSCR (0x1 << 3)
++#define LCDC_OVRIER1_ADD (0x1 << 4)
++#define LCDC_OVRIER1_DONE (0x1 << 5)
++#define LCDC_OVRIER1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIDR1 0x0110
++#define LCDC_OVRIDR1_DMA (0x1 << 2)
++#define LCDC_OVRIDR1_DSCR (0x1 << 3)
++#define LCDC_OVRIDR1_ADD (0x1 << 4)
++#define LCDC_OVRIDR1_DONE (0x1 << 5)
++#define LCDC_OVRIDR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIMR1 0x0114
++#define LCDC_OVRIMR1_DMA (0x1 << 2)
++#define LCDC_OVRIMR1_DSCR (0x1 << 3)
++#define LCDC_OVRIMR1_ADD (0x1 << 4)
++#define LCDC_OVRIMR1_DONE (0x1 << 5)
++#define LCDC_OVRIMR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRISR1 0x0118
++#define LCDC_OVRISR1_DMA (0x1 << 2)
++#define LCDC_OVRISR1_DSCR (0x1 << 3)
++#define LCDC_OVRISR1_ADD (0x1 << 4)
++#define LCDC_OVRISR1_DONE (0x1 << 5)
++#define LCDC_OVRISR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRHEAD1 0x011C
++
++#define ATMEL_LCDC_OVRADDR1 0x0120
++
++#define ATMEL_LCDC_OVRCTRL1 0x0124
++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_OVRNEXT1 0x0128
++
++#define ATMEL_LCDC_OVR1CFG0 0x012C
++#define LCDC_OVR1CFG0_BLEN_OFFSET 4
++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_OVR1CFG1 0x0130
++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_OVR1CFG2 0x0134
++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG3 0x0138
++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG4 0x013C
++
++#define ATMEL_LCDC_OVR1CFG5 0x0140
++
++#define ATMEL_LCDC_OVR1CFG6 0x0144
++#define LCDC_OVR1CFG6_BDEF_OFFSET 0
++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
++#define LCDC_OVR1CFG6_GDEF_OFFSET 8
++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
++#define LCDC_OVR1CFG6_RDEF_OFFSET 16
++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG7 0x0148
++#define LCDC_OVR1CFG7_BKEY_OFFSET 0
++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
++#define LCDC_OVR1CFG7_GKEY_OFFSET 8
++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
++#define LCDC_OVR1CFG7_RKEY_OFFSET 16
++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG8 0x014C
++#define LCDC_OVR1CFG8_BMASK_OFFSET 0
++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
++#define LCDC_OVR1CFG8_GMASK_OFFSET 8
++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
++#define LCDC_OVR1CFG8_RMASK_OFFSET 16
++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG9 0x0150
++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
++#define LCDC_OVR1CFG9_INV (0x1 << 1)
++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
++#define LCDC_OVR1CFG9_ITER (0x1 << 3)
++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
++#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
++#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
++#define LCDC_OVR1CFG9_OVR (0x1 << 7)
++#define LCDC_OVR1CFG9_DMA (0x1 << 8)
++#define LCDC_OVR1CFG9_REP (0x1 << 9)
++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
++#define LCDC_OVR1CFG9_GA_OFFSET 16
++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
++
++#define ATMEL_LCDC_HEOCHER 0x0280
++#define LCDC_HEOCHER_CHEN (0x1 << 0)
++#define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HEOCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HEOCHDR 0x0284
++#define LCDC_HEOCHDR_CHDIS (0x1 << 0)
++#define LCDC_HEOCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HEOCHSR 0x0288
++#define LCDC_HEOCHSR_CHSR (0x1 << 0)
++#define LCDC_HEOCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HEOCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HEOIER 0x028C
++#define LCDC_HEOIER_DMA (0x1 << 2)
++#define LCDC_HEOIER_DSCR (0x1 << 3)
++#define LCDC_HEOIER_ADD (0x1 << 4)
++#define LCDC_HEOIER_DONE (0x1 << 5)
++#define LCDC_HEOIER_OVR (0x1 << 6)
++#define LCDC_HEOIER_UDMA (0x1 << 10)
++#define LCDC_HEOIER_UDSCR (0x1 << 11)
++#define LCDC_HEOIER_UADD (0x1 << 12)
++#define LCDC_HEOIER_UDONE (0x1 << 13)
++#define LCDC_HEOIER_UOVR (0x1 << 14)
++#define LCDC_HEOIER_VDMA (0x1 << 18)
++#define LCDC_HEOIER_VDSCR (0x1 << 19)
++#define LCDC_HEOIER_VADD (0x1 << 20)
++#define LCDC_HEOIER_VDONE (0x1 << 21)
++#define LCDC_HEOIER_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIDR 0x0290
++#define LCDC_HEOIDR_DMA (0x1 << 2)
++#define LCDC_HEOIDR_DSCR (0x1 << 3)
++#define LCDC_HEOIDR_ADD (0x1 << 4)
++#define LCDC_HEOIDR_DONE (0x1 << 5)
++#define LCDC_HEOIDR_OVR (0x1 << 6)
++#define LCDC_HEOIDR_UDMA (0x1 << 10)
++#define LCDC_HEOIDR_UDSCR (0x1 << 11)
++#define LCDC_HEOIDR_UADD (0x1 << 12)
++#define LCDC_HEOIDR_UDONE (0x1 << 13)
++#define LCDC_HEOIDR_UOVR (0x1 << 14)
++#define LCDC_HEOIDR_VDMA (0x1 << 18)
++#define LCDC_HEOIDR_VDSCR (0x1 << 19)
++#define LCDC_HEOIDR_VADD (0x1 << 20)
++#define LCDC_HEOIDR_VDONE (0x1 << 21)
++#define LCDC_HEOIDR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOIMR 0x0294
++#define LCDC_HEOIMR_DMA (0x1 << 2)
++#define LCDC_HEOIMR_DSCR (0x1 << 3)
++#define LCDC_HEOIMR_ADD (0x1 << 4)
++#define LCDC_HEOIMR_DONE (0x1 << 5)
++#define LCDC_HEOIMR_OVR (0x1 << 6)
++#define LCDC_HEOIMR_UDMA (0x1 << 10)
++#define LCDC_HEOIMR_UDSCR (0x1 << 11)
++#define LCDC_HEOIMR_UADD (0x1 << 12)
++#define LCDC_HEOIMR_UDONE (0x1 << 13)
++#define LCDC_HEOIMR_UOVR (0x1 << 14)
++#define LCDC_HEOIMR_VDMA (0x1 << 18)
++#define LCDC_HEOIMR_VDSCR (0x1 << 19)
++#define LCDC_HEOIMR_VADD (0x1 << 20)
++#define LCDC_HEOIMR_VDONE (0x1 << 21)
++#define LCDC_HEOIMR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOISR 0x0298
++#define LCDC_HEOISR_DMA (0x1 << 2)
++#define LCDC_HEOISR_DSCR (0x1 << 3)
++#define LCDC_HEOISR_ADD (0x1 << 4)
++#define LCDC_HEOISR_DONE (0x1 << 5)
++#define LCDC_HEOISR_OVR (0x1 << 6)
++#define LCDC_HEOISR_UDMA (0x1 << 10)
++#define LCDC_HEOISR_UDSCR (0x1 << 11)
++#define LCDC_HEOISR_UADD (0x1 << 12)
++#define LCDC_HEOISR_UDONE (0x1 << 13)
++#define LCDC_HEOISR_UOVR (0x1 << 14)
++#define LCDC_HEOISR_VDMA (0x1 << 18)
++#define LCDC_HEOISR_VDSCR (0x1 << 19)
++#define LCDC_HEOISR_VADD (0x1 << 20)
++#define LCDC_HEOISR_VDONE (0x1 << 21)
++#define LCDC_HEOISR_VOVR (0x1 << 22)
++
++#define ATMEL_LCDC_HEOHEAD 0x029C
++
++#define ATMEL_LCDC_HEOADDR 0x02A0
++
++#define ATMEL_LCDC_HEOCTRL 0x02A4
++#define LCDC_HEOCTRL_DFETCH (0x1 << 0)
++#define LCDC_HEOCTRL_LFETCH (0x1 << 1)
++#define LCDC_HEOCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HEOCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HEOCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HEOCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEONEXT 0x02A8
++
++#define ATMEL_LCDC_HEOUHEAD 0x02AC
++
++#define ATMEL_LCDC_HEOUADDR 0x02B0
++
++#define ATMEL_LCDC_HEOUCTRL 0x02B4
++#define LCDC_HEOUCTRL_UDFETCH (0x1 << 0)
++#define LCDC_HEOUCTRL_UDMAIEN (0x1 << 2)
++#define LCDC_HEOUCTRL_UDSCRIEN (0x1 << 3)
++#define LCDC_HEOUCTRL_UADDIEN (0x1 << 4)
++#define LCDC_HEOUCTRL_UDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOUNEXT 0x02B8
++
++#define ATMEL_LCDC_HEOVHEAD 0x02BC
++
++#define ATMEL_LCDC_HEOVADDR 0x02C0
++
++#define ATMEL_LCDC_HEOVCTRL 0x02C4
++#define LCDC_HEOVCTRL_VDFETCH (0x1 << 0)
++#define LCDC_HEOVCTRL_VDMAIEN (0x1 << 2)
++#define LCDC_HEOVCTRL_VDSCRIEN (0x1 << 3)
++#define LCDC_HEOVCTRL_VADDIEN (0x1 << 4)
++#define LCDC_HEOVCTRL_VDONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HEOVNEXT 0x02C8
++
++#define ATMEL_LCDC_HEOCFG0 0x02CC
++#define LCDC_HEOCFG0_BLEN_OFFSET 4
++#define LCDC_HEOCFG0_BLEN (0x3 << LCDC_HEOCFG0_BLEN_OFFSET)
++#define LCDC_HEOCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HEOCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HEOCFG0_BLENUV_OFFSET 6
++#define LCDC_HEOCFG0_BLENUV (0x3 << LCDC_HEOCFG0_BLENUV_OFFSET)
++#define LCDC_HEOCFG0_BLENUV_AHB_SINGLE (0x0 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR4 (0x1 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR8 (0x2 << 6)
++#define LCDC_HEOCFG0_BLENUV_AHB_INCR16 (0x3 << 6)
++#define LCDC_HEOCFG0_DLBO (0x1 << 8)
++#define LCDC_HEOCFG0_ROTDIS (0x1 << 12)
++#define LCDC_HEOCFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_HEOCFG1 0x02D0
++#define LCDC_HEOCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HEOCFG1_YUVEN (0x1 << 1)
++#define LCDC_HEOCFG1_RGBMODE_OFFSET 4
++#define LCDC_HEOCFG1_RGBMODE (0xf << LCDC_HEOCFG1_RGBMODE_OFFSET)
++#define LCDC_HEOCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HEOCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HEOCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HEOCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HEOCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HEOCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HEOCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HEOCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HEOCFG1_CLUTMODE (0x3 << LCDC_HEOCFG1_CLUTMODE_OFFSET)
++#define LCDC_HEOCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HEOCFG1_CLUTMODE_8BPP (0x3 << 8)
++#define LCDC_HEOCFG1_YUVMODE_OFFSET 12
++#define LCDC_HEOCFG1_YUVMODE (0xf << LCDC_HEOCFG1_YUVMODE_OFFSET)
++#define LCDC_HEOCFG1_YUVMODE_32BPP_AYCBCR (0x0 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE0 (0x1 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE1 (0x2 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE2 (0x3 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_MODE3 (0x4 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_SEMIPLANAR (0x5 << 12)
++#define LCDC_HEOCFG1_YUVMODE_16BPP_YCBCR_PLANAR (0x6 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_SEMIPLANAR (0x7 << 12)
++#define LCDC_HEOCFG1_YUVMODE_12BPP_YCBCR_PLANAR (0x8 << 12)
++#define LCDC_HEOCFG1_YUV422ROT (0x1 << 16)
++#define LCDC_HEOCFG1_YUV422SWP (0x1 << 17)
++
++#define ATMEL_LCDC_HEOCFG2 0x02D4
++#define LCDC_HEOCFG2_XOFFSET_OFFSET 0
++#define LCDC_HEOCFG2_XOFFSET (0x7ff << LCDC_HEOCFG2_XOFFSET_OFFSET)
++#define LCDC_HEOCFG2_YOFFSET_OFFSET 16
++#define LCDC_HEOCFG2_YOFFSET (0x7ff << LCDC_HEOCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG3 0x02D8
++#define LCDC_HEOCFG3_XSIZE_OFFSET 0
++#define LCDC_HEOCFG3_XSIZE (0x7ff << LCDC_HEOCFG3_XSIZE_OFFSET)
++#define LCDC_HEOCFG3_YSIZE_OFFSET 16
++#define LCDC_HEOCFG3_YSIZE (0x7ff << LCDC_HEOCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG4 0x02DC
++#define LCDC_HEOCFG4_XMEM_SIZE_OFFSET 0
++#define LCDC_HEOCFG4_XMEM_SIZE (0x7ff << LCDC_HEOCFG4_XMEM_SIZE_OFFSET)
++#define LCDC_HEOCFG4_YMEM_SIZE_OFFSET 16
++#define LCDC_HEOCFG4_YMEM_SIZE (0x7ff << LCDC_HEOCFG4_YMEM_SIZE_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG5 0x02E0
++
++#define ATMEL_LCDC_HEOCFG6 0x02E4
++
++#define ATMEL_LCDC_HEOCFG7 0x02E8
++
++#define ATMEL_LCDC_HEOCFG8 0x02EC
++
++#define ATMEL_LCDC_HEOCFG9 0x02F0
++#define LCDC_HEOCFG9_BDEF_OFFSET 0
++#define LCDC_HEOCFG9_BDEF (0xff << LCDC_HEOCFG9_BDEF_OFFSET)
++#define LCDC_HEOCFG9_GDEF_OFFSET 8
++#define LCDC_HEOCFG9_GDEF (0xff << LCDC_HEOCFG9_GDEF_OFFSET)
++#define LCDC_HEOCFG9_RDEF_OFFSET 16
++#define LCDC_HEOCFG9_RDEF (0xff << LCDC_HEOCFG9_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG10 0x02F4
++#define LCDC_HEOCFG10_BKEY_OFFSET 0
++#define LCDC_HEOCFG10_BKEY (0xff << LCDC_HEOCFG10_BKEY_OFFSET)
++#define LCDC_HEOCFG10_GKEY_OFFSET 8
++#define LCDC_HEOCFG10_GKEY (0xff << LCDC_HEOCFG10_GKEY_OFFSET)
++#define LCDC_HEOCFG10_RKEY_OFFSET 16
++#define LCDC_HEOCFG10_RKEY (0xff << LCDC_HEOCFG10_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG11 0x02F8
++#define LCDC_HEOCFG11_BMASK_OFFSET 0
++#define LCDC_HEOCFG11_BMASK (0xff << LCDC_HEOCFG11_BMASK_OFFSET)
++#define LCDC_HEOCFG11_GMASK_OFFSET 8
++#define LCDC_HEOCFG11_GMASK (0xff << LCDC_HEOCFG11_GMASK_OFFSET)
++#define LCDC_HEOCFG11_RMASK_OFFSET 16
++#define LCDC_HEOCFG11_RMASK (0xff << LCDC_HEOCFG11_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG12 0x02FC
++#define LCDC_HEOCFG12_CRKEY (0x1 << 0)
++#define LCDC_HEOCFG12_INV (0x1 << 1)
++#define LCDC_HEOCFG12_ITER2BL (0x1 << 2)
++#define LCDC_HEOCFG12_ITER (0x1 << 3)
++#define LCDC_HEOCFG12_REVALPHA (0x1 << 4)
++#define LCDC_HEOCFG12_GAEN (0x1 << 5)
++#define LCDC_HEOCFG12_LAEN (0x1 << 6)
++#define LCDC_HEOCFG12_OVR (0x1 << 7)
++#define LCDC_HEOCFG12_DMA (0x1 << 8)
++#define LCDC_HEOCFG12_REP (0x1 << 9)
++#define LCDC_HEOCFG12_DSTKEY (0x1 << 10)
++#define LCDC_HEOCFG12_VIDPRI (0x1 << 12)
++#define LCDC_HEOCFG12_GA_OFFSET 16
++#define LCDC_HEOCFG12_GA (0xff << LCDC_HEOCFG12_GA_OFFSET)
++
++#define ATMEL_LCDC_HEOCFG13 0x0300
++#define LCDC_HEOCFG13_XFACTOR_OFFSET 0
++#define LCDC_HEOCFG13_XFACTOR (0x1fff << LCDC_HEOCFG13_XFACTOR_OFFSET)
++#define LCDC_HEOCFG13_YFACTOR_OFFSET 16
++#define LCDC_HEOCFG13_YFACTOR (0x1fff << LCDC_HEOCFG13_YFACTOR_OFFSET)
++#define LCDC_HEOCFG13_SCALEN (0x1 << 31)
++
++#define ATMEL_LCDC_HEOCFG14 0x0304
++#define LCDC_HEOCFG14_CSCRY_OFFSET 0
++#define LCDC_HEOCFG14_CSCRY (0x3ff << LCDC_HEOCFG14_CSCRY_OFFSET)
++#define LCDC_HEOCFG14_CSCRU_OFFSET 10
++#define LCDC_HEOCFG14_CSCRU (0x3ff << LCDC_HEOCFG14_CSCRU_OFFSET)
++#define LCDC_HEOCFG14_CSCRV_OFFSET 20
++#define LCDC_HEOCFG14_CSCRV (0x3ff << LCDC_HEOCFG14_CSCRV_OFFSET)
++#define LCDC_HEOCFG14_CSCYOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG15 0x0308
++#define LCDC_HEOCFG15_CSCGY_OFFSET 0
++#define LCDC_HEOCFG15_CSCGY (0x3ff << LCDC_HEOCFG15_CSCGY_OFFSET)
++#define LCDC_HEOCFG15_CSCGU_OFFSET 10
++#define LCDC_HEOCFG15_CSCGU (0x3ff << LCDC_HEOCFG15_CSCGU_OFFSET)
++#define LCDC_HEOCFG15_CSCGV_OFFSET 20
++#define LCDC_HEOCFG15_CSCGV (0x3ff << LCDC_HEOCFG15_CSCGV_OFFSET)
++#define LCDC_HEOCFG15_CSCUOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HEOCFG16 0x030C
++#define LCDC_HEOCFG16_CSCBY_OFFSET 0
++#define LCDC_HEOCFG16_CSCBY (0x3ff << LCDC_HEOCFG16_CSCBY_OFFSET)
++#define LCDC_HEOCFG16_CSCBU_OFFSET 10
++#define LCDC_HEOCFG16_CSCBU (0x3ff << LCDC_HEOCFG16_CSCBU_OFFSET)
++#define LCDC_HEOCFG16_CSCBV_OFFSET 20
++#define LCDC_HEOCFG16_CSCBV (0x3ff << LCDC_HEOCFG16_CSCBV_OFFSET)
++#define LCDC_HEOCFG16_CSCVOFF (0x1 << 30)
++
++#define ATMEL_LCDC_HCRCHER 0x0340
++#define LCDC_HCRCHER_CHEN (0x1 << 0)
++#define LCDC_HCRCHER_UPDATEEN (0x1 << 1)
++#define LCDC_HCRCHER_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_HCRCHDR 0x0344
++#define LCDC_HCRCHDR_CHDIS (0x1 << 0)
++#define LCDC_HCRCHDR_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCHSR 0x0348
++#define LCDC_HCRCHSR_CHSR (0x1 << 0)
++#define LCDC_HCRCHSR_UPDATESR (0x1 << 1)
++#define LCDC_HCRCHSR_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_HCRIER 0x034C
++#define LCDC_HCRIER_DMA (0x1 << 2)
++#define LCDC_HCRIER_DSCR (0x1 << 3)
++#define LCDC_HCRIER_ADD (0x1 << 4)
++#define LCDC_HCRIER_DONE (0x1 << 5)
++#define LCDC_HCRIER_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIDR 0x0350
++#define LCDC_HCRIDR_DMA (0x1 << 2)
++#define LCDC_HCRIDR_DSCR (0x1 << 3)
++#define LCDC_HCRIDR_ADD (0x1 << 4)
++#define LCDC_HCRIDR_DONE (0x1 << 5)
++#define LCDC_HCRIDR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRIMR 0x0354
++#define LCDC_HCRIMR_DMA (0x1 << 2)
++#define LCDC_HCRIMR_DSCR (0x1 << 3)
++#define LCDC_HCRIMR_ADD (0x1 << 4)
++#define LCDC_HCRIMR_DONE (0x1 << 5)
++#define LCDC_HCRIMR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRISR 0x0358
++#define LCDC_HCRISR_DMA (0x1 << 2)
++#define LCDC_HCRISR_DSCR (0x1 << 3)
++#define LCDC_HCRISR_ADD (0x1 << 4)
++#define LCDC_HCRISR_DONE (0x1 << 5)
++#define LCDC_HCRISR_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_HCRHEAD 0x035C
++
++#define ATMEL_LCDC_HCRADDR 0x0360
++
++#define ATMEL_LCDC_HCRCTRL 0x0364
++#define LCDC_HCRCTRL_DFETCH (0x1 << 0)
++#define LCDC_HCRCTRL_LFETCH (0x1 << 1)
++#define LCDC_HCRCTRL_DMAIEN (0x1 << 2)
++#define LCDC_HCRCTRL_DSCRIEN (0x1 << 3)
++#define LCDC_HCRCTRL_ADDIEN (0x1 << 4)
++#define LCDC_HCRCTRL_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_HCRNEXT 0x0368
++
++#define ATMEL_LCDC_HCRCFG0 0x036C
++#define LCDC_HCRCFG0_BLEN_OFFSET 4
++#define LCDC_HCRCFG0_BLEN (0x3 << LCDC_HCRCFG0_BLEN_OFFSET)
++#define LCDC_HCRCFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_HCRCFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_HCRCFG0_DLBO (0x1 << 8)
++
++#define ATMEL_LCDC_HCRCFG1 0x0370
++#define LCDC_HCRCFG1_CLUTEN (0x1 << 0)
++#define LCDC_HCRCFG1_RGBMODE_OFFSET 4
++#define LCDC_HCRCFG1_RGBMODE (0xf << LCDC_HCRCFG1_RGBMODE_OFFSET)
++#define LCDC_HCRCFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_HCRCFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_HCRCFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_HCRCFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_HCRCFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_HCRCFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_HCRCFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_HCRCFG1_CLUTMODE_OFFSET 8
++#define LCDC_HCRCFG1_CLUTMODE (0x3 << LCDC_HCRCFG1_CLUTMODE_OFFSET)
++#define LCDC_HCRCFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_HCRCFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_HCRCFG2 0x0374
++#define LCDC_HCRCFG2_XOFFSET_OFFSET 0
++#define LCDC_HCRCFG2_XOFFSET (0x7ff << LCDC_HCRCFG2_XOFFSET_OFFSET)
++#define LCDC_HCRCFG2_YOFFSET_OFFSET 16
++#define LCDC_HCRCFG2_YOFFSET (0x7ff << LCDC_HCRCFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG3 0x0378
++#define LCDC_HCRCFG3_XSIZE_OFFSET 0
++#define LCDC_HCRCFG3_XSIZE (0x7f << LCDC_HCRCFG3_XSIZE_OFFSET)
++#define LCDC_HCRCFG3_YSIZE_OFFSET 16
++#define LCDC_HCRCFG3_YSIZE (0x7f << LCDC_HCRCFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG4 0x037C
++
++#define ATMEL_LCDC_HCRCFG6 0x0384
++#define LCDC_HCRCFG6_BDEF_OFFSET 0
++#define LCDC_HCRCFG6_BDEF (0xff << LCDC_HCRCFG6_BDEF_OFFSET)
++#define LCDC_HCRCFG6_GDEF_OFFSET 8
++#define LCDC_HCRCFG6_GDEF (0xff << LCDC_HCRCFG6_GDEF_OFFSET)
++#define LCDC_HCRCFG6_RDEF_OFFSET 16
++#define LCDC_HCRCFG6_RDEF (0xff << LCDC_HCRCFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG7 0x0388
++#define LCDC_HCRCFG7_BKEY_OFFSET 0
++#define LCDC_HCRCFG7_BKEY (0xff << LCDC_HCRCFG7_BKEY_OFFSET)
++#define LCDC_HCRCFG7_GKEY_OFFSET 8
++#define LCDC_HCRCFG7_GKEY (0xff << LCDC_HCRCFG7_GKEY_OFFSET)
++#define LCDC_HCRCFG7_RKEY_OFFSET 16
++#define LCDC_HCRCFG7_RKEY (0xff << LCDC_HCRCFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG8 0x038C
++#define LCDC_HCRCFG8_BMASK_OFFSET 0
++#define LCDC_HCRCFG8_BMASK (0xff << LCDC_HCRCFG8_BMASK_OFFSET)
++#define LCDC_HCRCFG8_GMASK_OFFSET 8
++#define LCDC_HCRCFG8_GMASK (0xff << LCDC_HCRCFG8_GMASK_OFFSET)
++#define LCDC_HCRCFG8_RMASK_OFFSET 16
++#define LCDC_HCRCFG8_RMASK (0xff << LCDC_HCRCFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_HCRCFG9 0x0390
++#define LCDC_HCRCFG9_CRKEY (0x1 << 0)
++#define LCDC_HCRCFG9_INV (0x1 << 1)
++#define LCDC_HCRCFG9_ITER2BL (0x1 << 2)
++#define LCDC_HCRCFG9_ITER (0x1 << 3)
++#define LCDC_HCRCFG9_REVALPHA (0x1 << 4)
++#define LCDC_HCRCFG9_GAEN (0x1 << 5)
++#define LCDC_HCRCFG9_LAEN (0x1 << 6)
++#define LCDC_HCRCFG9_OVR (0x1 << 7)
++#define LCDC_HCRCFG9_DMA (0x1 << 8)
++#define LCDC_HCRCFG9_REP (0x1 << 9)
++#define LCDC_HCRCFG9_DSTKEY (0x1 << 10)
++#define LCDC_HCRCFG9_GA_OFFSET 16
++#define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
++
++#define ATMEL_LCDC_BASECLUT 0x400
++#define LCDC_BASECLUT_BCLUT_OFFSET 0
++#define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
++#define LCDC_BASECLUT_GCLUT_OFFSET 8
++#define LCDC_BASECLUT_GCLUT (0xff << LCDC_BASECLUT_GCLUT_OFFSET)
++#define LCDC_BASECLUT_RCLUT_OFFSET 16
++#define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
++
++#define ATMEL_LCDC_OVR1CLUT 0x800
++#define LCDC_OVR1CLUT_BCLUT_OFFSET 0
++#define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
++#define LCDC_OVR1CLUT_GCLUT_OFFSET 8
++#define LCDC_OVR1CLUT_GCLUT (0xff << LCDC_OVR1CLUT_GCLUT_OFFSET)
++#define LCDC_OVR1CLUT_RCLUT_OFFSET 16
++#define LCDC_OVR1CLUT_RCLUT (0xff << LCDC_OVR1CLUT_RCLUT_OFFSET)
++#define LCDC_OVR1CLUT_ACLUT_OFFSET 24
++#define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HEOCLUT 0x1000
++#define LCDC_HEOCLUT_BCLUT_OFFSET 0
++#define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
++#define LCDC_HEOCLUT_GCLUT_OFFSET 8
++#define LCDC_HEOCLUT_GCLUT (0xff << LCDC_HEOCLUT_GCLUT_OFFSET)
++#define LCDC_HEOCLUT_RCLUT_OFFSET 16
++#define LCDC_HEOCLUT_RCLUT (0xff << LCDC_HEOCLUT_RCLUT_OFFSET)
++#define LCDC_HEOCLUT_ACLUT_OFFSET 24
++#define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
++
++#define ATMEL_LCDC_HCRCLUT 0x1400
++#define LCDC_HCRCLUT_BCLUT_OFFSET 0
++#define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
++#define LCDC_HCRCLUT_GCLUT_OFFSET 8
++#define LCDC_HCRCLUT_GCLUT (0xff << LCDC_HCRCLUT_GCLUT_OFFSET)
++#define LCDC_HCRCLUT_RCLUT_OFFSET 16
++#define LCDC_HCRCLUT_RCLUT (0xff << LCDC_HCRCLUT_RCLUT_OFFSET)
++#define LCDC_HCRCLUT_ACLUT_OFFSET 24
++#define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
++
++/* Base layer CLUT */
++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++
++
++#endif /* __ATMEL_HLCDC4_H__ */
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index d99505b..c35f5c7 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -1,7 +1,7 @@
+ /*
+ * Driver for AT91/AT32 LCD Controller
+ *
+- * Copyright (C) 2007 Atmel Corporation
++ * Copyright (C) 2007-2010 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+@@ -25,6 +25,7 @@
+ #include <asm/gpio.h>
+
+ #include <video/atmel_lcdc.h>
++#include <mach/atmel_hlcdfb.h>
+
+ #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+ #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+@@ -76,6 +77,9 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
++static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
++ | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
++
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+ /* some bl->props field just changed */
+@@ -84,6 +88,7 @@ static int atmel_bl_update_status(struct backlight_device *bl)
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+ int power = sinfo->bl_power;
+ int brightness = bl->props.brightness;
++ u32 reg;
+
+ /* REVISIT there may be a meaningful difference between
+ * fb_blank and power ... there seem to be some cases
+@@ -94,17 +99,28 @@ static int atmel_bl_update_status(struct backlight_device *bl)
+ else if (bl->props.power != sinfo->bl_power)
+ power = bl->props.power;
+
+- if (brightness < 0 && power == FB_BLANK_UNBLANK)
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- else if (power != FB_BLANK_UNBLANK)
++ if (brightness < 0 && power == FB_BLANK_UNBLANK) {
++ if (cpu_is_at91sam9x5())
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ } else if (power != FB_BLANK_UNBLANK) {
+ brightness = 0;
++ }
+
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+- else
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ if (cpu_is_at91sam9x5()) {
++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++ else
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ }
+
+ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+
+@@ -115,7 +131,10 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
+ {
+ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ if (cpu_is_at91sam9x5())
++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ }
+
+ static const struct backlight_ops atmel_lcdc_bl_ops = {
+@@ -171,14 +190,17 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+
+ static void init_contrast(struct atmel_lcdfb_info *sinfo)
+ {
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+-
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+-
++ if (cpu_is_at91sam9x5()) {
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
++ } else {
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++ }
+ if (sinfo->lcdcon_is_backlight)
+ init_backlight(sinfo);
+ }
+@@ -220,32 +242,78 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+
+ static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+ {
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++ if (cpu_is_at91sam9x5()) {
++ /* Disable DISP signal */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ /* Disable synchronization */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ /* Disable pixel clock */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ /* Disable PWM */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++ } else {
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
+
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++ }
+ }
+
+ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+ {
+ atmel_lcdfb_stop_nowait(sinfo);
+
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ if (cpu_is_at91sam9x5()) {
++ /* Wait for the end of DMA transfer */
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
++ msleep(10);
++ } else {
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++ }
+ }
+
+ static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
++ u32 value;
++
++ if (cpu_is_at91sam9x5()) {
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++ }
+ }
+
+ static void atmel_lcdfb_update_dma(struct fb_info *info,
+@@ -254,14 +322,31 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct atmel_lcdfb_info *sinfo = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ unsigned long dma_addr;
++ struct lcd_dma_desc *desc;
+
+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+ + var->xoffset * info->var.bits_per_pixel / 8);
+
+ dma_addr &= ~3UL;
+
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++ if (cpu_is_at91sam9x5()) {
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
++ } else {
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++ }
+
+ atmel_lcdfb_update_dma2d(sinfo, var, info);
+ }
+@@ -272,12 +357,18 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
++
++ if (cpu_is_at91sam9x5()) {
++ if (sinfo->p_dma_desc)
++ dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
++ sinfo->p_dma_desc, sinfo->dma_desc_phys);
++ }
+ }
+
+ /**
+ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ * @sinfo: the frame buffer to allocate memory for
+- *
++ *
+ * This function is called only from the atmel_lcdfb_probe()
+ * so no locking by fb_info->mm_lock around smem_len setting is needed.
+ */
+@@ -300,6 +391,19 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ memset(info->screen_base, 0, info->fix.smem_len);
+
++ if (cpu_is_at91sam9x5()) {
++ sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
++ sizeof(struct lcd_dma_desc),
++ (dma_addr_t *)&(sinfo->dma_desc_phys),
++ GFP_KERNEL);
++
++ if (!sinfo->p_dma_desc) {
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++ return -ENOMEM;
++ }
++ }
++
+ return 0;
+ }
+
+@@ -393,18 +497,33 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
++ if (cpu_is_at91sam9x5()) {
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
++ var->right_margin = min_t(u32, var->right_margin,
++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++ } else {
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++ }
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+@@ -419,9 +538,53 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ case 8:
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length
+- = var->bits_per_pixel;
++ = var->bits_per_pixel;
++ break;
++ case 12:
++ if (cpu_is_at91sam9x5()) {
++ /* RGB:444 mode */
++ var->red.offset = 8;
++ var->blue.offset = 0;
++ var->green.offset = 4;
++ var->red.length = var->green.length = var->blue.length = 4;
++ } else {
++ /*TODO: rework*/
++ BUG();
++ }
++ break;
++ case 15:
++ if (cpu_is_at91sam9x5()) {
++ /* RGB:555 mode */
++ var->red.offset = 10;
++ var->blue.offset = 0;
++ var->green.length = 5;
++ var->red.length = var->green.length = var->blue.length = 5;
++ } else {
++ /*TODO: rework*/
++ BUG();
++ }
+ break;
+ case 16:
++ if (cpu_is_at91sam9x5()) {
++ if (sinfo->alpha_enabled) {
++ /* ARGB:4444 mode */
++ var->red.offset = 8;
++ var->blue.offset = 0;
++ var->green.offset = 4;
++ var->transp.offset = 12;
++ var->red.length = var->green.length
++ = var->blue.length
++ = var->transp.length = 4;
++ } else {
++ /* RGB:565 mode */
++ var->red.offset = 11;
++ var->blue.offset = 0;
++ var->green.offset = 5;
++ var->green.length = 6;
++ var->red.length = var->blue.length = 5;
++ }
++ break;
++ }
+ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+ /* RGB:565 mode */
+ var->red.offset = 11;
+@@ -436,6 +599,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ var->red.length = var->blue.length = 5;
+ break;
+ case 32:
++ /* TODO 32 & 24 modes */
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ /* fall through */
+@@ -472,6 +636,252 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ atmel_lcdfb_start(sinfo);
+ }
+
++static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long value;
++ unsigned long clk_value_khz;
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ /* Set pixel clock */
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < 1) {
++ dev_notice(info->device, "using system clock as pixel clock\n");
++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ } else {
++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ value = value - 2;
++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
++ value);
++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
++ | LCDC_LCDCFG0_CLKPOL
++ | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ }
++
++ /* Initialize control register 5 */
++ value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ | LCDC_LCDCFG5_DISPDLY
++ | LCDC_LCDCFG5_VSPDLYS;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= LCDC_LCDCFG5_HSPOL;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= LCDC_LCDCFG5_VSPOL;
++
++ switch (info->var.bits_per_pixel) {
++ case 12:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
++ break;
++ case 16:
++ if (info->var.transp.offset != 0)
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
++ else
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
++ break;
++ case 18:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
++ break;
++ case 24:
++ case 32:
++ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
++
++ /* Vertical & Horizontal Timing */
++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
++
++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
++
++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
++
++ /* Display size */
++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
++ switch (info->var.bits_per_pixel) {
++ case 12:
++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
++ break;
++ case 16:
++ if (info->var.transp.offset != 0)
++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
++ else
++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
++ break;
++ case 18:
++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
++ break;
++ case 24:
++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
++ break;
++ case 32:
++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
++
++ return 0;
++}
++
++static int atmel_lcdfb_setup_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long pix_factor = 2;
++
++ if (cpu_is_at91sam9x5()) {
++ return atmel_lcdfb_setup_9x5_core(info);
++ } else {
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value |= ATMEL_LCDC_PIXELSIZE_1;
++ break;
++ case 2:
++ value |= ATMEL_LCDC_PIXELSIZE_2;
++ break;
++ case 4:
++ value |= ATMEL_LCDC_PIXELSIZE_4;
++ break;
++ case 8:
++ value |= ATMEL_LCDC_PIXELSIZE_8;
++ break;
++ case 15: /* fall through */
++ case 16:
++ value |= ATMEL_LCDC_PIXELSIZE_16;
++ break;
++ case 24:
++ value |= ATMEL_LCDC_PIXELSIZE_24;
++ break;
++ case 32:
++ value |= ATMEL_LCDC_PIXELSIZE_32;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ return 0;
++ }
++}
++
+ /**
+ * atmel_lcdfb_set_par - Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+@@ -489,11 +899,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ static int atmel_lcdfb_set_par(struct fb_info *info)
+ {
+ struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+ unsigned long bits_per_line;
+- unsigned long pix_factor = 2;
+
+ might_sleep();
+
+@@ -518,98 +924,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+ /* Now, the LCDC core... */
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+- case 15: /* fall through */
+- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+- default: BUG(); break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ atmel_lcdfb_setup_core(info);
+
+ atmel_lcdfb_start(sinfo);
+
+@@ -772,14 +1088,32 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+ struct fb_info *info = dev_id;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ u32 status;
++ u32 baselayer_status;
++
++ if (cpu_is_at91sam9x5()) {
++ /* Check for error status via interrupt.*/
++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
++ if (status & LCDC_LCDISR_FIFOERR) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ } else if (status & LCDC_LCDISR_BASE) {
++ /* Check base layer's overflow error. */
++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
++
++ if (baselayer_status & LCDC_BASEISR_OVR)
++ dev_warn(info->device, "base layer overflow %#x\n",
++ baselayer_status);
+
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
++ }
++ } else {
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+ }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -920,6 +1254,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ sinfo->p_dma_desc = NULL;
++ sinfo->dma_desc_phys = 0;
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+@@ -1030,7 +1366,7 @@ unmap_mmio:
+ exit_backlight(sinfo);
+ iounmap(sinfo->mmio);
+ release_mem:
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ free_fb:
+ if (map)
+ iounmap(info->screen_base);
+@@ -1075,7 +1411,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+ fb_dealloc_cmap(&info->cmap);
+ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+@@ -1100,10 +1436,17 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ * We don't want to handle interrupts while the clock is
+ * stopped. It may take forever.
+ */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ if (cpu_is_at91sam9x5()) {
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++
++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
++ }
+
+- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+
+@@ -1122,11 +1465,18 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ atmel_lcdfb_start(sinfo);
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
+- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++ if (cpu_is_at91sam9x5()) {
++ /* Enable fifo error & BASE LAYER overflow interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
++ } else {
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
++
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++ }
+
+ return 0;
+ }
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 28447f1..5183ab7 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -47,12 +47,16 @@ struct atmel_lcdfb_info {
+ struct clk *bus_clk;
+ struct clk *lcdc_clk;
+
++ struct lcd_dma_desc *p_dma_desc;
++ dma_addr_t dma_desc_phys;
++
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+ #endif
+ bool lcdcon_is_backlight;
+ bool lcdcon_pol_negative;
++ bool alpha_enabled;
+ u8 saved_lcdcon;
+
+ u8 default_bpp;
+@@ -64,6 +68,12 @@ struct atmel_lcdfb_info {
+ u32 pseudo_palette[16];
+ };
+
++struct lcd_dma_desc {
++ u32 address;
++ u32 control;
++ u32 next;
++};
++
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+ #define ATMEL_LCDC_DMAFRMPT1 0x08
+@@ -214,6 +224,11 @@ struct atmel_lcdfb_info {
+ #define ATMEL_LCDC_OWRI (1 << 5)
+ #define ATMEL_LCDC_MERI (1 << 6)
+
++#if !defined(CONFIG_ARCH_AT91SAM9X5)
+ #define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
++#else
++/* Base layer CLUT */
++#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++#endif
+
+ #endif /* __ATMEL_LCDC_H__ */
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 4b390fa4276515efa7c11faf731368289873c486 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Wed, 9 Mar 2011 11:21:51 +0800
+Subject: video/atmel_lcdfb: The output bpp should not change according to
+ memory bpp
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The 9x5-ek using 24 bits output for its connection to LCD screen.
+The output bpp can now be configurated in board file.
+
+XXX: these are two different changes?
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 25 +++----------------------
+ 1 file changed, 3 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index c35f5c7..ae0e8e9 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -666,7 +666,9 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+ }
+
+ /* Initialize control register 5 */
+- value = (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
++ value = sinfo->default_lcdcon2;
++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
+ | LCDC_LCDCFG5_DISPDLY
+ | LCDC_LCDCFG5_VSPDLYS;
+
+@@ -675,27 +677,6 @@ static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ value |= LCDC_LCDCFG5_VSPOL;
+
+- switch (info->var.bits_per_pixel) {
+- case 12:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+- break;
+- case 16:
+- if (info->var.transp.offset != 0)
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+- else
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
+- break;
+- case 18:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
+- break;
+- case 24:
+- case 32:
+- value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+- break;
+- default:
+- BUG();
+- break;
+- }
+ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 565de7199ff8177b8034e2d799d820243ae76a0f Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 9 Oct 2012 18:23:51 +0200
-Subject: video: atmel_lcdfb*: protect bl_power with
- CONFIG_BACKLIGHT_ATMEL_LCDC
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/video/atmel_hlcdfb.c | 24 +++++++++++++++++++-----
- drivers/video/atmel_lcdfb.c | 24 +++++++++++++++++++-----
- 2 files changed, 38 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-index a629dda..db6ec3e 100644
---- a/drivers/video/atmel_hlcdfb.c
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -94,6 +94,7 @@ static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
- lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
- }
-
-+#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
- /* some bl->props field just changed */
- static int atmel_bl_update_status(struct backlight_device *bl)
- {
-@@ -133,17 +134,30 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
- return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
- }
-
--static const struct backlight_ops atmel_hlcdc_bl_ops = {
-- .update_status = atmel_bl_update_status,
-- .get_brightness = atmel_bl_get_brightness,
--};
--
- static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
- {
- /* have some default contrast/backlight settings */
- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL |
- (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET));
- }
-+#else
-+static int atmel_bl_update_status(struct backlight_device *bl)
-+{
-+ return 0;
-+}
-+
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
-+{
-+ return ATMEL_LCDC_CVAL_DEFAULT;
-+}
-+
-+static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
-+#endif
-+
-+static const struct backlight_ops atmel_hlcdc_bl_ops = {
-+ .update_status = atmel_bl_update_status,
-+ .get_brightness = atmel_bl_get_brightness,
-+};
-
- void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
- {
-diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
-index 86e3e32..651c88f 100644
---- a/drivers/video/atmel_lcdfb.c
-+++ b/drivers/video/atmel_lcdfb.c
-@@ -86,6 +86,7 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
- atmel_lcdfb_update_dma2d(sinfo, var);
- }
-
-+#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
- /* some bl->props field just changed */
- static int atmel_bl_update_status(struct backlight_device *bl)
- {
-@@ -123,11 +124,6 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
- }
-
--static const struct backlight_ops atmel_lcdc_bl_ops = {
-- .update_status = atmel_bl_update_status,
-- .get_brightness = atmel_bl_get_brightness,
--};
--
- static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
- {
- /* contrast pwm can be 'inverted' */
-@@ -138,6 +134,24 @@ static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
- }
-+#else
-+static int atmel_bl_update_status(struct backlight_device *bl)
-+{
-+ return 0;
-+}
-+
-+static int atmel_bl_get_brightness(struct backlight_device *bl)
-+{
-+ return ATMEL_LCDC_CVAL_DEFAULT;
-+}
-+
-+static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
-+#endif
-+
-+static const struct backlight_ops atmel_lcdc_bl_ops = {
-+ .update_status = atmel_bl_update_status,
-+ .get_brightness = atmel_bl_get_brightness,
-+};
-
- void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
- {
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From fe1559cee6d0716c401e9ae3d621f3ec4964982b Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:21:15 +0200
-Subject: ARM: at91/9x5: modify consistent DMA size
-
-update to 8M
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/at91sam9x5.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index c949dc7..7eb00c53 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -302,6 +302,7 @@ static void __init at91sam9x5_register_clocks(void)
- static void __init at91sam9x5_map_io(void)
- {
- at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
-+ init_consistent_dma_size(SZ_8M);
- }
-
- void __init at91sam9x5_initialize(void)
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From b87963ed623148fd11efc742fbabfcde68aba645 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 09:42:55 +0200
+Subject: video: atmelfb: initially split atmelfb into a driver and library
+ part
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+Conflicts:
+
+ drivers/video/atmel_lcdfb.c
+---
+ drivers/video/Makefile | 2 +-
+ drivers/video/atmel_lcdfb.c | 1427 +-------------------------------------
+ drivers/video/atmel_lcdfb_core.c | 1077 ++++++++++++++++++++++++++++
+ include/video/atmel_lcdc.h | 17 +-
+ 4 files changed, 1104 insertions(+), 1419 deletions(-)
+ create mode 100644 drivers/video/atmel_lcdfb_core.c
+
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 9356add..37c5625 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -95,7 +95,7 @@ obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o
+ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o
+ obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+-obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
++obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
+ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1) += sstfb.o
+ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index ae0e8e9..4e1454c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -10,1401 +10,12 @@
+
+ #include <linux/kernel.h>
+ #include <linux/platform_device.h>
+-#include <linux/dma-mapping.h>
+ #include <linux/interrupt.h>
+-#include <linux/clk.h>
+ #include <linux/fb.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/backlight.h>
+-#include <linux/gfp.h>
+-#include <linux/module.h>
+-
+-#include <mach/board.h>
+-#include <mach/cpu.h>
+-#include <asm/gpio.h>
+
+ #include <video/atmel_lcdc.h>
+-#include <mach/atmel_hlcdfb.h>
+-
+-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+-
+-/* configurable parameters */
+-#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+-
+-#if defined(CONFIG_ARCH_AT91)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+-
+-}
+-#elif defined(CONFIG_AVR32)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_XPAN \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- u32 dma2dcfg;
+- u32 pixeloff;
+-
+- pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f;
+-
+- dma2dcfg = (info->var.xres_virtual - info->var.xres)
+- * info->var.bits_per_pixel / 8;
+- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+-
+- /* Update configuration */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+- | ATMEL_LCDC_DMAUPDT);
+-}
+-#endif
+-
+-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+- | ATMEL_LCDC_POL_POSITIVE
+- | ATMEL_LCDC_ENA_PWMENABLE;
+-
+-static const u32 contrast_pwm_ctr = LCDC_LCDCFG6_PWMPOL
+- | (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET);
+-
+-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+-
+-/* some bl->props field just changed */
+-static int atmel_bl_update_status(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+- int power = sinfo->bl_power;
+- int brightness = bl->props.brightness;
+- u32 reg;
+-
+- /* REVISIT there may be a meaningful difference between
+- * fb_blank and power ... there seem to be some cases
+- * this doesn't handle correctly.
+- */
+- if (bl->props.fb_blank != sinfo->bl_power)
+- power = bl->props.fb_blank;
+- else if (bl->props.power != sinfo->bl_power)
+- power = bl->props.power;
+-
+- if (brightness < 0 && power == FB_BLANK_UNBLANK) {
+- if (cpu_is_at91sam9x5())
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
+- >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- else
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- } else if (power != FB_BLANK_UNBLANK) {
+- brightness = 0;
+- }
+-
+- if (cpu_is_at91sam9x5()) {
+- reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
+- reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE)
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+- else
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- }
+-
+- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+-
+- return 0;
+-}
+-
+-static int atmel_bl_get_brightness(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+-
+- if (cpu_is_at91sam9x5())
+- return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
+- else
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+-}
+-
+-static const struct backlight_ops atmel_lcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+-static void init_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- struct backlight_properties props;
+- struct backlight_device *bl;
+-
+- sinfo->bl_power = FB_BLANK_UNBLANK;
+-
+- if (sinfo->backlight)
+- return;
+-
+- memset(&props, 0, sizeof(struct backlight_properties));
+- props.type = BACKLIGHT_RAW;
+- props.max_brightness = 0xff;
+- bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+- &atmel_lcdc_bl_ops, &props);
+- if (IS_ERR(bl)) {
+- dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+- PTR_ERR(bl));
+- return;
+- }
+- sinfo->backlight = bl;
+-
+- bl->props.power = FB_BLANK_UNBLANK;
+- bl->props.fb_blank = FB_BLANK_UNBLANK;
+- bl->props.brightness = atmel_bl_get_brightness(bl);
+-}
+-
+-static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->backlight)
+- backlight_device_unregister(sinfo->backlight);
+-}
+-
+-#else
+-
+-static void init_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+- dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
+-}
+-
+-static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+-{
+-}
+-
+-#endif
+-
+-static void init_contrast(struct atmel_lcdfb_info *sinfo)
+-{
+- if (cpu_is_at91sam9x5()) {
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, contrast_pwm_ctr);
+- } else {
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+- }
+- if (sinfo->lcdcon_is_backlight)
+- init_backlight(sinfo);
+-}
+-
+-
+-static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+- .type = FB_TYPE_PACKED_PIXELS,
+- .visual = FB_VISUAL_TRUECOLOR,
+- .xpanstep = 0,
+- .ypanstep = 1,
+- .ywrapstep = 0,
+- .accel = FB_ACCEL_NONE,
+-};
+-
+-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+-{
+- unsigned long value;
+-
+- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()))
+- return xres;
+-
+- value = xres;
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+- /* STN display */
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+- value *= 3;
+- }
+- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+- value = DIV_ROUND_UP(value, 4);
+- else
+- value = DIV_ROUND_UP(value, 8);
+- }
+-
+- return value;
+-}
+-
+-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+-{
+- if (cpu_is_at91sam9x5()) {
+- /* Disable DISP signal */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
+- msleep(1);
+- /* Disable synchronization */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
+- msleep(1);
+- /* Disable pixel clock */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
+- msleep(1);
+- /* Disable PWM */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
+- while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
+- msleep(1);
+- } else {
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+-
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+- }
+-}
+-
+-static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+-{
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Wait for the end of DMA transfer */
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
+- msleep(10);
+- } else {
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+- }
+-}
+-
+-static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+-{
+- u32 value;
+-
+- if (cpu_is_at91sam9x5()) {
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
+- msleep(1);
+- value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
+- while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
+- msleep(1);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
+- }
+-}
+-
+-static void atmel_lcdfb_update_dma(struct fb_info *info,
+- struct fb_var_screeninfo *var)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- struct fb_fix_screeninfo *fix = &info->fix;
+- unsigned long dma_addr;
+- struct lcd_dma_desc *desc;
+-
+- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+- + var->xoffset * info->var.bits_per_pixel / 8);
+-
+- dma_addr &= ~3UL;
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Setup the DMA descriptor, this descriptor will loop to itself */
+- desc = (struct lcd_dma_desc *)sinfo->p_dma_desc;
+-
+- desc->address = dma_addr;
+- /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
+- desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
+- | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
+- desc->next = sinfo->dma_desc_phys;
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
+- } else {
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+- }
+-
+- atmel_lcdfb_update_dma2d(sinfo, var, info);
+-}
+-
+-static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+-
+- dma_free_writecombine(info->device, info->fix.smem_len,
+- info->screen_base, info->fix.smem_start);
+-
+- if (cpu_is_at91sam9x5()) {
+- if (sinfo->p_dma_desc)
+- dma_free_writecombine(info->device, sizeof(struct lcd_dma_desc),
+- sinfo->p_dma_desc, sinfo->dma_desc_phys);
+- }
+-}
+-
+-/**
+- * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+- * @sinfo: the frame buffer to allocate memory for
+- *
+- * This function is called only from the atmel_lcdfb_probe()
+- * so no locking by fb_info->mm_lock around smem_len setting is needed.
+- */
+-static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+- struct fb_var_screeninfo *var = &info->var;
+- unsigned int smem_len;
+-
+- smem_len = (var->xres_virtual * var->yres_virtual
+- * ((var->bits_per_pixel + 7) / 8));
+- info->fix.smem_len = max(smem_len, sinfo->smem_len);
+-
+- info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+- (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+-
+- if (!info->screen_base) {
+- return -ENOMEM;
+- }
+-
+- memset(info->screen_base, 0, info->fix.smem_len);
+-
+- if (cpu_is_at91sam9x5()) {
+- sinfo->p_dma_desc = dma_alloc_writecombine(info->device,
+- sizeof(struct lcd_dma_desc),
+- (dma_addr_t *)&(sinfo->dma_desc_phys),
+- GFP_KERNEL);
+-
+- if (!sinfo->p_dma_desc) {
+- dma_free_writecombine(info->device, info->fix.smem_len,
+- info->screen_base, info->fix.smem_start);
+- return -ENOMEM;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- struct fb_videomode varfbmode;
+- const struct fb_videomode *fbmode = NULL;
+-
+- fb_var_to_videomode(&varfbmode, var);
+- fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
+- if (fbmode)
+- fb_videomode_to_var(var, fbmode);
+- return fbmode;
+-}
+-
+-
+-/**
+- * atmel_lcdfb_check_var - Validates a var passed in.
+- * @var: frame buffer variable screen structure
+- * @info: frame buffer structure that represents a single frame buffer
+- *
+- * Checks to see if the hardware supports the state requested by
+- * var passed in. This function does not alter the hardware
+- * state!!! This means the data stored in struct fb_info and
+- * struct atmel_lcdfb_info do not change. This includes the var
+- * inside of struct fb_info. Do NOT change these. This function
+- * can be called on its own if we intent to only test a mode and
+- * not actually set it. The stuff in modedb.c is a example of
+- * this. If the var passed in is slightly off by what the
+- * hardware can support then we alter the var PASSED in to what
+- * we can do. If the hardware doesn't support mode change a
+- * -EINVAL will be returned by the upper layers. You don't need
+- * to implement this function then. If you hardware doesn't
+- * support changing the resolution then this function is not
+- * needed. In this case the driver would just provide a var that
+- * represents the static state the screen is in.
+- *
+- * Returns negative errno on error, or zero on success.
+- */
+-static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- struct device *dev = info->device;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long clk_value_khz;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- dev_dbg(dev, "%s:\n", __func__);
+-
+- if (!(var->pixclock && var->bits_per_pixel)) {
+- /* choose a suitable mode if possible */
+- if (!atmel_lcdfb_choose_mode(var, info)) {
+- dev_err(dev, "needed value not specified\n");
+- return -EINVAL;
+- }
+- }
+-
+- dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
+- dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
+- dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
+- dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
+-
+- if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
+- dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+- return -EINVAL;
+- }
+-
+- /* Do not allow to have real resoulution larger than virtual */
+- if (var->xres > var->xres_virtual)
+- var->xres_virtual = var->xres;
+-
+- if (var->yres > var->yres_virtual)
+- var->yres_virtual = var->yres;
+-
+- /* Force same alignment for each line */
+- var->xres = (var->xres + 3) & ~3UL;
+- var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+-
+- var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+- var->transp.msb_right = 0;
+- var->transp.offset = var->transp.length = 0;
+- var->xoffset = var->yoffset = 0;
+-
+- if (info->fix.smem_len) {
+- unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+- * ((var->bits_per_pixel + 7) / 8));
+- if (smem_len > info->fix.smem_len)
+- return -EINVAL;
+- }
+-
+- /* Saturate vertical and horizontal timings at maximum values */
+- if (cpu_is_at91sam9x5()) {
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
+- var->right_margin = min_t(u32, var->right_margin,
+- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+- } else {
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
+- }
+-
+- /* Some parameters can't be zero */
+- var->vsync_len = max_t(u32, var->vsync_len, 1);
+- var->right_margin = max_t(u32, var->right_margin, 1);
+- var->hsync_len = max_t(u32, var->hsync_len, 1);
+- var->left_margin = max_t(u32, var->left_margin, 1);
+-
+- switch (var->bits_per_pixel) {
+- case 1:
+- case 2:
+- case 4:
+- case 8:
+- var->red.offset = var->green.offset = var->blue.offset = 0;
+- var->red.length = var->green.length = var->blue.length
+- = var->bits_per_pixel;
+- break;
+- case 12:
+- if (cpu_is_at91sam9x5()) {
+- /* RGB:444 mode */
+- var->red.offset = 8;
+- var->blue.offset = 0;
+- var->green.offset = 4;
+- var->red.length = var->green.length = var->blue.length = 4;
+- } else {
+- /*TODO: rework*/
+- BUG();
+- }
+- break;
+- case 15:
+- if (cpu_is_at91sam9x5()) {
+- /* RGB:555 mode */
+- var->red.offset = 10;
+- var->blue.offset = 0;
+- var->green.length = 5;
+- var->red.length = var->green.length = var->blue.length = 5;
+- } else {
+- /*TODO: rework*/
+- BUG();
+- }
+- break;
+- case 16:
+- if (cpu_is_at91sam9x5()) {
+- if (sinfo->alpha_enabled) {
+- /* ARGB:4444 mode */
+- var->red.offset = 8;
+- var->blue.offset = 0;
+- var->green.offset = 4;
+- var->transp.offset = 12;
+- var->red.length = var->green.length
+- = var->blue.length
+- = var->transp.length = 4;
+- } else {
+- /* RGB:565 mode */
+- var->red.offset = 11;
+- var->blue.offset = 0;
+- var->green.offset = 5;
+- var->green.length = 6;
+- var->red.length = var->blue.length = 5;
+- }
+- break;
+- }
+- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+- /* RGB:565 mode */
+- var->red.offset = 11;
+- var->blue.offset = 0;
+- } else {
+- /* BGR:565 mode */
+- var->red.offset = 0;
+- var->blue.offset = 11;
+- }
+- var->green.offset = 5;
+- var->green.length = 6;
+- var->red.length = var->blue.length = 5;
+- break;
+- case 32:
+- /* TODO 32 & 24 modes */
+- var->transp.offset = 24;
+- var->transp.length = 8;
+- /* fall through */
+- case 24:
+- if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
+- /* RGB:888 mode */
+- var->red.offset = 16;
+- var->blue.offset = 0;
+- } else {
+- /* BGR:888 mode */
+- var->red.offset = 0;
+- var->blue.offset = 16;
+- }
+- var->green.offset = 8;
+- var->red.length = var->green.length = var->blue.length = 8;
+- break;
+- default:
+- dev_err(dev, "color depth %d not supported\n",
+- var->bits_per_pixel);
+- return -EINVAL;
+- }
+-
+- return 0;
+-}
+-
+-/*
+- * LCD reset sequence
+- */
+-static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+-{
+- might_sleep();
+-
+- atmel_lcdfb_stop(sinfo);
+- atmel_lcdfb_start(sinfo);
+-}
+-
+-static int atmel_lcdfb_setup_9x5_core(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long value;
+- unsigned long clk_value_khz;
+-
+- dev_dbg(info->device, "%s:\n", __func__);
+- /* Set pixel clock */
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < 1) {
+- dev_notice(info->device, "using system clock as pixel clock\n");
+- value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
+- } else {
+- info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- value = value - 2;
+- dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
+- value);
+- value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
+- | LCDC_LCDCFG0_CLKPOL
+- | LCDC_LCDCFG0_CGDISBASE;
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
+- }
+-
+- /* Initialize control register 5 */
+- /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
+- value = sinfo->default_lcdcon2;
+- value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
+- | LCDC_LCDCFG5_DISPDLY
+- | LCDC_LCDCFG5_VSPDLYS;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= LCDC_LCDCFG5_HSPOL;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= LCDC_LCDCFG5_VSPOL;
+-
+- dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
+-
+- /* Vertical & Horizontal Timing */
+- value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
+- value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
+-
+- value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
+- value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
+-
+- value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
+- value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
+-
+- /* Display size */
+- value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
+- value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
+- dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
+- switch (info->var.bits_per_pixel) {
+- case 12:
+- value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
+- break;
+- case 16:
+- if (info->var.transp.offset != 0)
+- value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
+- else
+- value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
+- break;
+- case 18:
+- value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
+- break;
+- case 24:
+- value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
+- break;
+- case 32:
+- value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
+- break;
+- default:
+- BUG();
+- break;
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, value);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
+- /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
+-
+- return 0;
+-}
+-
+-static int atmel_lcdfb_setup_core(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+- unsigned long pix_factor = 2;
+-
+- if (cpu_is_at91sam9x5()) {
+- return atmel_lcdfb_setup_9x5_core(info);
+- } else {
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1:
+- value |= ATMEL_LCDC_PIXELSIZE_1;
+- break;
+- case 2:
+- value |= ATMEL_LCDC_PIXELSIZE_2;
+- break;
+- case 4:
+- value |= ATMEL_LCDC_PIXELSIZE_4;
+- break;
+- case 8:
+- value |= ATMEL_LCDC_PIXELSIZE_8;
+- break;
+- case 15: /* fall through */
+- case 16:
+- value |= ATMEL_LCDC_PIXELSIZE_16;
+- break;
+- case 24:
+- value |= ATMEL_LCDC_PIXELSIZE_24;
+- break;
+- case 32:
+- value |= ATMEL_LCDC_PIXELSIZE_32;
+- break;
+- default:
+- BUG();
+- break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+-
+- return 0;
+- }
+-}
+-
+-/**
+- * atmel_lcdfb_set_par - Alters the hardware state.
+- * @info: frame buffer structure that represents a single frame buffer
+- *
+- * Using the fb_var_screeninfo in fb_info we set the resolution
+- * of the this particular framebuffer. This function alters the
+- * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+- * not alter var in fb_info since we are using that data. This
+- * means we depend on the data in var inside fb_info to be
+- * supported by the hardware. atmel_lcdfb_check_var is always called
+- * before atmel_lcdfb_set_par to ensure this. Again if you can't
+- * change the resolution you don't need this function.
+- *
+- */
+-static int atmel_lcdfb_set_par(struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long bits_per_line;
+-
+- might_sleep();
+-
+- dev_dbg(info->device, "%s:\n", __func__);
+- dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
+- info->var.xres, info->var.yres,
+- info->var.xres_virtual, info->var.yres_virtual);
+-
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- if (info->var.bits_per_pixel == 1)
+- info->fix.visual = FB_VISUAL_MONO01;
+- else if (info->var.bits_per_pixel <= 8)
+- info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+- else
+- info->fix.visual = FB_VISUAL_TRUECOLOR;
+-
+- bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+- info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
+-
+- /* Re-initialize the DMA engine... */
+- dev_dbg(info->device, " * update DMA engine\n");
+- atmel_lcdfb_update_dma(info, &info->var);
+-
+- /* Now, the LCDC core... */
+- atmel_lcdfb_setup_core(info);
+-
+- atmel_lcdfb_start(sinfo);
+-
+- dev_dbg(info->device, " * DONE\n");
+-
+- return 0;
+-}
+-
+-static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+-{
+- chan &= 0xffff;
+- chan >>= 16 - bf->length;
+- return chan << bf->offset;
+-}
+-
+-/**
+- * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+- * @regno: Which register in the CLUT we are programming
+- * @red: The red value which can be up to 16 bits wide
+- * @green: The green value which can be up to 16 bits wide
+- * @blue: The blue value which can be up to 16 bits wide.
+- * @transp: If supported the alpha value which can be up to 16 bits wide.
+- * @info: frame buffer info structure
+- *
+- * Set a single color register. The values supplied have a 16 bit
+- * magnitude which needs to be scaled in this function for the hardware.
+- * Things to take into consideration are how many color registers, if
+- * any, are supported with the current color visual. With truecolor mode
+- * no color palettes are supported. Here a pseudo palette is created
+- * which we store the value in pseudo_palette in struct fb_info. For
+- * pseudocolor mode we have a limited color palette. To deal with this
+- * we can program what color is displayed for a particular pixel value.
+- * DirectColor is similar in that we can program each color field. If
+- * we have a static colormap we don't need to implement this function.
+- *
+- * Returns negative errno on error, or zero on success. In an
+- * ideal world, this would have been the case, but as it turns
+- * out, the other drivers return 1 on failure, so that's what
+- * we're going to do.
+- */
+-static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+- unsigned int green, unsigned int blue,
+- unsigned int transp, struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned int val;
+- u32 *pal;
+- int ret = 1;
+-
+- if (info->var.grayscale)
+- red = green = blue = (19595 * red + 38470 * green
+- + 7471 * blue) >> 16;
+-
+- switch (info->fix.visual) {
+- case FB_VISUAL_TRUECOLOR:
+- if (regno < 16) {
+- pal = info->pseudo_palette;
+-
+- val = chan_to_field(red, &info->var.red);
+- val |= chan_to_field(green, &info->var.green);
+- val |= chan_to_field(blue, &info->var.blue);
+-
+- pal[regno] = val;
+- ret = 0;
+- }
+- break;
+-
+- case FB_VISUAL_PSEUDOCOLOR:
+- if (regno < 256) {
+- if (cpu_is_at91sam9261() || cpu_is_at91sam9263()
+- || cpu_is_at91sam9rl()) {
+- /* old style I+BGR:555 */
+- val = ((red >> 11) & 0x001f);
+- val |= ((green >> 6) & 0x03e0);
+- val |= ((blue >> 1) & 0x7c00);
+-
+- /*
+- * TODO: intensity bit. Maybe something like
+- * ~(red[10] ^ green[10] ^ blue[10]) & 1
+- */
+- } else {
+- /* new style BGR:565 / RGB:565 */
+- if (sinfo->lcd_wiring_mode ==
+- ATMEL_LCDC_WIRING_RGB) {
+- val = ((blue >> 11) & 0x001f);
+- val |= ((red >> 0) & 0xf800);
+- } else {
+- val = ((red >> 11) & 0x001f);
+- val |= ((blue >> 0) & 0xf800);
+- }
+-
+- val |= ((green >> 5) & 0x07e0);
+- }
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+- ret = 0;
+- }
+- break;
+-
+- case FB_VISUAL_MONO01:
+- if (regno < 2) {
+- val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+- ret = 0;
+- }
+- break;
+-
+- }
+-
+- return ret;
+-}
+-
+-static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+- struct fb_info *info)
+-{
+- dev_dbg(info->device, "%s\n", __func__);
+-
+- atmel_lcdfb_update_dma(info, var);
+-
+- return 0;
+-}
+-
+-static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+-
+- switch (blank_mode) {
+- case FB_BLANK_UNBLANK:
+- case FB_BLANK_NORMAL:
+- atmel_lcdfb_start(sinfo);
+- break;
+- case FB_BLANK_VSYNC_SUSPEND:
+- case FB_BLANK_HSYNC_SUSPEND:
+- break;
+- case FB_BLANK_POWERDOWN:
+- atmel_lcdfb_stop(sinfo);
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- /* let fbcon do a soft blank for us */
+- return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
+-}
+-
+-static struct fb_ops atmel_lcdfb_ops = {
+- .owner = THIS_MODULE,
+- .fb_check_var = atmel_lcdfb_check_var,
+- .fb_set_par = atmel_lcdfb_set_par,
+- .fb_setcolreg = atmel_lcdfb_setcolreg,
+- .fb_blank = atmel_lcdfb_blank,
+- .fb_pan_display = atmel_lcdfb_pan_display,
+- .fb_fillrect = cfb_fillrect,
+- .fb_copyarea = cfb_copyarea,
+- .fb_imageblit = cfb_imageblit,
+-};
+-
+-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+-{
+- struct fb_info *info = dev_id;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- u32 status;
+- u32 baselayer_status;
+-
+- if (cpu_is_at91sam9x5()) {
+- /* Check for error status via interrupt.*/
+- status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
+- if (status & LCDC_LCDISR_FIFOERR) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- } else if (status & LCDC_LCDISR_BASE) {
+- /* Check base layer's overflow error. */
+- baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
+-
+- if (baselayer_status & LCDC_BASEISR_OVR)
+- dev_warn(info->device, "base layer overflow %#x\n",
+- baselayer_status);
+-
+- }
+- } else {
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+- }
+-
+- return IRQ_HANDLED;
+-}
+-
+-/*
+- * LCD controller task (to reset the LCD)
+- */
+-static void atmel_lcdfb_task(struct work_struct *work)
+-{
+- struct atmel_lcdfb_info *sinfo =
+- container_of(work, struct atmel_lcdfb_info, task);
+-
+- atmel_lcdfb_reset(sinfo);
+-}
+-
+-static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+-{
+- struct fb_info *info = sinfo->info;
+- int ret = 0;
+-
+- info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+-
+- dev_info(info->device,
+- "%luKiB frame buffer at %08lx (mapped at %p)\n",
+- (unsigned long)info->fix.smem_len / 1024,
+- (unsigned long)info->fix.smem_start,
+- info->screen_base);
+-
+- /* Allocate colormap */
+- ret = fb_alloc_cmap(&info->cmap, 256, 0);
+- if (ret < 0)
+- dev_err(info->device, "Alloc color map failed\n");
+-
+- return ret;
+-}
+-
+-static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->bus_clk)
+- clk_enable(sinfo->bus_clk);
+- clk_enable(sinfo->lcdc_clk);
+-}
+-
+-static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+-{
+- if (sinfo->bus_clk)
+- clk_disable(sinfo->bus_clk);
+- clk_disable(sinfo->lcdc_clk);
+-}
+-
+-
+-static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct fb_info *info;
+- struct atmel_lcdfb_info *sinfo;
+- struct atmel_lcdfb_info *pdata_sinfo;
+- struct fb_videomode fbmode;
+- struct resource *regs = NULL;
+- struct resource *map = NULL;
+- int ret;
+-
+- dev_dbg(dev, "%s BEGIN\n", __func__);
+-
+- ret = -ENOMEM;
+- info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+- if (!info) {
+- dev_err(dev, "cannot allocate memory\n");
+- goto out;
+- }
+-
+- sinfo = info->par;
+-
+- if (dev->platform_data) {
+- pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+- sinfo->default_bpp = pdata_sinfo->default_bpp;
+- sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+- sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+- sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+- sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+- sinfo->guard_time = pdata_sinfo->guard_time;
+- sinfo->smem_len = pdata_sinfo->smem_len;
+- sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+- sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
+- sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
+- } else {
+- dev_err(dev, "cannot get default configuration\n");
+- goto free_info;
+- }
+- sinfo->info = info;
+- sinfo->pdev = pdev;
+-
+- strcpy(info->fix.id, sinfo->pdev->name);
+- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+- info->pseudo_palette = sinfo->pseudo_palette;
+- info->fbops = &atmel_lcdfb_ops;
+-
+- memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+- info->fix = atmel_lcdfb_fix;
+-
+- /* Enable LCDC Clocks */
+- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()) {
+- sinfo->bus_clk = clk_get(dev, "hck1");
+- if (IS_ERR(sinfo->bus_clk)) {
+- ret = PTR_ERR(sinfo->bus_clk);
+- goto free_info;
+- }
+- }
+- sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+- if (IS_ERR(sinfo->lcdc_clk)) {
+- ret = PTR_ERR(sinfo->lcdc_clk);
+- goto put_bus_clk;
+- }
+- atmel_lcdfb_start_clock(sinfo);
+-
+- ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+- info->monspecs.modedb_len, info->monspecs.modedb,
+- sinfo->default_bpp);
+- if (!ret) {
+- dev_err(dev, "no suitable video mode found\n");
+- goto stop_clk;
+- }
+-
+-
+- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!regs) {
+- dev_err(dev, "resources unusable\n");
+- ret = -ENXIO;
+- goto stop_clk;
+- }
+-
+- sinfo->irq_base = platform_get_irq(pdev, 0);
+- if (sinfo->irq_base < 0) {
+- dev_err(dev, "unable to get irq\n");
+- ret = sinfo->irq_base;
+- goto stop_clk;
+- }
+-
+- /* Initialize video memory */
+- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+- sinfo->p_dma_desc = NULL;
+- sinfo->dma_desc_phys = 0;
+- if (map) {
+- /* use a pre-allocated memory buffer */
+- info->fix.smem_start = map->start;
+- info->fix.smem_len = resource_size(map);
+- if (!request_mem_region(info->fix.smem_start,
+- info->fix.smem_len, pdev->name)) {
+- ret = -EBUSY;
+- goto stop_clk;
+- }
+-
+- info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+- if (!info->screen_base)
+- goto release_intmem;
+-
+- /*
+- * Don't clear the framebuffer -- someone may have set
+- * up a splash image.
+- */
+- } else {
+- /* alocate memory buffer */
+- ret = atmel_lcdfb_alloc_video_memory(sinfo);
+- if (ret < 0) {
+- dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+- goto stop_clk;
+- }
+- }
+-
+- /* LCDC registers */
+- info->fix.mmio_start = regs->start;
+- info->fix.mmio_len = resource_size(regs);
+-
+- if (!request_mem_region(info->fix.mmio_start,
+- info->fix.mmio_len, pdev->name)) {
+- ret = -EBUSY;
+- goto free_fb;
+- }
+-
+- sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+- if (!sinfo->mmio) {
+- dev_err(dev, "cannot map LCDC registers\n");
+- goto release_mem;
+- }
+-
+- /* Initialize PWM for contrast or backlight ("off") */
+- init_contrast(sinfo);
+-
+- /* interrupt */
+- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+- if (ret) {
+- dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
+- }
+-
+- /* Some operations on the LCDC might sleep and
+- * require a preemptible task context */
+- INIT_WORK(&sinfo->task, atmel_lcdfb_task);
+-
+- ret = atmel_lcdfb_init_fbinfo(sinfo);
+- if (ret < 0) {
+- dev_err(dev, "init fbinfo failed: %d\n", ret);
+- goto unregister_irqs;
+- }
+-
+- /*
+- * This makes sure that our colour bitfield
+- * descriptors are correctly initialised.
+- */
+- atmel_lcdfb_check_var(&info->var, info);
+-
+- ret = fb_set_var(info, &info->var);
+- if (ret) {
+- dev_warn(dev, "unable to set display parameters\n");
+- goto free_cmap;
+- }
+-
+- dev_set_drvdata(dev, info);
+-
+- /*
+- * Tell the world that we're ready to go
+- */
+- ret = register_framebuffer(info);
+- if (ret < 0) {
+- dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+- goto reset_drvdata;
+- }
+-
+- /* add selected videomode to modelist */
+- fb_var_to_videomode(&fbmode, &info->var);
+- fb_add_videomode(&fbmode, &info->modelist);
+-
+- /* Power up the LCDC screen */
+- if (sinfo->atmel_lcdfb_power_control)
+- sinfo->atmel_lcdfb_power_control(1);
+-
+- dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
+- info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+-
+- return 0;
+-
+-reset_drvdata:
+- dev_set_drvdata(dev, NULL);
+-free_cmap:
+- fb_dealloc_cmap(&info->cmap);
+-unregister_irqs:
+- cancel_work_sync(&sinfo->task);
+- free_irq(sinfo->irq_base, info);
+-unmap_mmio:
+- exit_backlight(sinfo);
+- iounmap(sinfo->mmio);
+-release_mem:
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+-free_fb:
+- if (map)
+- iounmap(info->screen_base);
+- else
+- atmel_lcdfb_free_video_memory(sinfo);
+-
+-release_intmem:
+- if (map)
+- release_mem_region(info->fix.smem_start, info->fix.smem_len);
+-stop_clk:
+- atmel_lcdfb_stop_clock(sinfo);
+- clk_put(sinfo->lcdc_clk);
+-put_bus_clk:
+- if (sinfo->bus_clk)
+- clk_put(sinfo->bus_clk);
+-free_info:
+- framebuffer_release(info);
+-out:
+- dev_dbg(dev, "%s FAILED\n", __func__);
+- return ret;
+-}
+-
+-static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+-{
+- struct device *dev = &pdev->dev;
+- struct fb_info *info = dev_get_drvdata(dev);
+- struct atmel_lcdfb_info *sinfo;
+-
+- if (!info || !info->par)
+- return 0;
+- sinfo = info->par;
+-
+- cancel_work_sync(&sinfo->task);
+- exit_backlight(sinfo);
+- if (sinfo->atmel_lcdfb_power_control)
+- sinfo->atmel_lcdfb_power_control(0);
+- unregister_framebuffer(info);
+- atmel_lcdfb_stop_clock(sinfo);
+- clk_put(sinfo->lcdc_clk);
+- if (sinfo->bus_clk)
+- clk_put(sinfo->bus_clk);
+- fb_dealloc_cmap(&info->cmap);
+- free_irq(sinfo->irq_base, info);
+- iounmap(sinfo->mmio);
+- release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+- if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+- iounmap(info->screen_base);
+- release_mem_region(info->fix.smem_start, info->fix.smem_len);
+- } else {
+- atmel_lcdfb_free_video_memory(sinfo);
+- }
+-
+- dev_set_drvdata(dev, NULL);
+- framebuffer_release(info);
+-
+- return 0;
+-}
+
+ #ifdef CONFIG_PM
+
+@@ -1417,16 +28,10 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ * We don't want to handle interrupts while the clock is
+ * stopped. It may take forever.
+ */
+- if (cpu_is_at91sam9x5()) {
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+- sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+- }
++ sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
+
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+@@ -1447,17 +52,11 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+
+- if (cpu_is_at91sam9x5()) {
+- /* Enable fifo error & BASE LAYER overflow interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE | LCDC_LCDIER_BASEIE);
+- } else {
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
+
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
+- | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+- }
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
++ | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+
+ return 0;
+ }
+@@ -1467,6 +66,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ #define atmel_lcdfb_resume NULL
+ #endif
+
++static int __init atmel_lcdfb_probe(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_probe(pdev);
++}
++static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_remove(pdev);
++}
++
+ static struct platform_driver atmel_lcdfb_driver = {
+ .remove = __exit_p(atmel_lcdfb_remove),
+ .suspend = atmel_lcdfb_suspend,
+@@ -1482,13 +90,12 @@ static int __init atmel_lcdfb_init(void)
+ {
+ return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+ }
++module_init(atmel_lcdfb_init);
+
+ static void __exit atmel_lcdfb_exit(void)
+ {
+ platform_driver_unregister(&atmel_lcdfb_driver);
+ }
+-
+-module_init(atmel_lcdfb_init);
+ module_exit(atmel_lcdfb_exit);
+
+ MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+new file mode 100644
+index 0000000..54bdbcb
+--- /dev/null
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -0,0 +1,1077 @@
++/*
++ * Driver for AT91/AT32 LCD Controller
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/backlight.h>
++#include <linux/gfp.h>
++
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/gpio.h>
++
++#include <video/atmel_lcdc.h>
++
++/* configurable parameters */
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
++
++#if defined(CONFIG_ARCH_AT91)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++
++}
++#elif defined(CONFIG_AVR32)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_XPAN \
++ | FBINFO_HWACCEL_YPAN)
++
++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++ u32 dma2dcfg;
++ u32 pixeloff;
++
++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
++
++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
++
++ /* Update configuration */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
++ | ATMEL_LCDC_DMAUPDT);
++}
++#endif
++
++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
++ | ATMEL_LCDC_POL_POSITIVE
++ | ATMEL_LCDC_ENA_PWMENABLE;
++
++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++}
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void init_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ struct backlight_properties props;
++ struct backlight_device *bl;
++
++ sinfo->bl_power = FB_BLANK_UNBLANK;
++
++ if (sinfo->backlight)
++ return;
++
++ memset(&props, 0, sizeof(struct backlight_properties));
++ props.type = BACKLIGHT_RAW;
++ props.max_brightness = 0xff;
++ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
++ &atmel_lcdc_bl_ops, &props);
++ if (IS_ERR(bl)) {
++ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
++ PTR_ERR(bl));
++ return;
++ }
++ sinfo->backlight = bl;
++
++ bl->props.power = FB_BLANK_UNBLANK;
++ bl->props.fb_blank = FB_BLANK_UNBLANK;
++ bl->props.brightness = atmel_bl_get_brightness(bl);
++}
++
++static void exit_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->backlight)
++ backlight_device_unregister(sinfo->backlight);
++}
++
++#else
++
++static void init_backlight(struct atmel_lcdfb_info *sinfo)
++{
++ dev_warn(&sinfo->pdev->dev, "backlight control is not available\n");
++}
++
++static void exit_backlight(struct atmel_lcdfb_info *sinfo)
++{
++}
++
++#endif
++
++static void init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++
++ if (sinfo->lcdcon_is_backlight)
++ init_backlight(sinfo);
++}
++
++
++static struct fb_fix_screeninfo atmel_lcdfb_fix = {
++ .type = FB_TYPE_PACKED_PIXELS,
++ .visual = FB_VISUAL_TRUECOLOR,
++ .xpanstep = 0,
++ .ypanstep = 1,
++ .ywrapstep = 0,
++ .accel = FB_ACCEL_NONE,
++};
++
++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
++{
++ unsigned long value;
++
++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()))
++ return xres;
++
++ value = xres;
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
++ /* STN display */
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
++ value *= 3;
++ }
++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
++ value = DIV_ROUND_UP(value, 4);
++ else
++ value = DIV_ROUND_UP(value, 8);
++ }
++
++ return value;
++}
++
++static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
++{
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++}
++
++void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
++{
++ atmel_lcdfb_stop_nowait(sinfo);
++
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
++
++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
++
++static void atmel_lcdfb_update_dma(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++
++ atmel_lcdfb_update_dma2d(sinfo, var);
++}
++
++static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++}
++
++/**
++ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
++ * @sinfo: the frame buffer to allocate memory for
++ *
++ * This function is called only from the atmel_lcdfb_probe()
++ * so no locking by fb_info->mm_lock around smem_len setting is needed.
++ */
++static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++ struct fb_var_screeninfo *var = &info->var;
++ unsigned int smem_len;
++
++ smem_len = (var->xres_virtual * var->yres_virtual
++ * ((var->bits_per_pixel + 7) / 8));
++ info->fix.smem_len = max(smem_len, sinfo->smem_len);
++
++ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
++ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
++
++ if (!info->screen_base) {
++ return -ENOMEM;
++ }
++
++ memset(info->screen_base, 0, info->fix.smem_len);
++
++ return 0;
++}
++
++static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ struct fb_videomode varfbmode;
++ const struct fb_videomode *fbmode = NULL;
++
++ fb_var_to_videomode(&varfbmode, var);
++ fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
++ if (fbmode)
++ fb_videomode_to_var(var, fbmode);
++ return fbmode;
++}
++
++
++/**
++ * atmel_lcdfb_check_var - Validates a var passed in.
++ * @var: frame buffer variable screen structure
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Checks to see if the hardware supports the state requested by
++ * var passed in. This function does not alter the hardware
++ * state!!! This means the data stored in struct fb_info and
++ * struct atmel_lcdfb_info do not change. This includes the var
++ * inside of struct fb_info. Do NOT change these. This function
++ * can be called on its own if we intent to only test a mode and
++ * not actually set it. The stuff in modedb.c is a example of
++ * this. If the var passed in is slightly off by what the
++ * hardware can support then we alter the var PASSED in to what
++ * we can do. If the hardware doesn't support mode change a
++ * -EINVAL will be returned by the upper layers. You don't need
++ * to implement this function then. If you hardware doesn't
++ * support changing the resolution then this function is not
++ * needed. In this case the driver would just provide a var that
++ * represents the static state the screen is in.
++ *
++ * Returns negative errno on error, or zero on success.
++ */
++static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ struct device *dev = info->device;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long clk_value_khz;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ dev_dbg(dev, "%s:\n", __func__);
++
++ if (!(var->pixclock && var->bits_per_pixel)) {
++ /* choose a suitable mode if possible */
++ if (!atmel_lcdfb_choose_mode(var, info)) {
++ dev_err(dev, "needed value not specified\n");
++ return -EINVAL;
++ }
++ }
++
++ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
++ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
++ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
++ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
++
++ if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
++ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
++ return -EINVAL;
++ }
++
++ /* Do not allow to have real resoulution larger than virtual */
++ if (var->xres > var->xres_virtual)
++ var->xres_virtual = var->xres;
++
++ if (var->yres > var->yres_virtual)
++ var->yres_virtual = var->yres;
++
++ /* Force same alignment for each line */
++ var->xres = (var->xres + 3) & ~3UL;
++ var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
++
++ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
++ var->transp.msb_right = 0;
++ var->transp.offset = var->transp.length = 0;
++ var->xoffset = var->yoffset = 0;
++
++ if (info->fix.smem_len) {
++ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
++ * ((var->bits_per_pixel + 7) / 8));
++ if (smem_len > info->fix.smem_len)
++ return -EINVAL;
++ }
++
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++
++ /* Some parameters can't be zero */
++ var->vsync_len = max_t(u32, var->vsync_len, 1);
++ var->right_margin = max_t(u32, var->right_margin, 1);
++ var->hsync_len = max_t(u32, var->hsync_len, 1);
++ var->left_margin = max_t(u32, var->left_margin, 1);
++
++ switch (var->bits_per_pixel) {
++ case 1:
++ case 2:
++ case 4:
++ case 8:
++ var->red.offset = var->green.offset = var->blue.offset = 0;
++ var->red.length = var->green.length = var->blue.length
++ = var->bits_per_pixel;
++ break;
++ case 15:
++ case 16:
++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
++ /* RGB:565 mode */
++ var->red.offset = 11;
++ var->blue.offset = 0;
++ var->green.length = 6;
++ } else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
++ var->red.offset = 10;
++ var->blue.offset = 0;
++ var->green.length = 5;
++ } else {
++ /* BGR:555 mode */
++ var->red.offset = 0;
++ var->blue.offset = 10;
++ var->green.length = 5;
++ }
++ var->green.offset = 5;
++ var->red.length = var->blue.length = 5;
++ break;
++ case 32:
++ var->transp.offset = 24;
++ var->transp.length = 8;
++ /* fall through */
++ case 24:
++ if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) {
++ /* RGB:888 mode */
++ var->red.offset = 16;
++ var->blue.offset = 0;
++ } else {
++ /* BGR:888 mode */
++ var->red.offset = 0;
++ var->blue.offset = 16;
++ }
++ var->green.offset = 8;
++ var->red.length = var->green.length = var->blue.length = 8;
++ break;
++ default:
++ dev_err(dev, "color depth %d not supported\n",
++ var->bits_per_pixel);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++/*
++ * LCD reset sequence
++ */
++static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
++{
++ might_sleep();
++
++ atmel_lcdfb_stop(sinfo);
++ atmel_lcdfb_start(sinfo);
++}
++
++/**
++ * atmel_lcdfb_set_par - Alters the hardware state.
++ * @info: frame buffer structure that represents a single frame buffer
++ *
++ * Using the fb_var_screeninfo in fb_info we set the resolution
++ * of the this particular framebuffer. This function alters the
++ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
++ * not alter var in fb_info since we are using that data. This
++ * means we depend on the data in var inside fb_info to be
++ * supported by the hardware. atmel_lcdfb_check_var is always called
++ * before atmel_lcdfb_set_par to ensure this. Again if you can't
++ * change the resolution you don't need this function.
++ *
++ */
++static int atmel_lcdfb_set_par(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long bits_per_line;
++ unsigned long pix_factor = 2;
++
++ might_sleep();
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
++ info->var.xres, info->var.yres,
++ info->var.xres_virtual, info->var.yres_virtual);
++
++ atmel_lcdfb_stop_nowait(sinfo);
++
++ if (info->var.bits_per_pixel == 1)
++ info->fix.visual = FB_VISUAL_MONO01;
++ else if (info->var.bits_per_pixel <= 8)
++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++ else
++ info->fix.visual = FB_VISUAL_TRUECOLOR;
++
++ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
++ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
++
++ /* Re-initialize the DMA engine... */
++ dev_dbg(info->device, " * update DMA engine\n");
++ atmel_lcdfb_update_dma(info, &info->var);
++
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Now, the LCDC core... */
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
++ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
++ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
++ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
++ case 15: /* fall through */
++ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
++ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
++ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
++ default: BUG(); break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ atmel_lcdfb_start(sinfo);
++
++ dev_dbg(info->device, " * DONE\n");
++
++ return 0;
++}
++
++static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
++{
++ chan &= 0xffff;
++ chan >>= 16 - bf->length;
++ return chan << bf->offset;
++}
++
++/**
++ * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
++ * @regno: Which register in the CLUT we are programming
++ * @red: The red value which can be up to 16 bits wide
++ * @green: The green value which can be up to 16 bits wide
++ * @blue: The blue value which can be up to 16 bits wide.
++ * @transp: If supported the alpha value which can be up to 16 bits wide.
++ * @info: frame buffer info structure
++ *
++ * Set a single color register. The values supplied have a 16 bit
++ * magnitude which needs to be scaled in this function for the hardware.
++ * Things to take into consideration are how many color registers, if
++ * any, are supported with the current color visual. With truecolor mode
++ * no color palettes are supported. Here a pseudo palette is created
++ * which we store the value in pseudo_palette in struct fb_info. For
++ * pseudocolor mode we have a limited color palette. To deal with this
++ * we can program what color is displayed for a particular pixel value.
++ * DirectColor is similar in that we can program each color field. If
++ * we have a static colormap we don't need to implement this function.
++ *
++ * Returns negative errno on error, or zero on success. In an
++ * ideal world, this would have been the case, but as it turns
++ * out, the other drivers return 1 on failure, so that's what
++ * we're going to do.
++ */
++static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned int val;
++ u32 *pal;
++ int ret = 1;
++
++ if (info->var.grayscale)
++ red = green = blue = (19595 * red + 38470 * green
++ + 7471 * blue) >> 16;
++
++ switch (info->fix.visual) {
++ case FB_VISUAL_TRUECOLOR:
++ if (regno < 16) {
++ pal = info->pseudo_palette;
++
++ val = chan_to_field(red, &info->var.red);
++ val |= chan_to_field(green, &info->var.green);
++ val |= chan_to_field(blue, &info->var.blue);
++
++ pal[regno] = val;
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_PSEUDOCOLOR:
++ if (regno < 256) {
++ val = ((red >> 11) & 0x001f);
++ val |= ((green >> 6) & 0x03e0);
++ val |= ((blue >> 1) & 0x7c00);
++
++ /*
++ * TODO: intensity bit. Maybe something like
++ * ~(red[10] ^ green[10] ^ blue[10]) & 1
++ */
++
++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_MONO01:
++ if (regno < 2) {
++ val = (regno == 0) ? 0x00 : 0x1F;
++ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ ret = 0;
++ }
++ break;
++
++ }
++
++ return ret;
++}
++
++static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ dev_dbg(info->device, "%s\n", __func__);
++
++ atmel_lcdfb_update_dma(info, var);
++
++ return 0;
++}
++
++static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ switch (blank_mode) {
++ case FB_BLANK_UNBLANK:
++ case FB_BLANK_NORMAL:
++ atmel_lcdfb_start(sinfo);
++ break;
++ case FB_BLANK_VSYNC_SUSPEND:
++ case FB_BLANK_HSYNC_SUSPEND:
++ break;
++ case FB_BLANK_POWERDOWN:
++ atmel_lcdfb_stop(sinfo);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* let fbcon do a soft blank for us */
++ return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0);
++}
++
++static struct fb_ops atmel_lcdfb_ops = {
++ .owner = THIS_MODULE,
++ .fb_check_var = atmel_lcdfb_check_var,
++ .fb_set_par = atmel_lcdfb_set_par,
++ .fb_setcolreg = atmel_lcdfb_setcolreg,
++ .fb_blank = atmel_lcdfb_blank,
++ .fb_pan_display = atmel_lcdfb_pan_display,
++ .fb_fillrect = cfb_fillrect,
++ .fb_copyarea = cfb_copyarea,
++ .fb_imageblit = cfb_imageblit,
++};
++
++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status;
++
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++ return IRQ_HANDLED;
++}
++
++/*
++ * LCD controller task (to reset the LCD)
++ */
++static void atmel_lcdfb_task(struct work_struct *work)
++{
++ struct atmel_lcdfb_info *sinfo =
++ container_of(work, struct atmel_lcdfb_info, task);
++
++ atmel_lcdfb_reset(sinfo);
++}
++
++static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
++{
++ struct fb_info *info = sinfo->info;
++ int ret = 0;
++
++ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
++
++ dev_info(info->device,
++ "%luKiB frame buffer at %08lx (mapped at %p)\n",
++ (unsigned long)info->fix.smem_len / 1024,
++ (unsigned long)info->fix.smem_start,
++ info->screen_base);
++
++ /* Allocate colormap */
++ ret = fb_alloc_cmap(&info->cmap, 256, 0);
++ if (ret < 0)
++ dev_err(info->device, "Alloc color map failed\n");
++
++ return ret;
++}
++
++void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->bus_clk)
++ clk_enable(sinfo->bus_clk);
++ clk_enable(sinfo->lcdc_clk);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_start_clock);
++
++void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
++{
++ if (sinfo->bus_clk)
++ clk_disable(sinfo->bus_clk);
++ clk_disable(sinfo->lcdc_clk);
++}
++EXPORT_SYMBOL_GPL(atmel_lcdfb_stop_clock);
++
++
++int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *dev_data)
++{
++ struct device *dev = &pdev->dev;
++ struct fb_info *info;
++ struct atmel_lcdfb_info *sinfo;
++ struct atmel_lcdfb_info *pdata_sinfo;
++ struct fb_videomode fbmode;
++ struct resource *regs = NULL;
++ struct resource *map = NULL;
++ int ret;
++
++ dev_dbg(dev, "%s BEGIN\n", __func__);
++
++ ret = -ENOMEM;
++ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
++ if (!info) {
++ dev_err(dev, "cannot allocate memory\n");
++ goto out;
++ }
++
++ sinfo = info->par;
++
++ if (dev->platform_data) {
++ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
++ sinfo->default_bpp = pdata_sinfo->default_bpp;
++ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
++ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
++ sinfo->default_monspecs = pdata_sinfo->default_monspecs;
++ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
++ sinfo->guard_time = pdata_sinfo->guard_time;
++ sinfo->smem_len = pdata_sinfo->smem_len;
++ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
++ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
++ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
++ } else {
++ dev_err(dev, "cannot get default configuration\n");
++ goto free_info;
++ }
++ sinfo->info = info;
++ sinfo->pdev = pdev;
++
++ strcpy(info->fix.id, sinfo->pdev->name);
++ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
++ info->pseudo_palette = sinfo->pseudo_palette;
++ info->fbops = &atmel_lcdfb_ops;
++
++ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
++ info->fix = atmel_lcdfb_fix;
++
++ /* Enable LCDC Clocks */
++ if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()) {
++ sinfo->bus_clk = clk_get(dev, "hck1");
++ if (IS_ERR(sinfo->bus_clk)) {
++ ret = PTR_ERR(sinfo->bus_clk);
++ goto free_info;
++ }
++ }
++ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
++ if (IS_ERR(sinfo->lcdc_clk)) {
++ ret = PTR_ERR(sinfo->lcdc_clk);
++ goto put_bus_clk;
++ }
++ atmel_lcdfb_start_clock(sinfo);
++
++ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
++ info->monspecs.modedb_len, info->monspecs.modedb,
++ sinfo->default_bpp);
++ if (!ret) {
++ dev_err(dev, "no suitable video mode found\n");
++ goto stop_clk;
++ }
++
++
++ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!regs) {
++ dev_err(dev, "resources unusable\n");
++ ret = -ENXIO;
++ goto stop_clk;
++ }
++
++ sinfo->irq_base = platform_get_irq(pdev, 0);
++ if (sinfo->irq_base < 0) {
++ dev_err(dev, "unable to get irq\n");
++ ret = sinfo->irq_base;
++ goto stop_clk;
++ }
++
++ /* Initialize video memory */
++ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (map) {
++ /* use a pre-allocated memory buffer */
++ info->fix.smem_start = map->start;
++ info->fix.smem_len = map->end - map->start + 1;
++ if (!request_mem_region(info->fix.smem_start,
++ info->fix.smem_len, pdev->name)) {
++ ret = -EBUSY;
++ goto stop_clk;
++ }
++
++ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
++ if (!info->screen_base)
++ goto release_intmem;
++
++ /*
++ * Don't clear the framebuffer -- someone may have set
++ * up a splash image.
++ */
++ } else {
++ /* alocate memory buffer */
++ ret = atmel_lcdfb_alloc_video_memory(sinfo);
++ if (ret < 0) {
++ dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
++ goto stop_clk;
++ }
++ }
++
++ /* LCDC registers */
++ info->fix.mmio_start = regs->start;
++ info->fix.mmio_len = regs->end - regs->start + 1;
++
++ if (!request_mem_region(info->fix.mmio_start,
++ info->fix.mmio_len, pdev->name)) {
++ ret = -EBUSY;
++ goto free_fb;
++ }
++
++ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
++ if (!sinfo->mmio) {
++ dev_err(dev, "cannot map LCDC registers\n");
++ goto release_mem;
++ }
++
++ /* Initialize PWM for contrast or backlight ("off") */
++ init_contrast(sinfo);
++
++ /* interrupt */
++ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
++ if (ret) {
++ dev_err(dev, "request_irq failed: %d\n", ret);
++ goto unmap_mmio;
++ }
++
++ /* Some operations on the LCDC might sleep and
++ * require a preemptible task context */
++ INIT_WORK(&sinfo->task, atmel_lcdfb_task);
++
++ ret = atmel_lcdfb_init_fbinfo(sinfo);
++ if (ret < 0) {
++ dev_err(dev, "init fbinfo failed: %d\n", ret);
++ goto unregister_irqs;
++ }
++
++ /*
++ * This makes sure that our colour bitfield
++ * descriptors are correctly initialised.
++ */
++ atmel_lcdfb_check_var(&info->var, info);
++
++ ret = fb_set_var(info, &info->var);
++ if (ret) {
++ dev_warn(dev, "unable to set display parameters\n");
++ goto free_cmap;
++ }
++
++ dev_set_drvdata(dev, info);
++
++ /*
++ * Tell the world that we're ready to go
++ */
++ ret = register_framebuffer(info);
++ if (ret < 0) {
++ dev_err(dev, "failed to register framebuffer device: %d\n", ret);
++ goto reset_drvdata;
++ }
++
++ /* add selected videomode to modelist */
++ fb_var_to_videomode(&fbmode, &info->var);
++ fb_add_videomode(&fbmode, &info->modelist);
++
++ /* Power up the LCDC screen */
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(1);
++
++ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
++ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
++
++ return 0;
++
++reset_drvdata:
++ dev_set_drvdata(dev, NULL);
++free_cmap:
++ fb_dealloc_cmap(&info->cmap);
++unregister_irqs:
++ cancel_work_sync(&sinfo->task);
++ free_irq(sinfo->irq_base, info);
++unmap_mmio:
++ exit_backlight(sinfo);
++ iounmap(sinfo->mmio);
++release_mem:
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++free_fb:
++ if (map)
++ iounmap(info->screen_base);
++ else
++ atmel_lcdfb_free_video_memory(sinfo);
++
++release_intmem:
++ if (map)
++ release_mem_region(info->fix.smem_start, info->fix.smem_len);
++stop_clk:
++ atmel_lcdfb_stop_clock(sinfo);
++ clk_put(sinfo->lcdc_clk);
++put_bus_clk:
++ if (sinfo->bus_clk)
++ clk_put(sinfo->bus_clk);
++free_info:
++ framebuffer_release(info);
++out:
++ dev_dbg(dev, "%s FAILED\n", __func__);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(__atmel_lcdfb_probe);
++
++int __atmel_lcdfb_remove(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct fb_info *info = dev_get_drvdata(dev);
++ struct atmel_lcdfb_info *sinfo;
++
++ if (!info || !info->par)
++ return 0;
++ sinfo = info->par;
++
++ cancel_work_sync(&sinfo->task);
++ exit_backlight(sinfo);
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(0);
++ unregister_framebuffer(info);
++ atmel_lcdfb_stop_clock(sinfo);
++ clk_put(sinfo->lcdc_clk);
++ if (sinfo->bus_clk)
++ clk_put(sinfo->bus_clk);
++ fb_dealloc_cmap(&info->cmap);
++ free_irq(sinfo->irq_base, info);
++ iounmap(sinfo->mmio);
++ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
++ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
++ iounmap(info->screen_base);
++ release_mem_region(info->fix.smem_start, info->fix.smem_len);
++ } else {
++ atmel_lcdfb_free_video_memory(sinfo);
++ }
++
++ dev_set_drvdata(dev, NULL);
++ framebuffer_release(info);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove);
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 5183ab7..4fa084b 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -32,6 +32,13 @@
+ #define ATMEL_LCDC_WIRING_RGB 1
+ #define ATMEL_LCDC_WIRING_RGB555 2
+
++extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
++
++extern int __atmel_lcdfb_probe(struct platform_device *pdev);
++extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
+ /* LCD Controller info data structure, stored in device platform_data */
+ struct atmel_lcdfb_info {
+@@ -47,9 +54,6 @@ struct atmel_lcdfb_info {
+ struct clk *bus_clk;
+ struct clk *lcdc_clk;
+
+- struct lcd_dma_desc *p_dma_desc;
+- dma_addr_t dma_desc_phys;
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+ struct backlight_device *backlight;
+ u8 bl_power;
+@@ -68,11 +72,8 @@ struct atmel_lcdfb_info {
+ u32 pseudo_palette[16];
+ };
+
+-struct lcd_dma_desc {
+- u32 address;
+- u32 control;
+- u32 next;
+-};
++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 564ee162bc8282b9ce6989d2338dcca66d5fbaec Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:23:00 +0200
-Subject: video: atmel_lcdfb: adapt to all IP configurations
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 3 +--
- drivers/video/atmel_hlcdfb.c | 14 ++++++++++++--
- 2 files changed, 13 insertions(+), 4 deletions(-)
-
-diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-index 738a853..71ccb96 100644
---- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-+++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
-@@ -157,8 +157,7 @@
- #define LCDC_LCDISR_BASE (0x1 << 8)
- #define LCDC_LCDISR_OVR1 (0x1 << 9)
- #define LCDC_LCDISR_OVR2 (0x1 << 10)
--#define LCDC_LCDISR_HEO (0x1 << 10)
--#define LCDC2_LCDISR_HEO (0x1 << 11)
-+#define LCDC_LCDISR_HEO (0x1 << 11)
- #define LCDC_LCDISR_HCR (0x1 << 12)
- #define LCDC_LCDISR_PP (0x1 << 13)
-
-diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
-index db6ec3e..262c15b 100644
---- a/drivers/video/atmel_hlcdfb.c
-+++ b/drivers/video/atmel_hlcdfb.c
-@@ -370,6 +370,16 @@ static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
- }
- static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
- {
-+ u32 hbpw, hfpw;
-+
-+ if (cpu_is_at91sam9x5()) {
-+ hbpw = LCDC_LCDCFG3_HBPW;
-+ hfpw = LCDC_LCDCFG3_HFPW;
-+ } else {
-+ hbpw = LCDC2_LCDCFG3_HBPW;
-+ hfpw = LCDC2_LCDCFG3_HFPW;
-+ }
-+
- /* Saturate vertical and horizontal timings at maximum values */
- var->vsync_len = min_t(u32, var->vsync_len,
- (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
-@@ -378,11 +388,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
- var->lower_margin = min_t(u32, var->lower_margin,
- LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
- var->right_margin = min_t(u32, var->right_margin,
-- (LCDC2_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
-+ (hbpw >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
- var->hsync_len = min_t(u32, var->hsync_len,
- (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
- var->left_margin = min_t(u32, var->left_margin,
-- (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-+ (hfpw >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
-
- }
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 69e93611104cfbc122ce9058de6c418018f550ba Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 14:29:36 +0200
+Subject: video: atmelfb: refactor core setup
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 158 ++++++++++++++++++++++++++++++++++++++-
+ drivers/video/atmel_lcdfb_core.c | 126 +------------------------------
+ include/video/atmel_lcdc.h | 8 +-
+ 3 files changed, 166 insertions(+), 126 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 4e1454c..85063d6 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -12,12 +12,162 @@
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/fb.h>
++#include <linux/clk.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+
++#include <mach/board.h>
++#include <mach/cpu.h>
++
+ #include <video/atmel_lcdc.h>
+
+-#ifdef CONFIG_PM
++/* configurable parameters */
++#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
++#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
++
++static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
++{
++ unsigned long value;
++
++ if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
++ || cpu_is_at32ap7000()))
++ return xres;
++
++ value = xres;
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
++ /* STN display */
++ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
++ value *= 3;
++ }
++ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
++ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
++ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
++ value = DIV_ROUND_UP(value, 4);
++ else
++ value = DIV_ROUND_UP(value, 8);
++ }
++
++ return value;
++}
++
++static int atmel_lcdfb_setup_core(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long hozval_linesz;
++ unsigned long value;
++ unsigned long clk_value_khz;
++ unsigned long pix_factor = 2;
++
++ /* ...set frame size and burst length = 8 words (?) */
++ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
++ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
++ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
++
++ /* Set pixel clock */
++ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
++ pix_factor = 1;
++
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < pix_factor) {
++ dev_notice(info->device, "Bypassing pixel clock divider\n");
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
++ } else {
++ value = (value / pix_factor) - 1;
++ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
++ value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
++ value << ATMEL_LCDC_CLKVAL_OFFSET);
++ info->var.pixclock =
++ KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ }
++
++
++ /* Initialize control register 2 */
++ value = sinfo->default_lcdcon2;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= ATMEL_LCDC_INVLINE_INVERTED;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= ATMEL_LCDC_INVFRAME_INVERTED;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value |= ATMEL_LCDC_PIXELSIZE_1;
++ break;
++ case 2:
++ value |= ATMEL_LCDC_PIXELSIZE_2;
++ break;
++ case 4:
++ value |= ATMEL_LCDC_PIXELSIZE_4;
++ break;
++ case 8:
++ value |= ATMEL_LCDC_PIXELSIZE_8;
++ break;
++ case 15: /* fall through */
++ case 16:
++ value |= ATMEL_LCDC_PIXELSIZE_16;
++ break;
++ case 24:
++ value |= ATMEL_LCDC_PIXELSIZE_24;
++ break;
++ case 32:
++ value |= ATMEL_LCDC_PIXELSIZE_32;
++ break;
++ default:
++ BUG();
++ break;
++ }
++ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
++
++ /* Vertical timing */
++ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
++ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
++ value |= info->var.lower_margin;
++ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
++
++ /* Horizontal timing */
++ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
++ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
++ value |= (info->var.left_margin - 1);
++ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
++
++ /* Horizontal value (aka line size) */
++ hozval_linesz = compute_hozval(info->var.xres,
++ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
++
++ /* Display size */
++ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
++ value |= info->var.yres - 1;
++ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
++
++ /* FIFO Threshold: Use formula from data sheet */
++ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
++ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
++
++ /* Toggle LCD_MODE every frame */
++ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
++ /* Enable FIFO & DMA errors */
++ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
++
++ /* ...wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++
++ return 0;
++}
++
+
+ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ {
+@@ -66,9 +216,13 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+ #define atmel_lcdfb_resume NULL
+ #endif
+
++static struct atmel_lcdfb_devdata dev_data = {
++ .setup_core = atmel_lcdfb_setup_core,
++};
++
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+ {
+- return __atmel_lcdfb_probe(pdev);
++ return __atmel_lcdfb_probe(pdev, &dev_data);
+ }
+ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+ {
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 54bdbcb..9a7c5eb 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -27,8 +27,6 @@
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+-#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+-#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
+ #if defined(CONFIG_ARCH_AT91)
+ #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+@@ -183,31 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+-{
+- unsigned long value;
+-
+- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
+- || cpu_is_at32ap7000()))
+- return xres;
+-
+- value = xres;
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+- /* STN display */
+- if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+- value *= 3;
+- }
+- if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+- || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+- && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+- value = DIV_ROUND_UP(value, 4);
+- else
+- value = DIV_ROUND_UP(value, 8);
+- }
+-
+- return value;
+-}
+-
+ static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+ {
+ /* Turn off the LCD controller and the DMA controller */
+@@ -487,11 +460,7 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ static int atmel_lcdfb_set_par(struct fb_info *info)
+ {
+ struct atmel_lcdfb_info *sinfo = info->par;
+- unsigned long hozval_linesz;
+- unsigned long value;
+- unsigned long clk_value_khz;
+ unsigned long bits_per_line;
+- unsigned long pix_factor = 2;
+
+ might_sleep();
+
+@@ -516,98 +485,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+- /* ...set frame size and burst length = 8 words (?) */
+- value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+- value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+- lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+-
+ /* Now, the LCDC core... */
+-
+- /* Set pixel clock */
+- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+- pix_factor = 1;
+-
+- clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+-
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+-
+- if (value < pix_factor) {
+- dev_notice(info->device, "Bypassing pixel clock divider\n");
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+- } else {
+- value = (value / pix_factor) - 1;
+- dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n",
+- value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1,
+- value << ATMEL_LCDC_CLKVAL_OFFSET);
+- info->var.pixclock =
+- KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1)));
+- dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+- PICOS2KHZ(info->var.pixclock));
+- }
+-
+-
+- /* Initialize control register 2 */
+- value = sinfo->default_lcdcon2;
+-
+- if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+- value |= ATMEL_LCDC_INVLINE_INVERTED;
+- if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+- value |= ATMEL_LCDC_INVFRAME_INVERTED;
+-
+- switch (info->var.bits_per_pixel) {
+- case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+- case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+- case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+- case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+- case 15: /* fall through */
+- case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+- case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+- case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+- default: BUG(); break;
+- }
+- dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+-
+- /* Vertical timing */
+- value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+- value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+- value |= info->var.lower_margin;
+- dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+-
+- /* Horizontal timing */
+- value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+- value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+- value |= (info->var.left_margin - 1);
+- dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+-
+- /* Horizontal value (aka line size) */
+- hozval_linesz = compute_hozval(info->var.xres,
+- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+-
+- /* Display size */
+- value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+- value |= info->var.yres - 1;
+- dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
+- lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+-
+- /* FIFO Threshold: Use formula from data sheet */
+- value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+- lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+-
+- /* Toggle LCD_MODE every frame */
+- lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+-
+- /* Disable all interrupts */
+- lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+- /* Enable FIFO & DMA errors */
+- lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
+-
+- /* ...wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
++ sinfo->dev_data->setup_core(info);
+
+ atmel_lcdfb_start(sinfo);
+
+@@ -837,7 +716,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+
+ sinfo = info->par;
+
+- if (dev->platform_data) {
++ if (dev->platform_data && dev_data) {
+ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+ sinfo->default_bpp = pdata_sinfo->default_bpp;
+ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+@@ -849,6 +728,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
+ sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative;
+ sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
++ sinfo->dev_data = dev_data;
+ } else {
+ dev_err(dev, "cannot get default configuration\n");
+ goto free_info;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 4fa084b..b1a5fad1 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -37,15 +37,21 @@ extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+
+-extern int __atmel_lcdfb_probe(struct platform_device *pdev);
++extern int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *devdata);
+ extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
++struct atmel_lcdfb_devdata {
++ int (*setup_core)(struct fb_info *info);
++};
++
+ /* LCD Controller info data structure, stored in device platform_data */
+ struct atmel_lcdfb_info {
+ spinlock_t lock;
+ struct fb_info *info;
+ void __iomem *mmio;
+ int irq_base;
++ struct atmel_lcdfb_devdata *dev_data;
+ struct work_struct task;
+
+ unsigned int guard_time;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 139db41120d5755f7a086fb8dc6d7080d10fd135 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:26:10 +0200
-Subject: media/at91sam9x5-video: cleanup modifications
-
-pdata not used: remove them for now: ease transition to DT
-one type, one static, and one debug message modifications
-
-Can we squashed in another patch...
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/media/video/at91sam9x5-video.c | 22 ++++++++++++++--------
- 1 file changed, 14 insertions(+), 8 deletions(-)
-
-diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
-index 26ce376..c83dad1 100644
---- a/drivers/media/video/at91sam9x5-video.c
-+++ b/drivers/media/video/at91sam9x5-video.c
-@@ -347,8 +347,7 @@ static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
- heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR);
- handled = at91sam9x5_video_handle_irqstat(priv);
-
-- debug("%x, HEOCHSR = %08x\n", handled,
-- at91sam9x5_video_read32(priv, REG_HEOCHSR));
-+ debug("HEOIMR = 0x%08x, HEOCHSR = 0x%08x\n", heoimr, handled);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
-@@ -475,7 +474,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
- priv->next.plane_size[2] = priv->plane_size[2];
- }
-
--static int experimental;
-+static bool experimental;
- module_param(experimental, bool, 0644);
- MODULE_PARM_DESC(experimental, "enable experimental features");
-
-@@ -1155,8 +1154,8 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
- int ret = -ENOMEM;
- struct platform_device *pdev = priv->pdev;
- struct resource *res;
-- const struct at91sam9x5_video_pdata *pdata =
-- dev_get_platdata(&pdev->dev);
-+ /*const struct at91sam9x5_video_pdata *pdata =
-+ dev_get_platdata(&pdev->dev);*/
- struct vb2_queue *q = &priv->queue;
- unsigned long flags;
-
-@@ -1171,10 +1170,13 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
- /* XXX: this doesn't belong here, does it? */
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-
-+ /* Not used for now */
-+#if 0
- if (!pdata) {
- dev_err(&pdev->dev, "failed to get platform data\n");
- goto err_get_pdata;
- }
-+#endif
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
-@@ -1272,10 +1274,14 @@ err_queue_init:
- iounmap(priv->regbase);
-
- priv->fbinfo = NULL;
-+ } else {
-+ dev_info(&pdev->dev,
-+ "video device registered @ 0x%08x, irq = %d\n",
-+ (unsigned int)priv->regbase, priv->irq);
- }
- err_ioremap:
- err_get_regbase:
-- err_get_pdata:
-+/* err_get_pdata:*/
-
- return ret;
- }
-@@ -1369,7 +1375,7 @@ err_alloc_priv:
- return 0;
- }
-
--int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
-+static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
- {
- struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
-
-@@ -1386,7 +1392,7 @@ static struct platform_driver at91sam9x5_video_driver = {
- .owner = THIS_MODULE,
- },
- .probe = at91sam9x5_video_probe,
-- .remove = at91sam9x5_video_remove,
-+ .remove = __devexit_p(at91sam9x5_video_remove),
- };
-
- static struct platform_device *at91sam9x5_video_device;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 77d8d936f1c593a6e273e93585514f7d8428c68a Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:12:30 +0200
+Subject: video: atmelfb: refactor start/stop
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 30 +++++++++++++++++++++++-
+ drivers/video/atmel_lcdfb_core.c | 50 ++++++++++------------------------------
+ include/video/atmel_lcdc.h | 9 +++++---
+ 3 files changed, 47 insertions(+), 42 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 85063d6..422be1a 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -25,6 +25,32 @@
+ #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+ #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
++void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
++ | ATMEL_LCDC_PWR);
++}
++
++static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
++{
++ /* Turn off the LCD controller and the DMA controller */
++ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
++ sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
++
++ /* Wait for the LCDC core to become idle */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
++ msleep(10);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
++
++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
++ /* Wait for DMA engine to become idle... */
++ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
++ msleep(10);
++}
++
+ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+ {
+ unsigned long value;
+@@ -186,7 +212,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+
+- atmel_lcdfb_stop(sinfo);
++ atmel_lcdfb_stop(sinfo, 0);
+ atmel_lcdfb_stop_clock(sinfo);
+
+ return 0;
+@@ -218,6 +244,8 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
+
+ static struct atmel_lcdfb_devdata dev_data = {
+ .setup_core = atmel_lcdfb_setup_core,
++ .start = atmel_lcdfb_start,
++ .stop = atmel_lcdfb_stop,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 9a7c5eb..8413b76 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -181,38 +181,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
+-{
+- /* Turn off the LCD controller and the DMA controller */
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+-
+- /* Wait for the LCDC core to become idle */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
+- msleep(10);
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+-}
+-
+-void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
+-{
+- atmel_lcdfb_stop_nowait(sinfo);
+-
+- /* Wait for DMA engine to become idle... */
+- while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+- msleep(10);
+-}
+-EXPORT_SYMBOL_GPL(atmel_lcdfb_stop);
+-
+-void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+-{
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+- lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+- (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
+- | ATMEL_LCDC_PWR);
+-}
+-EXPORT_SYMBOL_GPL(atmel_lcdfb_start);
+-
+ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+ {
+@@ -439,8 +407,10 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
+ {
+ might_sleep();
+
+- atmel_lcdfb_stop(sinfo);
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, 0);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+ }
+
+ /**
+@@ -469,7 +439,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ info->var.xres, info->var.yres,
+ info->var.xres_virtual, info->var.yres_virtual);
+
+- atmel_lcdfb_stop_nowait(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, ATMEL_LCDC_STOP_NOWAIT);
+
+ if (info->var.bits_per_pixel == 1)
+ info->fix.visual = FB_VISUAL_MONO01;
+@@ -488,7 +459,8 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+ /* Now, the LCDC core... */
+ sinfo->dev_data->setup_core(info);
+
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+
+ dev_dbg(info->device, " * DONE\n");
+
+@@ -600,13 +572,15 @@ static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info)
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ case FB_BLANK_NORMAL:
+- atmel_lcdfb_start(sinfo);
++ if (sinfo->dev_data->start)
++ sinfo->dev_data->start(sinfo);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ break;
+ case FB_BLANK_POWERDOWN:
+- atmel_lcdfb_stop(sinfo);
++ if (sinfo->dev_data->stop)
++ sinfo->dev_data->stop(sinfo, 0);
+ break;
+ default:
+ return -EINVAL;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index b1a5fad1..ea7ce31 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -32,17 +32,20 @@
+ #define ATMEL_LCDC_WIRING_RGB 1
+ #define ATMEL_LCDC_WIRING_RGB555 2
+
+-extern void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo);
+-extern void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo);
++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
++
+ extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+ extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+-
+ extern int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct atmel_lcdfb_devdata *devdata);
+ extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+
++struct atmel_lcdfb_info;
++
+ struct atmel_lcdfb_devdata {
+ int (*setup_core)(struct fb_info *info);
++ void (*start)(struct atmel_lcdfb_info *sinfo);
++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 92851e65d9f4db640eecc9e6b7d547396244b6c9 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:29:45 +0200
-Subject: media/at91sam9x5-video: align DMA descriptors on 64 bits
-
-Needed for future revisions of the LCD ip
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/media/video/at91sam9x5-video.c | 46 ++++++++++++++++++++--------------
- 1 file changed, 27 insertions(+), 19 deletions(-)
-
-diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
-index c83dad1..9d7e6c5 100644
---- a/drivers/media/video/at91sam9x5-video.c
-+++ b/drivers/media/video/at91sam9x5-video.c
-@@ -375,7 +375,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
- struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
- /* XXX: format dependant */
- size_t offset_dmadesc = ALIGN(pix->width * pix->height +
-- ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
-+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 64);
- u32 *dmadesc = vaddr + offset_dmadesc;
- u32 heocher;
-
-@@ -388,23 +388,30 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
- }
-
- debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
-+ debug("dmadesc @ 0x%08x\n", dmadesc);
-+ debug("dmadesc u @ 0x%08x\n", &dmadesc[4]);
-+ debug("dmadesc v @ 0x%08x\n", &dmadesc[8]);
-
- dmadesc[0] = buffer + priv->y_offset;
- dmadesc[1] = REG_HEOxCTRL_DFETCH;
- dmadesc[2] = buffer + offset_dmadesc;
-+ /* dmadesc[3] not used to align U plane descriptor */
-
- if (priv->u_planeno >= 0) {
-- dmadesc[3] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
-+ dmadesc[4] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
- priv->u_offset;
-- dmadesc[4] = REG_HEOxCTRL_DFETCH;
-- dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
-+ dmadesc[5] = REG_HEOxCTRL_DFETCH;
-+ /* link to physical address of this U descriptor */
-+ dmadesc[6] = buffer + offset_dmadesc + 4 * 4;
- }
-+ /* dmadesc[7] not used to align V plane descriptor */
-
- if (priv->v_planeno >= 0) {
-- dmadesc[6] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
-+ dmadesc[8] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
- priv->v_offset;
-- dmadesc[7] = REG_HEOxCTRL_DFETCH;
-- dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
-+ dmadesc[9] = REG_HEOxCTRL_DFETCH;
-+ /* link to physical address of this V descriptor */
-+ dmadesc[10] = buffer + offset_dmadesc + 8 * 4;
- }
-
-
-@@ -415,11 +422,11 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
-
- if (priv->u_planeno >= 0)
- at91sam9x5_video_write32(priv,
-- REG_HEOUHEAD, dmadesc[5]);
-+ REG_HEOUHEAD, dmadesc[6]);
-
- if (priv->v_planeno >= 0)
- at91sam9x5_video_write32(priv,
-- REG_HEOVHEAD, dmadesc[8]);
-+ REG_HEOVHEAD, dmadesc[10]);
-
- at91sam9x5_video_write32(priv,
- REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
-@@ -432,20 +439,20 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
-
- if (priv->u_planeno >= 0) {
- at91sam9x5_video_write32(priv,
-- REG_HEOUADDR, dmadesc[3]);
-+ REG_HEOUADDR, dmadesc[4]);
- at91sam9x5_video_write32(priv,
-- REG_HEOUCTRL, dmadesc[4]);
-+ REG_HEOUCTRL, dmadesc[5]);
- at91sam9x5_video_write32(priv,
-- REG_HEOUNEXT, dmadesc[5]);
-+ REG_HEOUNEXT, dmadesc[6]);
- }
-
- if (priv->v_planeno >= 0) {
- at91sam9x5_video_write32(priv,
-- REG_HEOVADDR, dmadesc[6]);
-+ REG_HEOVADDR, dmadesc[8]);
- at91sam9x5_video_write32(priv,
-- REG_HEOVCTRL, dmadesc[7]);
-+ REG_HEOVCTRL, dmadesc[9]);
- at91sam9x5_video_write32(priv,
-- REG_HEOVNEXT, dmadesc[8]);
-+ REG_HEOVNEXT, dmadesc[10]);
- }
-
- at91sam9x5_video_write32(priv, REG_HEOCHER,
-@@ -713,14 +720,15 @@ static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
- *num_planes = 1;
-
- /*
-- * The last 9 (aligned) words are used for the 3 dma descriptors (3
-- * 32-bit words each). The additional 32 bits are for alignment.
-+ * The last 9 (64 bits aligned) words are used for the 3 dma
-+ * descriptors (3 * 32-bit words each).
-+ * The additional 64 + 2 * 32 bits are for alignment.
- * XXX: is that allowed and done right?
- * XXX: format-dependant
- */
- sizes[0] = pix->width * pix->height +
- ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
-- 10 * 32;
-+ 9 * 32 + 128;
- priv->plane_size[0] = sizes[0];
-
- alloc_ctxs[0] = priv->alloc_ctx;
-@@ -787,7 +795,7 @@ static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
- /* XXX: format-dependant */
- if (vb->v4l2_planes[0].length < pix->width * pix->height +
- ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
-- 10 * 32)
-+ 9 * 32 + 128)
- return -EINVAL;
-
- return 0;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 815c18d931e79076ce64c0af0aa249ec993aa366 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 15:37:12 +0200
+Subject: video: atmelfb: refactor isr
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 39 ++++++++++++---------------------------
+ include/video/atmel_lcdc.h | 2 ++
+ 3 files changed, 32 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 422be1a..3653e2a 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -194,6 +194,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
+ return 0;
+ }
+
++static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status;
++
++ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
++ if (status & ATMEL_LCDC_UFLWI) {
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++ /* reset DMA and FIFO to avoid screen shifting */
++ schedule_work(&sinfo->task);
++ }
++ lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
++ return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_PM
+
+ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+ {
+@@ -246,6 +263,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .setup_core = atmel_lcdfb_setup_core,
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
++ .isr = atmel_lcdfb_interrupt,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 8413b76..eab4d88 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -602,22 +602,6 @@ static struct fb_ops atmel_lcdfb_ops = {
+ .fb_imageblit = cfb_imageblit,
+ };
+
+-static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+-{
+- struct fb_info *info = dev_id;
+- struct atmel_lcdfb_info *sinfo = info->par;
+- u32 status;
+-
+- status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+- if (status & ATMEL_LCDC_UFLWI) {
+- dev_warn(info->device, "FIFO underflow %#x\n", status);
+- /* reset DMA and FIFO to avoid screen shifting */
+- schedule_work(&sinfo->task);
+- }
+- lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
+- return IRQ_HANDLED;
+-}
+-
+ /*
+ * LCD controller task (to reset the LCD)
+ */
+@@ -750,12 +734,8 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
++ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+- if (sinfo->irq_base < 0) {
+- dev_err(dev, "unable to get irq\n");
+- ret = sinfo->irq_base;
+- goto stop_clk;
+- }
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+@@ -806,10 +786,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ init_contrast(sinfo);
+
+ /* interrupt */
+- ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+- if (ret) {
+- dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
++ if (sinfo->irq_base >= 0) {
++ ret = request_irq(sinfo->irq_base, sinfo->dev_data->isr,
++ IRQF_SHARED, pdev->name, info);
++ if (ret) {
++ dev_err(dev, "request_irq failed: %d\n", ret);
++ goto unmap_mmio;
++ }
+ }
+
+ /* Some operations on the LCDC might sleep and
+@@ -864,7 +847,8 @@ free_cmap:
+ fb_dealloc_cmap(&info->cmap);
+ unregister_irqs:
+ cancel_work_sync(&sinfo->task);
+- free_irq(sinfo->irq_base, info);
++ if (sinfo->irq_base >= 0)
++ free_irq(sinfo->irq_base, info);
+ unmap_mmio:
+ exit_backlight(sinfo);
+ iounmap(sinfo->mmio);
+@@ -913,7 +897,8 @@ int __atmel_lcdfb_remove(struct platform_device *pdev)
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+ fb_dealloc_cmap(&info->cmap);
+- free_irq(sinfo->irq_base, info);
++ if (sinfo->irq_base >= 0)
++ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index ea7ce31..14b5664 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -23,6 +23,7 @@
+ #define __ATMEL_LCDC_H__
+
+ #include <linux/workqueue.h>
++#include <linux/interrupt.h>
+
+ /* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+@@ -46,6 +47,7 @@ struct atmel_lcdfb_devdata {
+ int (*setup_core)(struct fb_info *info);
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
++ irqreturn_t (*isr)(int irq, void *dev_id);
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 08e62ea4aa3af6791f58ccf1012a80682bf7b517 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:30:47 +0200
-Subject: media/at91sam9x5-video: change scaling factor calculation
-
-Useful for future revision of the HEO IP
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/media/video/at91sam9x5-video.c | 36 ++++++++++++++++++++++++++++------
- 1 file changed, 30 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
-index 9d7e6c5..1e5a0a7 100644
---- a/drivers/media/video/at91sam9x5-video.c
-+++ b/drivers/media/video/at91sam9x5-video.c
-@@ -518,6 +518,19 @@ static void at91sam9x5_video_params(unsigned width, unsigned height,
- *tloffset = e[ro(0)];
- }
-
-+static void at91sam9x5_video_setup_scaling_coef(
-+ struct at91sam9x5_video_priv *priv,
-+ unsigned hwxmem_size, unsigned hwxsize,
-+ unsigned hwymem_size, unsigned hwysize,
-+ unsigned *xphidef, unsigned *yphidef) {}
-+
-+static void at91sam9x5_video_setup_scaling_factor(
-+ unsigned hwmem_size, unsigned hwsize,
-+ unsigned phidef, unsigned *factor)
-+{
-+ *factor = 1024 * hwmem_size / hwsize;
-+}
-+
- static void at91sam9x5_video_update_config_real(
- struct at91sam9x5_video_priv *priv)
- {
-@@ -529,6 +542,9 @@ static void at91sam9x5_video_update_config_real(
-
- unsigned hwxpos, hwypos, hwxsize, hwysize;
- unsigned hwxmem_size, hwymem_size;
-+ unsigned xphidef = 0;
-+ unsigned yphidef = 0;
-+ unsigned xfactor, yfactor;
- s32 hwxstride, hwpstride;
- s32 hwuvxstride, hwuvpstride;
- s32 rotated_pixwidth, rotated_pixheight;
-@@ -600,12 +616,20 @@ static void at91sam9x5_video_update_config_real(
- valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) |
- valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE));
-
-- at91sam9x5_video_write32(priv, REG_HEOCFG13,
-- REG_HEOCFG13_SCALEN |
-- valtomask(1024 * hwxmem_size / hwxsize,
-- REG_HEOCFG13_XFACTOR) |
-- valtomask(1024 * hwymem_size / hwysize,
-- REG_HEOCFG13_YFACTOR));
-+ at91sam9x5_video_setup_scaling_coef(priv,
-+ hwxmem_size, hwxsize,
-+ hwymem_size, hwysize,
-+ &xphidef, &yphidef);
-+
-+ at91sam9x5_video_setup_scaling_factor(hwxmem_size - 1, hwxsize - 1,
-+ xphidef, &xfactor);
-+
-+ at91sam9x5_video_setup_scaling_factor(hwymem_size - 1, hwysize - 1,
-+ yphidef, &yfactor);
-+
-+ at91sam9x5_video_write32(priv, REG_HEOCFG13, REG_HEOCFG13_SCALEN
-+ | valtomask(xfactor, REG_HEOCFG13_XFACTOR)
-+ | valtomask(yfactor, REG_HEOCFG13_YFACTOR));
-
- at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
- &hwxstride, &hwpstride, &priv->y_offset);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8da5e6762ea376a5ff47963430d72fe84bab91c9 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Thu, 19 May 2011 16:40:13 +0200
+Subject: video: atmelfb: refactor backlight routines
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 61 +++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 73 ++++------------------------------------
+ include/video/atmel_lcdc.h | 3 ++
+ 3 files changed, 71 insertions(+), 66 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 3653e2a..046e6c5 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
++#include <linux/backlight.h>
+ #include <linux/fb.h>
+ #include <linux/clk.h>
+ #include <linux/init.h>
+@@ -22,9 +23,67 @@
+ #include <video/atmel_lcdc.h>
+
+ /* configurable parameters */
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+ #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
+ #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+
++static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
++ | ATMEL_LCDC_POL_POSITIVE
++ | ATMEL_LCDC_ENA_PWMENABLE;
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
++ brightness ? contrast_ctr : 0);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
++}
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* contrast pwm can be 'inverted' */
++ if (sinfo->lcdcon_pol_negative)
++ contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
++
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
++ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
++}
++
+ void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+@@ -264,6 +323,8 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
+ .isr = atmel_lcdfb_interrupt,
++ .bl_ops = &atmel_lcdc_bl_ops,
++ .init_contrast = atmel_lcdfb_init_contrast,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index eab4d88..ef63996 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -16,7 +16,6 @@
+ #include <linux/fb.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+-#include <linux/backlight.h>
+ #include <linux/gfp.h>
+
+ #include <mach/board.h>
+@@ -63,54 +62,8 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ }
+ #endif
+
+-static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+- | ATMEL_LCDC_POL_POSITIVE
+- | ATMEL_LCDC_ENA_PWMENABLE;
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+-/* some bl->props field just changed */
+-static int atmel_bl_update_status(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+- int power = sinfo->bl_power;
+- int brightness = bl->props.brightness;
+-
+- /* REVISIT there may be a meaningful difference between
+- * fb_blank and power ... there seem to be some cases
+- * this doesn't handle correctly.
+- */
+- if (bl->props.fb_blank != sinfo->bl_power)
+- power = bl->props.fb_blank;
+- else if (bl->props.power != sinfo->bl_power)
+- power = bl->props.power;
+-
+- if (brightness < 0 && power == FB_BLANK_UNBLANK)
+- brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+- else if (power != FB_BLANK_UNBLANK)
+- brightness = 0;
+-
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR,
+- brightness ? contrast_ctr : 0);
+-
+- bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
+-
+- return 0;
+-}
+-
+-static int atmel_bl_get_brightness(struct backlight_device *bl)
+-{
+- struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
+-
+- return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+-}
+-
+-static const struct backlight_ops atmel_lcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+ {
+ struct backlight_properties props;
+@@ -118,14 +71,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+
+ sinfo->bl_power = FB_BLANK_UNBLANK;
+
+- if (sinfo->backlight)
++ if (sinfo->backlight || !sinfo->dev_data->bl_ops)
+ return;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = 0xff;
+ bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo,
+- &atmel_lcdc_bl_ops, &props);
++ sinfo->dev_data->bl_ops, &props);
+ if (IS_ERR(bl)) {
+ dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+@@ -135,7 +88,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+- bl->props.brightness = atmel_bl_get_brightness(bl);
++ bl->props.brightness = sinfo->dev_data->bl_ops->get_brightness(bl);
+ }
+
+ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+@@ -157,21 +110,6 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo)
+
+ #endif
+
+-static void init_contrast(struct atmel_lcdfb_info *sinfo)
+-{
+- /* contrast pwm can be 'inverted' */
+- if (sinfo->lcdcon_pol_negative)
+- contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE);
+-
+- /* have some default contrast/backlight settings */
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+- lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+-
+- if (sinfo->lcdcon_is_backlight)
+- init_backlight(sinfo);
+-}
+-
+-
+ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+@@ -783,7 +721,10 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ }
+
+ /* Initialize PWM for contrast or backlight ("off") */
+- init_contrast(sinfo);
++ if (sinfo->dev_data->init_contrast)
++ sinfo->dev_data->init_contrast(sinfo);
++ if (sinfo->lcdcon_is_backlight)
++ init_backlight(sinfo);
+
+ /* interrupt */
+ if (sinfo->irq_base >= 0) {
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 14b5664..e7c0a3f 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -24,6 +24,7 @@
+
+ #include <linux/workqueue.h>
+ #include <linux/interrupt.h>
++#include <linux/backlight.h>
+
+ /* Way LCD wires are connected to the chip:
+ * Some Atmel chips use BGR color mode (instead of standard RGB)
+@@ -48,6 +49,8 @@ struct atmel_lcdfb_devdata {
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ const struct backlight_ops *bl_ops;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5317bf1e9672b9a7e540e701a724d7d73910a87b Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 18:46:07 +0200
-Subject: media/at91sam9x5-video: add device tree support
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/media/video/at91sam9x5-video.c | 55 +++++++++++-----------------------
- 1 file changed, 18 insertions(+), 37 deletions(-)
-
-diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
-index 1e5a0a7..548aebc 100644
---- a/drivers/media/video/at91sam9x5-video.c
-+++ b/drivers/media/video/at91sam9x5-video.c
-@@ -21,6 +21,8 @@
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-
- #include <media/v4l2-common.h>
- #include <media/v4l2-dev.h>
-@@ -1418,59 +1420,38 @@ static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
- return 0;
- }
-
-+#if defined(CONFIG_OF)
-+static const struct of_device_id atmel_heo_dt_ids[] = {
-+ {
-+ .compatible = "atmel,at91sam9x5-heo",
-+ .data = (void *)0,
-+ }, {
-+ /* sentinel */
-+ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, atmel_heo_dt_ids);
-+#endif
-+
- static struct platform_driver at91sam9x5_video_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(atmel_heo_dt_ids),
- },
- .probe = at91sam9x5_video_probe,
- .remove = __devexit_p(at91sam9x5_video_remove),
- };
-
--static struct platform_device *at91sam9x5_video_device;
- static int __init at91sam9x5_video_init(void)
- {
-- /* XXX: register the device in arch/arm/mach-at91 */
-- int ret;
-- const struct resource res[] = {
-- {
-- .start = 0xf8038280,
-- .end = 0xf803833f,
-- .flags = IORESOURCE_MEM,
-- }, {
-- .start = 25,
-- .end = 25,
-- .flags = IORESOURCE_IRQ,
-- },
-- };
-- const struct at91sam9x5_video_pdata pdata = {
-- .base_width = 800,
-- .base_height = 480,
-- };
--
-- ret = platform_driver_register(&at91sam9x5_video_driver);
-- if (ret) {
-- pr_err("failed to register driver (%d)", ret);
-- goto err_driver_register;
-- }
--
-- at91sam9x5_video_device = platform_device_register_resndata(NULL,
-- DRIVER_NAME, -1,
-- res, ARRAY_SIZE(res), &pdata, sizeof(pdata));
-- if (IS_ERR(at91sam9x5_video_device)) {
-- ret = PTR_ERR(at91sam9x5_video_device);
-- pr_err("failed to register device (%d)", ret);
-- platform_driver_unregister(&at91sam9x5_video_driver);
-- }
--
-- err_driver_register:
-- return ret;
-+ return platform_driver_probe(&at91sam9x5_video_driver,
-+ &at91sam9x5_video_probe);
- }
- module_init(at91sam9x5_video_init);
-
- static void __exit at91sam9x5_video_exit(void)
- {
-- platform_device_unregister(at91sam9x5_video_device);
- platform_driver_unregister(&at91sam9x5_video_driver);
- }
- module_exit(at91sam9x5_video_exit);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 546b4b1084b216e3ee2a1cde0868ee256e5e43d5 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:31:29 +0200
+Subject: video: atmelfb: refactor dma_update
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 55 ++++++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 61 ++++------------------------------------
+ include/video/atmel_lcdc.h | 2 ++
+ 3 files changed, 62 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 046e6c5..cd6d22e 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -31,6 +31,59 @@ static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8
+ | ATMEL_LCDC_POL_POSITIVE
+ | ATMEL_LCDC_ENA_PWMENABLE;
+
++#if defined(CONFIG_ARCH_AT91)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++
++}
++#elif defined(CONFIG_AVR32)
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_XPAN \
++ | FBINFO_HWACCEL_YPAN)
++
++static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
++ struct fb_var_screeninfo *var)
++{
++ u32 dma2dcfg;
++ u32 pixeloff;
++
++ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
++
++ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
++ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
++
++ /* Update configuration */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
++ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
++ | ATMEL_LCDC_DMAUPDT);
++}
++#endif
++
++static void atmel_lcdfb_update_dma(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Set framebuffer DMA base address and pixel offset */
++ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
++
++ atmel_lcdfb_update_dma2d(sinfo, var);
++}
++
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -323,8 +376,10 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .start = atmel_lcdfb_start,
+ .stop = atmel_lcdfb_stop,
+ .isr = atmel_lcdfb_interrupt,
++ .update_dma = atmel_lcdfb_update_dma,
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index ef63996..4146e9b 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -27,41 +27,6 @@
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+
+-#if defined(CONFIG_ARCH_AT91)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+-
+-}
+-#elif defined(CONFIG_AVR32)
+-#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+- | FBINFO_PARTIAL_PAN_OK \
+- | FBINFO_HWACCEL_XPAN \
+- | FBINFO_HWACCEL_YPAN)
+-
+-static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+- struct fb_var_screeninfo *var)
+-{
+- u32 dma2dcfg;
+- u32 pixeloff;
+-
+- pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+-
+- dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+- dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+- lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+-
+- /* Update configuration */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+- lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+- | ATMEL_LCDC_DMAUPDT);
+-}
+-#endif
+-
+ #ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+
+ static void init_backlight(struct atmel_lcdfb_info *sinfo)
+@@ -119,24 +84,6 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix = {
+ .accel = FB_ACCEL_NONE,
+ };
+
+-static void atmel_lcdfb_update_dma(struct fb_info *info,
+- struct fb_var_screeninfo *var)
+-{
+- struct atmel_lcdfb_info *sinfo = info->par;
+- struct fb_fix_screeninfo *fix = &info->fix;
+- unsigned long dma_addr;
+-
+- dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+- + var->xoffset * var->bits_per_pixel / 8);
+-
+- dma_addr &= ~3UL;
+-
+- /* Set framebuffer DMA base address and pixel offset */
+- lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+-
+- atmel_lcdfb_update_dma2d(sinfo, var);
+-}
+-
+ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+ {
+ struct fb_info *info = sinfo->info;
+@@ -392,7 +339,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
+
+ /* Re-initialize the DMA engine... */
+ dev_dbg(info->device, " * update DMA engine\n");
+- atmel_lcdfb_update_dma(info, &info->var);
++ sinfo->dev_data->update_dma(info, &info->var);
+
+ /* Now, the LCDC core... */
+ sinfo->dev_data->setup_core(info);
+@@ -496,9 +443,11 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+ {
++ struct atmel_lcdfb_info *sinfo = info->par;
++
+ dev_dbg(info->device, "%s\n", __func__);
+
+- atmel_lcdfb_update_dma(info, var);
++ sinfo->dev_data->update_dma(info, var);
+
+ return 0;
+ }
+@@ -633,7 +582,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ sinfo->pdev = pdev;
+
+ strcpy(info->fix.id, sinfo->pdev->name);
+- info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
++ info->flags = dev_data->fbinfo_flags;
+ info->pseudo_palette = sinfo->pseudo_palette;
+ info->fbops = &atmel_lcdfb_ops;
+
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index e7c0a3f..866ab47 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -49,8 +49,10 @@ struct atmel_lcdfb_devdata {
+ void (*start)(struct atmel_lcdfb_info *sinfo);
+ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+ const struct backlight_ops *bl_ops;
++ int fbinfo_flags;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 25f953cbb8bf107346227628c0554f9b142b637b Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 18 Jun 2012 14:14:57 +0200
-Subject: ARM: at91/video: Atmel HLCD is only selected by newer products
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/Kconfig | 4 ++--
- drivers/video/Kconfig | 5 ++++-
- 2 files changed, 6 insertions(+), 3 deletions(-)
-
-diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
-index c8050b1..79d08ed 100644
---- a/arch/arm/mach-at91/Kconfig
-+++ b/arch/arm/mach-at91/Kconfig
-@@ -86,7 +86,7 @@ config SOC_AT91SAM9X5
- bool "AT91SAM9x5 family"
- select SOC_AT91SAM9
- select HAVE_AT91_DBGU0
-- select HAVE_FB_ATMEL
-+ select HAVE_FB_ATMEL_HLCD
- select HAVE_NET_MACB
- help
- Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
-@@ -99,7 +99,7 @@ config SOC_AT91SAM9N12
- bool "AT91SAM9N12 family"
- select SOC_AT91SAM9
- select HAVE_AT91_DBGU0
-- select HAVE_FB_ATMEL
-+ select HAVE_FB_ATMEL_HLCD
- help
- Select this if you are using Atmel's AT91SAM9N12 SoC.
-
-diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
-index ceccaa3..0928c36 100644
---- a/drivers/video/Kconfig
-+++ b/drivers/video/Kconfig
-@@ -8,6 +8,9 @@ menu "Graphics support"
- config HAVE_FB_ATMEL
- bool
-
-+config HAVE_FB_ATMEL_HLCD
-+ bool
-+
- config SH_MIPI_DSI
- tristate
- depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
-@@ -1030,7 +1033,7 @@ config FB_ATMEL_STN
-
- config FB_ATMEL_HLCD
- tristate "AT91 HLCD Controller support"
-- depends on FB && HAVE_FB_ATMEL
-+ depends on FB && HAVE_FB_ATMEL_HLCD
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 67667d141480aa33acf52e27648fccb696282d03 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 14:51:45 +0200
+Subject: video: atmelfb: refactor LUT
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 1 +
+ drivers/video/atmel_lcdfb_core.c | 6 ++++--
+ include/video/atmel_lcdc.h | 8 ++------
+ 3 files changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index cd6d22e..f8993cd 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -380,6 +380,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = ATMEL_LCDC_LUT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 4146e9b..0edafb6 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -422,7 +422,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
++ val);
+ ret = 0;
+ }
+ break;
+@@ -430,7 +431,8 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
++ lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
++ val);
+ ret = 0;
+ }
+ break;
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 866ab47..6c470c4 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -53,6 +53,7 @@ struct atmel_lcdfb_devdata {
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
++ u32 lut_base;
+ };
+
+ /* LCD Controller info data structure, stored in device platform_data */
+@@ -241,11 +242,6 @@ struct atmel_lcdfb_info {
+ #define ATMEL_LCDC_OWRI (1 << 5)
+ #define ATMEL_LCDC_MERI (1 << 6)
+
+-#if !defined(CONFIG_ARCH_AT91SAM9X5)
+-#define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
+-#else
+-/* Base layer CLUT */
+-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
+-#endif
++#define ATMEL_LCDC_LUT 0x0c00
+
+ #endif /* __ATMEL_LCDC_H__ */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 3ea2cbea34f1de73412b06cfc95e2c7a06a6aa04 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 16 May 2012 15:25:58 +0200
-Subject: mmc: atmel-mci: the r/w proof capability lack was not well managed
-
-First mci IPs (mainly on rm9200 and 9261) don't have the r/w proof
-capability. The driver didn't work correctly without this capability
-in PDC mode because of the double buffer switch which is too slow
-even if we stop the transfer to perform this switch.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Chris Ball <cjb@laptop.org>
----
- drivers/mmc/host/atmel-mci.c | 92 +++++++++++++++++++++++++++++++++++++-------
- 1 file changed, 78 insertions(+), 14 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index e94476b..6f56ef0 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -91,6 +91,11 @@ struct atmel_mci_dma {
- * @regs: Pointer to MMIO registers.
- * @sg: Scatterlist entry currently being processed by PIO or PDC code.
- * @pio_offset: Offset into the current scatterlist entry.
-+ * @buffer: Buffer used if we don't have the r/w proof capability. We
-+ * don't have the time to switch pdc buffers so we have to use only
-+ * one buffer for the full transaction.
-+ * @buf_size: size of the buffer.
-+ * @phys_buf_addr: buffer address needed for pdc.
- * @cur_slot: The slot which is currently using the controller.
- * @mrq: The request currently being processed on @cur_slot,
- * or NULL if the controller is idle.
-@@ -166,6 +171,9 @@ struct atmel_mci {
-
- struct scatterlist *sg;
- unsigned int pio_offset;
-+ unsigned int *buffer;
-+ unsigned int buf_size;
-+ dma_addr_t buf_phys_addr;
-
- struct atmel_mci_slot *cur_slot;
- struct mmc_request *mrq;
-@@ -480,6 +488,11 @@ err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
- }
-
-+static inline unsigned int atmci_get_version(struct atmel_mci *host)
-+{
-+ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
-+}
-+
- static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
- unsigned int ns)
- {
-@@ -603,6 +616,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
- enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
- {
- u32 pointer_reg, counter_reg;
-+ unsigned int buf_size;
-
- if (dir == XFER_RECEIVE) {
- pointer_reg = ATMEL_PDC_RPR;
-@@ -617,8 +631,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
- counter_reg += ATMEL_PDC_SCND_BUF_OFF;
- }
-
-- atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
-- if (host->data_size <= sg_dma_len(host->sg)) {
-+ if (!host->caps.has_rwproof) {
-+ buf_size = host->buf_size;
-+ atmci_writel(host, pointer_reg, host->buf_phys_addr);
-+ } else {
-+ buf_size = sg_dma_len(host->sg);
-+ atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
-+ }
-+
-+ if (host->data_size <= buf_size) {
- if (host->data_size & 0x3) {
- /* If size is different from modulo 4, transfer bytes */
- atmci_writel(host, counter_reg, host->data_size);
-@@ -670,7 +691,15 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
- */
- static void atmci_pdc_complete(struct atmel_mci *host)
- {
-+ int transfer_size = host->data->blocks * host->data->blksz;
-+
- atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-+
-+ if ((!host->caps.has_rwproof)
-+ && (host->data->flags & MMC_DATA_READ))
-+ sg_copy_from_buffer(host->data->sg, host->data->sg_len,
-+ host->buffer, transfer_size);
-+
- atmci_pdc_cleanup(host);
-
- /*
-@@ -818,6 +847,12 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
- /* Configure PDC */
- host->data_size = data->blocks * data->blksz;
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
-+
-+ if ((!host->caps.has_rwproof)
-+ && (host->data->flags & MMC_DATA_WRITE))
-+ sg_copy_to_buffer(host->data->sg, host->data->sg_len,
-+ host->buffer, host->data_size);
-+
- if (host->data_size)
- atmci_pdc_set_both_buf(host,
- ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
-@@ -1877,13 +1912,26 @@ static int __init atmci_init_slot(struct atmel_mci *host,
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- if (host->caps.has_highspeed)
- mmc->caps |= MMC_CAP_SD_HIGHSPEED;
-- if (slot_data->bus_width >= 4)
-+ /*
-+ * Without the read/write proof capability, it is strongly suggested to
-+ * use only one bit for data to prevent fifo underruns and overruns
-+ * which will corrupt data.
-+ */
-+ if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
-- mmc->max_segs = 64;
-- mmc->max_req_size = 32768 * 512;
-- mmc->max_blk_size = 32768;
-- mmc->max_blk_count = 512;
-+ if (atmci_get_version(host) < 0x200) {
-+ mmc->max_segs = 256;
-+ mmc->max_blk_size = 4095;
-+ mmc->max_blk_count = 256;
-+ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-+ mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs;
-+ } else {
-+ mmc->max_segs = 64;
-+ mmc->max_req_size = 32768 * 512;
-+ mmc->max_blk_size = 32768;
-+ mmc->max_blk_count = 512;
-+ }
-
- /* Assume card is present initially */
- set_bit(ATMCI_CARD_PRESENT, &slot->flags);
-@@ -2007,11 +2055,6 @@ static bool atmci_configure_dma(struct atmel_mci *host)
- }
- }
-
--static inline unsigned int atmci_get_version(struct atmel_mci *host)
--{
-- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
--}
--
- /*
- * HSMCI (High Speed MCI) module is not fully compatible with MCI module.
- * HSMCI provides DMA support and a new config register but no more supports
-@@ -2138,14 +2181,20 @@ static int __init atmci_probe(struct platform_device *pdev)
- if (pdata->slot[0].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[0],
- 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
-- if (!ret)
-+ if (!ret) {
- nr_slots++;
-+ host->buf_size = host->slot[0]->mmc->max_req_size;
-+ }
- }
- if (pdata->slot[1].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[1],
- 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
-- if (!ret)
-+ if (!ret) {
- nr_slots++;
-+ if (host->slot[1]->mmc->max_req_size > host->buf_size)
-+ host->buf_size =
-+ host->slot[1]->mmc->max_req_size;
-+ }
- }
-
- if (!nr_slots) {
-@@ -2153,6 +2202,17 @@ static int __init atmci_probe(struct platform_device *pdev)
- goto err_init_slot;
- }
-
-+ if (!host->caps.has_rwproof) {
-+ host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
-+ &host->buf_phys_addr,
-+ GFP_KERNEL);
-+ if (!host->buffer) {
-+ ret = -ENOMEM;
-+ dev_err(&pdev->dev, "buffer allocation failed\n");
-+ goto err_init_slot;
-+ }
-+ }
-+
- dev_info(&pdev->dev,
- "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
- host->mapbase, irq, nr_slots);
-@@ -2179,6 +2239,10 @@ static int __exit atmci_remove(struct platform_device *pdev)
-
- platform_set_drvdata(pdev, NULL);
-
-+ if (host->buffer)
-+ dma_free_coherent(&pdev->dev, host->buf_size,
-+ host->buffer, host->buf_phys_addr);
-+
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- if (host->slot[i])
- atmci_cleanup_slot(host->slot[i], i);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 005b72392f702b19971e90e6be15c87a37df492c Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Fri, 20 May 2011 15:04:10 +0200
+Subject: video: atmelfb: refactor limit_screeninfo
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb.c | 18 ++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 14 ++------------
+ include/video/atmel_lcdc.h | 1 +
+ 3 files changed, 21 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index f8993cd..7a48e9c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -306,6 +306,23 @@ static int atmel_lcdfb_setup_core(struct fb_info *info)
+ return 0;
+ }
+
++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
++{
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ ATMEL_LCDC_VFP);
++ var->right_margin = min_t(u32, var->right_margin,
++ (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ ATMEL_LCDC_HBP + 1);
++}
++
+ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+ {
+ struct fb_info *info = dev_id;
+@@ -379,6 +396,7 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .update_dma = atmel_lcdfb_update_dma,
+ .bl_ops = &atmel_lcdc_bl_ops,
+ .init_contrast = atmel_lcdfb_init_contrast,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+ .lut_base = ATMEL_LCDC_LUT,
+ };
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 0edafb6..20a4e4f 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -211,18 +211,8 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+- var->vsync_len = min_t(u32, var->vsync_len,
+- (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
+- var->upper_margin = min_t(u32, var->upper_margin,
+- ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET);
+- var->lower_margin = min_t(u32, var->lower_margin,
+- ATMEL_LCDC_VFP);
+- var->right_margin = min_t(u32, var->right_margin,
+- (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1);
+- var->hsync_len = min_t(u32, var->hsync_len,
+- (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1);
+- var->left_margin = min_t(u32, var->left_margin,
+- ATMEL_LCDC_HBP + 1);
++ if (sinfo->dev_data->limit_screeninfo)
++ sinfo->dev_data->limit_screeninfo(var);
+
+ /* Some parameters can't be zero */
+ var->vsync_len = max_t(u32, var->vsync_len, 1);
+diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
+index 6c470c4..6031b5a 100644
+--- a/include/video/atmel_lcdc.h
++++ b/include/video/atmel_lcdc.h
+@@ -51,6 +51,7 @@ struct atmel_lcdfb_devdata {
+ irqreturn_t (*isr)(int irq, void *dev_id);
+ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
+ u32 lut_base;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From a9336b89063ddcea9906959bcc72ff47c7cbeed8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:45:30 +0200
+Subject: arm: at91: refactor lcdc-includes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Among others the HEO-ISR bit is fixed.
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+Conflicts:
+ arch/arm/mach-at91/board-neocore926.c
+ arch/arm/mach-at91/board-sam9261ek.c
+ arch/arm/mach-at91/board-sam9263ek.c
+ arch/arm/mach-at91/board-sam9m10g45ek.c
+ arch/arm/mach-at91/board-sam9rlek.c
+---
+ arch/arm/mach-at91/at91sam9261_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9g45_devices.c | 4 +-
+ arch/arm/mach-at91/at91sam9rl_devices.c | 4 +-
+ arch/arm/mach-at91/board-neocore926.c | 4 +-
+ arch/arm/mach-at91/board-sam9261ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9263ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9m10g45ek.c | 4 +-
+ arch/arm/mach-at91/board-sam9rlek.c | 4 +-
+ .../include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} | 157 +--------------------
+ arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h | 156 ++++++++++++++++++++
+ .../arm/mach-at91/include/mach}/atmel_lcdc.h | 77 +---------
+ drivers/video/atmel_lcdfb.c | 3 +-
+ drivers/video/atmel_lcdfb_core.c | 2 +-
+ include/video/atmel_lcdfb.h | 100 +++++++++++++
+ 15 files changed, 294 insertions(+), 237 deletions(-)
+ rename arch/arm/mach-at91/include/mach/{atmel_hlcdfb.h => atmel_hlcdc.h} (82%)
+ create mode 100644 arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+ rename {include/video => arch/arm/mach-at91/include/mach}/atmel_lcdc.h (73%)
+ create mode 100644 include/video/atmel_lcdfb.h
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 8df5c1b..1eecff8 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -19,9 +19,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9261.h>
+ #include <mach/at91sam9261_matrix.h>
+ #include <mach/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index eb6bbf8..f0318e9 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -18,9 +18,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9263.h>
+ #include <mach/at91sam9263_matrix.h>
+ #include <mach/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 7ab7e06..73eb743 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -20,9 +20,11 @@
+ #include <linux/atmel-mci.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9g45.h>
+ #include <mach/at91sam9g45_matrix.h>
+ #include <mach/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index f09fff9..0d1b76f 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -15,9 +15,11 @@
+ #include <linux/i2c-gpio.h>
+
+ #include <linux/fb.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <mach/board.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9rl.h>
+ #include <mach/at91sam9rl_matrix.h>
+ #include <mach/at91_matrix.h>
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 18103c5d..5d3b4d6 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -32,7 +32,7 @@
+ #include <linux/gpio_keys.h>
+ #include <linux/input.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -46,6 +46,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+
+ #include "sam9_smc.h"
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 2269be5..2e1c9c5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -34,7 +34,7 @@
+ #include <linux/gpio_keys.h>
+ #include <linux/input.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -47,6 +47,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 82adf58..7c34908 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -33,7 +33,7 @@
+ #include <linux/input.h>
+ #include <linux/leds.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -46,6 +46,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
+index d1882d5..78210f6 100644
+--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
+@@ -28,7 +28,7 @@
+ #include <linux/delay.h>
+
+ #include <mach/hardware.h>
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+ #include <media/soc_camera.h>
+ #include <media/atmel-isi.h>
+
+@@ -42,6 +42,8 @@
+
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+ #include <mach/system_rev.h>
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index e7dc3ea..81d82be 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -19,7 +19,7 @@
+ #include <linux/input.h>
+ #include <linux/gpio_keys.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ #include <asm/setup.h>
+ #include <asm/mach-types.h>
+@@ -32,6 +32,8 @@
+ #include <mach/hardware.h>
+ #include <mach/board.h>
+ #include <mach/at91_aic.h>
++#include <mach/gpio.h>
++#include <mach/atmel_lcdc.h>
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at91_shdwc.h>
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+similarity index 82%
+rename from arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
+rename to arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index a57b79b..9ed7e6e 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdfb.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -19,8 +19,8 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+-#ifndef __ATMEL_HLCD_H__
+-#define __ATMEL_HLCD_H__
++#ifndef __MACH_ATMEL_HLCD_H__
++#define __MACH_ATMEL_HLCD_H__
+
+ /* Lcdc hardware registers */
+ #define ATMEL_LCDC_LCDCFG0 0x0000
+@@ -145,7 +145,7 @@
+ #define LCDC_LCDISR_FIFOERR (0x1 << 4)
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
+-#define LCDC_LCDISR_HEO (0x1 << 11)
++#define LCDC_LCDISR_HEO (0x1 << 10)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
+
+ #define ATMEL_LCDC_BASECHER 0x0040
+@@ -252,153 +252,6 @@
+ #define LCDC_BASECFG4_DMA (0x1 << 8)
+ #define LCDC_BASECFG4_REP (0x1 << 9)
+
+-#define ATMEL_LCDC_OVRCHER1 0x0100
+-#define LCDC_OVRCHER1_CHEN (0x1 << 0)
+-#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
+-#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
+-
+-#define ATMEL_LCDC_OVRCHDR1 0x0104
+-#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
+-#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
+-
+-#define ATMEL_LCDC_OVRCHSR1 0x0108
+-#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
+-#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
+-#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
+-
+-#define ATMEL_LCDC_OVRIER1 0x010C
+-#define LCDC_OVRIER1_DMA (0x1 << 2)
+-#define LCDC_OVRIER1_DSCR (0x1 << 3)
+-#define LCDC_OVRIER1_ADD (0x1 << 4)
+-#define LCDC_OVRIER1_DONE (0x1 << 5)
+-#define LCDC_OVRIER1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRIDR1 0x0110
+-#define LCDC_OVRIDR1_DMA (0x1 << 2)
+-#define LCDC_OVRIDR1_DSCR (0x1 << 3)
+-#define LCDC_OVRIDR1_ADD (0x1 << 4)
+-#define LCDC_OVRIDR1_DONE (0x1 << 5)
+-#define LCDC_OVRIDR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRIMR1 0x0114
+-#define LCDC_OVRIMR1_DMA (0x1 << 2)
+-#define LCDC_OVRIMR1_DSCR (0x1 << 3)
+-#define LCDC_OVRIMR1_ADD (0x1 << 4)
+-#define LCDC_OVRIMR1_DONE (0x1 << 5)
+-#define LCDC_OVRIMR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRISR1 0x0118
+-#define LCDC_OVRISR1_DMA (0x1 << 2)
+-#define LCDC_OVRISR1_DSCR (0x1 << 3)
+-#define LCDC_OVRISR1_ADD (0x1 << 4)
+-#define LCDC_OVRISR1_DONE (0x1 << 5)
+-#define LCDC_OVRISR1_OVR (0x1 << 6)
+-
+-#define ATMEL_LCDC_OVRHEAD1 0x011C
+-
+-#define ATMEL_LCDC_OVRADDR1 0x0120
+-
+-#define ATMEL_LCDC_OVRCTRL1 0x0124
+-#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
+-#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
+-#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
+-#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
+-#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
+-#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
+-
+-#define ATMEL_LCDC_OVRNEXT1 0x0128
+-
+-#define ATMEL_LCDC_OVR1CFG0 0x012C
+-#define LCDC_OVR1CFG0_BLEN_OFFSET 4
+-#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
+-#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
+-#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
+-#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
+-#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
+-#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
+-
+-#define ATMEL_LCDC_OVR1CFG1 0x0130
+-#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
+-#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
+-#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
+-#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
+-#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
+-#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
+-#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
+-#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
+-#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
+-
+-#define ATMEL_LCDC_OVR1CFG2 0x0134
+-#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
+-#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
+-#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
+-#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG3 0x0138
+-#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
+-#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
+-#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
+-#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG4 0x013C
+-
+-#define ATMEL_LCDC_OVR1CFG5 0x0140
+-
+-#define ATMEL_LCDC_OVR1CFG6 0x0144
+-#define LCDC_OVR1CFG6_BDEF_OFFSET 0
+-#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
+-#define LCDC_OVR1CFG6_GDEF_OFFSET 8
+-#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
+-#define LCDC_OVR1CFG6_RDEF_OFFSET 16
+-#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG7 0x0148
+-#define LCDC_OVR1CFG7_BKEY_OFFSET 0
+-#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
+-#define LCDC_OVR1CFG7_GKEY_OFFSET 8
+-#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
+-#define LCDC_OVR1CFG7_RKEY_OFFSET 16
+-#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG8 0x014C
+-#define LCDC_OVR1CFG8_BMASK_OFFSET 0
+-#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
+-#define LCDC_OVR1CFG8_GMASK_OFFSET 8
+-#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
+-#define LCDC_OVR1CFG8_RMASK_OFFSET 16
+-#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
+-
+-#define ATMEL_LCDC_OVR1CFG9 0x0150
+-#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
+-#define LCDC_OVR1CFG9_INV (0x1 << 1)
+-#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
+-#define LCDC_OVR1CFG9_ITER (0x1 << 3)
+-#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
+-#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
+-#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
+-#define LCDC_OVR1CFG9_OVR (0x1 << 7)
+-#define LCDC_OVR1CFG9_DMA (0x1 << 8)
+-#define LCDC_OVR1CFG9_REP (0x1 << 9)
+-#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
+-#define LCDC_OVR1CFG9_GA_OFFSET 16
+-#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
+-
+ #define ATMEL_LCDC_HEOCHER 0x0280
+ #define LCDC_HEOCHER_CHEN (0x1 << 0)
+ #define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
+@@ -859,7 +712,7 @@
+ #define LCDC_HCRCLUT_ACLUT (0xff << LCDC_HCRCLUT_ACLUT_OFFSET)
+
+ /* Base layer CLUT */
+-#define ATMEL_LCDC_LUT(n) (0x0400 + ((n)*4))
++#define ATMEL_HLCDC_LUT 0x0400
+
+
+-#endif /* __ATMEL_HLCDC4_H__ */
++#endif /* __MACH_ATMEL_HLCDC4_H__ */
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+new file mode 100644
+index 0000000..4416403
+--- /dev/null
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc_ovl.h
+@@ -0,0 +1,156 @@
++#ifndef __MACH_ATMEL_HLCD_OVL_H__
++#define __MACH_ATMEL_HLCD_OVL_H__
++
++/*
++ * OVL has a seperate resource which already starts at offset 0x100.
++ * So, these defines start at 0x0. The manual will list them at 0x100.
++ */
++
++#define ATMEL_LCDC_OVRCHER1 0x0000
++#define LCDC_OVRCHER1_CHEN (0x1 << 0)
++#define LCDC_OVRCHER1_UPDATEEN (0x1 << 1)
++#define LCDC_OVRCHER1_A2QEN (0x1 << 2)
++
++#define ATMEL_LCDC_OVRCHDR1 0x0004
++#define LCDC_OVRCHDR1_CHDIS (0x1 << 0)
++#define LCDC_OVRCHDR1_CHRST (0x1 << 8)
++
++#define ATMEL_LCDC_OVRCHSR1 0x0008
++#define LCDC_OVRCHSR1_CHSR (0x1 << 0)
++#define LCDC_OVRCHSR1_UPDATESR (0x1 << 1)
++#define LCDC_OVRCHSR1_A2QSR (0x1 << 2)
++
++#define ATMEL_LCDC_OVRIER1 0x000C
++#define LCDC_OVRIER1_DMA (0x1 << 2)
++#define LCDC_OVRIER1_DSCR (0x1 << 3)
++#define LCDC_OVRIER1_ADD (0x1 << 4)
++#define LCDC_OVRIER1_DONE (0x1 << 5)
++#define LCDC_OVRIER1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIDR1 0x0010
++#define LCDC_OVRIDR1_DMA (0x1 << 2)
++#define LCDC_OVRIDR1_DSCR (0x1 << 3)
++#define LCDC_OVRIDR1_ADD (0x1 << 4)
++#define LCDC_OVRIDR1_DONE (0x1 << 5)
++#define LCDC_OVRIDR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRIMR1 0x0014
++#define LCDC_OVRIMR1_DMA (0x1 << 2)
++#define LCDC_OVRIMR1_DSCR (0x1 << 3)
++#define LCDC_OVRIMR1_ADD (0x1 << 4)
++#define LCDC_OVRIMR1_DONE (0x1 << 5)
++#define LCDC_OVRIMR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRISR1 0x0018
++#define LCDC_OVRISR1_DMA (0x1 << 2)
++#define LCDC_OVRISR1_DSCR (0x1 << 3)
++#define LCDC_OVRISR1_ADD (0x1 << 4)
++#define LCDC_OVRISR1_DONE (0x1 << 5)
++#define LCDC_OVRISR1_OVR (0x1 << 6)
++
++#define ATMEL_LCDC_OVRHEAD1 0x001C
++
++#define ATMEL_LCDC_OVRADDR1 0x0020
++
++#define ATMEL_LCDC_OVRCTRL1 0x0024
++#define LCDC_OVRCTRL1_DFETCH (0x1 << 0)
++#define LCDC_OVRCTRL1_LFETCH (0x1 << 1)
++#define LCDC_OVRCTRL1_DMAIEN (0x1 << 2)
++#define LCDC_OVRCTRL1_DSCRIEN (0x1 << 3)
++#define LCDC_OVRCTRL1_ADDIEN (0x1 << 4)
++#define LCDC_OVRCTRL1_DONEIEN (0x1 << 5)
++
++#define ATMEL_LCDC_OVRNEXT1 0x0028
++
++#define ATMEL_LCDC_OVR1CFG0 0x002C
++#define LCDC_OVR1CFG0_BLEN_OFFSET 4
++#define LCDC_OVR1CFG0_BLEN (0x3 << LCDC_OVR1CFG0_BLEN_OFFSET)
++#define LCDC_OVR1CFG0_BLEN_AHB_SINGLE (0x0 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR4 (0x1 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR8 (0x2 << 4)
++#define LCDC_OVR1CFG0_BLEN_AHB_INCR16 (0x3 << 4)
++#define LCDC_OVR1CFG0_DLBO (0x1 << 8)
++#define LCDC_OVR1CFG0_ROTDIS (0x1 << 12)
++#define LCDC_OVR1CFG0_LOCKDIS (0x1 << 13)
++
++#define ATMEL_LCDC_OVR1CFG1 0x0030
++#define LCDC_OVR1CFG1_CLUTEN (0x1 << 0)
++#define LCDC_OVR1CFG1_RGBMODE_OFFSET 4
++#define LCDC_OVR1CFG1_RGBMODE (0xf << LCDC_OVR1CFG1_RGBMODE_OFFSET)
++#define LCDC_OVR1CFG1_RGBMODE_12BPP_RGB_444 (0x0 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_ARGB_4444 (0x1 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGBA_4444 (0x2 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_RGB_565 (0x3 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_16BPP_TRGB_1555 (0x4 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666 (0x5 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_18BPP_RGB_666_PACKED (0x6 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_1666 (0x7 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_19BPP_TRGB_PACKED (0x8 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888 (0x9 << 4)
++#define LCDC_OVR1CFG1_RGBMODE_24BPP_RGB_888_PACKED (0xA << 4)
++#define LCDC_OVR1CFG1_RGBMODE_25BPP_TRGB_1888 (0xB << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_ARGB_8888 (0xC << 4)
++#define LCDC_OVR1CFG1_RGBMODE_32BPP_RGBA_8888 (0xD << 4)
++#define LCDC_OVR1CFG1_CLUTMODE_OFFSET 8
++#define LCDC_OVR1CFG1_CLUTMODE (0x3 << LCDC_OVR1CFG1_CLUTMODE_OFFSET)
++#define LCDC_OVR1CFG1_CLUTMODE_1BPP (0x0 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_2BPP (0x1 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_4BPP (0x2 << 8)
++#define LCDC_OVR1CFG1_CLUTMODE_8BPP (0x3 << 8)
++
++#define ATMEL_LCDC_OVR1CFG2 0x0034
++#define LCDC_OVR1CFG2_XOFFSET_OFFSET 0
++#define LCDC_OVR1CFG2_XOFFSET (0x7ff << LCDC_OVR1CFG2_XOFFSET_OFFSET)
++#define LCDC_OVR1CFG2_YOFFSET_OFFSET 16
++#define LCDC_OVR1CFG2_YOFFSET (0x7ff << LCDC_OVR1CFG2_YOFFSET_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG3 0x0038
++#define LCDC_OVR1CFG3_XSIZE_OFFSET 0
++#define LCDC_OVR1CFG3_XSIZE (0x7ff << LCDC_OVR1CFG3_XSIZE_OFFSET)
++#define LCDC_OVR1CFG3_YSIZE_OFFSET 16
++#define LCDC_OVR1CFG3_YSIZE (0x7ff << LCDC_OVR1CFG3_YSIZE_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG4 0x003C
++
++#define ATMEL_LCDC_OVR1CFG5 0x0040
++
++#define ATMEL_LCDC_OVR1CFG6 0x0044
++#define LCDC_OVR1CFG6_BDEF_OFFSET 0
++#define LCDC_OVR1CFG6_BDEF (0xff << LCDC_OVR1CFG6_BDEF_OFFSET)
++#define LCDC_OVR1CFG6_GDEF_OFFSET 8
++#define LCDC_OVR1CFG6_GDEF (0xff << LCDC_OVR1CFG6_GDEF_OFFSET)
++#define LCDC_OVR1CFG6_RDEF_OFFSET 16
++#define LCDC_OVR1CFG6_RDEF (0xff << LCDC_OVR1CFG6_RDEF_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG7 0x0048
++#define LCDC_OVR1CFG7_BKEY_OFFSET 0
++#define LCDC_OVR1CFG7_BKEY (0xff << LCDC_OVR1CFG7_BKEY_OFFSET)
++#define LCDC_OVR1CFG7_GKEY_OFFSET 8
++#define LCDC_OVR1CFG7_GKEY (0xff << LCDC_OVR1CFG7_GKEY_OFFST)
++#define LCDC_OVR1CFG7_RKEY_OFFSET 16
++#define LCDC_OVR1CFG7_RKEY (0xff << LCDC_OVR1CFG7_RKEY_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG8 0x004C
++#define LCDC_OVR1CFG8_BMASK_OFFSET 0
++#define LCDC_OVR1CFG8_BMASK (0xff << LCDC_OVR1CFG8_BMASK_OFFSET)
++#define LCDC_OVR1CFG8_GMASK_OFFSET 8
++#define LCDC_OVR1CFG8_GMASK (0xff << LCDC_OVR1CFG8_GMASK_OFFSET)
++#define LCDC_OVR1CFG8_RMASK_OFFSET 16
++#define LCDC_OVR1CFG8_RMASK (0xff << LCDC_OVR1CFG8_RMASK_OFFSET)
++
++#define ATMEL_LCDC_OVR1CFG9 0x0050
++#define LCDC_OVR1CFG9_CRKEY (0x1 << 0)
++#define LCDC_OVR1CFG9_INV (0x1 << 1)
++#define LCDC_OVR1CFG9_ITER2BL (0x1 << 2)
++#define LCDC_OVR1CFG9_ITER (0x1 << 3)
++#define LCDC_OVR1CFG9_REVALPHA (0x1 << 4)
++#define LCDC_OVR1CFG9_GAEN (0x1 << 5)
++#define LCDC_OVR1CFG9_LAEN (0x1 << 6)
++#define LCDC_OVR1CFG9_OVR (0x1 << 7)
++#define LCDC_OVR1CFG9_DMA (0x1 << 8)
++#define LCDC_OVR1CFG9_REP (0x1 << 9)
++#define LCDC_OVR1CFG9_DSTKEY (0x1 << 10)
++#define LCDC_OVR1CFG9_GA_OFFSET 16
++#define LCDC_OVR1CFG9_GA (0xff << LCDC_OVR1CFG9_GA_OFFSET)
++
++#endif /* __MACH_ATMEL_HLCD_OVL_H__ */
+diff --git a/include/video/atmel_lcdc.h b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+similarity index 73%
+rename from include/video/atmel_lcdc.h
+rename to arch/arm/mach-at91/include/mach/atmel_lcdc.h
+index 6031b5a..248fed3 100644
+--- a/include/video/atmel_lcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_lcdc.h
+@@ -19,79 +19,8 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+-#ifndef __ATMEL_LCDC_H__
+-#define __ATMEL_LCDC_H__
+-
+-#include <linux/workqueue.h>
+-#include <linux/interrupt.h>
+-#include <linux/backlight.h>
+-
+-/* Way LCD wires are connected to the chip:
+- * Some Atmel chips use BGR color mode (instead of standard RGB)
+- * A swapped wiring onboard can bring to RGB mode.
+- */
+-#define ATMEL_LCDC_WIRING_BGR 0
+-#define ATMEL_LCDC_WIRING_RGB 1
+-#define ATMEL_LCDC_WIRING_RGB555 2
+-
+-#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
+-
+-extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
+-extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
+-extern int __atmel_lcdfb_probe(struct platform_device *pdev,
+- struct atmel_lcdfb_devdata *devdata);
+-extern int __atmel_lcdfb_remove(struct platform_device *pdev);
+-
+-struct atmel_lcdfb_info;
+-
+-struct atmel_lcdfb_devdata {
+- int (*setup_core)(struct fb_info *info);
+- void (*start)(struct atmel_lcdfb_info *sinfo);
+- void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
+- irqreturn_t (*isr)(int irq, void *dev_id);
+- void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
+- void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
+- void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+- const struct backlight_ops *bl_ops;
+- int fbinfo_flags;
+- u32 lut_base;
+-};
+-
+- /* LCD Controller info data structure, stored in device platform_data */
+-struct atmel_lcdfb_info {
+- spinlock_t lock;
+- struct fb_info *info;
+- void __iomem *mmio;
+- int irq_base;
+- struct atmel_lcdfb_devdata *dev_data;
+- struct work_struct task;
+-
+- unsigned int guard_time;
+- unsigned int smem_len;
+- struct platform_device *pdev;
+- struct clk *bus_clk;
+- struct clk *lcdc_clk;
+-
+-#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
+- struct backlight_device *backlight;
+- u8 bl_power;
+-#endif
+- bool lcdcon_is_backlight;
+- bool lcdcon_pol_negative;
+- bool alpha_enabled;
+- u8 saved_lcdcon;
+-
+- u8 default_bpp;
+- u8 lcd_wiring_mode;
+- unsigned int default_lcdcon2;
+- unsigned int default_dmacon;
+- void (*atmel_lcdfb_power_control)(int on);
+- struct fb_monspecs *default_monspecs;
+- u32 pseudo_palette[16];
+-};
+-
+-#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+-#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
++#ifndef __MACH_ATMEL_LCDC_H__
++#define __MACH_ATMEL_LCDC_H__
+
+ #define ATMEL_LCDC_DMABADDR1 0x00
+ #define ATMEL_LCDC_DMABADDR2 0x04
+@@ -245,4 +174,4 @@ struct atmel_lcdfb_info {
+
+ #define ATMEL_LCDC_LUT 0x0c00
+
+-#endif /* __ATMEL_LCDC_H__ */
++#endif /* __MACH_ATMEL_LCDC_H__ */
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 7a48e9c..8d7992c 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -19,8 +19,9 @@
+
+ #include <mach/board.h>
+ #include <mach/cpu.h>
++#include <mach/atmel_lcdc.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 20a4e4f..060d41f 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -22,7 +22,7 @@
+ #include <mach/cpu.h>
+ #include <mach/gpio.h>
+
+-#include <video/atmel_lcdc.h>
++#include <video/atmel_lcdfb.h>
+
+ /* configurable parameters */
+ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
+new file mode 100644
+index 0000000..3a0dfc7
+--- /dev/null
++++ b/include/video/atmel_lcdfb.h
+@@ -0,0 +1,100 @@
++/*
++ * Header file for AT91/AT32 LCD Controller
++ *
++ * Data structure and register user interface
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * 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.
++ *
++ * This program 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 General Public License for more details.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef __ATMEL_LCDC_H__
++#define __ATMEL_LCDC_H__
++
++#include <linux/workqueue.h>
++#include <linux/interrupt.h>
++#include <linux/backlight.h>
++
++/* Way LCD wires are connected to the chip:
++ * Some Atmel chips use BGR color mode (instead of standard RGB)
++ * A swapped wiring onboard can bring to RGB mode.
++ */
++#define ATMEL_LCDC_WIRING_BGR 0
++#define ATMEL_LCDC_WIRING_RGB 1
++#define ATMEL_LCDC_WIRING_RGB555 2
++
++#define ATMEL_LCDC_STOP_NOWAIT (1 << 0)
++
++struct atmel_lcdfb_info;
++
++struct atmel_lcdfb_devdata {
++ int (*setup_core)(struct fb_info *info);
++ void (*start)(struct atmel_lcdfb_info *sinfo);
++ void (*stop)(struct atmel_lcdfb_info *sinfo, u32 flags);
++ irqreturn_t (*isr)(int irq, void *dev_id);
++ void (*update_dma)(struct fb_info *info, struct fb_var_screeninfo *var);
++ void (*init_contrast)(struct atmel_lcdfb_info *sinfo);
++ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
++ const struct backlight_ops *bl_ops;
++ int fbinfo_flags;
++ u32 lut_base;
++ int dma_desc_size;
++};
++
++extern void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo);
++extern void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo);
++extern int __atmel_lcdfb_probe(struct platform_device *pdev,
++ struct atmel_lcdfb_devdata *devdata);
++extern int __atmel_lcdfb_remove(struct platform_device *pdev);
++
++ /* LCD Controller info data structure, stored in device platform_data */
++struct atmel_lcdfb_info {
++ spinlock_t lock;
++ struct fb_info *info;
++ void __iomem *mmio;
++ int irq_base;
++ struct atmel_lcdfb_devdata *dev_data;
++ struct work_struct task;
++
++ void *dma_desc;
++ dma_addr_t dma_desc_phys;
++
++ unsigned int guard_time;
++ unsigned int smem_len;
++ struct platform_device *pdev;
++ struct clk *bus_clk;
++ struct clk *lcdc_clk;
++
++#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC
++ struct backlight_device *backlight;
++ u8 bl_power;
++#endif
++ bool lcdcon_is_backlight;
++ bool lcdcon_pol_negative;
++ bool alpha_enabled;
++ u8 saved_lcdcon;
++
++ u8 default_bpp;
++ u8 lcd_wiring_mode;
++ unsigned int default_lcdcon2;
++ unsigned int default_dmacon;
++ void (*atmel_lcdfb_power_control)(int on);
++ struct fb_monspecs *default_monspecs;
++ u32 pseudo_palette[16];
++};
++
++#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
++#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
++
++#endif /* __ATMEL_LCDC_H__ */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 9f4aec64067d8c95e8f71489090fbf0d04947675 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 16 May 2012 15:25:59 +0200
-Subject: mmc: atmel-mci: change the state machine for compatibility with old
- IP
-
-The state machine use in atmel-mci can't work with old IP versions
-(< 0x200). This patch allows to have a common state machine for all
-versions in order to remove at91-mci driver only used for old versions.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Chris Ball <cjb@laptop.org>
----
- drivers/mmc/host/atmel-mci.c | 278 +++++++++++++++++++++++++------------------
- 1 file changed, 162 insertions(+), 116 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 6f56ef0..1baaaebb 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -45,19 +45,19 @@
- #define ATMCI_DMA_THRESHOLD 16
-
- enum {
-- EVENT_CMD_COMPLETE = 0,
-+ EVENT_CMD_RDY = 0,
- EVENT_XFER_COMPLETE,
-- EVENT_DATA_COMPLETE,
-+ EVENT_NOTBUSY,
- EVENT_DATA_ERROR,
- };
-
- enum atmel_mci_state {
- STATE_IDLE = 0,
- STATE_SENDING_CMD,
-- STATE_SENDING_DATA,
-- STATE_DATA_BUSY,
-+ STATE_DATA_XFER,
-+ STATE_WAITING_NOTBUSY,
- STATE_SENDING_STOP,
-- STATE_DATA_ERROR,
-+ STATE_END_REQUEST,
- };
-
- enum atmci_xfer_dir {
-@@ -709,7 +709,6 @@ static void atmci_pdc_complete(struct atmel_mci *host)
- if (host->data) {
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
-- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
- }
-
-@@ -835,7 +834,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
- iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
- } else {
- dir = DMA_TO_DEVICE;
-- iflags |= ATMCI_ENDTX | ATMCI_TXBUFE;
-+ iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
- }
-
- /* Set BLKLEN */
-@@ -975,8 +974,7 @@ static void atmci_stop_transfer(struct atmel_mci *host)
- */
- static void atmci_stop_transfer_pdc(struct atmel_mci *host)
- {
-- atmci_set_pending(host, EVENT_XFER_COMPLETE);
-- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-+ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
- }
-
- static void atmci_stop_transfer_dma(struct atmel_mci *host)
-@@ -1012,6 +1010,7 @@ static void atmci_start_request(struct atmel_mci *host,
-
- host->pending_events = 0;
- host->completed_events = 0;
-+ host->cmd_status = 0;
- host->data_status = 0;
-
- if (host->need_reset) {
-@@ -1029,7 +1028,7 @@ static void atmci_start_request(struct atmel_mci *host,
-
- iflags = atmci_readl(host, ATMCI_IMR);
- if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
-- dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
-+ dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
- iflags);
-
- if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
-@@ -1367,19 +1366,6 @@ static void atmci_command_complete(struct atmel_mci *host,
- cmd->error = -EIO;
- else
- cmd->error = 0;
--
-- if (cmd->error) {
-- dev_dbg(&host->pdev->dev,
-- "command error: status=0x%08x\n", status);
--
-- if (cmd->data) {
-- host->stop_transfer(host);
-- host->data = NULL;
-- atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY
-- | ATMCI_TXRDY | ATMCI_RXRDY
-- | ATMCI_DATA_ERROR_FLAGS);
-- }
-- }
- }
-
- static void atmci_detect_change(unsigned long data)
-@@ -1442,23 +1428,21 @@ static void atmci_detect_change(unsigned long data)
- break;
- case STATE_SENDING_CMD:
- mrq->cmd->error = -ENOMEDIUM;
-- if (!mrq->data)
-- break;
-- /* fall through */
-- case STATE_SENDING_DATA:
-+ if (mrq->data)
-+ host->stop_transfer(host);
-+ break;
-+ case STATE_DATA_XFER:
- mrq->data->error = -ENOMEDIUM;
- host->stop_transfer(host);
- break;
-- case STATE_DATA_BUSY:
-- case STATE_DATA_ERROR:
-- if (mrq->data->error == -EINPROGRESS)
-- mrq->data->error = -ENOMEDIUM;
-- if (!mrq->stop)
-- break;
-- /* fall through */
-+ case STATE_WAITING_NOTBUSY:
-+ mrq->data->error = -ENOMEDIUM;
-+ break;
- case STATE_SENDING_STOP:
- mrq->stop->error = -ENOMEDIUM;
- break;
-+ case STATE_END_REQUEST:
-+ break;
- }
-
- atmci_request_end(host, mrq);
-@@ -1486,7 +1470,6 @@ static void atmci_tasklet_func(unsigned long priv)
- struct atmel_mci *host = (struct atmel_mci *)priv;
- struct mmc_request *mrq = host->mrq;
- struct mmc_data *data = host->data;
-- struct mmc_command *cmd = host->cmd;
- enum atmel_mci_state state = host->state;
- enum atmel_mci_state prev_state;
- u32 status;
-@@ -1508,101 +1491,164 @@ static void atmci_tasklet_func(unsigned long priv)
- break;
-
- case STATE_SENDING_CMD:
-+ /*
-+ * Command has been sent, we are waiting for command
-+ * ready. Then we have three next states possible:
-+ * END_REQUEST by default, WAITING_NOTBUSY if it's a
-+ * command needing it or DATA_XFER if there is data.
-+ */
- if (!atmci_test_and_clear_pending(host,
-- EVENT_CMD_COMPLETE))
-+ EVENT_CMD_RDY))
- break;
-
- host->cmd = NULL;
-- atmci_set_completed(host, EVENT_CMD_COMPLETE);
-+ atmci_set_completed(host, EVENT_CMD_RDY);
- atmci_command_complete(host, mrq->cmd);
-- if (!mrq->data || cmd->error) {
-- atmci_request_end(host, host->mrq);
-- goto unlock;
-- }
-+ if (mrq->data) {
-+ /*
-+ * If there is a command error don't start
-+ * data transfer.
-+ */
-+ if (mrq->cmd->error) {
-+ host->stop_transfer(host);
-+ host->data = NULL;
-+ atmci_writel(host, ATMCI_IDR,
-+ ATMCI_TXRDY | ATMCI_RXRDY
-+ | ATMCI_DATA_ERROR_FLAGS);
-+ state = STATE_END_REQUEST;
-+ } else
-+ state = STATE_DATA_XFER;
-+ } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
-+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-+ state = STATE_WAITING_NOTBUSY;
-+ } else
-+ state = STATE_END_REQUEST;
-
-- prev_state = state = STATE_SENDING_DATA;
-- /* fall through */
-+ break;
-
-- case STATE_SENDING_DATA:
-+ case STATE_DATA_XFER:
- if (atmci_test_and_clear_pending(host,
- EVENT_DATA_ERROR)) {
-- host->stop_transfer(host);
-- if (data->stop)
-- atmci_send_stop_cmd(host, data);
-- state = STATE_DATA_ERROR;
-+ atmci_set_completed(host, EVENT_DATA_ERROR);
-+ state = STATE_END_REQUEST;
- break;
- }
-
-+ /*
-+ * A data transfer is in progress. The event expected
-+ * to move to the next state depends of data transfer
-+ * type (PDC or DMA). Once transfer done we can move
-+ * to the next step which is WAITING_NOTBUSY in write
-+ * case and directly SENDING_STOP in read case.
-+ */
- if (!atmci_test_and_clear_pending(host,
- EVENT_XFER_COMPLETE))
- break;
-
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
-- prev_state = state = STATE_DATA_BUSY;
-- /* fall through */
-
-- case STATE_DATA_BUSY:
-- if (!atmci_test_and_clear_pending(host,
-- EVENT_DATA_COMPLETE))
-- break;
--
-- host->data = NULL;
-- atmci_set_completed(host, EVENT_DATA_COMPLETE);
-- status = host->data_status;
-- if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
-- if (status & ATMCI_DTOE) {
-- dev_dbg(&host->pdev->dev,
-- "data timeout error\n");
-- data->error = -ETIMEDOUT;
-- } else if (status & ATMCI_DCRCE) {
-- dev_dbg(&host->pdev->dev,
-- "data CRC error\n");
-- data->error = -EILSEQ;
-- } else {
-- dev_dbg(&host->pdev->dev,
-- "data FIFO error (status=%08x)\n",
-- status);
-- data->error = -EIO;
-- }
-+ if (host->data->flags & MMC_DATA_WRITE) {
-+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-+ state = STATE_WAITING_NOTBUSY;
-+ } else if (host->mrq->stop) {
-+ atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
-+ atmci_send_stop_cmd(host, data);
-+ state = STATE_SENDING_STOP;
- } else {
-+ host->data = NULL;
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
-- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS);
-+ state = STATE_END_REQUEST;
- }
-+ break;
-
-- if (!data->stop) {
-- atmci_request_end(host, host->mrq);
-- goto unlock;
-- }
-+ case STATE_WAITING_NOTBUSY:
-+ /*
-+ * We can be in the state for two reasons: a command
-+ * requiring waiting not busy signal (stop command
-+ * included) or a write operation. In the latest case,
-+ * we need to send a stop command.
-+ */
-+ if (!atmci_test_and_clear_pending(host,
-+ EVENT_NOTBUSY))
-+ break;
-
-- prev_state = state = STATE_SENDING_STOP;
-- if (!data->error)
-- atmci_send_stop_cmd(host, data);
-- /* fall through */
-+ atmci_set_completed(host, EVENT_NOTBUSY);
-+
-+ if (host->data) {
-+ /*
-+ * For some commands such as CMD53, even if
-+ * there is data transfer, there is no stop
-+ * command to send.
-+ */
-+ if (host->mrq->stop) {
-+ atmci_writel(host, ATMCI_IER,
-+ ATMCI_CMDRDY);
-+ atmci_send_stop_cmd(host, data);
-+ state = STATE_SENDING_STOP;
-+ } else {
-+ host->data = NULL;
-+ data->bytes_xfered = data->blocks
-+ * data->blksz;
-+ data->error = 0;
-+ state = STATE_END_REQUEST;
-+ }
-+ } else
-+ state = STATE_END_REQUEST;
-+ break;
-
- case STATE_SENDING_STOP:
-+ /*
-+ * In this state, it is important to set host->data to
-+ * NULL (which is tested in the waiting notbusy state)
-+ * in order to go to the end request state instead of
-+ * sending stop again.
-+ */
- if (!atmci_test_and_clear_pending(host,
-- EVENT_CMD_COMPLETE))
-+ EVENT_CMD_RDY))
- break;
-
- host->cmd = NULL;
-+ host->data = NULL;
-+ data->bytes_xfered = data->blocks * data->blksz;
-+ data->error = 0;
- atmci_command_complete(host, mrq->stop);
-- atmci_request_end(host, host->mrq);
-- goto unlock;
-+ if (mrq->stop->error) {
-+ host->stop_transfer(host);
-+ atmci_writel(host, ATMCI_IDR,
-+ ATMCI_TXRDY | ATMCI_RXRDY
-+ | ATMCI_DATA_ERROR_FLAGS);
-+ state = STATE_END_REQUEST;
-+ } else {
-+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-+ state = STATE_WAITING_NOTBUSY;
-+ }
-+ break;
-
-- case STATE_DATA_ERROR:
-- if (!atmci_test_and_clear_pending(host,
-- EVENT_XFER_COMPLETE))
-- break;
-+ case STATE_END_REQUEST:
-+ atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY
-+ | ATMCI_DATA_ERROR_FLAGS);
-+ status = host->data_status;
-+ if (unlikely(status)) {
-+ host->stop_transfer(host);
-+ host->data = NULL;
-+ if (status & ATMCI_DTOE) {
-+ data->error = -ETIMEDOUT;
-+ } else if (status & ATMCI_DCRCE) {
-+ data->error = -EILSEQ;
-+ } else {
-+ data->error = -EIO;
-+ }
-+ }
-
-- state = STATE_DATA_BUSY;
-+ atmci_request_end(host, host->mrq);
-+ state = STATE_IDLE;
- break;
- }
- } while (state != prev_state);
-
- host->state = state;
-
--unlock:
- spin_unlock(&host->lock);
- }
-
-@@ -1655,9 +1701,6 @@ static void atmci_read_data_pio(struct atmel_mci *host)
- | ATMCI_DATA_ERROR_FLAGS));
- host->data_status = status;
- data->bytes_xfered += nbytes;
-- smp_wmb();
-- atmci_set_pending(host, EVENT_DATA_ERROR);
-- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & ATMCI_RXRDY);
-@@ -1726,9 +1769,6 @@ static void atmci_write_data_pio(struct atmel_mci *host)
- | ATMCI_DATA_ERROR_FLAGS));
- host->data_status = status;
- data->bytes_xfered += nbytes;
-- smp_wmb();
-- atmci_set_pending(host, EVENT_DATA_ERROR);
-- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & ATMCI_TXRDY);
-@@ -1746,16 +1786,6 @@ done:
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- }
-
--static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
--{
-- atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
--
-- host->cmd_status = status;
-- smp_wmb();
-- atmci_set_pending(host, EVENT_CMD_COMPLETE);
-- tasklet_schedule(&host->tasklet);
--}
--
- static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
- {
- int i;
-@@ -1784,8 +1814,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
-
- if (pending & ATMCI_DATA_ERROR_FLAGS) {
- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
-- | ATMCI_RXRDY | ATMCI_TXRDY);
-- pending &= atmci_readl(host, ATMCI_IMR);
-+ | ATMCI_RXRDY | ATMCI_TXRDY
-+ | ATMCI_ENDRX | ATMCI_ENDTX
-+ | ATMCI_RXBUFF | ATMCI_TXBUFE);
-
- host->data_status = status;
- smp_wmb();
-@@ -1843,23 +1874,38 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- }
- }
-
-+ /*
-+ * First mci IPs, so mainly the ones having pdc, have some
-+ * issues with the notbusy signal. You can't get it after
-+ * data transmission if you have not sent a stop command.
-+ * The appropriate workaround is to use the BLKE signal.
-+ */
-+ if (pending & ATMCI_BLKE) {
-+ atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
-+ smp_wmb();
-+ atmci_set_pending(host, EVENT_NOTBUSY);
-+ tasklet_schedule(&host->tasklet);
-+ }
-
- if (pending & ATMCI_NOTBUSY) {
-- atmci_writel(host, ATMCI_IDR,
-- ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY);
-- if (!host->data_status)
-- host->data_status = status;
-+ atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
- smp_wmb();
-- atmci_set_pending(host, EVENT_DATA_COMPLETE);
-+ atmci_set_pending(host, EVENT_NOTBUSY);
- tasklet_schedule(&host->tasklet);
- }
-+
- if (pending & ATMCI_RXRDY)
- atmci_read_data_pio(host);
- if (pending & ATMCI_TXRDY)
- atmci_write_data_pio(host);
-
-- if (pending & ATMCI_CMDRDY)
-- atmci_cmd_interrupt(host, status);
-+ if (pending & ATMCI_CMDRDY) {
-+ atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
-+ host->cmd_status = status;
-+ smp_wmb();
-+ atmci_set_pending(host, EVENT_CMD_RDY);
-+ tasklet_schedule(&host->tasklet);
-+ }
-
- if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
- atmci_sdio_interrupt(host, status);
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From d243a7c47bee93f8dc2544dbd26ce7b5dd879e96 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 16 May 2012 15:26:00 +0200
-Subject: mmc: atmel-mci: add support for version lower than v2xx
-
-Fix mci IP bugs and endianness issue.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Chris Ball <cjb@laptop.org>
----
- drivers/mmc/host/atmel-mci.c | 62 +++++++++++++++++++++++++++++++++++++++++---
- 1 file changed, 58 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 1baaaebb..5fe8300 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -78,6 +78,9 @@ struct atmel_mci_caps {
- bool has_highspeed;
- bool has_rwproof;
- bool has_odd_clk_div;
-+ bool has_bad_data_ordering;
-+ bool need_reset_after_xfer;
-+ bool need_blksz_mul_4;
- };
-
- struct atmel_mci_dma {
-@@ -121,6 +124,7 @@ struct atmel_mci_dma {
- * @queue: List of slots waiting for access to the controller.
- * @need_clock_update: Update the clock rate before the next request.
- * @need_reset: Reset controller before next request.
-+ * @timer: Timer to balance the data timeout error flag which cannot rise.
- * @mode_reg: Value of the MR register.
- * @cfg_reg: Value of the CFG register.
- * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
-@@ -197,6 +201,7 @@ struct atmel_mci {
-
- bool need_clock_update;
- bool need_reset;
-+ struct timer_list timer;
- u32 mode_reg;
- u32 cfg_reg;
- unsigned long bus_hz;
-@@ -493,6 +498,27 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host)
- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
- }
-
-+static void atmci_timeout_timer(unsigned long data)
-+{
-+ struct atmel_mci *host;
-+
-+ host = (struct atmel_mci *)data;
-+
-+ dev_dbg(&host->pdev->dev, "software timeout\n");
-+
-+ if (host->mrq->cmd->data) {
-+ host->mrq->cmd->data->error = -ETIMEDOUT;
-+ host->data = NULL;
-+ } else {
-+ host->mrq->cmd->error = -ETIMEDOUT;
-+ host->cmd = NULL;
-+ }
-+ host->need_reset = 1;
-+ host->state = STATE_END_REQUEST;
-+ smp_wmb();
-+ tasklet_schedule(&host->tasklet);
-+}
-+
- static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
- unsigned int ns)
- {
-@@ -692,13 +718,18 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
- static void atmci_pdc_complete(struct atmel_mci *host)
- {
- int transfer_size = host->data->blocks * host->data->blksz;
-+ int i;
-
- atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- if ((!host->caps.has_rwproof)
-- && (host->data->flags & MMC_DATA_READ))
-+ && (host->data->flags & MMC_DATA_READ)) {
-+ if (host->caps.has_bad_data_ordering)
-+ for (i = 0; i < transfer_size; i++)
-+ host->buffer[i] = swab32(host->buffer[i]);
- sg_copy_from_buffer(host->data->sg, host->data->sg_len,
- host->buffer, transfer_size);
-+ }
-
- atmci_pdc_cleanup(host);
-
-@@ -819,6 +850,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
- u32 iflags, tmp;
- unsigned int sg_len;
- enum dma_data_direction dir;
-+ int i;
-
- data->error = -EINPROGRESS;
-
-@@ -848,9 +880,13 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
-
- if ((!host->caps.has_rwproof)
-- && (host->data->flags & MMC_DATA_WRITE))
-+ && (host->data->flags & MMC_DATA_WRITE)) {
- sg_copy_to_buffer(host->data->sg, host->data->sg_len,
- host->buffer, host->data_size);
-+ if (host->caps.has_bad_data_ordering)
-+ for (i = 0; i < host->data_size; i++)
-+ host->buffer[i] = swab32(host->buffer[i]);
-+ }
-
- if (host->data_size)
- atmci_pdc_set_both_buf(host,
-@@ -1013,7 +1049,7 @@ static void atmci_start_request(struct atmel_mci *host,
- host->cmd_status = 0;
- host->data_status = 0;
-
-- if (host->need_reset) {
-+ if (host->need_reset || host->caps.need_reset_after_xfer) {
- iflags = atmci_readl(host, ATMCI_IMR);
- iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
-@@ -1077,6 +1113,8 @@ static void atmci_start_request(struct atmel_mci *host,
- * prepared yet.)
- */
- atmci_writel(host, ATMCI_IER, iflags);
-+
-+ mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
- }
-
- static void atmci_queue_request(struct atmel_mci *host,
-@@ -1342,6 +1380,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
- host->state = STATE_IDLE;
- }
-
-+ del_timer(&host->timer);
-+
- spin_unlock(&host->lock);
- mmc_request_done(prev_mmc, mrq);
- spin_lock(&host->lock);
-@@ -1364,7 +1404,12 @@ static void atmci_command_complete(struct atmel_mci *host,
- cmd->error = -EILSEQ;
- else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))
- cmd->error = -EIO;
-- else
-+ else if (host->mrq->data && (host->mrq->data->blksz & 3)) {
-+ if (host->caps.need_blksz_mul_4) {
-+ cmd->error = -EINVAL;
-+ host->need_reset = 1;
-+ }
-+ } else
- cmd->error = 0;
- }
-
-@@ -2121,6 +2166,9 @@ static void __init atmci_get_cap(struct atmel_mci *host)
- host->caps.has_highspeed = 0;
- host->caps.has_rwproof = 0;
- host->caps.has_odd_clk_div = 0;
-+ host->caps.has_bad_data_ordering = 1;
-+ host->caps.need_reset_after_xfer = 1;
-+ host->caps.need_blksz_mul_4 = 1;
-
- /* keep only major version number */
- switch (version & 0xf00) {
-@@ -2140,7 +2188,11 @@ static void __init atmci_get_cap(struct atmel_mci *host)
- host->caps.has_highspeed = 1;
- case 0x200:
- host->caps.has_rwproof = 1;
-+ host->caps.need_blksz_mul_4 = 0;
- case 0x100:
-+ host->caps.has_bad_data_ordering = 0;
-+ host->caps.need_reset_after_xfer = 0;
-+ case 0x0:
- break;
- default:
- host->caps.has_pdc = 0;
-@@ -2259,6 +2311,8 @@ static int __init atmci_probe(struct platform_device *pdev)
- }
- }
-
-+ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
-+
- dev_info(&pdev->dev,
- "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
- host->mapbase, irq, nr_slots);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 3ceb9c35a7c43f0762c0a857a49a3633fef821fd Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 23 May 2011 15:36:52 +0200
+Subject: video: atmel_hlcdfb: add new driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/Kconfig | 9 +
+ drivers/video/Makefile | 1 +
+ drivers/video/atmel_hlcdfb.c | 514 +++++++++++++++++++++++++++++++++++++++
+ drivers/video/atmel_lcdfb_core.c | 15 ++
+ 4 files changed, 539 insertions(+)
+ create mode 100644 drivers/video/atmel_hlcdfb.c
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index a290be5..ceccaa3 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -1028,6 +1028,15 @@ config FB_ATMEL_STN
+
+ If unsure, say N.
+
++config FB_ATMEL_HLCD
++ tristate "AT91 HLCD Controller support"
++ depends on FB && HAVE_FB_ATMEL
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ help
++ This enables support for the AT91 HLCD Controller.
++
+ config FB_NVIDIA
+ tristate "nVidia Framebuffer Support"
+ depends on FB && PCI
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 37c5625..36320ea 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -96,6 +96,7 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o
+ obj-$(CONFIG_FB_HIT) += hitfb.o
+ obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+ obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o
++obj-$(CONFIG_FB_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o
+ obj-$(CONFIG_FB_PVR2) += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1) += sstfb.o
+ obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+new file mode 100644
+index 0000000..b772841
+--- /dev/null
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -0,0 +1,514 @@
++/*
++ * Driver for AT91/AT32 LCD Controller
++ *
++ * Copyright (C) 2007 Atmel Corporation
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file COPYING in the main directory of this archive for
++ * more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/backlight.h>
++#include <linux/fb.h>
++#include <linux/clk.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <mach/board.h>
++#include <mach/cpu.h>
++#include <mach/atmel_hlcdc.h>
++#include <mach/atmel_hlcdc_ovl.h>
++
++#include <video/atmel_lcdfb.h>
++
++#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
++ | FBINFO_PARTIAL_PAN_OK \
++ | FBINFO_HWACCEL_YPAN)
++
++#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
++
++struct atmel_hlcd_dma_desc {
++ u32 address;
++ u32 control;
++ u32 next;
++};
++
++static void atmel_hlcdfb_update_dma_base(struct fb_info *info,
++
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++ struct atmel_hlcd_dma_desc *desc;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = sinfo->dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
++ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEADDR, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN);
++}
++
++static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
++ struct fb_var_screeninfo *var)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ struct fb_fix_screeninfo *fix = &info->fix;
++ unsigned long dma_addr;
++ struct atmel_hlcd_dma_desc *desc;
++
++ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
++ + var->xoffset * var->bits_per_pixel / 8);
++
++ dma_addr &= ~3UL;
++
++ /* Setup the DMA descriptor, this descriptor will loop to itself */
++ desc = sinfo->dma_desc;
++
++ desc->address = dma_addr;
++ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
++ desc->control = LCDC_OVRCTRL1_ADDIEN | LCDC_OVRCTRL1_DSCRIEN
++ | LCDC_OVRCTRL1_DMAIEN | LCDC_OVRCTRL1_DFETCH;
++ desc->next = sinfo->dma_desc_phys;
++
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRADDR1, dma_addr);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCTRL1, desc->control);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRNEXT1, sinfo->dma_desc_phys);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
++}
++
++/* some bl->props field just changed */
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++ int power = sinfo->bl_power;
++ int brightness = bl->props.brightness;
++ u32 reg;
++
++ /* REVISIT there may be a meaningful difference between
++ * fb_blank and power ... there seem to be some cases
++ * this doesn't handle correctly.
++ */
++ if (bl->props.fb_blank != sinfo->bl_power)
++ power = bl->props.fb_blank;
++ else if (bl->props.power != sinfo->bl_power)
++ power = bl->props.power;
++
++ if (brightness < 0 && power == FB_BLANK_UNBLANK)
++ brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6)
++ >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ else if (power != FB_BLANK_UNBLANK)
++ brightness = 0;
++
++ reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL;
++ reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg);
++
++ bl->props.fb_blank = bl->props.power = sinfo->bl_power = power;
++
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ struct atmel_lcdfb_info *sinfo = bl_get_data(bl);
++
++ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
++}
++
++static const struct backlight_ops atmel_hlcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
++
++static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
++{
++ /* have some default contrast/backlight settings */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL |
++ (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET));
++}
++
++void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
++{
++ u32 value;
++
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_CLKEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_SYNCEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_DISPEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ value = lcdc_readl(sinfo, ATMEL_LCDC_LCDEN);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, value | LCDC_LCDEN_PWMEN);
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++}
++
++static void atmel_hlcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags)
++{
++ /* Disable DISP signal */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS))
++ msleep(1);
++ /* Disable synchronization */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS))
++ msleep(1);
++ /* Disable pixel clock */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS))
++ msleep(1);
++ /* Disable PWM */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
++ while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS))
++ msleep(1);
++
++ if (!(flags & ATMEL_LCDC_STOP_NOWAIT))
++ /* Wait for the end of DMA transfer */
++ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA))
++ msleep(10);
++ //FIXME: OVL DMA?
++}
++
++static u32 atmel_hlcdfb_get_rgbmode(struct fb_info *info)
++{
++ u32 value = 0;
++
++ switch (info->var.bits_per_pixel) {
++ case 1:
++ value = LCDC_BASECFG1_CLUTMODE_1BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 2:
++ value = LCDC_BASECFG1_CLUTMODE_2BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 4:
++ value = LCDC_BASECFG1_CLUTMODE_4BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 8:
++ value = LCDC_BASECFG1_CLUTMODE_8BPP | LCDC_BASECFG1_CLUTEN;
++ break;
++ case 12:
++ value = LCDC_BASECFG1_RGBMODE_12BPP_RGB_444;
++ break;
++ case 16:
++ if (info->var.transp.offset)
++ value = LCDC_BASECFG1_RGBMODE_16BPP_ARGB_4444;
++ else
++ value = LCDC_BASECFG1_RGBMODE_16BPP_RGB_565;
++ break;
++ case 18:
++ value = LCDC_BASECFG1_RGBMODE_18BPP_RGB_666_PACKED;
++ break;
++ case 24:
++ value = LCDC_BASECFG1_RGBMODE_24BPP_RGB_888_PACKED;
++ break;
++ case 32:
++ value = LCDC_BASECFG1_RGBMODE_32BPP_ARGB_8888;
++ break;
++ default:
++ dev_err(info->device, "Cannot set video mode for %dbpp\n",
++ info->var.bits_per_pixel);
++ break;
++ }
++
++ return value;
++}
++
++static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ unsigned long value;
++ unsigned long clk_value_khz;
++
++ dev_dbg(info->device, "%s:\n", __func__);
++ /* Set pixel clock */
++ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
++
++ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++
++ if (value < 1) {
++ dev_notice(info->device, "using system clock as pixel clock\n");
++ value = LCDC_LCDCFG0_CLKPOL | LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ } else {
++ info->var.pixclock = KHZ2PICOS(clk_value_khz / value);
++ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
++ PICOS2KHZ(info->var.pixclock));
++ value = value - 2;
++ dev_dbg(info->device, " * programming CLKDIV = 0x%08lx\n",
++ value);
++ value = (value << LCDC_LCDCFG0_CLKDIV_OFFSET)
++ | LCDC_LCDCFG0_CLKPOL
++ | LCDC_LCDCFG0_CGDISBASE;
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value);
++ }
++
++ /* Initialize control register 5 */
++ /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */
++ value = sinfo->default_lcdcon2;
++ value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET)
++ | LCDC_LCDCFG5_DISPDLY
++ | LCDC_LCDCFG5_VSPDLYS;
++
++ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
++ value |= LCDC_LCDCFG5_HSPOL;
++ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
++ value |= LCDC_LCDCFG5_VSPOL;
++
++ dev_dbg(info->device, " * LCDC_LCDCFG5 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG5, value);
++
++ /* Vertical & Horizontal Timing */
++ value = (info->var.vsync_len - 1) << LCDC_LCDCFG1_VSPW_OFFSET;
++ value |= (info->var.hsync_len - 1) << LCDC_LCDCFG1_HSPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG1 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG1, value);
++
++ value = (info->var.lower_margin) << LCDC_LCDCFG2_VBPW_OFFSET;
++ value |= (info->var.upper_margin - 1) << LCDC_LCDCFG2_VFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG2 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG2, value);
++
++ value = (info->var.right_margin - 1) << LCDC_LCDCFG3_HBPW_OFFSET;
++ value |= (info->var.left_margin - 1) << LCDC_LCDCFG3_HFPW_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG3 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG3, value);
++
++ /* Display size */
++ value = (info->var.yres - 1) << LCDC_LCDCFG4_RPF_OFFSET;
++ value |= (info->var.xres - 1) << LCDC_LCDCFG4_PPL_OFFSET;
++ dev_dbg(info->device, " * LCDC_LCDCFG4 = %08lx\n", value);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG4, value);
++
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG1, atmel_hlcdfb_get_rgbmode(info));
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG2, 0);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG3, 0); /* Default color */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
++
++ /* Disable all interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++ /* Enable BASE LAYER overflow interrupts, if want to enable DMA interrupt, also need set it at LCDC_BASECTRL reg */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ //FIXME: Let video-driver register a callback
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
++
++ return 0;
++}
++
++static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
++{
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 xpos, ypos, xres, yres, cfg9;
++
++ if (info->var.nonstd >> 31) {
++ xpos = (info->var.nonstd >> 10) & 0x3ff;
++ ypos = info->var.nonstd & 0x3ff;
++ xres = info->var.xres ? info->var.xres - 1 : 0;
++ yres = info->var.yres ? info->var.yres - 1 : 0;
++ cfg9 = LCDC_OVR1CFG9_DMA | LCDC_OVR1CFG9_OVR |
++ LCDC_OVR1CFG9_ITER | LCDC_OVR1CFG9_ITER2BL |
++ LCDC_OVR1CFG9_REP;
++ if (info->var.transp.offset)
++ cfg9 |= LCDC_OVR1CFG9_LAEN;
++ else
++ cfg9 |= LCDC_OVR1CFG9_GAEN | LCDC_OVR1CFG9_GA;
++ } else {
++ xpos = ypos = yres = xres = cfg9 = 0;
++ }
++
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG0,
++ LCDC_OVR1CFG0_BLEN_AHB_INCR4 | LCDC_OVR1CFG0_DLBO);
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG1,
++ atmel_hlcdfb_get_rgbmode(info));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG2, xpos |
++ (ypos << LCDC_OVR1CFG2_YOFFSET_OFFSET));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG3, xres |
++ (yres << LCDC_OVR1CFG3_YSIZE_OFFSET));
++ lcdc_writel(sinfo, ATMEL_LCDC_OVR1CFG9, cfg9);
++
++ return 0;
++}
++static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
++{
++ /* Saturate vertical and horizontal timings at maximum values */
++ var->vsync_len = min_t(u32, var->vsync_len,
++ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
++ var->upper_margin = min_t(u32, var->upper_margin,
++ (LCDC_LCDCFG2_VFPW >> LCDC_LCDCFG2_VFPW_OFFSET) + 1);
++ var->lower_margin = min_t(u32, var->lower_margin,
++ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
++ var->right_margin = min_t(u32, var->right_margin,
++ (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ var->hsync_len = min_t(u32, var->hsync_len,
++ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
++ var->left_margin = min_t(u32, var->left_margin,
++ (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++
++}
++
++static irqreturn_t atmel_hlcdfb_interrupt(int irq, void *dev_id)
++{
++ struct fb_info *info = dev_id;
++ struct atmel_lcdfb_info *sinfo = info->par;
++ u32 status, baselayer_status;
++
++ /* Check for error status via interrupt.*/
++ status = lcdc_readl(sinfo, ATMEL_LCDC_LCDISR);
++ if (status & LCDC_LCDISR_HEO)
++ return IRQ_NONE;
++
++ if (status & LCDC_LCDISR_FIFOERR)
++ dev_warn(info->device, "FIFO underflow %#x\n", status);
++
++ if (status & LCDC_LCDISR_BASE) {
++ /* Check base layer's overflow error. */
++ baselayer_status = lcdc_readl(sinfo, ATMEL_LCDC_BASEISR);
++
++ if (baselayer_status & LCDC_BASEISR_OVR)
++ dev_warn(info->device, "base layer overflow %#x\n",
++ baselayer_status);
++ }
++
++ return IRQ_HANDLED;
++}
++
++
++#ifdef CONFIG_PM
++
++static int atmel_hlcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
++{
++ struct fb_info *info = platform_get_drvdata(pdev);
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ /*
++ * We don't want to handle interrupts while the clock is
++ * stopped. It may take forever.
++ */
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIDR, ~0UL);
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIDR, ~0UL);
++
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(0);
++
++ atmel_hlcdfb_stop(sinfo, 0);
++ atmel_lcdfb_stop_clock(sinfo);
++
++ return 0;
++}
++
++static int atmel_hlcdfb_resume(struct platform_device *pdev)
++{
++ struct fb_info *info = platform_get_drvdata(pdev);
++ struct atmel_lcdfb_info *sinfo = info->par;
++
++ atmel_lcdfb_start_clock(sinfo);
++ atmel_hlcdfb_start(sinfo);
++ if (sinfo->atmel_lcdfb_power_control)
++ sinfo->atmel_lcdfb_power_control(1);
++
++ /* Enable fifo error & BASE LAYER overflow interrupts */
++ lcdc_writel(sinfo, ATMEL_LCDC_BASEIER, LCDC_BASEIER_OVR);
++ lcdc_writel(sinfo, ATMEL_LCDC_LCDIER, LCDC_LCDIER_FIFOERRIE |
++ LCDC_LCDIER_BASEIE | LCDC_LCDIER_HEOIE);
++
++ return 0;
++}
++
++#else
++#define atmel_hlcdfb_suspend NULL
++#define atmel_hlcdfb_resume NULL
++#endif
++
++static struct atmel_lcdfb_devdata dev_data_base = {
++ .setup_core = atmel_hlcdfb_setup_core_base,
++ .start = atmel_hlcdfb_start,
++ .stop = atmel_hlcdfb_stop,
++ .isr = atmel_hlcdfb_interrupt,
++ .update_dma = atmel_hlcdfb_update_dma_base,
++ .bl_ops = &atmel_hlcdc_bl_ops,
++ .init_contrast = atmel_hlcdfb_init_contrast,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = ATMEL_HLCDC_LUT,
++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
++};
++
++static struct atmel_lcdfb_devdata dev_data_ovl = {
++ .setup_core = atmel_hlcdfb_setup_core_ovl,
++ .update_dma = atmel_hlcdfb_update_dma_ovl,
++ .limit_screeninfo = atmelfb_limit_screeninfo,
++ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
++ .lut_base = 0x800, //FIXME: add define
++ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
++};
++
++static const struct platform_device_id atmelfb_dev_table[] = {
++ { "atmel_hlcdfb_base", (kernel_ulong_t)&dev_data_base },
++ { "atmel_hlcdfb_ovl", (kernel_ulong_t)&dev_data_ovl },
++}
++MODULE_DEVICE_TABLE(platform, atmelfb_dev_table);
++
++static int __init atmel_hlcdfb_probe(struct platform_device *pdev)
++{
++ const struct platform_device_id *id = platform_get_device_id(pdev);
++
++ return __atmel_lcdfb_probe(pdev, (struct atmel_lcdfb_devdata *)id->driver_data);
++}
++static int __exit atmel_hlcdfb_remove(struct platform_device *pdev)
++{
++ return __atmel_lcdfb_remove(pdev);
++}
++
++static struct platform_driver atmel_hlcdfb_driver = {
++ .remove = __exit_p(atmel_hlcdfb_remove),
++ .suspend = atmel_hlcdfb_suspend,
++ .resume = atmel_hlcdfb_resume,
++
++ .driver = {
++ .name = "atmel_hlcdfb",
++ .owner = THIS_MODULE,
++ },
++ .id_table = atmelfb_dev_table,
++};
++
++static int __init atmel_hlcdfb_init(void)
++{
++ return platform_driver_probe(&atmel_hlcdfb_driver, atmel_hlcdfb_probe);
++}
++module_init(atmel_hlcdfb_init);
++
++static void __exit atmel_hlcdfb_exit(void)
++{
++ platform_driver_unregister(&atmel_hlcdfb_driver);
++}
++module_exit(atmel_hlcdfb_exit);
++
++MODULE_DESCRIPTION("AT91 HLCD Controller framebuffer driver");
++MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com> "
++ "and Wolfram Sang <w.sang@pengutronix.de");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 060d41f..cd57361 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -90,6 +90,10 @@ static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
++
++ if (sinfo->dev_data->dma_desc_size && sinfo->dma_desc)
++ dma_free_writecombine(info->device, sinfo->dev_data->dma_desc_size,
++ sinfo->dma_desc, sinfo->dma_desc_phys);
+ }
+
+ /**
+@@ -118,6 +122,17 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+
+ memset(info->screen_base, 0, info->fix.smem_len);
+
++ if (sinfo->dev_data->dma_desc_size) {
++ sinfo->dma_desc = dma_alloc_writecombine(info->device,
++ sinfo->dev_data->dma_desc_size,
++ &(sinfo->dma_desc_phys), GFP_KERNEL);
++
++ if (!sinfo->dma_desc) {
++ dma_free_writecombine(info->device, info->fix.smem_len,
++ info->screen_base, info->fix.smem_start);
++ return -ENOMEM;
++ }
++ }
+ return 0;
+ }
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From b1afedb79996e6e81b696c380a170564bf0aec72 Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Mon, 30 May 2011 17:04:35 +0200
+Subject: WIP: add clut resource
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Warning: will currently break old AT91-boards!
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_hlcdfb.c | 2 --
+ drivers/video/atmel_lcdfb.c | 1 -
+ drivers/video/atmel_lcdfb_core.c | 35 ++++++++++++++++++++++++++---------
+ include/video/atmel_lcdfb.h | 2 +-
+ 4 files changed, 27 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index b772841..346bb80 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -454,7 +454,6 @@ static struct atmel_lcdfb_devdata dev_data_base = {
+ .init_contrast = atmel_hlcdfb_init_contrast,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = ATMEL_HLCDC_LUT,
+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
+ };
+
+@@ -463,7 +462,6 @@ static struct atmel_lcdfb_devdata dev_data_ovl = {
+ .update_dma = atmel_hlcdfb_update_dma_ovl,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = 0x800, //FIXME: add define
+ .dma_desc_size = sizeof(struct atmel_hlcd_dma_desc),
+ };
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 8d7992c..402cb24 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -399,7 +399,6 @@ static struct atmel_lcdfb_devdata dev_data = {
+ .init_contrast = atmel_lcdfb_init_contrast,
+ .limit_screeninfo = atmelfb_limit_screeninfo,
+ .fbinfo_flags = ATMEL_LCDFB_FBINFO_DEFAULT,
+- .lut_base = ATMEL_LCDC_LUT,
+ };
+
+ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index cd57361..89d974a 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -426,9 +426,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ * TODO: intensity bit. Maybe something like
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+-
+- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
+- val);
++ writel(val, sinfo->clut + regno * 4);
+ ret = 0;
+ }
+ break;
+@@ -436,8 +434,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+- lcdc_writel(sinfo, sinfo->dev_data->lut_base + regno * 4,
+- val);
++ writel(val, sinfo->clut + regno * 4);
+ ret = 0;
+ }
+ break;
+@@ -553,7 +550,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ struct atmel_lcdfb_info *sinfo;
+ struct atmel_lcdfb_info *pdata_sinfo;
+ struct fb_videomode fbmode;
+- struct resource *regs = NULL;
++ struct resource *regs = NULL, *clut = NULL;
+ struct resource *map = NULL;
+ int ret;
+
+@@ -628,11 +625,19 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto stop_clk;
+ }
+
++ clut = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!clut) {
++ dev_err(dev, "clut resources unusable\n");
++ ret = -ENXIO;
++ goto stop_clk;
++ }
++
+ /* No error checking, some devices can do without IRQ */
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+
+ /* Initialize video memory */
+- map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ //FIXME: Fix LUTs for old platforms
++ map = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+@@ -676,6 +681,17 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ goto release_mem;
+ }
+
++ //FIXME: proper request_region and cleanup
++ if (!request_mem_region(clut->start, resource_size(clut), pdev->name)) {
++ ret = -EBUSY;
++ goto unmap_mmio;
++ }
++ sinfo->clut = ioremap(clut->start, resource_size(clut));
++ if (!sinfo->clut) {
++ dev_err(dev, "cannot map CLUT\n");
++ goto unmap_mmio;
++ }
++
+ /* Initialize PWM for contrast or backlight ("off") */
+ if (sinfo->dev_data->init_contrast)
+ sinfo->dev_data->init_contrast(sinfo);
+@@ -688,7 +704,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev,
+ IRQF_SHARED, pdev->name, info);
+ if (ret) {
+ dev_err(dev, "request_irq failed: %d\n", ret);
+- goto unmap_mmio;
++ goto clear_backlight;
+ }
+ }
+
+@@ -746,8 +762,9 @@ unregister_irqs:
+ cancel_work_sync(&sinfo->task);
+ if (sinfo->irq_base >= 0)
+ free_irq(sinfo->irq_base, info);
+-unmap_mmio:
++clear_backlight:
+ exit_backlight(sinfo);
++unmap_mmio:
+ iounmap(sinfo->mmio);
+ release_mem:
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+diff --git a/include/video/atmel_lcdfb.h b/include/video/atmel_lcdfb.h
+index 3a0dfc7..a9563b8 100644
+--- a/include/video/atmel_lcdfb.h
++++ b/include/video/atmel_lcdfb.h
+@@ -48,7 +48,6 @@ struct atmel_lcdfb_devdata {
+ void (*limit_screeninfo)(struct fb_var_screeninfo *var);
+ const struct backlight_ops *bl_ops;
+ int fbinfo_flags;
+- u32 lut_base;
+ int dma_desc_size;
+ };
+
+@@ -63,6 +62,7 @@ struct atmel_lcdfb_info {
+ spinlock_t lock;
+ struct fb_info *info;
+ void __iomem *mmio;
++ void __iomem *clut;
+ int irq_base;
+ struct atmel_lcdfb_devdata *dev_data;
+ struct work_struct task;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 630d7210859cec33916489d29cced3150b017bee Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 16 May 2012 15:26:01 +0200
-Subject: mmc: atmel-mci: add debug logs
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Chris Ball <cjb@laptop.org>
----
- drivers/mmc/host/atmel-mci.c | 41 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 41 insertions(+)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 5fe8300..420aca6 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -630,6 +630,7 @@ static void atmci_send_command(struct atmel_mci *host,
-
- static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
- {
-+ dev_dbg(&host->pdev->dev, "send stop command\n");
- atmci_send_command(host, data->stop, host->stop_cmdr);
- atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
- }
-@@ -738,6 +739,8 @@ static void atmci_pdc_complete(struct atmel_mci *host)
- * to send the stop command or waiting for NBUSY in this case.
- */
- if (host->data) {
-+ dev_dbg(&host->pdev->dev,
-+ "(%s) set pending xfer complete\n", __func__);
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
- }
-@@ -775,6 +778,8 @@ static void atmci_dma_complete(void *arg)
- * to send the stop command or waiting for NBUSY in this case.
- */
- if (data) {
-+ dev_dbg(&host->pdev->dev,
-+ "(%s) set pending xfer complete\n", __func__);
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
-
-@@ -1001,6 +1006,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
-
- static void atmci_stop_transfer(struct atmel_mci *host)
- {
-+ dev_dbg(&host->pdev->dev,
-+ "(%s) set pending xfer complete\n", __func__);
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
-@@ -1022,6 +1029,8 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host)
- atmci_dma_cleanup(host);
- } else {
- /* Data transfer was stopped by the interrupt handler */
-+ dev_dbg(&host->pdev->dev,
-+ "(%s) set pending xfer complete\n", __func__);
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
-@@ -1049,6 +1058,8 @@ static void atmci_start_request(struct atmel_mci *host,
- host->cmd_status = 0;
- host->data_status = 0;
-
-+ dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
-+
- if (host->need_reset || host->caps.need_reset_after_xfer) {
- iflags = atmci_readl(host, ATMCI_IMR);
- iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
-@@ -1129,6 +1140,7 @@ static void atmci_queue_request(struct atmel_mci *host,
- host->state = STATE_SENDING_CMD;
- atmci_start_request(host, slot);
- } else {
-+ dev_dbg(&host->pdev->dev, "queue request\n");
- list_add_tail(&slot->queue_node, &host->queue);
- }
- spin_unlock_bh(&host->lock);
-@@ -1141,6 +1153,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
- struct mmc_data *data;
-
- WARN_ON(slot->mrq);
-+ dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
-
- /*
- * We may "know" the card is gone even though there's still an
-@@ -1530,6 +1543,7 @@ static void atmci_tasklet_func(unsigned long priv)
-
- do {
- prev_state = state;
-+ dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
-
- switch (state) {
- case STATE_IDLE:
-@@ -1542,14 +1556,18 @@ static void atmci_tasklet_func(unsigned long priv)
- * END_REQUEST by default, WAITING_NOTBUSY if it's a
- * command needing it or DATA_XFER if there is data.
- */
-+ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
- if (!atmci_test_and_clear_pending(host,
- EVENT_CMD_RDY))
- break;
-
-+ dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
- host->cmd = NULL;
- atmci_set_completed(host, EVENT_CMD_RDY);
- atmci_command_complete(host, mrq->cmd);
- if (mrq->data) {
-+ dev_dbg(&host->pdev->dev,
-+ "command with data transfer");
- /*
- * If there is a command error don't start
- * data transfer.
-@@ -1564,6 +1582,8 @@ static void atmci_tasklet_func(unsigned long priv)
- } else
- state = STATE_DATA_XFER;
- } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
-+ dev_dbg(&host->pdev->dev,
-+ "command response need waiting notbusy");
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- state = STATE_WAITING_NOTBUSY;
- } else
-@@ -1574,6 +1594,7 @@ static void atmci_tasklet_func(unsigned long priv)
- case STATE_DATA_XFER:
- if (atmci_test_and_clear_pending(host,
- EVENT_DATA_ERROR)) {
-+ dev_dbg(&host->pdev->dev, "set completed data error\n");
- atmci_set_completed(host, EVENT_DATA_ERROR);
- state = STATE_END_REQUEST;
- break;
-@@ -1586,10 +1607,14 @@ static void atmci_tasklet_func(unsigned long priv)
- * to the next step which is WAITING_NOTBUSY in write
- * case and directly SENDING_STOP in read case.
- */
-+ dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
- if (!atmci_test_and_clear_pending(host,
- EVENT_XFER_COMPLETE))
- break;
-
-+ dev_dbg(&host->pdev->dev,
-+ "(%s) set completed xfer complete\n",
-+ __func__);
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
-
- if (host->data->flags & MMC_DATA_WRITE) {
-@@ -1614,10 +1639,12 @@ static void atmci_tasklet_func(unsigned long priv)
- * included) or a write operation. In the latest case,
- * we need to send a stop command.
- */
-+ dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
- if (!atmci_test_and_clear_pending(host,
- EVENT_NOTBUSY))
- break;
-
-+ dev_dbg(&host->pdev->dev, "set completed not busy\n");
- atmci_set_completed(host, EVENT_NOTBUSY);
-
- if (host->data) {
-@@ -1649,10 +1676,12 @@ static void atmci_tasklet_func(unsigned long priv)
- * in order to go to the end request state instead of
- * sending stop again.
- */
-+ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
- if (!atmci_test_and_clear_pending(host,
- EVENT_CMD_RDY))
- break;
-
-+ dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
- host->cmd = NULL;
- host->data = NULL;
- data->bytes_xfered = data->blocks * data->blksz;
-@@ -1858,18 +1887,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- break;
-
- if (pending & ATMCI_DATA_ERROR_FLAGS) {
-+ dev_dbg(&host->pdev->dev, "IRQ: data error\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
- | ATMCI_RXRDY | ATMCI_TXRDY
- | ATMCI_ENDRX | ATMCI_ENDTX
- | ATMCI_RXBUFF | ATMCI_TXBUFE);
-
- host->data_status = status;
-+ dev_dbg(&host->pdev->dev, "set pending data error\n");
- smp_wmb();
- atmci_set_pending(host, EVENT_DATA_ERROR);
- tasklet_schedule(&host->tasklet);
- }
-
- if (pending & ATMCI_TXBUFE) {
-+ dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
- /*
-@@ -1885,6 +1917,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- atmci_pdc_complete(host);
- }
- } else if (pending & ATMCI_ENDTX) {
-+ dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
-
- if (host->data_size) {
-@@ -1895,6 +1928,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- }
-
- if (pending & ATMCI_RXBUFF) {
-+ dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
- /*
-@@ -1910,6 +1944,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- atmci_pdc_complete(host);
- }
- } else if (pending & ATMCI_ENDRX) {
-+ dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
-
- if (host->data_size) {
-@@ -1926,15 +1961,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- * The appropriate workaround is to use the BLKE signal.
- */
- if (pending & ATMCI_BLKE) {
-+ dev_dbg(&host->pdev->dev, "IRQ: blke\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
- smp_wmb();
-+ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
- atmci_set_pending(host, EVENT_NOTBUSY);
- tasklet_schedule(&host->tasklet);
- }
-
- if (pending & ATMCI_NOTBUSY) {
-+ dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
- smp_wmb();
-+ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
- atmci_set_pending(host, EVENT_NOTBUSY);
- tasklet_schedule(&host->tasklet);
- }
-@@ -1945,9 +1984,11 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
- atmci_write_data_pio(host);
-
- if (pending & ATMCI_CMDRDY) {
-+ dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
- atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
- host->cmd_status = status;
- smp_wmb();
-+ dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
- atmci_set_pending(host, EVENT_CMD_RDY);
- tasklet_schedule(&host->tasklet);
- }
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 20b33d7617155ab35517ac63b8a2f839ca3f935b Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 23 May 2012 15:46:00 +0200
-Subject: mmc: atmel-mci: fix data timeout issue
-
-The data timeout timer was configured after mmc_add_host call. So, with bad
-timings, it was possible to have a mmc request causing mod_timer call on a
-non setup timer.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 420aca6..456c077 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -2314,6 +2314,8 @@ static int __init atmci_probe(struct platform_device *pdev)
-
- platform_set_drvdata(pdev, host);
-
-+ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
-+
- /* We need at least one slot to succeed */
- nr_slots = 0;
- ret = -ENODEV;
-@@ -2352,8 +2354,6 @@ static int __init atmci_probe(struct platform_device *pdev)
- }
- }
-
-- setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
--
- dev_info(&pdev->dev,
- "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
- host->mapbase, irq, nr_slots);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From fc3816309304b6ccbb3f1db1b433d2cb9a7df6ca Mon Sep 17 00:00:00 2001
+From: Wolfram Sang <w.sang@pengutronix.de>
+Date: Tue, 7 Jun 2011 12:58:36 +0200
+Subject: video: atmel_lcdfb: add error-msg when out of memory
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/video/atmel_lcdfb_core.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index 89d974a..ff84234 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -221,8 +221,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ if (info->fix.smem_len) {
+ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+ * ((var->bits_per_pixel + 7) / 8));
+- if (smem_len > info->fix.smem_len)
++ if (smem_len > info->fix.smem_len) {
++ dev_err(dev, "not enough memory for this mode\n");
+ return -EINVAL;
++ }
+ }
+
+ /* Saturate vertical and horizontal timings at maximum values */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From aeb632c71d6bdbf80b969863edb9f4a0b5b02945 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Mon, 21 May 2012 12:23:27 +0200
-Subject: ARM: at91: add atmel-mci support for chips and boards which can use
- it
-
-Since atmel-mci driver supports all atmel mci versions,
-use it instead of the deprecated at91_mci driver.
-Platform data and all related configuration are removed.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-[nicolas.ferre@atmel.com: remove at91_mci platform data]
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/at91rm9200_devices.c | 92 ++++++++++--------
- arch/arm/mach-at91/at91sam9260_devices.c | 84 +---------------
- arch/arm/mach-at91/at91sam9261_devices.c | 60 ++++++------
- arch/arm/mach-at91/at91sam9263.c | 4 +-
- arch/arm/mach-at91/at91sam9263_devices.c | 161 ++++++++++++++++++-------------
- arch/arm/mach-at91/at91sam9rl_devices.c | 60 ++++++------
- arch/arm/mach-at91/board-afeb-9260v1.c | 14 +--
- arch/arm/mach-at91/board-carmeva.c | 14 +--
- arch/arm/mach-at91/board-cpu9krea.c | 14 +--
- arch/arm/mach-at91/board-cpuat91.c | 13 +--
- arch/arm/mach-at91/board-csb337.c | 14 +--
- arch/arm/mach-at91/board-eb9200.c | 14 +--
- arch/arm/mach-at91/board-ecbat91.c | 14 +--
- arch/arm/mach-at91/board-eco920.c | 14 +--
- arch/arm/mach-at91/board-flexibity.c | 14 +--
- arch/arm/mach-at91/board-foxg20.c | 16 +--
- arch/arm/mach-at91/board-kb9202.c | 14 +--
- arch/arm/mach-at91/board-neocore926.c | 13 +--
- arch/arm/mach-at91/board-picotux200.c | 14 +--
- arch/arm/mach-at91/board-qil-a9260.c | 14 +--
- arch/arm/mach-at91/board-rm9200dk.c | 14 +--
- arch/arm/mach-at91/board-rm9200ek.c | 14 +--
- arch/arm/mach-at91/board-rsi-ews.c | 13 +--
- arch/arm/mach-at91/board-sam9-l9260.c | 16 +--
- arch/arm/mach-at91/board-sam9260ek.c | 16 +--
- arch/arm/mach-at91/board-sam9261ek.c | 13 +--
- arch/arm/mach-at91/board-sam9263ek.c | 13 +--
- arch/arm/mach-at91/board-sam9g20ek.c | 16 +--
- arch/arm/mach-at91/board-sam9rlek.c | 13 +--
- arch/arm/mach-at91/board-stamp9g20.c | 14 ---
- arch/arm/mach-at91/board-usb-a926x.c | 2 -
- arch/arm/mach-at91/board-yl-9200.c | 13 +--
- 32 files changed, 375 insertions(+), 439 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
-index 01fb732..9ac427a 100644
---- a/arch/arm/mach-at91/at91rm9200_devices.c
-+++ b/arch/arm/mach-at91/at91rm9200_devices.c
-@@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
- * MMC / SD
- * -------------------------------------------------------------------- */
-
--#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
- static u64 mmc_dmamask = DMA_BIT_MASK(32);
--static struct at91_mmc_data mmc_data;
-+static struct mci_platform_data mmc_data;
-
- static struct resource mmc_resources[] = {
- [0] = {
-@@ -312,7 +312,7 @@ static struct resource mmc_resources[] = {
- };
-
- static struct platform_device at91rm9200_mmc_device = {
-- .name = "at91_mci",
-+ .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
-@@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = {
- .num_resources = ARRAY_SIZE(mmc_resources),
- };
-
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
- {
-+ unsigned int i;
-+ unsigned int slot_count = 0;
-+
- if (!data)
- return;
-
-- /* input/irq */
-- if (gpio_is_valid(data->det_pin)) {
-- at91_set_gpio_input(data->det_pin, 1);
-- at91_set_deglitch(data->det_pin, 1);
-- }
-- if (gpio_is_valid(data->wp_pin))
-- at91_set_gpio_input(data->wp_pin, 1);
-- if (gpio_is_valid(data->vcc_pin))
-- at91_set_gpio_output(data->vcc_pin, 0);
--
-- /* CLK */
-- at91_set_A_periph(AT91_PIN_PA27, 0);
-+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
-
-- if (data->slot_b) {
-- /* CMD */
-- at91_set_B_periph(AT91_PIN_PA8, 1);
-+ if (!data->slot[i].bus_width)
-+ continue;
-
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_B_periph(AT91_PIN_PA9, 1);
-- if (data->wire4) {
-- at91_set_B_periph(AT91_PIN_PA10, 1);
-- at91_set_B_periph(AT91_PIN_PA11, 1);
-- at91_set_B_periph(AT91_PIN_PA12, 1);
-+ /* input/irq */
-+ if (gpio_is_valid(data->slot[i].detect_pin)) {
-+ at91_set_gpio_input(data->slot[i].detect_pin, 1);
-+ at91_set_deglitch(data->slot[i].detect_pin, 1);
- }
-- } else {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA28, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA29, 1);
-- if (data->wire4) {
-- at91_set_B_periph(AT91_PIN_PB3, 1);
-- at91_set_B_periph(AT91_PIN_PB4, 1);
-- at91_set_B_periph(AT91_PIN_PB5, 1);
-+ if (gpio_is_valid(data->slot[i].wp_pin))
-+ at91_set_gpio_input(data->slot[i].wp_pin, 1);
-+
-+ switch (i) {
-+ case 0: /* slot A */
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA28, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA29, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_B_periph(AT91_PIN_PB3, 1);
-+ at91_set_B_periph(AT91_PIN_PB4, 1);
-+ at91_set_B_periph(AT91_PIN_PB5, 1);
-+ }
-+ slot_count++;
-+ break;
-+ case 1: /* slot B */
-+ /* CMD */
-+ at91_set_B_periph(AT91_PIN_PA8, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_B_periph(AT91_PIN_PA9, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_B_periph(AT91_PIN_PA10, 1);
-+ at91_set_B_periph(AT91_PIN_PA11, 1);
-+ at91_set_B_periph(AT91_PIN_PA12, 1);
-+ }
-+ slot_count++;
-+ break;
-+ default:
-+ printk(KERN_ERR
-+ "AT91: SD/MMC slot %d not available\n", i);
-+ break;
-+ }
-+ if (slot_count) {
-+ /* CLK */
-+ at91_set_A_periph(AT91_PIN_PA27, 0);
-+
-+ mmc_data = *data;
-+ platform_device_register(&at91rm9200_mmc_device);
- }
- }
-
-- mmc_data = *data;
-- platform_device_register(&at91rm9200_mmc_device);
- }
- #else
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
- #endif
-
-
-diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
-index 43e60fb..2c54662 100644
---- a/arch/arm/mach-at91/at91sam9260_devices.c
-+++ b/arch/arm/mach-at91/at91sam9260_devices.c
-@@ -206,92 +206,10 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
-
-
- /* --------------------------------------------------------------------
-- * MMC / SD
-- * -------------------------------------------------------------------- */
--
--#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
--static u64 mmc_dmamask = DMA_BIT_MASK(32);
--static struct at91_mmc_data mmc_data;
--
--static struct resource mmc_resources[] = {
-- [0] = {
-- .start = AT91SAM9260_BASE_MCI,
-- .end = AT91SAM9260_BASE_MCI + SZ_16K - 1,
-- .flags = IORESOURCE_MEM,
-- },
-- [1] = {
-- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-- .flags = IORESOURCE_IRQ,
-- },
--};
--
--static struct platform_device at91sam9260_mmc_device = {
-- .name = "at91_mci",
-- .id = -1,
-- .dev = {
-- .dma_mask = &mmc_dmamask,
-- .coherent_dma_mask = DMA_BIT_MASK(32),
-- .platform_data = &mmc_data,
-- },
-- .resource = mmc_resources,
-- .num_resources = ARRAY_SIZE(mmc_resources),
--};
--
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
--{
-- if (!data)
-- return;
--
-- /* input/irq */
-- if (gpio_is_valid(data->det_pin)) {
-- at91_set_gpio_input(data->det_pin, 1);
-- at91_set_deglitch(data->det_pin, 1);
-- }
-- if (gpio_is_valid(data->wp_pin))
-- at91_set_gpio_input(data->wp_pin, 1);
-- if (gpio_is_valid(data->vcc_pin))
-- at91_set_gpio_output(data->vcc_pin, 0);
--
-- /* CLK */
-- at91_set_A_periph(AT91_PIN_PA8, 0);
--
-- if (data->slot_b) {
-- /* CMD */
-- at91_set_B_periph(AT91_PIN_PA1, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_B_periph(AT91_PIN_PA0, 1);
-- if (data->wire4) {
-- at91_set_B_periph(AT91_PIN_PA5, 1);
-- at91_set_B_periph(AT91_PIN_PA4, 1);
-- at91_set_B_periph(AT91_PIN_PA3, 1);
-- }
-- } else {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA7, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA6, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA9, 1);
-- at91_set_A_periph(AT91_PIN_PA10, 1);
-- at91_set_A_periph(AT91_PIN_PA11, 1);
-- }
-- }
--
-- mmc_data = *data;
-- platform_device_register(&at91sam9260_mmc_device);
--}
--#else
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
--#endif
--
--/* --------------------------------------------------------------------
- * MMC / SD Slot for Atmel MCI Driver
- * -------------------------------------------------------------------- */
-
--#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
- static u64 mmc_dmamask = DMA_BIT_MASK(32);
- static struct mci_platform_data mmc_data;
-
-diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
-index 1eecff8..08b3b02 100644
---- a/arch/arm/mach-at91/at91sam9261_devices.c
-+++ b/arch/arm/mach-at91/at91sam9261_devices.c
-@@ -139,9 +139,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
- * MMC / SD
- * -------------------------------------------------------------------- */
-
--#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
- static u64 mmc_dmamask = DMA_BIT_MASK(32);
--static struct at91_mmc_data mmc_data;
-+static struct mci_platform_data mmc_data;
-
- static struct resource mmc_resources[] = {
- [0] = {
-@@ -157,7 +157,7 @@ static struct resource mmc_resources[] = {
- };
-
- static struct platform_device at91sam9261_mmc_device = {
-- .name = "at91_mci",
-+ .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
-@@ -168,40 +168,40 @@ static struct platform_device at91sam9261_mmc_device = {
- .num_resources = ARRAY_SIZE(mmc_resources),
- };
-
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
- {
- if (!data)
- return;
-
-- /* input/irq */
-- if (gpio_is_valid(data->det_pin)) {
-- at91_set_gpio_input(data->det_pin, 1);
-- at91_set_deglitch(data->det_pin, 1);
-- }
-- if (gpio_is_valid(data->wp_pin))
-- at91_set_gpio_input(data->wp_pin, 1);
-- if (gpio_is_valid(data->vcc_pin))
-- at91_set_gpio_output(data->vcc_pin, 0);
--
-- /* CLK */
-- at91_set_B_periph(AT91_PIN_PA2, 0);
--
-- /* CMD */
-- at91_set_B_periph(AT91_PIN_PA1, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_B_periph(AT91_PIN_PA0, 1);
-- if (data->wire4) {
-- at91_set_B_periph(AT91_PIN_PA4, 1);
-- at91_set_B_periph(AT91_PIN_PA5, 1);
-- at91_set_B_periph(AT91_PIN_PA6, 1);
-- }
-+ if (data->slot[0].bus_width) {
-+ /* input/irq */
-+ if (gpio_is_valid(data->slot[0].detect_pin)) {
-+ at91_set_gpio_input(data->slot[0].detect_pin, 1);
-+ at91_set_deglitch(data->slot[0].detect_pin, 1);
-+ }
-+ if (gpio_is_valid(data->slot[0].wp_pin))
-+ at91_set_gpio_input(data->slot[0].wp_pin, 1);
-+
-+ /* CLK */
-+ at91_set_B_periph(AT91_PIN_PA2, 0);
-
-- mmc_data = *data;
-- platform_device_register(&at91sam9261_mmc_device);
-+ /* CMD */
-+ at91_set_B_periph(AT91_PIN_PA1, 1);
-+
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_B_periph(AT91_PIN_PA0, 1);
-+ if (data->slot[0].bus_width == 4) {
-+ at91_set_B_periph(AT91_PIN_PA4, 1);
-+ at91_set_B_periph(AT91_PIN_PA5, 1);
-+ at91_set_B_periph(AT91_PIN_PA6, 1);
-+ }
-+
-+ mmc_data = *data;
-+ platform_device_register(&at91sam9261_mmc_device);
-+ }
- }
- #else
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
- #endif
-
-
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index 84b3810..144ef5d 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_ID("hclk", &macb_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
-- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
-diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
-index f0318e9..a111315 100644
---- a/arch/arm/mach-at91/at91sam9263_devices.c
-+++ b/arch/arm/mach-at91/at91sam9263_devices.c
-@@ -220,9 +220,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
- * MMC / SD
- * -------------------------------------------------------------------- */
-
--#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
- static u64 mmc_dmamask = DMA_BIT_MASK(32);
--static struct at91_mmc_data mmc0_data, mmc1_data;
-+static struct mci_platform_data mmc0_data, mmc1_data;
-
- static struct resource mmc0_resources[] = {
- [0] = {
-@@ -238,7 +238,7 @@ static struct resource mmc0_resources[] = {
- };
-
- static struct platform_device at91sam9263_mmc0_device = {
-- .name = "at91_mci",
-+ .name = "atmel_mci",
- .id = 0,
- .dev = {
- .dma_mask = &mmc_dmamask,
-@@ -263,7 +263,7 @@ static struct resource mmc1_resources[] = {
- };
-
- static struct platform_device at91sam9263_mmc1_device = {
-- .name = "at91_mci",
-+ .name = "atmel_mci",
- .id = 1,
- .dev = {
- .dma_mask = &mmc_dmamask,
-@@ -274,85 +274,110 @@ static struct platform_device at91sam9263_mmc1_device = {
- .num_resources = ARRAY_SIZE(mmc1_resources),
- };
-
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
- {
-+ unsigned int i;
-+ unsigned int slot_count = 0;
-+
- if (!data)
- return;
-
-- /* input/irq */
-- if (gpio_is_valid(data->det_pin)) {
-- at91_set_gpio_input(data->det_pin, 1);
-- at91_set_deglitch(data->det_pin, 1);
-- }
-- if (gpio_is_valid(data->wp_pin))
-- at91_set_gpio_input(data->wp_pin, 1);
-- if (gpio_is_valid(data->vcc_pin))
-- at91_set_gpio_output(data->vcc_pin, 0);
-+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
-
-- if (mmc_id == 0) { /* MCI0 */
-- /* CLK */
-- at91_set_A_periph(AT91_PIN_PA12, 0);
-+ if (!data->slot[i].bus_width)
-+ continue;
-
-- if (data->slot_b) {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA16, 1);
-+ /* input/irq */
-+ if (gpio_is_valid(data->slot[i].detect_pin)) {
-+ at91_set_gpio_input(data->slot[i].detect_pin,
-+ 1);
-+ at91_set_deglitch(data->slot[i].detect_pin,
-+ 1);
-+ }
-+ if (gpio_is_valid(data->slot[i].wp_pin))
-+ at91_set_gpio_input(data->slot[i].wp_pin, 1);
-+
-+ if (mmc_id == 0) { /* MCI0 */
-+ switch (i) {
-+ case 0: /* slot A */
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA1, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA0, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_A_periph(AT91_PIN_PA3, 1);
-+ at91_set_A_periph(AT91_PIN_PA4, 1);
-+ at91_set_A_periph(AT91_PIN_PA5, 1);
-+ }
-+ slot_count++;
-+ break;
-+ case 1: /* slot B */
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA16, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA17, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_A_periph(AT91_PIN_PA18, 1);
-+ at91_set_A_periph(AT91_PIN_PA19, 1);
-+ at91_set_A_periph(AT91_PIN_PA20, 1);
-+ }
-+ slot_count++;
-+ break;
-+ default:
-+ printk(KERN_ERR
-+ "AT91: SD/MMC slot %d not available\n", i);
-+ break;
-+ }
-+ if (slot_count) {
-+ /* CLK */
-+ at91_set_A_periph(AT91_PIN_PA12, 0);
-
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA17, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA18, 1);
-- at91_set_A_periph(AT91_PIN_PA19, 1);
-- at91_set_A_periph(AT91_PIN_PA20, 1);
-+ mmc0_data = *data;
-+ platform_device_register(&at91sam9263_mmc0_device);
- }
-- } else {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA1, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA0, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA3, 1);
-- at91_set_A_periph(AT91_PIN_PA4, 1);
-- at91_set_A_periph(AT91_PIN_PA5, 1);
-+ } else if (mmc_id == 1) { /* MCI1 */
-+ switch (i) {
-+ case 0: /* slot A */
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA7, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA8, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_A_periph(AT91_PIN_PA9, 1);
-+ at91_set_A_periph(AT91_PIN_PA10, 1);
-+ at91_set_A_periph(AT91_PIN_PA11, 1);
-+ }
-+ slot_count++;
-+ break;
-+ case 1: /* slot B */
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA21, 1);
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA22, 1);
-+ if (data->slot[i].bus_width == 4) {
-+ at91_set_A_periph(AT91_PIN_PA23, 1);
-+ at91_set_A_periph(AT91_PIN_PA24, 1);
-+ at91_set_A_periph(AT91_PIN_PA25, 1);
-+ }
-+ slot_count++;
-+ break;
-+ default:
-+ printk(KERN_ERR
-+ "AT91: SD/MMC slot %d not available\n", i);
-+ break;
- }
-- }
-+ if (slot_count) {
-+ /* CLK */
-+ at91_set_A_periph(AT91_PIN_PA6, 0);
-
-- mmc0_data = *data;
-- platform_device_register(&at91sam9263_mmc0_device);
-- } else { /* MCI1 */
-- /* CLK */
-- at91_set_A_periph(AT91_PIN_PA6, 0);
--
-- if (data->slot_b) {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA21, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA22, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA23, 1);
-- at91_set_A_periph(AT91_PIN_PA24, 1);
-- at91_set_A_periph(AT91_PIN_PA25, 1);
-- }
-- } else {
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA7, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA8, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA9, 1);
-- at91_set_A_periph(AT91_PIN_PA10, 1);
-- at91_set_A_periph(AT91_PIN_PA11, 1);
-+ mmc1_data = *data;
-+ platform_device_register(&at91sam9263_mmc1_device);
- }
- }
--
-- mmc1_data = *data;
-- platform_device_register(&at91sam9263_mmc1_device);
- }
- }
- #else
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
- #endif
-
- /* --------------------------------------------------------------------
-diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
-index 0d1b76f..88687b9 100644
---- a/arch/arm/mach-at91/at91sam9rl_devices.c
-+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
-@@ -163,9 +163,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {}
- * MMC / SD
- * -------------------------------------------------------------------- */
-
--#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
- static u64 mmc_dmamask = DMA_BIT_MASK(32);
--static struct at91_mmc_data mmc_data;
-+static struct mci_platform_data mmc_data;
-
- static struct resource mmc_resources[] = {
- [0] = {
-@@ -181,7 +181,7 @@ static struct resource mmc_resources[] = {
- };
-
- static struct platform_device at91sam9rl_mmc_device = {
-- .name = "at91_mci",
-+ .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
-@@ -192,40 +192,40 @@ static struct platform_device at91sam9rl_mmc_device = {
- .num_resources = ARRAY_SIZE(mmc_resources),
- };
-
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
- {
- if (!data)
- return;
-
-- /* input/irq */
-- if (gpio_is_valid(data->det_pin)) {
-- at91_set_gpio_input(data->det_pin, 1);
-- at91_set_deglitch(data->det_pin, 1);
-- }
-- if (gpio_is_valid(data->wp_pin))
-- at91_set_gpio_input(data->wp_pin, 1);
-- if (gpio_is_valid(data->vcc_pin))
-- at91_set_gpio_output(data->vcc_pin, 0);
--
-- /* CLK */
-- at91_set_A_periph(AT91_PIN_PA2, 0);
--
-- /* CMD */
-- at91_set_A_periph(AT91_PIN_PA1, 1);
--
-- /* DAT0, maybe DAT1..DAT3 */
-- at91_set_A_periph(AT91_PIN_PA0, 1);
-- if (data->wire4) {
-- at91_set_A_periph(AT91_PIN_PA3, 1);
-- at91_set_A_periph(AT91_PIN_PA4, 1);
-- at91_set_A_periph(AT91_PIN_PA5, 1);
-+ if (data->slot[0].bus_width) {
-+ /* input/irq */
-+ if (gpio_is_valid(data->slot[0].detect_pin)) {
-+ at91_set_gpio_input(data->slot[0].detect_pin, 1);
-+ at91_set_deglitch(data->slot[0].detect_pin, 1);
-+ }
-+ if (gpio_is_valid(data->slot[0].wp_pin))
-+ at91_set_gpio_input(data->slot[0].wp_pin, 1);
-+
-+ /* CLK */
-+ at91_set_A_periph(AT91_PIN_PA2, 0);
-+
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA1, 1);
-+
-+ /* DAT0, maybe DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA0, 1);
-+ if (data->slot[0].bus_width == 4) {
-+ at91_set_A_periph(AT91_PIN_PA3, 1);
-+ at91_set_A_periph(AT91_PIN_PA4, 1);
-+ at91_set_A_periph(AT91_PIN_PA5, 1);
-+ }
-+
-+ mmc_data = *data;
-+ platform_device_register(&at91sam9rl_mmc_device);
- }
--
-- mmc_data = *data;
-- platform_device_register(&at91sam9rl_mmc_device);
- }
- #else
--void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
- #endif
-
-
-diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
-index de7be19..93a832f 100644
---- a/arch/arm/mach-at91/board-afeb-9260v1.c
-+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
-@@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata afeb9260_mmc_data = {
-- .det_pin = AT91_PIN_PC9,
-- .wp_pin = AT91_PIN_PC4,
-- .slot_b = 1,
-- .wire4 = 1,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata afeb9260_mci0_data = {
-+ .slot[1] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PC9,
-+ .wp_pin = AT91_PIN_PC4,
-+ },
- };
-
-
-@@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void)
- at91_set_B_periph(AT91_PIN_PA10, 0); /* ETX2 */
- at91_set_B_periph(AT91_PIN_PA11, 0); /* ETX3 */
- /* MMC */
-- at91_add_device_mmc(0, &afeb9260_mmc_data);
-+ at91_add_device_mci(0, &afeb9260_mci0_data);
- /* I2C */
- at91_add_device_i2c(afeb9260_i2c_devices,
- ARRAY_SIZE(afeb9260_i2c_devices));
-diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
-index a5b002f..71d8f36 100644
---- a/arch/arm/mach-at91/board-carmeva.c
-+++ b/arch/arm/mach-at91/board-carmeva.c
-@@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = {
- // .vcc_pin = -EINVAL,
- // };
-
--static struct at91_mmc_data __initdata carmeva_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PB10,
-- .wp_pin = AT91_PIN_PC14,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata carmeva_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB10,
-+ .wp_pin = AT91_PIN_PC14,
-+ },
- };
-
- static struct spi_board_info carmeva_spi_devices[] = {
-@@ -150,7 +150,7 @@ static void __init carmeva_board_init(void)
- /* Compact Flash */
- // at91_add_device_cf(&carmeva_cf_data);
- /* MMC */
-- at91_add_device_mmc(0, &carmeva_mmc_data);
-+ at91_add_device_mci(0, &carmeva_mci0_data);
- /* LEDs */
- at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
- }
-diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
-index 7ddc219..e71c473 100644
---- a/arch/arm/mach-at91/board-cpu9krea.c
-+++ b/arch/arm/mach-at91/board-cpu9krea.c
-@@ -311,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void)
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PA29,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata cpu9krea_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PA29,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- static void __init cpu9krea_board_init(void)
-@@ -358,7 +358,7 @@ static void __init cpu9krea_board_init(void)
- /* Ethernet */
- at91_add_device_eth(&cpu9krea_macb_data);
- /* MMC */
-- at91_add_device_mmc(0, &cpu9krea_mmc_data);
-+ at91_add_device_mci(0, &cpu9krea_mci0_data);
- /* I2C */
- at91_add_device_i2c(cpu9krea_i2c_devices,
- ARRAY_SIZE(cpu9krea_i2c_devices));
-diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
-index 2e6d043..2cbd1a2 100644
---- a/arch/arm/mach-at91/board-cpuat91.c
-+++ b/arch/arm/mach-at91/board-cpuat91.c
-@@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = {
- .pullup_pin = AT91_PIN_PC14,
- };
-
--static struct at91_mmc_data __initdata cpuat91_mmc_data = {
-- .det_pin = AT91_PIN_PC2,
-- .wire4 = 1,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata cpuat91_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PC2,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- static struct physmap_flash_data cpuat91_flash_data = {
-@@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void)
- /* USB Device */
- at91_add_device_udc(&cpuat91_udc_data);
- /* MMC */
-- at91_add_device_mmc(0, &cpuat91_mmc_data);
-+ at91_add_device_mci(0, &cpuat91_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* Platform devices */
-diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
-index 462bc31..81a8bc4 100644
---- a/arch/arm/mach-at91/board-csb337.c
-+++ b/arch/arm/mach-at91/board-csb337.c
-@@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = {
- .rst_pin = AT91_PIN_PD2,
- };
-
--static struct at91_mmc_data __initdata csb337_mmc_data = {
-- .det_pin = AT91_PIN_PD5,
-- .slot_b = 0,
-- .wire4 = 1,
-- .wp_pin = AT91_PIN_PD6,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata csb337_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PD5,
-+ .wp_pin = AT91_PIN_PD6,
-+ },
- };
-
- static struct spi_board_info csb337_spi_devices[] = {
-@@ -240,7 +240,7 @@ static void __init csb337_board_init(void)
- /* SPI */
- at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
- /* MMC */
-- at91_add_device_mmc(0, &csb337_mmc_data);
-+ at91_add_device_mci(0, &csb337_mci0_data);
- /* NOR flash */
- platform_device_register(&csb_flash);
- /* LEDs */
-diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
-index d1e1f3f..0cfac16 100644
---- a/arch/arm/mach-at91/board-eb9200.c
-+++ b/arch/arm/mach-at91/board-eb9200.c
-@@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = {
- .rst_pin = AT91_PIN_PC5,
- };
-
--static struct at91_mmc_data __initdata eb9200_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata eb9200_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
-@@ -113,7 +113,7 @@ static void __init eb9200_board_init(void)
- at91_add_device_spi(NULL, 0);
- /* MMC */
- /* only supports 1 or 4 bit interface, not wired through to SPI */
-- at91_add_device_mmc(0, &eb9200_mmc_data);
-+ at91_add_device_mci(0, &eb9200_mci0_data);
- }
-
- MACHINE_START(ATEB9200, "Embest ATEB9200")
-diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
-index 9c24cb2..a9d50fc 100644
---- a/arch/arm/mach-at91/board-ecbat91.c
-+++ b/arch/arm/mach-at91/board-ecbat91.c
-@@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = {
- .overcurrent_pin= {-EINVAL, -EINVAL},
- };
-
--static struct at91_mmc_data __initdata ecb_at91mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata ecbat91_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
-
-@@ -161,7 +161,7 @@ static void __init ecb_at91board_init(void)
- at91_add_device_i2c(NULL, 0);
-
- /* MMC */
-- at91_add_device_mmc(0, &ecb_at91mmc_data);
-+ at91_add_device_mci(0, &ecbat91_mci0_data);
-
- /* SPI */
- at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
-diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
-index 82bdfde..aaf7015 100644
---- a/arch/arm/mach-at91/board-eco920.c
-+++ b/arch/arm/mach-at91/board-eco920.c
-@@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = {
- .pullup_pin = AT91_PIN_PB13,
- };
-
--static struct at91_mmc_data __initdata eco920_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 0,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata eco920_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 1,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- static struct physmap_flash_data eco920_flash_data = {
-@@ -104,7 +104,7 @@ static void __init eco920_board_init(void)
- at91_add_device_usbh(&eco920_usbh_data);
- at91_add_device_udc(&eco920_udc_data);
-
-- at91_add_device_mmc(0, &eco920_mmc_data);
-+ at91_add_device_mci(0, &eco920_mci0_data);
- platform_device_register(&eco920_flash);
-
- at91_ramc_write(0, AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
-diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
-index 6cc83a8..fa98aba 100644
---- a/arch/arm/mach-at91/board-flexibity.c
-+++ b/arch/arm/mach-at91/board-flexibity.c
-@@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = {
- };
-
- /* MCI (SD/MMC) */
--static struct at91_mmc_data __initdata flexibity_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PC9,
-- .wp_pin = AT91_PIN_PC4,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata flexibity_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PC9,
-+ .wp_pin = AT91_PIN_PC4,
-+ },
- };
-
- /* LEDs */
-@@ -152,7 +152,7 @@ static void __init flexibity_board_init(void)
- at91_add_device_spi(flexibity_spi_devices,
- ARRAY_SIZE(flexibity_spi_devices));
- /* MMC */
-- at91_add_device_mmc(0, &flexibity_mmc_data);
-+ at91_add_device_mci(0, &flexibity_mci0_data);
- /* LEDs */
- at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
- }
-diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
-index 69ab124..6e47071 100644
---- a/arch/arm/mach-at91/board-foxg20.c
-+++ b/arch/arm/mach-at91/board-foxg20.c
-@@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = {
- * SPI devices.
- */
- static struct spi_board_info foxg20_spi_devices[] = {
--#if !defined(CONFIG_MMC_AT91)
-+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- {
- .modalias = "mtd_dataflash",
- .chip_select = 1,
-@@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = {
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
--static struct at91_mmc_data __initdata foxg20_mmc_data = {
-- .slot_b = 1,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata foxg20_mci0_data = {
-+ .slot[1] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
-
-@@ -247,7 +247,7 @@ static void __init foxg20_board_init(void)
- /* Ethernet */
- at91_add_device_eth(&foxg20_macb_data);
- /* MMC */
-- at91_add_device_mmc(0, &foxg20_mmc_data);
-+ at91_add_device_mci(0, &foxg20_mci0_data);
- /* I2C */
- at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
- /* LEDs */
-diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
-index 5d96cb8..330d603 100644
---- a/arch/arm/mach-at91/board-kb9202.c
-+++ b/arch/arm/mach-at91/board-kb9202.c
-@@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = {
- .pullup_pin = AT91_PIN_PB22,
- };
-
--static struct at91_mmc_data __initdata kb9202_mmc_data = {
-- .det_pin = AT91_PIN_PB2,
-- .slot_b = 0,
-- .wire4 = 1,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata kb9202_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB2,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- static struct mtd_partition __initdata kb9202_nand_partition[] = {
-@@ -121,7 +121,7 @@ static void __init kb9202_board_init(void)
- /* USB Device */
- at91_add_device_udc(&kb9202_udc_data);
- /* MMC */
-- at91_add_device_mmc(0, &kb9202_mmc_data);
-+ at91_add_device_mci(0, &kb9202_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
-diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
-index 5d3b4d6..7fb2a8f 100644
---- a/arch/arm/mach-at91/board-neocore926.c
-+++ b/arch/arm/mach-at91/board-neocore926.c
-@@ -140,11 +140,12 @@ static struct spi_board_info neocore926_spi_devices[] = {
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata neocore926_mmc_data = {
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PE18,
-- .wp_pin = AT91_PIN_PE19,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata neocore926_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PE18,
-+ .wp_pin = AT91_PIN_PE19,
-+ },
- };
-
-
-@@ -356,7 +357,7 @@ static void __init neocore926_board_init(void)
- neocore926_add_device_ts();
-
- /* MMC */
-- at91_add_device_mmc(1, &neocore926_mmc_data);
-+ at91_add_device_mci(0, &neocore926_mci0_data);
-
- /* Ethernet */
- at91_add_device_eth(&neocore926_macb_data);
-diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
-index 1270655..f83e1de 100644
---- a/arch/arm/mach-at91/board-picotux200.c
-+++ b/arch/arm/mach-at91/board-picotux200.c
-@@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = {
- .overcurrent_pin= {-EINVAL, -EINVAL},
- };
-
--static struct at91_mmc_data __initdata picotux200_mmc_data = {
-- .det_pin = AT91_PIN_PB27,
-- .slot_b = 0,
-- .wire4 = 1,
-- .wp_pin = AT91_PIN_PA17,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata picotux200_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB27,
-+ .wp_pin = AT91_PIN_PA17,
-+ },
- };
-
- #define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
-@@ -112,7 +112,7 @@ static void __init picotux200_board_init(void)
- at91_add_device_i2c(NULL, 0);
- /* MMC */
- at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
-- at91_add_device_mmc(0, &picotux200_mmc_data);
-+ at91_add_device_mci(0, &picotux200_mci0_data);
- /* NOR Flash */
- platform_device_register(&picotux200_flash);
- }
-diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
-index bf351e2..799f214 100644
---- a/arch/arm/mach-at91/board-qil-a9260.c
-+++ b/arch/arm/mach-at91/board-qil-a9260.c
-@@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void)
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata ek_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- /*
-@@ -245,7 +245,7 @@ static void __init ek_board_init(void)
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* MMC */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &ek_mci0_data);
- /* Push Buttons */
- ek_add_device_buttons();
- /* LEDs */
-diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
-index cc2bf97..54733ec 100644
---- a/arch/arm/mach-at91/board-rm9200dk.c
-+++ b/arch/arm/mach-at91/board-rm9200dk.c
-@@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = {
- };
-
- #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
--static struct at91_mmc_data __initdata dk_mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata dk_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
- #endif
-
-@@ -208,7 +208,7 @@ static void __init dk_board_init(void)
- #else
- /* MMC */
- at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
-- at91_add_device_mmc(0, &dk_mmc_data);
-+ at91_add_device_mci(0, &dk_mci0_data);
- #endif
- /* NAND */
- at91_add_device_nand(&dk_nand_data);
-diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
-index 62e19e6..69ef141 100644
---- a/arch/arm/mach-at91/board-rm9200ek.c
-+++ b/arch/arm/mach-at91/board-rm9200ek.c
-@@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = {
- };
-
- #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .det_pin = AT91_PIN_PB27,
-- .slot_b = 0,
-- .wire4 = 1,
-- .wp_pin = AT91_PIN_PA17,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata ek_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB27,
-+ .wp_pin = AT91_PIN_PA17,
-+ }
- };
- #endif
-
-@@ -177,7 +177,7 @@ static void __init ek_board_init(void)
- #else
- /* MMC */
- at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &ek_mci0_data);
- #endif
- /* NOR Flash */
- platform_device_register(&ek_flash);
-diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
-index c3b43ae..806d0c3 100644
---- a/arch/arm/mach-at91/board-rsi-ews.c
-+++ b/arch/arm/mach-at91/board-rsi-ews.c
-@@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = {
- /*
- * SD/MC
- */
--static struct at91_mmc_data rsi_ews_mmc_data __initdata = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PB27,
-- .wp_pin = AT91_PIN_PB29,
-+static struct mci_platform_data __initdata rsi_ews_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB27,
-+ .wp_pin = AT91_PIN_PB29,
-+ },
- };
-
- /*
-@@ -215,7 +216,7 @@ static void __init rsi_ews_board_init(void)
- at91_add_device_spi(rsi_ews_spi_devices,
- ARRAY_SIZE(rsi_ews_spi_devices));
- /* MMC */
-- at91_add_device_mmc(0, &rsi_ews_mmc_data);
-+ at91_add_device_mci(0, &rsi_ews_mci0_data);
- /* NOR Flash */
- platform_device_register(&rsiews_nor_flash);
- /* LEDs */
-diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
-index 7bf6da7..3573f10 100644
---- a/arch/arm/mach-at91/board-sam9-l9260.c
-+++ b/arch/arm/mach-at91/board-sam9-l9260.c
-@@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
- * SPI devices.
- */
- static struct spi_board_info ek_spi_devices[] = {
--#if !defined(CONFIG_MMC_AT91)
-+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
-@@ -158,12 +158,12 @@ static void __init ek_add_device_nand(void)
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .slot_b = 1,
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PC8,
-- .wp_pin = AT91_PIN_PC4,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata ek_mci0_data = {
-+ .slot[1] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PC8,
-+ .wp_pin = AT91_PIN_PC4,
-+ },
- };
-
- static void __init ek_board_init(void)
-@@ -194,7 +194,7 @@ static void __init ek_board_init(void)
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* MMC */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &ek_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- }
-diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
-index 889c1bf..8cd6e67 100644
---- a/arch/arm/mach-at91/board-sam9260ek.c
-+++ b/arch/arm/mach-at91/board-sam9260ek.c
-@@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
- * SPI devices.
- */
- static struct spi_board_info ek_spi_devices[] = {
--#if !defined(CONFIG_MMC_AT91)
-+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
-@@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void)
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .slot_b = 1,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata ek_mci0_data = {
-+ .slot[1] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
-
-@@ -329,7 +329,7 @@ static void __init ek_board_init(void)
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* MMC */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &ek_mci0_data);
- /* I2C */
- at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
- /* SSC (to AT73C213) */
-diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
-index 2e1c9c5..b8900d5 100644
---- a/arch/arm/mach-at91/board-sam9261ek.c
-+++ b/arch/arm/mach-at91/board-sam9261ek.c
-@@ -342,11 +342,12 @@ static struct spi_board_info ek_spi_devices[] = {
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = -EINVAL,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- #endif /* CONFIG_SPI_ATMEL_* */
-@@ -600,7 +601,7 @@ static void __init ek_board_init(void)
- at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
- #else
- /* MMC */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &mci0_data);
- #endif
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
-diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
-index 7c34908..d4dd017 100644
---- a/arch/arm/mach-at91/board-sam9263ek.c
-+++ b/arch/arm/mach-at91/board-sam9263ek.c
-@@ -143,11 +143,12 @@ static struct spi_board_info ek_spi_devices[] = {
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PE18,
-- .wp_pin = AT91_PIN_PE19,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata mci1_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PE18,
-+ .wp_pin = AT91_PIN_PE19,
-+ },
- };
-
-
-@@ -422,7 +423,7 @@ static void __init ek_board_init(void)
- /* Touchscreen */
- ek_add_device_ts();
- /* MMC */
-- at91_add_device_mmc(1, &ek_mmc_data);
-+ at91_add_device_mci(1, &mci1_data);
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* NAND */
-diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
-index da6d019..50dc86d 100644
---- a/arch/arm/mach-at91/board-sam9g20ek.c
-+++ b/arch/arm/mach-at91/board-sam9g20ek.c
-@@ -90,7 +90,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
- * SPI devices.
- */
- static struct spi_board_info ek_spi_devices[] = {
--#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
-+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
-@@ -197,7 +197,6 @@ static void __init ek_add_device_nand(void)
- * MCI (SD/MMC)
- * wp_pin and vcc_pin are not connected
- */
--#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
- static struct mci_platform_data __initdata ek_mmc_data = {
- .slot[1] = {
- .bus_width = 4,
-@@ -206,28 +205,15 @@ static struct mci_platform_data __initdata ek_mmc_data = {
- },
-
- };
--#else
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .slot_b = 1, /* Only one slot so use slot B */
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PC9,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
--};
--#endif
-
- static void __init ek_add_device_mmc(void)
- {
--#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
- if (ek_have_2mmc()) {
- ek_mmc_data.slot[0].bus_width = 4;
- ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
- ek_mmc_data.slot[0].wp_pin = -1;
- }
- at91_add_device_mci(0, &ek_mmc_data);
--#else
-- at91_add_device_mmc(0, &ek_mmc_data);
--#endif
- }
-
- /*
-diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
-index 81d82be..628fec9 100644
---- a/arch/arm/mach-at91/board-sam9rlek.c
-+++ b/arch/arm/mach-at91/board-sam9rlek.c
-@@ -58,11 +58,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = {
- /*
- * MCI (SD/MMC)
- */
--static struct at91_mmc_data __initdata ek_mmc_data = {
-- .wire4 = 1,
-- .det_pin = AT91_PIN_PA15,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PA15,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
-
-@@ -305,7 +306,7 @@ static void __init ek_board_init(void)
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* MMC */
-- at91_add_device_mmc(0, &ek_mmc_data);
-+ at91_add_device_mci(0, &mci0_data);
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
- /* AC97 */
-diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
-index 29eae16..c3fb31d 100644
---- a/arch/arm/mach-at91/board-stamp9g20.c
-+++ b/arch/arm/mach-at91/board-stamp9g20.c
-@@ -83,7 +83,6 @@ static void __init add_device_nand(void)
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
--#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
- static struct mci_platform_data __initdata mmc_data = {
- .slot[0] = {
- .bus_width = 4,
-@@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = {
- .wp_pin = -1,
- },
- };
--#else
--static struct at91_mmc_data __initdata mmc_data = {
-- .slot_b = 0,
-- .wire4 = 1,
-- .det_pin = -EINVAL,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
--};
--#endif
-
-
- /*
-@@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void)
- /* NAND */
- add_device_nand();
- /* MMC */
--#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
- at91_add_device_mci(0, &mmc_data);
--#else
-- at91_add_device_mmc(0, &mmc_data);
--#endif
- /* W1 */
- add_w1();
- }
-diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
-index c1476b9..6ea069b 100644
---- a/arch/arm/mach-at91/board-usb-a926x.c
-+++ b/arch/arm/mach-at91/board-usb-a926x.c
-@@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = {
- * SPI devices.
- */
- static struct spi_board_info usb_a9263_spi_devices[] = {
--#if !defined(CONFIG_MMC_AT91)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- }
--#endif
- };
-
- static struct spi_board_info usb_a9g20_spi_devices[] = {
-diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
-index 516d340..2355de2 100644
---- a/arch/arm/mach-at91/board-yl-9200.c
-+++ b/arch/arm/mach-at91/board-yl-9200.c
-@@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = {
- /*
- * MMC
- */
--static struct at91_mmc_data __initdata yl9200_mmc_data = {
-- .det_pin = AT91_PIN_PB9,
-- .wire4 = 1,
-- .wp_pin = -EINVAL,
-- .vcc_pin = -EINVAL,
-+static struct mci_platform_data __initdata yl9200_mci0_data = {
-+ .slot[0] = {
-+ .bus_width = 4,
-+ .detect_pin = AT91_PIN_PB9,
-+ .wp_pin = -EINVAL,
-+ },
- };
-
- /*
-@@ -568,7 +569,7 @@ static void __init yl9200_board_init(void)
- /* I2C */
- at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
- /* MMC */
-- at91_add_device_mmc(0, &yl9200_mmc_data);
-+ at91_add_device_mci(0, &yl9200_mci0_data);
- /* NAND */
- at91_add_device_nand(&yl9200_nand_data);
- /* NOR Flash */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 368c0a49db43c164a47f60bb1d956ebea0a661ef Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 17 Feb 2012 13:12:21 +0100
+Subject: video: atmel_lcdfb: HLCD modifications
+
+HAS TO BE REWORKED: break compatibility with previous LCD IP due to register
+map changes
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 43 +++++++++++++++++++++++++++
+ drivers/video/atmel_hlcdfb.c | 5 ++--
+ drivers/video/atmel_lcdfb.c | 1 +
+ drivers/video/atmel_lcdfb_core.c | 1 +
+ drivers/video/backlight/Kconfig | 4 +--
+ 5 files changed, 50 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index 9ed7e6e..738a853 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -29,8 +29,10 @@
+ #define LCDC_LCDCFG0_CLKPWMSEL (0x1 << 3)
+ #define LCDC_LCDCFG0_CGDISBASE (0x1 << 8)
+ #define LCDC_LCDCFG0_CGDISOVR1 (0x1 << 9)
++#define LCDC_LCDCFG0_CGDISOVR2 (0x1 << 10)
+ #define LCDC_LCDCFG0_CGDISHEO (0x1 << 11)
+ #define LCDC_LCDCFG0_CGDISHCR (0x1 << 12)
++#define LCDC_LCDCFG0_CGDISPP (0x1 << 13)
+ #define LCDC_LCDCFG0_CLKDIV_OFFSET 16
+ #define LCDC_LCDCFG0_CLKDIV (0xff << LCDC_LCDCFG0_CLKDIV_OFFSET)
+
+@@ -49,8 +51,10 @@
+ #define ATMEL_LCDC_LCDCFG3 0x000C
+ #define LCDC_LCDCFG3_HFPW_OFFSET 0
+ #define LCDC_LCDCFG3_HFPW (0xff << LCDC_LCDCFG3_HFPW_OFFSET)
++#define LCDC2_LCDCFG3_HFPW (0x1ff << LCDC_LCDCFG3_HFPW_OFFSET)
+ #define LCDC_LCDCFG3_HBPW_OFFSET 16
+ #define LCDC_LCDCFG3_HBPW (0xff << LCDC_LCDCFG3_HBPW_OFFSET)
++#define LCDC2_LCDCFG3_HBPW (0x1ff << LCDC_LCDCFG3_HBPW_OFFSET)
+
+ #define ATMEL_LCDC_LCDCFG4 0x0010
+ #define LCDC_LCDCFG4_PPL_OFFSET 0
+@@ -73,6 +77,7 @@
+ #define LCDC_LCDCFG5_MODE_OUTPUT_16BPP (0x1 << 8)
+ #define LCDC_LCDCFG5_MODE_OUTPUT_18BPP (0x2 << 8)
+ #define LCDC_LCDCFG5_MODE_OUTPUT_24BPP (0x3 << 8)
++#define LCDC_LCDCFG5_PP (0x1 << 10)
+ #define LCDC_LCDCFG5_VSPSU (0x1 << 12)
+ #define LCDC_LCDCFG5_VSPHO (0x1 << 13)
+ #define LCDC_LCDCFG5_GUARDTIME_OFFSET 16
+@@ -115,8 +120,10 @@
+ #define LCDC_LCDIER_FIFOERRIE (0x1 << 4)
+ #define LCDC_LCDIER_BASEIE (0x1 << 8)
+ #define LCDC_LCDIER_OVR1IE (0x1 << 9)
++#define LCDC_LCDIER_OVR2IE (0x1 << 10)
+ #define LCDC_LCDIER_HEOIE (0x1 << 11)
+ #define LCDC_LCDIER_HCRIE (0x1 << 12)
++#define LCDC_LCDIER_PPIE (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDIDR 0x0030
+ #define LCDC_LCDIDR_SOFID (0x1 << 0)
+@@ -125,8 +132,10 @@
+ #define LCDC_LCDIDR_FIFOERRID (0x1 << 4)
+ #define LCDC_LCDIDR_BASEID (0x1 << 8)
+ #define LCDC_LCDIDR_OVR1ID (0x1 << 9)
++#define LCDC_LCDIDR_OVR2ID (0x1 << 10)
+ #define LCDC_LCDIDR_HEOID (0x1 << 11)
+ #define LCDC_LCDIDR_HCRID (0x1 << 12)
++#define LCDC_LCDIDR_PPID (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDIMR 0x0034
+ #define LCDC_LCDIMR_SOFIM (0x1 << 0)
+@@ -135,8 +144,10 @@
+ #define LCDC_LCDIMR_FIFOERRIM (0x1 << 4)
+ #define LCDC_LCDIMR_BASEIM (0x1 << 8)
+ #define LCDC_LCDIMR_OVR1IM (0x1 << 9)
++#define LCDC_LCDIMR_OVR2IM (0x1 << 10)
+ #define LCDC_LCDIMR_HEOIM (0x1 << 11)
+ #define LCDC_LCDIMR_HCRIM (0x1 << 12)
++#define LCDC_LCDIMR_PPIM (0x1 << 13)
+
+ #define ATMEL_LCDC_LCDISR 0x0038
+ #define LCDC_LCDISR_SOF (0x1 << 0)
+@@ -145,8 +156,11 @@
+ #define LCDC_LCDISR_FIFOERR (0x1 << 4)
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
++#define LCDC_LCDISR_OVR2 (0x1 << 10)
+ #define LCDC_LCDISR_HEO (0x1 << 10)
++#define LCDC2_LCDISR_HEO (0x1 << 11)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
++#define LCDC_LCDISR_PP (0x1 << 13)
+
+ #define ATMEL_LCDC_BASECHER 0x0040
+ #define LCDC_BASECHER_CHEN (0x1 << 0)
+@@ -205,6 +219,7 @@
+ #define ATMEL_LCDC_BASENEXT 0x0068
+
+ #define ATMEL_LCDC_BASECFG0 0x006C
++#define LCDC_BASECFG0_SIF (0x1 << 0)
+ #define LCDC_BASECFG0_BLEN_OFFSET 4
+ #define LCDC_BASECFG0_BLEN (0x3 << LCDC_BASECFG0_BLEN_OFFSET)
+ #define LCDC_BASECFG0_BLEN_AHB_SINGLE (0x0 << 4)
+@@ -251,8 +266,22 @@
+ #define ATMEL_LCDC_BASECFG4 0x007C
+ #define LCDC_BASECFG4_DMA (0x1 << 8)
+ #define LCDC_BASECFG4_REP (0x1 << 9)
++#define LCDC_BASECFG4_DISCEN (0x1 << 11)
++
++#define ATMEL_LCDC_BASECFG5 0x0080
++#define LCDC_BASECFG5_DISCXPOS_OFFSET 0
++#define LCDC_BASECFG5_DISCXPOS (0x7ff << LCDC_BASECFG5_DISCXPOS_OFFSET)
++#define LCDC_BASECFG5_DISCYPOS_OFFSET 16
++#define LCDC_BASECFG5_DISCYPOS (0x7ff << LCDC_BASECFG5_DISCYPOS_OFFSET)
++
++#define ATMEL_LCDC_BASECFG6 0x0084
++#define LCDC_BASECFG6_DISCXSIZE_OFFSET 0
++#define LCDC_BASECFG6_DISCXSIZE (0x7ff << LCDC_BASECFG6_DISCXSIZE_OFFSET)
++#define LCDC_BASECFG6_DISCYSIZE_OFFSET 16
++#define LCDC_BASECFG6_DISCYSIZE (0x7ff << LCDC_BASECFG6_DISCYSIZE_OFFSET)
+
+ #define ATMEL_LCDC_HEOCHER 0x0280
++#define ATMEL_LCDC2_HEOCHER 0x0340
+ #define LCDC_HEOCHER_CHEN (0x1 << 0)
+ #define LCDC_HEOCHER_UPDATEEN (0x1 << 1)
+ #define LCDC_HEOCHER_A2QEN (0x1 << 2)
+@@ -674,6 +703,7 @@
+ #define LCDC_HCRCFG9_GA_Msk (0xff << LCDC_HCRCFG9_GA_OFFSET)
+
+ #define ATMEL_LCDC_BASECLUT 0x400
++#define ATMEL_LCDC2_BASECLUT 0x600
+ #define LCDC_BASECLUT_BCLUT_OFFSET 0
+ #define LCDC_BASECLUT_BCLUT (0xff << LCDC_BASECLUT_BCLUT_OFFSET)
+ #define LCDC_BASECLUT_GCLUT_OFFSET 8
+@@ -682,6 +712,7 @@
+ #define LCDC_BASECLUT_RCLUT (0xff << LCDC_BASECLUT_RCLUT_OFFSET)
+
+ #define ATMEL_LCDC_OVR1CLUT 0x800
++#define ATMEL_LCDC2_OVR1CLUT 0xa00
+ #define LCDC_OVR1CLUT_BCLUT_OFFSET 0
+ #define LCDC_OVR1CLUT_BCLUT (0xff << LCDC_OVR1CLUT_BCLUT_OFFSET)
+ #define LCDC_OVR1CLUT_GCLUT_OFFSET 8
+@@ -691,7 +722,18 @@
+ #define LCDC_OVR1CLUT_ACLUT_OFFSET 24
+ #define LCDC_OVR1CLUT_ACLUT (0xff << LCDC_OVR1CLUT_ACLUT_OFFSET)
+
++#define ATMEL_LCDC_OVR2CLUT 0xe00
++#define LCDC_OVR2CLUT_BCLUT_OFFSET 0
++#define LCDC_OVR2CLUT_BCLUT (0xff << LCDC_OVR2CLUT_BCLUT_OFFSET)
++#define LCDC_OVR2CLUT_GCLUT_OFFSET 8
++#define LCDC_OVR2CLUT_GCLUT (0xff << LCDC_OVR2CLUT_GCLUT_OFFSET)
++#define LCDC_OVR2CLUT_RCLUT_OFFSET 16
++#define LCDC_OVR2CLUT_RCLUT (0xff << LCDC_OVR2CLUT_RCLUT_OFFSET)
++#define LCDC_OVR2CLUT_ACLUT_OFFSET 24
++#define LCDC_OVR2CLUT_ACLUT (0xff << LCDC_OVR2CLUT_ACLUT_OFFSET)
++
+ #define ATMEL_LCDC_HEOCLUT 0x1000
++#define ATMEL_LCDC2_HEOCLUT 0x1200
+ #define LCDC_HEOCLUT_BCLUT_OFFSET 0
+ #define LCDC_HEOCLUT_BCLUT (0xff << LCDC_HEOCLUT_BCLUT_OFFSET)
+ #define LCDC_HEOCLUT_GCLUT_OFFSET 8
+@@ -702,6 +744,7 @@
+ #define LCDC_HEOCLUT_ACLUT (0xff << LCDC_HEOCLUT_ACLUT_OFFSET)
+
+ #define ATMEL_LCDC_HCRCLUT 0x1400
++#define ATMEL_LCDC2_HCRCLUT 0x1600
+ #define LCDC_HCRCLUT_BCLUT_OFFSET 0
+ #define LCDC_HCRCLUT_BCLUT (0xff << LCDC_HCRCLUT_BCLUT_OFFSET)
+ #define LCDC_HCRCLUT_GCLUT_OFFSET 8
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index 346bb80..c4c4559 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/backlight.h>
+@@ -363,11 +364,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ var->lower_margin = min_t(u32, var->lower_margin,
+ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
+ var->right_margin = min_t(u32, var->right_margin,
+- (LCDC_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ (LCDC2_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
+ var->hsync_len = min_t(u32, var->hsync_len,
+ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
+ var->left_margin = min_t(u32, var->left_margin,
+- (LCDC_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++ (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+
+ }
+
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 402cb24..86e3e32 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/interrupt.h>
+ #include <linux/backlight.h>
+diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c
+index ff84234..133d4ad 100644
+--- a/drivers/video/atmel_lcdfb_core.c
++++ b/drivers/video/atmel_lcdfb_core.c
+@@ -9,6 +9,7 @@
+ */
+
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/interrupt.h>
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index af16884..18d066b 100644
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -144,8 +144,8 @@ if BACKLIGHT_CLASS_DEVICE
+
+ config BACKLIGHT_ATMEL_LCDC
+ bool "Atmel LCDC Contrast-as-Backlight control"
+- depends on FB_ATMEL
+- default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
++ depends on FB_ATMEL || FB_ATMEL_HLCD
++ default y
+ help
+ This provides a backlight control internal to the Atmel LCDC
+ driver. If the LCD "contrast control" on your board is wired
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 646f4f7426dbbc1814d2d7935562bdf46ffc8e0f Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 2 Jul 2012 17:15:58 +0200
-Subject: ARM: at91/defconfig: change the MCI driver to use in defconfigs
-
-Since atmel-mci driver supports all atmel mci versions,
-use it instead of the deprecated at91_mci driver.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/configs/at91rm9200_defconfig | 2 +-
- arch/arm/configs/at91sam9261_defconfig | 2 +-
- arch/arm/configs/at91sam9263_defconfig | 2 +-
- arch/arm/configs/at91sam9g20_defconfig | 2 +-
- arch/arm/configs/at91sam9rl_defconfig | 2 +-
- arch/arm/configs/cpu9260_defconfig | 2 +-
- arch/arm/configs/cpu9g20_defconfig | 2 +-
- arch/arm/configs/qil-a9260_defconfig | 2 +-
- arch/arm/configs/stamp9g20_defconfig | 1 -
- 9 files changed, 8 insertions(+), 9 deletions(-)
-
-diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
-index d54e2ac..4ae57a3 100644
---- a/arch/arm/configs/at91rm9200_defconfig
-+++ b/arch/arm/configs/at91rm9200_defconfig
-@@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y
- CONFIG_USB_ETH=m
- CONFIG_USB_MASS_STORAGE=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=y
-+CONFIG_MMC_ATMELMCI=y
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig
-index ade6b2f..1e8712e 100644
---- a/arch/arm/configs/at91sam9261_defconfig
-+++ b/arch/arm/configs/at91sam9261_defconfig
-@@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m
- CONFIG_USB_FILE_STORAGE=m
- CONFIG_USB_G_SERIAL=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
-index 585e7e0..d2050ca 100644
---- a/arch/arm/configs/at91sam9263_defconfig
-+++ b/arch/arm/configs/at91sam9263_defconfig
-@@ -137,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m
- CONFIG_USB_G_SERIAL=m
- CONFIG_MMC=y
- CONFIG_SDIO_UART=m
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_ATMEL_PWM=y
-diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig
-index 994d331..e1b0e80 100644
---- a/arch/arm/configs/at91sam9g20_defconfig
-+++ b/arch/arm/configs/at91sam9g20_defconfig
-@@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m
- CONFIG_USB_FILE_STORAGE=m
- CONFIG_USB_G_SERIAL=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig
-index ad562ee..7cf8785 100644
---- a/arch/arm/configs/at91sam9rl_defconfig
-+++ b/arch/arm/configs/at91sam9rl_defconfig
-@@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y
- CONFIG_FB=y
- CONFIG_FB_ATMEL=y
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_RTC_CLASS=y
- CONFIG_RTC_DRV_AT91SAM9=y
- CONFIG_EXT2_FS=y
-diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig
-index bbf729e..921480c 100644
---- a/arch/arm/configs/cpu9260_defconfig
-+++ b/arch/arm/configs/cpu9260_defconfig
-@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
- CONFIG_USB_GADGET=y
- CONFIG_USB_ETH=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig
-index e7d7942..ea116cb 100644
---- a/arch/arm/configs/cpu9g20_defconfig
-+++ b/arch/arm/configs/cpu9g20_defconfig
-@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
- CONFIG_USB_GADGET=y
- CONFIG_USB_ETH=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
-index 2bb100b..42d5db1 100644
---- a/arch/arm/configs/qil-a9260_defconfig
-+++ b/arch/arm/configs/qil-a9260_defconfig
-@@ -86,7 +86,7 @@ CONFIG_USB_STORAGE=y
- CONFIG_USB_GADGET=y
- CONFIG_USB_ETH=m
- CONFIG_MMC=y
--CONFIG_MMC_AT91=m
-+CONFIG_MMC_ATMELMCI=m
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
- CONFIG_LEDS_GPIO=y
-diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig
-index d5e260b..52f1488 100644
---- a/arch/arm/configs/stamp9g20_defconfig
-+++ b/arch/arm/configs/stamp9g20_defconfig
-@@ -100,7 +100,6 @@ CONFIG_USB_ETH=m
- CONFIG_USB_FILE_STORAGE=m
- CONFIG_USB_G_SERIAL=m
- CONFIG_MMC=y
--# CONFIG_MMC_AT91 is not set
- CONFIG_MMC_ATMELMCI=y
- CONFIG_NEW_LEDS=y
- CONFIG_LEDS_CLASS=y
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 44715fbb365b351a7f1efe27639a56684991eccc Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 24 Jun 2011 13:03:29 +0200
+Subject: atmel_lcdfb: change pixel clock ratio calculation
+
+DIV_ROUND_UP() was used to calculate the pixel clock divider
+in atmel_hlcdfb_setup_core_base().
+But this rounding was producing a bigger divider each time it was called.
+We replace by DIV_ROUND_CLOSEST() to calculate it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/video/atmel_hlcdfb.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index c4c4559..a629dda 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -247,7 +247,7 @@ static int atmel_hlcdfb_setup_core_base(struct fb_info *info)
+ /* Set pixel clock */
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+- value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
++ value = DIV_ROUND_CLOSEST(clk_value_khz, PICOS2KHZ(info->var.pixclock));
+
+ if (value < 1) {
+ dev_notice(info->device, "using system clock as pixel clock\n");
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From a16a507fb90bf1629f81cae4fc197def0382bc91 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Tue, 24 May 2011 23:45:21 +0200
+Subject: media/at91sam9x5-video: new driver for the high end overlay on
+ at91sam9x5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+---
+ drivers/media/video/Kconfig | 8 +
+ drivers/media/video/Makefile | 1 +
+ drivers/media/video/at91sam9x5-video.c | 1441 ++++++++++++++++++++++++++++++++
+ 3 files changed, 1450 insertions(+)
+ create mode 100644 drivers/media/video/at91sam9x5-video.c
+
+diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
+index ce1e7ba..70a6a55 100644
+--- a/drivers/media/video/Kconfig
++++ b/drivers/media/video/Kconfig
+@@ -1163,6 +1163,14 @@ source "drivers/media/video/s5p-tv/Kconfig"
+ endif # V4L_PLATFORM_DRIVERS
+ endif # VIDEO_CAPTURE_DRIVERS
+
++config VIDEO_AT91SAM9X5
++ tristate "Support for AT91SAM9X5 Video"
++ depends on ARCH_AT91
++ depends on VIDEO_V4L2
++ select VIDEOBUF2_DMA_CONTIG
++ help
++ support for the "High End Overlay" found in Atmel's AT91SAM9X5 SoCs.
++
+ menuconfig V4L_MEM2MEM_DRIVERS
+ bool "Memory-to-memory multimedia devices"
+ depends on VIDEO_V4L2
+diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
+index a6282a3..2b41c18 100644
+--- a/drivers/media/video/Makefile
++++ b/drivers/media/video/Makefile
+@@ -121,6 +121,7 @@ obj-$(CONFIG_VIDEO_MXB) += mxb.o
+ obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
+ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+ obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
++obj-$(CONFIG_VIDEO_AT91SAM9X5) += at91sam9x5-video.o
+
+ obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+ obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+new file mode 100644
+index 0000000..26ce376
+--- /dev/null
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -0,0 +1,1441 @@
++/*
++ * Copyright (C) 2011 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation.
++ */
++
++/*
++ * XXX:
++ * - handle setting of global alpha
++ * - handle more formats
++ * - complete this list :-)
++ */
++
++#include <linux/err.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-ioctl.h>
++#include <media/videobuf2-dma-contig.h>
++
++#define debug(fmt, ...)
++
++#define DRIVER_NAME "at91sam9x5-video"
++
++#define REG_HEOCHER 0x00
++#define REG_HEOCHER_CHEN 0x00000001
++#define REG_HEOCHER_UPDATEEN 0x00000002
++#define REG_HEOCHER_A2QEN 0x00000004
++
++#define REG_HEOCHDR 0x04
++#define REG_HEOCHDR_CHDIS 0x00000001
++#define REG_HEOCHDR_CHRST 0x00000100
++
++#define REG_HEOCHSR 0x08
++#define REG_HEOCHSR_CHSR 0x00000001
++#define REG_HEOCHSR_UPDATESR 0x00000002
++#define REG_HEOCHSR_A2QSR 0x00000004
++
++#define REG_HEOIER 0x0c
++#define REG_HEOIDR 0x10
++#define REG_HEOIMR 0x14
++#define REG_HEOISR 0x18
++#define REG_HEOIxR_DMA 0x00000004
++#define REG_HEOIxR_DSCR 0x00000008
++#define REG_HEOIxR_ADD 0x00000010
++#define REG_HEOIxR_DONE 0x00000020
++#define REG_HEOIxR_OVR 0x00000040
++#define REG_HEOIxR_UDMA 0x00000400
++#define REG_HEOIxR_UDSCR 0x00000800
++#define REG_HEOIxR_UADD 0x00001000
++#define REG_HEOIxR_UDONE 0x00002000
++#define REG_HEOIxR_UOVR 0x00004000
++#define REG_HEOIxR_VDMA 0x00040000
++#define REG_HEOIxR_VDSCR 0x00080000
++#define REG_HEOIxR_VADD 0x00100000
++#define REG_HEOIxR_VDONE 0x00200000
++#define REG_HEOIxR_VOVR 0x00400000
++
++#define REG_HEOHEAD 0x1c
++#define REG_HEOUHEAD 0x2c
++#define REG_HEOVHEAD 0x3c
++
++#define REG_HEOADDR 0x20
++#define REG_HEOUADDR 0x30
++#define REG_HEOVADDR 0x40
++
++#define REG_HEOCTRL 0x24
++#define REG_HEOUCTRL 0x34
++#define REG_HEOVCTRL 0x44
++#define REG_HEOxCTRL_DFETCH 0x00000001
++#define REG_HEOCTRL_LFETCH 0x00000002
++#define REG_HEOxCTRL_DMAIEN 0x00000004
++#define REG_HEOxCTRL_DSCRIEN 0x00000008
++#define REG_HEOxCTRL_ADDIEN 0x00000010
++#define REG_HEOxCTRL_DONEIEN 0x00000020
++
++#define REG_HEONEXT 0x28
++#define REG_HEOUNEXT 0x38
++#define REG_HEOVNEXT 0x48
++
++#define REG_HEOCFG0 0x4c
++#define REG_HEOCFG0_DLBO 0x00000100
++#define REG_HEOCFG0_BLEN 0x00000030
++#define REG_HEOCFG0_BLEN_INCR1 0x00000000
++#define REG_HEOCFG0_BLEN_INCR4 0x00000010
++#define REG_HEOCFG0_BLEN_INCR8 0x00000020
++#define REG_HEOCFG0_BLEN_INCR16 0x00000030
++#define REG_HEOCFG0_BLENUV 0x000000c0
++#define REG_HEOCFG0_BLENUV_INCR1 0x00000000
++#define REG_HEOCFG0_BLENUV_INCR4 0x00000040
++#define REG_HEOCFG0_BLENUV_INCR8 0x00000080
++#define REG_HEOCFG0_BLENUV_INCR16 0x000000c0
++
++#define REG_HEOCFG1 0x50
++#define REG_HEOCFG1_CLUTEN 0x00000001
++#define REG_HEOCFG1_YUVEN 0x00000002
++#define REG_HEOCFG1_YUVMODE_12YCBCRP 0x00008000
++
++#define REG_HEOCFG2 0x54
++#define REG_HEOCFG2_XPOS 0x000007ff
++#define REG_HEOCFG2_YPOS 0x07ff0000
++
++#define REG_HEOCFG3 0x58
++#define REG_HEOCFG3_XSIZE 0x000007ff
++#define REG_HEOCFG3_YSIZE 0x07ff0000
++
++#define REG_HEOCFG4 0x5c
++#define REG_HEOCFG4_XMEMSIZE 0x000007ff
++#define REG_HEOCFG4_YMEMSIZE 0x07ff0000
++
++#define REG_HEOCFG5 0x60
++#define REG_HEOCFG5_XSTRIDE 0xffffffff
++
++#define REG_HEOCFG6 0x64
++#define REG_HEOCFG6_PSTRIDE 0xffffffff
++
++#define REG_HEOCFG7 0x68
++#define REG_HEOCFG7_UVXSTRIDE 0xffffffff
++
++#define REG_HEOCFG8 0x6c
++#define REG_HEOCFG8_UVPSTRIDE 0xffffffff
++
++#define REG_HEOCFG9 0x70
++#define REG_HEOCFG10 0x74
++#define REG_HEOCFG11 0x78
++
++#define REG_HEOCFG12 0x7c
++#define REG_HEOCFG12_CRKEY 0x00000001
++#define REG_HEOCFG12_INV 0x00000002
++#define REG_HEOCFG12_ITER2BL 0x00000004
++#define REG_HEOCFG12_ITER 0x00000008
++#define REG_HEOCFG12_REVALPHA 0x00000010
++#define REG_HEOCFG12_GAEN 0x00000020
++#define REG_HEOCFG12_LAEN 0x00000040
++#define REG_HEOCFG12_OVR 0x00000080
++#define REG_HEOCFG12_DMA 0x00000100
++#define REG_HEOCFG12_REP 0x00000200
++#define REG_HEOCFG12_DSTKEY 0x00000400
++#define REG_HEOCFG12_VIDPRI 0x00001000
++#define REG_HEOCFG12_GA 0x00ff0000
++
++#define REG_HEOCFG13 0x80
++#define REG_HEOCFG13_XFACTOR 0x00001fff
++#define REG_HEOCFG13_YFACTOR 0x1fff0000
++#define REG_HEOCFG13_SCALEN 0x80000000
++
++#define REG_HEOCFG14 0x84
++#define REG_HEOCFG15 0x88
++#define REG_HEOCFG16 0x8c
++
++#define valtomask(val, mask) (((val) << __ffs((mask))) & (mask))
++#define valfrommask(val, mask) (((val) & (mask)) >> __ffs((mask)))
++
++struct at91sam9x5_video_pdata {
++ u16 base_width;
++ u16 base_height;
++};
++
++struct at91sam9x5_video_bufinfo {
++ struct vb2_buffer *vb;
++ unsigned u_planeno, v_planeno;
++ unsigned long plane_size[3];
++};
++
++struct at91sam9x5_video_priv {
++ struct platform_device *pdev;
++
++ /* framebuffer stuff */
++ struct notifier_block fb_notifier;
++ struct fb_info *fbinfo;
++
++ struct video_device *video_dev;
++
++ void __iomem *regbase;
++ unsigned int irq;
++
++ struct vb2_queue queue;
++ void *alloc_ctx;
++
++ struct at91sam9x5_video_bufinfo cur, next;
++
++ /* protects the members after lock and hardware access */
++ spinlock_t lock;
++
++ enum {
++ /* DMA not running */
++ at91sam9x5_video_HW_IDLE,
++ /* DMA running, unless cfgstate is BAD */
++ at91sam9x5_video_HW_RUNNING,
++ } hwstate;
++
++ enum {
++ at91sam9x5_video_CFG_GOOD,
++ /* the shadow registers need an update */
++ at91sam9x5_video_CFG_GOOD_LATCH,
++ at91sam9x5_video_CFG_BAD,
++ } cfgstate;
++
++ /* if true the vid_out config in hardware doesn't match sw config */
++ int cfgupdate;
++
++ int valid_config;
++
++ struct v4l2_pix_format fmt_vid_out_cur, fmt_vid_out_next;
++
++ int rotation;
++
++ struct v4l2_window fmt_vid_overlay;
++
++ /*
++ * For YUV formats Y data is always in plane 0. U, V are either both in
++ * 0, both in 1, or U in 1 or V in 2. -1 for formats that don't use U
++ * and V.
++ */
++ int u_planeno, v_planeno;
++
++ unsigned long plane_size[3];
++
++ /*
++ * These are the offsets into the buffers to start the hardware for.
++ * Depending on rotation and overlay position this is more or less ugly
++ * to calculate. (y_offset is used for rgb data, too.)
++ */
++ u32 y_offset, u_offset, v_offset;
++
++ u32 irqstat;
++};
++
++static u32 at91sam9x5_video_read32(struct at91sam9x5_video_priv *priv,
++ size_t offset)
++{
++ /* XXX: really use the __raw variants? */
++ return __raw_readl(priv->regbase + offset);
++}
++
++static void at91sam9x5_video_write32(struct at91sam9x5_video_priv *priv,
++ size_t offset, u32 val)
++{
++ debug("$%x := %08x, $08 == %08x\n", offset, val,
++ at91sam9x5_video_read32(priv, REG_HEOCHSR));
++ __raw_writel(val, priv->regbase + offset);
++ debug("$08 == %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
++}
++
++static int __at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
++ struct at91sam9x5_video_bufinfo *bi,
++ size_t heoaddr_offset, unsigned planeno)
++{
++ if (planeno >= 0) {
++ u32 heoaddr = at91sam9x5_video_read32(priv, heoaddr_offset);
++ dma_addr_t plane_paddr =
++ vb2_dma_contig_plane_dma_addr(bi->vb, planeno);
++
++ if (heoaddr - plane_paddr <= bi->plane_size[planeno])
++ return 1;
++ }
++
++ return 0;
++}
++
++
++static int at91sam9x5_video_buf_in_use(struct at91sam9x5_video_priv *priv,
++ struct at91sam9x5_video_bufinfo *bi)
++{
++ if (__at91sam9x5_video_buf_in_use(priv, bi, REG_HEOADDR, 0))
++ return 1;
++ if (__at91sam9x5_video_buf_in_use(priv, bi,
++ REG_HEOUADDR, bi->u_planeno))
++ return 1;
++ if (__at91sam9x5_video_buf_in_use(priv, bi,
++ REG_HEOVADDR, bi->v_planeno))
++ return 1;
++
++ return 0;
++}
++
++static u32 at91sam9x5_video_handle_irqstat(struct at91sam9x5_video_priv *priv)
++{
++ u32 heoisr = at91sam9x5_video_read32(priv, REG_HEOISR);
++
++ debug("cur=%p, next=%p, heoisr=%08x\n", priv->cur.vb,
++ priv->next.vb, heoisr);
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++
++ if (!priv->cur.vb) {
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++
++ if (priv->hwstate == at91sam9x5_video_HW_IDLE &&
++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
++ REG_HEOCHSR_CHSR)) {
++ if (priv->cur.vb) {
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++ priv->cur.vb = NULL;
++ }
++
++ if (priv->next.vb) {
++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_DONE);
++ priv->next.vb = NULL;
++ }
++
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ } else if (priv->cur.vb && priv->next.vb) {
++ int hwrunning = 1;
++ if (priv->cfgstate == at91sam9x5_video_CFG_BAD &&
++ !(at91sam9x5_video_read32(priv, REG_HEOCHSR) &
++ REG_HEOCHSR_CHSR))
++ hwrunning = 0;
++
++ if (!hwrunning || !at91sam9x5_video_buf_in_use(priv,
++ &priv->cur)) {
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++ } else if (priv->next.vb) {
++ priv->cur = priv->next;
++ priv->next.vb = NULL;
++ }
++
++ return heoisr;
++}
++
++static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
++{
++ struct at91sam9x5_video_priv *priv = data;
++ unsigned long flags;
++ u32 handled, heoimr;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR);
++ handled = at91sam9x5_video_handle_irqstat(priv);
++
++ debug("%x, HEOCHSR = %08x\n", handled,
++ at91sam9x5_video_read32(priv, REG_HEOCHSR));
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ if (handled & heoimr)
++ return IRQ_HANDLED;
++ else
++ return IRQ_NONE;
++}
++
++static inline int sign(int x)
++{
++ if (x > 0)
++ return 1;
++ else if (x < 0)
++ return -1;
++ else
++ return 0;
++}
++
++static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
++ struct vb2_buffer *vb)
++{
++ dma_addr_t buffer = vb2_dma_contig_plane_dma_addr(vb, 0);
++ void *vaddr = vb2_plane_vaddr(vb, 0);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ /* XXX: format dependant */
++ size_t offset_dmadesc = ALIGN(pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
++ u32 *dmadesc = vaddr + offset_dmadesc;
++ u32 heocher;
++
++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD_LATCH) {
++ heocher = REG_HEOCHER_UPDATEEN;
++ priv->cfgstate = at91sam9x5_video_CFG_GOOD;
++ } else {
++ BUG_ON(priv->cfgstate != at91sam9x5_video_CFG_GOOD);
++ heocher = 0;
++ }
++
++ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
++
++ dmadesc[0] = buffer + priv->y_offset;
++ dmadesc[1] = REG_HEOxCTRL_DFETCH;
++ dmadesc[2] = buffer + offset_dmadesc;
++
++ if (priv->u_planeno >= 0) {
++ dmadesc[3] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
++ priv->u_offset;
++ dmadesc[4] = REG_HEOxCTRL_DFETCH;
++ dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
++ }
++
++ if (priv->v_planeno >= 0) {
++ dmadesc[6] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
++ priv->v_offset;
++ dmadesc[7] = REG_HEOxCTRL_DFETCH;
++ dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
++ }
++
++
++ debug("HEOCHSR = %08x\n", at91sam9x5_video_read32(priv, REG_HEOCHSR));
++ if (likely(priv->hwstate == at91sam9x5_video_HW_RUNNING)) {
++
++ at91sam9x5_video_write32(priv, REG_HEOHEAD, dmadesc[2]);
++
++ if (priv->u_planeno >= 0)
++ at91sam9x5_video_write32(priv,
++ REG_HEOUHEAD, dmadesc[5]);
++
++ if (priv->v_planeno >= 0)
++ at91sam9x5_video_write32(priv,
++ REG_HEOVHEAD, dmadesc[8]);
++
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
++
++ } else {
++
++ at91sam9x5_video_write32(priv, REG_HEOADDR, dmadesc[0]);
++ at91sam9x5_video_write32(priv, REG_HEOCTRL, dmadesc[1]);
++ at91sam9x5_video_write32(priv, REG_HEONEXT, dmadesc[2]);
++
++ if (priv->u_planeno >= 0) {
++ at91sam9x5_video_write32(priv,
++ REG_HEOUADDR, dmadesc[3]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOUCTRL, dmadesc[4]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOUNEXT, dmadesc[5]);
++ }
++
++ if (priv->v_planeno >= 0) {
++ at91sam9x5_video_write32(priv,
++ REG_HEOVADDR, dmadesc[6]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOVCTRL, dmadesc[7]);
++ at91sam9x5_video_write32(priv,
++ REG_HEOVNEXT, dmadesc[8]);
++ }
++
++ at91sam9x5_video_write32(priv, REG_HEOCHER,
++ heocher | REG_HEOCHER_CHEN);
++
++ priv->hwstate = at91sam9x5_video_HW_RUNNING;
++ }
++
++ if (priv->cur.vb && at91sam9x5_video_buf_in_use(priv, &priv->cur)) {
++ if (priv->next.vb) {
++ /* drop next; XXX: is this an error? */
++ debug("drop %p\n", priv->next.vb);
++ vb2_buffer_done(priv->next.vb, VB2_BUF_STATE_ERROR);
++ }
++ } else {
++ if (priv->cur.vb)
++ vb2_buffer_done(priv->cur.vb, VB2_BUF_STATE_DONE);
++
++ priv->cur = priv->next;
++ }
++ priv->next.vb = vb;
++ priv->next.u_planeno = priv->u_planeno;
++ priv->next.v_planeno = priv->v_planeno;
++ priv->next.plane_size[0] = priv->plane_size[0];
++ priv->next.plane_size[1] = priv->plane_size[1];
++ priv->next.plane_size[2] = priv->plane_size[2];
++}
++
++static int experimental;
++module_param(experimental, bool, 0644);
++MODULE_PARM_DESC(experimental, "enable experimental features");
++
++static void at91sam9x5_video_params(unsigned width, unsigned height,
++ int rotation, u32 *xstride, u32 *pstride, u32 *tloffset)
++{
++/* offset of pixel at (x, y) in the buffer */
++#define po(x, y) ((x) + width * (y))
++
++ /* offsets of the edges in counter-clockwise order */
++ const unsigned e[] = {
++ po(0, 0),
++ po(0, height - 1),
++ po(width - 1, height - 1),
++ po(width - 1, 0),
++ };
++
++ /*
++ * offsets of the pixels next to the corresponding edges
++ * If edge[i] goes to the top left corner, edge_neighbour[i] is
++ * located just below of edge[i].
++ */
++ const unsigned en[] = {
++ po(0, 1),
++ po(1, height - 1),
++ po(width - 1, height - 2),
++ po(width - 2, 0),
++ };
++
++#define ro(r) ((rotation + (r)) % 4)
++
++ *xstride = en[ro(0)] - e[ro(3)];
++ *pstride = e[ro(3)] - en[ro(3)];
++ *tloffset = e[ro(0)];
++}
++
++static void at91sam9x5_video_update_config_real(
++ struct at91sam9x5_video_priv *priv)
++{
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ struct v4l2_window *win = &priv->fmt_vid_overlay;
++ struct v4l2_rect *rect = &win->w;
++ /* XXX: check for overflow? */
++ s32 right = rect->left + rect->width, bottom = rect->top + rect->height;
++
++ unsigned hwxpos, hwypos, hwxsize, hwysize;
++ unsigned hwxmem_size, hwymem_size;
++ s32 hwxstride, hwpstride;
++ s32 hwuvxstride, hwuvpstride;
++ s32 rotated_pixwidth, rotated_pixheight;
++
++ debug("vout=%ux%u, ovl=(%d,%d)+(%d,%d)\n", pix->width, pix->height,
++ rect->left, rect->top, rect->width, rect->height);
++
++ if (!experimental && priv->rotation) {
++ dev_info(&priv->video_dev->dev, "disable rotation\n");
++ priv->rotation = 0;
++ }
++
++ if (rect->left < 0)
++ hwxpos = 0;
++ else
++ hwxpos = rect->left;
++
++ if (rect->top < 0)
++ hwypos = 0;
++ else
++ hwypos = rect->top;
++
++ if (right > priv->fbinfo->var.xres)
++ hwxsize = priv->fbinfo->var.xres - hwxpos;
++ else
++ hwxsize = right - hwxpos;
++
++ if (bottom > priv->fbinfo->var.yres)
++ hwysize = priv->fbinfo->var.yres - hwypos;
++ else
++ hwysize = bottom - hwypos;
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG2,
++ valtomask(hwxpos, REG_HEOCFG2_XPOS) |
++ valtomask(hwypos, REG_HEOCFG2_YPOS));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG3,
++ valtomask(hwxsize - 1, REG_HEOCFG3_XSIZE) |
++ valtomask(hwysize - 1, REG_HEOCFG3_YSIZE));
++
++ /* XXX:
++ * - clipping
++ */
++ at91sam9x5_video_write32(priv, REG_HEOCFG1,
++ REG_HEOCFG1_YUVMODE_12YCBCRP |
++ REG_HEOCFG1_YUVEN);
++ at91sam9x5_video_write32(priv, REG_HEOCFG12,
++ REG_HEOCFG12_GAEN |
++ REG_HEOCFG12_OVR |
++ REG_HEOCFG12_DMA |
++ REG_HEOCFG12_REP |
++ REG_HEOCFG12_GA);
++
++#define vx(pos) xedge[(priv->rotation + pos) % 4]
++#define vy(pos) yedge[(priv->rotation + pos) % 4]
++
++ if (priv->rotation & 1) {
++ rotated_pixwidth = pix->height;
++ rotated_pixheight = pix->width;
++ } else {
++ rotated_pixwidth = pix->width;
++ rotated_pixheight = pix->height;
++ }
++
++ hwxmem_size = rotated_pixwidth * hwxsize / rect->width;
++ hwymem_size = rotated_pixheight * hwysize / rect->height;
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG4,
++ valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) |
++ valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG13,
++ REG_HEOCFG13_SCALEN |
++ valtomask(1024 * hwxmem_size / hwxsize,
++ REG_HEOCFG13_XFACTOR) |
++ valtomask(1024 * hwymem_size / hwysize,
++ REG_HEOCFG13_YFACTOR));
++
++ at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
++ &hwxstride, &hwpstride, &priv->y_offset);
++
++ /* XXX: format-dependant */
++ at91sam9x5_video_params(DIV_ROUND_UP(pix->width, 2),
++ DIV_ROUND_UP(pix->height, 2), priv->rotation,
++ &hwuvxstride, &hwuvpstride, &priv->u_offset);
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG5,
++ valtomask(hwxstride - 1, REG_HEOCFG5_XSTRIDE));
++ at91sam9x5_video_write32(priv, REG_HEOCFG6,
++ valtomask(hwpstride - 1, REG_HEOCFG6_PSTRIDE));
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG7,
++ valtomask(hwuvxstride - 1, REG_HEOCFG7_UVXSTRIDE));
++ at91sam9x5_video_write32(priv, REG_HEOCFG8,
++ valtomask(hwuvpstride - 1, REG_HEOCFG8_UVPSTRIDE));
++
++ /* XXX: format dependant */
++ priv->u_planeno = 0;
++ priv->v_planeno = 0;
++ priv->u_offset += pix->width * pix->height;
++ priv->v_offset = priv->u_offset +
++ DIV_ROUND_UP(pix->width, 2) * DIV_ROUND_UP(pix->height, 2);
++
++ /* XXX: evaluate pix->colorspace */
++ at91sam9x5_video_write32(priv, REG_HEOCFG14, 0x4c900091);
++ at91sam9x5_video_write32(priv, REG_HEOCFG15, 0x7a5f5090);
++ at91sam9x5_video_write32(priv, REG_HEOCFG16, 0x40040890);
++}
++
++static void at91sam9x5_video_update_config(struct at91sam9x5_video_priv *priv,
++ int overlay_only)
++{
++ debug("cfgupdate=%d overlay_only=%d\n", priv->cfgupdate, overlay_only);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ if (priv->cfgupdate || overlay_only) {
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ struct v4l2_window *win = &priv->fmt_vid_overlay;
++ struct v4l2_rect *rect = &win->w;
++
++ if (!overlay_only) {
++ *pix = priv->fmt_vid_out_next;
++ priv->cfgupdate = 0;
++ }
++
++ /* XXX: handle clipping */
++ if (rect->width <= 0 || rect->height <= 0 ||
++ /* vid_out is set */
++ pix->width <= 0 ||
++ pix->height <= 0 ||
++ /* window is partly invisible or too small */
++ rect->left < 0 ||
++ rect->top < 0 ||
++ rect->left >= (int)priv->fbinfo->var.xres - 5 ||
++ rect->top >= (int)priv->fbinfo->var.yres - 5 ||
++ rect->left + rect->width >
++ (int)priv->fbinfo->var.xres ||
++ rect->top + rect->height >
++ (int)priv->fbinfo->var.yres) {
++
++ if (priv->cfgstate == at91sam9x5_video_CFG_GOOD ||
++ priv->cfgstate ==
++ at91sam9x5_video_CFG_GOOD_LATCH)
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHDR, REG_HEOCHDR_CHDIS);
++
++ priv->cfgstate = at91sam9x5_video_CFG_BAD;
++ } else {
++ at91sam9x5_video_update_config_real(priv);
++
++ debug("hwstate=%d cfgstate=%d\n",
++ priv->hwstate, priv->cfgstate);
++ if (overlay_only && priv->hwstate ==
++ at91sam9x5_video_HW_RUNNING) {
++ if (priv->cfgstate ==
++ at91sam9x5_video_CFG_BAD) {
++ priv->cfgstate =
++ at91sam9x5_video_CFG_GOOD_LATCH;
++ priv->hwstate =
++ at91sam9x5_video_HW_IDLE;
++
++ at91sam9x5_video_show_buf(priv,
++ priv->cur.vb);
++ } else
++ at91sam9x5_video_write32(priv,
++ REG_HEOCHER,
++ REG_HEOCHER_UPDATEEN);
++ } else
++ priv->cfgstate =
++ at91sam9x5_video_CFG_GOOD_LATCH;
++ }
++
++ }
++}
++
++static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
++ const struct v4l2_format *fmt,
++ unsigned int *num_buffers, unsigned int *num_planes,
++ unsigned int sizes[], void *alloc_ctxs[])
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_next;
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++
++ /* XXX */
++ *num_planes = 1;
++
++ /*
++ * The last 9 (aligned) words are used for the 3 dma descriptors (3
++ * 32-bit words each). The additional 32 bits are for alignment.
++ * XXX: is that allowed and done right?
++ * XXX: format-dependant
++ */
++ sizes[0] = pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
++ 10 * 32;
++ priv->plane_size[0] = sizes[0];
++
++ alloc_ctxs[0] = priv->alloc_ctx;
++
++ return 0;
++}
++
++static void at91sam9x5_video_vb_wait_prepare(struct vb2_queue *q)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ at91sam9x5_video_write32(priv, REG_HEOIER,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++static void at91sam9x5_video_vb_wait_finish(struct vb2_queue *q)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ debug("cfgupdate=%d hwstate=%d cfgstate=%d\n",
++ priv->cfgupdate, priv->hwstate, priv->cfgstate);
++ debug("bufs=%p,%p\n", priv->cur.vb, priv->next.vb);
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
++{
++ struct vb2_queue *q = vb->vb2_queue;
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->cfgupdate)
++ pix = &priv->fmt_vid_out_next;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++ debug("buflen=%u\n", vb->v4l2_planes[0].length);
++
++ /* XXX: format-dependant */
++ if (vb->v4l2_planes[0].length < pix->width * pix->height +
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
++ 10 * 32)
++ return -EINVAL;
++
++ return 0;
++}
++
++static void at91sam9x5_video_vb_buf_queue(struct vb2_buffer *vb)
++{
++ struct vb2_queue *q = vb->vb2_queue;
++ struct at91sam9x5_video_priv *priv =
++ container_of(q, struct at91sam9x5_video_priv, queue);
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ at91sam9x5_video_update_config(priv, 0);
++
++ switch (priv->cfgstate) {
++ case at91sam9x5_video_CFG_GOOD:
++ case at91sam9x5_video_CFG_GOOD_LATCH:
++ /* show_buf takes care of the eventual hwstate update */
++ at91sam9x5_video_show_buf(priv, vb);
++ break;
++
++ case at91sam9x5_video_CFG_BAD:
++ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
++ priv->hwstate = at91sam9x5_video_HW_RUNNING;
++ break;
++ }
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++const struct vb2_ops at91sam9x5_video_vb_ops = {
++ .queue_setup = at91sam9x5_video_vb_queue_setup,
++
++ .wait_prepare = at91sam9x5_video_vb_wait_prepare,
++ .wait_finish = at91sam9x5_video_vb_wait_finish,
++
++ .buf_prepare = at91sam9x5_video_vb_buf_prepare,
++ .buf_queue = at91sam9x5_video_vb_buf_queue,
++};
++
++static int at91sam9x5_video_vidioc_querycap(struct file *filp,
++ void *fh, struct v4l2_capability *cap)
++{
++ strcpy(cap->driver, DRIVER_NAME);
++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING |
++ V4L2_CAP_VIDEO_OVERLAY;
++
++ /* XXX */
++ cap->version = 0;
++ cap->card[0] = '\0';
++ cap->bus_info[0] = '\0';
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_g_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ f->fmt.pix = priv->fmt_vid_out_next;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_s_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct v4l2_pix_format *pix = &f->fmt.pix;
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
++ return -EINVAL;
++
++ if (pix->pixelformat != V4L2_PIX_FMT_YUV420)
++ return -EINVAL;
++
++ debug("vout=%ux%u\n", pix->width, pix->height);
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ priv->fmt_vid_out_next = *pix;
++
++ priv->cfgupdate = 1;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_g_fmt_vid_overlay(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++ return -EINVAL;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ f->fmt.win = priv->fmt_vid_overlay;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_s_fmt_vid_overlay(struct file *filp,
++ void *fh, struct v4l2_format *f)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct v4l2_window *win = &f->fmt.win;
++ unsigned long flags;
++
++ if (f->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
++ return -EINVAL;
++
++ debug("rect=(%d,%d)+(%d,%d)\n",
++ win->w.left, win->w.top, win->w.width, win->w.height);
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ priv->fmt_vid_overlay = *win;
++
++ at91sam9x5_video_update_config(priv, 1);
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_enum_fmt_vid_out(struct file *filp,
++ void *fh, struct v4l2_fmtdesc *f)
++{
++ /* XXX: support more formats */
++ if (f->index > 0)
++ return -EINVAL;
++
++ f->pixelformat = V4L2_PIX_FMT_YUV420;
++ return 0;
++}
++
++static int at91sam9x5_video_vidioc_reqbufs(struct file *filp,
++ void *fh, struct v4l2_requestbuffers *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ struct vb2_queue *q = &priv->queue;
++
++ if (b->type != q->type) {
++ dev_err(&priv->pdev->dev, "invalid buffer type (%d != %d)\n",
++ b->type, q->type);
++ return -EINVAL;
++ }
++
++ return vb2_reqbufs(q, b);
++}
++
++static int at91sam9x5_video_vidioc_querybuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_querybuf(&priv->queue, b);
++}
++
++static int at91sam9x5_video_vidioc_qbuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_qbuf(&priv->queue, b);
++}
++
++static int at91sam9x5_video_vidioc_dqbuf(struct file *filp,
++ void *fh, struct v4l2_buffer *b)
++{
++ struct video_device *vdev = filp->private_data;
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_dqbuf(&priv->queue, b, filp->f_flags & O_NONBLOCK);
++}
++
++static int at91sam9x5_video_vidioc_streamon(struct file *filp,
++ void *fh, enum v4l2_buf_type type)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ return vb2_streamon(&priv->queue, type);
++}
++
++static int at91sam9x5_video_vidioc_streamoff(struct file *filp,
++ void *fh, enum v4l2_buf_type type)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ /* disable channel */
++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHDIS);
++
++ at91sam9x5_video_handle_irqstat(priv);
++
++ if (priv->cur.vb)
++ at91sam9x5_video_write32(priv, REG_HEOIER,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA |
++ REG_HEOIxR_UADD | REG_HEOIxR_UDMA |
++ REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ priv->hwstate = at91sam9x5_video_HW_IDLE;
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return vb2_streamoff(&priv->queue, type);
++}
++
++static int at91sam9x5_video_vidioc_queryctrl(struct file *filp, void *fh,
++ struct v4l2_queryctrl *a)
++{
++ int ret;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ ret = v4l2_ctrl_query_fill(a, 0, 270, 90, 0);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static int at91sam9x5_video_vidioc_g_ctrl(struct file *filp, void *fh,
++ struct v4l2_control *a)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ int ret = 0;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ a->value = 90 * priv->rotation;
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static int at91sam9x5_video_vidioc_s_ctrl(struct file *filp, void *fh,
++ struct v4l2_control *a)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++ int ret;
++ unsigned long flags;
++
++ switch (a->id) {
++ case V4L2_CID_ROTATE:
++ if (a->value / 90 * 90 != a->value ||
++ (a->value / 90) % 4 != a->value / 90) {
++ ret = -EINVAL;
++ } else {
++ debug("rotation: %d\n", a->value);
++ spin_lock_irqsave(&priv->lock, flags);
++ priv->rotation = a->value / 90;
++ at91sam9x5_video_update_config(priv, 1);
++ spin_unlock_irqrestore(&priv->lock, flags);
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret;
++}
++
++static const struct v4l2_ioctl_ops at91sam9x5_video_ioctl_ops = {
++ .vidioc_querycap = at91sam9x5_video_vidioc_querycap,
++ .vidioc_g_fmt_vid_out = at91sam9x5_video_vidioc_g_fmt_vid_out,
++ .vidioc_s_fmt_vid_out = at91sam9x5_video_vidioc_s_fmt_vid_out,
++ .vidioc_g_fmt_vid_overlay = at91sam9x5_video_vidioc_g_fmt_vid_overlay,
++ .vidioc_s_fmt_vid_overlay = at91sam9x5_video_vidioc_s_fmt_vid_overlay,
++ .vidioc_enum_fmt_vid_out = at91sam9x5_video_vidioc_enum_fmt_vid_out,
++ .vidioc_reqbufs = at91sam9x5_video_vidioc_reqbufs,
++ .vidioc_querybuf = at91sam9x5_video_vidioc_querybuf,
++ .vidioc_qbuf = at91sam9x5_video_vidioc_qbuf,
++ .vidioc_dqbuf = at91sam9x5_video_vidioc_dqbuf,
++ .vidioc_streamon = at91sam9x5_video_vidioc_streamon,
++ .vidioc_streamoff = at91sam9x5_video_vidioc_streamoff,
++ .vidioc_queryctrl = at91sam9x5_video_vidioc_queryctrl,
++ .vidioc_g_ctrl = at91sam9x5_video_vidioc_g_ctrl,
++ .vidioc_s_ctrl = at91sam9x5_video_vidioc_s_ctrl,
++};
++
++static int at91sam9x5_video_open(struct file *filp)
++{
++ struct video_device *vdev = video_devdata(filp);
++
++ /*
++ * XXX: allow only one open? Or is that already enforced by the
++ * framework?
++ */
++ filp->private_data = vdev;
++
++ return 0;
++}
++
++static int at91sam9x5_video_release(struct file *filp)
++{
++ struct video_device *vdev = video_devdata(filp);
++
++ dev_dbg(&vdev->dev, "%s\n", __func__);
++
++ return 0;
++}
++
++static int at91sam9x5_video_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ struct video_device *vdev = video_devdata(filp);
++ struct at91sam9x5_video_priv *priv = video_get_drvdata(vdev);
++
++ dev_dbg(&vdev->dev, "%s\n", __func__);
++
++ /* returning -EIO here makes gst-launch segfault */
++ return vb2_mmap(&priv->queue, vma);
++}
++
++static struct v4l2_file_operations at91sam9x5_video_fops = {
++ .owner = THIS_MODULE,
++ .open = at91sam9x5_video_open,
++ .release = at91sam9x5_video_release,
++ .ioctl = video_ioctl2,
++ .mmap = at91sam9x5_video_mmap,
++};
++
++static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
++ struct fb_info *fbinfo)
++{
++ int ret = -ENOMEM;
++ struct platform_device *pdev = priv->pdev;
++ struct resource *res;
++ const struct at91sam9x5_video_pdata *pdata =
++ dev_get_platdata(&pdev->dev);
++ struct vb2_queue *q = &priv->queue;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ if (priv->fbinfo) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return -EBUSY;
++ }
++ priv->fbinfo = fbinfo;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ /* XXX: this doesn't belong here, does it? */
++ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
++
++ if (!pdata) {
++ dev_err(&pdev->dev, "failed to get platform data\n");
++ goto err_get_pdata;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "failed to get register base\n");
++ goto err_get_regbase;
++ }
++
++ priv->regbase = ioremap(res->start, resource_size(res));
++ if (!priv->regbase) {
++ dev_err(&pdev->dev, "failed to remap register base\n");
++ goto err_ioremap;
++ }
++
++ /*
++ * XXX: video_device_alloc is just a kzalloc, so embedding struct
++ * video_device into struct at91sam9x5_video_priv would work, too.
++ * Is that allowed?
++ */
++ priv->video_dev = video_device_alloc();
++ if (!priv->video_dev) {
++ dev_err(&pdev->dev, "failed to alloc video device for %p\n",
++ fbinfo);
++ goto err_video_device_alloc;
++ }
++
++ priv->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
++ if (IS_ERR(priv->alloc_ctx)) {
++ ret = PTR_ERR(priv->alloc_ctx);
++ dev_err(&pdev->dev, "failed to init alloc_ctx (%d)\n", ret);
++ goto err_init_ctx;
++ }
++
++ q->ops = &at91sam9x5_video_vb_ops;
++ q->mem_ops = &vb2_dma_contig_memops;
++ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
++
++ ret = vb2_queue_init(q);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to init queue (%d)\n", ret);
++ goto err_queue_init;
++ }
++
++ priv->video_dev->fops = &at91sam9x5_video_fops;
++ priv->video_dev->ioctl_ops = &at91sam9x5_video_ioctl_ops;
++ priv->video_dev->release = video_device_release;
++
++ video_set_drvdata(priv->video_dev, priv);
++
++ /* reset channel and clear status */
++ at91sam9x5_video_write32(priv, REG_HEOCHDR, REG_HEOCHDR_CHRST);
++ (void)at91sam9x5_video_read32(priv, REG_HEOISR);
++
++ /* set maximal bursting */
++ at91sam9x5_video_write32(priv, REG_HEOCFG0,
++ REG_HEOCFG0_BLEN_INCR16 |
++ REG_HEOCFG0_BLENUV_INCR16);
++
++ ret = platform_get_irq(pdev, 0);
++ if (ret <= 0) {
++ dev_err(&pdev->dev, "failed to get irq from resources (%d)\n",
++ ret);
++ if (!ret)
++ ret = -ENXIO;
++ goto err_get_irq;
++ }
++ priv->irq = ret;
++
++ ret = request_irq(priv->irq, at91sam9x5_video_irq, IRQF_SHARED,
++ DRIVER_NAME, priv);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
++ goto err_request_irq;
++ }
++
++ ret = video_register_device(priv->video_dev,
++ /* XXX: really grabber? */ VFL_TYPE_GRABBER, -1);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register video device (%d)\n",
++ ret);
++
++ free_irq(priv->irq, priv);
++ err_request_irq:
++ err_get_irq:
++
++ vb2_queue_release(q);
++err_queue_init:
++
++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
++ err_init_ctx:
++
++ video_device_release(priv->video_dev);
++ err_video_device_alloc:
++
++ iounmap(priv->regbase);
++
++ priv->fbinfo = NULL;
++ }
++ err_ioremap:
++ err_get_regbase:
++ err_get_pdata:
++
++ return ret;
++}
++
++static void at91sam9x5_video_unregister(struct at91sam9x5_video_priv *priv)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->lock, flags);
++
++ if (!priv->fbinfo) {
++ spin_unlock_irqrestore(&priv->lock, flags);
++ return;
++ }
++ /* XXX: handle fbinfo being NULL in various callbacks */
++ priv->fbinfo = NULL;
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ /* silence DMA */
++ at91sam9x5_video_write32(priv, REG_HEOIDR,
++ REG_HEOIxR_ADD | REG_HEOIxR_DMA | REG_HEOIxR_UADD |
++ REG_HEOIxR_UDMA | REG_HEOIxR_VADD | REG_HEOIxR_VDMA);
++
++ video_unregister_device(priv->video_dev);
++ free_irq(priv->irq, priv);
++ vb2_queue_release(&priv->queue);
++ vb2_dma_contig_cleanup_ctx(priv->alloc_ctx);
++ video_device_release(priv->video_dev);
++ iounmap(priv->regbase);
++}
++
++static int at91sam9x5_video_fb_event_notify(struct notifier_block *self,
++ unsigned long action, void *data)
++{
++ struct at91sam9x5_video_priv *priv =
++ container_of(self, struct at91sam9x5_video_priv, fb_notifier);
++ struct fb_event *event = data;
++ struct fb_info *fbinfo = event->info;
++
++ /* XXX: only do this for atmel_lcdfb devices! */
++ switch (action) {
++ case FB_EVENT_FB_REGISTERED:
++ at91sam9x5_video_register(priv, fbinfo);
++ break;
++
++ case FB_EVENT_FB_UNREGISTERED:
++ at91sam9x5_video_unregister(priv);
++ break;
++ }
++ return 0;
++}
++
++static int __devinit at91sam9x5_video_probe(struct platform_device *pdev)
++{
++ int ret = -ENOMEM;
++ size_t i;
++ struct at91sam9x5_video_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
++
++ if (!priv) {
++ dev_err(&pdev->dev, "failed to allocate driver private data\n");
++ goto err_alloc_priv;
++ }
++
++ priv->pdev = pdev;
++ priv->fb_notifier.notifier_call = at91sam9x5_video_fb_event_notify;
++
++ platform_set_drvdata(pdev, priv);
++
++ spin_lock_init(&priv->lock);
++
++ ret = fb_register_client(&priv->fb_notifier);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to register fb client (%d)\n", ret);
++
++ kfree(priv);
++err_alloc_priv:
++
++ return ret;
++ }
++
++ /* XXX: This is racy. If a new fb is registered then
++ * at91sam9x5_video_register is called twice. This should be solved
++ * somewhere in drivers/fb. priv->fbinfo is used to prevent multiple
++ * registration.
++ */
++
++ for (i = 0; i < ARRAY_SIZE(registered_fb); ++i)
++ if (registered_fb[i])
++ at91sam9x5_video_register(priv, registered_fb[i]);
++
++ return 0;
++}
++
++int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
++{
++ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
++
++ fb_unregister_client(&priv->fb_notifier);
++ at91sam9x5_video_unregister(priv);
++ kfree(priv);
++
++ return 0;
++}
++
++static struct platform_driver at91sam9x5_video_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = at91sam9x5_video_probe,
++ .remove = at91sam9x5_video_remove,
++};
++
++static struct platform_device *at91sam9x5_video_device;
++static int __init at91sam9x5_video_init(void)
++{
++ /* XXX: register the device in arch/arm/mach-at91 */
++ int ret;
++ const struct resource res[] = {
++ {
++ .start = 0xf8038280,
++ .end = 0xf803833f,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = 25,
++ .end = 25,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++ const struct at91sam9x5_video_pdata pdata = {
++ .base_width = 800,
++ .base_height = 480,
++ };
++
++ ret = platform_driver_register(&at91sam9x5_video_driver);
++ if (ret) {
++ pr_err("failed to register driver (%d)", ret);
++ goto err_driver_register;
++ }
++
++ at91sam9x5_video_device = platform_device_register_resndata(NULL,
++ DRIVER_NAME, -1,
++ res, ARRAY_SIZE(res), &pdata, sizeof(pdata));
++ if (IS_ERR(at91sam9x5_video_device)) {
++ ret = PTR_ERR(at91sam9x5_video_device);
++ pr_err("failed to register device (%d)", ret);
++ platform_driver_unregister(&at91sam9x5_video_driver);
++ }
++
++ err_driver_register:
++ return ret;
++}
++module_init(at91sam9x5_video_init);
++
++static void __exit at91sam9x5_video_exit(void)
++{
++ platform_device_unregister(at91sam9x5_video_device);
++ platform_driver_unregister(&at91sam9x5_video_driver);
++}
++module_exit(at91sam9x5_video_exit);
++
++MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
++MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From b50d6057cf77fe331626efe31cd1814f69e13747 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 24 Apr 2012 16:46:26 +0200
-Subject: mmc: atmel-mci: fix burst/chunk size modification
-
-The use of DMA slave config operation requires that the burst size
-(aka chunk size) is specified through this interface.
-Modify atmel-mci slave driver to use this specification on its side.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mmc/host/atmel-mci-regs.h | 14 ++++++++++++++
- drivers/mmc/host/atmel-mci.c | 8 +++++---
- 2 files changed, 19 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
-index 787aba1..ab56f7d 100644
---- a/drivers/mmc/host/atmel-mci-regs.h
-+++ b/drivers/mmc/host/atmel-mci-regs.h
-@@ -140,4 +140,18 @@
- #define atmci_writel(port,reg,value) \
- __raw_writel((value), (port)->regs + reg)
-
-+/*
-+ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
-+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
-+ *
-+ * This can be done by finding most significant bit set.
-+ */
-+static inline unsigned int atmci_convert_chksize(unsigned int maxburst)
-+{
-+ if (maxburst > 1)
-+ return fls(maxburst) - 2;
-+ else
-+ return 0;
-+}
-+
- #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 456c077..f2c115e 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -910,6 +910,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
- enum dma_data_direction direction;
- enum dma_transfer_direction slave_dirn;
- unsigned int sglen;
-+ u32 maxburst;
- u32 iflags;
-
- data->error = -EINPROGRESS;
-@@ -943,17 +944,18 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
- if (!chan)
- return -ENODEV;
-
-- if (host->caps.has_dma)
-- atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN);
--
- if (data->flags & MMC_DATA_READ) {
- direction = DMA_FROM_DEVICE;
- host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
-+ maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
- } else {
- direction = DMA_TO_DEVICE;
- host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
-+ maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
- }
-
-+ atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN);
-+
- sglen = dma_map_sg(chan->device->dev, data->sg,
- data->sg_len, direction);
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From abcc103a1d98b3b91596e068deef52032756cbfc Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 20 Mar 2012 18:41:48 +0100
-Subject: mmc: atmel-mci: add device tree support
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- .../devicetree/bindings/mmc/atmel-hsmci.txt | 67 +++++++++++++++++
- drivers/mmc/host/atmel-mci.c | 85 +++++++++++++++++++++-
- 2 files changed, 150 insertions(+), 2 deletions(-)
- create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
-
-diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
-new file mode 100644
-index 0000000..81c20cc
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
-@@ -0,0 +1,67 @@
-+* Atmel High Speed MultiMedia Card Interface
-+
-+This controller on atmel products provides an interface for MMC, SD and SDIO
-+types of memory cards.
-+
-+1) MCI node
-+
-+Required properties:
-+- compatible: no blank "atmel,hsmci"
-+- reg: should contain HSMCI registers location and length
-+- interrupts: should contain HSMCI interrupt number
-+- #address-cells: should be one. The cell is the slot id.
-+- #size-cells: should be zero.
-+- at least one slot node
-+
-+The node contains child nodes for each slot that the platform uses
-+
-+Example MCI node:
-+
-+mmc0: mmc@f0008000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xf0008000 0x600>;
-+ interrupts = <12 4>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ [ child node definitions...]
-+};
-+
-+2) slot nodes
-+
-+Required properties:
-+- reg: should contain the slot id.
-+- bus-width: number of data lines connected to the controller
-+
-+Optional properties:
-+- cd-gpios: specify GPIOs for card detection
-+- cd-inverted: invert the value of external card detect gpio line
-+- wp-gpios: specify GPIOs for write protection
-+
-+Example slot node:
-+
-+slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 15 0>
-+ cd-inverted;
-+};
-+
-+Example full MCI node:
-+mmc0: mmc@f0008000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xf0008000 0x600>;
-+ interrupts = <12 4>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 15 0>
-+ cd-inverted;
-+ };
-+ slot@1 {
-+ reg = <1>;
-+ bus-width = <4>;
-+ };
-+};
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index f2c115e..47421fc 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -19,6 +19,9 @@
- #include <linux/interrupt.h>
- #include <linux/ioport.h>
- #include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_gpio.h>
- #include <linux/platform_device.h>
- #include <linux/scatterlist.h>
- #include <linux/seq_file.h>
-@@ -493,6 +496,70 @@ err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
- }
-
-+#if defined(CONFIG_OF)
-+static const struct of_device_id atmci_dt_ids[] = {
-+ { .compatible = "atmel,hsmci" },
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, atmci_dt_ids);
-+
-+static struct mci_platform_data __devinit*
-+atmci_of_init(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct device_node *cnp;
-+ struct mci_platform_data *pdata;
-+ u32 slot_id;
-+
-+ if (!np) {
-+ dev_err(&pdev->dev, "device node not found\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-+ if (!pdata) {
-+ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ for_each_child_of_node(np, cnp) {
-+ if (of_property_read_u32(cnp, "reg", &slot_id)) {
-+ dev_warn(&pdev->dev, "reg property is missing for %s\n",
-+ cnp->full_name);
-+ continue;
-+ }
-+
-+ if (slot_id >= ATMCI_MAX_NR_SLOTS) {
-+ dev_warn(&pdev->dev, "can't have more than %d slots\n",
-+ ATMCI_MAX_NR_SLOTS);
-+ break;
-+ }
-+
-+ if (of_property_read_u32(cnp, "bus-width",
-+ &pdata->slot[slot_id].bus_width))
-+ pdata->slot[slot_id].bus_width = 1;
-+
-+ pdata->slot[slot_id].detect_pin =
-+ of_get_named_gpio(cnp, "cd-gpios", 0);
-+
-+ pdata->slot[slot_id].detect_is_active_high =
-+ of_property_read_bool(cnp, "cd-inverted");
-+
-+ pdata->slot[slot_id].wp_pin =
-+ of_get_named_gpio(cnp, "wp-gpios", 0);
-+ }
-+
-+ return pdata;
-+}
-+#else /* CONFIG_OF */
-+static inline struct mci_platform_data*
-+atmci_of_init(struct platform_device *dev)
-+{
-+ return ERR_PTR(-EINVAL);
-+}
-+#endif
-+
- static inline unsigned int atmci_get_version(struct atmel_mci *host)
- {
- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
-@@ -2038,6 +2105,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
- slot->sdc_reg = sdc_reg;
- slot->sdio_irq = sdio_irq;
-
-+ dev_dbg(&mmc->class_dev,
-+ "slot[%u]: bus_width=%u, detect_pin=%d, "
-+ "detect_is_active_high=%s, wp_pin=%d\n",
-+ id, slot_data->bus_width, slot_data->detect_pin,
-+ slot_data->detect_is_active_high ? "true" : "false",
-+ slot_data->wp_pin);
-+
- mmc->ops = &atmci_ops;
- mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
- mmc->f_max = host->bus_hz / 2;
-@@ -2258,8 +2332,14 @@ static int __init atmci_probe(struct platform_device *pdev)
- if (!regs)
- return -ENXIO;
- pdata = pdev->dev.platform_data;
-- if (!pdata)
-- return -ENXIO;
-+ if (!pdata) {
-+ pdata = atmci_of_init(pdev);
-+ if (IS_ERR(pdata)) {
-+ dev_err(&pdev->dev, "platform data not available\n");
-+ return PTR_ERR(pdata);
-+ }
-+ }
-+
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-@@ -2477,6 +2557,7 @@ static struct platform_driver atmci_driver = {
- .driver = {
- .name = "atmel_mci",
- .pm = ATMCI_PM_OPS,
-+ .of_match_table = of_match_ptr(atmci_dt_ids),
- },
- };
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 4518de39893c780fa549a88ee1d671c152c3b1a6 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 9 Oct 2012 18:23:51 +0200
+Subject: video: atmel_lcdfb*: protect bl_power with
+ CONFIG_BACKLIGHT_ATMEL_LCDC
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/video/atmel_hlcdfb.c | 24 +++++++++++++++++++-----
+ drivers/video/atmel_lcdfb.c | 24 +++++++++++++++++++-----
+ 2 files changed, 38 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index a629dda..db6ec3e 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -94,6 +94,7 @@ static void atmel_hlcdfb_update_dma_ovl(struct fb_info *info,
+ lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER1, LCDC_OVRCHER1_CHEN | LCDC_OVRCHER1_UPDATEEN);
+ }
+
++#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -133,17 +134,30 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
+ return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET;
+ }
+
+-static const struct backlight_ops atmel_hlcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+ static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
+ {
+ /* have some default contrast/backlight settings */
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, LCDC_LCDCFG6_PWMPOL |
+ (ATMEL_LCDC_CVAL_DEFAULT << LCDC_LCDCFG6_PWMCVAL_OFFSET));
+ }
++#else
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ return ATMEL_LCDC_CVAL_DEFAULT;
++}
++
++static void atmel_hlcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
++#endif
++
++static const struct backlight_ops atmel_hlcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
+
+ void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
+index 86e3e32..651c88f 100644
+--- a/drivers/video/atmel_lcdfb.c
++++ b/drivers/video/atmel_lcdfb.c
+@@ -86,6 +86,7 @@ static void atmel_lcdfb_update_dma(struct fb_info *info,
+ atmel_lcdfb_update_dma2d(sinfo, var);
+ }
+
++#if defined(CONFIG_BACKLIGHT_ATMEL_LCDC)
+ /* some bl->props field just changed */
+ static int atmel_bl_update_status(struct backlight_device *bl)
+ {
+@@ -123,11 +124,6 @@ static int atmel_bl_get_brightness(struct backlight_device *bl)
+ return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
+ }
+
+-static const struct backlight_ops atmel_lcdc_bl_ops = {
+- .update_status = atmel_bl_update_status,
+- .get_brightness = atmel_bl_get_brightness,
+-};
+-
+ static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
+ {
+ /* contrast pwm can be 'inverted' */
+@@ -138,6 +134,24 @@ static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo)
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ }
++#else
++static int atmel_bl_update_status(struct backlight_device *bl)
++{
++ return 0;
++}
++
++static int atmel_bl_get_brightness(struct backlight_device *bl)
++{
++ return ATMEL_LCDC_CVAL_DEFAULT;
++}
++
++static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) {}
++#endif
++
++static const struct backlight_ops atmel_lcdc_bl_ops = {
++ .update_status = atmel_bl_update_status,
++ .get_brightness = atmel_bl_get_brightness,
++};
+
+ void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
+ {
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From baff53548e8947d970076daf0f1322c9afdadd9f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:21:15 +0200
+Subject: ARM: at91/9x5: modify consistent DMA size
+
+update to 8M
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91sam9x5.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index c949dc7..7eb00c53 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -302,6 +302,7 @@ static void __init at91sam9x5_register_clocks(void)
+ static void __init at91sam9x5_map_io(void)
+ {
+ at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
++ init_consistent_dma_size(SZ_8M);
+ }
+
+ void __init at91sam9x5_initialize(void)
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 1061326519a35f8af1b07fff6f80b9f217bb8097 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 22 May 2012 11:38:26 +0200
-Subject: ARM: at91: add clocks for DT entries
-
-Add clocks to clock lookup table for DT entries.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/mach-at91/at91sam9260.c | 1 +
- arch/arm/mach-at91/at91sam9263.c | 2 ++
- arch/arm/mach-at91/at91sam9g45.c | 2 ++
- arch/arm/mach-at91/at91sam9n12.c | 1 +
- arch/arm/mach-at91/at91sam9x5.c | 2 ++
- 5 files changed, 8 insertions(+)
-
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index c644131..4696729 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -219,6 +219,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index 144ef5d..c82d521 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -210,6 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
- };
-
- static struct clk_lookup usart_clocks_lookups[] = {
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index 55d2959..f6d0eab 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -236,6 +236,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
-index 0849466..cce4e0f 100644
---- a/arch/arm/mach-at91/at91sam9n12.c
-+++ b/arch/arm/mach-at91/at91sam9n12.c
-@@ -168,6 +168,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
- CLKDEV_CON_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index 7eb00c53..796b3c0 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -225,6 +225,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
-+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
- CLKDEV_CON_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 5447e89571ef3242d7452e0d13051e27ceb31a07 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Thu, 24 May 2012 16:58:42 +0200
-Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel SOCs
-
-Add mci controller nodes to atmel SOCs.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-
-Conflicts:
-
- arch/arm/boot/dts/at91sam9260.dtsi
- arch/arm/boot/dts/at91sam9g45.dtsi
- arch/arm/boot/dts/at91sam9x5.dtsi
----
- arch/arm/boot/dts/at91sam9260.dtsi | 9 +++++++++
- arch/arm/boot/dts/at91sam9263.dtsi | 18 ++++++++++++++++++
- arch/arm/boot/dts/at91sam9g45.dtsi | 18 ++++++++++++++++++
- arch/arm/boot/dts/at91sam9n12.dtsi | 9 +++++++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 18 ++++++++++++++++++
- 5 files changed, 72 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index 12df8ca..1f2c7d0 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -201,6 +201,15 @@
- interrupts = <10 4 2>;
- status = "disabled";
- };
-+
-+ mmc0: mmc@fffa8000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xfffa800 0x600>;
-+ interrupts = <9 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 195019b..a76f6cd 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -185,6 +185,24 @@
- interrupts = <24 4 2>;
- status = "disabled";
- };
-+
-+ mmc0: mmc@fff80000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xfff80000 0x600>;
-+ interrupts = <10 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
-+ mmc1: mmc@fff84000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xfff84000 0x600>;
-+ interrupts = <11 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index 6a3ed54..4b833d4 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -205,6 +205,24 @@
- interrupts = <25 4 3>;
- status = "disabled";
- };
-+
-+ mmc0: mmc@fff80000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xfff80000 0x600>;
-+ interrupts = <11 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
-+ mmc1: mmc@fffd0000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xfffd0000 0x600>;
-+ interrupts = <29 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index ef9336a..aead257 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -82,6 +82,15 @@
- reg = <0xfffffe10 0x10>;
- };
-
-+ mmc0: mmc@f0008000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xf0008000 0x600>;
-+ interrupts = <12 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
- tcb0: timer@f8008000 {
- compatible = "atmel,at91sam9x5-tcb";
- reg = <0xf8008000 0x100>;
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index fc38d21..1be3df7 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -195,6 +195,24 @@
- interrupts = <27 4 3>;
- status = "disabled";
- };
-+
-+ mmc0: mmc@f0008000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xf0008000 0x600>;
-+ interrupts = <12 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
-+
-+ mmc1: mmc@f000c000 {
-+ compatible = "atmel,hsmci";
-+ reg = <0xf000c000 0x600>;
-+ interrupts = <26 4>;
-+ status = "disabled";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 4cb1b0adbd898531ca518f009a6086777d69cf0f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:23:00 +0200
+Subject: video: atmel_lcdfb: adapt to all IP configurations
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/include/mach/atmel_hlcdc.h | 3 +--
+ drivers/video/atmel_hlcdfb.c | 14 ++++++++++++--
+ 2 files changed, 13 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+index 738a853..71ccb96 100644
+--- a/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
++++ b/arch/arm/mach-at91/include/mach/atmel_hlcdc.h
+@@ -157,8 +157,7 @@
+ #define LCDC_LCDISR_BASE (0x1 << 8)
+ #define LCDC_LCDISR_OVR1 (0x1 << 9)
+ #define LCDC_LCDISR_OVR2 (0x1 << 10)
+-#define LCDC_LCDISR_HEO (0x1 << 10)
+-#define LCDC2_LCDISR_HEO (0x1 << 11)
++#define LCDC_LCDISR_HEO (0x1 << 11)
+ #define LCDC_LCDISR_HCR (0x1 << 12)
+ #define LCDC_LCDISR_PP (0x1 << 13)
+
+diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c
+index db6ec3e..262c15b 100644
+--- a/drivers/video/atmel_hlcdfb.c
++++ b/drivers/video/atmel_hlcdfb.c
+@@ -370,6 +370,16 @@ static int atmel_hlcdfb_setup_core_ovl(struct fb_info *info)
+ }
+ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ {
++ u32 hbpw, hfpw;
++
++ if (cpu_is_at91sam9x5()) {
++ hbpw = LCDC_LCDCFG3_HBPW;
++ hfpw = LCDC_LCDCFG3_HFPW;
++ } else {
++ hbpw = LCDC2_LCDCFG3_HBPW;
++ hfpw = LCDC2_LCDCFG3_HFPW;
++ }
++
+ /* Saturate vertical and horizontal timings at maximum values */
+ var->vsync_len = min_t(u32, var->vsync_len,
+ (LCDC_LCDCFG1_VSPW >> LCDC_LCDCFG1_VSPW_OFFSET) + 1);
+@@ -378,11 +388,11 @@ static void atmelfb_limit_screeninfo(struct fb_var_screeninfo *var)
+ var->lower_margin = min_t(u32, var->lower_margin,
+ LCDC_LCDCFG2_VBPW >> LCDC_LCDCFG2_VBPW_OFFSET);
+ var->right_margin = min_t(u32, var->right_margin,
+- (LCDC2_LCDCFG3_HBPW >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
++ (hbpw >> LCDC_LCDCFG3_HBPW_OFFSET) + 1);
+ var->hsync_len = min_t(u32, var->hsync_len,
+ (LCDC_LCDCFG1_HSPW >> LCDC_LCDCFG1_HSPW_OFFSET) + 1);
+ var->left_margin = min_t(u32, var->left_margin,
+- (LCDC2_LCDCFG3_HFPW >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
++ (hfpw >> LCDC_LCDCFG3_HFPW_OFFSET) + 1);
+
+ }
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From c8564440b52c2ad6a6adc3e826adc0c5dc7035af Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Thu, 24 May 2012 17:01:19 +0200
-Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel boards
-
-Add mci controller nodes to atmel boards.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- arch/arm/boot/dts/at91sam9263ek.dts | 10 ++++++++++
- arch/arm/boot/dts/at91sam9g20ek_2mmc.dts | 12 ++++++++++++
- arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 9 +++++++++
- arch/arm/boot/dts/at91sam9g25ek.dts | 18 ++++++++++++++++++
- arch/arm/boot/dts/at91sam9m10g45ek.dts | 19 +++++++++++++++++++
- arch/arm/boot/dts/at91sam9n12ek.dts | 9 +++++++++
- 6 files changed, 77 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
-index f86ac4b..05028ed 100644
---- a/arch/arm/boot/dts/at91sam9263ek.dts
-+++ b/arch/arm/boot/dts/at91sam9263ek.dts
-@@ -50,6 +50,16 @@
- atmel,vbus-gpio = <&pioA 25 0>;
- status = "okay";
- };
-+
-+ mmc0: mmc@fff80000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioE 18 0>;
-+ wp-gpios = <&pioE 19 0>;
-+ };
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
-index f1b2e14..684b229 100644
---- a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
-+++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
-@@ -12,6 +12,18 @@
- model = "Atmel at91sam9g20ek 2 mmc";
- compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
-
-+ ahb {
-+ apb{
-+ mmc0: mmc@fffa8000 {
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioC 2 0>;
-+ };
-+ };
-+ };
-+ };
-+
- leds {
- compatible = "gpio-leds";
-
-diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-index b06c0db..7da326a 100644
---- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-@@ -51,6 +51,15 @@
- atmel,vbus-gpio = <&pioC 5 0>;
- status = "okay";
- };
-+
-+ mmc0: mmc@fffa8000 {
-+ status = "okay";
-+ slot@1 {
-+ reg = <1>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioC 9 0>;
-+ };
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
-index 96514c1..4857e6c 100644
---- a/arch/arm/boot/dts/at91sam9g25ek.dts
-+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
-@@ -32,6 +32,24 @@
- phy-mode = "rmii";
- status = "okay";
- };
-+
-+ mmc0: mmc@f0008000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 15 0>;
-+ };
-+ };
-+
-+ mmc1: mmc@f000c000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 14 0>;
-+ };
-+ };
- };
-
- usb0: ohci@00600000 {
-diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-index a3633bd..7a7b571 100644
---- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
-+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-@@ -46,6 +46,25 @@
- phy-mode = "rmii";
- status = "okay";
- };
-+
-+ mmc0: mmc@fff80000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 10 0>;
-+ };
-+ };
-+
-+ mmc1: mmc@fffd0000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 11 0>;
-+ wp-gpios = <&pioD 29 0>;
-+ };
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
-index f4e43e3..44b42d9 100644
---- a/arch/arm/boot/dts/at91sam9n12ek.dts
-+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
-@@ -37,6 +37,15 @@
- dbgu: serial@fffff200 {
- status = "okay";
- };
-+
-+ mmc0: mmc@f0008000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioA 7 0>;
-+ };
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From b2453fc81b197e3fbcfebdc3be5509dcaea82f59 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:26:10 +0200
+Subject: media/at91sam9x5-video: cleanup modifications
+
+pdata not used: remove them for now: ease transition to DT
+one type, one static, and one debug message modifications
+
+Can we squashed in another patch...
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 26ce376..c83dad1 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -347,8 +347,7 @@ static irqreturn_t at91sam9x5_video_irq(int irq, void *data)
+ heoimr = at91sam9x5_video_read32(priv, REG_HEOIMR);
+ handled = at91sam9x5_video_handle_irqstat(priv);
+
+- debug("%x, HEOCHSR = %08x\n", handled,
+- at91sam9x5_video_read32(priv, REG_HEOCHSR));
++ debug("HEOIMR = 0x%08x, HEOCHSR = 0x%08x\n", heoimr, handled);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+@@ -475,7 +474,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ priv->next.plane_size[2] = priv->plane_size[2];
+ }
+
+-static int experimental;
++static bool experimental;
+ module_param(experimental, bool, 0644);
+ MODULE_PARM_DESC(experimental, "enable experimental features");
+
+@@ -1155,8 +1154,8 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
+ int ret = -ENOMEM;
+ struct platform_device *pdev = priv->pdev;
+ struct resource *res;
+- const struct at91sam9x5_video_pdata *pdata =
+- dev_get_platdata(&pdev->dev);
++ /*const struct at91sam9x5_video_pdata *pdata =
++ dev_get_platdata(&pdev->dev);*/
+ struct vb2_queue *q = &priv->queue;
+ unsigned long flags;
+
+@@ -1171,10 +1170,13 @@ static int at91sam9x5_video_register(struct at91sam9x5_video_priv *priv,
+ /* XXX: this doesn't belong here, does it? */
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
++ /* Not used for now */
++#if 0
+ if (!pdata) {
+ dev_err(&pdev->dev, "failed to get platform data\n");
+ goto err_get_pdata;
+ }
++#endif
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+@@ -1272,10 +1274,14 @@ err_queue_init:
+ iounmap(priv->regbase);
+
+ priv->fbinfo = NULL;
++ } else {
++ dev_info(&pdev->dev,
++ "video device registered @ 0x%08x, irq = %d\n",
++ (unsigned int)priv->regbase, priv->irq);
+ }
+ err_ioremap:
+ err_get_regbase:
+- err_get_pdata:
++/* err_get_pdata:*/
+
+ return ret;
+ }
+@@ -1369,7 +1375,7 @@ err_alloc_priv:
+ return 0;
+ }
+
+-int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
++static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
+ {
+ struct at91sam9x5_video_priv *priv = platform_get_drvdata(pdev);
+
+@@ -1386,7 +1392,7 @@ static struct platform_driver at91sam9x5_video_driver = {
+ .owner = THIS_MODULE,
+ },
+ .probe = at91sam9x5_video_probe,
+- .remove = at91sam9x5_video_remove,
++ .remove = __devexit_p(at91sam9x5_video_remove),
+ };
+
+ static struct platform_device *at91sam9x5_video_device;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From d97e93bccbd81a88c5c60553b1dca5d59f23aa08 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:29:45 +0200
+Subject: media/at91sam9x5-video: align DMA descriptors on 64 bits
+
+Needed for future revisions of the LCD ip
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 46 ++++++++++++++++++++--------------
+ 1 file changed, 27 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index c83dad1..9d7e6c5 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -375,7 +375,7 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ struct v4l2_pix_format *pix = &priv->fmt_vid_out_cur;
+ /* XXX: format dependant */
+ size_t offset_dmadesc = ALIGN(pix->width * pix->height +
+- ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 32);
++ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2, 64);
+ u32 *dmadesc = vaddr + offset_dmadesc;
+ u32 heocher;
+
+@@ -388,23 +388,30 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+ }
+
+ debug("vout=%ux%u, heocher=%08x\n", pix->width, pix->height, heocher);
++ debug("dmadesc @ 0x%08x\n", dmadesc);
++ debug("dmadesc u @ 0x%08x\n", &dmadesc[4]);
++ debug("dmadesc v @ 0x%08x\n", &dmadesc[8]);
+
+ dmadesc[0] = buffer + priv->y_offset;
+ dmadesc[1] = REG_HEOxCTRL_DFETCH;
+ dmadesc[2] = buffer + offset_dmadesc;
++ /* dmadesc[3] not used to align U plane descriptor */
+
+ if (priv->u_planeno >= 0) {
+- dmadesc[3] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
++ dmadesc[4] = vb2_dma_contig_plane_dma_addr(vb, priv->u_planeno) +
+ priv->u_offset;
+- dmadesc[4] = REG_HEOxCTRL_DFETCH;
+- dmadesc[5] = buffer + offset_dmadesc + 3 * 4;
++ dmadesc[5] = REG_HEOxCTRL_DFETCH;
++ /* link to physical address of this U descriptor */
++ dmadesc[6] = buffer + offset_dmadesc + 4 * 4;
+ }
++ /* dmadesc[7] not used to align V plane descriptor */
+
+ if (priv->v_planeno >= 0) {
+- dmadesc[6] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
++ dmadesc[8] = vb2_dma_contig_plane_dma_addr(vb, priv->v_planeno) +
+ priv->v_offset;
+- dmadesc[7] = REG_HEOxCTRL_DFETCH;
+- dmadesc[8] = buffer + offset_dmadesc + 6 * 4;
++ dmadesc[9] = REG_HEOxCTRL_DFETCH;
++ /* link to physical address of this V descriptor */
++ dmadesc[10] = buffer + offset_dmadesc + 8 * 4;
+ }
+
+
+@@ -415,11 +422,11 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+
+ if (priv->u_planeno >= 0)
+ at91sam9x5_video_write32(priv,
+- REG_HEOUHEAD, dmadesc[5]);
++ REG_HEOUHEAD, dmadesc[6]);
+
+ if (priv->v_planeno >= 0)
+ at91sam9x5_video_write32(priv,
+- REG_HEOVHEAD, dmadesc[8]);
++ REG_HEOVHEAD, dmadesc[10]);
+
+ at91sam9x5_video_write32(priv,
+ REG_HEOCHER, heocher | REG_HEOCHER_A2QEN);
+@@ -432,20 +439,20 @@ static void at91sam9x5_video_show_buf(struct at91sam9x5_video_priv *priv,
+
+ if (priv->u_planeno >= 0) {
+ at91sam9x5_video_write32(priv,
+- REG_HEOUADDR, dmadesc[3]);
++ REG_HEOUADDR, dmadesc[4]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOUCTRL, dmadesc[4]);
++ REG_HEOUCTRL, dmadesc[5]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOUNEXT, dmadesc[5]);
++ REG_HEOUNEXT, dmadesc[6]);
+ }
+
+ if (priv->v_planeno >= 0) {
+ at91sam9x5_video_write32(priv,
+- REG_HEOVADDR, dmadesc[6]);
++ REG_HEOVADDR, dmadesc[8]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOVCTRL, dmadesc[7]);
++ REG_HEOVCTRL, dmadesc[9]);
+ at91sam9x5_video_write32(priv,
+- REG_HEOVNEXT, dmadesc[8]);
++ REG_HEOVNEXT, dmadesc[10]);
+ }
+
+ at91sam9x5_video_write32(priv, REG_HEOCHER,
+@@ -713,14 +720,15 @@ static int at91sam9x5_video_vb_queue_setup(struct vb2_queue *q,
+ *num_planes = 1;
+
+ /*
+- * The last 9 (aligned) words are used for the 3 dma descriptors (3
+- * 32-bit words each). The additional 32 bits are for alignment.
++ * The last 9 (64 bits aligned) words are used for the 3 dma
++ * descriptors (3 * 32-bit words each).
++ * The additional 64 + 2 * 32 bits are for alignment.
+ * XXX: is that allowed and done right?
+ * XXX: format-dependant
+ */
+ sizes[0] = pix->width * pix->height +
+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
+- 10 * 32;
++ 9 * 32 + 128;
+ priv->plane_size[0] = sizes[0];
+
+ alloc_ctxs[0] = priv->alloc_ctx;
+@@ -787,7 +795,7 @@ static int at91sam9x5_video_vb_buf_prepare(struct vb2_buffer *vb)
+ /* XXX: format-dependant */
+ if (vb->v4l2_planes[0].length < pix->width * pix->height +
+ ALIGN(pix->width, 2) * ALIGN(pix->height, 2) / 2 +
+- 10 * 32)
++ 9 * 32 + 128)
+ return -EINVAL;
+
+ return 0;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 9149e1f9aea1ca2e58c803467ee43a345b5b6645 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 7 Jun 2012 10:54:33 +0200
-Subject: mmc: atmel-mci: remove not needed DMA capability test
-
-The test about DMA capability is not needed as it is
-performed in DMA-only functions: so remove it.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 47421fc..7d9812c 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -834,9 +834,8 @@ static void atmci_dma_complete(void *arg)
-
- dev_vdbg(&host->pdev->dev, "DMA complete\n");
-
-- if (host->caps.has_dma)
-- /* Disable DMA hardware handshaking on MCI */
-- atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
-+ /* Disable DMA hardware handshaking on MCI */
-+ atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
-
- atmci_dma_cleanup(host);
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 0de76cf9cfdc7f9285768b599e54fca430693623 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Wed, 14 Mar 2012 12:46:18 +0100
-Subject: ARM: at91/atmel-mci: remove unused setup_dma_addr() macro
-
-This macro is not used anymove in atmel-mci driver. It has been removed
-by a patch that was dealing with dw_dmac.c e2b35f3:
-(dmaengine/dw_dmac: Fix dw_dmac user drivers to adapt to slave_config changes)
-
-We are now using the dmaengine API to specify the slave DMA parameters:
-dmaengine_slave_config().
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Cc: Chris Ball <cjb@laptop.org>
-Cc: <linux-mmc@vger.kernel.org>
----
- arch/arm/mach-at91/include/mach/atmel-mci.h | 7 -------
- 1 file changed, 7 deletions(-)
-
-diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/arch/arm/mach-at91/include/mach/atmel-mci.h
-index 998cb0c..5d84fe3 100644
---- a/arch/arm/mach-at91/include/mach/atmel-mci.h
-+++ b/arch/arm/mach-at91/include/mach/atmel-mci.h
-@@ -14,11 +14,4 @@ struct mci_dma_data {
- #define slave_data_ptr(s) (&(s)->sdata)
- #define find_slave_dev(s) ((s)->sdata.dma_dev)
-
--#define setup_dma_addr(s, t, r) do { \
-- if (s) { \
-- (s)->sdata.tx_reg = (t); \
-- (s)->sdata.rx_reg = (r); \
-- } \
--} while (0)
--
- #endif /* __MACH_ATMEL_MCI_H */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 5ce36caa7629ccccf5ae2b7c35c578cc2bfedc3f Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:30:47 +0200
+Subject: media/at91sam9x5-video: change scaling factor calculation
+
+Useful for future revision of the HEO IP
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 36 ++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 9d7e6c5..1e5a0a7 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -518,6 +518,19 @@ static void at91sam9x5_video_params(unsigned width, unsigned height,
+ *tloffset = e[ro(0)];
+ }
+
++static void at91sam9x5_video_setup_scaling_coef(
++ struct at91sam9x5_video_priv *priv,
++ unsigned hwxmem_size, unsigned hwxsize,
++ unsigned hwymem_size, unsigned hwysize,
++ unsigned *xphidef, unsigned *yphidef) {}
++
++static void at91sam9x5_video_setup_scaling_factor(
++ unsigned hwmem_size, unsigned hwsize,
++ unsigned phidef, unsigned *factor)
++{
++ *factor = 1024 * hwmem_size / hwsize;
++}
++
+ static void at91sam9x5_video_update_config_real(
+ struct at91sam9x5_video_priv *priv)
+ {
+@@ -529,6 +542,9 @@ static void at91sam9x5_video_update_config_real(
+
+ unsigned hwxpos, hwypos, hwxsize, hwysize;
+ unsigned hwxmem_size, hwymem_size;
++ unsigned xphidef = 0;
++ unsigned yphidef = 0;
++ unsigned xfactor, yfactor;
+ s32 hwxstride, hwpstride;
+ s32 hwuvxstride, hwuvpstride;
+ s32 rotated_pixwidth, rotated_pixheight;
+@@ -600,12 +616,20 @@ static void at91sam9x5_video_update_config_real(
+ valtomask(hwxmem_size - 1, REG_HEOCFG4_XMEMSIZE) |
+ valtomask(hwymem_size - 1, REG_HEOCFG4_YMEMSIZE));
+
+- at91sam9x5_video_write32(priv, REG_HEOCFG13,
+- REG_HEOCFG13_SCALEN |
+- valtomask(1024 * hwxmem_size / hwxsize,
+- REG_HEOCFG13_XFACTOR) |
+- valtomask(1024 * hwymem_size / hwysize,
+- REG_HEOCFG13_YFACTOR));
++ at91sam9x5_video_setup_scaling_coef(priv,
++ hwxmem_size, hwxsize,
++ hwymem_size, hwysize,
++ &xphidef, &yphidef);
++
++ at91sam9x5_video_setup_scaling_factor(hwxmem_size - 1, hwxsize - 1,
++ xphidef, &xfactor);
++
++ at91sam9x5_video_setup_scaling_factor(hwymem_size - 1, hwysize - 1,
++ yphidef, &yfactor);
++
++ at91sam9x5_video_write32(priv, REG_HEOCFG13, REG_HEOCFG13_SCALEN
++ | valtomask(xfactor, REG_HEOCFG13_XFACTOR)
++ | valtomask(yfactor, REG_HEOCFG13_YFACTOR));
+
+ at91sam9x5_video_params(pix->width, pix->height, priv->rotation,
+ &hwxstride, &hwpstride, &priv->y_offset);
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From e189f537c714246294a5b552d4d8110fbabb4636 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 18:46:07 +0200
+Subject: media/at91sam9x5-video: add device tree support
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/media/video/at91sam9x5-video.c | 55 +++++++++++-----------------------
+ 1 file changed, 18 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/media/video/at91sam9x5-video.c b/drivers/media/video/at91sam9x5-video.c
+index 1e5a0a7..548aebc 100644
+--- a/drivers/media/video/at91sam9x5-video.c
++++ b/drivers/media/video/at91sam9x5-video.c
+@@ -21,6 +21,8 @@
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
+
+ #include <media/v4l2-common.h>
+ #include <media/v4l2-dev.h>
+@@ -1418,59 +1420,38 @@ static int __devexit at91sam9x5_video_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_heo_dt_ids[] = {
++ {
++ .compatible = "atmel,at91sam9x5-heo",
++ .data = (void *)0,
++ }, {
++ /* sentinel */
++ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_heo_dt_ids);
++#endif
++
+ static struct platform_driver at91sam9x5_video_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_heo_dt_ids),
+ },
+ .probe = at91sam9x5_video_probe,
+ .remove = __devexit_p(at91sam9x5_video_remove),
+ };
+
+-static struct platform_device *at91sam9x5_video_device;
+ static int __init at91sam9x5_video_init(void)
+ {
+- /* XXX: register the device in arch/arm/mach-at91 */
+- int ret;
+- const struct resource res[] = {
+- {
+- .start = 0xf8038280,
+- .end = 0xf803833f,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 25,
+- .end = 25,
+- .flags = IORESOURCE_IRQ,
+- },
+- };
+- const struct at91sam9x5_video_pdata pdata = {
+- .base_width = 800,
+- .base_height = 480,
+- };
+-
+- ret = platform_driver_register(&at91sam9x5_video_driver);
+- if (ret) {
+- pr_err("failed to register driver (%d)", ret);
+- goto err_driver_register;
+- }
+-
+- at91sam9x5_video_device = platform_device_register_resndata(NULL,
+- DRIVER_NAME, -1,
+- res, ARRAY_SIZE(res), &pdata, sizeof(pdata));
+- if (IS_ERR(at91sam9x5_video_device)) {
+- ret = PTR_ERR(at91sam9x5_video_device);
+- pr_err("failed to register device (%d)", ret);
+- platform_driver_unregister(&at91sam9x5_video_driver);
+- }
+-
+- err_driver_register:
+- return ret;
++ return platform_driver_probe(&at91sam9x5_video_driver,
++ &at91sam9x5_video_probe);
+ }
+ module_init(at91sam9x5_video_init);
+
+ static void __exit at91sam9x5_video_exit(void)
+ {
+- platform_device_unregister(at91sam9x5_video_device);
+ platform_driver_unregister(&at91sam9x5_video_driver);
+ }
+ module_exit(at91sam9x5_video_exit);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From a9f7179d7975807f1f56be9d94495c8ac4bc1b53 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Thu, 15 Mar 2012 14:28:58 +0100
-Subject: mmc: atmel-mci: remove the need for CONFIG_MMC_ATMELMCI_DMA
-
-This Kconfig option is not needed anymore, so remove it.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-
-Conflicts:
-
- drivers/mmc/host/Kconfig
----
- drivers/mmc/host/Kconfig | 10 ----------
- drivers/mmc/host/atmel-mci.c | 2 --
- 2 files changed, 12 deletions(-)
-
-diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
-index 2bc06e7..dbdd907 100644
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -297,16 +297,6 @@ config MMC_ATMELMCI
-
- endchoice
-
--config MMC_ATMELMCI_DMA
-- bool "Atmel MCI DMA support"
-- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
-- help
-- Say Y here to have the Atmel MCI driver use a DMA engine to
-- do data transfers and thus increase the throughput and
-- reduce the CPU utilization.
--
-- If unsure, say N.
--
- config MMC_IMX
- tristate "Motorola i.MX Multimedia Card Interface support"
- depends on ARCH_MX1
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 7d9812c..cc81ef8 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -2476,10 +2476,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
- atmci_readl(host, ATMCI_SR);
- clk_disable(host->mck);
-
--#ifdef CONFIG_MMC_ATMELMCI_DMA
- if (host->dma.chan)
- dma_release_channel(host->dma.chan);
--#endif
-
- free_irq(platform_get_irq(pdev, 0), host);
- iounmap(host->regs);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 0b97e71038029ad93c9acb1ee992de536c236226 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 18 Jun 2012 14:14:57 +0200
+Subject: ARM: at91/video: Atmel HLCD is only selected by newer products
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/Kconfig | 4 ++--
+ drivers/video/Kconfig | 5 ++++-
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
+index c8050b1..79d08ed 100644
+--- a/arch/arm/mach-at91/Kconfig
++++ b/arch/arm/mach-at91/Kconfig
+@@ -86,7 +86,7 @@ config SOC_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+- select HAVE_FB_ATMEL
++ select HAVE_FB_ATMEL_HLCD
+ select HAVE_NET_MACB
+ help
+ Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
+@@ -99,7 +99,7 @@ config SOC_AT91SAM9N12
+ bool "AT91SAM9N12 family"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
+- select HAVE_FB_ATMEL
++ select HAVE_FB_ATMEL_HLCD
+ help
+ Select this if you are using Atmel's AT91SAM9N12 SoC.
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index ceccaa3..0928c36 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -8,6 +8,9 @@ menu "Graphics support"
+ config HAVE_FB_ATMEL
+ bool
+
++config HAVE_FB_ATMEL_HLCD
++ bool
++
+ config SH_MIPI_DSI
+ tristate
+ depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+@@ -1030,7 +1033,7 @@ config FB_ATMEL_STN
+
+ config FB_ATMEL_HLCD
+ tristate "AT91 HLCD Controller support"
+- depends on FB && HAVE_FB_ATMEL
++ depends on FB && HAVE_FB_ATMEL_HLCD
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 426627d4be46a018b2ed24272befcfb64eea04c6 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 22 Jun 2012 16:41:08 +0200
-Subject: ARM: dts: fix add mmc irq priority
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- arch/arm/boot/dts/at91sam9260.dtsi | 2 +-
- arch/arm/boot/dts/at91sam9263.dtsi | 4 ++--
- arch/arm/boot/dts/at91sam9g45.dtsi | 4 ++--
- arch/arm/boot/dts/at91sam9n12.dtsi | 2 +-
- arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++--
- 5 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index 1f2c7d0..8d95e83c 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -205,7 +205,7 @@
- mmc0: mmc@fffa8000 {
- compatible = "atmel,hsmci";
- reg = <0xfffa800 0x600>;
-- interrupts = <9 4>;
-+ interrupts = <9 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index a76f6cd..54e6984 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -189,7 +189,7 @@
- mmc0: mmc@fff80000 {
- compatible = "atmel,hsmci";
- reg = <0xfff80000 0x600>;
-- interrupts = <10 4>;
-+ interrupts = <10 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-@@ -198,7 +198,7 @@
- mmc1: mmc@fff84000 {
- compatible = "atmel,hsmci";
- reg = <0xfff84000 0x600>;
-- interrupts = <11 4>;
-+ interrupts = <11 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index 4b833d4..da135f9 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -209,7 +209,7 @@
- mmc0: mmc@fff80000 {
- compatible = "atmel,hsmci";
- reg = <0xfff80000 0x600>;
-- interrupts = <11 4>;
-+ interrupts = <11 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-@@ -218,7 +218,7 @@
- mmc1: mmc@fffd0000 {
- compatible = "atmel,hsmci";
- reg = <0xfffd0000 0x600>;
-- interrupts = <29 4>;
-+ interrupts = <29 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index aead257..42d5fc2 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -85,7 +85,7 @@
- mmc0: mmc@f0008000 {
- compatible = "atmel,hsmci";
- reg = <0xf0008000 0x600>;
-- interrupts = <12 4>;
-+ interrupts = <12 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 1be3df7..ad7016a 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -199,7 +199,7 @@
- mmc0: mmc@f0008000 {
- compatible = "atmel,hsmci";
- reg = <0xf0008000 0x600>;
-- interrupts = <12 4>;
-+ interrupts = <12 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-@@ -208,7 +208,7 @@
- mmc1: mmc@f000c000 {
- compatible = "atmel,hsmci";
- reg = <0xf000c000 0x600>;
-- interrupts = <26 4>;
-+ interrupts = <26 4 0>;
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 5269cb6e428f2d3678304517ec43d9fd0982d05b Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 6 Sep 2011 17:49:35 +0200
-Subject: mmc: atmel-mci: support 8-bit buswidth
-
-This patch adds support for 8-bit buswidth.
-Relevant SDCR value modified.
-
-Derived from a patch by Jaehoon Chung on dw_mmc.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index cc81ef8..b626d1e 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -1261,6 +1261,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
- case MMC_BUS_WIDTH_4:
- slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
- break;
-+ case MMC_BUS_WIDTH_8:
-+ slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
-+ break;
- }
-
- if (ios->clock) {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2a9a4fc2e8860de7266d5b5c6624865b7647c17c Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:25:58 +0200
+Subject: mmc: atmel-mci: the r/w proof capability lack was not well managed
+
+commit 7a90dcc2d7ceb64bb37044a8d2ee462b936ddf73 upstream.
+
+First mci IPs (mainly on rm9200 and 9261) don't have the r/w proof
+capability. The driver didn't work correctly without this capability
+in PDC mode because of the double buffer switch which is too slow
+even if we stop the transfer to perform this switch.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 92 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 78 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index e94476b..6f56ef0 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -91,6 +91,11 @@ struct atmel_mci_dma {
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO or PDC code.
+ * @pio_offset: Offset into the current scatterlist entry.
++ * @buffer: Buffer used if we don't have the r/w proof capability. We
++ * don't have the time to switch pdc buffers so we have to use only
++ * one buffer for the full transaction.
++ * @buf_size: size of the buffer.
++ * @phys_buf_addr: buffer address needed for pdc.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ * or NULL if the controller is idle.
+@@ -166,6 +171,9 @@ struct atmel_mci {
+
+ struct scatterlist *sg;
+ unsigned int pio_offset;
++ unsigned int *buffer;
++ unsigned int buf_size;
++ dma_addr_t buf_phys_addr;
+
+ struct atmel_mci_slot *cur_slot;
+ struct mmc_request *mrq;
+@@ -480,6 +488,11 @@ err:
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ }
+
++static inline unsigned int atmci_get_version(struct atmel_mci *host)
++{
++ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
++}
++
+ static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
+ unsigned int ns)
+ {
+@@ -603,6 +616,7 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
+ enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
+ {
+ u32 pointer_reg, counter_reg;
++ unsigned int buf_size;
+
+ if (dir == XFER_RECEIVE) {
+ pointer_reg = ATMEL_PDC_RPR;
+@@ -617,8 +631,15 @@ static void atmci_pdc_set_single_buf(struct atmel_mci *host,
+ counter_reg += ATMEL_PDC_SCND_BUF_OFF;
+ }
+
+- atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
+- if (host->data_size <= sg_dma_len(host->sg)) {
++ if (!host->caps.has_rwproof) {
++ buf_size = host->buf_size;
++ atmci_writel(host, pointer_reg, host->buf_phys_addr);
++ } else {
++ buf_size = sg_dma_len(host->sg);
++ atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
++ }
++
++ if (host->data_size <= buf_size) {
+ if (host->data_size & 0x3) {
+ /* If size is different from modulo 4, transfer bytes */
+ atmci_writel(host, counter_reg, host->data_size);
+@@ -670,7 +691,15 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
+ */
+ static void atmci_pdc_complete(struct atmel_mci *host)
+ {
++ int transfer_size = host->data->blocks * host->data->blksz;
++
+ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
++
++ if ((!host->caps.has_rwproof)
++ && (host->data->flags & MMC_DATA_READ))
++ sg_copy_from_buffer(host->data->sg, host->data->sg_len,
++ host->buffer, transfer_size);
++
+ atmci_pdc_cleanup(host);
+
+ /*
+@@ -818,6 +847,12 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ /* Configure PDC */
+ host->data_size = data->blocks * data->blksz;
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
++
++ if ((!host->caps.has_rwproof)
++ && (host->data->flags & MMC_DATA_WRITE))
++ sg_copy_to_buffer(host->data->sg, host->data->sg_len,
++ host->buffer, host->data_size);
++
+ if (host->data_size)
+ atmci_pdc_set_both_buf(host,
+ ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
+@@ -1877,13 +1912,26 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ if (host->caps.has_highspeed)
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+- if (slot_data->bus_width >= 4)
++ /*
++ * Without the read/write proof capability, it is strongly suggested to
++ * use only one bit for data to prevent fifo underruns and overruns
++ * which will corrupt data.
++ */
++ if ((slot_data->bus_width >= 4) && host->caps.has_rwproof)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+- mmc->max_segs = 64;
+- mmc->max_req_size = 32768 * 512;
+- mmc->max_blk_size = 32768;
+- mmc->max_blk_count = 512;
++ if (atmci_get_version(host) < 0x200) {
++ mmc->max_segs = 256;
++ mmc->max_blk_size = 4095;
++ mmc->max_blk_count = 256;
++ mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
++ mmc->max_seg_size = mmc->max_blk_size * mmc->max_segs;
++ } else {
++ mmc->max_segs = 64;
++ mmc->max_req_size = 32768 * 512;
++ mmc->max_blk_size = 32768;
++ mmc->max_blk_count = 512;
++ }
+
+ /* Assume card is present initially */
+ set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+@@ -2007,11 +2055,6 @@ static bool atmci_configure_dma(struct atmel_mci *host)
+ }
+ }
+
+-static inline unsigned int atmci_get_version(struct atmel_mci *host)
+-{
+- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+-}
+-
+ /*
+ * HSMCI (High Speed MCI) module is not fully compatible with MCI module.
+ * HSMCI provides DMA support and a new config register but no more supports
+@@ -2138,14 +2181,20 @@ static int __init atmci_probe(struct platform_device *pdev)
+ if (pdata->slot[0].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[0],
+ 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
+- if (!ret)
++ if (!ret) {
+ nr_slots++;
++ host->buf_size = host->slot[0]->mmc->max_req_size;
++ }
+ }
+ if (pdata->slot[1].bus_width) {
+ ret = atmci_init_slot(host, &pdata->slot[1],
+ 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
+- if (!ret)
++ if (!ret) {
+ nr_slots++;
++ if (host->slot[1]->mmc->max_req_size > host->buf_size)
++ host->buf_size =
++ host->slot[1]->mmc->max_req_size;
++ }
+ }
+
+ if (!nr_slots) {
+@@ -2153,6 +2202,17 @@ static int __init atmci_probe(struct platform_device *pdev)
+ goto err_init_slot;
+ }
+
++ if (!host->caps.has_rwproof) {
++ host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
++ &host->buf_phys_addr,
++ GFP_KERNEL);
++ if (!host->buffer) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "buffer allocation failed\n");
++ goto err_init_slot;
++ }
++ }
++
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+@@ -2179,6 +2239,10 @@ static int __exit atmci_remove(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, NULL);
+
++ if (host->buffer)
++ dma_free_coherent(&pdev->dev, host->buf_size,
++ host->buffer, host->buf_phys_addr);
++
+ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+ if (host->slot[i])
+ atmci_cleanup_slot(host->slot[i], i);
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 6ab65f30491092a6dc2fadf895ff4b1dbe95566b Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:25:59 +0200
+Subject: mmc: atmel-mci: change the state machine for compatibility with old
+ IP
+
+commit f51775471ac6155d3bb8494dcb5c0a13a84f611e upstream.
+
+The state machine use in atmel-mci can't work with old IP versions
+(< 0x200). This patch allows to have a common state machine for all
+versions in order to remove at91-mci driver only used for old versions.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 278 +++++++++++++++++++++++++------------------
+ 1 file changed, 162 insertions(+), 116 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 6f56ef0..1baaaebb 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -45,19 +45,19 @@
+ #define ATMCI_DMA_THRESHOLD 16
+
+ enum {
+- EVENT_CMD_COMPLETE = 0,
++ EVENT_CMD_RDY = 0,
+ EVENT_XFER_COMPLETE,
+- EVENT_DATA_COMPLETE,
++ EVENT_NOTBUSY,
+ EVENT_DATA_ERROR,
+ };
+
+ enum atmel_mci_state {
+ STATE_IDLE = 0,
+ STATE_SENDING_CMD,
+- STATE_SENDING_DATA,
+- STATE_DATA_BUSY,
++ STATE_DATA_XFER,
++ STATE_WAITING_NOTBUSY,
+ STATE_SENDING_STOP,
+- STATE_DATA_ERROR,
++ STATE_END_REQUEST,
+ };
+
+ enum atmci_xfer_dir {
+@@ -709,7 +709,6 @@ static void atmci_pdc_complete(struct atmel_mci *host)
+ if (host->data) {
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+ }
+
+@@ -835,7 +834,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
+ } else {
+ dir = DMA_TO_DEVICE;
+- iflags |= ATMCI_ENDTX | ATMCI_TXBUFE;
++ iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
+ }
+
+ /* Set BLKLEN */
+@@ -975,8 +974,7 @@ static void atmci_stop_transfer(struct atmel_mci *host)
+ */
+ static void atmci_stop_transfer_pdc(struct atmel_mci *host)
+ {
+- atmci_set_pending(host, EVENT_XFER_COMPLETE);
+- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+ }
+
+ static void atmci_stop_transfer_dma(struct atmel_mci *host)
+@@ -1012,6 +1010,7 @@ static void atmci_start_request(struct atmel_mci *host,
+
+ host->pending_events = 0;
+ host->completed_events = 0;
++ host->cmd_status = 0;
+ host->data_status = 0;
+
+ if (host->need_reset) {
+@@ -1029,7 +1028,7 @@ static void atmci_start_request(struct atmel_mci *host,
+
+ iflags = atmci_readl(host, ATMCI_IMR);
+ if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
+- dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
++ dev_dbg(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+ iflags);
+
+ if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+@@ -1367,19 +1366,6 @@ static void atmci_command_complete(struct atmel_mci *host,
+ cmd->error = -EIO;
+ else
+ cmd->error = 0;
+-
+- if (cmd->error) {
+- dev_dbg(&host->pdev->dev,
+- "command error: status=0x%08x\n", status);
+-
+- if (cmd->data) {
+- host->stop_transfer(host);
+- host->data = NULL;
+- atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY
+- | ATMCI_TXRDY | ATMCI_RXRDY
+- | ATMCI_DATA_ERROR_FLAGS);
+- }
+- }
+ }
+
+ static void atmci_detect_change(unsigned long data)
+@@ -1442,23 +1428,21 @@ static void atmci_detect_change(unsigned long data)
+ break;
+ case STATE_SENDING_CMD:
+ mrq->cmd->error = -ENOMEDIUM;
+- if (!mrq->data)
+- break;
+- /* fall through */
+- case STATE_SENDING_DATA:
++ if (mrq->data)
++ host->stop_transfer(host);
++ break;
++ case STATE_DATA_XFER:
+ mrq->data->error = -ENOMEDIUM;
+ host->stop_transfer(host);
+ break;
+- case STATE_DATA_BUSY:
+- case STATE_DATA_ERROR:
+- if (mrq->data->error == -EINPROGRESS)
+- mrq->data->error = -ENOMEDIUM;
+- if (!mrq->stop)
+- break;
+- /* fall through */
++ case STATE_WAITING_NOTBUSY:
++ mrq->data->error = -ENOMEDIUM;
++ break;
+ case STATE_SENDING_STOP:
+ mrq->stop->error = -ENOMEDIUM;
+ break;
++ case STATE_END_REQUEST:
++ break;
+ }
+
+ atmci_request_end(host, mrq);
+@@ -1486,7 +1470,6 @@ static void atmci_tasklet_func(unsigned long priv)
+ struct atmel_mci *host = (struct atmel_mci *)priv;
+ struct mmc_request *mrq = host->mrq;
+ struct mmc_data *data = host->data;
+- struct mmc_command *cmd = host->cmd;
+ enum atmel_mci_state state = host->state;
+ enum atmel_mci_state prev_state;
+ u32 status;
+@@ -1508,101 +1491,164 @@ static void atmci_tasklet_func(unsigned long priv)
+ break;
+
+ case STATE_SENDING_CMD:
++ /*
++ * Command has been sent, we are waiting for command
++ * ready. Then we have three next states possible:
++ * END_REQUEST by default, WAITING_NOTBUSY if it's a
++ * command needing it or DATA_XFER if there is data.
++ */
+ if (!atmci_test_and_clear_pending(host,
+- EVENT_CMD_COMPLETE))
++ EVENT_CMD_RDY))
+ break;
+
+ host->cmd = NULL;
+- atmci_set_completed(host, EVENT_CMD_COMPLETE);
++ atmci_set_completed(host, EVENT_CMD_RDY);
+ atmci_command_complete(host, mrq->cmd);
+- if (!mrq->data || cmd->error) {
+- atmci_request_end(host, host->mrq);
+- goto unlock;
+- }
++ if (mrq->data) {
++ /*
++ * If there is a command error don't start
++ * data transfer.
++ */
++ if (mrq->cmd->error) {
++ host->stop_transfer(host);
++ host->data = NULL;
++ atmci_writel(host, ATMCI_IDR,
++ ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
++ } else
++ state = STATE_DATA_XFER;
++ } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ } else
++ state = STATE_END_REQUEST;
+
+- prev_state = state = STATE_SENDING_DATA;
+- /* fall through */
++ break;
+
+- case STATE_SENDING_DATA:
++ case STATE_DATA_XFER:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
+- host->stop_transfer(host);
+- if (data->stop)
+- atmci_send_stop_cmd(host, data);
+- state = STATE_DATA_ERROR;
++ atmci_set_completed(host, EVENT_DATA_ERROR);
++ state = STATE_END_REQUEST;
+ break;
+ }
+
++ /*
++ * A data transfer is in progress. The event expected
++ * to move to the next state depends of data transfer
++ * type (PDC or DMA). Once transfer done we can move
++ * to the next step which is WAITING_NOTBUSY in write
++ * case and directly SENDING_STOP in read case.
++ */
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+- prev_state = state = STATE_DATA_BUSY;
+- /* fall through */
+
+- case STATE_DATA_BUSY:
+- if (!atmci_test_and_clear_pending(host,
+- EVENT_DATA_COMPLETE))
+- break;
+-
+- host->data = NULL;
+- atmci_set_completed(host, EVENT_DATA_COMPLETE);
+- status = host->data_status;
+- if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+- if (status & ATMCI_DTOE) {
+- dev_dbg(&host->pdev->dev,
+- "data timeout error\n");
+- data->error = -ETIMEDOUT;
+- } else if (status & ATMCI_DCRCE) {
+- dev_dbg(&host->pdev->dev,
+- "data CRC error\n");
+- data->error = -EILSEQ;
+- } else {
+- dev_dbg(&host->pdev->dev,
+- "data FIFO error (status=%08x)\n",
+- status);
+- data->error = -EIO;
+- }
++ if (host->data->flags & MMC_DATA_WRITE) {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ } else if (host->mrq->stop) {
++ atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
++ atmci_send_stop_cmd(host, data);
++ state = STATE_SENDING_STOP;
+ } else {
++ host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
+ }
++ break;
+
+- if (!data->stop) {
+- atmci_request_end(host, host->mrq);
+- goto unlock;
+- }
++ case STATE_WAITING_NOTBUSY:
++ /*
++ * We can be in the state for two reasons: a command
++ * requiring waiting not busy signal (stop command
++ * included) or a write operation. In the latest case,
++ * we need to send a stop command.
++ */
++ if (!atmci_test_and_clear_pending(host,
++ EVENT_NOTBUSY))
++ break;
+
+- prev_state = state = STATE_SENDING_STOP;
+- if (!data->error)
+- atmci_send_stop_cmd(host, data);
+- /* fall through */
++ atmci_set_completed(host, EVENT_NOTBUSY);
++
++ if (host->data) {
++ /*
++ * For some commands such as CMD53, even if
++ * there is data transfer, there is no stop
++ * command to send.
++ */
++ if (host->mrq->stop) {
++ atmci_writel(host, ATMCI_IER,
++ ATMCI_CMDRDY);
++ atmci_send_stop_cmd(host, data);
++ state = STATE_SENDING_STOP;
++ } else {
++ host->data = NULL;
++ data->bytes_xfered = data->blocks
++ * data->blksz;
++ data->error = 0;
++ state = STATE_END_REQUEST;
++ }
++ } else
++ state = STATE_END_REQUEST;
++ break;
+
+ case STATE_SENDING_STOP:
++ /*
++ * In this state, it is important to set host->data to
++ * NULL (which is tested in the waiting notbusy state)
++ * in order to go to the end request state instead of
++ * sending stop again.
++ */
+ if (!atmci_test_and_clear_pending(host,
+- EVENT_CMD_COMPLETE))
++ EVENT_CMD_RDY))
+ break;
+
+ host->cmd = NULL;
++ host->data = NULL;
++ data->bytes_xfered = data->blocks * data->blksz;
++ data->error = 0;
+ atmci_command_complete(host, mrq->stop);
+- atmci_request_end(host, host->mrq);
+- goto unlock;
++ if (mrq->stop->error) {
++ host->stop_transfer(host);
++ atmci_writel(host, ATMCI_IDR,
++ ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ state = STATE_END_REQUEST;
++ } else {
++ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
++ state = STATE_WAITING_NOTBUSY;
++ }
++ break;
+
+- case STATE_DATA_ERROR:
+- if (!atmci_test_and_clear_pending(host,
+- EVENT_XFER_COMPLETE))
+- break;
++ case STATE_END_REQUEST:
++ atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY | ATMCI_RXRDY
++ | ATMCI_DATA_ERROR_FLAGS);
++ status = host->data_status;
++ if (unlikely(status)) {
++ host->stop_transfer(host);
++ host->data = NULL;
++ if (status & ATMCI_DTOE) {
++ data->error = -ETIMEDOUT;
++ } else if (status & ATMCI_DCRCE) {
++ data->error = -EILSEQ;
++ } else {
++ data->error = -EIO;
++ }
++ }
+
+- state = STATE_DATA_BUSY;
++ atmci_request_end(host, host->mrq);
++ state = STATE_IDLE;
+ break;
+ }
+ } while (state != prev_state);
+
+ host->state = state;
+
+-unlock:
+ spin_unlock(&host->lock);
+ }
+
+@@ -1655,9 +1701,6 @@ static void atmci_read_data_pio(struct atmel_mci *host)
+ | ATMCI_DATA_ERROR_FLAGS));
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_ERROR);
+- tasklet_schedule(&host->tasklet);
+ return;
+ }
+ } while (status & ATMCI_RXRDY);
+@@ -1726,9 +1769,6 @@ static void atmci_write_data_pio(struct atmel_mci *host)
+ | ATMCI_DATA_ERROR_FLAGS));
+ host->data_status = status;
+ data->bytes_xfered += nbytes;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_ERROR);
+- tasklet_schedule(&host->tasklet);
+ return;
+ }
+ } while (status & ATMCI_TXRDY);
+@@ -1746,16 +1786,6 @@ done:
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ }
+
+-static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
+-{
+- atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
+-
+- host->cmd_status = status;
+- smp_wmb();
+- atmci_set_pending(host, EVENT_CMD_COMPLETE);
+- tasklet_schedule(&host->tasklet);
+-}
+-
+ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
+ {
+ int i;
+@@ -1784,8 +1814,9 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+
+ if (pending & ATMCI_DATA_ERROR_FLAGS) {
+ atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
+- | ATMCI_RXRDY | ATMCI_TXRDY);
+- pending &= atmci_readl(host, ATMCI_IMR);
++ | ATMCI_RXRDY | ATMCI_TXRDY
++ | ATMCI_ENDRX | ATMCI_ENDTX
++ | ATMCI_RXBUFF | ATMCI_TXBUFE);
+
+ host->data_status = status;
+ smp_wmb();
+@@ -1843,23 +1874,38 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ }
+ }
+
++ /*
++ * First mci IPs, so mainly the ones having pdc, have some
++ * issues with the notbusy signal. You can't get it after
++ * data transmission if you have not sent a stop command.
++ * The appropriate workaround is to use the BLKE signal.
++ */
++ if (pending & ATMCI_BLKE) {
++ atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
++ smp_wmb();
++ atmci_set_pending(host, EVENT_NOTBUSY);
++ tasklet_schedule(&host->tasklet);
++ }
+
+ if (pending & ATMCI_NOTBUSY) {
+- atmci_writel(host, ATMCI_IDR,
+- ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY);
+- if (!host->data_status)
+- host->data_status = status;
++ atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
+ smp_wmb();
+- atmci_set_pending(host, EVENT_DATA_COMPLETE);
++ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
++
+ if (pending & ATMCI_RXRDY)
+ atmci_read_data_pio(host);
+ if (pending & ATMCI_TXRDY)
+ atmci_write_data_pio(host);
+
+- if (pending & ATMCI_CMDRDY)
+- atmci_cmd_interrupt(host, status);
++ if (pending & ATMCI_CMDRDY) {
++ atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
++ host->cmd_status = status;
++ smp_wmb();
++ atmci_set_pending(host, EVENT_CMD_RDY);
++ tasklet_schedule(&host->tasklet);
++ }
+
+ if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
+ atmci_sdio_interrupt(host, status);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From fe76a21fcd710c2e3da0072676d7d01b23247a24 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Fri, 6 Jul 2012 11:49:05 +0200
-Subject: mmc: atmel-mci: fix incorrect setting of host->data to NULL
-
-Setting host->data to NULL is incorrect sequence in STATE_SENDING_STOP
-state of FSM: This early setting leads to the skip of dma_unmap_sg()
-in atmci_dma_cleanup() which is a bug.
-
-Idea taken form dw_mmc by Seungwon Jeon.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Cc: Seungwon Jeon <tgih.jun@samsung.com>
----
- drivers/mmc/host/atmel-mci.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index b626d1e..90df83b 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -1754,7 +1754,6 @@ static void atmci_tasklet_func(unsigned long priv)
-
- dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
- host->cmd = NULL;
-- host->data = NULL;
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
- atmci_command_complete(host, mrq->stop);
-@@ -1768,6 +1767,7 @@ static void atmci_tasklet_func(unsigned long priv)
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- state = STATE_WAITING_NOTBUSY;
- }
-+ host->data = NULL;
- break;
-
- case STATE_END_REQUEST:
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 410edf632453503d8d888a2932679ced461e16b6 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:26:00 +0200
+Subject: mmc: atmel-mci: add support for version lower than v2xx
+
+commit 24011f346471f7636f0ba6ffe2064fdd1a091daa upstream.
+
+Fix mci IP bugs and endianness issue.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 62 +++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 58 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 1baaaebb..5fe8300 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -78,6 +78,9 @@ struct atmel_mci_caps {
+ bool has_highspeed;
+ bool has_rwproof;
+ bool has_odd_clk_div;
++ bool has_bad_data_ordering;
++ bool need_reset_after_xfer;
++ bool need_blksz_mul_4;
+ };
+
+ struct atmel_mci_dma {
+@@ -121,6 +124,7 @@ struct atmel_mci_dma {
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
++ * @timer: Timer to balance the data timeout error flag which cannot rise.
+ * @mode_reg: Value of the MR register.
+ * @cfg_reg: Value of the CFG register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+@@ -197,6 +201,7 @@ struct atmel_mci {
+
+ bool need_clock_update;
+ bool need_reset;
++ struct timer_list timer;
+ u32 mode_reg;
+ u32 cfg_reg;
+ unsigned long bus_hz;
+@@ -493,6 +498,27 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host)
+ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+ }
+
++static void atmci_timeout_timer(unsigned long data)
++{
++ struct atmel_mci *host;
++
++ host = (struct atmel_mci *)data;
++
++ dev_dbg(&host->pdev->dev, "software timeout\n");
++
++ if (host->mrq->cmd->data) {
++ host->mrq->cmd->data->error = -ETIMEDOUT;
++ host->data = NULL;
++ } else {
++ host->mrq->cmd->error = -ETIMEDOUT;
++ host->cmd = NULL;
++ }
++ host->need_reset = 1;
++ host->state = STATE_END_REQUEST;
++ smp_wmb();
++ tasklet_schedule(&host->tasklet);
++}
++
+ static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
+ unsigned int ns)
+ {
+@@ -692,13 +718,18 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
+ static void atmci_pdc_complete(struct atmel_mci *host)
+ {
+ int transfer_size = host->data->blocks * host->data->blksz;
++ int i;
+
+ atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+ if ((!host->caps.has_rwproof)
+- && (host->data->flags & MMC_DATA_READ))
++ && (host->data->flags & MMC_DATA_READ)) {
++ if (host->caps.has_bad_data_ordering)
++ for (i = 0; i < transfer_size; i++)
++ host->buffer[i] = swab32(host->buffer[i]);
+ sg_copy_from_buffer(host->data->sg, host->data->sg_len,
+ host->buffer, transfer_size);
++ }
+
+ atmci_pdc_cleanup(host);
+
+@@ -819,6 +850,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ u32 iflags, tmp;
+ unsigned int sg_len;
+ enum dma_data_direction dir;
++ int i;
+
+ data->error = -EINPROGRESS;
+
+@@ -848,9 +880,13 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
+
+ if ((!host->caps.has_rwproof)
+- && (host->data->flags & MMC_DATA_WRITE))
++ && (host->data->flags & MMC_DATA_WRITE)) {
+ sg_copy_to_buffer(host->data->sg, host->data->sg_len,
+ host->buffer, host->data_size);
++ if (host->caps.has_bad_data_ordering)
++ for (i = 0; i < host->data_size; i++)
++ host->buffer[i] = swab32(host->buffer[i]);
++ }
+
+ if (host->data_size)
+ atmci_pdc_set_both_buf(host,
+@@ -1013,7 +1049,7 @@ static void atmci_start_request(struct atmel_mci *host,
+ host->cmd_status = 0;
+ host->data_status = 0;
+
+- if (host->need_reset) {
++ if (host->need_reset || host->caps.need_reset_after_xfer) {
+ iflags = atmci_readl(host, ATMCI_IMR);
+ iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
+ atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
+@@ -1077,6 +1113,8 @@ static void atmci_start_request(struct atmel_mci *host,
+ * prepared yet.)
+ */
+ atmci_writel(host, ATMCI_IER, iflags);
++
++ mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
+ }
+
+ static void atmci_queue_request(struct atmel_mci *host,
+@@ -1342,6 +1380,8 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+ host->state = STATE_IDLE;
+ }
+
++ del_timer(&host->timer);
++
+ spin_unlock(&host->lock);
+ mmc_request_done(prev_mmc, mrq);
+ spin_lock(&host->lock);
+@@ -1364,7 +1404,12 @@ static void atmci_command_complete(struct atmel_mci *host,
+ cmd->error = -EILSEQ;
+ else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))
+ cmd->error = -EIO;
+- else
++ else if (host->mrq->data && (host->mrq->data->blksz & 3)) {
++ if (host->caps.need_blksz_mul_4) {
++ cmd->error = -EINVAL;
++ host->need_reset = 1;
++ }
++ } else
+ cmd->error = 0;
+ }
+
+@@ -2121,6 +2166,9 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_highspeed = 0;
+ host->caps.has_rwproof = 0;
+ host->caps.has_odd_clk_div = 0;
++ host->caps.has_bad_data_ordering = 1;
++ host->caps.need_reset_after_xfer = 1;
++ host->caps.need_blksz_mul_4 = 1;
+
+ /* keep only major version number */
+ switch (version & 0xf00) {
+@@ -2140,7 +2188,11 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_highspeed = 1;
+ case 0x200:
+ host->caps.has_rwproof = 1;
++ host->caps.need_blksz_mul_4 = 0;
+ case 0x100:
++ host->caps.has_bad_data_ordering = 0;
++ host->caps.need_reset_after_xfer = 0;
++ case 0x0:
+ break;
+ default:
+ host->caps.has_pdc = 0;
+@@ -2259,6 +2311,8 @@ static int __init atmci_probe(struct platform_device *pdev)
+ }
+ }
+
++ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
++
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From abb226194272a5844bdbdcd04e3a8e1b1762e256 Mon Sep 17 00:00:00 2001
-From: Subhash Jadavani <subhashj@codeaurora.org>
-Date: Wed, 13 Jun 2012 17:10:43 +0530
-Subject: mmc: block: fix the data timeout issue with ACMD22
-
-If multi block write operation fails for SD card, during
-error handling we send the SD_APP_SEND_NUM_WR_BLKS (ACMD22)
-to know how many blocks were already programmed by card.
-
-But mmc_sd_num_wr_blocks() function which sends the ACMD22
-calculates the data timeout value from csd.tacc_ns and
-csd.tacc_clks parameters which will be 0 for block addressed
-(>2GB cards) SD card. This would result in timeout_ns and
-timeout_clks being 0 in the mmc_request passed to host driver.
-This means host controller would program its data timeout timer
-value with 0 which could result in DATA TIMEOUT errors from
-controller.
-
-To fix this issue, mmc_sd_num_wr_blocks() should instead
-just call the mmc_set_data_timeout() to calculate the
-data timeout value. mmc_set_data_timeout() function
-ensures that non zero timeout value is set even for
-block addressed SD cards.
-
-Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-Reviewed-by: Venkatraman S <svenkatr@ti.com>
-Signed-off-by: Chris Ball <cjb@laptop.org>
----
- drivers/mmc/card/block.c | 14 +-------------
- 1 file changed, 1 insertion(+), 13 deletions(-)
-
-diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
-index dabec55..d8f802e 100644
---- a/drivers/mmc/card/block.c
-+++ b/drivers/mmc/card/block.c
-@@ -553,7 +553,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
-- unsigned int timeout_us;
-
- struct scatterlist sg;
-
-@@ -573,23 +572,12 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
- cmd.arg = 0;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-
-- data.timeout_ns = card->csd.tacc_ns * 100;
-- data.timeout_clks = card->csd.tacc_clks * 100;
--
-- timeout_us = data.timeout_ns / 1000;
-- timeout_us += data.timeout_clks * 1000 /
-- (card->host->ios.clock / 1000);
--
-- if (timeout_us > 100000) {
-- data.timeout_ns = 100000000;
-- data.timeout_clks = 0;
-- }
--
- data.blksz = 4;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-+ mmc_set_data_timeout(&data, card);
-
- mrq.cmd = &cmd;
- mrq.data = &data;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f83911708a2a24e8d44657d737f6aac9e840d2d2 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 16 May 2012 15:26:01 +0200
+Subject: mmc: atmel-mci: add debug logs
+
+commit 6801c41a77123712accfde898820972a1f6fc117 upstream.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/host/atmel-mci.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 41 insertions(+)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 5fe8300..420aca6 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -630,6 +630,7 @@ static void atmci_send_command(struct atmel_mci *host,
+
+ static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
+ {
++ dev_dbg(&host->pdev->dev, "send stop command\n");
+ atmci_send_command(host, data->stop, host->stop_cmdr);
+ atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
+ }
+@@ -738,6 +739,8 @@ static void atmci_pdc_complete(struct atmel_mci *host)
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (host->data) {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+ }
+@@ -775,6 +778,8 @@ static void atmci_dma_complete(void *arg)
+ * to send the stop command or waiting for NBUSY in this case.
+ */
+ if (data) {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ tasklet_schedule(&host->tasklet);
+
+@@ -1001,6 +1006,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+
+ static void atmci_stop_transfer(struct atmel_mci *host)
+ {
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+@@ -1022,6 +1029,8 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host)
+ atmci_dma_cleanup(host);
+ } else {
+ /* Data transfer was stopped by the interrupt handler */
++ dev_dbg(&host->pdev->dev,
++ "(%s) set pending xfer complete\n", __func__);
+ atmci_set_pending(host, EVENT_XFER_COMPLETE);
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ }
+@@ -1049,6 +1058,8 @@ static void atmci_start_request(struct atmel_mci *host,
+ host->cmd_status = 0;
+ host->data_status = 0;
+
++ dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
++
+ if (host->need_reset || host->caps.need_reset_after_xfer) {
+ iflags = atmci_readl(host, ATMCI_IMR);
+ iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
+@@ -1129,6 +1140,7 @@ static void atmci_queue_request(struct atmel_mci *host,
+ host->state = STATE_SENDING_CMD;
+ atmci_start_request(host, slot);
+ } else {
++ dev_dbg(&host->pdev->dev, "queue request\n");
+ list_add_tail(&slot->queue_node, &host->queue);
+ }
+ spin_unlock_bh(&host->lock);
+@@ -1141,6 +1153,7 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+ struct mmc_data *data;
+
+ WARN_ON(slot->mrq);
++ dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
+
+ /*
+ * We may "know" the card is gone even though there's still an
+@@ -1530,6 +1543,7 @@ static void atmci_tasklet_func(unsigned long priv)
+
+ do {
+ prev_state = state;
++ dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
+
+ switch (state) {
+ case STATE_IDLE:
+@@ -1542,14 +1556,18 @@ static void atmci_tasklet_func(unsigned long priv)
+ * END_REQUEST by default, WAITING_NOTBUSY if it's a
+ * command needing it or DATA_XFER if there is data.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_RDY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
+ host->cmd = NULL;
+ atmci_set_completed(host, EVENT_CMD_RDY);
+ atmci_command_complete(host, mrq->cmd);
+ if (mrq->data) {
++ dev_dbg(&host->pdev->dev,
++ "command with data transfer");
+ /*
+ * If there is a command error don't start
+ * data transfer.
+@@ -1564,6 +1582,8 @@ static void atmci_tasklet_func(unsigned long priv)
+ } else
+ state = STATE_DATA_XFER;
+ } else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
++ dev_dbg(&host->pdev->dev,
++ "command response need waiting notbusy");
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ } else
+@@ -1574,6 +1594,7 @@ static void atmci_tasklet_func(unsigned long priv)
+ case STATE_DATA_XFER:
+ if (atmci_test_and_clear_pending(host,
+ EVENT_DATA_ERROR)) {
++ dev_dbg(&host->pdev->dev, "set completed data error\n");
+ atmci_set_completed(host, EVENT_DATA_ERROR);
+ state = STATE_END_REQUEST;
+ break;
+@@ -1586,10 +1607,14 @@ static void atmci_tasklet_func(unsigned long priv)
+ * to the next step which is WAITING_NOTBUSY in write
+ * case and directly SENDING_STOP in read case.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_XFER_COMPLETE))
+ break;
+
++ dev_dbg(&host->pdev->dev,
++ "(%s) set completed xfer complete\n",
++ __func__);
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+
+ if (host->data->flags & MMC_DATA_WRITE) {
+@@ -1614,10 +1639,12 @@ static void atmci_tasklet_func(unsigned long priv)
+ * included) or a write operation. In the latest case,
+ * we need to send a stop command.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_NOTBUSY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "set completed not busy\n");
+ atmci_set_completed(host, EVENT_NOTBUSY);
+
+ if (host->data) {
+@@ -1649,10 +1676,12 @@ static void atmci_tasklet_func(unsigned long priv)
+ * in order to go to the end request state instead of
+ * sending stop again.
+ */
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
+ if (!atmci_test_and_clear_pending(host,
+ EVENT_CMD_RDY))
+ break;
+
++ dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
+ host->cmd = NULL;
+ host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+@@ -1858,18 +1887,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ break;
+
+ if (pending & ATMCI_DATA_ERROR_FLAGS) {
++ dev_dbg(&host->pdev->dev, "IRQ: data error\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
+ | ATMCI_RXRDY | ATMCI_TXRDY
+ | ATMCI_ENDRX | ATMCI_ENDTX
+ | ATMCI_RXBUFF | ATMCI_TXBUFE);
+
+ host->data_status = status;
++ dev_dbg(&host->pdev->dev, "set pending data error\n");
+ smp_wmb();
+ atmci_set_pending(host, EVENT_DATA_ERROR);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & ATMCI_TXBUFE) {
++ dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
+ /*
+@@ -1885,6 +1917,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_pdc_complete(host);
+ }
+ } else if (pending & ATMCI_ENDTX) {
++ dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
+
+ if (host->data_size) {
+@@ -1895,6 +1928,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ }
+
+ if (pending & ATMCI_RXBUFF) {
++ dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
+ /*
+@@ -1910,6 +1944,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_pdc_complete(host);
+ }
+ } else if (pending & ATMCI_ENDRX) {
++ dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
+
+ if (host->data_size) {
+@@ -1926,15 +1961,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ * The appropriate workaround is to use the BLKE signal.
+ */
+ if (pending & ATMCI_BLKE) {
++ dev_dbg(&host->pdev->dev, "IRQ: blke\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
+
+ if (pending & ATMCI_NOTBUSY) {
++ dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending notbusy\n");
+ atmci_set_pending(host, EVENT_NOTBUSY);
+ tasklet_schedule(&host->tasklet);
+ }
+@@ -1945,9 +1984,11 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+ atmci_write_data_pio(host);
+
+ if (pending & ATMCI_CMDRDY) {
++ dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
+ atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
+ host->cmd_status = status;
+ smp_wmb();
++ dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
+ atmci_set_pending(host, EVENT_CMD_RDY);
+ tasklet_schedule(&host->tasklet);
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 7a25326f9063c55c62944a8890ec061f2e86bea3 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Fri, 6 Jul 2012 12:11:51 +0200
-Subject: mmc: atmel-mci: modify CLKDIV displaying in debugfs
-
-Modify clock division displaying in debugfs for matching
-the new CLKDIV,CLKODD user interface arrangement.
-Is using the has_odd_clk_div property to choose the proper format.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 12 +++++++++---
- 1 file changed, 9 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 90df83b..e03367c 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -394,11 +394,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
- clk_disable(host->mck);
- spin_unlock_bh(&host->lock);
-
-- seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
-+ seq_printf(s, "MR:\t0x%08x%s%s ",
- buf[ATMCI_MR / 4],
- buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
-- buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
-- buf[ATMCI_MR / 4] & 0xff);
-+ buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
-+ if (host->caps.has_odd_clk_div)
-+ seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
-+ ((buf[ATMCI_MR / 4] & 0xff) << 1)
-+ | ((buf[ATMCI_MR / 4] >> 16) & 1));
-+ else
-+ seq_printf(s, "CLKDIV=%u\n",
-+ (buf[ATMCI_MR / 4] & 0xff));
- seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
- seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
- seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From df09e320ce8def6b95f5ae3fb7d3b547e0d275a8 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 23 May 2012 15:46:00 +0200
+Subject: mmc: atmel-mci: fix data timeout issue
+
+commit b87cc1b5d3a96ef9f1b3a4f8ce7aaff18e96c994 upstream.
+
+The data timeout timer was configured after mmc_add_host call. So, with bad
+timings, it was possible to have a mmc request causing mod_timer call on a
+non setup timer.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 420aca6..456c077 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -2314,6 +2314,8 @@ static int __init atmci_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, host);
+
++ setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
++
+ /* We need at least one slot to succeed */
+ nr_slots = 0;
+ ret = -ENODEV;
+@@ -2352,8 +2354,6 @@ static int __init atmci_probe(struct platform_device *pdev)
+ }
+ }
+
+- setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
+-
+ dev_info(&pdev->dev,
+ "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+ host->mapbase, irq, nr_slots);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 3903e1f7186f676dcce3a631624cf7ece8b9fbfd Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Mon, 9 Jul 2012 08:51:50 +0200
-Subject: mmc: atmel-mci: increase dma threshold
-
-There are some issues with some SD cards when dma is used. DMA transfer
-during cmd6 seems to hang for an unknown reason. Since using PIO prevents from
-this issue, the dma threshold has been increased to not use dma for this
-command.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index e03367c..05a293e 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -45,7 +45,7 @@
- #include "atmel-mci-regs.h"
-
- #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
--#define ATMCI_DMA_THRESHOLD 16
-+#define ATMCI_DMA_THRESHOLD 65
-
- enum {
- EVENT_CMD_RDY = 0,
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 975d22ac8acbc75c1f283bad017101d603a263f1 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 21 May 2012 12:23:27 +0200
+Subject: ARM: at91: add atmel-mci support for chips and boards which can use
+ it
+
+commit 4cf3326ab5f34a333a46c59d0d3783db9cef13bf upstream.
+
+Since atmel-mci driver supports all atmel mci versions,
+use it instead of the deprecated at91_mci driver.
+Platform data and all related configuration are removed.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+[nicolas.ferre@atmel.com: remove at91_mci platform data]
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/at91rm9200_devices.c | 92 ++++++++++--------
+ arch/arm/mach-at91/at91sam9260_devices.c | 84 +---------------
+ arch/arm/mach-at91/at91sam9261_devices.c | 60 ++++++------
+ arch/arm/mach-at91/at91sam9263.c | 4 +-
+ arch/arm/mach-at91/at91sam9263_devices.c | 161 ++++++++++++++++++-------------
+ arch/arm/mach-at91/at91sam9rl_devices.c | 60 ++++++------
+ arch/arm/mach-at91/board-afeb-9260v1.c | 14 +--
+ arch/arm/mach-at91/board-carmeva.c | 14 +--
+ arch/arm/mach-at91/board-cpu9krea.c | 14 +--
+ arch/arm/mach-at91/board-cpuat91.c | 13 +--
+ arch/arm/mach-at91/board-csb337.c | 14 +--
+ arch/arm/mach-at91/board-eb9200.c | 14 +--
+ arch/arm/mach-at91/board-ecbat91.c | 14 +--
+ arch/arm/mach-at91/board-eco920.c | 14 +--
+ arch/arm/mach-at91/board-flexibity.c | 14 +--
+ arch/arm/mach-at91/board-foxg20.c | 16 +--
+ arch/arm/mach-at91/board-kb9202.c | 14 +--
+ arch/arm/mach-at91/board-neocore926.c | 13 +--
+ arch/arm/mach-at91/board-picotux200.c | 14 +--
+ arch/arm/mach-at91/board-qil-a9260.c | 14 +--
+ arch/arm/mach-at91/board-rm9200dk.c | 14 +--
+ arch/arm/mach-at91/board-rm9200ek.c | 14 +--
+ arch/arm/mach-at91/board-rsi-ews.c | 13 +--
+ arch/arm/mach-at91/board-sam9-l9260.c | 16 +--
+ arch/arm/mach-at91/board-sam9260ek.c | 16 +--
+ arch/arm/mach-at91/board-sam9261ek.c | 13 +--
+ arch/arm/mach-at91/board-sam9263ek.c | 13 +--
+ arch/arm/mach-at91/board-sam9g20ek.c | 16 +--
+ arch/arm/mach-at91/board-sam9rlek.c | 13 +--
+ arch/arm/mach-at91/board-stamp9g20.c | 14 ---
+ arch/arm/mach-at91/board-usb-a926x.c | 2 -
+ arch/arm/mach-at91/board-yl-9200.c | 13 +--
+ 32 files changed, 375 insertions(+), 439 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
+index 01fb732..9ac427a 100644
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -312,7 +312,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91rm9200_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
++ unsigned int i;
++ unsigned int slot_count = 0;
++
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA27, 0);
++ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA8, 1);
++ if (!data->slot[i].bus_width)
++ continue;
+
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA9, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA10, 1);
+- at91_set_B_periph(AT91_PIN_PA11, 1);
+- at91_set_B_periph(AT91_PIN_PA12, 1);
++ /* input/irq */
++ if (gpio_is_valid(data->slot[i].detect_pin)) {
++ at91_set_gpio_input(data->slot[i].detect_pin, 1);
++ at91_set_deglitch(data->slot[i].detect_pin, 1);
+ }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA28, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA29, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PB3, 1);
+- at91_set_B_periph(AT91_PIN_PB4, 1);
+- at91_set_B_periph(AT91_PIN_PB5, 1);
++ if (gpio_is_valid(data->slot[i].wp_pin))
++ at91_set_gpio_input(data->slot[i].wp_pin, 1);
++
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA28, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA29, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PB3, 1);
++ at91_set_B_periph(AT91_PIN_PB4, 1);
++ at91_set_B_periph(AT91_PIN_PB5, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA8, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA9, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PA10, 1);
++ at91_set_B_periph(AT91_PIN_PA11, 1);
++ at91_set_B_periph(AT91_PIN_PA12, 1);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
++ }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA27, 0);
++
++ mmc_data = *data;
++ platform_device_register(&at91rm9200_mmc_device);
+ }
+ }
+
+- mmc_data = *data;
+- platform_device_register(&at91rm9200_mmc_device);
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
+index 43e60fb..2c54662 100644
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -206,92 +206,10 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
+
+
+ /* --------------------------------------------------------------------
+- * MMC / SD
+- * -------------------------------------------------------------------- */
+-
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+-static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
+-
+-static struct resource mmc_resources[] = {
+- [0] = {
+- .start = AT91SAM9260_BASE_MCI,
+- .end = AT91SAM9260_BASE_MCI + SZ_16K - 1,
+- .flags = IORESOURCE_MEM,
+- },
+- [1] = {
+- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-static struct platform_device at91sam9260_mmc_device = {
+- .name = "at91_mci",
+- .id = -1,
+- .dev = {
+- .dma_mask = &mmc_dmamask,
+- .coherent_dma_mask = DMA_BIT_MASK(32),
+- .platform_data = &mmc_data,
+- },
+- .resource = mmc_resources,
+- .num_resources = ARRAY_SIZE(mmc_resources),
+-};
+-
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+-{
+- if (!data)
+- return;
+-
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA8, 0);
+-
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA5, 1);
+- at91_set_B_periph(AT91_PIN_PA4, 1);
+- at91_set_B_periph(AT91_PIN_PA3, 1);
+- }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA7, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA6, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA9, 1);
+- at91_set_A_periph(AT91_PIN_PA10, 1);
+- at91_set_A_periph(AT91_PIN_PA11, 1);
+- }
+- }
+-
+- mmc_data = *data;
+- platform_device_register(&at91sam9260_mmc_device);
+-}
+-#else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+-#endif
+-
+-/* --------------------------------------------------------------------
+ * MMC / SD Slot for Atmel MCI Driver
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+ static struct mci_platform_data mmc_data;
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 1eecff8..08b3b02 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -139,9 +139,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -157,7 +157,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91sam9261_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -168,40 +168,40 @@ static struct platform_device at91sam9261_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_B_periph(AT91_PIN_PA2, 0);
+-
+- /* CMD */
+- at91_set_B_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_B_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_B_periph(AT91_PIN_PA4, 1);
+- at91_set_B_periph(AT91_PIN_PA5, 1);
+- at91_set_B_periph(AT91_PIN_PA6, 1);
+- }
++ if (data->slot[0].bus_width) {
++ /* input/irq */
++ if (gpio_is_valid(data->slot[0].detect_pin)) {
++ at91_set_gpio_input(data->slot[0].detect_pin, 1);
++ at91_set_deglitch(data->slot[0].detect_pin, 1);
++ }
++ if (gpio_is_valid(data->slot[0].wp_pin))
++ at91_set_gpio_input(data->slot[0].wp_pin, 1);
++
++ /* CLK */
++ at91_set_B_periph(AT91_PIN_PA2, 0);
+
+- mmc_data = *data;
+- platform_device_register(&at91sam9261_mmc_device);
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA1, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA0, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_B_periph(AT91_PIN_PA4, 1);
++ at91_set_B_periph(AT91_PIN_PA5, 1);
++ at91_set_B_periph(AT91_PIN_PA6, 1);
++ }
++
++ mmc_data = *data;
++ platform_device_register(&at91sam9261_mmc_device);
++ }
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 84b3810..144ef5d 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("hclk", &macb_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+- CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
+index f0318e9..a111315 100644
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -220,9 +220,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc0_data, mmc1_data;
++static struct mci_platform_data mmc0_data, mmc1_data;
+
+ static struct resource mmc0_resources[] = {
+ [0] = {
+@@ -238,7 +238,7 @@ static struct resource mmc0_resources[] = {
+ };
+
+ static struct platform_device at91sam9263_mmc0_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -263,7 +263,7 @@ static struct resource mmc1_resources[] = {
+ };
+
+ static struct platform_device at91sam9263_mmc1_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = 1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -274,85 +274,110 @@ static struct platform_device at91sam9263_mmc1_device = {
+ .num_resources = ARRAY_SIZE(mmc1_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
++ unsigned int i;
++ unsigned int slot_count = 0;
++
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
++ for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
+
+- if (mmc_id == 0) { /* MCI0 */
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA12, 0);
++ if (!data->slot[i].bus_width)
++ continue;
+
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* input/irq */
++ if (gpio_is_valid(data->slot[i].detect_pin)) {
++ at91_set_gpio_input(data->slot[i].detect_pin,
++ 1);
++ at91_set_deglitch(data->slot[i].detect_pin,
++ 1);
++ }
++ if (gpio_is_valid(data->slot[i].wp_pin))
++ at91_set_gpio_input(data->slot[i].wp_pin, 1);
++
++ if (mmc_id == 0) { /* MCI0 */
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA1, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA0, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA3, 1);
++ at91_set_A_periph(AT91_PIN_PA4, 1);
++ at91_set_A_periph(AT91_PIN_PA5, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA17, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA18, 1);
++ at91_set_A_periph(AT91_PIN_PA19, 1);
++ at91_set_A_periph(AT91_PIN_PA20, 1);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
++ }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA12, 0);
+
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA17, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA18, 1);
+- at91_set_A_periph(AT91_PIN_PA19, 1);
+- at91_set_A_periph(AT91_PIN_PA20, 1);
++ mmc0_data = *data;
++ platform_device_register(&at91sam9263_mmc0_device);
+ }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA3, 1);
+- at91_set_A_periph(AT91_PIN_PA4, 1);
+- at91_set_A_periph(AT91_PIN_PA5, 1);
++ } else if (mmc_id == 1) { /* MCI1 */
++ switch (i) {
++ case 0: /* slot A */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA7, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA8, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA9, 1);
++ at91_set_A_periph(AT91_PIN_PA10, 1);
++ at91_set_A_periph(AT91_PIN_PA11, 1);
++ }
++ slot_count++;
++ break;
++ case 1: /* slot B */
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA21, 1);
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA22, 1);
++ if (data->slot[i].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA23, 1);
++ at91_set_A_periph(AT91_PIN_PA24, 1);
++ at91_set_A_periph(AT91_PIN_PA25, 1);
++ }
++ slot_count++;
++ break;
++ default:
++ printk(KERN_ERR
++ "AT91: SD/MMC slot %d not available\n", i);
++ break;
+ }
+- }
++ if (slot_count) {
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA6, 0);
+
+- mmc0_data = *data;
+- platform_device_register(&at91sam9263_mmc0_device);
+- } else { /* MCI1 */
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA6, 0);
+-
+- if (data->slot_b) {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA21, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA22, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA23, 1);
+- at91_set_A_periph(AT91_PIN_PA24, 1);
+- at91_set_A_periph(AT91_PIN_PA25, 1);
+- }
+- } else {
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA7, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA8, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA9, 1);
+- at91_set_A_periph(AT91_PIN_PA10, 1);
+- at91_set_A_periph(AT91_PIN_PA11, 1);
++ mmc1_data = *data;
++ platform_device_register(&at91sam9263_mmc1_device);
+ }
+ }
+-
+- mmc1_data = *data;
+- platform_device_register(&at91sam9263_mmc1_device);
+ }
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+ /* --------------------------------------------------------------------
+diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
+index 0d1b76f..88687b9 100644
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -163,9 +163,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {}
+ * MMC / SD
+ * -------------------------------------------------------------------- */
+
+-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
++#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ static u64 mmc_dmamask = DMA_BIT_MASK(32);
+-static struct at91_mmc_data mmc_data;
++static struct mci_platform_data mmc_data;
+
+ static struct resource mmc_resources[] = {
+ [0] = {
+@@ -181,7 +181,7 @@ static struct resource mmc_resources[] = {
+ };
+
+ static struct platform_device at91sam9rl_mmc_device = {
+- .name = "at91_mci",
++ .name = "atmel_mci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &mmc_dmamask,
+@@ -192,40 +192,40 @@ static struct platform_device at91sam9rl_mmc_device = {
+ .num_resources = ARRAY_SIZE(mmc_resources),
+ };
+
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
+ {
+ if (!data)
+ return;
+
+- /* input/irq */
+- if (gpio_is_valid(data->det_pin)) {
+- at91_set_gpio_input(data->det_pin, 1);
+- at91_set_deglitch(data->det_pin, 1);
+- }
+- if (gpio_is_valid(data->wp_pin))
+- at91_set_gpio_input(data->wp_pin, 1);
+- if (gpio_is_valid(data->vcc_pin))
+- at91_set_gpio_output(data->vcc_pin, 0);
+-
+- /* CLK */
+- at91_set_A_periph(AT91_PIN_PA2, 0);
+-
+- /* CMD */
+- at91_set_A_periph(AT91_PIN_PA1, 1);
+-
+- /* DAT0, maybe DAT1..DAT3 */
+- at91_set_A_periph(AT91_PIN_PA0, 1);
+- if (data->wire4) {
+- at91_set_A_periph(AT91_PIN_PA3, 1);
+- at91_set_A_periph(AT91_PIN_PA4, 1);
+- at91_set_A_periph(AT91_PIN_PA5, 1);
++ if (data->slot[0].bus_width) {
++ /* input/irq */
++ if (gpio_is_valid(data->slot[0].detect_pin)) {
++ at91_set_gpio_input(data->slot[0].detect_pin, 1);
++ at91_set_deglitch(data->slot[0].detect_pin, 1);
++ }
++ if (gpio_is_valid(data->slot[0].wp_pin))
++ at91_set_gpio_input(data->slot[0].wp_pin, 1);
++
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA2, 0);
++
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA1, 1);
++
++ /* DAT0, maybe DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA0, 1);
++ if (data->slot[0].bus_width == 4) {
++ at91_set_A_periph(AT91_PIN_PA3, 1);
++ at91_set_A_periph(AT91_PIN_PA4, 1);
++ at91_set_A_periph(AT91_PIN_PA5, 1);
++ }
++
++ mmc_data = *data;
++ platform_device_register(&at91sam9rl_mmc_device);
+ }
+-
+- mmc_data = *data;
+- platform_device_register(&at91sam9rl_mmc_device);
+ }
+ #else
+-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
++void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+ #endif
+
+
+diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
+index de7be19..93a832f 100644
+--- a/arch/arm/mach-at91/board-afeb-9260v1.c
++++ b/arch/arm/mach-at91/board-afeb-9260v1.c
+@@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata afeb9260_mmc_data = {
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = AT91_PIN_PC4,
+- .slot_b = 1,
+- .wire4 = 1,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata afeb9260_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC9,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+
+@@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void)
+ at91_set_B_periph(AT91_PIN_PA10, 0); /* ETX2 */
+ at91_set_B_periph(AT91_PIN_PA11, 0); /* ETX3 */
+ /* MMC */
+- at91_add_device_mmc(0, &afeb9260_mmc_data);
++ at91_add_device_mci(0, &afeb9260_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(afeb9260_i2c_devices,
+ ARRAY_SIZE(afeb9260_i2c_devices));
+diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
+index a5b002f..71d8f36 100644
+--- a/arch/arm/mach-at91/board-carmeva.c
++++ b/arch/arm/mach-at91/board-carmeva.c
+@@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = {
+ // .vcc_pin = -EINVAL,
+ // };
+
+-static struct at91_mmc_data __initdata carmeva_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PB10,
+- .wp_pin = AT91_PIN_PC14,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata carmeva_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB10,
++ .wp_pin = AT91_PIN_PC14,
++ },
+ };
+
+ static struct spi_board_info carmeva_spi_devices[] = {
+@@ -150,7 +150,7 @@ static void __init carmeva_board_init(void)
+ /* Compact Flash */
+ // at91_add_device_cf(&carmeva_cf_data);
+ /* MMC */
+- at91_add_device_mmc(0, &carmeva_mmc_data);
++ at91_add_device_mci(0, &carmeva_mci0_data);
+ /* LEDs */
+ at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
+ }
+diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
+index 7ddc219..e71c473 100644
+--- a/arch/arm/mach-at91/board-cpu9krea.c
++++ b/arch/arm/mach-at91/board-cpu9krea.c
+@@ -311,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PA29,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata cpu9krea_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PA29,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static void __init cpu9krea_board_init(void)
+@@ -358,7 +358,7 @@ static void __init cpu9krea_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&cpu9krea_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &cpu9krea_mmc_data);
++ at91_add_device_mci(0, &cpu9krea_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(cpu9krea_i2c_devices,
+ ARRAY_SIZE(cpu9krea_i2c_devices));
+diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
+index 2e6d043..2cbd1a2 100644
+--- a/arch/arm/mach-at91/board-cpuat91.c
++++ b/arch/arm/mach-at91/board-cpuat91.c
+@@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = {
+ .pullup_pin = AT91_PIN_PC14,
+ };
+
+-static struct at91_mmc_data __initdata cpuat91_mmc_data = {
+- .det_pin = AT91_PIN_PC2,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata cpuat91_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC2,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct physmap_flash_data cpuat91_flash_data = {
+@@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void)
+ /* USB Device */
+ at91_add_device_udc(&cpuat91_udc_data);
+ /* MMC */
+- at91_add_device_mmc(0, &cpuat91_mmc_data);
++ at91_add_device_mci(0, &cpuat91_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* Platform devices */
+diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
+index 462bc31..81a8bc4 100644
+--- a/arch/arm/mach-at91/board-csb337.c
++++ b/arch/arm/mach-at91/board-csb337.c
+@@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = {
+ .rst_pin = AT91_PIN_PD2,
+ };
+
+-static struct at91_mmc_data __initdata csb337_mmc_data = {
+- .det_pin = AT91_PIN_PD5,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PD6,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata csb337_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PD5,
++ .wp_pin = AT91_PIN_PD6,
++ },
+ };
+
+ static struct spi_board_info csb337_spi_devices[] = {
+@@ -240,7 +240,7 @@ static void __init csb337_board_init(void)
+ /* SPI */
+ at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &csb337_mmc_data);
++ at91_add_device_mci(0, &csb337_mci0_data);
+ /* NOR flash */
+ platform_device_register(&csb_flash);
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
+index d1e1f3f..0cfac16 100644
+--- a/arch/arm/mach-at91/board-eb9200.c
++++ b/arch/arm/mach-at91/board-eb9200.c
+@@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = {
+ .rst_pin = AT91_PIN_PC5,
+ };
+
+-static struct at91_mmc_data __initdata eb9200_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata eb9200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
+@@ -113,7 +113,7 @@ static void __init eb9200_board_init(void)
+ at91_add_device_spi(NULL, 0);
+ /* MMC */
+ /* only supports 1 or 4 bit interface, not wired through to SPI */
+- at91_add_device_mmc(0, &eb9200_mmc_data);
++ at91_add_device_mci(0, &eb9200_mci0_data);
+ }
+
+ MACHINE_START(ATEB9200, "Embest ATEB9200")
+diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
+index 9c24cb2..a9d50fc 100644
+--- a/arch/arm/mach-at91/board-ecbat91.c
++++ b/arch/arm/mach-at91/board-ecbat91.c
+@@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = {
+ .overcurrent_pin= {-EINVAL, -EINVAL},
+ };
+
+-static struct at91_mmc_data __initdata ecb_at91mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ecbat91_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -161,7 +161,7 @@ static void __init ecb_at91board_init(void)
+ at91_add_device_i2c(NULL, 0);
+
+ /* MMC */
+- at91_add_device_mmc(0, &ecb_at91mmc_data);
++ at91_add_device_mci(0, &ecbat91_mci0_data);
+
+ /* SPI */
+ at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
+diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
+index 82bdfde..aaf7015 100644
+--- a/arch/arm/mach-at91/board-eco920.c
++++ b/arch/arm/mach-at91/board-eco920.c
+@@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = {
+ .pullup_pin = AT91_PIN_PB13,
+ };
+
+-static struct at91_mmc_data __initdata eco920_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 0,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata eco920_mci0_data = {
++ .slot[0] = {
++ .bus_width = 1,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct physmap_flash_data eco920_flash_data = {
+@@ -104,7 +104,7 @@ static void __init eco920_board_init(void)
+ at91_add_device_usbh(&eco920_usbh_data);
+ at91_add_device_udc(&eco920_udc_data);
+
+- at91_add_device_mmc(0, &eco920_mmc_data);
++ at91_add_device_mci(0, &eco920_mci0_data);
+ platform_device_register(&eco920_flash);
+
+ at91_ramc_write(0, AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
+diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
+index 6cc83a8..fa98aba 100644
+--- a/arch/arm/mach-at91/board-flexibity.c
++++ b/arch/arm/mach-at91/board-flexibity.c
+@@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = {
+ };
+
+ /* MCI (SD/MMC) */
+-static struct at91_mmc_data __initdata flexibity_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = AT91_PIN_PC4,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata flexibity_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC9,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+ /* LEDs */
+@@ -152,7 +152,7 @@ static void __init flexibity_board_init(void)
+ at91_add_device_spi(flexibity_spi_devices,
+ ARRAY_SIZE(flexibity_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &flexibity_mmc_data);
++ at91_add_device_mci(0, &flexibity_mci0_data);
+ /* LEDs */
+ at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
+ }
+diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
+index 69ab124..6e47071 100644
+--- a/arch/arm/mach-at91/board-foxg20.c
++++ b/arch/arm/mach-at91/board-foxg20.c
+@@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info foxg20_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ {
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = {
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-static struct at91_mmc_data __initdata foxg20_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata foxg20_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -247,7 +247,7 @@ static void __init foxg20_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&foxg20_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &foxg20_mmc_data);
++ at91_add_device_mci(0, &foxg20_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
+index 5d96cb8..330d603 100644
+--- a/arch/arm/mach-at91/board-kb9202.c
++++ b/arch/arm/mach-at91/board-kb9202.c
+@@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = {
+ .pullup_pin = AT91_PIN_PB22,
+ };
+
+-static struct at91_mmc_data __initdata kb9202_mmc_data = {
+- .det_pin = AT91_PIN_PB2,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata kb9202_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB2,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ static struct mtd_partition __initdata kb9202_nand_partition[] = {
+@@ -121,7 +121,7 @@ static void __init kb9202_board_init(void)
+ /* USB Device */
+ at91_add_device_udc(&kb9202_udc_data);
+ /* MMC */
+- at91_add_device_mmc(0, &kb9202_mmc_data);
++ at91_add_device_mci(0, &kb9202_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ /* SPI */
+diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
+index 5d3b4d6..7fb2a8f 100644
+--- a/arch/arm/mach-at91/board-neocore926.c
++++ b/arch/arm/mach-at91/board-neocore926.c
+@@ -140,11 +140,12 @@ static struct spi_board_info neocore926_spi_devices[] = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata neocore926_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PE18,
+- .wp_pin = AT91_PIN_PE19,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata neocore926_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PE18,
++ .wp_pin = AT91_PIN_PE19,
++ },
+ };
+
+
+@@ -356,7 +357,7 @@ static void __init neocore926_board_init(void)
+ neocore926_add_device_ts();
+
+ /* MMC */
+- at91_add_device_mmc(1, &neocore926_mmc_data);
++ at91_add_device_mci(0, &neocore926_mci0_data);
+
+ /* Ethernet */
+ at91_add_device_eth(&neocore926_macb_data);
+diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
+index 1270655..f83e1de 100644
+--- a/arch/arm/mach-at91/board-picotux200.c
++++ b/arch/arm/mach-at91/board-picotux200.c
+@@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = {
+ .overcurrent_pin= {-EINVAL, -EINVAL},
+ };
+
+-static struct at91_mmc_data __initdata picotux200_mmc_data = {
+- .det_pin = AT91_PIN_PB27,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PA17,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata picotux200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PA17,
++ },
+ };
+
+ #define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
+@@ -112,7 +112,7 @@ static void __init picotux200_board_init(void)
+ at91_add_device_i2c(NULL, 0);
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &picotux200_mmc_data);
++ at91_add_device_mci(0, &picotux200_mci0_data);
+ /* NOR Flash */
+ platform_device_register(&picotux200_flash);
+ }
+diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
+index bf351e2..799f214 100644
+--- a/arch/arm/mach-at91/board-qil-a9260.c
++++ b/arch/arm/mach-at91/board-qil-a9260.c
+@@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ /*
+@@ -245,7 +245,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* Push Buttons */
+ ek_add_device_buttons();
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
+index cc2bf97..54733ec 100644
+--- a/arch/arm/mach-at91/board-rm9200dk.c
++++ b/arch/arm/mach-at91/board-rm9200dk.c
+@@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = {
+ };
+
+ #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+-static struct at91_mmc_data __initdata dk_mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata dk_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+ #endif
+
+@@ -208,7 +208,7 @@ static void __init dk_board_init(void)
+ #else
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &dk_mmc_data);
++ at91_add_device_mci(0, &dk_mci0_data);
+ #endif
+ /* NAND */
+ at91_add_device_nand(&dk_nand_data);
+diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
+index 62e19e6..69ef141 100644
+--- a/arch/arm/mach-at91/board-rm9200ek.c
++++ b/arch/arm/mach-at91/board-rm9200ek.c
+@@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ };
+
+ #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .det_pin = AT91_PIN_PB27,
+- .slot_b = 0,
+- .wire4 = 1,
+- .wp_pin = AT91_PIN_PA17,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PA17,
++ }
+ };
+ #endif
+
+@@ -177,7 +177,7 @@ static void __init ek_board_init(void)
+ #else
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ #endif
+ /* NOR Flash */
+ platform_device_register(&ek_flash);
+diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
+index c3b43ae..806d0c3 100644
+--- a/arch/arm/mach-at91/board-rsi-ews.c
++++ b/arch/arm/mach-at91/board-rsi-ews.c
+@@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = {
+ /*
+ * SD/MC
+ */
+-static struct at91_mmc_data rsi_ews_mmc_data __initdata = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PB27,
+- .wp_pin = AT91_PIN_PB29,
++static struct mci_platform_data __initdata rsi_ews_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB27,
++ .wp_pin = AT91_PIN_PB29,
++ },
+ };
+
+ /*
+@@ -215,7 +216,7 @@ static void __init rsi_ews_board_init(void)
+ at91_add_device_spi(rsi_ews_spi_devices,
+ ARRAY_SIZE(rsi_ews_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &rsi_ews_mmc_data);
++ at91_add_device_mci(0, &rsi_ews_mci0_data);
+ /* NOR Flash */
+ platform_device_register(&rsiews_nor_flash);
+ /* LEDs */
+diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
+index 7bf6da7..3573f10 100644
+--- a/arch/arm/mach-at91/board-sam9-l9260.c
++++ b/arch/arm/mach-at91/board-sam9-l9260.c
+@@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -158,12 +158,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC8,
+- .wp_pin = AT91_PIN_PC4,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PC8,
++ .wp_pin = AT91_PIN_PC4,
++ },
+ };
+
+ static void __init ek_board_init(void)
+@@ -194,7 +194,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(NULL, 0);
+ }
+diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
+index 889c1bf..8cd6e67 100644
+--- a/arch/arm/mach-at91/board-sam9260ek.c
++++ b/arch/arm/mach-at91/board-sam9260ek.c
+@@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void)
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata ek_mci0_data = {
++ .slot[1] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -329,7 +329,7 @@ static void __init ek_board_init(void)
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &ek_mci0_data);
+ /* I2C */
+ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+ /* SSC (to AT73C213) */
+diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
+index 2e1c9c5..b8900d5 100644
+--- a/arch/arm/mach-at91/board-sam9261ek.c
++++ b/arch/arm/mach-at91/board-sam9261ek.c
+@@ -342,11 +342,12 @@ static struct spi_board_info ek_spi_devices[] = {
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = -EINVAL,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ #endif /* CONFIG_SPI_ATMEL_* */
+@@ -600,7 +601,7 @@ static void __init ek_board_init(void)
+ at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
+ #else
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &mci0_data);
+ #endif
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
+index 7c34908..d4dd017 100644
+--- a/arch/arm/mach-at91/board-sam9263ek.c
++++ b/arch/arm/mach-at91/board-sam9263ek.c
+@@ -143,11 +143,12 @@ static struct spi_board_info ek_spi_devices[] = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PE18,
+- .wp_pin = AT91_PIN_PE19,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci1_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PE18,
++ .wp_pin = AT91_PIN_PE19,
++ },
+ };
+
+
+@@ -422,7 +423,7 @@ static void __init ek_board_init(void)
+ /* Touchscreen */
+ ek_add_device_ts();
+ /* MMC */
+- at91_add_device_mmc(1, &ek_mmc_data);
++ at91_add_device_mci(1, &mci1_data);
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* NAND */
+diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
+index da6d019..50dc86d 100644
+--- a/arch/arm/mach-at91/board-sam9g20ek.c
++++ b/arch/arm/mach-at91/board-sam9g20ek.c
+@@ -90,7 +90,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
+ * SPI devices.
+ */
+ static struct spi_board_info ek_spi_devices[] = {
+-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
++#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+@@ -197,7 +197,6 @@ static void __init ek_add_device_nand(void)
+ * MCI (SD/MMC)
+ * wp_pin and vcc_pin are not connected
+ */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ static struct mci_platform_data __initdata ek_mmc_data = {
+ .slot[1] = {
+ .bus_width = 4,
+@@ -206,28 +205,15 @@ static struct mci_platform_data __initdata ek_mmc_data = {
+ },
+
+ };
+-#else
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .slot_b = 1, /* Only one slot so use slot B */
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PC9,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
+-};
+-#endif
+
+ static void __init ek_add_device_mmc(void)
+ {
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ if (ek_have_2mmc()) {
+ ek_mmc_data.slot[0].bus_width = 4;
+ ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
+ ek_mmc_data.slot[0].wp_pin = -1;
+ }
+ at91_add_device_mci(0, &ek_mmc_data);
+-#else
+- at91_add_device_mmc(0, &ek_mmc_data);
+-#endif
+ }
+
+ /*
+diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
+index 81d82be..628fec9 100644
+--- a/arch/arm/mach-at91/board-sam9rlek.c
++++ b/arch/arm/mach-at91/board-sam9rlek.c
+@@ -58,11 +58,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = {
+ /*
+ * MCI (SD/MMC)
+ */
+-static struct at91_mmc_data __initdata ek_mmc_data = {
+- .wire4 = 1,
+- .det_pin = AT91_PIN_PA15,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PA15,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+
+@@ -305,7 +306,7 @@ static void __init ek_board_init(void)
+ /* SPI */
+ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &ek_mmc_data);
++ at91_add_device_mci(0, &mci0_data);
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* AC97 */
+diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
+index 29eae16..c3fb31d 100644
+--- a/arch/arm/mach-at91/board-stamp9g20.c
++++ b/arch/arm/mach-at91/board-stamp9g20.c
+@@ -83,7 +83,6 @@ static void __init add_device_nand(void)
+ * MCI (SD/MMC)
+ * det_pin, wp_pin and vcc_pin are not connected
+ */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ static struct mci_platform_data __initdata mmc_data = {
+ .slot[0] = {
+ .bus_width = 4,
+@@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = {
+ .wp_pin = -1,
+ },
+ };
+-#else
+-static struct at91_mmc_data __initdata mmc_data = {
+- .slot_b = 0,
+- .wire4 = 1,
+- .det_pin = -EINVAL,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
+-};
+-#endif
+
+
+ /*
+@@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void)
+ /* NAND */
+ add_device_nand();
+ /* MMC */
+-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+ at91_add_device_mci(0, &mmc_data);
+-#else
+- at91_add_device_mmc(0, &mmc_data);
+-#endif
+ /* W1 */
+ add_w1();
+ }
+diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
+index c1476b9..6ea069b 100644
+--- a/arch/arm/mach-at91/board-usb-a926x.c
++++ b/arch/arm/mach-at91/board-usb-a926x.c
+@@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = {
+ * SPI devices.
+ */
+ static struct spi_board_info usb_a9263_spi_devices[] = {
+-#if !defined(CONFIG_MMC_AT91)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 0,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ }
+-#endif
+ };
+
+ static struct spi_board_info usb_a9g20_spi_devices[] = {
+diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
+index 516d340..2355de2 100644
+--- a/arch/arm/mach-at91/board-yl-9200.c
++++ b/arch/arm/mach-at91/board-yl-9200.c
+@@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = {
+ /*
+ * MMC
+ */
+-static struct at91_mmc_data __initdata yl9200_mmc_data = {
+- .det_pin = AT91_PIN_PB9,
+- .wire4 = 1,
+- .wp_pin = -EINVAL,
+- .vcc_pin = -EINVAL,
++static struct mci_platform_data __initdata yl9200_mci0_data = {
++ .slot[0] = {
++ .bus_width = 4,
++ .detect_pin = AT91_PIN_PB9,
++ .wp_pin = -EINVAL,
++ },
+ };
+
+ /*
+@@ -568,7 +569,7 @@ static void __init yl9200_board_init(void)
+ /* I2C */
+ at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
+ /* MMC */
+- at91_add_device_mmc(0, &yl9200_mmc_data);
++ at91_add_device_mci(0, &yl9200_mci0_data);
+ /* NAND */
+ at91_add_device_nand(&yl9200_nand_data);
+ /* NOR Flash */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 07e35236641fb67d7ca946a68335141989d5c8a1 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 24 Jul 2012 09:32:29 +0200
-Subject: mmc: atmel-mci: not busy flag has also to be used for read operations
-
-Even if the datasheet says that the not busy flag has to be used only for
-write operations, it's false excepted for version lesser than v2xx.
-Not waiting the not busy flag for read operations can cause the controller to
-hang-up during some SD card initialization.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/mmc/host/atmel-mci.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
-index 05a293e..3d9c7b8 100644
---- a/drivers/mmc/host/atmel-mci.c
-+++ b/drivers/mmc/host/atmel-mci.c
-@@ -84,6 +84,7 @@ struct atmel_mci_caps {
- bool has_bad_data_ordering;
- bool need_reset_after_xfer;
- bool need_blksz_mul_4;
-+ bool need_notbusy_for_read_ops;
- };
-
- struct atmel_mci_dma {
-@@ -1694,7 +1695,8 @@ static void atmci_tasklet_func(unsigned long priv)
- __func__);
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
-
-- if (host->data->flags & MMC_DATA_WRITE) {
-+ if (host->caps.need_notbusy_for_read_ops
-+ || (host->data->flags & MMC_DATA_WRITE)) {
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- state = STATE_WAITING_NOTBUSY;
- } else if (host->mrq->stop) {
-@@ -2294,6 +2296,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
- host->caps.has_bad_data_ordering = 1;
- host->caps.need_reset_after_xfer = 1;
- host->caps.need_blksz_mul_4 = 1;
-+ host->caps.need_notbusy_for_read_ops = 0;
-
- /* keep only major version number */
- switch (version & 0xf00) {
-@@ -2314,6 +2317,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
- case 0x200:
- host->caps.has_rwproof = 1;
- host->caps.need_blksz_mul_4 = 0;
-+ host->caps.need_notbusy_for_read_ops = 1;
- case 0x100:
- host->caps.has_bad_data_ordering = 0;
- host->caps.need_reset_after_xfer = 0;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 92fd4e4886274f462ffdb6eb350fa2b851e2f263 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 2 Jul 2012 17:15:58 +0200
+Subject: ARM: at91/defconfig: change the MCI driver to use in defconfigs
+
+commit 24f5c4b6e6f2933eb22979283db6174f378d9b36 upstream.
+
+Since atmel-mci driver supports all atmel mci versions,
+use it instead of the deprecated at91_mci driver.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/configs/at91rm9200_defconfig | 2 +-
+ arch/arm/configs/at91sam9261_defconfig | 2 +-
+ arch/arm/configs/at91sam9263_defconfig | 2 +-
+ arch/arm/configs/at91sam9g20_defconfig | 2 +-
+ arch/arm/configs/at91sam9rl_defconfig | 2 +-
+ arch/arm/configs/cpu9260_defconfig | 2 +-
+ arch/arm/configs/cpu9g20_defconfig | 2 +-
+ arch/arm/configs/qil-a9260_defconfig | 2 +-
+ arch/arm/configs/stamp9g20_defconfig | 1 -
+ 9 files changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
+index d54e2ac..4ae57a3 100644
+--- a/arch/arm/configs/at91rm9200_defconfig
++++ b/arch/arm/configs/at91rm9200_defconfig
+@@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_USB_MASS_STORAGE=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=y
++CONFIG_MMC_ATMELMCI=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9261_defconfig b/arch/arm/configs/at91sam9261_defconfig
+index ade6b2f..1e8712e 100644
+--- a/arch/arm/configs/at91sam9261_defconfig
++++ b/arch/arm/configs/at91sam9261_defconfig
+@@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
+index 585e7e0..d2050ca 100644
+--- a/arch/arm/configs/at91sam9263_defconfig
++++ b/arch/arm/configs/at91sam9263_defconfig
+@@ -137,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+ CONFIG_SDIO_UART=m
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_ATMEL_PWM=y
+diff --git a/arch/arm/configs/at91sam9g20_defconfig b/arch/arm/configs/at91sam9g20_defconfig
+index 994d331..e1b0e80 100644
+--- a/arch/arm/configs/at91sam9g20_defconfig
++++ b/arch/arm/configs/at91sam9g20_defconfig
+@@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig
+index ad562ee..7cf8785 100644
+--- a/arch/arm/configs/at91sam9rl_defconfig
++++ b/arch/arm/configs/at91sam9rl_defconfig
+@@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y
+ CONFIG_FB=y
+ CONFIG_FB_ATMEL=y
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_RTC_CLASS=y
+ CONFIG_RTC_DRV_AT91SAM9=y
+ CONFIG_EXT2_FS=y
+diff --git a/arch/arm/configs/cpu9260_defconfig b/arch/arm/configs/cpu9260_defconfig
+index bbf729e..921480c 100644
+--- a/arch/arm/configs/cpu9260_defconfig
++++ b/arch/arm/configs/cpu9260_defconfig
+@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/cpu9g20_defconfig b/arch/arm/configs/cpu9g20_defconfig
+index e7d7942..ea116cb 100644
+--- a/arch/arm/configs/cpu9g20_defconfig
++++ b/arch/arm/configs/cpu9g20_defconfig
+@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/qil-a9260_defconfig b/arch/arm/configs/qil-a9260_defconfig
+index 2bb100b..42d5db1 100644
+--- a/arch/arm/configs/qil-a9260_defconfig
++++ b/arch/arm/configs/qil-a9260_defconfig
+@@ -86,7 +86,7 @@ CONFIG_USB_STORAGE=y
+ CONFIG_USB_GADGET=y
+ CONFIG_USB_ETH=m
+ CONFIG_MMC=y
+-CONFIG_MMC_AT91=m
++CONFIG_MMC_ATMELMCI=m
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+ CONFIG_LEDS_GPIO=y
+diff --git a/arch/arm/configs/stamp9g20_defconfig b/arch/arm/configs/stamp9g20_defconfig
+index d5e260b..52f1488 100644
+--- a/arch/arm/configs/stamp9g20_defconfig
++++ b/arch/arm/configs/stamp9g20_defconfig
+@@ -100,7 +100,6 @@ CONFIG_USB_ETH=m
+ CONFIG_USB_FILE_STORAGE=m
+ CONFIG_USB_G_SERIAL=m
+ CONFIG_MMC=y
+-# CONFIG_MMC_AT91 is not set
+ CONFIG_MMC_ATMELMCI=y
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From e10db2b8116769c8b0ccdd53c424fac0bd7a2c64 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 15:52:48 +0200
-Subject: Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk
-
-The old driver used con_id clock entries. Convert to use dev_id
-for clock lookup via standard method.
-
-Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
-Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-
-Conflicts:
- arch/arm/mach-at91/at91sam9x5.c
----
- arch/arm/mach-at91/at91rm9200.c | 1 +
- arch/arm/mach-at91/at91sam9260.c | 1 +
- arch/arm/mach-at91/at91sam9261.c | 1 +
- arch/arm/mach-at91/at91sam9263.c | 1 +
- arch/arm/mach-at91/at91sam9g45.c | 2 ++
- arch/arm/mach-at91/at91sam9rl.c | 2 ++
- arch/arm/mach-at91/at91sam9x5.c | 3 +++
- 7 files changed, 11 insertions(+)
-
-diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
-index 6f50c67..f2112f9 100644
---- a/arch/arm/mach-at91/at91rm9200.c
-+++ b/arch/arm/mach-at91/at91rm9200.c
-@@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index 4696729..d824b0e 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -203,6 +203,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
-diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
-index f40762c..71ca1e0 100644
---- a/arch/arm/mach-at91/at91sam9261.c
-+++ b/arch/arm/mach-at91/at91sam9261.c
-@@ -178,6 +178,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index c82d521..00c947e 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index f6d0eab..5de8b00 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -222,6 +222,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
-diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
-index 72ce50a..bf79c1f 100644
---- a/arch/arm/mach-at91/at91sam9rl.c
-+++ b/arch/arm/mach-at91/at91sam9rl.c
-@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index 796b3c0..15ac57b 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -227,6 +227,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
- CLKDEV_CON_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 191188312560199aab82f13568cc1532035a3cf1 Mon Sep 17 00:00:00 2001
-From: Nikolaus Voss <n.voss@weinmann.de>
-Date: Tue, 8 Nov 2011 11:49:24 +0100
-Subject: i2c: at91: remove old polling driver
-
-It will get replaced by a superior one. Safe to remove since this one
-depends on BROKEN anyhow.
-
-Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
-Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-
-[wsa: added commit message]
-
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- arch/arm/mach-at91/include/mach/at91_twi.h | 68 -------
- drivers/i2c/busses/Makefile | 1 -
- drivers/i2c/busses/i2c-at91.c | 314 -----------------------------
- 3 files changed, 383 deletions(-)
- delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h
- delete mode 100644 drivers/i2c/busses/i2c-at91.c
-
-diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
-deleted file mode 100644
-index bb2880f..0000000
---- a/arch/arm/mach-at91/include/mach/at91_twi.h
-+++ /dev/null
-@@ -1,68 +0,0 @@
--/*
-- * arch/arm/mach-at91/include/mach/at91_twi.h
-- *
-- * Copyright (C) 2005 Ivan Kokshaysky
-- * Copyright (C) SAN People
-- *
-- * Two-wire Interface (TWI) registers.
-- * Based on AT91RM9200 datasheet revision E.
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; either version 2 of the License, or
-- * (at your option) any later version.
-- */
--
--#ifndef AT91_TWI_H
--#define AT91_TWI_H
--
--#define AT91_TWI_CR 0x00 /* Control Register */
--#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
--#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
--#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
--#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
--#define AT91_TWI_SVEN (1 << 4) /* Slave Transfer Enable [SAM9260 only] */
--#define AT91_TWI_SVDIS (1 << 5) /* Slave Transfer Disable [SAM9260 only] */
--#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
--
--#define AT91_TWI_MMR 0x04 /* Master Mode Register */
--#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
--#define AT91_TWI_IADRSZ_NO (0 << 8)
--#define AT91_TWI_IADRSZ_1 (1 << 8)
--#define AT91_TWI_IADRSZ_2 (2 << 8)
--#define AT91_TWI_IADRSZ_3 (3 << 8)
--#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
--#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
--
--#define AT91_TWI_SMR 0x08 /* Slave Mode Register [SAM9260 only] */
--#define AT91_TWI_SADR (0x7f << 16) /* Slave Address */
--
--#define AT91_TWI_IADR 0x0c /* Internal Address Register */
--
--#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
--#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
--#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
--#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
--
--#define AT91_TWI_SR 0x20 /* Status Register */
--#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
--#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
--#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
--#define AT91_TWI_SVREAD (1 << 3) /* Slave Read [SAM9260 only] */
--#define AT91_TWI_SVACC (1 << 4) /* Slave Access [SAM9260 only] */
--#define AT91_TWI_GACC (1 << 5) /* General Call Access [SAM9260 only] */
--#define AT91_TWI_OVRE (1 << 6) /* Overrun Error [AT91RM9200 only] */
--#define AT91_TWI_UNRE (1 << 7) /* Underrun Error [AT91RM9200 only] */
--#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
--#define AT91_TWI_ARBLST (1 << 9) /* Arbitration Lost [SAM9260 only] */
--#define AT91_TWI_SCLWS (1 << 10) /* Clock Wait State [SAM9260 only] */
--#define AT91_TWI_EOSACC (1 << 11) /* End of Slave Address [SAM9260 only] */
--
--#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
--#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
--#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
--#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
--#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
--
--#endif
--
-diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
-index 569567b..b74c801 100644
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -28,7 +28,6 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
- obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
-
- # Embedded system I2C/SMBus host controller drivers
--obj-$(CONFIG_I2C_AT91) += i2c-at91.o
- obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
- obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
- obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
-diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
-deleted file mode 100644
-index 1679dee..0000000
---- a/drivers/i2c/busses/i2c-at91.c
-+++ /dev/null
-@@ -1,314 +0,0 @@
--/*
-- i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
--
-- Copyright (C) 2004 Rick Bronson
-- Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
--
-- Borrowed heavily from original work by:
-- Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--*/
--
--#include <linux/module.h>
--#include <linux/kernel.h>
--#include <linux/err.h>
--#include <linux/slab.h>
--#include <linux/types.h>
--#include <linux/delay.h>
--#include <linux/i2c.h>
--#include <linux/init.h>
--#include <linux/clk.h>
--#include <linux/platform_device.h>
--#include <linux/io.h>
--
--#include <mach/at91_twi.h>
--#include <mach/board.h>
--#include <mach/cpu.h>
--
--#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
--
--
--static struct clk *twi_clk;
--static void __iomem *twi_base;
--
--#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
--#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
--
--
--/*
-- * Initialize the TWI hardware registers.
-- */
--static void __devinit at91_twi_hwinit(void)
--{
-- unsigned long cdiv, ckdiv;
--
-- at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
--
-- /* Calcuate clock dividers */
-- cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
-- cdiv = cdiv + 1; /* round up */
-- ckdiv = 0;
-- while (cdiv > 255) {
-- ckdiv++;
-- cdiv = cdiv >> 1;
-- }
--
-- if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
-- if (ckdiv > 5) {
-- printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
-- ckdiv = 5;
-- }
-- }
--
-- at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
--}
--
--/*
-- * Poll the i2c status register until the specified bit is set.
-- * Returns 0 if timed out (100 msec).
-- */
--static short at91_poll_status(unsigned long bit)
--{
-- int loop_cntr = 10000;
--
-- do {
-- udelay(10);
-- } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
--
-- return (loop_cntr > 0);
--}
--
--static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
--{
-- /* Send Start */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
--
-- /* Read data */
-- while (length--) {
-- if (!length) /* need to send Stop before reading last byte */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
-- if (!at91_poll_status(AT91_TWI_RXRDY)) {
-- dev_dbg(&adap->dev, "RXRDY timeout\n");
-- return -ETIMEDOUT;
-- }
-- *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
-- }
--
-- return 0;
--}
--
--static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
--{
-- /* Load first byte into transmitter */
-- at91_twi_write(AT91_TWI_THR, *buf++);
--
-- /* Send Start */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
--
-- do {
-- if (!at91_poll_status(AT91_TWI_TXRDY)) {
-- dev_dbg(&adap->dev, "TXRDY timeout\n");
-- return -ETIMEDOUT;
-- }
--
-- length--; /* byte was transmitted */
--
-- if (length > 0) /* more data to send? */
-- at91_twi_write(AT91_TWI_THR, *buf++);
-- } while (length);
--
-- /* Send Stop */
-- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
--
-- return 0;
--}
--
--/*
-- * Generic i2c master transfer entrypoint.
-- *
-- * Note: We do not use Atmel's feature of storing the "internal device address".
-- * Instead the "internal device address" has to be written using a separate
-- * i2c message.
-- * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
-- */
--static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
--{
-- int i, ret;
--
-- dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
--
-- for (i = 0; i < num; i++) {
-- dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
-- pmsg->flags & I2C_M_RD ? "read" : "writ",
-- pmsg->len, pmsg->len > 1 ? "s" : "",
-- pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
--
-- at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
-- | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
--
-- if (pmsg->len && pmsg->buf) { /* sanity check */
-- if (pmsg->flags & I2C_M_RD)
-- ret = xfer_read(adap, pmsg->buf, pmsg->len);
-- else
-- ret = xfer_write(adap, pmsg->buf, pmsg->len);
--
-- if (ret)
-- return ret;
--
-- /* Wait until transfer is finished */
-- if (!at91_poll_status(AT91_TWI_TXCOMP)) {
-- dev_dbg(&adap->dev, "TXCOMP timeout\n");
-- return -ETIMEDOUT;
-- }
-- }
-- dev_dbg(&adap->dev, "transfer complete\n");
-- pmsg++; /* next message */
-- }
-- return i;
--}
--
--/*
-- * Return list of supported functionality.
-- */
--static u32 at91_func(struct i2c_adapter *adapter)
--{
-- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
--}
--
--static struct i2c_algorithm at91_algorithm = {
-- .master_xfer = at91_xfer,
-- .functionality = at91_func,
--};
--
--/*
-- * Main initialization routine.
-- */
--static int __devinit at91_i2c_probe(struct platform_device *pdev)
--{
-- struct i2c_adapter *adapter;
-- struct resource *res;
-- int rc;
--
-- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- if (!res)
-- return -ENXIO;
--
-- if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
-- return -EBUSY;
--
-- twi_base = ioremap(res->start, resource_size(res));
-- if (!twi_base) {
-- rc = -ENOMEM;
-- goto fail0;
-- }
--
-- twi_clk = clk_get(NULL, "twi_clk");
-- if (IS_ERR(twi_clk)) {
-- dev_err(&pdev->dev, "no clock defined\n");
-- rc = -ENODEV;
-- goto fail1;
-- }
--
-- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
-- if (adapter == NULL) {
-- dev_err(&pdev->dev, "can't allocate inteface!\n");
-- rc = -ENOMEM;
-- goto fail2;
-- }
-- snprintf(adapter->name, sizeof(adapter->name), "AT91");
-- adapter->algo = &at91_algorithm;
-- adapter->class = I2C_CLASS_HWMON;
-- adapter->dev.parent = &pdev->dev;
-- /* adapter->id == 0 ... only one TWI controller for now */
--
-- platform_set_drvdata(pdev, adapter);
--
-- clk_enable(twi_clk); /* enable peripheral clock */
-- at91_twi_hwinit(); /* initialize TWI controller */
--
-- rc = i2c_add_numbered_adapter(adapter);
-- if (rc) {
-- dev_err(&pdev->dev, "Adapter %s registration failed\n",
-- adapter->name);
-- goto fail3;
-- }
--
-- dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
-- return 0;
--
--fail3:
-- platform_set_drvdata(pdev, NULL);
-- kfree(adapter);
-- clk_disable(twi_clk);
--fail2:
-- clk_put(twi_clk);
--fail1:
-- iounmap(twi_base);
--fail0:
-- release_mem_region(res->start, resource_size(res));
--
-- return rc;
--}
--
--static int __devexit at91_i2c_remove(struct platform_device *pdev)
--{
-- struct i2c_adapter *adapter = platform_get_drvdata(pdev);
-- struct resource *res;
-- int rc;
--
-- rc = i2c_del_adapter(adapter);
-- platform_set_drvdata(pdev, NULL);
--
-- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- iounmap(twi_base);
-- release_mem_region(res->start, resource_size(res));
--
-- clk_disable(twi_clk); /* disable peripheral clock */
-- clk_put(twi_clk);
--
-- return rc;
--}
--
--#ifdef CONFIG_PM
--
--/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
--
--static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
--{
-- clk_disable(twi_clk);
-- return 0;
--}
--
--static int at91_i2c_resume(struct platform_device *pdev)
--{
-- return clk_enable(twi_clk);
--}
--
--#else
--#define at91_i2c_suspend NULL
--#define at91_i2c_resume NULL
--#endif
--
--static struct platform_driver at91_i2c_driver = {
-- .probe = at91_i2c_probe,
-- .remove = __devexit_p(at91_i2c_remove),
-- .suspend = at91_i2c_suspend,
-- .resume = at91_i2c_resume,
-- .driver = {
-- .name = "at91_i2c",
-- .owner = THIS_MODULE,
-- },
--};
--
--module_platform_driver(at91_i2c_driver);
--
--MODULE_AUTHOR("Rick Bronson");
--MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
--MODULE_LICENSE("GPL");
--MODULE_ALIAS("platform:at91_i2c");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 66bca56097bd85e2969d9ef7df5e53b0dc51a258 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 24 Apr 2012 16:46:26 +0200
+Subject: mmc: atmel-mci: fix burst/chunk size modification
+
+commit 693e5e2025278d90e1427f037e5ec8ea1ec7d5c4 upstream.
+
+The use of DMA slave config operation requires that the burst size
+(aka chunk size) is specified through this interface.
+Modify atmel-mci slave driver to use this specification on its side.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci-regs.h | 14 ++++++++++++++
+ drivers/mmc/host/atmel-mci.c | 8 +++++---
+ 2 files changed, 19 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
+index 787aba1..ab56f7d 100644
+--- a/drivers/mmc/host/atmel-mci-regs.h
++++ b/drivers/mmc/host/atmel-mci-regs.h
+@@ -140,4 +140,18 @@
+ #define atmci_writel(port,reg,value) \
+ __raw_writel((value), (port)->regs + reg)
+
++/*
++ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
++ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
++ *
++ * This can be done by finding most significant bit set.
++ */
++static inline unsigned int atmci_convert_chksize(unsigned int maxburst)
++{
++ if (maxburst > 1)
++ return fls(maxburst) - 2;
++ else
++ return 0;
++}
++
+ #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 456c077..f2c115e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -910,6 +910,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
+ enum dma_data_direction direction;
+ enum dma_transfer_direction slave_dirn;
+ unsigned int sglen;
++ u32 maxburst;
+ u32 iflags;
+
+ data->error = -EINPROGRESS;
+@@ -943,17 +944,18 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
+ if (!chan)
+ return -ENODEV;
+
+- if (host->caps.has_dma)
+- atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN);
+-
+ if (data->flags & MMC_DATA_READ) {
+ direction = DMA_FROM_DEVICE;
+ host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
++ maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
+ } else {
+ direction = DMA_TO_DEVICE;
+ host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
++ maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
+ }
+
++ atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(maxburst) | ATMCI_DMAEN);
++
+ sglen = dma_map_sg(chan->device->dev, data->sg,
+ data->sg_len, direction);
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 1762cb01f6be4ddf6560eca0b2529901736d6cbb Mon Sep 17 00:00:00 2001
-From: Nikolaus Voss <n.voss@weinmann.de>
-Date: Tue, 8 Nov 2011 11:49:46 +0100
-Subject: i2c: at91: add new driver
-
-This driver has the following properties compared to the old driver:
-1. Support for multiple interfaces.
-2. Interrupt driven I/O as opposed to polling/busy waiting.
-3. Support for _one_ repeated start (Sr) condition, which is enough
- for most real-world applications including all SMBus transfer types.
- (The hardware does not support issuing arbitrary Sr conditions on the
- bus.)
-
-testing: SoC: at91sam9g45
- - BQ20Z80 battery SMBus client.
- - on a 2.6.38 kernel with several i2c clients (temp-sensor,
- audio-codec, touchscreen-controller, w1-bridge, io-expanders)
-
-Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
-Reviewed-by: Felipe Balbi <balbi@ti.com>
-Tested-by: Hubert Feurstein <h.feurstein@gmail.com>
-Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-
-[wsa: squashed with the following patches from Ludovic to have some flaws
-fixed:
- i2c: at91: use managed resources
- i2c: at91: add warning about transmission issues for some devices
- i2c: at91: use an id table for SoC dependent parameters
-]
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- arch/arm/mach-at91/at91rm9200.c | 2
- arch/arm/mach-at91/at91rm9200_devices.c | 2
- arch/arm/mach-at91/at91sam9260.c | 3
- arch/arm/mach-at91/at91sam9260_devices.c | 8
- arch/arm/mach-at91/at91sam9261.c | 3
- arch/arm/mach-at91/at91sam9261_devices.c | 8
- arch/arm/mach-at91/at91sam9263.c | 2
- arch/arm/mach-at91/at91sam9263_devices.c | 2
- arch/arm/mach-at91/at91sam9g45.c | 4
- arch/arm/mach-at91/at91sam9g45_devices.c | 4
- arch/arm/mach-at91/at91sam9rl.c | 4
- arch/arm/mach-at91/at91sam9rl_devices.c | 2
- drivers/i2c/busses/Kconfig | 17 -
- drivers/i2c/busses/Makefile | 1
- drivers/i2c/busses/i2c-at91.c | 505 +++++++++++++++++++++++++++++++
- 15 files changed, 545 insertions(+), 22 deletions(-)
- create mode 100644 drivers/i2c/busses/i2c-at91.c
-
---- a/arch/arm/mach-at91/at91rm9200.c
-+++ b/arch/arm/mach-at91/at91rm9200.c
-@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
---- a/arch/arm/mach-at91/at91rm9200_devices.c
-+++ b/arch/arm/mach-at91/at91rm9200_devices.c
-@@ -511,7 +511,7 @@ static struct resource twi_resources[] =
- };
-
- static struct platform_device at91rm9200_twi_device = {
-- .name = "at91_i2c",
-+ .name = "i2c-at91rm9200",
- .id = -1,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -203,7 +203,8 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
---- a/arch/arm/mach-at91/at91sam9260_devices.c
-+++ b/arch/arm/mach-at91/at91sam9260_devices.c
-@@ -418,7 +418,6 @@ static struct resource twi_resources[] =
- };
-
- static struct platform_device at91sam9260_twi_device = {
-- .name = "at91_i2c",
- .id = -1,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-@@ -426,6 +425,13 @@ static struct platform_device at91sam926
-
- void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
- {
-+ /* IP version is not the same on 9260 and g20 */
-+ if (cpu_is_at91sam9g20()) {
-+ at91sam9260_twi_device.name = "i2c-at91sam9g20";
-+ } else {
-+ at91sam9260_twi_device.name = "i2c-at91sam9260";
-+ }
-+
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA23, 1);
---- a/arch/arm/mach-at91/at91sam9261.c
-+++ b/arch/arm/mach-at91/at91sam9261.c
-@@ -178,7 +178,8 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
---- a/arch/arm/mach-at91/at91sam9261_devices.c
-+++ b/arch/arm/mach-at91/at91sam9261_devices.c
-@@ -319,7 +319,6 @@ static struct resource twi_resources[] =
- };
-
- static struct platform_device at91sam9261_twi_device = {
-- .name = "at91_i2c",
- .id = -1,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-@@ -327,6 +326,13 @@ static struct platform_device at91sam926
-
- void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
- {
-+ /* IP version is not the same on 9261 and g10 */
-+ if (cpu_is_at91sam9g10()) {
-+ at91sam9261_twi_device.name = "i2c-at91sam9g10";
-+ } else {
-+ at91sam9261_twi_device.name = "i2c-at91sam9261";
-+ }
-+
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA7, 1);
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
---- a/arch/arm/mach-at91/at91sam9263_devices.c
-+++ b/arch/arm/mach-at91/at91sam9263_devices.c
-@@ -601,7 +601,7 @@ static struct resource twi_resources[] =
- };
-
- static struct platform_device at91sam9263_twi_device = {
-- .name = "at91_i2c",
-+ .name = "i2c-at91sam9260",
- .id = -1,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -222,8 +222,8 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -651,7 +651,7 @@ static struct resource twi0_resources[]
- };
-
- static struct platform_device at91sam9g45_twi0_device = {
-- .name = "at91_i2c",
-+ .name = "i2c-at91sam9g10",
- .id = 0,
- .resource = twi0_resources,
- .num_resources = ARRAY_SIZE(twi0_resources),
-@@ -671,7 +671,7 @@ static struct resource twi1_resources[]
- };
-
- static struct platform_device at91sam9g45_twi1_device = {
-- .name = "at91_i2c",
-+ .name = "i2c-at91sam9g10",
- .id = 1,
- .resource = twi1_resources,
- .num_resources = ARRAY_SIZE(twi1_resources),
---- a/arch/arm/mach-at91/at91sam9rl.c
-+++ b/arch/arm/mach-at91/at91sam9rl.c
-@@ -186,8 +186,8 @@ static struct clk_lookup periph_clocks_l
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
---- a/arch/arm/mach-at91/at91sam9rl_devices.c
-+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
-@@ -348,7 +348,7 @@ static struct resource twi_resources[] =
- };
-
- static struct platform_device at91sam9rl_twi_device = {
-- .name = "at91_i2c",
-+ .name = "i2c-at91sam9g20",
- .id = -1,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -287,18 +287,21 @@ comment "I2C system bus drivers (mostly
-
- config I2C_AT91
- tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-- depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
-+ depends on ARCH_AT91 && EXPERIMENTAL
- help
- This supports the use of the I2C interface on Atmel AT91
- processors.
-
-- This driver is BROKEN because the controller which it uses
-- will easily trigger RX overrun and TX underrun errors. Using
-- low I2C clock rates may partially work around those issues
-- on some systems. Another serious problem is that there is no
-- documented way to issue repeated START conditions, as needed
-+ A serious problem is that there is no documented way to issue
-+ repeated START conditions for more than two messages, as needed
- to support combined I2C messages. Use the i2c-gpio driver
-- unless your system can cope with those limitations.
-+ unless your system can cope with this limitation.
-+
-+ Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
-+ don't have clock stretching in transmission mode. For that reason,
-+ you can encounter underrun issues causing premature stop sendings if
-+ the latency to fill the transmission register is too long. If you
-+ are facing this situation, use the i2c-gpio driver.
-
- config I2C_AU1550
- tristate "Au1550/Au1200/Au1300 SMBus interface"
---- a/drivers/i2c/busses/Makefile
-+++ b/drivers/i2c/busses/Makefile
-@@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
- obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
-
- # Embedded system I2C/SMBus host controller drivers
-+obj-$(CONFIG_I2C_AT91) += i2c-at91.o
- obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
- obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
- obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
---- /dev/null
-+++ b/drivers/i2c/busses/i2c-at91.c
-@@ -0,0 +1,505 @@
-+/*
-+ * i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
-+ *
-+ * Copyright (C) 2011 Weinmann Medical GmbH
-+ * Author: Nikolaus Voss <n.voss@weinmann.de>
-+ *
-+ * Evolved from original work by:
-+ * Copyright (C) 2004 Rick Bronson
-+ * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
-+ *
-+ * Borrowed heavily from original work by:
-+ * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/completion.h>
-+#include <linux/err.h>
-+#include <linux/i2c.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+
-+#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
-+#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
-+
-+/* AT91 TWI register definitions */
-+#define AT91_TWI_CR 0x0000 /* Control Register */
-+#define AT91_TWI_START 0x0001 /* Send a Start Condition */
-+#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */
-+#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */
-+#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */
-+#define AT91_TWI_SWRST 0x0080 /* Software Reset */
-+
-+#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
-+#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
-+#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */
-+
-+#define AT91_TWI_IADR 0x000c /* Internal Address Register */
-+
-+#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
-+
-+#define AT91_TWI_SR 0x0020 /* Status Register */
-+#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */
-+#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */
-+#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */
-+
-+#define AT91_TWI_OVRE 0x0040 /* Overrun Error */
-+#define AT91_TWI_UNRE 0x0080 /* Underrun Error */
-+#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */
-+
-+#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
-+#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
-+#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
-+#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
-+#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
-+
-+struct at91_twi_pdata {
-+ unsigned clk_max_div;
-+ unsigned clk_offset;
-+ bool has_unre_flag;
-+};
-+
-+struct at91_twi_dev {
-+ struct device *dev;
-+ void __iomem *base;
-+ struct completion cmd_complete;
-+ struct clk *clk;
-+ u8 *buf;
-+ size_t buf_len;
-+ struct i2c_msg *msg;
-+ int irq;
-+ unsigned transfer_status;
-+ struct i2c_adapter adapter;
-+ unsigned twi_cwgr_reg;
-+ struct at91_twi_pdata *pdata;
-+};
-+
-+static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
-+{
-+ return readl_relaxed(dev->base + reg);
-+}
-+
-+static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
-+{
-+ writel_relaxed(val, dev->base + reg);
-+}
-+
-+static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
-+{
-+ at91_twi_write(dev, AT91_TWI_IDR,
-+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
-+}
-+
-+static void at91_init_twi_bus(struct at91_twi_dev *dev)
-+{
-+ at91_disable_twi_interrupts(dev);
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
-+ at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
-+}
-+
-+/*
-+ * Calculate symmetric clock as stated in datasheet:
-+ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
-+ */
-+static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
-+{
-+ int ckdiv, cdiv, div;
-+ struct at91_twi_pdata *pdata = dev->pdata;
-+ int offset = pdata->clk_offset;
-+ int max_ckdiv = pdata->clk_max_div;
-+
-+ div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
-+ 2 * twi_clk) - offset);
-+ ckdiv = fls(div >> 8);
-+ cdiv = div >> ckdiv;
-+
-+ if (ckdiv > max_ckdiv) {
-+ dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
-+ ckdiv, max_ckdiv);
-+ ckdiv = max_ckdiv;
-+ cdiv = 255;
-+ }
-+
-+ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
-+ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
-+}
-+
-+static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
-+{
-+ if (dev->buf_len <= 0)
-+ return;
-+
-+ at91_twi_write(dev, AT91_TWI_THR, *dev->buf);
-+
-+ /* send stop when last byte has been written */
-+ if (--dev->buf_len == 0)
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
-+
-+ dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
-+
-+ ++dev->buf;
-+}
-+
-+static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
-+{
-+ if (dev->buf_len <= 0)
-+ return;
-+
-+ *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
-+ --dev->buf_len;
-+
-+ /* handle I2C_SMBUS_BLOCK_DATA */
-+ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
-+ dev->msg->flags &= ~I2C_M_RECV_LEN;
-+ dev->buf_len += *dev->buf;
-+ dev->msg->len = dev->buf_len + 1;
-+ dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
-+ }
-+
-+ /* send stop if second but last byte has been read */
-+ if (dev->buf_len == 1)
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
-+
-+ dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
-+
-+ ++dev->buf;
-+}
-+
-+static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
-+{
-+ struct at91_twi_dev *dev = dev_id;
-+ const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
-+ const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
-+
-+ if (!irqstatus)
-+ return IRQ_NONE;
-+ else if (irqstatus & AT91_TWI_RXRDY)
-+ at91_twi_read_next_byte(dev);
-+ else if (irqstatus & AT91_TWI_TXRDY)
-+ at91_twi_write_next_byte(dev);
-+
-+ /* catch error flags */
-+ dev->transfer_status |= status;
-+
-+ if (irqstatus & AT91_TWI_TXCOMP) {
-+ at91_disable_twi_interrupts(dev);
-+ complete(&dev->cmd_complete);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int at91_do_twi_transfer(struct at91_twi_dev *dev)
-+{
-+ int ret;
-+ bool has_unre_flag = dev->pdata->has_unre_flag;
-+
-+ dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
-+ (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
-+
-+ INIT_COMPLETION(dev->cmd_complete);
-+ dev->transfer_status = 0;
-+ if (dev->msg->flags & I2C_M_RD) {
-+ unsigned start_flags = AT91_TWI_START;
-+
-+ if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
-+ dev_err(dev->dev, "RXRDY still set!");
-+ at91_twi_read(dev, AT91_TWI_RHR);
-+ }
-+
-+ /* if only one byte is to be read, immediately stop transfer */
-+ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
-+ start_flags |= AT91_TWI_STOP;
-+ at91_twi_write(dev, AT91_TWI_CR, start_flags);
-+ at91_twi_write(dev, AT91_TWI_IER,
-+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
-+ } else {
-+ at91_twi_write_next_byte(dev);
-+ at91_twi_write(dev, AT91_TWI_IER,
-+ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
-+ }
-+
-+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
-+ dev->adapter.timeout);
-+ if (ret == 0) {
-+ dev_err(dev->dev, "controller timed out\n");
-+ at91_init_twi_bus(dev);
-+ return -ETIMEDOUT;
-+ }
-+ if (dev->transfer_status & AT91_TWI_NACK) {
-+ dev_dbg(dev->dev, "received nack\n");
-+ return -EREMOTEIO;
-+ }
-+ if (dev->transfer_status & AT91_TWI_OVRE) {
-+ dev_err(dev->dev, "overrun while reading\n");
-+ return -EIO;
-+ }
-+ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
-+ dev_err(dev->dev, "underrun while writing\n");
-+ return -EIO;
-+ }
-+ dev_dbg(dev->dev, "transfer complete\n");
-+
-+ return 0;
-+}
-+
-+static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
-+{
-+ struct at91_twi_dev *dev = i2c_get_adapdata(adap);
-+ int ret;
-+ unsigned int_addr_flag = 0;
-+ struct i2c_msg *m_start = msg;
-+
-+ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
-+
-+ /*
-+ * The hardware can handle at most two messages concatenated by a
-+ * repeated start via it's internal address feature.
-+ */
-+ if (num > 2) {
-+ dev_err(dev->dev,
-+ "cannot handle more than two concatenated messages.\n");
-+ return 0;
-+ } else if (num == 2) {
-+ int internal_address = 0;
-+ int i;
-+
-+ if (msg->flags & I2C_M_RD) {
-+ dev_err(dev->dev, "first transfer must be write.\n");
-+ return -EINVAL;
-+ }
-+ if (msg->len > 3) {
-+ dev_err(dev->dev, "first message size must be <= 3.\n");
-+ return -EINVAL;
-+ }
-+
-+ /* 1st msg is put into the internal address, start with 2nd */
-+ m_start = &msg[1];
-+ for (i = 0; i < msg->len; ++i) {
-+ const unsigned addr = msg->buf[msg->len - 1 - i];
-+
-+ internal_address |= addr << (8 * i);
-+ int_addr_flag += AT91_TWI_IADRSZ_1;
-+ }
-+ at91_twi_write(dev, AT91_TWI_IADR, internal_address);
-+ }
-+
-+ at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag
-+ | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
-+
-+ dev->buf_len = m_start->len;
-+ dev->buf = m_start->buf;
-+ dev->msg = m_start;
-+
-+ ret = at91_do_twi_transfer(dev);
-+
-+ return (ret < 0) ? ret : num;
-+}
-+
-+static u32 at91_twi_func(struct i2c_adapter *adapter)
-+{
-+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
-+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
-+}
-+
-+static struct i2c_algorithm at91_twi_algorithm = {
-+ .master_xfer = at91_twi_xfer,
-+ .functionality = at91_twi_func,
-+};
-+
-+static struct at91_twi_pdata at91rm9200_config = {
-+ .clk_max_div = 5,
-+ .clk_offset = 3,
-+ .has_unre_flag = true,
-+};
-+
-+static struct at91_twi_pdata at91sam9261_config = {
-+ .clk_max_div = 5,
-+ .clk_offset = 4,
-+ .has_unre_flag = false,
-+};
-+
-+static struct at91_twi_pdata at91sam9260_config = {
-+ .clk_max_div = 7,
-+ .clk_offset = 4,
-+ .has_unre_flag = false,
-+};
-+
-+static struct at91_twi_pdata at91sam9g20_config = {
-+ .clk_max_div = 7,
-+ .clk_offset = 4,
-+ .has_unre_flag = false,
-+};
-+
-+static struct at91_twi_pdata at91sam9g10_config = {
-+ .clk_max_div = 7,
-+ .clk_offset = 4,
-+ .has_unre_flag = false,
-+};
-+
-+static const struct platform_device_id at91_twi_devtypes[] = {
-+ {
-+ .name = "i2c-at91rm9200",
-+ .driver_data = (unsigned long) &at91rm9200_config,
-+ }, {
-+ .name = "i2c-at91sam9261",
-+ .driver_data = (unsigned long) &at91sam9261_config,
-+ }, {
-+ .name = "i2c-at91sam9260",
-+ .driver_data = (unsigned long) &at91sam9260_config,
-+ }, {
-+ .name = "i2c-at91sam9g20",
-+ .driver_data = (unsigned long) &at91sam9g20_config,
-+ }, {
-+ .name = "i2c-at91sam9g10",
-+ .driver_data = (unsigned long) &at91sam9g10_config,
-+ }, {
-+ /* sentinel */
-+ }
-+};
-+
-+static int __devinit at91_twi_probe(struct platform_device *pdev)
-+{
-+ struct at91_twi_dev *dev;
-+ struct resource *mem;
-+ int rc;
-+
-+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-+ if (!dev)
-+ return -ENOMEM;
-+ init_completion(&dev->cmd_complete);
-+ dev->dev = &pdev->dev;
-+
-+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!mem)
-+ return -ENODEV;
-+
-+ dev->pdata = at91_twi_get_driver_data(pdev);
-+ if (!dev->pdata)
-+ return -ENODEV;
-+
-+ dev->base = devm_request_and_ioremap(&pdev->dev, mem);
-+ if (!dev->base)
-+ return -EBUSY;
-+
-+ dev->irq = platform_get_irq(pdev, 0);
-+ if (dev->irq < 0)
-+ return dev->irq;
-+
-+ rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
-+ dev_name(dev->dev), dev);
-+ if (rc) {
-+ dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
-+ return rc;
-+ }
-+
-+ platform_set_drvdata(pdev, dev);
-+
-+ dev->clk = devm_clk_get(dev->dev, NULL);
-+ if (IS_ERR(dev->clk)) {
-+ dev_err(dev->dev, "no clock defined\n");
-+ return -ENODEV;
-+ }
-+ clk_prepare_enable(dev->clk);
-+
-+ at91_calc_twi_clock(dev, TWI_CLK_HZ);
-+ at91_init_twi_bus(dev);
-+
-+ snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
-+ i2c_set_adapdata(&dev->adapter, dev);
-+ dev->adapter.owner = THIS_MODULE;
-+ dev->adapter.class = I2C_CLASS_HWMON;
-+ dev->adapter.algo = &at91_twi_algorithm;
-+ dev->adapter.dev.parent = dev->dev;
-+ dev->adapter.nr = pdev->id;
-+ dev->adapter.timeout = AT91_I2C_TIMEOUT;
-+
-+ rc = i2c_add_numbered_adapter(&dev->adapter);
-+ if (rc) {
-+ dev_err(dev->dev, "Adapter %s registration failed\n",
-+ dev->adapter.name);
-+ clk_disable_unprepare(dev->clk);
-+ return rc;
-+ }
-+
-+ dev_info(dev->dev, "AT91 i2c bus driver.\n");
-+ return 0;
-+}
-+
-+static int __devexit at91_twi_remove(struct platform_device *pdev)
-+{
-+ struct at91_twi_dev *dev = platform_get_drvdata(pdev);
-+ int rc;
-+
-+ rc = i2c_del_adapter(&dev->adapter);
-+ clk_disable_unprepare(dev->clk);
-+
-+ return rc;
-+}
-+
-+#ifdef CONFIG_PM
-+
-+static int at91_twi_runtime_suspend(struct device *dev)
-+{
-+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
-+
-+ clk_disable(twi_dev->clk);
-+
-+ return 0;
-+}
-+
-+static int at91_twi_runtime_resume(struct device *dev)
-+{
-+ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
-+
-+ return clk_enable(twi_dev->clk);
-+}
-+
-+static const struct dev_pm_ops at91_twi_pm = {
-+ .runtime_suspend = at91_twi_runtime_suspend,
-+ .runtime_resume = at91_twi_runtime_resume,
-+};
-+
-+#define at91_twi_pm_ops (&at91_twi_pm)
-+#else
-+#define at91_twi_pm_ops NULL
-+#endif
-+
-+static struct platform_driver at91_twi_driver = {
-+ .probe = at91_twi_probe,
-+ .remove = __devexit_p(at91_twi_remove),
-+ .id_table = at91_twi_devtypes,
-+ .driver = {
-+ .name = "at91_i2c",
-+ .owner = THIS_MODULE,
-+ .pm = at91_twi_pm_ops,
-+ },
-+};
-+
-+static int __init at91_twi_init(void)
-+{
-+ return platform_driver_register(&at91_twi_driver);
-+}
-+
-+static void __exit at91_twi_exit(void)
-+{
-+ platform_driver_unregister(&at91_twi_driver);
-+}
-+
-+subsys_initcall(at91_twi_init);
-+module_exit(at91_twi_exit);
-+
-+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
-+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:at91_i2c");
--- /dev/null
+From d7950b4e5a002a389587c0c85ef326a61ef1ef3d Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 20 Mar 2012 18:41:48 +0100
+Subject: mmc: atmel-mci: add device tree support
+
+commit e919fd200033e80b26f152d22c00a8fae7f8d548 upstream.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ .../devicetree/bindings/mmc/atmel-hsmci.txt | 67 +++++++++++++++++
+ drivers/mmc/host/atmel-mci.c | 85 +++++++++++++++++++++-
+ 2 files changed, 150 insertions(+), 2 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+
+diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+new file mode 100644
+index 0000000..81c20cc
+--- /dev/null
++++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
+@@ -0,0 +1,67 @@
++* Atmel High Speed MultiMedia Card Interface
++
++This controller on atmel products provides an interface for MMC, SD and SDIO
++types of memory cards.
++
++1) MCI node
++
++Required properties:
++- compatible: no blank "atmel,hsmci"
++- reg: should contain HSMCI registers location and length
++- interrupts: should contain HSMCI interrupt number
++- #address-cells: should be one. The cell is the slot id.
++- #size-cells: should be zero.
++- at least one slot node
++
++The node contains child nodes for each slot that the platform uses
++
++Example MCI node:
++
++mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ [ child node definitions...]
++};
++
++2) slot nodes
++
++Required properties:
++- reg: should contain the slot id.
++- bus-width: number of data lines connected to the controller
++
++Optional properties:
++- cd-gpios: specify GPIOs for card detection
++- cd-inverted: invert the value of external card detect gpio line
++- wp-gpios: specify GPIOs for write protection
++
++Example slot node:
++
++slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>
++ cd-inverted;
++};
++
++Example full MCI node:
++mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>
++ cd-inverted;
++ };
++ slot@1 {
++ reg = <1>;
++ bus-width = <4>;
++ };
++};
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index f2c115e..47421fc 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -19,6 +19,9 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioport.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_gpio.h>
+ #include <linux/platform_device.h>
+ #include <linux/scatterlist.h>
+ #include <linux/seq_file.h>
+@@ -493,6 +496,70 @@ err:
+ dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
+ }
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmci_dt_ids[] = {
++ { .compatible = "atmel,hsmci" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmci_dt_ids);
++
++static struct mci_platform_data __devinit*
++atmci_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *cnp;
++ struct mci_platform_data *pdata;
++ u32 slot_id;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ for_each_child_of_node(np, cnp) {
++ if (of_property_read_u32(cnp, "reg", &slot_id)) {
++ dev_warn(&pdev->dev, "reg property is missing for %s\n",
++ cnp->full_name);
++ continue;
++ }
++
++ if (slot_id >= ATMCI_MAX_NR_SLOTS) {
++ dev_warn(&pdev->dev, "can't have more than %d slots\n",
++ ATMCI_MAX_NR_SLOTS);
++ break;
++ }
++
++ if (of_property_read_u32(cnp, "bus-width",
++ &pdata->slot[slot_id].bus_width))
++ pdata->slot[slot_id].bus_width = 1;
++
++ pdata->slot[slot_id].detect_pin =
++ of_get_named_gpio(cnp, "cd-gpios", 0);
++
++ pdata->slot[slot_id].detect_is_active_high =
++ of_property_read_bool(cnp, "cd-inverted");
++
++ pdata->slot[slot_id].wp_pin =
++ of_get_named_gpio(cnp, "wp-gpios", 0);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct mci_platform_data*
++atmci_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
+ static inline unsigned int atmci_get_version(struct atmel_mci *host)
+ {
+ return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
+@@ -2038,6 +2105,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
+ slot->sdc_reg = sdc_reg;
+ slot->sdio_irq = sdio_irq;
+
++ dev_dbg(&mmc->class_dev,
++ "slot[%u]: bus_width=%u, detect_pin=%d, "
++ "detect_is_active_high=%s, wp_pin=%d\n",
++ id, slot_data->bus_width, slot_data->detect_pin,
++ slot_data->detect_is_active_high ? "true" : "false",
++ slot_data->wp_pin);
++
+ mmc->ops = &atmci_ops;
+ mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+ mmc->f_max = host->bus_hz / 2;
+@@ -2258,8 +2332,14 @@ static int __init atmci_probe(struct platform_device *pdev)
+ if (!regs)
+ return -ENXIO;
+ pdata = pdev->dev.platform_data;
+- if (!pdata)
+- return -ENXIO;
++ if (!pdata) {
++ pdata = atmci_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ return PTR_ERR(pdata);
++ }
++ }
++
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+@@ -2477,6 +2557,7 @@ static struct platform_driver atmci_driver = {
+ .driver = {
+ .name = "atmel_mci",
+ .pm = ATMCI_PM_OPS,
++ .of_match_table = of_match_ptr(atmci_dt_ids),
+ },
+ };
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 51bec071d4a9c3202e5d03821f12659a46866ad6 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 22 May 2012 11:38:26 +0200
+Subject: ARM: at91: add clocks for DT entries
+
+Add clocks to clock lookup table for DT entries.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 2 ++
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9n12.c | 1 +
+ arch/arm/mach-at91/at91sam9x5.c | 2 ++
+ 5 files changed, 8 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index c644131..4696729 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -219,6 +219,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 144ef5d..c82d521 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -210,6 +210,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 55d2959..f6d0eab 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -236,6 +236,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index 0849466..cce4e0f 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -168,6 +168,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 7eb00c53..796b3c0 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -225,6 +225,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
++ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 2994ada46baa5d0444b4ac86a50addd9550480e6 Mon Sep 17 00:00:00 2001
-From: Nikolaus Voss <n.voss@weinmann.de>
-Date: Tue, 8 Nov 2011 12:11:03 +0100
-Subject: arm: at91: G45 TWI: remove open drain setting for twi function gpios
-
-The G45 datasheets explicitly states that setting the open drain property
-on peripheral function gpios is not allowed. (How about other A91 chips?)
-
-Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
-Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- arch/arm/mach-at91/at91sam9g45_devices.c | 6 ------
- 1 file changed, 6 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
-index 4223d28..29f334c 100644
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -684,18 +684,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in
- /* pins used for TWI interface */
- if (i2c_id == 0) {
- at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
-- at91_set_multi_drive(AT91_PIN_PA20, 1);
--
- at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
-- at91_set_multi_drive(AT91_PIN_PA21, 1);
-
- platform_device_register(&at91sam9g45_twi0_device);
- } else {
- at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
-- at91_set_multi_drive(AT91_PIN_PB10, 1);
--
- at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
-- at91_set_multi_drive(AT91_PIN_PB11, 1);
-
- platform_device_register(&at91sam9g45_twi1_device);
- }
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From c4eb8fe58495048f1bde1cb26dcab0e8db89b552 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 12 Sep 2012 08:42:13 +0200
-Subject: ARM: at91: do not configure at91sam9g10 twi pio as open-drain
-
-As indicated in the datasheet, TWD and TWCK must not be programmed as
-open-drain.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nikolaus Voss <n.voss@weinmann.de>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- arch/arm/mach-at91/at91sam9261_devices.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
-index 3d7b2f4..d2ae522 100644
---- a/arch/arm/mach-at91/at91sam9261_devices.c
-+++ b/arch/arm/mach-at91/at91sam9261_devices.c
-@@ -329,16 +329,16 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
- /* IP version is not the same on 9261 and g10 */
- if (cpu_is_at91sam9g10()) {
- at91sam9261_twi_device.name = "i2c-at91sam9g10";
-+ /* I2C PIO must not be configured as open-drain on this chip */
- } else {
- at91sam9261_twi_device.name = "i2c-at91sam9261";
-+ at91_set_multi_drive(AT91_PIN_PA7, 1);
-+ at91_set_multi_drive(AT91_PIN_PA8, 1);
- }
-
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
-- at91_set_multi_drive(AT91_PIN_PA7, 1);
--
- at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
-- at91_set_multi_drive(AT91_PIN_PA8, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9261_twi_device);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f71ff4055fb6e030293b84faa33e61123cc7b3a2 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 24 May 2012 16:58:42 +0200
+Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel SOCs
+
+Add mci controller nodes to atmel SOCs.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+
+ arch/arm/boot/dts/at91sam9260.dtsi
+ arch/arm/boot/dts/at91sam9g45.dtsi
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9263.dtsi | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 18 ++++++++++++++++++
+ 5 files changed, 72 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 12df8ca..1f2c7d0 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -201,6 +201,15 @@
+ interrupts = <10 4 2>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fffa8000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfffa800 0x600>;
++ interrupts = <9 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 195019b..a76f6cd 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -185,6 +185,24 @@
+ interrupts = <24 4 2>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fff80000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff80000 0x600>;
++ interrupts = <10 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@fff84000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff84000 0x600>;
++ interrupts = <11 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 6a3ed54..4b833d4 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -205,6 +205,24 @@
+ interrupts = <25 4 3>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@fff80000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfff80000 0x600>;
++ interrupts = <11 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@fffd0000 {
++ compatible = "atmel,hsmci";
++ reg = <0xfffd0000 0x600>;
++ interrupts = <29 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index ef9336a..aead257 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -82,6 +82,15 @@
+ reg = <0xfffffe10 0x10>;
+ };
+
++ mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index fc38d21..1be3df7 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -195,6 +195,24 @@
+ interrupts = <27 4 3>;
+ status = "disabled";
+ };
++
++ mmc0: mmc@f0008000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf0008000 0x600>;
++ interrupts = <12 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ mmc1: mmc@f000c000 {
++ compatible = "atmel,hsmci";
++ reg = <0xf000c000 0x600>;
++ interrupts = <26 4>;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From ca13863c856e2bf24c72539444a06237ce6834fb Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Thu, 24 May 2012 17:01:19 +0200
+Subject: ARM: dts: add nodes for atmel hsmci controllers for atmel boards
+
+Add mci controller nodes to atmel boards.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9263ek.dts | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9g20ek_2mmc.dts | 12 ++++++++++++
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 9 +++++++++
+ arch/arm/boot/dts/at91sam9g25ek.dts | 18 ++++++++++++++++++
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 19 +++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12ek.dts | 9 +++++++++
+ 6 files changed, 77 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
+index f86ac4b..05028ed 100644
+--- a/arch/arm/boot/dts/at91sam9263ek.dts
++++ b/arch/arm/boot/dts/at91sam9263ek.dts
+@@ -50,6 +50,16 @@
+ atmel,vbus-gpio = <&pioA 25 0>;
+ status = "okay";
+ };
++
++ mmc0: mmc@fff80000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioE 18 0>;
++ wp-gpios = <&pioE 19 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+index f1b2e14..684b229 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
++++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+@@ -12,6 +12,18 @@
+ model = "Atmel at91sam9g20ek 2 mmc";
+ compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
+
++ ahb {
++ apb{
++ mmc0: mmc@fffa8000 {
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioC 2 0>;
++ };
++ };
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+index b06c0db..7da326a 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -51,6 +51,15 @@
+ atmel,vbus-gpio = <&pioC 5 0>;
+ status = "okay";
+ };
++
++ mmc0: mmc@fffa8000 {
++ status = "okay";
++ slot@1 {
++ reg = <1>;
++ bus-width = <4>;
++ cd-gpios = <&pioC 9 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 96514c1..4857e6c 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -32,6 +32,24 @@
+ phy-mode = "rmii";
+ status = "okay";
+ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>;
++ };
++ };
++
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
+ };
+
+ usb0: ohci@00600000 {
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index a3633bd..7a7b571 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -46,6 +46,25 @@
+ phy-mode = "rmii";
+ status = "okay";
+ };
++
++ mmc0: mmc@fff80000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 10 0>;
++ };
++ };
++
++ mmc1: mmc@fffd0000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 11 0>;
++ wp-gpios = <&pioD 29 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
+index f4e43e3..44b42d9 100644
+--- a/arch/arm/boot/dts/at91sam9n12ek.dts
++++ b/arch/arm/boot/dts/at91sam9n12ek.dts
+@@ -37,6 +37,15 @@
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioA 7 0>;
++ };
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 2f7c847b1fc49780a3d9d963864a105cdca96c62 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 12 Sep 2012 08:42:14 +0200
-Subject: i2c: at91: add dt support to i2c-at91
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nikolaus Voss <n.voss@weinmann.de>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- .../devicetree/bindings/i2c/atmel-i2c.txt | 30 +++++++++++++
- drivers/i2c/busses/i2c-at91.c | 49 ++++++++++++++++++++++
- 2 files changed, 79 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/i2c/atmel-i2c.txt
-
-diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
-new file mode 100644
-index 0000000..b689a0d
---- /dev/null
-+++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
-@@ -0,0 +1,30 @@
-+I2C for Atmel platforms
-+
-+Required properties :
-+- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
-+ "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
-+ or "atmel,at91sam9x5-i2c"
-+- reg: physical base address of the controller and length of memory mapped
-+ region.
-+- interrupts: interrupt number to the cpu.
-+- #address-cells = <1>;
-+- #size-cells = <0>;
-+
-+Optional properties:
-+- Child nodes conforming to i2c bus binding
-+
-+Examples :
-+
-+i2c0: i2c@fff84000 {
-+ compatible = "atmel,at91sam9g20-i2c";
-+ reg = <0xfff84000 0x100>;
-+ interrupts = <12 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ 24c512@50 {
-+ compatible = "24c512";
-+ reg = <0x50>;
-+ pagesize = <128>;
-+ }
-+}
-diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
-index 78bcad0..aa59a25 100644
---- a/drivers/i2c/busses/i2c-at91.c
-+++ b/drivers/i2c/busses/i2c-at91.c
-@@ -24,6 +24,9 @@
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_i2c.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
-
-@@ -347,6 +350,12 @@ static struct at91_twi_pdata at91sam9g10_config = {
- .has_unre_flag = false,
- };
-
-+static struct at91_twi_pdata at91sam9x5_config = {
-+ .clk_max_div = 7,
-+ .clk_offset = 4,
-+ .has_unre_flag = false,
-+};
-+
- static const struct platform_device_id at91_twi_devtypes[] = {
- {
- .name = "i2c-at91rm9200",
-@@ -368,6 +377,42 @@ static const struct platform_device_id at91_twi_devtypes[] = {
- }
- };
-
-+#if defined(CONFIG_OF)
-+static const struct of_device_id atmel_twi_dt_ids[] = {
-+ {
-+ .compatible = "atmel,at91sam9260-i2c",
-+ .data = &at91sam9260_config,
-+ } , {
-+ .compatible = "atmel,at91sam9g20-i2c",
-+ .data = &at91sam9g20_config,
-+ } , {
-+ .compatible = "atmel,at91sam9g10-i2c",
-+ .data = &at91sam9g10_config,
-+ }, {
-+ .compatible = "atmel,at91sam9x5-i2c",
-+ .data = &at91sam9x5_config,
-+ }, {
-+ /* sentinel */
-+ }
-+};
-+MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
-+#else
-+#define atmel_twi_dt_ids NULL
-+#endif
-+
-+static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
-+ struct platform_device *pdev)
-+{
-+ if (pdev->dev.of_node) {
-+ const struct of_device_id *match;
-+ match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
-+ if (!match)
-+ return NULL;
-+ return match->data;
-+ }
-+ return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
-+}
-+
- static int __devinit at91_twi_probe(struct platform_device *pdev)
- {
- struct at91_twi_dev *dev;
-@@ -423,6 +468,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- dev->adapter.dev.parent = dev->dev;
- dev->adapter.nr = pdev->id;
- dev->adapter.timeout = AT91_I2C_TIMEOUT;
-+ dev->adapter.dev.of_node = pdev->dev.of_node;
-
- rc = i2c_add_numbered_adapter(&dev->adapter);
- if (rc) {
-@@ -432,6 +478,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- return rc;
- }
-
-+ of_i2c_register_devices(&dev->adapter);
-+
- dev_info(dev->dev, "AT91 i2c bus driver.\n");
- return 0;
- }
-@@ -482,6 +530,7 @@ static struct platform_driver at91_twi_driver = {
- .driver = {
- .name = "at91_i2c",
- .owner = THIS_MODULE,
-+ .of_match_table = atmel_twi_dt_ids,
- .pm = at91_twi_pm_ops,
- },
- };
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 16a2fab8b00700750c3bf55d9ae47142bcd62cbc Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 15:53:10 +0200
-Subject: ARM: at91: add clocks for I2C DT entries
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nikolaus Voss <n.voss@weinmann.de>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-
-Conflicts:
- arch/arm/mach-at91/at91sam9263.c
- arch/arm/mach-at91/at91sam9g45.c
- arch/arm/mach-at91/at91sam9x5.c
----
- arch/arm/mach-at91/at91sam9260.c | 1 +
- arch/arm/mach-at91/at91sam9263.c | 1 +
- arch/arm/mach-at91/at91sam9g45.c | 2 ++
- arch/arm/mach-at91/at91sam9n12.c | 2 ++
- arch/arm/mach-at91/at91sam9x5.c | 3 +++
- 5 files changed, 9 insertions(+)
-
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index a936c15..040f79a 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
- CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
- /* more tc lookup table for DT entries */
- CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index d49cfe9..00723ec 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
- };
-
- static struct clk_lookup usart_clocks_lookups[] = {
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index 7d5ac91..7ccbf9c 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -240,6 +240,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
-index cce4e0f..ebe94bb 100644
---- a/arch/arm/mach-at91/at91sam9n12.c
-+++ b/arch/arm/mach-at91/at91sam9n12.c
-@@ -170,6 +170,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
- CLKDEV_CON_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index 15ac57b..f40c1ab 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -230,6 +230,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
- CLKDEV_CON_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 7cc485eab96c78d9e36f62040cc1c5ba927a5eed Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 7 Jun 2012 10:54:33 +0200
+Subject: mmc: atmel-mci: remove not needed DMA capability test
+
+The test about DMA capability is not needed as it is
+performed in DMA-only functions: so remove it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 47421fc..7d9812c 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -834,9 +834,8 @@ static void atmci_dma_complete(void *arg)
+
+ dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+- if (host->caps.has_dma)
+- /* Disable DMA hardware handshaking on MCI */
+- atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
++ /* Disable DMA hardware handshaking on MCI */
++ atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
+
+ atmci_dma_cleanup(host);
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 78f6c26cc14ac43da5dbfd46726ce7b8df9b0702 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 14 Mar 2012 12:46:18 +0100
+Subject: ARM: at91/atmel-mci: remove unused setup_dma_addr() macro
+
+This macro is not used anymove in atmel-mci driver. It has been removed
+by a patch that was dealing with dw_dmac.c e2b35f3:
+(dmaengine/dw_dmac: Fix dw_dmac user drivers to adapt to slave_config changes)
+
+We are now using the dmaengine API to specify the slave DMA parameters:
+dmaengine_slave_config().
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Cc: Chris Ball <cjb@laptop.org>
+Cc: <linux-mmc@vger.kernel.org>
+---
+ arch/arm/mach-at91/include/mach/atmel-mci.h | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/arch/arm/mach-at91/include/mach/atmel-mci.h
+index 998cb0c..5d84fe3 100644
+--- a/arch/arm/mach-at91/include/mach/atmel-mci.h
++++ b/arch/arm/mach-at91/include/mach/atmel-mci.h
+@@ -14,11 +14,4 @@ struct mci_dma_data {
+ #define slave_data_ptr(s) (&(s)->sdata)
+ #define find_slave_dev(s) ((s)->sdata.dma_dev)
+
+-#define setup_dma_addr(s, t, r) do { \
+- if (s) { \
+- (s)->sdata.tx_reg = (t); \
+- (s)->sdata.rx_reg = (r); \
+- } \
+-} while (0)
+-
+ #endif /* __MACH_ATMEL_MCI_H */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From cfd444af2516de03e37de245cf8b926d2bfe9738 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 12 Sep 2012 08:42:16 +0200
-Subject: ARM: dts: add twi nodes for atmel SoCs
-
-Add TWI nodes for atmel SoCs but keep i2c-gpio ones in order to let the
-choice to the user in dts files.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
----
- arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++
- arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++
- arch/arm/boot/dts/at91sam9g20.dtsi | 8 ++++++++
- arch/arm/boot/dts/at91sam9g45.dtsi | 20 ++++++++++++++++++++
- arch/arm/boot/dts/at91sam9n12.dtsi | 20 ++++++++++++++++++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 30 ++++++++++++++++++++++++++++++
- 6 files changed, 98 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index 8d95e83c..0352bf8 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -28,6 +28,7 @@
- gpio2 = &pioC;
- tcb0 = &tcb0;
- tcb1 = &tcb1;
-+ i2c0 = &i2c0;
- };
- cpus {
- cpu@0 {
-@@ -210,6 +211,15 @@
- #address-cells = <1>;
- #size-cells = <0>;
- };
-+
-+ i2c0: i2c@fffac000 {
-+ compatible = "atmel,at91sam9260-i2c";
-+ reg = <0xfffac000 0x100>;
-+ interrupts = <11 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 54e6984..26ab452 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -24,6 +24,7 @@
- gpio3 = &pioD;
- gpio4 = &pioE;
- tcb0 = &tcb0;
-+ i2c0 = &i2c0;
- };
- cpus {
- cpu@0 {
-@@ -203,6 +204,15 @@
- #address-cells = <1>;
- #size-cells = <0>;
- };
-+
-+ i2c0: i2c@fff88000 {
-+ compatible = "atmel,at91sam9263-i2c";
-+ reg = <0xfff88000 0x100>;
-+ interrupts = <13 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
-index 0eb1a75..4537a74 100644
---- a/arch/arm/boot/dts/at91sam9g20.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
-@@ -15,4 +15,12 @@
- memory {
- reg = <0x20000000 0x08000000>;
- };
-+
-+ ahb {
-+ apb {
-+ i2c0: i2c@fffac000 {
-+ compatible = "atmel,at91sam9g20-i2c";
-+ };
-+ };
-+ };
- };
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index da135f9..b032a8c 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -29,6 +29,8 @@
- gpio4 = &pioE;
- tcb0 = &tcb0;
- tcb1 = &tcb1;
-+ i2c0 = &i2c0;
-+ i2c1 = &i2c1;
- };
- cpus {
- cpu@0 {
-@@ -223,6 +225,24 @@
- #address-cells = <1>;
- #size-cells = <0>;
- };
-+
-+ i2c0: i2c@fff84000 {
-+ compatible = "atmel,at91sam9g10-i2c";
-+ reg = <0xfff84000 0x100>;
-+ interrupts = <12 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c1: i2c@fff88000 {
-+ compatible = "atmel,at91sam9g10-i2c";
-+ reg = <0xfff88000 0x100>;
-+ interrupts = <13 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index 42d5fc2..0d08c4e 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -26,6 +26,8 @@
- gpio3 = &pioD;
- tcb0 = &tcb0;
- tcb1 = &tcb1;
-+ i2c0 = &i2c0;
-+ i2c1 = &i2c1;
- };
- cpus {
- cpu@0 {
-@@ -191,6 +193,24 @@
- atmel,use-dma-tx;
- status = "disabled";
- };
-+
-+ i2c0: i2c@f8010000 {
-+ compatible = "atmel,at91sam9x5-i2c";
-+ reg = <0xf8010000 0x100>;
-+ interrupts = <9 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c1: i2c@f8014000 {
-+ compatible = "atmel,at91sam9x5-i2c";
-+ reg = <0xf8014000 0x100>;
-+ interrupts = <10 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index ad7016a..fec3316 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -27,6 +27,9 @@
- gpio3 = &pioD;
- tcb0 = &tcb0;
- tcb1 = &tcb1;
-+ i2c0 = &i2c0;
-+ i2c1 = &i2c1;
-+ i2c2 = &i2c2;
- };
- cpus {
- cpu@0 {
-@@ -213,6 +216,33 @@
- #address-cells = <1>;
- #size-cells = <0>;
- };
-+
-+ i2c0: i2c@f8010000 {
-+ compatible = "atmel,at91sam9x5-i2c";
-+ reg = <0xf8010000 0x100>;
-+ interrupts = <9 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c1: i2c@f8014000 {
-+ compatible = "atmel,at91sam9x5-i2c";
-+ reg = <0xf8014000 0x100>;
-+ interrupts = <10 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
-+
-+ i2c2: i2c@f8018000 {
-+ compatible = "atmel,at91sam9x5-i2c";
-+ reg = <0xf8018000 0x100>;
-+ interrupts = <11 4 6>;
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 4b10c24b6a6aa99991c10c670e22b95cc0520d7c Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 15:53:27 +0200
-Subject: ARM: dts: add twi nodes for atmel boards
-
-Still use i2c-gpio on boards which have a SoC with a TWI IP which
-doesn't have clock stretching in transmission mode.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9g25ek.dts
- arch/arm/boot/dts/at91sam9m10g45ek.dts
- arch/arm/boot/dts/at91sam9n12ek.dts
----
- arch/arm/boot/dts/at91sam9g25ek.dts | 12 ++++++++++++
- arch/arm/boot/dts/at91sam9m10g45ek.dts | 8 ++++++++
- arch/arm/boot/dts/at91sam9n12ek.dts | 8 ++++++++
- 3 files changed, 28 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
-index 4857e6c..5b054e4 100644
---- a/arch/arm/boot/dts/at91sam9g25ek.dts
-+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
-@@ -50,6 +50,18 @@
- cd-gpios = <&pioD 14 0>;
- };
- };
-+
-+ i2c0: i2c@f8010000 {
-+ status = "okay";
-+ };
-+
-+ i2c1: i2c@f8014000 {
-+ status = "okay";
-+ };
-+
-+ i2c2: i2c@f8018000 {
-+ status = "okay";
-+ };
- };
-
- usb0: ohci@00600000 {
-diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-index 7a7b571..6a4aedd 100644
---- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
-+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-@@ -65,6 +65,14 @@
- wp-gpios = <&pioD 29 0>;
- };
- };
-+
-+ i2c0: i2c@fff84000 {
-+ status = "okay";
-+ };
-+
-+ i2c1: i2c@fff88000 {
-+ status = "okay";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
-index 44b42d9..ccc94de 100644
---- a/arch/arm/boot/dts/at91sam9n12ek.dts
-+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
-@@ -46,6 +46,14 @@
- cd-gpios = <&pioA 7 0>;
- };
- };
-+
-+ i2c0: i2c@f8010000 {
-+ status = "okay";
-+ };
-+
-+ i2c1: i2c@f8014000 {
-+ status = "okay";
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 85edd366befdc9eed99473da3ad3f5a8a325c085 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Thu, 15 Mar 2012 14:28:58 +0100
+Subject: mmc: atmel-mci: remove the need for CONFIG_MMC_ATMELMCI_DMA
+
+This Kconfig option is not needed anymore, so remove it.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+
+ drivers/mmc/host/Kconfig
+---
+ drivers/mmc/host/Kconfig | 10 ----------
+ drivers/mmc/host/atmel-mci.c | 2 --
+ 2 files changed, 12 deletions(-)
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 2bc06e7..dbdd907 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -297,16 +297,6 @@ config MMC_ATMELMCI
+
+ endchoice
+
+-config MMC_ATMELMCI_DMA
+- bool "Atmel MCI DMA support"
+- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
+- help
+- Say Y here to have the Atmel MCI driver use a DMA engine to
+- do data transfers and thus increase the throughput and
+- reduce the CPU utilization.
+-
+- If unsure, say N.
+-
+ config MMC_IMX
+ tristate "Motorola i.MX Multimedia Card Interface support"
+ depends on ARCH_MX1
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 7d9812c..cc81ef8 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -2476,10 +2476,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
+ atmci_readl(host, ATMCI_SR);
+ clk_disable(host->mck);
+
+-#ifdef CONFIG_MMC_ATMELMCI_DMA
+ if (host->dma.chan)
+ dma_release_channel(host->dma.chan);
+-#endif
+
+ free_irq(platform_get_irq(pdev, 0), host);
+ iounmap(host->regs);
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 6dd4494f6c46cf3aeba389b557a5315b6453b727 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 22 Jun 2012 16:41:08 +0200
+Subject: ARM: dts: fix add mmc irq priority
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 2 +-
+ arch/arm/boot/dts/at91sam9263.dtsi | 4 ++--
+ arch/arm/boot/dts/at91sam9g45.dtsi | 4 ++--
+ arch/arm/boot/dts/at91sam9n12.dtsi | 2 +-
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++--
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 1f2c7d0..8d95e83c 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -205,7 +205,7 @@
+ mmc0: mmc@fffa8000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffa800 0x600>;
+- interrupts = <9 4>;
++ interrupts = <9 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index a76f6cd..54e6984 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -189,7 +189,7 @@
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+- interrupts = <10 4>;
++ interrupts = <10 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -198,7 +198,7 @@
+ mmc1: mmc@fff84000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff84000 0x600>;
+- interrupts = <11 4>;
++ interrupts = <11 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 4b833d4..da135f9 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -209,7 +209,7 @@
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+- interrupts = <11 4>;
++ interrupts = <11 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -218,7 +218,7 @@
+ mmc1: mmc@fffd0000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffd0000 0x600>;
+- interrupts = <29 4>;
++ interrupts = <29 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index aead257..42d5fc2 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -85,7 +85,7 @@
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+- interrupts = <12 4>;
++ interrupts = <12 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 1be3df7..ad7016a 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -199,7 +199,7 @@
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+- interrupts = <12 4>;
++ interrupts = <12 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+@@ -208,7 +208,7 @@
+ mmc1: mmc@f000c000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf000c000 0x600>;
+- interrupts = <26 4>;
++ interrupts = <26 4 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 38916c66f279b3c86d4c018154a6d6c4f3de0316 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Fri, 14 Sep 2012 16:04:55 +0200
-Subject: i2c: at91: add dma support
-
-Add dma support for Atmel TWI which is available on sam9x5 and later.
-
-When using dma for reception, you have to read only n-2 bytes. The last
-two bytes are read manually. Don't doing this should cause to send the
-STOP command too late and then to get extra data in the receive
-register.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/i2c/busses/i2c-at91.c | 326 ++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 314 insertions(+), 12 deletions(-)
-
-diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
-index aa59a25..33219f8 100644
---- a/drivers/i2c/busses/i2c-at91.c
-+++ b/drivers/i2c/busses/i2c-at91.c
-@@ -19,6 +19,8 @@
-
- #include <linux/clk.h>
- #include <linux/completion.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmaengine.h>
- #include <linux/err.h>
- #include <linux/i2c.h>
- #include <linux/interrupt.h>
-@@ -30,6 +32,8 @@
- #include <linux/platform_device.h>
- #include <linux/slab.h>
-
-+#include <mach/at_hdmac.h>
-+
- #define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
- #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
-
-@@ -65,9 +69,21 @@
- #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
-
- struct at91_twi_pdata {
-- unsigned clk_max_div;
-- unsigned clk_offset;
-- bool has_unre_flag;
-+ unsigned clk_max_div;
-+ unsigned clk_offset;
-+ bool has_unre_flag;
-+ bool has_dma_support;
-+ struct at_dma_slave dma_slave;
-+};
-+
-+struct at91_twi_dma {
-+ struct dma_chan *chan_rx;
-+ struct dma_chan *chan_tx;
-+ struct scatterlist sg;
-+ struct dma_async_tx_descriptor *data_desc;
-+ enum dma_data_direction direction;
-+ bool buf_mapped;
-+ bool xfer_in_progress;
- };
-
- struct at91_twi_dev {
-@@ -79,10 +95,13 @@ struct at91_twi_dev {
- size_t buf_len;
- struct i2c_msg *msg;
- int irq;
-+ unsigned imr;
- unsigned transfer_status;
- struct i2c_adapter adapter;
- unsigned twi_cwgr_reg;
- struct at91_twi_pdata *pdata;
-+ bool use_dma;
-+ struct at91_twi_dma dma;
- };
-
- static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
-@@ -98,7 +117,18 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
- static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
- {
- at91_twi_write(dev, AT91_TWI_IDR,
-- AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
-+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
-+}
-+
-+static void at91_twi_irq_save(struct at91_twi_dev *dev)
-+{
-+ dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
-+ at91_disable_twi_interrupts(dev);
-+}
-+
-+static void at91_twi_irq_restore(struct at91_twi_dev *dev)
-+{
-+ at91_twi_write(dev, AT91_TWI_IER, dev->imr);
- }
-
- static void at91_init_twi_bus(struct at91_twi_dev *dev)
-@@ -137,6 +167,30 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
- dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
- }
-
-+static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
-+{
-+ struct at91_twi_dma *dma = &dev->dma;
-+
-+ at91_twi_irq_save(dev);
-+
-+ if (dma->xfer_in_progress) {
-+ if (dma->direction == DMA_FROM_DEVICE)
-+ dma->chan_rx->device->device_control(dma->chan_rx,
-+ DMA_TERMINATE_ALL, 0);
-+ else
-+ dma->chan_tx->device->device_control(dma->chan_tx,
-+ DMA_TERMINATE_ALL, 0);
-+ dma->xfer_in_progress = false;
-+ }
-+ if (dma->buf_mapped) {
-+ dma_unmap_single(dev->dev, sg_dma_address(&dma->sg),
-+ dev->buf_len, dma->direction);
-+ dma->buf_mapped = false;
-+ }
-+
-+ at91_twi_irq_restore(dev);
-+}
-+
- static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
- {
- if (dev->buf_len <= 0)
-@@ -153,6 +207,65 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
- ++dev->buf;
- }
-
-+static void at91_twi_write_data_dma_callback(void *data)
-+{
-+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
-+
-+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
-+ dev->buf_len, DMA_TO_DEVICE);
-+
-+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
-+}
-+
-+static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
-+{
-+ dma_addr_t dma_addr;
-+ dma_cookie_t cookie;
-+ struct dma_async_tx_descriptor *txdesc;
-+ struct at91_twi_dma *dma = &dev->dma;
-+ struct dma_chan *chan_tx = dma->chan_tx;
-+
-+ if (dev->buf_len <= 0)
-+ return;
-+
-+ dma->direction = DMA_TO_DEVICE;
-+
-+ at91_twi_irq_save(dev);
-+ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
-+ DMA_TO_DEVICE);
-+ if (dma_mapping_error(dev->dev, dma_addr)) {
-+ dev_err(dev->dev, "dma map failed\n");
-+ return;
-+ }
-+ dma->buf_mapped = true;
-+ at91_twi_irq_restore(dev);
-+ sg_dma_len(&dma->sg) = dev->buf_len;
-+ sg_dma_address(&dma->sg) = dma_addr;
-+
-+ txdesc = chan_tx->device->device_prep_slave_sg(chan_tx, &dma->sg,
-+ 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
-+ if (!txdesc) {
-+ dev_err(dev->dev, "dma prep slave sg failed\n");
-+ goto error;
-+ }
-+
-+ txdesc->callback = at91_twi_write_data_dma_callback;
-+ txdesc->callback_param = dev;
-+
-+ dma->xfer_in_progress = true;
-+ cookie = txdesc->tx_submit(txdesc);
-+ if (dma_submit_error(cookie)) {
-+ dev_err(dev->dev, "dma submit error\n");
-+ goto error;
-+ }
-+ dma->chan_tx->device->device_issue_pending(chan_tx);
-+
-+ return;
-+
-+error:
-+ at91_twi_dma_cleanup(dev);
-+}
-+
- static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
- {
- if (dev->buf_len <= 0)
-@@ -178,6 +291,66 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
- ++dev->buf;
- }
-
-+static void at91_twi_read_data_dma_callback(void *data)
-+{
-+ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
-+
-+ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
-+ dev->buf_len, DMA_FROM_DEVICE);
-+
-+ /* The last two bytes have to be read without using dma */
-+ dev->buf += dev->buf_len - 2;
-+ dev->buf_len = 2;
-+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY);
-+}
-+
-+static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
-+{
-+ dma_addr_t dma_addr;
-+ dma_cookie_t cookie;
-+ struct dma_async_tx_descriptor *rxdesc;
-+ struct at91_twi_dma *dma = &dev->dma;
-+ struct dma_chan *chan_rx = dma->chan_rx;
-+
-+ dma->direction = DMA_FROM_DEVICE;
-+
-+ /* Keep in mind that we won't use dma to read the last two bytes */
-+ at91_twi_irq_save(dev);
-+ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2,
-+ DMA_FROM_DEVICE);
-+ if (dma_mapping_error(dev->dev, dma_addr)) {
-+ dev_err(dev->dev, "dma map failed\n");
-+ return;
-+ }
-+ dma->buf_mapped = true;
-+ at91_twi_irq_restore(dev);
-+ dma->sg.dma_address = dma_addr;
-+ sg_dma_len(&dma->sg) = dev->buf_len - 2;
-+
-+ rxdesc = chan_rx->device->device_prep_slave_sg(chan_rx, &dma->sg,
-+ 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
-+ if (!rxdesc) {
-+ dev_err(dev->dev, "dma prep slave sg failed\n");
-+ goto error;
-+ }
-+
-+ rxdesc->callback = at91_twi_read_data_dma_callback;
-+ rxdesc->callback_param = dev;
-+
-+ dma->xfer_in_progress = true;
-+ cookie = rxdesc->tx_submit(rxdesc);
-+ if (dma_submit_error(cookie)) {
-+ dev_err(dev->dev, "dma submit error\n");
-+ goto error;
-+ }
-+ dma->chan_rx->device->device_issue_pending(dma->chan_rx);
-+
-+ return;
-+
-+error:
-+ at91_twi_dma_cleanup(dev);
-+}
-+
- static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
- {
- struct at91_twi_dev *dev = dev_id;
-@@ -224,12 +397,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
- if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
- start_flags |= AT91_TWI_STOP;
- at91_twi_write(dev, AT91_TWI_CR, start_flags);
-- at91_twi_write(dev, AT91_TWI_IER,
-+ /*
-+ * When using dma, the last byte has to be read manually in
-+ * order to not send the stop command too late and then
-+ * to receive extra data. In practice, there are some issues
-+ * if you use the dma to read n-1 bytes because of latency.
-+ * Reading n-2 bytes with dma and the two last ones manually
-+ * seems to be the best solution.
-+ */
-+ if (dev->use_dma && (dev->buf_len > 2)) {
-+ at91_twi_read_data_dma(dev);
-+ /*
-+ * It is important to enable TXCOMP irq here because
-+ * doing it only when transferring the last two bytes
-+ * will mask NACK errors since TXCOMP is set when a
-+ * NACK occurs.
-+ */
-+ at91_twi_write(dev, AT91_TWI_IER,
-+ AT91_TWI_TXCOMP);
-+ } else
-+ at91_twi_write(dev, AT91_TWI_IER,
- AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
- } else {
-- at91_twi_write_next_byte(dev);
-- at91_twi_write(dev, AT91_TWI_IER,
-- AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
-+ if (dev->use_dma) {
-+ at91_twi_write_data_dma(dev);
-+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
-+ } else {
-+ at91_twi_write_next_byte(dev);
-+ at91_twi_write(dev, AT91_TWI_IER,
-+ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
-+ }
- }
-
- ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
-@@ -237,23 +434,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
- if (ret == 0) {
- dev_err(dev->dev, "controller timed out\n");
- at91_init_twi_bus(dev);
-- return -ETIMEDOUT;
-+ ret = -ETIMEDOUT;
-+ goto error;
- }
- if (dev->transfer_status & AT91_TWI_NACK) {
- dev_dbg(dev->dev, "received nack\n");
-- return -EREMOTEIO;
-+ ret = -EREMOTEIO;
-+ goto error;
- }
- if (dev->transfer_status & AT91_TWI_OVRE) {
- dev_err(dev->dev, "overrun while reading\n");
-- return -EIO;
-+ ret = -EIO;
-+ goto error;
- }
- if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
- dev_err(dev->dev, "underrun while writing\n");
-- return -EIO;
-+ ret = -EIO;
-+ goto error;
- }
- dev_dbg(dev->dev, "transfer complete\n");
-
- return 0;
-+
-+error:
-+ at91_twi_dma_cleanup(dev);
-+ return ret;
- }
-
- static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
-@@ -324,36 +529,42 @@ static struct at91_twi_pdata at91rm9200_config = {
- .clk_max_div = 5,
- .clk_offset = 3,
- .has_unre_flag = true,
-+ .has_dma_support = false,
- };
-
- static struct at91_twi_pdata at91sam9261_config = {
- .clk_max_div = 5,
- .clk_offset = 4,
- .has_unre_flag = false,
-+ .has_dma_support = false,
- };
-
- static struct at91_twi_pdata at91sam9260_config = {
- .clk_max_div = 7,
- .clk_offset = 4,
- .has_unre_flag = false,
-+ .has_dma_support = false,
- };
-
- static struct at91_twi_pdata at91sam9g20_config = {
- .clk_max_div = 7,
- .clk_offset = 4,
- .has_unre_flag = false,
-+ .has_dma_support = false,
- };
-
- static struct at91_twi_pdata at91sam9g10_config = {
- .clk_max_div = 7,
- .clk_offset = 4,
- .has_unre_flag = false,
-+ .has_dma_support = false,
- };
-
- static struct at91_twi_pdata at91sam9x5_config = {
- .clk_max_div = 7,
- .clk_offset = 4,
- .has_unre_flag = false,
-+ .has_dma_support = true,
- };
-
- static const struct platform_device_id at91_twi_devtypes[] = {
-@@ -400,6 +611,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
- #define atmel_twi_dt_ids NULL
- #endif
-
-+static bool __devinit filter(struct dma_chan *chan, void *slave)
-+{
-+ struct at_dma_slave *sl = slave;
-+
-+ if (sl->dma_dev == chan->device->dev) {
-+ chan->private = sl;
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
-+static int __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
-+{
-+ int ret = 0;
-+ struct at_dma_slave *sdata;
-+ struct dma_slave_config slave_config;
-+ struct at91_twi_dma *dma = &dev->dma;
-+
-+ sdata = &dev->pdata->dma_slave;
-+
-+ memset(&slave_config, 0, sizeof(slave_config));
-+ slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
-+ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ slave_config.src_maxburst = 1;
-+ slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
-+ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ slave_config.dst_maxburst = 1;
-+ slave_config.device_fc = false;
-+
-+ if (sdata && sdata->dma_dev) {
-+ dma_cap_mask_t mask;
-+
-+ dma_cap_zero(mask);
-+ dma_cap_set(DMA_SLAVE, mask);
-+ dma->chan_tx = dma_request_channel(mask, filter, sdata);
-+ if (!dma->chan_tx) {
-+ dev_err(dev->dev, "no DMA channel available for tx\n");
-+ ret = -EBUSY;
-+ goto error;
-+ }
-+ dma->chan_rx = dma_request_channel(mask, filter, sdata);
-+ if (!dma->chan_rx) {
-+ dev_err(dev->dev, "no DMA channel available for rx\n");
-+ ret = -EBUSY;
-+ goto error;
-+ }
-+ } else {
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ slave_config.direction = DMA_TO_DEVICE;
-+ if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
-+ dev_err(dev->dev, "failed to configure tx channel\n");
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ slave_config.direction = DMA_FROM_DEVICE;
-+ if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
-+ dev_err(dev->dev, "failed to configure rx channel\n");
-+ ret = -EINVAL;
-+ goto error;
-+ }
-+
-+ sg_init_table(&dma->sg, 1);
-+ dma->buf_mapped = false;
-+ dma->xfer_in_progress = false;
-+
-+ dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
-+ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
-+
-+ return ret;
-+
-+error:
-+ dev_info(dev->dev, "can't use DMA\n");
-+ if (dma->chan_rx)
-+ dma_release_channel(dma->chan_rx);
-+ if (dma->chan_tx)
-+ dma_release_channel(dma->chan_tx);
-+ return ret;
-+}
-+
- static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
- struct platform_device *pdev)
- {
-@@ -418,6 +713,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- struct at91_twi_dev *dev;
- struct resource *mem;
- int rc;
-+ u32 phy_addr;
-
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev)
-@@ -428,6 +724,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem)
- return -ENODEV;
-+ phy_addr = mem->start;
-
- dev->pdata = at91_twi_get_driver_data(pdev);
- if (!dev->pdata)
-@@ -457,6 +754,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- }
- clk_prepare_enable(dev->clk);
-
-+ if (dev->pdata->has_dma_support) {
-+ if (at91_twi_configure_dma(dev, phy_addr) == 0)
-+ dev->use_dma = true;
-+ }
-+
- at91_calc_twi_clock(dev, TWI_CLK_HZ);
- at91_init_twi_bus(dev);
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From b98bff151c11efa7c7c80613b25c1d4890e84cf2 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Tue, 18 Sep 2012 18:32:38 +0200
-Subject: i2c: at91: backport fix for devm_clk_get
-
-i2c-at91 is backported from a 3.6, devm_clk_get is not yet implemented
-on 3.4.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- drivers/i2c/busses/i2c-at91.c | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
-index 33219f8..296c430 100644
---- a/drivers/i2c/busses/i2c-at91.c
-+++ b/drivers/i2c/busses/i2c-at91.c
-@@ -747,7 +747,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
-
- platform_set_drvdata(pdev, dev);
-
-- dev->clk = devm_clk_get(dev->dev, NULL);
-+ dev->clk = clk_get(dev->dev, NULL);
- if (IS_ERR(dev->clk)) {
- dev_err(dev->dev, "no clock defined\n");
- return -ENODEV;
-@@ -777,6 +777,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- dev_err(dev->dev, "Adapter %s registration failed\n",
- dev->adapter.name);
- clk_disable_unprepare(dev->clk);
-+ clk_put(dev->clk);
- return rc;
- }
-
-@@ -793,6 +794,7 @@ static int __devexit at91_twi_remove(struct platform_device *pdev)
-
- rc = i2c_del_adapter(&dev->adapter);
- clk_disable_unprepare(dev->clk);
-+ clk_put(dev->clk);
-
- return rc;
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6eecb222c79306c6fad8e4934ba9dfbbac033067 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 6 Sep 2011 17:49:35 +0200
+Subject: mmc: atmel-mci: support 8-bit buswidth
+
+This patch adds support for 8-bit buswidth.
+Relevant SDCR value modified.
+
+Derived from a patch by Jaehoon Chung on dw_mmc.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index cc81ef8..b626d1e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -1261,6 +1261,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+ case MMC_BUS_WIDTH_4:
+ slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
+ break;
++ case MMC_BUS_WIDTH_8:
++ slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
++ break;
+ }
+
+ if (ios->clock) {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 9c0c6f313b432d8ae6effe769df5712508d00622 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 16:00:47 +0200
-Subject: i2c: at91: add dt property for DMA configuration
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9x5.dtsi
----
- arch/arm/boot/dts/at91sam9x5.dtsi | 5 ++++
- drivers/i2c/busses/i2c-at91.c | 56 ++++++++++++++++++++++++++++++++++++++-
- 2 files changed, 60 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index fec3316..79718e7 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -103,12 +103,14 @@
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
- interrupts = <20 4 0>;
-+ #dma-cells = <1>;
- };
-
- dma1: dma-controller@ffffee00 {
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffee00 0x200>;
- interrupts = <21 4 0>;
-+ #dma-cells = <1>;
- };
-
- pioA: gpio@fffff400 {
-@@ -221,6 +223,7 @@
- compatible = "atmel,at91sam9x5-i2c";
- reg = <0xf8010000 0x100>;
- interrupts = <9 4 6>;
-+ dma = <&dma0 0x10002278>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
-@@ -230,6 +233,7 @@
- compatible = "atmel,at91sam9x5-i2c";
- reg = <0xf8014000 0x100>;
- interrupts = <10 4 6>;
-+ dma = <&dma1 0x10002256>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
-@@ -239,6 +243,7 @@
- compatible = "atmel,at91sam9x5-i2c";
- reg = <0xf8018000 0x100>;
- interrupts = <11 4 6>;
-+ dma = <&dma0 0x1000229A>;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
-diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
-index 296c430..c004b34 100644
---- a/drivers/i2c/busses/i2c-at91.c
-+++ b/drivers/i2c/busses/i2c-at91.c
-@@ -589,6 +589,55 @@ static const struct platform_device_id at91_twi_devtypes[] = {
- };
-
- #if defined(CONFIG_OF)
-+static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
-+{
-+ struct of_phandle_args dma_spec;
-+ struct device_node *dmac_np;
-+ struct platform_device *dmac_pdev;
-+ const __be32 *nbcells;
-+ int ret;
-+
-+ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
-+ if (ret || !dma_spec.np) {
-+ pr_err("%s: can't parse dma property (%d)\n", np->full_name, ret);
-+ goto err0;
-+ }
-+ dmac_np = dma_spec.np;
-+
-+ /* check property format */
-+ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
-+ if (!nbcells) {
-+ pr_err("%s: #dma-cells property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ if (dma_spec.args_count != be32_to_cpup(nbcells)
-+ || dma_spec.args_count != 1) {
-+ pr_err("%s: wrong #dma-cells for %s\n",
-+ np->full_name, dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ dmac_pdev = of_find_device_by_node(dmac_np);
-+ if (!dmac_pdev) {
-+ pr_err("%s: unable to find pdev from DMA controller\n",
-+ dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ atslave->dma_dev = &dmac_pdev->dev;
-+ atslave->cfg = dma_spec.args[0];
-+
-+err1:
-+ of_node_put(dma_spec.np);
-+err0:
-+ pr_debug("%s exited with status %d\n", __func__, ret);
-+ return ret;
-+}
-+
- static const struct of_device_id atmel_twi_dt_ids[] = {
- {
- .compatible = "atmel,at91sam9260-i2c",
-@@ -608,6 +657,10 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
- };
- MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
- #else
-+static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
-+{
-+ return -ENODEV;
-+}
- #define atmel_twi_dt_ids NULL
- #endif
-
-@@ -755,7 +808,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
- clk_prepare_enable(dev->clk);
-
- if (dev->pdata->has_dma_support) {
-- if (at91_twi_configure_dma(dev, phy_addr) == 0)
-+ if ( at91_twi_of_init(pdev->dev.of_node, &dev->pdata->dma_slave) == 0
-+ && at91_twi_configure_dma(dev, phy_addr) == 0)
- dev->use_dma = true;
- }
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6200f62344e4ab0492623a51fabdac4e57ba6e89 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 6 Jul 2012 11:49:05 +0200
+Subject: mmc: atmel-mci: fix incorrect setting of host->data to NULL
+
+commit 41b4e9a194f69b1c945038c559ea407a6b383e81 upstream.
+
+Setting host->data to NULL is incorrect sequence in STATE_SENDING_STOP
+state of FSM: This early setting leads to the skip of dma_unmap_sg()
+in atmci_dma_cleanup() which is a bug.
+
+Idea taken form dw_mmc by Seungwon Jeon.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Cc: Seungwon Jeon <tgih.jun@samsung.com>
+---
+ drivers/mmc/host/atmel-mci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index b626d1e..90df83b 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -1754,7 +1754,6 @@ static void atmci_tasklet_func(unsigned long priv)
+
+ dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
+ host->cmd = NULL;
+- host->data = NULL;
+ data->bytes_xfered = data->blocks * data->blksz;
+ data->error = 0;
+ atmci_command_complete(host, mrq->stop);
+@@ -1768,6 +1767,7 @@ static void atmci_tasklet_func(unsigned long priv)
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ }
++ host->data = NULL;
+ break;
+
+ case STATE_END_REQUEST:
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From a26a550bb2339e928d60bcb4bf200eb0380ca6cc Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 24 Sep 2012 12:12:27 +0200
-Subject: ARM: at91: add MCI DMA for at91sam9x5.dtsi
-
-Temporary cfg hack
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 79718e7..88907db 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -208,6 +208,7 @@
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-+ dma = <&dma0 0x10002200>;
- };
-
- mmc1: mmc@f000c000 {
-@@ -217,6 +218,7 @@
- status = "disabled";
- #address-cells = <1>;
- #size-cells = <0>;
-+ dma = <&dma1 0x10002200>;
- };
-
- i2c0: i2c@f8010000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From a57a7a65247a77826cd2f021fadd536d46bb7d36 Mon Sep 17 00:00:00 2001
+From: Subhash Jadavani <subhashj@codeaurora.org>
+Date: Wed, 13 Jun 2012 17:10:43 +0530
+Subject: mmc: block: fix the data timeout issue with ACMD22
+
+commit d380443cd0271903bf9516bc04cead81676be034 upstream.
+
+If multi block write operation fails for SD card, during
+error handling we send the SD_APP_SEND_NUM_WR_BLKS (ACMD22)
+to know how many blocks were already programmed by card.
+
+But mmc_sd_num_wr_blocks() function which sends the ACMD22
+calculates the data timeout value from csd.tacc_ns and
+csd.tacc_clks parameters which will be 0 for block addressed
+(>2GB cards) SD card. This would result in timeout_ns and
+timeout_clks being 0 in the mmc_request passed to host driver.
+This means host controller would program its data timeout timer
+value with 0 which could result in DATA TIMEOUT errors from
+controller.
+
+To fix this issue, mmc_sd_num_wr_blocks() should instead
+just call the mmc_set_data_timeout() to calculate the
+data timeout value. mmc_set_data_timeout() function
+ensures that non zero timeout value is set even for
+block addressed SD cards.
+
+Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
+Reviewed-by: Venkatraman S <svenkatr@ti.com>
+Signed-off-by: Chris Ball <cjb@laptop.org>
+---
+ drivers/mmc/card/block.c | 14 +-------------
+ 1 file changed, 1 insertion(+), 13 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index dabec55..d8f802e 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -553,7 +553,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+- unsigned int timeout_us;
+
+ struct scatterlist sg;
+
+@@ -573,23 +572,12 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+- data.timeout_ns = card->csd.tacc_ns * 100;
+- data.timeout_clks = card->csd.tacc_clks * 100;
+-
+- timeout_us = data.timeout_ns / 1000;
+- timeout_us += data.timeout_clks * 1000 /
+- (card->host->ios.clock / 1000);
+-
+- if (timeout_us > 100000) {
+- data.timeout_ns = 100000000;
+- data.timeout_clks = 0;
+- }
+-
+ data.blksz = 4;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
++ mmc_set_data_timeout(&data, card);
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 9ee686bef09cb282f384de19a8d0d8d0b96d9119 Mon Sep 17 00:00:00 2001
-From: Ludovic Desroches <ludovic.desroches@atmel.com>
-Date: Wed, 19 Sep 2012 09:27:02 +0200
-Subject: ARM: at91: add i2c and qt1070 pin muxing
-
-Pin mux is temporary done in board-dt file.
-
-Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
----
- arch/arm/mach-at91/board-dt.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
-index e8f45c4..9355d77 100644
---- a/arch/arm/mach-at91/board-dt.c
-+++ b/arch/arm/mach-at91/board-dt.c
-@@ -43,6 +43,14 @@ static void __init at91_dt_init_irq(void)
- static void __init at91_dt_device_init(void)
- {
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-+ /* Temporary pin mux stuff */
-+ if (of_machine_is_compatible("atmel,at91sam9x5")) {
-+ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
-+ at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */
-+ printk("AT91: i2c pin mux done\n");
-+ at91_set_gpio_input(AT91_PIN_PA7, 1);
-+ printk("AT91: qt1070 pin mux done\n");
-+ }
- }
-
- static const char *at91_dt_board_compat[] __initdata = {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 8f6fe6c730556e621c6e404c945a330ed4107ad3 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Fri, 6 Jul 2012 12:11:51 +0200
+Subject: mmc: atmel-mci: modify CLKDIV displaying in debugfs
+
+commit 8a4de07e05e7bedc894c2de3b3b04673d6d840ec upstream.
+
+Modify clock division displaying in debugfs for matching
+the new CLKDIV,CLKODD user interface arrangement.
+Is using the has_odd_clk_div property to choose the proper format.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 90df83b..e03367c 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -394,11 +394,17 @@ static int atmci_regs_show(struct seq_file *s, void *v)
+ clk_disable(host->mck);
+ spin_unlock_bh(&host->lock);
+
+- seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
++ seq_printf(s, "MR:\t0x%08x%s%s ",
+ buf[ATMCI_MR / 4],
+ buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
+- buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
+- buf[ATMCI_MR / 4] & 0xff);
++ buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "");
++ if (host->caps.has_odd_clk_div)
++ seq_printf(s, "{CLKDIV,CLKODD}=%u\n",
++ ((buf[ATMCI_MR / 4] & 0xff) << 1)
++ | ((buf[ATMCI_MR / 4] >> 16) & 1));
++ else
++ seq_printf(s, "CLKDIV=%u\n",
++ (buf[ATMCI_MR / 4] & 0xff));
+ seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
+ seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
+ seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ee1a2b1fec441a9e821c3c6d0198e4b68545caf8 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 24 Sep 2012 12:27:10 +0200
-Subject: AT91: board-dt add mci pinmux for 9x5
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/board-dt.c | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
-diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
-index 9355d77..15830cb 100644
---- a/arch/arm/mach-at91/board-dt.c
-+++ b/arch/arm/mach-at91/board-dt.c
-@@ -50,6 +50,30 @@ static void __init at91_dt_device_init(void)
- printk("AT91: i2c pin mux done\n");
- at91_set_gpio_input(AT91_PIN_PA7, 1);
- printk("AT91: qt1070 pin mux done\n");
-+
-+ at91_set_gpio_input(AT91_PIN_PD14, 1);
-+ at91_set_deglitch(AT91_PIN_PD14, 1);
-+ at91_set_gpio_input(AT91_PIN_PD15, 1);
-+ at91_set_deglitch(AT91_PIN_PD15, 1);
-+ /* CLK */
-+ at91_set_A_periph(AT91_PIN_PA17, 0);
-+ /* CMD */
-+ at91_set_A_periph(AT91_PIN_PA16, 1);
-+ /* DAT0, DAT1..DAT3 */
-+ at91_set_A_periph(AT91_PIN_PA15, 1);
-+ at91_set_A_periph(AT91_PIN_PA18, 1);
-+ at91_set_A_periph(AT91_PIN_PA19, 1);
-+ at91_set_A_periph(AT91_PIN_PA20, 1);
-+ /* CLK */
-+ at91_set_B_periph(AT91_PIN_PA13, 0);
-+ /* CMD */
-+ at91_set_B_periph(AT91_PIN_PA12, 1);
-+ /* DAT0, DAT1..DAT3 */
-+ at91_set_B_periph(AT91_PIN_PA11, 1);
-+ at91_set_B_periph(AT91_PIN_PA2, 1);
-+ at91_set_B_periph(AT91_PIN_PA3, 1);
-+ at91_set_B_periph(AT91_PIN_PA4, 1);
-+ printk("AT91: mci0/1 pin mux done\n");
- }
- }
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 60bbd1c2625b64f10374f25698d289fa3147bef2 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Mon, 9 Jul 2012 08:51:50 +0200
+Subject: mmc: atmel-mci: increase dma threshold
+
+There are some issues with some SD cards when dma is used. DMA transfer
+during cmd6 seems to hang for an unknown reason. Since using PIO prevents from
+this issue, the dma threshold has been increased to not use dma for this
+command.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index e03367c..05a293e 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -45,7 +45,7 @@
+ #include "atmel-mci-regs.h"
+
+ #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
+-#define ATMCI_DMA_THRESHOLD 16
++#define ATMCI_DMA_THRESHOLD 65
+
+ enum {
+ EVENT_CMD_RDY = 0,
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 7c25754fa2e567e1a0d91f79e6c4813da979c0b1 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 24 Jul 2012 09:32:29 +0200
+Subject: mmc: atmel-mci: not busy flag has also to be used for read operations
+
+commit 077d40731edc90ee9dedf63249034c8cd5f694ce upstream.
+
+Even if the datasheet says that the not busy flag has to be used only for
+write operations, it's false excepted for version lesser than v2xx.
+Not waiting the not busy flag for read operations can cause the controller to
+hang-up during some SD card initialization.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/mmc/host/atmel-mci.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
+index 05a293e..3d9c7b8 100644
+--- a/drivers/mmc/host/atmel-mci.c
++++ b/drivers/mmc/host/atmel-mci.c
+@@ -84,6 +84,7 @@ struct atmel_mci_caps {
+ bool has_bad_data_ordering;
+ bool need_reset_after_xfer;
+ bool need_blksz_mul_4;
++ bool need_notbusy_for_read_ops;
+ };
+
+ struct atmel_mci_dma {
+@@ -1694,7 +1695,8 @@ static void atmci_tasklet_func(unsigned long priv)
+ __func__);
+ atmci_set_completed(host, EVENT_XFER_COMPLETE);
+
+- if (host->data->flags & MMC_DATA_WRITE) {
++ if (host->caps.need_notbusy_for_read_ops
++ || (host->data->flags & MMC_DATA_WRITE)) {
+ atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
+ state = STATE_WAITING_NOTBUSY;
+ } else if (host->mrq->stop) {
+@@ -2294,6 +2296,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ host->caps.has_bad_data_ordering = 1;
+ host->caps.need_reset_after_xfer = 1;
+ host->caps.need_blksz_mul_4 = 1;
++ host->caps.need_notbusy_for_read_ops = 0;
+
+ /* keep only major version number */
+ switch (version & 0xf00) {
+@@ -2314,6 +2317,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
+ case 0x200:
+ host->caps.has_rwproof = 1;
+ host->caps.need_blksz_mul_4 = 0;
++ host->caps.need_notbusy_for_read_ops = 1;
+ case 0x100:
+ host->caps.has_bad_data_ordering = 0;
+ host->caps.need_reset_after_xfer = 0;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5447f10bde89a2237dabb7775d927911997f9d10 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Mon, 24 Sep 2012 14:50:45 +0800
-Subject: mtd: atmel_nand: add 4k page nand flash support for PMECC.
-
----
- drivers/mtd/nand/atmel_nand.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index b1158b4..431a8d9 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -952,6 +952,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
- /* set ECC page size and oob layout */
- switch (mtd->writesize) {
- case 2048:
-+ case 4096:
- host->pmecc_degree = PMECC_GF_DIMENSION_13;
- host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
- host->pmecc_sector_number = mtd->writesize / sector_size;
-@@ -977,7 +978,6 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
- break;
- case 512:
- case 1024:
-- case 4096:
- /* TODO */
- dev_warn(host->dev,
- "Unsupported page size for PMECC, use Software ECC\n");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f15c1fee74041aaa81f21f9f499b1f6926bcf716 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:52:48 +0200
+Subject: Replace clk_lookup.con_id with clk_lookup.dev_id entries for twi clk
+
+commit af2a5f09fb6d317a0ec4b5026cd50f0b49a60419 upstream.
+
+The old driver used con_id clock entries. Convert to use dev_id
+for clock lookup via standard method.
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ arch/arm/mach-at91/at91rm9200.c | 1 +
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9261.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9rl.c | 2 ++
+ arch/arm/mach-at91/at91sam9x5.c | 3 +++
+ 7 files changed, 11 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index 6f50c67..f2112f9 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 4696729..d824b0e 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -203,6 +203,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index f40762c..71ca1e0 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -178,6 +178,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index c82d521..00c947e 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index f6d0eab..5de8b00 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -222,6 +222,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index 72ce50a..bf79c1f 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 796b3c0..15ac57b 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -227,6 +227,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 2631653caecceee1abc6643f4253f8a7e53d6284 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Mon, 24 Sep 2012 14:58:38 +0800
-Subject: mtd: atmel_nand: incease the chip_delay time(tR) for support big
- flash chips such like MT29F8G08ABABA.
-
----
- drivers/mtd/nand/atmel_nand.c | 6 +++++-
- 1 file changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 431a8d9..980ffdd 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -1415,7 +1415,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- nand_chip->dev_ready = atmel_nand_device_ready;
-
- nand_chip->ecc.mode = host->board.ecc_mode;
-- nand_chip->chip_delay = 20; /* 20us command delay time */
-+
-+ /* For support 4k-page flash, incease the delay time to 25us.
-+ * In P.108 of MT29F8G08ABABA datasheet, tR max is 25us.
-+ */
-+ nand_chip->chip_delay = 25;
-
- if (host->board.bus_width_16) /* 16-bit bus width */
- nand_chip->options |= NAND_BUSWIDTH_16;
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From cd0c1e4a82957d9f21ad07efa5fcdb553ad28cb2 Mon Sep 17 00:00:00 2001
-From: Josh Wu <josh.wu@atmel.com>
-Date: Tue, 25 Sep 2012 10:40:22 +0800
-Subject: at91: 9x5: add DT parameters to enable PMECC
-
-Signed-off-by: Josh Wu <josh.wu@atmel.com>
----
- arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
- arch/arm/boot/dts/at91sam9x5cm.dtsi | 5 ++++-
- 2 files changed, 8 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 88907db..2cefd49 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -257,7 +257,11 @@
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0x40000000 0x10000000
-+ 0xffffe000 0x600 /* PMECC Registers */
-+ 0xffffe600 0x200 /* PMECC Error Location Registers */
-+ 0x00100000 0x100000 /* ROM code */
- >;
-+ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
- atmel,nand-addr-offset = <21>;
- atmel,nand-cmd-offset = <22>;
- gpios = <&pioD 5 0
-diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
-index 31e7be2..4027ac7 100644
---- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
-@@ -26,7 +26,10 @@
- ahb {
- nand0: nand@40000000 {
- nand-bus-width = <8>;
-- nand-ecc-mode = "soft";
-+ nand-ecc-mode = "hw";
-+ atmel,has-pmecc; /* Enable PMECC */
-+ atmel,pmecc-cap = <2>;
-+ atmel,pmecc-sector-size = <512>;
- nand-on-flash-bbt;
- status = "okay";
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From bec34acb1d565ac4659747861bd68b1b99492c83 Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 11:49:24 +0100
+Subject: i2c: at91: remove old polling driver
+
+commit a879e9c34b93ee43f5caa7f94eb17e7af4f6ef50 upstream.
+
+It will get replaced by a superior one. Safe to remove since this one
+depends on BROKEN anyhow.
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+[wsa: added commit message]
+
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/include/mach/at91_twi.h | 68 -------
+ drivers/i2c/busses/Makefile | 1 -
+ drivers/i2c/busses/i2c-at91.c | 314 -----------------------------
+ 3 files changed, 383 deletions(-)
+ delete mode 100644 arch/arm/mach-at91/include/mach/at91_twi.h
+ delete mode 100644 drivers/i2c/busses/i2c-at91.c
+
+diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h
+deleted file mode 100644
+index bb2880f..0000000
+--- a/arch/arm/mach-at91/include/mach/at91_twi.h
++++ /dev/null
+@@ -1,68 +0,0 @@
+-/*
+- * arch/arm/mach-at91/include/mach/at91_twi.h
+- *
+- * Copyright (C) 2005 Ivan Kokshaysky
+- * Copyright (C) SAN People
+- *
+- * Two-wire Interface (TWI) registers.
+- * Based on AT91RM9200 datasheet revision E.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- */
+-
+-#ifndef AT91_TWI_H
+-#define AT91_TWI_H
+-
+-#define AT91_TWI_CR 0x00 /* Control Register */
+-#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
+-#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
+-#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
+-#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
+-#define AT91_TWI_SVEN (1 << 4) /* Slave Transfer Enable [SAM9260 only] */
+-#define AT91_TWI_SVDIS (1 << 5) /* Slave Transfer Disable [SAM9260 only] */
+-#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
+-
+-#define AT91_TWI_MMR 0x04 /* Master Mode Register */
+-#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
+-#define AT91_TWI_IADRSZ_NO (0 << 8)
+-#define AT91_TWI_IADRSZ_1 (1 << 8)
+-#define AT91_TWI_IADRSZ_2 (2 << 8)
+-#define AT91_TWI_IADRSZ_3 (3 << 8)
+-#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
+-#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
+-
+-#define AT91_TWI_SMR 0x08 /* Slave Mode Register [SAM9260 only] */
+-#define AT91_TWI_SADR (0x7f << 16) /* Slave Address */
+-
+-#define AT91_TWI_IADR 0x0c /* Internal Address Register */
+-
+-#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
+-#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
+-#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
+-#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
+-
+-#define AT91_TWI_SR 0x20 /* Status Register */
+-#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
+-#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
+-#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
+-#define AT91_TWI_SVREAD (1 << 3) /* Slave Read [SAM9260 only] */
+-#define AT91_TWI_SVACC (1 << 4) /* Slave Access [SAM9260 only] */
+-#define AT91_TWI_GACC (1 << 5) /* General Call Access [SAM9260 only] */
+-#define AT91_TWI_OVRE (1 << 6) /* Overrun Error [AT91RM9200 only] */
+-#define AT91_TWI_UNRE (1 << 7) /* Underrun Error [AT91RM9200 only] */
+-#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
+-#define AT91_TWI_ARBLST (1 << 9) /* Arbitration Lost [SAM9260 only] */
+-#define AT91_TWI_SCLWS (1 << 10) /* Clock Wait State [SAM9260 only] */
+-#define AT91_TWI_EOSACC (1 << 11) /* End of Slave Address [SAM9260 only] */
+-
+-#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
+-#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
+-#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
+-#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
+-#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
+-
+-#endif
+-
+diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
+index 569567b..b74c801 100644
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -28,7 +28,6 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+ # Embedded system I2C/SMBus host controller drivers
+-obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+deleted file mode 100644
+index 1679dee..0000000
+--- a/drivers/i2c/busses/i2c-at91.c
++++ /dev/null
+@@ -1,314 +0,0 @@
+-/*
+- i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+-
+- Copyright (C) 2004 Rick Bronson
+- Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+-
+- Borrowed heavily from original work by:
+- Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+-
+- This program is free software; you can redistribute it and/or modify
+- it under the terms of the GNU General Public License as published by
+- the Free Software Foundation; either version 2 of the License, or
+- (at your option) any later version.
+-*/
+-
+-#include <linux/module.h>
+-#include <linux/kernel.h>
+-#include <linux/err.h>
+-#include <linux/slab.h>
+-#include <linux/types.h>
+-#include <linux/delay.h>
+-#include <linux/i2c.h>
+-#include <linux/init.h>
+-#include <linux/clk.h>
+-#include <linux/platform_device.h>
+-#include <linux/io.h>
+-
+-#include <mach/at91_twi.h>
+-#include <mach/board.h>
+-#include <mach/cpu.h>
+-
+-#define TWI_CLOCK 100000 /* Hz. max 400 Kbits/sec */
+-
+-
+-static struct clk *twi_clk;
+-static void __iomem *twi_base;
+-
+-#define at91_twi_read(reg) __raw_readl(twi_base + (reg))
+-#define at91_twi_write(reg, val) __raw_writel((val), twi_base + (reg))
+-
+-
+-/*
+- * Initialize the TWI hardware registers.
+- */
+-static void __devinit at91_twi_hwinit(void)
+-{
+- unsigned long cdiv, ckdiv;
+-
+- at91_twi_write(AT91_TWI_IDR, 0xffffffff); /* Disable all interrupts */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST); /* Reset peripheral */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN); /* Set Master mode */
+-
+- /* Calcuate clock dividers */
+- cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+- cdiv = cdiv + 1; /* round up */
+- ckdiv = 0;
+- while (cdiv > 255) {
+- ckdiv++;
+- cdiv = cdiv >> 1;
+- }
+-
+- if (cpu_is_at91rm9200()) { /* AT91RM9200 Errata #22 */
+- if (ckdiv > 5) {
+- printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+- ckdiv = 5;
+- }
+- }
+-
+- at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+-}
+-
+-/*
+- * Poll the i2c status register until the specified bit is set.
+- * Returns 0 if timed out (100 msec).
+- */
+-static short at91_poll_status(unsigned long bit)
+-{
+- int loop_cntr = 10000;
+-
+- do {
+- udelay(10);
+- } while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+-
+- return (loop_cntr > 0);
+-}
+-
+-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+-{
+- /* Send Start */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+-
+- /* Read data */
+- while (length--) {
+- if (!length) /* need to send Stop before reading last byte */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+- if (!at91_poll_status(AT91_TWI_RXRDY)) {
+- dev_dbg(&adap->dev, "RXRDY timeout\n");
+- return -ETIMEDOUT;
+- }
+- *buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+- }
+-
+- return 0;
+-}
+-
+-static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+-{
+- /* Load first byte into transmitter */
+- at91_twi_write(AT91_TWI_THR, *buf++);
+-
+- /* Send Start */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+-
+- do {
+- if (!at91_poll_status(AT91_TWI_TXRDY)) {
+- dev_dbg(&adap->dev, "TXRDY timeout\n");
+- return -ETIMEDOUT;
+- }
+-
+- length--; /* byte was transmitted */
+-
+- if (length > 0) /* more data to send? */
+- at91_twi_write(AT91_TWI_THR, *buf++);
+- } while (length);
+-
+- /* Send Stop */
+- at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+-
+- return 0;
+-}
+-
+-/*
+- * Generic i2c master transfer entrypoint.
+- *
+- * Note: We do not use Atmel's feature of storing the "internal device address".
+- * Instead the "internal device address" has to be written using a separate
+- * i2c message.
+- * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+- */
+-static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+-{
+- int i, ret;
+-
+- dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+-
+- for (i = 0; i < num; i++) {
+- dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+- pmsg->flags & I2C_M_RD ? "read" : "writ",
+- pmsg->len, pmsg->len > 1 ? "s" : "",
+- pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+-
+- at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+- | ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+-
+- if (pmsg->len && pmsg->buf) { /* sanity check */
+- if (pmsg->flags & I2C_M_RD)
+- ret = xfer_read(adap, pmsg->buf, pmsg->len);
+- else
+- ret = xfer_write(adap, pmsg->buf, pmsg->len);
+-
+- if (ret)
+- return ret;
+-
+- /* Wait until transfer is finished */
+- if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+- dev_dbg(&adap->dev, "TXCOMP timeout\n");
+- return -ETIMEDOUT;
+- }
+- }
+- dev_dbg(&adap->dev, "transfer complete\n");
+- pmsg++; /* next message */
+- }
+- return i;
+-}
+-
+-/*
+- * Return list of supported functionality.
+- */
+-static u32 at91_func(struct i2c_adapter *adapter)
+-{
+- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+-}
+-
+-static struct i2c_algorithm at91_algorithm = {
+- .master_xfer = at91_xfer,
+- .functionality = at91_func,
+-};
+-
+-/*
+- * Main initialization routine.
+- */
+-static int __devinit at91_i2c_probe(struct platform_device *pdev)
+-{
+- struct i2c_adapter *adapter;
+- struct resource *res;
+- int rc;
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!res)
+- return -ENXIO;
+-
+- if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
+- return -EBUSY;
+-
+- twi_base = ioremap(res->start, resource_size(res));
+- if (!twi_base) {
+- rc = -ENOMEM;
+- goto fail0;
+- }
+-
+- twi_clk = clk_get(NULL, "twi_clk");
+- if (IS_ERR(twi_clk)) {
+- dev_err(&pdev->dev, "no clock defined\n");
+- rc = -ENODEV;
+- goto fail1;
+- }
+-
+- adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+- if (adapter == NULL) {
+- dev_err(&pdev->dev, "can't allocate inteface!\n");
+- rc = -ENOMEM;
+- goto fail2;
+- }
+- snprintf(adapter->name, sizeof(adapter->name), "AT91");
+- adapter->algo = &at91_algorithm;
+- adapter->class = I2C_CLASS_HWMON;
+- adapter->dev.parent = &pdev->dev;
+- /* adapter->id == 0 ... only one TWI controller for now */
+-
+- platform_set_drvdata(pdev, adapter);
+-
+- clk_enable(twi_clk); /* enable peripheral clock */
+- at91_twi_hwinit(); /* initialize TWI controller */
+-
+- rc = i2c_add_numbered_adapter(adapter);
+- if (rc) {
+- dev_err(&pdev->dev, "Adapter %s registration failed\n",
+- adapter->name);
+- goto fail3;
+- }
+-
+- dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+- return 0;
+-
+-fail3:
+- platform_set_drvdata(pdev, NULL);
+- kfree(adapter);
+- clk_disable(twi_clk);
+-fail2:
+- clk_put(twi_clk);
+-fail1:
+- iounmap(twi_base);
+-fail0:
+- release_mem_region(res->start, resource_size(res));
+-
+- return rc;
+-}
+-
+-static int __devexit at91_i2c_remove(struct platform_device *pdev)
+-{
+- struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+- struct resource *res;
+- int rc;
+-
+- rc = i2c_del_adapter(adapter);
+- platform_set_drvdata(pdev, NULL);
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- iounmap(twi_base);
+- release_mem_region(res->start, resource_size(res));
+-
+- clk_disable(twi_clk); /* disable peripheral clock */
+- clk_put(twi_clk);
+-
+- return rc;
+-}
+-
+-#ifdef CONFIG_PM
+-
+-/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+-
+-static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+-{
+- clk_disable(twi_clk);
+- return 0;
+-}
+-
+-static int at91_i2c_resume(struct platform_device *pdev)
+-{
+- return clk_enable(twi_clk);
+-}
+-
+-#else
+-#define at91_i2c_suspend NULL
+-#define at91_i2c_resume NULL
+-#endif
+-
+-static struct platform_driver at91_i2c_driver = {
+- .probe = at91_i2c_probe,
+- .remove = __devexit_p(at91_i2c_remove),
+- .suspend = at91_i2c_suspend,
+- .resume = at91_i2c_resume,
+- .driver = {
+- .name = "at91_i2c",
+- .owner = THIS_MODULE,
+- },
+-};
+-
+-module_platform_driver(at91_i2c_driver);
+-
+-MODULE_AUTHOR("Rick Bronson");
+-MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform:at91_i2c");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5656f4e07c7b30e26ecd3716c8ab1c9157946e80 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 2 Oct 2012 11:50:15 +0200
-Subject: ARM: at91: split 9x5 dts/dtsi in a "common" set of peripherals
-
-Creating this new at91sam9x5_common.dtsi, will allow to cover the
-whole at91sam9x5 family of SoCs without having to duplicate nodes.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9g25ek.dts
----
- arch/arm/boot/dts/at91sam9g25ek.dts | 19 +----------
- arch/arm/boot/dts/at91sam9x5_common.dtsi | 54 ++++++++++++++++++++++++++++++++
- 2 files changed, 55 insertions(+), 18 deletions(-)
- create mode 100644 arch/arm/boot/dts/at91sam9x5_common.dtsi
-
-diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
-index 5b054e4..91c0f02 100644
---- a/arch/arm/boot/dts/at91sam9g25ek.dts
-+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
-@@ -7,8 +7,7 @@
- * Licensed under GPLv2 or later.
- */
- /dts-v1/;
--/include/ "at91sam9x5.dtsi"
--/include/ "at91sam9x5cm.dtsi"
-+/include/ "at91sam9x5_common.dtsi"
-
- / {
- model = "Atmel AT91SAM9G25-EK";
-@@ -20,10 +19,6 @@
-
- ahb {
- apb {
-- dbgu: serial@fffff200 {
-- status = "okay";
-- };
--
- usart0: serial@f801c000 {
- status = "okay";
- };
-@@ -63,17 +58,5 @@
- status = "okay";
- };
- };
--
-- usb0: ohci@00600000 {
-- status = "okay";
-- num-ports = <2>;
-- atmel,vbus-gpio = <&pioD 19 1
-- &pioD 20 1
-- >;
-- };
--
-- usb1: ehci@00700000 {
-- status = "okay";
-- };
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9x5_common.dtsi b/arch/arm/boot/dts/at91sam9x5_common.dtsi
-new file mode 100644
-index 0000000..b805425
---- /dev/null
-+++ b/arch/arm/boot/dts/at91sam9x5_common.dtsi
-@@ -0,0 +1,54 @@
-+/*
-+ * at91sam9x5_common.dtsi - Device Tree Include file for AT91SAM9x5 Evaluation Kit:
-+ * common peripherals.
-+ *
-+ * Copyright (C) 2012 Atmel,
-+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
-+ *
-+ * Licensed under GPLv2 or later.
-+ */
-+/include/ "at91sam9x5.dtsi"
-+/include/ "at91sam9x5cm.dtsi"
-+
-+/ {
-+ ahb {
-+ apb {
-+ dbgu: serial@fffff200 {
-+ status = "okay";
-+ };
-+
-+ mmc0: mmc@f0008000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 15 0>;
-+ };
-+ };
-+
-+ i2c0: i2c@f8010000 {
-+ status = "okay";
-+ };
-+
-+ i2c1: i2c@f8014000 {
-+ status = "okay";
-+ };
-+
-+ i2c2: i2c@f8018000 {
-+ status = "okay";
-+ };
-+ };
-+
-+ usb0: ohci@00600000 {
-+ status = "okay";
-+ num-ports = <2>;
-+ atmel,vbus-gpio = <&pioD 19 1
-+ &pioD 20 1
-+ >;
-+ };
-+
-+ usb1: ehci@00700000 {
-+ status = "okay";
-+ };
-+ };
-+};
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 3fbefb2c85df4c467c48f9963119f26c62d7a31b Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 11:49:46 +0100
+Subject: i2c: at91: add new driver
+
+commit fac368a040484293006bb488e67972aafcf88ec7 upstream.
+
+This driver has the following properties compared to the old driver:
+1. Support for multiple interfaces.
+2. Interrupt driven I/O as opposed to polling/busy waiting.
+3. Support for _one_ repeated start (Sr) condition, which is enough
+ for most real-world applications including all SMBus transfer types.
+ (The hardware does not support issuing arbitrary Sr conditions on the
+ bus.)
+
+testing: SoC: at91sam9g45
+ - BQ20Z80 battery SMBus client.
+ - on a 2.6.38 kernel with several i2c clients (temp-sensor,
+ audio-codec, touchscreen-controller, w1-bridge, io-expanders)
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Reviewed-by: Felipe Balbi <balbi@ti.com>
+Tested-by: Hubert Feurstein <h.feurstein@gmail.com>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+[wsa: squashed with the following patches from Ludovic to have some flaws
+fixed:
+ i2c: at91: use managed resources
+ i2c: at91: add warning about transmission issues for some devices
+ i2c: at91: use an id table for SoC dependent parameters
+]
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91rm9200.c | 2
+ arch/arm/mach-at91/at91rm9200_devices.c | 2
+ arch/arm/mach-at91/at91sam9260.c | 3
+ arch/arm/mach-at91/at91sam9260_devices.c | 8
+ arch/arm/mach-at91/at91sam9261.c | 3
+ arch/arm/mach-at91/at91sam9261_devices.c | 8
+ arch/arm/mach-at91/at91sam9263.c | 2
+ arch/arm/mach-at91/at91sam9263_devices.c | 2
+ arch/arm/mach-at91/at91sam9g45.c | 4
+ arch/arm/mach-at91/at91sam9g45_devices.c | 4
+ arch/arm/mach-at91/at91sam9rl.c | 4
+ arch/arm/mach-at91/at91sam9rl_devices.c | 2
+ drivers/i2c/busses/Kconfig | 17 -
+ drivers/i2c/busses/Makefile | 1
+ drivers/i2c/busses/i2c-at91.c | 505 +++++++++++++++++++++++++++++++
+ 15 files changed, 545 insertions(+), 22 deletions(-)
+ create mode 100644 drivers/i2c/busses/i2c-at91.c
+
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+--- a/arch/arm/mach-at91/at91rm9200_devices.c
++++ b/arch/arm/mach-at91/at91rm9200_devices.c
+@@ -511,7 +511,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91rm9200_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91rm9200",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -203,7 +203,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
+--- a/arch/arm/mach-at91/at91sam9260_devices.c
++++ b/arch/arm/mach-at91/at91sam9260_devices.c
+@@ -418,7 +418,6 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9260_twi_device = {
+- .name = "at91_i2c",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+@@ -426,6 +425,13 @@ static struct platform_device at91sam926
+
+ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ {
++ /* IP version is not the same on 9260 and g20 */
++ if (cpu_is_at91sam9g20()) {
++ at91sam9260_twi_device.name = "i2c-at91sam9g20";
++ } else {
++ at91sam9260_twi_device.name = "i2c-at91sam9260";
++ }
++
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA23, 1);
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -178,7 +178,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -319,7 +319,6 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9261_twi_device = {
+- .name = "at91_i2c",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+@@ -327,6 +326,13 @@ static struct platform_device at91sam926
+
+ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ {
++ /* IP version is not the same on 9261 and g10 */
++ if (cpu_is_at91sam9g10()) {
++ at91sam9261_twi_device.name = "i2c-at91sam9g10";
++ } else {
++ at91sam9261_twi_device.name = "i2c-at91sam9261";
++ }
++
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
+ at91_set_multi_drive(AT91_PIN_PA7, 1);
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+--- a/arch/arm/mach-at91/at91sam9263_devices.c
++++ b/arch/arm/mach-at91/at91sam9263_devices.c
+@@ -601,7 +601,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9263_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9260",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -222,8 +222,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -651,7 +651,7 @@ static struct resource twi0_resources[]
+ };
+
+ static struct platform_device at91sam9g45_twi0_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g10",
+ .id = 0,
+ .resource = twi0_resources,
+ .num_resources = ARRAY_SIZE(twi0_resources),
+@@ -671,7 +671,7 @@ static struct resource twi1_resources[]
+ };
+
+ static struct platform_device at91sam9g45_twi1_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g10",
+ .id = 1,
+ .resource = twi1_resources,
+ .num_resources = ARRAY_SIZE(twi1_resources),
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -186,8 +186,8 @@ static struct clk_lookup periph_clocks_l
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+--- a/arch/arm/mach-at91/at91sam9rl_devices.c
++++ b/arch/arm/mach-at91/at91sam9rl_devices.c
+@@ -348,7 +348,7 @@ static struct resource twi_resources[] =
+ };
+
+ static struct platform_device at91sam9rl_twi_device = {
+- .name = "at91_i2c",
++ .name = "i2c-at91sam9g20",
+ .id = -1,
+ .resource = twi_resources,
+ .num_resources = ARRAY_SIZE(twi_resources),
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -287,18 +287,21 @@ comment "I2C system bus drivers (mostly
+
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+- depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
++ depends on ARCH_AT91 && EXPERIMENTAL
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+
+- This driver is BROKEN because the controller which it uses
+- will easily trigger RX overrun and TX underrun errors. Using
+- low I2C clock rates may partially work around those issues
+- on some systems. Another serious problem is that there is no
+- documented way to issue repeated START conditions, as needed
++ A serious problem is that there is no documented way to issue
++ repeated START conditions for more than two messages, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+- unless your system can cope with those limitations.
++ unless your system can cope with this limitation.
++
++ Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices
++ don't have clock stretching in transmission mode. For that reason,
++ you can encounter underrun issues causing premature stop sendings if
++ the latency to fill the transmission register is too long. If you
++ are facing this situation, use the i2c-gpio driver.
+
+ config I2C_AU1550
+ tristate "Au1550/Au1200/Au1300 SMBus interface"
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -28,6 +28,7 @@ obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
+ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
+
+ # Embedded system I2C/SMBus host controller drivers
++obj-$(CONFIG_I2C_AT91) += i2c-at91.o
+ obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+ obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -0,0 +1,505 @@
++/*
++ * i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
++ *
++ * Copyright (C) 2011 Weinmann Medical GmbH
++ * Author: Nikolaus Voss <n.voss@weinmann.de>
++ *
++ * Evolved from original work by:
++ * Copyright (C) 2004 Rick Bronson
++ * Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
++ *
++ * Borrowed heavily from original work by:
++ * Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/clk.h>
++#include <linux/completion.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
++#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
++
++/* AT91 TWI register definitions */
++#define AT91_TWI_CR 0x0000 /* Control Register */
++#define AT91_TWI_START 0x0001 /* Send a Start Condition */
++#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */
++#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */
++#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */
++#define AT91_TWI_SWRST 0x0080 /* Software Reset */
++
++#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
++#define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */
++#define AT91_TWI_MREAD 0x1000 /* Master Read Direction */
++
++#define AT91_TWI_IADR 0x000c /* Internal Address Register */
++
++#define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */
++
++#define AT91_TWI_SR 0x0020 /* Status Register */
++#define AT91_TWI_TXCOMP 0x0001 /* Transmission Complete */
++#define AT91_TWI_RXRDY 0x0002 /* Receive Holding Register Ready */
++#define AT91_TWI_TXRDY 0x0004 /* Transmit Holding Register Ready */
++
++#define AT91_TWI_OVRE 0x0040 /* Overrun Error */
++#define AT91_TWI_UNRE 0x0080 /* Underrun Error */
++#define AT91_TWI_NACK 0x0100 /* Not Acknowledged */
++
++#define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */
++#define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */
++#define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */
++#define AT91_TWI_RHR 0x0030 /* Receive Holding Register */
++#define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
++
++struct at91_twi_pdata {
++ unsigned clk_max_div;
++ unsigned clk_offset;
++ bool has_unre_flag;
++};
++
++struct at91_twi_dev {
++ struct device *dev;
++ void __iomem *base;
++ struct completion cmd_complete;
++ struct clk *clk;
++ u8 *buf;
++ size_t buf_len;
++ struct i2c_msg *msg;
++ int irq;
++ unsigned transfer_status;
++ struct i2c_adapter adapter;
++ unsigned twi_cwgr_reg;
++ struct at91_twi_pdata *pdata;
++};
++
++static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
++{
++ return readl_relaxed(dev->base + reg);
++}
++
++static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
++{
++ writel_relaxed(val, dev->base + reg);
++}
++
++static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
++{
++ at91_twi_write(dev, AT91_TWI_IDR,
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++}
++
++static void at91_init_twi_bus(struct at91_twi_dev *dev)
++{
++ at91_disable_twi_interrupts(dev);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN);
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS);
++ at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg);
++}
++
++/*
++ * Calculate symmetric clock as stated in datasheet:
++ * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
++ */
++static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
++{
++ int ckdiv, cdiv, div;
++ struct at91_twi_pdata *pdata = dev->pdata;
++ int offset = pdata->clk_offset;
++ int max_ckdiv = pdata->clk_max_div;
++
++ div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk),
++ 2 * twi_clk) - offset);
++ ckdiv = fls(div >> 8);
++ cdiv = div >> ckdiv;
++
++ if (ckdiv > max_ckdiv) {
++ dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n",
++ ckdiv, max_ckdiv);
++ ckdiv = max_ckdiv;
++ cdiv = 255;
++ }
++
++ dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv;
++ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
++}
++
++static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
++{
++ if (dev->buf_len <= 0)
++ return;
++
++ at91_twi_write(dev, AT91_TWI_THR, *dev->buf);
++
++ /* send stop when last byte has been written */
++ if (--dev->buf_len == 0)
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++
++ dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len);
++
++ ++dev->buf;
++}
++
++static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
++{
++ if (dev->buf_len <= 0)
++ return;
++
++ *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
++ --dev->buf_len;
++
++ /* handle I2C_SMBUS_BLOCK_DATA */
++ if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
++ dev->msg->flags &= ~I2C_M_RECV_LEN;
++ dev->buf_len += *dev->buf;
++ dev->msg->len = dev->buf_len + 1;
++ dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
++ }
++
++ /* send stop if second but last byte has been read */
++ if (dev->buf_len == 1)
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++
++ dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len);
++
++ ++dev->buf;
++}
++
++static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
++{
++ struct at91_twi_dev *dev = dev_id;
++ const unsigned status = at91_twi_read(dev, AT91_TWI_SR);
++ const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR);
++
++ if (!irqstatus)
++ return IRQ_NONE;
++ else if (irqstatus & AT91_TWI_RXRDY)
++ at91_twi_read_next_byte(dev);
++ else if (irqstatus & AT91_TWI_TXRDY)
++ at91_twi_write_next_byte(dev);
++
++ /* catch error flags */
++ dev->transfer_status |= status;
++
++ if (irqstatus & AT91_TWI_TXCOMP) {
++ at91_disable_twi_interrupts(dev);
++ complete(&dev->cmd_complete);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int at91_do_twi_transfer(struct at91_twi_dev *dev)
++{
++ int ret;
++ bool has_unre_flag = dev->pdata->has_unre_flag;
++
++ dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
++ (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len);
++
++ INIT_COMPLETION(dev->cmd_complete);
++ dev->transfer_status = 0;
++ if (dev->msg->flags & I2C_M_RD) {
++ unsigned start_flags = AT91_TWI_START;
++
++ if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
++ dev_err(dev->dev, "RXRDY still set!");
++ at91_twi_read(dev, AT91_TWI_RHR);
++ }
++
++ /* if only one byte is to be read, immediately stop transfer */
++ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
++ start_flags |= AT91_TWI_STOP;
++ at91_twi_write(dev, AT91_TWI_CR, start_flags);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
++ } else {
++ at91_twi_write_next_byte(dev);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ }
++
++ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
++ dev->adapter.timeout);
++ if (ret == 0) {
++ dev_err(dev->dev, "controller timed out\n");
++ at91_init_twi_bus(dev);
++ return -ETIMEDOUT;
++ }
++ if (dev->transfer_status & AT91_TWI_NACK) {
++ dev_dbg(dev->dev, "received nack\n");
++ return -EREMOTEIO;
++ }
++ if (dev->transfer_status & AT91_TWI_OVRE) {
++ dev_err(dev->dev, "overrun while reading\n");
++ return -EIO;
++ }
++ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
++ dev_err(dev->dev, "underrun while writing\n");
++ return -EIO;
++ }
++ dev_dbg(dev->dev, "transfer complete\n");
++
++ return 0;
++}
++
++static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
++{
++ struct at91_twi_dev *dev = i2c_get_adapdata(adap);
++ int ret;
++ unsigned int_addr_flag = 0;
++ struct i2c_msg *m_start = msg;
++
++ dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
++
++ /*
++ * The hardware can handle at most two messages concatenated by a
++ * repeated start via it's internal address feature.
++ */
++ if (num > 2) {
++ dev_err(dev->dev,
++ "cannot handle more than two concatenated messages.\n");
++ return 0;
++ } else if (num == 2) {
++ int internal_address = 0;
++ int i;
++
++ if (msg->flags & I2C_M_RD) {
++ dev_err(dev->dev, "first transfer must be write.\n");
++ return -EINVAL;
++ }
++ if (msg->len > 3) {
++ dev_err(dev->dev, "first message size must be <= 3.\n");
++ return -EINVAL;
++ }
++
++ /* 1st msg is put into the internal address, start with 2nd */
++ m_start = &msg[1];
++ for (i = 0; i < msg->len; ++i) {
++ const unsigned addr = msg->buf[msg->len - 1 - i];
++
++ internal_address |= addr << (8 * i);
++ int_addr_flag += AT91_TWI_IADRSZ_1;
++ }
++ at91_twi_write(dev, AT91_TWI_IADR, internal_address);
++ }
++
++ at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag
++ | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
++
++ dev->buf_len = m_start->len;
++ dev->buf = m_start->buf;
++ dev->msg = m_start;
++
++ ret = at91_do_twi_transfer(dev);
++
++ return (ret < 0) ? ret : num;
++}
++
++static u32 at91_twi_func(struct i2c_adapter *adapter)
++{
++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
++ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
++}
++
++static struct i2c_algorithm at91_twi_algorithm = {
++ .master_xfer = at91_twi_xfer,
++ .functionality = at91_twi_func,
++};
++
++static struct at91_twi_pdata at91rm9200_config = {
++ .clk_max_div = 5,
++ .clk_offset = 3,
++ .has_unre_flag = true,
++};
++
++static struct at91_twi_pdata at91sam9261_config = {
++ .clk_max_div = 5,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9260_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9g20_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static struct at91_twi_pdata at91sam9g10_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
++static const struct platform_device_id at91_twi_devtypes[] = {
++ {
++ .name = "i2c-at91rm9200",
++ .driver_data = (unsigned long) &at91rm9200_config,
++ }, {
++ .name = "i2c-at91sam9261",
++ .driver_data = (unsigned long) &at91sam9261_config,
++ }, {
++ .name = "i2c-at91sam9260",
++ .driver_data = (unsigned long) &at91sam9260_config,
++ }, {
++ .name = "i2c-at91sam9g20",
++ .driver_data = (unsigned long) &at91sam9g20_config,
++ }, {
++ .name = "i2c-at91sam9g10",
++ .driver_data = (unsigned long) &at91sam9g10_config,
++ }, {
++ /* sentinel */
++ }
++};
++
++static int __devinit at91_twi_probe(struct platform_device *pdev)
++{
++ struct at91_twi_dev *dev;
++ struct resource *mem;
++ int rc;
++
++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
++ if (!dev)
++ return -ENOMEM;
++ init_completion(&dev->cmd_complete);
++ dev->dev = &pdev->dev;
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem)
++ return -ENODEV;
++
++ dev->pdata = at91_twi_get_driver_data(pdev);
++ if (!dev->pdata)
++ return -ENODEV;
++
++ dev->base = devm_request_and_ioremap(&pdev->dev, mem);
++ if (!dev->base)
++ return -EBUSY;
++
++ dev->irq = platform_get_irq(pdev, 0);
++ if (dev->irq < 0)
++ return dev->irq;
++
++ rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0,
++ dev_name(dev->dev), dev);
++ if (rc) {
++ dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc);
++ return rc;
++ }
++
++ platform_set_drvdata(pdev, dev);
++
++ dev->clk = devm_clk_get(dev->dev, NULL);
++ if (IS_ERR(dev->clk)) {
++ dev_err(dev->dev, "no clock defined\n");
++ return -ENODEV;
++ }
++ clk_prepare_enable(dev->clk);
++
++ at91_calc_twi_clock(dev, TWI_CLK_HZ);
++ at91_init_twi_bus(dev);
++
++ snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
++ i2c_set_adapdata(&dev->adapter, dev);
++ dev->adapter.owner = THIS_MODULE;
++ dev->adapter.class = I2C_CLASS_HWMON;
++ dev->adapter.algo = &at91_twi_algorithm;
++ dev->adapter.dev.parent = dev->dev;
++ dev->adapter.nr = pdev->id;
++ dev->adapter.timeout = AT91_I2C_TIMEOUT;
++
++ rc = i2c_add_numbered_adapter(&dev->adapter);
++ if (rc) {
++ dev_err(dev->dev, "Adapter %s registration failed\n",
++ dev->adapter.name);
++ clk_disable_unprepare(dev->clk);
++ return rc;
++ }
++
++ dev_info(dev->dev, "AT91 i2c bus driver.\n");
++ return 0;
++}
++
++static int __devexit at91_twi_remove(struct platform_device *pdev)
++{
++ struct at91_twi_dev *dev = platform_get_drvdata(pdev);
++ int rc;
++
++ rc = i2c_del_adapter(&dev->adapter);
++ clk_disable_unprepare(dev->clk);
++
++ return rc;
++}
++
++#ifdef CONFIG_PM
++
++static int at91_twi_runtime_suspend(struct device *dev)
++{
++ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
++
++ clk_disable(twi_dev->clk);
++
++ return 0;
++}
++
++static int at91_twi_runtime_resume(struct device *dev)
++{
++ struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
++
++ return clk_enable(twi_dev->clk);
++}
++
++static const struct dev_pm_ops at91_twi_pm = {
++ .runtime_suspend = at91_twi_runtime_suspend,
++ .runtime_resume = at91_twi_runtime_resume,
++};
++
++#define at91_twi_pm_ops (&at91_twi_pm)
++#else
++#define at91_twi_pm_ops NULL
++#endif
++
++static struct platform_driver at91_twi_driver = {
++ .probe = at91_twi_probe,
++ .remove = __devexit_p(at91_twi_remove),
++ .id_table = at91_twi_devtypes,
++ .driver = {
++ .name = "at91_i2c",
++ .owner = THIS_MODULE,
++ .pm = at91_twi_pm_ops,
++ },
++};
++
++static int __init at91_twi_init(void)
++{
++ return platform_driver_register(&at91_twi_driver);
++}
++
++static void __exit at91_twi_exit(void)
++{
++ platform_driver_unregister(&at91_twi_driver);
++}
++
++subsys_initcall(at91_twi_init);
++module_exit(at91_twi_exit);
++
++MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
++MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:at91_i2c");
+++ /dev/null
-From 632da89db09717d999cad5669385db5a85e876ab Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 2 Oct 2012 11:55:18 +0200
-Subject: ARM: at91/9x5 family: add at91sam9x25ek.dts
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9x25ek.dts | 46 +++++++++++++++++++++++++++++++++++++
- arch/arm/mach-at91/Makefile.boot | 1 +
- 2 files changed, 47 insertions(+)
- create mode 100644 arch/arm/boot/dts/at91sam9x25ek.dts
-
-diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
-new file mode 100644
-index 0000000..cf903f5
---- /dev/null
-+++ b/arch/arm/boot/dts/at91sam9x25ek.dts
-@@ -0,0 +1,46 @@
-+/*
-+ * at91sam9x25ek.dts - Device Tree file for AT91SAM9X25-EK board
-+ *
-+ * Copyright (C) 2012 Atmel,
-+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
-+ *
-+ * Licensed under GPLv2 or later.
-+ */
-+/dts-v1/;
-+/include/ "at91sam9x5_common.dtsi"
-+
-+/ {
-+ model = "Atmel AT91SAM9X25-EK";
-+ compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
-+
-+ chosen {
-+ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
-+ };
-+
-+ ahb {
-+ apb {
-+ mmc1: mmc@f000c000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 14 0>;
-+ };
-+ };
-+
-+ usart0: serial@f801c000 {
-+ status = "okay";
-+ };
-+
-+ macb0: ethernet@f802c000 {
-+ phy-mode = "rmii";
-+ status = "okay";
-+ };
-+
-+ macb1: ethernet@f8030000 {
-+ phy-mode = "rmii";
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
-diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
-index 9e84fe4..9532f93 100644
---- a/arch/arm/mach-at91/Makefile.boot
-+++ b/arch/arm/mach-at91/Makefile.boot
-@@ -34,3 +34,4 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
- dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
- # sam9x5
- dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
-+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 5ef32638a0ab40462ae3f103062d27b47c9f1ca0 Mon Sep 17 00:00:00 2001
+From: Nikolaus Voss <n.voss@weinmann.de>
+Date: Tue, 8 Nov 2011 12:11:03 +0100
+Subject: arm: at91: G45 TWI: remove open drain setting for twi function gpios
+
+commit 774c8018d2566207c92f47b6421dad7d88bbfd49 upstream.
+
+The G45 datasheets explicitly states that setting the open drain property
+on peripheral function gpios is not allowed. (How about other A91 chips?)
+
+Signed-off-by: Nikolaus Voss <n.voss@weinmann.de>
+Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Reviewed-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 4223d28..29f334c 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -684,18 +684,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in
+ /* pins used for TWI interface */
+ if (i2c_id == 0) {
+ at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PA20, 1);
+-
+ at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PA21, 1);
+
+ platform_device_register(&at91sam9g45_twi0_device);
+ } else {
+ at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PB10, 1);
+-
+ at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PB11, 1);
+
+ platform_device_register(&at91sam9g45_twi1_device);
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 4b171e9b798f8fc6ce79303691522c080b085c5c Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 19:04:39 +0200
-Subject: ARM: at91: add new at91sam9g35ek.dts
-
-With LCD DT definition
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9g35ek.dts | 49 +++++++++++++++++++++++++++++++++++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 15 ++++++++++++
- arch/arm/mach-at91/Makefile.boot | 1 +
- 3 files changed, 65 insertions(+)
- create mode 100644 arch/arm/boot/dts/at91sam9g35ek.dts
-
-diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
-new file mode 100644
-index 0000000..f2c3341
---- /dev/null
-+++ b/arch/arm/boot/dts/at91sam9g35ek.dts
-@@ -0,0 +1,49 @@
-+/*
-+ * at91sam9g35ek.dts - Device Tree file for AT91SAM9G35-EK board
-+ *
-+ * Copyright (C) 2012 Atmel,
-+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
-+ *
-+ * Licensed under GPLv2 or later.
-+ */
-+/dts-v1/;
-+/include/ "at91sam9x5_common.dtsi"
-+
-+/ {
-+ model = "Atmel AT91SAM9G35-EK";
-+ compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
-+
-+ chosen {
-+ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
-+ };
-+
-+ ahb {
-+ apb {
-+ mmc1: mmc@f000c000 {
-+ status = "okay";
-+ slot@0 {
-+ reg = <0>;
-+ bus-width = <4>;
-+ cd-gpios = <&pioD 14 0>;
-+ };
-+ };
-+
-+ usart0: serial@f801c000 {
-+ status = "okay";
-+ };
-+
-+ macb0: ethernet@f802c000 {
-+ phy-mode = "rmii";
-+ status = "okay";
-+ };
-+
-+ lcd@f8038000 {
-+ status = "okay";
-+ };
-+
-+ lcdovl1@f8038100 {
-+ status = "okay";
-+ };
-+ };
-+ };
-+};
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 2cefd49..50388fd 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -250,6 +250,21 @@
- #size-cells = <0>;
- status = "disabled";
- };
-+
-+ lcd@f8038000 {
-+ compatible = "atmel,at91sam9x5-lcd";
-+ reg = <0xf8038000 0xff
-+ 0xf8038400 0x3ff>;
-+ interrupts = <25 4 3>;
-+ status = "disabled";
-+ };
-+
-+ lcdovl1@f8038100 {
-+ compatible = "atmel,at91sam9x5-lcd";
-+ reg = <0xf8038100 0xff
-+ 0xf8038800 0x3ff>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
-diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
-index 9532f93..410485a 100644
---- a/arch/arm/mach-at91/Makefile.boot
-+++ b/arch/arm/mach-at91/Makefile.boot
-@@ -34,4 +34,5 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
- dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
- # sam9x5
- dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
-+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g35ek.dtb
- dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 5a1164b76ebc50a37e21818651b755787c19dc26 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:13 +0200
+Subject: ARM: at91: do not configure at91sam9g10 twi pio as open-drain
+
+commit 94e734655fbe294c50d304547cae033e87ec229e upstream.
+
+As indicated in the datasheet, TWD and TWCK must not be programmed as
+open-drain.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/mach-at91/at91sam9261_devices.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
+index 3d7b2f4..d2ae522 100644
+--- a/arch/arm/mach-at91/at91sam9261_devices.c
++++ b/arch/arm/mach-at91/at91sam9261_devices.c
+@@ -329,16 +329,16 @@ void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
+ /* IP version is not the same on 9261 and g10 */
+ if (cpu_is_at91sam9g10()) {
+ at91sam9261_twi_device.name = "i2c-at91sam9g10";
++ /* I2C PIO must not be configured as open-drain on this chip */
+ } else {
+ at91sam9261_twi_device.name = "i2c-at91sam9261";
++ at91_set_multi_drive(AT91_PIN_PA7, 1);
++ at91_set_multi_drive(AT91_PIN_PA8, 1);
+ }
+
+ /* pins used for TWI interface */
+ at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
+- at91_set_multi_drive(AT91_PIN_PA7, 1);
+-
+ at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
+- at91_set_multi_drive(AT91_PIN_PA8, 1);
+
+ i2c_register_board_info(0, devices, nr_devices);
+ platform_device_register(&at91sam9261_twi_device);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From a9002e549702ca79f7bc946b3ec1072eca79a563 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Tue, 16 Oct 2012 19:05:25 +0200
-Subject: ARM: at91: add pinmux for 9x5 LCD
-
-Temporaty in board-dt
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/mach-at91/board-dt.c | 102 +++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 101 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
-index 15830cb..c0d242c 100644
---- a/arch/arm/mach-at91/board-dt.c
-+++ b/arch/arm/mach-at91/board-dt.c
-@@ -26,6 +26,103 @@
-
- #include "generic.h"
-
-+#include <linux/fb.h>
-+
-+#include <video/atmel_lcdfb.h>
-+#include <mach/atmel_hlcdc.h>
-+
-+/*
-+ * LCD Controller
-+ */
-+static struct fb_videomode at91_tft_vga_modes[] = {
-+ {
-+ .name = "LG",
-+ .refresh = 60,
-+ .xres = 800, .yres = 480,
-+ .pixclock = KHZ2PICOS(33260),
-+
-+ .left_margin = 88, .right_margin = 168,
-+ .upper_margin = 8, .lower_margin = 37,
-+ .hsync_len = 128, .vsync_len = 2,
-+
-+ .sync = 0,
-+ .vmode = FB_VMODE_NONINTERLACED,
-+ },
-+};
-+
-+static struct fb_monspecs at91fb_default_monspecs = {
-+ .manufacturer = "LG",
-+ .monitor = "LB043WQ1",
-+
-+ .modedb = at91_tft_vga_modes,
-+ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
-+ .hfmin = 15000,
-+ .hfmax = 17640,
-+ .vfmin = 57,
-+ .vfmax = 67,
-+};
-+
-+/* Default output mode is TFT 24 bit */
-+#define BPP_OUT_DEFAULT_LCDCFG5 (LCDC_LCDCFG5_MODE_OUTPUT_24BPP)
-+
-+/* Driver datas */
-+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
-+ .lcdcon_is_backlight = true,
-+ .alpha_enabled = false,
-+ .default_bpp = 16,
-+ /* Reserve enough memory for 32bpp */
-+ .smem_len = 800 * 480 * 4,
-+ /* default_lcdcon2 is used for LCDCFG5 */
-+ .default_lcdcon2 = BPP_OUT_DEFAULT_LCDCFG5,
-+ .default_monspecs = &at91fb_default_monspecs,
-+ .guard_time = 9,
-+ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
-+};
-+
-+void __init at91sam9x5_pinmux_lcd(void)
-+{
-+ at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDPWM */
-+
-+ at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDVSYNC */
-+ at91_set_A_periph(AT91_PIN_PC28, 0); /* LCDHSYNC */
-+
-+ at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDDISP */
-+ at91_set_A_periph(AT91_PIN_PC29, 0); /* LCDDEN */
-+ at91_set_A_periph(AT91_PIN_PC30, 0); /* LCDPCK */
-+
-+ at91_set_A_periph(AT91_PIN_PC0, 0); /* LCDD0 */
-+ at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDD1 */
-+ at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDD2 */
-+ at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDD3 */
-+ at91_set_A_periph(AT91_PIN_PC4, 0); /* LCDD4 */
-+ at91_set_A_periph(AT91_PIN_PC5, 0); /* LCDD5 */
-+ at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD6 */
-+ at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD7 */
-+ at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD8 */
-+ at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD9 */
-+ at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD10 */
-+ at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD11 */
-+ at91_set_A_periph(AT91_PIN_PC12, 0); /* LCDD12 */
-+ at91_set_A_periph(AT91_PIN_PC13, 0); /* LCDD13 */
-+ at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD14 */
-+ at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD15 */
-+ at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD16 */
-+ at91_set_A_periph(AT91_PIN_PC17, 0); /* LCDD17 */
-+ at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD18 */
-+ at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD19 */
-+ at91_set_A_periph(AT91_PIN_PC20, 0); /* LCDD20 */
-+ at91_set_A_periph(AT91_PIN_PC21, 0); /* LCDD21 */
-+ at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD22 */
-+ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */
-+
-+ printk("AT91: lcd pin mux done\n");
-+}
-+
-+struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
-+ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038000, "atmel_hlcdfb_base", &ek_lcdc_data),
-+ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038100, "atmel_hlcdfb_ovl", &ek_lcdc_data),
-+ { /* sentinel */ }
-+};
-
- static const struct of_device_id irq_of_match[] __initconst = {
-
-@@ -42,7 +139,6 @@ static void __init at91_dt_init_irq(void)
-
- static void __init at91_dt_device_init(void)
- {
-- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
- /* Temporary pin mux stuff */
- if (of_machine_is_compatible("atmel,at91sam9x5")) {
- at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
-@@ -74,7 +170,11 @@ static void __init at91_dt_device_init(void)
- at91_set_B_periph(AT91_PIN_PA3, 1);
- at91_set_B_periph(AT91_PIN_PA4, 1);
- printk("AT91: mci0/1 pin mux done\n");
-+
-+ at91sam9x5_pinmux_lcd();
- }
-+
-+ of_platform_populate(NULL, of_default_bus_match_table, at91_auxdata_lookup, NULL);
- }
-
- static const char *at91_dt_board_compat[] __initdata = {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2fdca46a8f7ee49b6f38f8d8a42c14cfaf02881b Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:14 +0200
+Subject: i2c: at91: add dt support to i2c-at91
+
+commit 70d46a241ed3bb0d1bb2bc15720b6f7c215c37f5 upstream.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ .../devicetree/bindings/i2c/atmel-i2c.txt | 30 +++++++++++++
+ drivers/i2c/busses/i2c-at91.c | 49 ++++++++++++++++++++++
+ 2 files changed, 79 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+
+diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+new file mode 100644
+index 0000000..b689a0d
+--- /dev/null
++++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt
+@@ -0,0 +1,30 @@
++I2C for Atmel platforms
++
++Required properties :
++- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c",
++ "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c"
++ or "atmel,at91sam9x5-i2c"
++- reg: physical base address of the controller and length of memory mapped
++ region.
++- interrupts: interrupt number to the cpu.
++- #address-cells = <1>;
++- #size-cells = <0>;
++
++Optional properties:
++- Child nodes conforming to i2c bus binding
++
++Examples :
++
++i2c0: i2c@fff84000 {
++ compatible = "atmel,at91sam9g20-i2c";
++ reg = <0xfff84000 0x100>;
++ interrupts = <12 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ 24c512@50 {
++ compatible = "24c512";
++ reg = <0x50>;
++ pagesize = <128>;
++ }
++}
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 78bcad0..aa59a25 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -24,6 +24,9 @@
+ #include <linux/interrupt.h>
+ #include <linux/io.h>
+ #include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_i2c.h>
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
+@@ -347,6 +350,12 @@ static struct at91_twi_pdata at91sam9g10_config = {
+ .has_unre_flag = false,
+ };
+
++static struct at91_twi_pdata at91sam9x5_config = {
++ .clk_max_div = 7,
++ .clk_offset = 4,
++ .has_unre_flag = false,
++};
++
+ static const struct platform_device_id at91_twi_devtypes[] = {
+ {
+ .name = "i2c-at91rm9200",
+@@ -368,6 +377,42 @@ static const struct platform_device_id at91_twi_devtypes[] = {
+ }
+ };
+
++#if defined(CONFIG_OF)
++static const struct of_device_id atmel_twi_dt_ids[] = {
++ {
++ .compatible = "atmel,at91sam9260-i2c",
++ .data = &at91sam9260_config,
++ } , {
++ .compatible = "atmel,at91sam9g20-i2c",
++ .data = &at91sam9g20_config,
++ } , {
++ .compatible = "atmel,at91sam9g10-i2c",
++ .data = &at91sam9g10_config,
++ }, {
++ .compatible = "atmel,at91sam9x5-i2c",
++ .data = &at91sam9x5_config,
++ }, {
++ /* sentinel */
++ }
++};
++MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
++#else
++#define atmel_twi_dt_ids NULL
++#endif
++
++static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
++ struct platform_device *pdev)
++{
++ if (pdev->dev.of_node) {
++ const struct of_device_id *match;
++ match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
++ if (!match)
++ return NULL;
++ return match->data;
++ }
++ return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
++}
++
+ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ {
+ struct at91_twi_dev *dev;
+@@ -423,6 +468,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ dev->adapter.dev.parent = dev->dev;
+ dev->adapter.nr = pdev->id;
+ dev->adapter.timeout = AT91_I2C_TIMEOUT;
++ dev->adapter.dev.of_node = pdev->dev.of_node;
+
+ rc = i2c_add_numbered_adapter(&dev->adapter);
+ if (rc) {
+@@ -432,6 +478,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ return rc;
+ }
+
++ of_i2c_register_devices(&dev->adapter);
++
+ dev_info(dev->dev, "AT91 i2c bus driver.\n");
+ return 0;
+ }
+@@ -482,6 +530,7 @@ static struct platform_driver at91_twi_driver = {
+ .driver = {
+ .name = "at91_i2c",
+ .owner = THIS_MODULE,
++ .of_match_table = atmel_twi_dt_ids,
+ .pm = at91_twi_pm_ops,
+ },
+ };
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From e19f22bd4c8c9d63f777d58a38b6dd14b34c0b30 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Wed, 17 Oct 2012 10:14:48 +0200
-Subject: ARM: at91: add LCD HEO DT entry for at91sam9x5
-
-At91sam9x5.dtsi entry and activated in sam9g35ek.dts.
-
-Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
----
- arch/arm/boot/dts/at91sam9g35ek.dts | 4 ++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 7 +++++++
- 2 files changed, 11 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
-index f2c3341..0cb762e 100644
---- a/arch/arm/boot/dts/at91sam9g35ek.dts
-+++ b/arch/arm/boot/dts/at91sam9g35ek.dts
-@@ -44,6 +44,10 @@
- lcdovl1@f8038100 {
- status = "okay";
- };
-+
-+ lcdheo1@f8038280 {
-+ status = "okay";
-+ };
- };
- };
- };
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 50388fd..027b9eb 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -265,6 +265,13 @@
- 0xf8038800 0x3ff>;
- status = "disabled";
- };
-+
-+ lcdheo1@f8038280 {
-+ compatible = "atmel,at91sam9x5-heo";
-+ reg = <0xf8038280 0xbf>;
-+ interrupts = <25 4 3>;
-+ status = "disabled";
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2724054c26f7d6f755ddd75a8e0ad93f63db6e96 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:53:10 +0200
+Subject: ARM: at91: add clocks for I2C DT entries
+
+commit f7d19b9065569268dd13307213c40d168fb0be82 upstream.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nikolaus Voss <n.voss@weinmann.de>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9263.c
+ arch/arm/mach-at91/at91sam9g45.c
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ arch/arm/mach-at91/at91sam9260.c | 1 +
+ arch/arm/mach-at91/at91sam9263.c | 1 +
+ arch/arm/mach-at91/at91sam9g45.c | 2 ++
+ arch/arm/mach-at91/at91sam9n12.c | 2 ++
+ arch/arm/mach-at91/at91sam9x5.c | 3 +++
+ 5 files changed, 9 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index a936c15..040f79a 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
+ /* more tc lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index d49cfe9..00723ec 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -213,6 +213,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 7d5ac91..7ccbf9c 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -240,6 +240,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index cce4e0f..ebe94bb 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -170,6 +170,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index 15ac57b..f40c1ab 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -230,6 +230,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
++ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 21e4af4484eeb15cdc5e79f2ec5655598c5bc8bc Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 12 Sep 2012 08:42:16 +0200
+Subject: ARM: dts: add twi nodes for atmel SoCs
+
+commit 05dcd361a2785c3fcb9c43a621da4434cf1519b4 upstream.
+
+Add TWI nodes for atmel SoCs but keep i2c-gpio ones in order to let the
+choice to the user in dts files.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++
+ arch/arm/boot/dts/at91sam9g20.dtsi | 8 ++++++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 20 ++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 20 ++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 30 ++++++++++++++++++++++++++++++
+ 6 files changed, 98 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 8d95e83c..0352bf8 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -28,6 +28,7 @@
+ gpio2 = &pioC;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
+ };
+ cpus {
+ cpu@0 {
+@@ -210,6 +211,15 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fffac000 {
++ compatible = "atmel,at91sam9260-i2c";
++ reg = <0xfffac000 0x100>;
++ interrupts = <11 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 54e6984..26ab452 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -24,6 +24,7 @@
+ gpio3 = &pioD;
+ gpio4 = &pioE;
+ tcb0 = &tcb0;
++ i2c0 = &i2c0;
+ };
+ cpus {
+ cpu@0 {
+@@ -203,6 +204,15 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fff88000 {
++ compatible = "atmel,at91sam9263-i2c";
++ reg = <0xfff88000 0x100>;
++ interrupts = <13 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
+index 0eb1a75..4537a74 100644
+--- a/arch/arm/boot/dts/at91sam9g20.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20.dtsi
+@@ -15,4 +15,12 @@
+ memory {
+ reg = <0x20000000 0x08000000>;
+ };
++
++ ahb {
++ apb {
++ i2c0: i2c@fffac000 {
++ compatible = "atmel,at91sam9g20-i2c";
++ };
++ };
++ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index da135f9..b032a8c 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -29,6 +29,8 @@
+ gpio4 = &pioE;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
+ };
+ cpus {
+ cpu@0 {
+@@ -223,6 +225,24 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@fff84000 {
++ compatible = "atmel,at91sam9g10-i2c";
++ reg = <0xfff84000 0x100>;
++ interrupts = <12 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@fff88000 {
++ compatible = "atmel,at91sam9g10-i2c";
++ reg = <0xfff88000 0x100>;
++ interrupts = <13 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 42d5fc2..0d08c4e 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -26,6 +26,8 @@
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
+ };
+ cpus {
+ cpu@0 {
+@@ -191,6 +193,24 @@
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
++
++ i2c0: i2c@f8010000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8010000 0x100>;
++ interrupts = <9 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@f8014000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8014000 0x100>;
++ interrupts = <10 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index ad7016a..fec3316 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -27,6 +27,9 @@
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
++ i2c0 = &i2c0;
++ i2c1 = &i2c1;
++ i2c2 = &i2c2;
+ };
+ cpus {
+ cpu@0 {
+@@ -213,6 +216,33 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
++
++ i2c0: i2c@f8010000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8010000 0x100>;
++ interrupts = <9 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@f8014000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8014000 0x100>;
++ interrupts = <10 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++
++ i2c2: i2c@f8018000 {
++ compatible = "atmel,at91sam9x5-i2c";
++ reg = <0xf8018000 0x100>;
++ interrupts = <11 4 6>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From f0a167e19975fff4396904bf6c9521db525316e8 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 16:04:42 +0200
-Subject: AT91SAM9G45: add crypto peripherals
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
-
-Conflicts:
- arch/arm/mach-at91/at91sam9g45.c
----
- arch/arm/mach-at91/at91sam9g45.c | 16 +++-
- arch/arm/mach-at91/at91sam9g45_devices.c | 131 +++++++++++++++++++++++++-
- arch/arm/mach-at91/include/mach/at91sam9g45.h | 2 +
- 3 files changed, 147 insertions(+), 2 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index 7ccbf9c..4b791bf 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -177,6 +177,13 @@ static struct clk vdec_clk = {
- .type = CLK_TYPE_PERIPHERAL,
- };
-
-+/* AES/TDES/SHA clock - Only for sam9m11/sam9g56 */
-+static struct clk aestdessha_clk = {
-+ .name = "aestdessha_clk",
-+ .pmc_mask = 1 << AT91SAM9G45_ID_AESTDESSHA,
-+ .type = CLK_TYPE_PERIPHERAL,
-+};
-+
- static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
-@@ -205,6 +212,7 @@ static struct clk *periph_clocks[] __initdata = {
- &isi_clk,
- &udphs_clk,
- &mmc1_clk,
-+ &aestdessha_clk,
- // irq0
- };
-
-@@ -226,6 +234,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-+ CLKDEV_CON_DEV_ID("sha_clk", "atmel_sha", &aestdessha_clk),
-+ CLKDEV_CON_DEV_ID("tdes_clk", "atmel_tdes", &aestdessha_clk),
-+ CLKDEV_CON_DEV_ID("aes_clk", "atmel_aes", &aestdessha_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
-@@ -242,6 +253,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
-+ CLKDEV_CON_DEV_ID("aes_clk", "fffc0000.aes", &aestdessha_clk),
-+ CLKDEV_CON_DEV_ID("tdes_clk", "fffc4000.tdes", &aestdessha_clk),
-+ CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
-@@ -387,7 +401,7 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 2, /* USB Device High speed port */
- 0,
- 0, /* Multimedia Card Interface 1 */
-- 0,
-+ 0, /* AESTDESSHA Crypto HW Accelerators */
- 0, /* Advanced Interrupt Controller (IRQ0) */
- };
-
-diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
-index 29f334c..3d523f0 100644
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -31,7 +31,7 @@
- #include <mach/at91sam9_smc.h>
- #include <mach/at_hdmac.h>
- #include <mach/atmel-mci.h>
--
-+#include <linux/platform_data/atmel-aes.h>
- #include <media/atmel-isi.h>
-
- #include "generic.h"
-@@ -514,6 +514,132 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-
-
- /* --------------------------------------------------------------------
-+ * SHA1/SHA256
-+ * -------------------------------------------------------------------- */
-+
-+#if defined(CONFIG_CRYPTO_DEV_ATMEL_SHA) || defined(CONFIG_CRYPTO_DEV_ATMEL_SHA_MODULE)
-+static struct resource sha_resources[] = {
-+ {
-+ .start = AT91SAM9G45_BASE_SHA,
-+ .end = AT91SAM9G45_BASE_SHA + SZ_16K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static struct platform_device at91sam9g45_sha_device = {
-+ .name = "atmel_sha",
-+ .id = -1,
-+ .resource = sha_resources,
-+ .num_resources = ARRAY_SIZE(sha_resources),
-+};
-+
-+static void __init at91_add_device_sha(void)
-+{
-+ platform_device_register(&at91sam9g45_sha_device);
-+}
-+#else
-+static void __init at91_add_device_sha(void) {}
-+#endif
-+
-+/* --------------------------------------------------------------------
-+ * DES/TDES
-+ * -------------------------------------------------------------------- */
-+
-+#if defined(CONFIG_CRYPTO_DEV_ATMEL_TDES) || defined(CONFIG_CRYPTO_DEV_ATMEL_TDES_MODULE)
-+static struct resource tdes_resources[] = {
-+ [0] = {
-+ .start = AT91SAM9G45_BASE_TDES,
-+ .end = AT91SAM9G45_BASE_TDES + SZ_16K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static struct platform_device at91sam9g45_tdes_device = {
-+ .name = "atmel_tdes",
-+ .id = -1,
-+ .resource = tdes_resources,
-+ .num_resources = ARRAY_SIZE(tdes_resources),
-+};
-+
-+static void __init at91_add_device_tdes(void)
-+{
-+ platform_device_register(&at91sam9g45_tdes_device);
-+}
-+#else
-+static void __init at91_add_device_tdes(void) {}
-+#endif
-+
-+/* --------------------------------------------------------------------
-+ * AES
-+ * -------------------------------------------------------------------- */
-+
-+#if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
-+static struct aes_platform_data aes_data;
-+static u64 aes_dmamask = DMA_BIT_MASK(32);
-+
-+static struct resource aes_resources[] = {
-+ [0] = {
-+ .start = AT91SAM9G45_BASE_AES,
-+ .end = AT91SAM9G45_BASE_AES + SZ_16K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
-+static struct platform_device at91sam9g45_aes_device = {
-+ .name = "atmel_aes",
-+ .id = -1,
-+ .dev = {
-+ .dma_mask = &aes_dmamask,
-+ .coherent_dma_mask = DMA_BIT_MASK(32),
-+ .platform_data = &aes_data,
-+ },
-+ .resource = aes_resources,
-+ .num_resources = ARRAY_SIZE(aes_resources),
-+};
-+
-+static void __init at91_add_device_aes(void)
-+{
-+ struct at_dma_slave *atslave;
-+ struct aes_dma_data *alt_atslave;
-+
-+ alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
-+
-+ /* DMA TX slave channel configuration */
-+ atslave = &alt_atslave->txdata;
-+ atslave->dma_dev = &at_hdmac_device.dev;
-+ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_SRC_H2SEL_HW |
-+ ATC_SRC_PER(AT_DMA_ID_AES_RX);
-+
-+ /* DMA RX slave channel configuration */
-+ atslave = &alt_atslave->rxdata;
-+ atslave->dma_dev = &at_hdmac_device.dev;
-+ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_DST_H2SEL_HW |
-+ ATC_DST_PER(AT_DMA_ID_AES_TX);
-+
-+ aes_data.dma_slave = alt_atslave;
-+ platform_device_register(&at91sam9g45_aes_device);
-+}
-+#else
-+static void __init at91_add_device_aes(void) {}
-+#endif
-+
-+
-+/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-@@ -1742,6 +1868,9 @@ static int __init at91_add_standard_devices(void)
- at91_add_device_trng();
- at91_add_device_watchdog();
- at91_add_device_tc();
-+ at91_add_device_sha();
-+ at91_add_device_tdes();
-+ at91_add_device_aes();
- return 0;
- }
-
-diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
-index 3a4da24..8eba102 100644
---- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
-+++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
-@@ -136,6 +136,8 @@
- #define AT_DMA_ID_SSC1_RX 8
- #define AT_DMA_ID_AC97_TX 9
- #define AT_DMA_ID_AC97_RX 10
-+#define AT_DMA_ID_AES_TX 11
-+#define AT_DMA_ID_AES_RX 12
- #define AT_DMA_ID_MCI1 13
-
- #endif
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From dbdd2b87e86567c31fa90d1d72ee974306a3c8c7 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 15:53:27 +0200
+Subject: ARM: dts: add twi nodes for atmel boards
+
+commit fbc1871511ed201504d6e5b36f13ea77e4be2907 upstream.
+
+Still use i2c-gpio on boards which have a SoC with a TWI IP which
+doesn't have clock stretching in transmission mode.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g25ek.dts
+ arch/arm/boot/dts/at91sam9m10g45ek.dts
+ arch/arm/boot/dts/at91sam9n12ek.dts
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 12 ++++++++++++
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 8 ++++++++
+ arch/arm/boot/dts/at91sam9n12ek.dts | 8 ++++++++
+ 3 files changed, 28 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 4857e6c..5b054e4 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -50,6 +50,18 @@
+ cd-gpios = <&pioD 14 0>;
+ };
+ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
++
++ i2c2: i2c@f8018000 {
++ status = "okay";
++ };
+ };
+
+ usb0: ohci@00600000 {
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index 7a7b571..6a4aedd 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -65,6 +65,14 @@
+ wp-gpios = <&pioD 29 0>;
+ };
+ };
++
++ i2c0: i2c@fff84000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@fff88000 {
++ status = "okay";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
+index 44b42d9..ccc94de 100644
+--- a/arch/arm/boot/dts/at91sam9n12ek.dts
++++ b/arch/arm/boot/dts/at91sam9n12ek.dts
+@@ -46,6 +46,14 @@
+ cd-gpios = <&pioA 7 0>;
+ };
+ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From c6353d7b9b2b4b1d51e39f877f2ecf666c2c850d Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:04 +0200
-Subject: crypto: add Atmel AES driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/Kconfig | 17 +
- drivers/crypto/Makefile | 1 +
- drivers/crypto/atmel-aes-regs.h | 62 ++
- drivers/crypto/atmel-aes.c | 1206 +++++++++++++++++++++++++++++++
- include/linux/platform_data/atmel-aes.h | 22 +
- 5 files changed, 1308 insertions(+)
- create mode 100644 drivers/crypto/atmel-aes-regs.h
- create mode 100644 drivers/crypto/atmel-aes.c
- create mode 100644 include/linux/platform_data/atmel-aes.h
-
-diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
-index dd414d9..98c7da5 100644
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -296,4 +296,21 @@ config CRYPTO_DEV_TEGRA_AES
- To compile this driver as a module, choose M here: the module
- will be called tegra-aes.
-
-+config CRYPTO_DEV_ATMEL_AES
-+ tristate "Support for Atmel AES hw accelerator"
-+ depends on ARCH_AT91
-+ select CRYPTO_CBC
-+ select CRYPTO_ECB
-+ select CRYPTO_AES
-+ select CRYPTO_ALGAPI
-+ select CRYPTO_BLKCIPHER
-+ select AT_HDMAC
-+ help
-+ Some Atmel processors have AES hw accelerator.
-+ Select this if you want to use the Atmel module for
-+ AES algorithms.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called atmel-aes.
-+
- endif # CRYPTO_HW
-diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
-index f3e64ea..73ad830 100644
---- a/drivers/crypto/Makefile
-+++ b/drivers/crypto/Makefile
-@@ -14,3 +14,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
- obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
- obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
- obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
-+obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
-diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h
-new file mode 100644
-index 0000000..2786bb1
---- /dev/null
-+++ b/drivers/crypto/atmel-aes-regs.h
-@@ -0,0 +1,62 @@
-+#ifndef __ATMEL_AES_REGS_H__
-+#define __ATMEL_AES_REGS_H__
-+
-+#define AES_CR 0x00
-+#define AES_CR_START (1 << 0)
-+#define AES_CR_SWRST (1 << 8)
-+#define AES_CR_LOADSEED (1 << 16)
-+
-+#define AES_MR 0x04
-+#define AES_MR_CYPHER_DEC (0 << 0)
-+#define AES_MR_CYPHER_ENC (1 << 0)
-+#define AES_MR_DUALBUFF (1 << 3)
-+#define AES_MR_PROCDLY_MASK (0xF << 4)
-+#define AES_MR_PROCDLY_OFFSET 4
-+#define AES_MR_SMOD_MASK (0x3 << 8)
-+#define AES_MR_SMOD_MANUAL (0x0 << 8)
-+#define AES_MR_SMOD_AUTO (0x1 << 8)
-+#define AES_MR_SMOD_IDATAR0 (0x2 << 8)
-+#define AES_MR_KEYSIZE_MASK (0x3 << 10)
-+#define AES_MR_KEYSIZE_128 (0x0 << 10)
-+#define AES_MR_KEYSIZE_192 (0x1 << 10)
-+#define AES_MR_KEYSIZE_256 (0x2 << 10)
-+#define AES_MR_OPMOD_MASK (0x7 << 12)
-+#define AES_MR_OPMOD_ECB (0x0 << 12)
-+#define AES_MR_OPMOD_CBC (0x1 << 12)
-+#define AES_MR_OPMOD_OFB (0x2 << 12)
-+#define AES_MR_OPMOD_CFB (0x3 << 12)
-+#define AES_MR_OPMOD_CTR (0x4 << 12)
-+#define AES_MR_LOD (0x1 << 15)
-+#define AES_MR_CFBS_MASK (0x7 << 16)
-+#define AES_MR_CFBS_128b (0x0 << 16)
-+#define AES_MR_CFBS_64b (0x1 << 16)
-+#define AES_MR_CFBS_32b (0x2 << 16)
-+#define AES_MR_CFBS_16b (0x3 << 16)
-+#define AES_MR_CFBS_8b (0x4 << 16)
-+#define AES_MR_CKEY_MASK (0xF << 20)
-+#define AES_MR_CKEY_OFFSET 20
-+#define AES_MR_CMTYP_MASK (0x1F << 24)
-+#define AES_MR_CMTYP_OFFSET 24
-+
-+#define AES_IER 0x10
-+#define AES_IDR 0x14
-+#define AES_IMR 0x18
-+#define AES_ISR 0x1C
-+#define AES_INT_DATARDY (1 << 0)
-+#define AES_INT_URAD (1 << 8)
-+#define AES_ISR_URAT_MASK (0xF << 12)
-+#define AES_ISR_URAT_IDR_WR_PROC (0x0 << 12)
-+#define AES_ISR_URAT_ODR_RD_PROC (0x1 << 12)
-+#define AES_ISR_URAT_MR_WR_PROC (0x2 << 12)
-+#define AES_ISR_URAT_ODR_RD_SUBK (0x3 << 12)
-+#define AES_ISR_URAT_MR_WR_SUBK (0x4 << 12)
-+#define AES_ISR_URAT_WOR_RD (0x5 << 12)
-+
-+#define AES_KEYWR(x) (0x20 + ((x) * 0x04))
-+#define AES_IDATAR(x) (0x40 + ((x) * 0x04))
-+#define AES_ODATAR(x) (0x50 + ((x) * 0x04))
-+#define AES_IVR(x) (0x60 + ((x) * 0x04))
-+
-+#define AES_HW_VERSION 0xFC
-+
-+#endif /* __ATMEL_AES_REGS_H__ */
-diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
-new file mode 100644
-index 0000000..6bb20ff
---- /dev/null
-+++ b/drivers/crypto/atmel-aes.c
-@@ -0,0 +1,1206 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * Support for ATMEL AES HW acceleration.
-+ *
-+ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
-+ * Author: Nicolas Royer <nicolas@eukrea.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ * Some ideas are from omap-aes.c driver.
-+ */
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/hw_random.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/irq.h>
-+#include <linux/io.h>
-+#include <linux/platform_device.h>
-+#include <linux/scatterlist.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/delay.h>
-+#include <linux/crypto.h>
-+#include <linux/cryptohash.h>
-+#include <crypto/scatterwalk.h>
-+#include <crypto/algapi.h>
-+#include <crypto/aes.h>
-+#include <crypto/hash.h>
-+#include <crypto/internal/hash.h>
-+#include <linux/platform_data/atmel-aes.h>
-+#include "atmel-aes-regs.h"
-+
-+#define CFB8_BLOCK_SIZE 1
-+#define CFB16_BLOCK_SIZE 2
-+#define CFB32_BLOCK_SIZE 4
-+#define CFB64_BLOCK_SIZE 8
-+
-+/* AES flags */
-+#define AES_FLAGS_MODE_MASK 0x01ff
-+#define AES_FLAGS_ENCRYPT BIT(0)
-+#define AES_FLAGS_CBC BIT(1)
-+#define AES_FLAGS_CFB BIT(2)
-+#define AES_FLAGS_CFB8 BIT(3)
-+#define AES_FLAGS_CFB16 BIT(4)
-+#define AES_FLAGS_CFB32 BIT(5)
-+#define AES_FLAGS_CFB64 BIT(6)
-+#define AES_FLAGS_OFB BIT(7)
-+#define AES_FLAGS_CTR BIT(8)
-+
-+#define AES_FLAGS_INIT BIT(16)
-+#define AES_FLAGS_DMA BIT(17)
-+#define AES_FLAGS_BUSY BIT(18)
-+
-+#define AES_FLAGS_DUALBUFF BIT(24)
-+
-+#define ATMEL_AES_QUEUE_LENGTH 1
-+#define ATMEL_AES_CACHE_SIZE 0
-+
-+#define ATMEL_AES_DMA_THRESHOLD 16
-+
-+
-+struct atmel_aes_dev;
-+
-+struct atmel_aes_ctx {
-+ struct atmel_aes_dev *dd;
-+
-+ int keylen;
-+ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
-+};
-+
-+struct atmel_aes_reqctx {
-+ unsigned long mode;
-+};
-+
-+struct atmel_aes_dma {
-+ struct dma_chan *chan;
-+ struct dma_slave_config dma_conf;
-+};
-+
-+struct atmel_aes_dev {
-+ struct list_head list;
-+ unsigned long phys_base;
-+ void __iomem *io_base;
-+
-+ struct atmel_aes_ctx *ctx;
-+ struct device *dev;
-+ struct clk *iclk;
-+ int irq;
-+
-+ unsigned long flags;
-+ int err;
-+
-+ spinlock_t lock;
-+ struct crypto_queue queue;
-+
-+ struct tasklet_struct done_task;
-+ struct tasklet_struct queue_task;
-+
-+ struct ablkcipher_request *req;
-+ size_t total;
-+
-+ struct scatterlist *in_sg;
-+ unsigned int nb_in_sg;
-+
-+ struct scatterlist *out_sg;
-+ unsigned int nb_out_sg;
-+
-+ size_t bufcnt;
-+
-+ u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
-+ int dma_in;
-+ struct atmel_aes_dma dma_lch_in;
-+
-+ u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
-+ int dma_out;
-+ struct atmel_aes_dma dma_lch_out;
-+
-+ u32 hw_version;
-+};
-+
-+struct atmel_aes_drv {
-+ struct list_head dev_list;
-+ spinlock_t lock;
-+};
-+
-+static struct atmel_aes_drv atmel_aes = {
-+ .dev_list = LIST_HEAD_INIT(atmel_aes.dev_list),
-+ .lock = __SPIN_LOCK_UNLOCKED(atmel_aes.lock),
-+};
-+
-+static int atmel_aes_sg_length(struct ablkcipher_request *req,
-+ struct scatterlist *sg)
-+{
-+ unsigned int total = req->nbytes;
-+ int sg_nb;
-+ unsigned int len;
-+ struct scatterlist *sg_list;
-+
-+ sg_nb = 0;
-+ sg_list = sg;
-+ total = req->nbytes;
-+
-+ while (total) {
-+ len = min(sg_list->length, total);
-+
-+ sg_nb++;
-+ total -= len;
-+
-+ sg_list = sg_next(sg_list);
-+ if (!sg_list)
-+ total = 0;
-+ }
-+
-+ return sg_nb;
-+}
-+
-+static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
-+{
-+ return readl_relaxed(dd->io_base + offset);
-+}
-+
-+static inline void atmel_aes_write(struct atmel_aes_dev *dd,
-+ u32 offset, u32 value)
-+{
-+ writel_relaxed(value, dd->io_base + offset);
-+}
-+
-+static void atmel_aes_read_n(struct atmel_aes_dev *dd, u32 offset,
-+ u32 *value, int count)
-+{
-+ for (; count--; value++, offset += 4)
-+ *value = atmel_aes_read(dd, offset);
-+}
-+
-+static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
-+ u32 *value, int count)
-+{
-+ for (; count--; value++, offset += 4)
-+ atmel_aes_write(dd, offset, *value);
-+}
-+
-+static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
-+{
-+ atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
-+
-+ if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
-+ dd->flags |= AES_FLAGS_DUALBUFF;
-+}
-+
-+static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
-+{
-+ struct atmel_aes_dev *aes_dd = NULL;
-+ struct atmel_aes_dev *tmp;
-+
-+ spin_lock_bh(&atmel_aes.lock);
-+ if (!ctx->dd) {
-+ list_for_each_entry(tmp, &atmel_aes.dev_list, list) {
-+ aes_dd = tmp;
-+ break;
-+ }
-+ ctx->dd = aes_dd;
-+ } else {
-+ aes_dd = ctx->dd;
-+ }
-+
-+ spin_unlock_bh(&atmel_aes.lock);
-+
-+ return aes_dd;
-+}
-+
-+static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
-+{
-+ clk_prepare_enable(dd->iclk);
-+
-+ if (!(dd->flags & AES_FLAGS_INIT)) {
-+ atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
-+ atmel_aes_dualbuff_test(dd);
-+ dd->flags |= AES_FLAGS_INIT;
-+ dd->err = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
-+{
-+ atmel_aes_hw_init(dd);
-+
-+ dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
-+
-+ clk_disable_unprepare(dd->iclk);
-+}
-+
-+static void atmel_aes_finish_req(struct atmel_aes_dev *dd, int err)
-+{
-+ struct ablkcipher_request *req = dd->req;
-+
-+ clk_disable_unprepare(dd->iclk);
-+ dd->flags &= ~AES_FLAGS_BUSY;
-+
-+ req->base.complete(&req->base, err);
-+}
-+
-+static void atmel_aes_dma_callback(void *data)
-+{
-+ struct atmel_aes_dev *dd = data;
-+
-+ /* dma_lch_out - completed */
-+ tasklet_schedule(&dd->done_task);
-+}
-+
-+static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
-+{
-+ struct dma_async_tx_descriptor *in_desc, *out_desc;
-+ int nb_dma_sg_in, nb_dma_sg_out;
-+
-+ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
-+ if (!dd->nb_in_sg)
-+ goto exit_err;
-+
-+ nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
-+ DMA_TO_DEVICE);
-+ if (!nb_dma_sg_in)
-+ goto exit_err;
-+
-+ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
-+ nb_dma_sg_in, DMA_MEM_TO_DEV,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+
-+ if (!in_desc)
-+ goto unmap_in;
-+
-+ /* callback not needed */
-+
-+ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
-+ if (!dd->nb_out_sg)
-+ goto unmap_in;
-+
-+ nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
-+ DMA_FROM_DEVICE);
-+ if (!nb_dma_sg_out)
-+ goto unmap_out;
-+
-+ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
-+ nb_dma_sg_out, DMA_DEV_TO_MEM,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+
-+ if (!out_desc)
-+ goto unmap_out;
-+
-+ out_desc->callback = atmel_aes_dma_callback;
-+ out_desc->callback_param = dd;
-+
-+ dd->total -= dd->req->nbytes;
-+
-+ dmaengine_submit(out_desc);
-+ dma_async_issue_pending(dd->dma_lch_out.chan);
-+
-+ dmaengine_submit(in_desc);
-+ dma_async_issue_pending(dd->dma_lch_in.chan);
-+
-+ return 0;
-+
-+unmap_out:
-+ dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
-+ DMA_FROM_DEVICE);
-+unmap_in:
-+ dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
-+ DMA_TO_DEVICE);
-+exit_err:
-+ return -EINVAL;
-+}
-+
-+static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
-+{
-+ dd->flags &= ~AES_FLAGS_DMA;
-+
-+ /* use cache buffers */
-+ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
-+ if (!dd->nb_in_sg)
-+ return -EINVAL;
-+
-+ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
-+ if (!dd->nb_in_sg)
-+ return -EINVAL;
-+
-+ dd->bufcnt = sg_copy_to_buffer(dd->in_sg, dd->nb_in_sg,
-+ dd->buf_in, dd->total);
-+
-+ if (!dd->bufcnt)
-+ return -EINVAL;
-+
-+ dd->total -= dd->bufcnt;
-+
-+ atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
-+ atmel_aes_write_n(dd, AES_IDATAR(0), (u32 *) dd->buf_in,
-+ dd->bufcnt >> 2);
-+
-+ return 0;
-+}
-+
-+static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
-+{
-+ int err;
-+
-+ if (dd->flags & AES_FLAGS_CFB8) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ } else if (dd->flags & AES_FLAGS_CFB16) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ } else {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ }
-+
-+ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
-+ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
-+
-+ dd->flags |= AES_FLAGS_DMA;
-+ err = atmel_aes_crypt_dma(dd);
-+
-+ return err;
-+}
-+
-+static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
-+{
-+ int err;
-+ u32 valcr = 0, valmr = 0;
-+
-+ err = atmel_aes_hw_init(dd);
-+
-+ if (err)
-+ return err;
-+
-+ /* MR register must be set before IV registers */
-+ if (dd->ctx->keylen == AES_KEYSIZE_128)
-+ valmr |= AES_MR_KEYSIZE_128;
-+ else if (dd->ctx->keylen == AES_KEYSIZE_192)
-+ valmr |= AES_MR_KEYSIZE_192;
-+ else
-+ valmr |= AES_MR_KEYSIZE_256;
-+
-+ if (dd->flags & AES_FLAGS_CBC) {
-+ valmr |= AES_MR_OPMOD_CBC;
-+ } else if (dd->flags & AES_FLAGS_CFB) {
-+ valmr |= AES_MR_OPMOD_CFB;
-+ if (dd->flags & AES_FLAGS_CFB8)
-+ valmr |= AES_MR_CFBS_8b;
-+ else if (dd->flags & AES_FLAGS_CFB16)
-+ valmr |= AES_MR_CFBS_16b;
-+ else if (dd->flags & AES_FLAGS_CFB32)
-+ valmr |= AES_MR_CFBS_32b;
-+ else if (dd->flags & AES_FLAGS_CFB64)
-+ valmr |= AES_MR_CFBS_64b;
-+ } else if (dd->flags & AES_FLAGS_OFB) {
-+ valmr |= AES_MR_OPMOD_OFB;
-+ } else if (dd->flags & AES_FLAGS_CTR) {
-+ valmr |= AES_MR_OPMOD_CTR;
-+ } else {
-+ valmr |= AES_MR_OPMOD_ECB;
-+ }
-+
-+ if (dd->flags & AES_FLAGS_ENCRYPT)
-+ valmr |= AES_MR_CYPHER_ENC;
-+
-+ if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
-+ valmr |= AES_MR_SMOD_IDATAR0;
-+ if (dd->flags & AES_FLAGS_DUALBUFF)
-+ valmr |= AES_MR_DUALBUFF;
-+ } else {
-+ valmr |= AES_MR_SMOD_AUTO;
-+ }
-+
-+ atmel_aes_write(dd, AES_CR, valcr);
-+ atmel_aes_write(dd, AES_MR, valmr);
-+
-+ atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key,
-+ dd->ctx->keylen >> 2);
-+
-+ if (((dd->flags & AES_FLAGS_CBC) || (dd->flags & AES_FLAGS_CFB) ||
-+ (dd->flags & AES_FLAGS_OFB) || (dd->flags & AES_FLAGS_CTR)) &&
-+ dd->req->info) {
-+ atmel_aes_write_n(dd, AES_IVR(0), dd->req->info, 4);
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
-+ struct ablkcipher_request *req)
-+{
-+ struct crypto_async_request *async_req, *backlog;
-+ struct atmel_aes_ctx *ctx;
-+ struct atmel_aes_reqctx *rctx;
-+ unsigned long flags;
-+ int err, ret = 0;
-+
-+ spin_lock_irqsave(&dd->lock, flags);
-+ if (req)
-+ ret = ablkcipher_enqueue_request(&dd->queue, req);
-+ if (dd->flags & AES_FLAGS_BUSY) {
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+ return ret;
-+ }
-+ backlog = crypto_get_backlog(&dd->queue);
-+ async_req = crypto_dequeue_request(&dd->queue);
-+ if (async_req)
-+ dd->flags |= AES_FLAGS_BUSY;
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+
-+ if (!async_req)
-+ return ret;
-+
-+ if (backlog)
-+ backlog->complete(backlog, -EINPROGRESS);
-+
-+ req = ablkcipher_request_cast(async_req);
-+
-+ /* assign new request to device */
-+ dd->req = req;
-+ dd->total = req->nbytes;
-+ dd->in_sg = req->src;
-+ dd->out_sg = req->dst;
-+
-+ rctx = ablkcipher_request_ctx(req);
-+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
-+ rctx->mode &= AES_FLAGS_MODE_MASK;
-+ dd->flags = (dd->flags & ~AES_FLAGS_MODE_MASK) | rctx->mode;
-+ dd->ctx = ctx;
-+ ctx->dd = dd;
-+
-+ err = atmel_aes_write_ctrl(dd);
-+ if (!err) {
-+ if (dd->total > ATMEL_AES_DMA_THRESHOLD)
-+ err = atmel_aes_crypt_dma_start(dd);
-+ else
-+ err = atmel_aes_crypt_cpu_start(dd);
-+ }
-+ if (err) {
-+ /* aes_task will not finish it, so do it here */
-+ atmel_aes_finish_req(dd, err);
-+ tasklet_schedule(&dd->queue_task);
-+ }
-+
-+ return ret;
-+}
-+
-+static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
-+{
-+ int err = -EINVAL;
-+
-+ if (dd->flags & AES_FLAGS_DMA) {
-+ dma_unmap_sg(dd->dev, dd->out_sg,
-+ dd->nb_out_sg, DMA_FROM_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->in_sg,
-+ dd->nb_in_sg, DMA_TO_DEVICE);
-+ err = 0;
-+ }
-+
-+ return err;
-+}
-+
-+static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
-+{
-+ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
-+ crypto_ablkcipher_reqtfm(req));
-+ struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
-+ struct atmel_aes_dev *dd;
-+
-+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of AES blocks\n");
-+ return -EINVAL;
-+ }
-+
-+ dd = atmel_aes_find_dev(ctx);
-+ if (!dd)
-+ return -ENODEV;
-+
-+ rctx->mode = mode;
-+
-+ return atmel_aes_handle_queue(dd, req);
-+}
-+
-+static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
-+{
-+ struct at_dma_slave *sl = slave;
-+
-+ if (sl && sl->dma_dev == chan->device->dev) {
-+ chan->private = sl;
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
-+static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
-+{
-+ int err = -ENOMEM;
-+ struct aes_platform_data *pdata;
-+ dma_cap_mask_t mask_in, mask_out;
-+
-+ pdata = dd->dev->platform_data;
-+
-+ if (pdata && pdata->dma_slave->txdata.dma_dev &&
-+ pdata->dma_slave->rxdata.dma_dev) {
-+
-+ /* Try to grab 2 DMA channels */
-+ dma_cap_zero(mask_in);
-+ dma_cap_set(DMA_SLAVE, mask_in);
-+
-+ dd->dma_lch_in.chan = dma_request_channel(mask_in,
-+ atmel_aes_filter, &pdata->dma_slave->rxdata);
-+ if (!dd->dma_lch_in.chan)
-+ goto err_dma_in;
-+
-+ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
-+ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
-+ AES_IDATAR(0);
-+ dd->dma_lch_in.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.device_fc = false;
-+
-+ dma_cap_zero(mask_out);
-+ dma_cap_set(DMA_SLAVE, mask_out);
-+ dd->dma_lch_out.chan = dma_request_channel(mask_out,
-+ atmel_aes_filter, &pdata->dma_slave->txdata);
-+ if (!dd->dma_lch_out.chan)
-+ goto err_dma_out;
-+
-+ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
-+ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
-+ AES_ODATAR(0);
-+ dd->dma_lch_out.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.device_fc = false;
-+
-+ return 0;
-+ } else {
-+ return -ENODEV;
-+ }
-+
-+err_dma_out:
-+ dma_release_channel(dd->dma_lch_in.chan);
-+err_dma_in:
-+ return err;
-+}
-+
-+static void atmel_aes_dma_cleanup(struct atmel_aes_dev *dd)
-+{
-+ dma_release_channel(dd->dma_lch_in.chan);
-+ dma_release_channel(dd->dma_lch_out.chan);
-+}
-+
-+static int atmel_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
-+ unsigned int keylen)
-+{
-+ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-+
-+ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
-+ keylen != AES_KEYSIZE_256) {
-+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(ctx->key, key, keylen);
-+ ctx->keylen = keylen;
-+
-+ return 0;
-+}
-+
-+static int atmel_aes_ecb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT);
-+}
-+
-+static int atmel_aes_ecb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ 0);
-+}
-+
-+static int atmel_aes_cbc_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
-+}
-+
-+static int atmel_aes_cbc_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CBC);
-+}
-+
-+static int atmel_aes_ofb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_OFB);
-+}
-+
-+static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_OFB);
-+}
-+
-+static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
-+}
-+
-+static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CFB);
-+}
-+
-+static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB64);
-+}
-+
-+static int atmel_aes_cfb64_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CFB | AES_FLAGS_CFB64);
-+}
-+
-+static int atmel_aes_cfb32_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB32);
-+}
-+
-+static int atmel_aes_cfb32_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CFB | AES_FLAGS_CFB32);
-+}
-+
-+static int atmel_aes_cfb16_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB16);
-+}
-+
-+static int atmel_aes_cfb16_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CFB | AES_FLAGS_CFB16);
-+}
-+
-+static int atmel_aes_cfb8_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB8);
-+}
-+
-+static int atmel_aes_cfb8_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CFB | AES_FLAGS_CFB8);
-+}
-+
-+static int atmel_aes_ctr_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CTR);
-+}
-+
-+static int atmel_aes_ctr_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_aes_crypt(req,
-+ AES_FLAGS_CTR);
-+}
-+
-+static int atmel_aes_cra_init(struct crypto_tfm *tfm)
-+{
-+ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_aes_reqctx);
-+
-+ return 0;
-+}
-+
-+static void atmel_aes_cra_exit(struct crypto_tfm *tfm)
-+{
-+}
-+
-+static struct crypto_alg aes_algs[] = {
-+{
-+ .cra_name = "ecb(aes)",
-+ .cra_driver_name = "atmel-ecb-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = AES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_ecb_encrypt,
-+ .decrypt = atmel_aes_ecb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cbc(aes)",
-+ .cra_driver_name = "atmel-cbc-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = AES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cbc_encrypt,
-+ .decrypt = atmel_aes_cbc_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "ofb(aes)",
-+ .cra_driver_name = "atmel-ofb-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = AES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_ofb_encrypt,
-+ .decrypt = atmel_aes_ofb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb(aes)",
-+ .cra_driver_name = "atmel-cfb-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = AES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cfb_encrypt,
-+ .decrypt = atmel_aes_cfb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb32(aes)",
-+ .cra_driver_name = "atmel-cfb32-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB32_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cfb32_encrypt,
-+ .decrypt = atmel_aes_cfb32_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb16(aes)",
-+ .cra_driver_name = "atmel-cfb16-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB16_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cfb16_encrypt,
-+ .decrypt = atmel_aes_cfb16_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb8(aes)",
-+ .cra_driver_name = "atmel-cfb8-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB64_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cfb8_encrypt,
-+ .decrypt = atmel_aes_cfb8_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "ctr(aes)",
-+ .cra_driver_name = "atmel-ctr-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = AES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_ctr_encrypt,
-+ .decrypt = atmel_aes_ctr_decrypt,
-+ }
-+},
-+};
-+
-+static struct crypto_alg aes_cfb64_alg[] = {
-+{
-+ .cra_name = "cfb64(aes)",
-+ .cra_driver_name = "atmel-cfb64-aes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB64_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-+ .cra_alignmask = 0x0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_aes_cra_init,
-+ .cra_exit = atmel_aes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = AES_MIN_KEY_SIZE,
-+ .max_keysize = AES_MAX_KEY_SIZE,
-+ .ivsize = AES_BLOCK_SIZE,
-+ .setkey = atmel_aes_setkey,
-+ .encrypt = atmel_aes_cfb64_encrypt,
-+ .decrypt = atmel_aes_cfb64_decrypt,
-+ }
-+},
-+};
-+
-+static void atmel_aes_queue_task(unsigned long data)
-+{
-+ struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data;
-+
-+ atmel_aes_handle_queue(dd, NULL);
-+}
-+
-+static void atmel_aes_done_task(unsigned long data)
-+{
-+ struct atmel_aes_dev *dd = (struct atmel_aes_dev *) data;
-+ int err;
-+
-+ if (!(dd->flags & AES_FLAGS_DMA)) {
-+ atmel_aes_read_n(dd, AES_ODATAR(0), (u32 *) dd->buf_out,
-+ dd->bufcnt >> 2);
-+
-+ if (sg_copy_from_buffer(dd->out_sg, dd->nb_out_sg,
-+ dd->buf_out, dd->bufcnt))
-+ err = 0;
-+ else
-+ err = -EINVAL;
-+
-+ goto cpu_end;
-+ }
-+
-+ err = atmel_aes_crypt_dma_stop(dd);
-+
-+ err = dd->err ? : err;
-+
-+ if (dd->total && !err) {
-+ err = atmel_aes_crypt_dma_start(dd);
-+ if (!err)
-+ return; /* DMA started. Not fininishing. */
-+ }
-+
-+cpu_end:
-+ atmel_aes_finish_req(dd, err);
-+ atmel_aes_handle_queue(dd, NULL);
-+}
-+
-+static irqreturn_t atmel_aes_irq(int irq, void *dev_id)
-+{
-+ struct atmel_aes_dev *aes_dd = dev_id;
-+ u32 reg;
-+
-+ reg = atmel_aes_read(aes_dd, AES_ISR);
-+ if (reg & atmel_aes_read(aes_dd, AES_IMR)) {
-+ atmel_aes_write(aes_dd, AES_IDR, reg);
-+ if (AES_FLAGS_BUSY & aes_dd->flags)
-+ tasklet_schedule(&aes_dd->done_task);
-+ else
-+ dev_warn(aes_dd->dev, "AES interrupt when no active requests.\n");
-+ return IRQ_HANDLED;
-+ }
-+
-+ return IRQ_NONE;
-+}
-+
-+static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
-+ crypto_unregister_alg(&aes_algs[i]);
-+ if (dd->hw_version >= 0x130)
-+ crypto_unregister_alg(&aes_cfb64_alg[0]);
-+}
-+
-+static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
-+{
-+ int err, i, j;
-+
-+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
-+ INIT_LIST_HEAD(&aes_algs[i].cra_list);
-+ err = crypto_register_alg(&aes_algs[i]);
-+ if (err)
-+ goto err_aes_algs;
-+ }
-+
-+ atmel_aes_hw_version_init(dd);
-+
-+ if (dd->hw_version >= 0x130) {
-+ INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
-+ err = crypto_register_alg(&aes_cfb64_alg[0]);
-+ if (err)
-+ goto err_aes_cfb64_alg;
-+ }
-+
-+ return 0;
-+
-+err_aes_cfb64_alg:
-+ i = ARRAY_SIZE(aes_algs);
-+err_aes_algs:
-+ for (j = 0; j < i; j++)
-+ crypto_unregister_alg(&aes_algs[j]);
-+
-+ return err;
-+}
-+
-+static int __devinit atmel_aes_probe(struct platform_device *pdev)
-+{
-+ struct atmel_aes_dev *aes_dd;
-+ struct aes_platform_data *pdata;
-+ struct device *dev = &pdev->dev;
-+ struct resource *aes_res;
-+ unsigned long aes_phys_size;
-+ int err;
-+
-+ pdata = pdev->dev.platform_data;
-+ if (!pdata) {
-+ err = -ENXIO;
-+ goto aes_dd_err;
-+ }
-+
-+ aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
-+ if (aes_dd == NULL) {
-+ dev_err(dev, "unable to alloc data struct.\n");
-+ err = -ENOMEM;
-+ goto aes_dd_err;
-+ }
-+
-+ aes_dd->dev = dev;
-+
-+ platform_set_drvdata(pdev, aes_dd);
-+
-+ INIT_LIST_HEAD(&aes_dd->list);
-+
-+ tasklet_init(&aes_dd->done_task, atmel_aes_done_task,
-+ (unsigned long)aes_dd);
-+ tasklet_init(&aes_dd->queue_task, atmel_aes_queue_task,
-+ (unsigned long)aes_dd);
-+
-+ crypto_init_queue(&aes_dd->queue, ATMEL_AES_QUEUE_LENGTH);
-+
-+ aes_dd->irq = -1;
-+
-+ /* Get the base address */
-+ aes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!aes_res) {
-+ dev_err(dev, "no MEM resource info\n");
-+ err = -ENODEV;
-+ goto res_err;
-+ }
-+ aes_dd->phys_base = aes_res->start;
-+ aes_phys_size = resource_size(aes_res);
-+
-+ /* Get the IRQ */
-+ aes_dd->irq = platform_get_irq(pdev, 0);
-+ if (aes_dd->irq < 0) {
-+ dev_err(dev, "no IRQ resource info\n");
-+ err = aes_dd->irq;
-+ goto aes_irq_err;
-+ }
-+
-+ err = request_irq(aes_dd->irq, atmel_aes_irq, IRQF_SHARED, "atmel-aes",
-+ aes_dd);
-+ if (err) {
-+ dev_err(dev, "unable to request aes irq.\n");
-+ goto aes_irq_err;
-+ }
-+
-+ /* Initializing the clock */
-+ aes_dd->iclk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(aes_dd->iclk)) {
-+ dev_err(dev, "clock intialization failed.\n");
-+ err = PTR_ERR(aes_dd->iclk);
-+ goto clk_err;
-+ }
-+
-+ aes_dd->io_base = ioremap(aes_dd->phys_base, aes_phys_size);
-+ if (!aes_dd->io_base) {
-+ dev_err(dev, "can't ioremap\n");
-+ err = -ENOMEM;
-+ goto aes_io_err;
-+ }
-+
-+ err = atmel_aes_dma_init(aes_dd);
-+ if (err)
-+ goto err_aes_dma;
-+
-+ spin_lock(&atmel_aes.lock);
-+ list_add_tail(&aes_dd->list, &atmel_aes.dev_list);
-+ spin_unlock(&atmel_aes.lock);
-+
-+ err = atmel_aes_register_algs(aes_dd);
-+ if (err)
-+ goto err_algs;
-+
-+ dev_info(dev, "Atmel AES\n");
-+
-+ return 0;
-+
-+err_algs:
-+ spin_lock(&atmel_aes.lock);
-+ list_del(&aes_dd->list);
-+ spin_unlock(&atmel_aes.lock);
-+ atmel_aes_dma_cleanup(aes_dd);
-+err_aes_dma:
-+ iounmap(aes_dd->io_base);
-+aes_io_err:
-+ clk_put(aes_dd->iclk);
-+clk_err:
-+ free_irq(aes_dd->irq, aes_dd);
-+aes_irq_err:
-+res_err:
-+ tasklet_kill(&aes_dd->done_task);
-+ tasklet_kill(&aes_dd->queue_task);
-+ kfree(aes_dd);
-+ aes_dd = NULL;
-+aes_dd_err:
-+ dev_err(dev, "initialization failed.\n");
-+
-+ return err;
-+}
-+
-+static int __devexit atmel_aes_remove(struct platform_device *pdev)
-+{
-+ static struct atmel_aes_dev *aes_dd;
-+
-+ aes_dd = platform_get_drvdata(pdev);
-+ if (!aes_dd)
-+ return -ENODEV;
-+ spin_lock(&atmel_aes.lock);
-+ list_del(&aes_dd->list);
-+ spin_unlock(&atmel_aes.lock);
-+
-+ atmel_aes_unregister_algs(aes_dd);
-+
-+ tasklet_kill(&aes_dd->done_task);
-+ tasklet_kill(&aes_dd->queue_task);
-+
-+ atmel_aes_dma_cleanup(aes_dd);
-+
-+ iounmap(aes_dd->io_base);
-+
-+ clk_put(aes_dd->iclk);
-+
-+ if (aes_dd->irq > 0)
-+ free_irq(aes_dd->irq, aes_dd);
-+
-+ kfree(aes_dd);
-+ aes_dd = NULL;
-+
-+ return 0;
-+}
-+
-+static struct platform_driver atmel_aes_driver = {
-+ .probe = atmel_aes_probe,
-+ .remove = __devexit_p(atmel_aes_remove),
-+ .driver = {
-+ .name = "atmel_aes",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(atmel_aes_driver);
-+
-+MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
-diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
-new file mode 100644
-index 0000000..e7a1949
---- /dev/null
-+++ b/include/linux/platform_data/atmel-aes.h
-@@ -0,0 +1,22 @@
-+#ifndef __LINUX_ATMEL_AES_H
-+#define __LINUX_ATMEL_AES_H
-+
-+#include <mach/at_hdmac.h>
-+
-+/**
-+ * struct aes_dma_data - DMA data for AES
-+ */
-+struct aes_dma_data {
-+ struct at_dma_slave txdata;
-+ struct at_dma_slave rxdata;
-+};
-+
-+/**
-+ * struct aes_platform_data - board-specific AES configuration
-+ * @dma_slave: DMA slave interface to use in data transfers.
-+ */
-+struct aes_platform_data {
-+ struct aes_dma_data *dma_slave;
-+};
-+
-+#endif /* __LINUX_ATMEL_AES_H */
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 189348edb141027c8f6ba232380dda1dcfd56979 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:05 +0200
-Subject: crypto: add Atmel DES/TDES driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/Kconfig | 16 +
- drivers/crypto/Makefile | 1 +
- drivers/crypto/atmel-tdes-regs.h | 89 +++
- drivers/crypto/atmel-tdes.c | 1215 ++++++++++++++++++++++++++++++++++++++
- 4 files changed, 1321 insertions(+)
- create mode 100644 drivers/crypto/atmel-tdes-regs.h
- create mode 100644 drivers/crypto/atmel-tdes.c
-
-diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
-index 98c7da5..2124898 100644
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -313,4 +313,20 @@ config CRYPTO_DEV_ATMEL_AES
- To compile this driver as a module, choose M here: the module
- will be called atmel-aes.
-
-+config CRYPTO_DEV_ATMEL_TDES
-+ tristate "Support for Atmel DES/TDES hw accelerator"
-+ depends on ARCH_AT91
-+ select CRYPTO_DES
-+ select CRYPTO_CBC
-+ select CRYPTO_ECB
-+ select CRYPTO_ALGAPI
-+ select CRYPTO_BLKCIPHER
-+ help
-+ Some Atmel processors have DES/TDES hw accelerator.
-+ Select this if you want to use the Atmel module for
-+ DES/TDES algorithms.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called atmel-tdes.
-+
- endif # CRYPTO_HW
-diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
-index 73ad830..443bf4d 100644
---- a/drivers/crypto/Makefile
-+++ b/drivers/crypto/Makefile
-@@ -15,3 +15,4 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
- obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
- obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
-+obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
-diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
-new file mode 100644
-index 0000000..5ac2a90
---- /dev/null
-+++ b/drivers/crypto/atmel-tdes-regs.h
-@@ -0,0 +1,89 @@
-+#ifndef __ATMEL_TDES_REGS_H__
-+#define __ATMEL_TDES_REGS_H__
-+
-+#define TDES_CR 0x00
-+#define TDES_CR_START (1 << 0)
-+#define TDES_CR_SWRST (1 << 8)
-+#define TDES_CR_LOADSEED (1 << 16)
-+
-+#define TDES_MR 0x04
-+#define TDES_MR_CYPHER_DEC (0 << 0)
-+#define TDES_MR_CYPHER_ENC (1 << 0)
-+#define TDES_MR_TDESMOD_MASK (0x3 << 1)
-+#define TDES_MR_TDESMOD_DES (0x0 << 1)
-+#define TDES_MR_TDESMOD_TDES (0x1 << 1)
-+#define TDES_MR_TDESMOD_XTEA (0x2 << 1)
-+#define TDES_MR_KEYMOD_3KEY (0 << 4)
-+#define TDES_MR_KEYMOD_2KEY (1 << 4)
-+#define TDES_MR_SMOD_MASK (0x3 << 8)
-+#define TDES_MR_SMOD_MANUAL (0x0 << 8)
-+#define TDES_MR_SMOD_AUTO (0x1 << 8)
-+#define TDES_MR_SMOD_PDC (0x2 << 8)
-+#define TDES_MR_OPMOD_MASK (0x3 << 12)
-+#define TDES_MR_OPMOD_ECB (0x0 << 12)
-+#define TDES_MR_OPMOD_CBC (0x1 << 12)
-+#define TDES_MR_OPMOD_OFB (0x2 << 12)
-+#define TDES_MR_OPMOD_CFB (0x3 << 12)
-+#define TDES_MR_LOD (0x1 << 15)
-+#define TDES_MR_CFBS_MASK (0x3 << 16)
-+#define TDES_MR_CFBS_64b (0x0 << 16)
-+#define TDES_MR_CFBS_32b (0x1 << 16)
-+#define TDES_MR_CFBS_16b (0x2 << 16)
-+#define TDES_MR_CFBS_8b (0x3 << 16)
-+#define TDES_MR_CKEY_MASK (0xF << 20)
-+#define TDES_MR_CKEY_OFFSET 20
-+#define TDES_MR_CTYPE_MASK (0x3F << 24)
-+#define TDES_MR_CTYPE_OFFSET 24
-+
-+#define TDES_IER 0x10
-+#define TDES_IDR 0x14
-+#define TDES_IMR 0x18
-+#define TDES_ISR 0x1C
-+#define TDES_INT_DATARDY (1 << 0)
-+#define TDES_INT_ENDRX (1 << 1)
-+#define TDES_INT_ENDTX (1 << 2)
-+#define TDES_INT_RXBUFF (1 << 3)
-+#define TDES_INT_TXBUFE (1 << 4)
-+#define TDES_INT_URAD (1 << 8)
-+#define TDES_ISR_URAT_MASK (0x3 << 12)
-+#define TDES_ISR_URAT_IDR (0x0 << 12)
-+#define TDES_ISR_URAT_ODR (0x1 << 12)
-+#define TDES_ISR_URAT_MR (0x2 << 12)
-+#define TDES_ISR_URAT_WO (0x3 << 12)
-+
-+
-+#define TDES_KEY1W1R 0x20
-+#define TDES_KEY1W2R 0x24
-+#define TDES_KEY2W1R 0x28
-+#define TDES_KEY2W2R 0x2C
-+#define TDES_KEY3W1R 0x30
-+#define TDES_KEY3W2R 0x34
-+#define TDES_IDATA1R 0x40
-+#define TDES_IDATA2R 0x44
-+#define TDES_ODATA1R 0x50
-+#define TDES_ODATA2R 0x54
-+#define TDES_IV1R 0x60
-+#define TDES_IV2R 0x64
-+
-+#define TDES_XTEARNDR 0x70
-+#define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
-+#define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
-+
-+#define TDES_RPR 0x100
-+#define TDES_RCR 0x104
-+#define TDES_TPR 0x108
-+#define TDES_TCR 0x10C
-+#define TDES_RNPR 0x118
-+#define TDES_RNCR 0x11C
-+#define TDES_TNPR 0x118
-+#define TDES_TNCR 0x11C
-+#define TDES_PTCR 0x120
-+#define TDES_PTCR_RXTEN (1 << 0)
-+#define TDES_PTCR_RXTDIS (1 << 1)
-+#define TDES_PTCR_TXTEN (1 << 8)
-+#define TDES_PTCR_TXTDIS (1 << 9)
-+#define TDES_PTSR 0x124
-+#define TDES_PTSR_RXTEN (1 << 0)
-+#define TDES_PTSR_TXTEN (1 << 8)
-+
-+#endif /* __ATMEL_TDES_REGS_H__ */
-diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
-new file mode 100644
-index 0000000..eb2b61e
---- /dev/null
-+++ b/drivers/crypto/atmel-tdes.c
-@@ -0,0 +1,1215 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * Support for ATMEL DES/TDES HW acceleration.
-+ *
-+ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
-+ * Author: Nicolas Royer <nicolas@eukrea.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ * Some ideas are from omap-aes.c drivers.
-+ */
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/hw_random.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/irq.h>
-+#include <linux/io.h>
-+#include <linux/platform_device.h>
-+#include <linux/scatterlist.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/delay.h>
-+#include <linux/crypto.h>
-+#include <linux/cryptohash.h>
-+#include <crypto/scatterwalk.h>
-+#include <crypto/algapi.h>
-+#include <crypto/des.h>
-+#include <crypto/hash.h>
-+#include <crypto/internal/hash.h>
-+#include "atmel-tdes-regs.h"
-+
-+/* TDES flags */
-+#define TDES_FLAGS_MODE_MASK 0x007f
-+#define TDES_FLAGS_ENCRYPT BIT(0)
-+#define TDES_FLAGS_CBC BIT(1)
-+#define TDES_FLAGS_CFB BIT(2)
-+#define TDES_FLAGS_CFB8 BIT(3)
-+#define TDES_FLAGS_CFB16 BIT(4)
-+#define TDES_FLAGS_CFB32 BIT(5)
-+#define TDES_FLAGS_OFB BIT(6)
-+
-+#define TDES_FLAGS_INIT BIT(16)
-+#define TDES_FLAGS_FAST BIT(17)
-+#define TDES_FLAGS_BUSY BIT(18)
-+
-+#define ATMEL_TDES_QUEUE_LENGTH 1
-+
-+#define CFB8_BLOCK_SIZE 1
-+#define CFB16_BLOCK_SIZE 2
-+#define CFB32_BLOCK_SIZE 4
-+#define CFB64_BLOCK_SIZE 8
-+
-+
-+struct atmel_tdes_dev;
-+
-+struct atmel_tdes_ctx {
-+ struct atmel_tdes_dev *dd;
-+
-+ int keylen;
-+ u32 key[3*DES_KEY_SIZE / sizeof(u32)];
-+ unsigned long flags;
-+};
-+
-+struct atmel_tdes_reqctx {
-+ unsigned long mode;
-+};
-+
-+struct atmel_tdes_dev {
-+ struct list_head list;
-+ unsigned long phys_base;
-+ void __iomem *io_base;
-+
-+ struct atmel_tdes_ctx *ctx;
-+ struct device *dev;
-+ struct clk *iclk;
-+ int irq;
-+
-+ unsigned long flags;
-+ int err;
-+
-+ spinlock_t lock;
-+ struct crypto_queue queue;
-+
-+ struct tasklet_struct done_task;
-+ struct tasklet_struct queue_task;
-+
-+ struct ablkcipher_request *req;
-+ size_t total;
-+
-+ struct scatterlist *in_sg;
-+ size_t in_offset;
-+ struct scatterlist *out_sg;
-+ size_t out_offset;
-+
-+ size_t buflen;
-+ size_t dma_size;
-+
-+ void *buf_in;
-+ int dma_in;
-+ dma_addr_t dma_addr_in;
-+
-+ void *buf_out;
-+ int dma_out;
-+ dma_addr_t dma_addr_out;
-+};
-+
-+struct atmel_tdes_drv {
-+ struct list_head dev_list;
-+ spinlock_t lock;
-+};
-+
-+static struct atmel_tdes_drv atmel_tdes = {
-+ .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list),
-+ .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock),
-+};
-+
-+static int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset,
-+ void *buf, size_t buflen, size_t total, int out)
-+{
-+ unsigned int count, off = 0;
-+
-+ while (buflen && total) {
-+ count = min((*sg)->length - *offset, total);
-+ count = min(count, buflen);
-+
-+ if (!count)
-+ return off;
-+
-+ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
-+
-+ off += count;
-+ buflen -= count;
-+ *offset += count;
-+ total -= count;
-+
-+ if (*offset == (*sg)->length) {
-+ *sg = sg_next(*sg);
-+ if (*sg)
-+ *offset = 0;
-+ else
-+ total = 0;
-+ }
-+ }
-+
-+ return off;
-+}
-+
-+static inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset)
-+{
-+ return readl_relaxed(dd->io_base + offset);
-+}
-+
-+static inline void atmel_tdes_write(struct atmel_tdes_dev *dd,
-+ u32 offset, u32 value)
-+{
-+ writel_relaxed(value, dd->io_base + offset);
-+}
-+
-+static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset,
-+ u32 *value, int count)
-+{
-+ for (; count--; value++, offset += 4)
-+ atmel_tdes_write(dd, offset, *value);
-+}
-+
-+static struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx)
-+{
-+ struct atmel_tdes_dev *tdes_dd = NULL;
-+ struct atmel_tdes_dev *tmp;
-+
-+ spin_lock_bh(&atmel_tdes.lock);
-+ if (!ctx->dd) {
-+ list_for_each_entry(tmp, &atmel_tdes.dev_list, list) {
-+ tdes_dd = tmp;
-+ break;
-+ }
-+ ctx->dd = tdes_dd;
-+ } else {
-+ tdes_dd = ctx->dd;
-+ }
-+ spin_unlock_bh(&atmel_tdes.lock);
-+
-+ return tdes_dd;
-+}
-+
-+static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
-+{
-+ clk_prepare_enable(dd->iclk);
-+
-+ if (!(dd->flags & TDES_FLAGS_INIT)) {
-+ atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST);
-+ dd->flags |= TDES_FLAGS_INIT;
-+ dd->err = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
-+{
-+ int err;
-+ u32 valcr = 0, valmr = TDES_MR_SMOD_PDC;
-+
-+ err = atmel_tdes_hw_init(dd);
-+
-+ if (err)
-+ return err;
-+
-+ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
-+
-+ /* MR register must be set before IV registers */
-+ if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
-+ valmr |= TDES_MR_KEYMOD_3KEY;
-+ valmr |= TDES_MR_TDESMOD_TDES;
-+ } else if (dd->ctx->keylen > DES_KEY_SIZE) {
-+ valmr |= TDES_MR_KEYMOD_2KEY;
-+ valmr |= TDES_MR_TDESMOD_TDES;
-+ } else {
-+ valmr |= TDES_MR_TDESMOD_DES;
-+ }
-+
-+ if (dd->flags & TDES_FLAGS_CBC) {
-+ valmr |= TDES_MR_OPMOD_CBC;
-+ } else if (dd->flags & TDES_FLAGS_CFB) {
-+ valmr |= TDES_MR_OPMOD_CFB;
-+
-+ if (dd->flags & TDES_FLAGS_CFB8)
-+ valmr |= TDES_MR_CFBS_8b;
-+ else if (dd->flags & TDES_FLAGS_CFB16)
-+ valmr |= TDES_MR_CFBS_16b;
-+ else if (dd->flags & TDES_FLAGS_CFB32)
-+ valmr |= TDES_MR_CFBS_32b;
-+ } else if (dd->flags & TDES_FLAGS_OFB) {
-+ valmr |= TDES_MR_OPMOD_OFB;
-+ }
-+
-+ if ((dd->flags & TDES_FLAGS_ENCRYPT) || (dd->flags & TDES_FLAGS_OFB))
-+ valmr |= TDES_MR_CYPHER_ENC;
-+
-+ atmel_tdes_write(dd, TDES_CR, valcr);
-+ atmel_tdes_write(dd, TDES_MR, valmr);
-+
-+ atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key,
-+ dd->ctx->keylen >> 2);
-+
-+ if (((dd->flags & TDES_FLAGS_CBC) || (dd->flags & TDES_FLAGS_CFB) ||
-+ (dd->flags & TDES_FLAGS_OFB)) && dd->req->info) {
-+ atmel_tdes_write_n(dd, TDES_IV1R, dd->req->info, 2);
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
-+{
-+ int err = 0;
-+ size_t count;
-+
-+ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
-+
-+ if (dd->flags & TDES_FLAGS_FAST) {
-+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ } else {
-+ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
-+ dd->dma_size, DMA_FROM_DEVICE);
-+
-+ /* copy data */
-+ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
-+ dd->buf_out, dd->buflen, dd->dma_size, 1);
-+ if (count != dd->dma_size) {
-+ err = -EINVAL;
-+ pr_err("not all data converted: %u\n", count);
-+ }
-+ }
-+
-+ return err;
-+}
-+
-+static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
-+{
-+ int err = -ENOMEM;
-+
-+ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
-+ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
-+ dd->buflen = PAGE_SIZE;
-+ dd->buflen &= ~(DES_BLOCK_SIZE - 1);
-+
-+ if (!dd->buf_in || !dd->buf_out) {
-+ dev_err(dd->dev, "unable to alloc pages.\n");
-+ goto err_alloc;
-+ }
-+
-+ /* MAP here */
-+ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
-+ dd->buflen, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
-+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-+ err = -EINVAL;
-+ goto err_map_in;
-+ }
-+
-+ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
-+ dd->buflen, DMA_FROM_DEVICE);
-+ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
-+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-+ err = -EINVAL;
-+ goto err_map_out;
-+ }
-+
-+ return 0;
-+
-+err_map_out:
-+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
-+ DMA_TO_DEVICE);
-+err_map_in:
-+ free_page((unsigned long)dd->buf_out);
-+ free_page((unsigned long)dd->buf_in);
-+err_alloc:
-+ if (err)
-+ pr_err("error: %d\n", err);
-+ return err;
-+}
-+
-+static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
-+{
-+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
-+ DMA_FROM_DEVICE);
-+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
-+ DMA_TO_DEVICE);
-+ free_page((unsigned long)dd->buf_out);
-+ free_page((unsigned long)dd->buf_in);
-+}
-+
-+static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
-+ dma_addr_t dma_addr_out, int length)
-+{
-+ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
-+ struct atmel_tdes_dev *dd = ctx->dd;
-+ int len32;
-+
-+ dd->dma_size = length;
-+
-+ if (!(dd->flags & TDES_FLAGS_FAST)) {
-+ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
-+ DMA_TO_DEVICE);
-+ }
-+
-+ if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB8))
-+ len32 = DIV_ROUND_UP(length, sizeof(u8));
-+ else if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB16))
-+ len32 = DIV_ROUND_UP(length, sizeof(u16));
-+ else
-+ len32 = DIV_ROUND_UP(length, sizeof(u32));
-+
-+ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
-+ atmel_tdes_write(dd, TDES_TPR, dma_addr_in);
-+ atmel_tdes_write(dd, TDES_TCR, len32);
-+ atmel_tdes_write(dd, TDES_RPR, dma_addr_out);
-+ atmel_tdes_write(dd, TDES_RCR, len32);
-+
-+ /* Enable Interrupt */
-+ atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX);
-+
-+ /* Start DMA transfer */
-+ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN);
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
-+{
-+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
-+ crypto_ablkcipher_reqtfm(dd->req));
-+ int err, fast = 0, in, out;
-+ size_t count;
-+ dma_addr_t addr_in, addr_out;
-+
-+ if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
-+ /* check for alignment */
-+ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
-+ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
-+
-+ fast = in && out;
-+ }
-+
-+ if (fast) {
-+ count = min(dd->total, sg_dma_len(dd->in_sg));
-+ count = min(count, sg_dma_len(dd->out_sg));
-+
-+ if (count != dd->total) {
-+ pr_err("request length != buffer length\n");
-+ return -EINVAL;
-+ }
-+
-+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ if (!err) {
-+ dev_err(dd->dev, "dma_map_sg() error\n");
-+ return -EINVAL;
-+ }
-+
-+ err = dma_map_sg(dd->dev, dd->out_sg, 1,
-+ DMA_FROM_DEVICE);
-+ if (!err) {
-+ dev_err(dd->dev, "dma_map_sg() error\n");
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1,
-+ DMA_TO_DEVICE);
-+ return -EINVAL;
-+ }
-+
-+ addr_in = sg_dma_address(dd->in_sg);
-+ addr_out = sg_dma_address(dd->out_sg);
-+
-+ dd->flags |= TDES_FLAGS_FAST;
-+
-+ } else {
-+ /* use cache buffers */
-+ count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset,
-+ dd->buf_in, dd->buflen, dd->total, 0);
-+
-+ addr_in = dd->dma_addr_in;
-+ addr_out = dd->dma_addr_out;
-+
-+ dd->flags &= ~TDES_FLAGS_FAST;
-+
-+ }
-+
-+ dd->total -= count;
-+
-+ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
-+ if (err) {
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
-+ }
-+
-+ return err;
-+}
-+
-+
-+static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
-+{
-+ struct ablkcipher_request *req = dd->req;
-+
-+ clk_disable_unprepare(dd->iclk);
-+
-+ dd->flags &= ~TDES_FLAGS_BUSY;
-+
-+ req->base.complete(&req->base, err);
-+}
-+
-+static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
-+ struct ablkcipher_request *req)
-+{
-+ struct crypto_async_request *async_req, *backlog;
-+ struct atmel_tdes_ctx *ctx;
-+ struct atmel_tdes_reqctx *rctx;
-+ unsigned long flags;
-+ int err, ret = 0;
-+
-+ spin_lock_irqsave(&dd->lock, flags);
-+ if (req)
-+ ret = ablkcipher_enqueue_request(&dd->queue, req);
-+ if (dd->flags & TDES_FLAGS_BUSY) {
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+ return ret;
-+ }
-+ backlog = crypto_get_backlog(&dd->queue);
-+ async_req = crypto_dequeue_request(&dd->queue);
-+ if (async_req)
-+ dd->flags |= TDES_FLAGS_BUSY;
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+
-+ if (!async_req)
-+ return ret;
-+
-+ if (backlog)
-+ backlog->complete(backlog, -EINPROGRESS);
-+
-+ req = ablkcipher_request_cast(async_req);
-+
-+ /* assign new request to device */
-+ dd->req = req;
-+ dd->total = req->nbytes;
-+ dd->in_offset = 0;
-+ dd->in_sg = req->src;
-+ dd->out_offset = 0;
-+ dd->out_sg = req->dst;
-+
-+ rctx = ablkcipher_request_ctx(req);
-+ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
-+ rctx->mode &= TDES_FLAGS_MODE_MASK;
-+ dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode;
-+ dd->ctx = ctx;
-+ ctx->dd = dd;
-+
-+ err = atmel_tdes_write_ctrl(dd);
-+ if (!err)
-+ err = atmel_tdes_crypt_dma_start(dd);
-+ if (err) {
-+ /* des_task will not finish it, so do it here */
-+ atmel_tdes_finish_req(dd, err);
-+ tasklet_schedule(&dd->queue_task);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
-+{
-+ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
-+ crypto_ablkcipher_reqtfm(req));
-+ struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
-+ struct atmel_tdes_dev *dd;
-+
-+ if (mode & TDES_FLAGS_CFB8) {
-+ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB8 blocks\n");
-+ return -EINVAL;
-+ }
-+ } else if (mode & TDES_FLAGS_CFB16) {
-+ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB16 blocks\n");
-+ return -EINVAL;
-+ }
-+ } else if (mode & TDES_FLAGS_CFB32) {
-+ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB32 blocks\n");
-+ return -EINVAL;
-+ }
-+ } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of DES blocks\n");
-+ return -EINVAL;
-+ }
-+
-+ dd = atmel_tdes_find_dev(ctx);
-+ if (!dd)
-+ return -ENODEV;
-+
-+ rctx->mode = mode;
-+
-+ return atmel_tdes_handle_queue(dd, req);
-+}
-+
-+static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
-+ unsigned int keylen)
-+{
-+ u32 tmp[DES_EXPKEY_WORDS];
-+ int err;
-+ struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm);
-+
-+ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-+
-+ if (keylen != DES_KEY_SIZE) {
-+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-+ return -EINVAL;
-+ }
-+
-+ err = des_ekey(tmp, key);
-+ if (err == 0 && (ctfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
-+ ctfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
-+ return -EINVAL;
-+ }
-+
-+ memcpy(ctx->key, key, keylen);
-+ ctx->keylen = keylen;
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
-+ unsigned int keylen)
-+{
-+ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
-+ const char *alg_name;
-+
-+ alg_name = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
-+
-+ /*
-+ * HW bug in cfb 3-keys mode.
-+ */
-+ if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
-+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-+ return -EINVAL;
-+ } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
-+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
-+ return -EINVAL;
-+ }
-+
-+ memcpy(ctx->key, key, keylen);
-+ ctx->keylen = keylen;
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_ecb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT);
-+}
-+
-+static int atmel_tdes_ecb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, 0);
-+}
-+
-+static int atmel_tdes_cbc_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CBC);
-+}
-+
-+static int atmel_tdes_cbc_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_CBC);
-+}
-+static int atmel_tdes_cfb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB);
-+}
-+
-+static int atmel_tdes_cfb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_CFB);
-+}
-+
-+static int atmel_tdes_cfb8_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
-+ TDES_FLAGS_CFB8);
-+}
-+
-+static int atmel_tdes_cfb8_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB8);
-+}
-+
-+static int atmel_tdes_cfb16_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
-+ TDES_FLAGS_CFB16);
-+}
-+
-+static int atmel_tdes_cfb16_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB16);
-+}
-+
-+static int atmel_tdes_cfb32_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
-+ TDES_FLAGS_CFB32);
-+}
-+
-+static int atmel_tdes_cfb32_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB32);
-+}
-+
-+static int atmel_tdes_ofb_encrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_OFB);
-+}
-+
-+static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
-+{
-+ return atmel_tdes_crypt(req, TDES_FLAGS_OFB);
-+}
-+
-+static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
-+{
-+ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
-+
-+ return 0;
-+}
-+
-+static void atmel_tdes_cra_exit(struct crypto_tfm *tfm)
-+{
-+}
-+
-+static struct crypto_alg tdes_algs[] = {
-+{
-+ .cra_name = "ecb(des)",
-+ .cra_driver_name = "atmel-ecb-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_ecb_encrypt,
-+ .decrypt = atmel_tdes_ecb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cbc(des)",
-+ .cra_driver_name = "atmel-cbc-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_cbc_encrypt,
-+ .decrypt = atmel_tdes_cbc_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb(des)",
-+ .cra_driver_name = "atmel-cfb-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_cfb_encrypt,
-+ .decrypt = atmel_tdes_cfb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb8(des)",
-+ .cra_driver_name = "atmel-cfb8-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB8_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_cfb8_encrypt,
-+ .decrypt = atmel_tdes_cfb8_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb16(des)",
-+ .cra_driver_name = "atmel-cfb16-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB16_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_cfb16_encrypt,
-+ .decrypt = atmel_tdes_cfb16_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb32(des)",
-+ .cra_driver_name = "atmel-cfb32-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB32_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_cfb32_encrypt,
-+ .decrypt = atmel_tdes_cfb32_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "ofb(des)",
-+ .cra_driver_name = "atmel-ofb-des",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = DES_KEY_SIZE,
-+ .max_keysize = DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_des_setkey,
-+ .encrypt = atmel_tdes_ofb_encrypt,
-+ .decrypt = atmel_tdes_ofb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "ecb(des3_ede)",
-+ .cra_driver_name = "atmel-ecb-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2 * DES_KEY_SIZE,
-+ .max_keysize = 3 * DES_KEY_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_ecb_encrypt,
-+ .decrypt = atmel_tdes_ecb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cbc(des3_ede)",
-+ .cra_driver_name = "atmel-cbc-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 3*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_cbc_encrypt,
-+ .decrypt = atmel_tdes_cbc_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb(des3_ede)",
-+ .cra_driver_name = "atmel-cfb-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 2*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_cfb_encrypt,
-+ .decrypt = atmel_tdes_cfb_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb8(des3_ede)",
-+ .cra_driver_name = "atmel-cfb8-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB8_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 2*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_cfb8_encrypt,
-+ .decrypt = atmel_tdes_cfb8_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb16(des3_ede)",
-+ .cra_driver_name = "atmel-cfb16-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB16_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 2*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_cfb16_encrypt,
-+ .decrypt = atmel_tdes_cfb16_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "cfb32(des3_ede)",
-+ .cra_driver_name = "atmel-cfb32-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = CFB32_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 2*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_cfb32_encrypt,
-+ .decrypt = atmel_tdes_cfb32_decrypt,
-+ }
-+},
-+{
-+ .cra_name = "ofb(des3_ede)",
-+ .cra_driver_name = "atmel-ofb-tdes",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
-+ .cra_blocksize = DES_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-+ .cra_alignmask = 0,
-+ .cra_type = &crypto_ablkcipher_type,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_tdes_cra_init,
-+ .cra_exit = atmel_tdes_cra_exit,
-+ .cra_u.ablkcipher = {
-+ .min_keysize = 2*DES_KEY_SIZE,
-+ .max_keysize = 3*DES_KEY_SIZE,
-+ .ivsize = DES_BLOCK_SIZE,
-+ .setkey = atmel_tdes_setkey,
-+ .encrypt = atmel_tdes_ofb_encrypt,
-+ .decrypt = atmel_tdes_ofb_decrypt,
-+ }
-+},
-+};
-+
-+static void atmel_tdes_queue_task(unsigned long data)
-+{
-+ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data;
-+
-+ atmel_tdes_handle_queue(dd, NULL);
-+}
-+
-+static void atmel_tdes_done_task(unsigned long data)
-+{
-+ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
-+ int err;
-+
-+ err = atmel_tdes_crypt_dma_stop(dd);
-+
-+ err = dd->err ? : err;
-+
-+ if (dd->total && !err) {
-+ err = atmel_tdes_crypt_dma_start(dd);
-+ if (!err)
-+ return;
-+ }
-+
-+ atmel_tdes_finish_req(dd, err);
-+ atmel_tdes_handle_queue(dd, NULL);
-+}
-+
-+static irqreturn_t atmel_tdes_irq(int irq, void *dev_id)
-+{
-+ struct atmel_tdes_dev *tdes_dd = dev_id;
-+ u32 reg;
-+
-+ reg = atmel_tdes_read(tdes_dd, TDES_ISR);
-+ if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) {
-+ atmel_tdes_write(tdes_dd, TDES_IDR, reg);
-+ if (TDES_FLAGS_BUSY & tdes_dd->flags)
-+ tasklet_schedule(&tdes_dd->done_task);
-+ else
-+ dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n");
-+ return IRQ_HANDLED;
-+ }
-+
-+ return IRQ_NONE;
-+}
-+
-+static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++)
-+ crypto_unregister_alg(&tdes_algs[i]);
-+}
-+
-+static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
-+{
-+ int err, i, j;
-+
-+ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
-+ INIT_LIST_HEAD(&tdes_algs[i].cra_list);
-+ err = crypto_register_alg(&tdes_algs[i]);
-+ if (err)
-+ goto err_tdes_algs;
-+ }
-+
-+ return 0;
-+
-+err_tdes_algs:
-+ for (j = 0; j < i; j++)
-+ crypto_unregister_alg(&tdes_algs[j]);
-+
-+ return err;
-+}
-+
-+static int __devinit atmel_tdes_probe(struct platform_device *pdev)
-+{
-+ struct atmel_tdes_dev *tdes_dd;
-+ struct device *dev = &pdev->dev;
-+ struct resource *tdes_res;
-+ unsigned long tdes_phys_size;
-+ int err;
-+
-+ tdes_dd = kzalloc(sizeof(struct atmel_tdes_dev), GFP_KERNEL);
-+ if (tdes_dd == NULL) {
-+ dev_err(dev, "unable to alloc data struct.\n");
-+ err = -ENOMEM;
-+ goto tdes_dd_err;
-+ }
-+
-+ tdes_dd->dev = dev;
-+
-+ platform_set_drvdata(pdev, tdes_dd);
-+
-+ INIT_LIST_HEAD(&tdes_dd->list);
-+
-+ tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task,
-+ (unsigned long)tdes_dd);
-+ tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task,
-+ (unsigned long)tdes_dd);
-+
-+ crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH);
-+
-+ tdes_dd->irq = -1;
-+
-+ /* Get the base address */
-+ tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!tdes_res) {
-+ dev_err(dev, "no MEM resource info\n");
-+ err = -ENODEV;
-+ goto res_err;
-+ }
-+ tdes_dd->phys_base = tdes_res->start;
-+ tdes_phys_size = resource_size(tdes_res);
-+
-+ /* Get the IRQ */
-+ tdes_dd->irq = platform_get_irq(pdev, 0);
-+ if (tdes_dd->irq < 0) {
-+ dev_err(dev, "no IRQ resource info\n");
-+ err = tdes_dd->irq;
-+ goto res_err;
-+ }
-+
-+ err = request_irq(tdes_dd->irq, atmel_tdes_irq, IRQF_SHARED,
-+ "atmel-tdes", tdes_dd);
-+ if (err) {
-+ dev_err(dev, "unable to request tdes irq.\n");
-+ goto tdes_irq_err;
-+ }
-+
-+ /* Initializing the clock */
-+ tdes_dd->iclk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(tdes_dd->iclk)) {
-+ dev_err(dev, "clock intialization failed.\n");
-+ err = PTR_ERR(tdes_dd->iclk);
-+ goto clk_err;
-+ }
-+
-+ tdes_dd->io_base = ioremap(tdes_dd->phys_base, tdes_phys_size);
-+ if (!tdes_dd->io_base) {
-+ dev_err(dev, "can't ioremap\n");
-+ err = -ENOMEM;
-+ goto tdes_io_err;
-+ }
-+
-+ err = atmel_tdes_dma_init(tdes_dd);
-+ if (err)
-+ goto err_tdes_dma;
-+
-+ spin_lock(&atmel_tdes.lock);
-+ list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
-+ spin_unlock(&atmel_tdes.lock);
-+
-+ err = atmel_tdes_register_algs(tdes_dd);
-+ if (err)
-+ goto err_algs;
-+
-+ dev_info(dev, "Atmel DES/TDES\n");
-+
-+ return 0;
-+
-+err_algs:
-+ spin_lock(&atmel_tdes.lock);
-+ list_del(&tdes_dd->list);
-+ spin_unlock(&atmel_tdes.lock);
-+ atmel_tdes_dma_cleanup(tdes_dd);
-+err_tdes_dma:
-+ iounmap(tdes_dd->io_base);
-+tdes_io_err:
-+ clk_put(tdes_dd->iclk);
-+clk_err:
-+ free_irq(tdes_dd->irq, tdes_dd);
-+tdes_irq_err:
-+res_err:
-+ tasklet_kill(&tdes_dd->done_task);
-+ tasklet_kill(&tdes_dd->queue_task);
-+ kfree(tdes_dd);
-+ tdes_dd = NULL;
-+tdes_dd_err:
-+ dev_err(dev, "initialization failed.\n");
-+
-+ return err;
-+}
-+
-+static int __devexit atmel_tdes_remove(struct platform_device *pdev)
-+{
-+ static struct atmel_tdes_dev *tdes_dd;
-+
-+ tdes_dd = platform_get_drvdata(pdev);
-+ if (!tdes_dd)
-+ return -ENODEV;
-+ spin_lock(&atmel_tdes.lock);
-+ list_del(&tdes_dd->list);
-+ spin_unlock(&atmel_tdes.lock);
-+
-+ atmel_tdes_unregister_algs(tdes_dd);
-+
-+ tasklet_kill(&tdes_dd->done_task);
-+ tasklet_kill(&tdes_dd->queue_task);
-+
-+ atmel_tdes_dma_cleanup(tdes_dd);
-+
-+ iounmap(tdes_dd->io_base);
-+
-+ clk_put(tdes_dd->iclk);
-+
-+ if (tdes_dd->irq >= 0)
-+ free_irq(tdes_dd->irq, tdes_dd);
-+
-+ kfree(tdes_dd);
-+ tdes_dd = NULL;
-+
-+ return 0;
-+}
-+
-+static struct platform_driver atmel_tdes_driver = {
-+ .probe = atmel_tdes_probe,
-+ .remove = __devexit_p(atmel_tdes_remove),
-+ .driver = {
-+ .name = "atmel_tdes",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(atmel_tdes_driver);
-+
-+MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f8a2c18935b2f0955623ca0c59ba8832485a47c3 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Fri, 14 Sep 2012 16:04:55 +0200
+Subject: i2c: at91: add dma support
+
+Add dma support for Atmel TWI which is available on sam9x5 and later.
+
+When using dma for reception, you have to read only n-2 bytes. The last
+two bytes are read manually. Don't doing this should cause to send the
+STOP command too late and then to get extra data in the receive
+register.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/i2c/busses/i2c-at91.c | 326 ++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 314 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index aa59a25..33219f8 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -19,6 +19,8 @@
+
+ #include <linux/clk.h>
+ #include <linux/completion.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmaengine.h>
+ #include <linux/err.h>
+ #include <linux/i2c.h>
+ #include <linux/interrupt.h>
+@@ -30,6 +32,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/slab.h>
+
++#include <mach/at_hdmac.h>
++
+ #define TWI_CLK_HZ 100000 /* max 400 Kbits/s */
+ #define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
+
+@@ -65,9 +69,21 @@
+ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */
+
+ struct at91_twi_pdata {
+- unsigned clk_max_div;
+- unsigned clk_offset;
+- bool has_unre_flag;
++ unsigned clk_max_div;
++ unsigned clk_offset;
++ bool has_unre_flag;
++ bool has_dma_support;
++ struct at_dma_slave dma_slave;
++};
++
++struct at91_twi_dma {
++ struct dma_chan *chan_rx;
++ struct dma_chan *chan_tx;
++ struct scatterlist sg;
++ struct dma_async_tx_descriptor *data_desc;
++ enum dma_data_direction direction;
++ bool buf_mapped;
++ bool xfer_in_progress;
+ };
+
+ struct at91_twi_dev {
+@@ -79,10 +95,13 @@ struct at91_twi_dev {
+ size_t buf_len;
+ struct i2c_msg *msg;
+ int irq;
++ unsigned imr;
+ unsigned transfer_status;
+ struct i2c_adapter adapter;
+ unsigned twi_cwgr_reg;
+ struct at91_twi_pdata *pdata;
++ bool use_dma;
++ struct at91_twi_dma dma;
+ };
+
+ static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
+@@ -98,7 +117,18 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
+ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
+ {
+ at91_twi_write(dev, AT91_TWI_IDR,
+- AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++ AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
++}
++
++static void at91_twi_irq_save(struct at91_twi_dev *dev)
++{
++ dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
++ at91_disable_twi_interrupts(dev);
++}
++
++static void at91_twi_irq_restore(struct at91_twi_dev *dev)
++{
++ at91_twi_write(dev, AT91_TWI_IER, dev->imr);
+ }
+
+ static void at91_init_twi_bus(struct at91_twi_dev *dev)
+@@ -137,6 +167,30 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+ dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
+ }
+
++static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
++{
++ struct at91_twi_dma *dma = &dev->dma;
++
++ at91_twi_irq_save(dev);
++
++ if (dma->xfer_in_progress) {
++ if (dma->direction == DMA_FROM_DEVICE)
++ dma->chan_rx->device->device_control(dma->chan_rx,
++ DMA_TERMINATE_ALL, 0);
++ else
++ dma->chan_tx->device->device_control(dma->chan_tx,
++ DMA_TERMINATE_ALL, 0);
++ dma->xfer_in_progress = false;
++ }
++ if (dma->buf_mapped) {
++ dma_unmap_single(dev->dev, sg_dma_address(&dma->sg),
++ dev->buf_len, dma->direction);
++ dma->buf_mapped = false;
++ }
++
++ at91_twi_irq_restore(dev);
++}
++
+ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+ {
+ if (dev->buf_len <= 0)
+@@ -153,6 +207,65 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
+ ++dev->buf;
+ }
+
++static void at91_twi_write_data_dma_callback(void *data)
++{
++ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
++
++ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
++ dev->buf_len, DMA_TO_DEVICE);
++
++ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
++}
++
++static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
++{
++ dma_addr_t dma_addr;
++ dma_cookie_t cookie;
++ struct dma_async_tx_descriptor *txdesc;
++ struct at91_twi_dma *dma = &dev->dma;
++ struct dma_chan *chan_tx = dma->chan_tx;
++
++ if (dev->buf_len <= 0)
++ return;
++
++ dma->direction = DMA_TO_DEVICE;
++
++ at91_twi_irq_save(dev);
++ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
++ DMA_TO_DEVICE);
++ if (dma_mapping_error(dev->dev, dma_addr)) {
++ dev_err(dev->dev, "dma map failed\n");
++ return;
++ }
++ dma->buf_mapped = true;
++ at91_twi_irq_restore(dev);
++ sg_dma_len(&dma->sg) = dev->buf_len;
++ sg_dma_address(&dma->sg) = dma_addr;
++
++ txdesc = chan_tx->device->device_prep_slave_sg(chan_tx, &dma->sg,
++ 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
++ if (!txdesc) {
++ dev_err(dev->dev, "dma prep slave sg failed\n");
++ goto error;
++ }
++
++ txdesc->callback = at91_twi_write_data_dma_callback;
++ txdesc->callback_param = dev;
++
++ dma->xfer_in_progress = true;
++ cookie = txdesc->tx_submit(txdesc);
++ if (dma_submit_error(cookie)) {
++ dev_err(dev->dev, "dma submit error\n");
++ goto error;
++ }
++ dma->chan_tx->device->device_issue_pending(chan_tx);
++
++ return;
++
++error:
++ at91_twi_dma_cleanup(dev);
++}
++
+ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+ {
+ if (dev->buf_len <= 0)
+@@ -178,6 +291,66 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
+ ++dev->buf;
+ }
+
++static void at91_twi_read_data_dma_callback(void *data)
++{
++ struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
++
++ dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
++ dev->buf_len, DMA_FROM_DEVICE);
++
++ /* The last two bytes have to be read without using dma */
++ dev->buf += dev->buf_len - 2;
++ dev->buf_len = 2;
++ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY);
++}
++
++static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
++{
++ dma_addr_t dma_addr;
++ dma_cookie_t cookie;
++ struct dma_async_tx_descriptor *rxdesc;
++ struct at91_twi_dma *dma = &dev->dma;
++ struct dma_chan *chan_rx = dma->chan_rx;
++
++ dma->direction = DMA_FROM_DEVICE;
++
++ /* Keep in mind that we won't use dma to read the last two bytes */
++ at91_twi_irq_save(dev);
++ dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2,
++ DMA_FROM_DEVICE);
++ if (dma_mapping_error(dev->dev, dma_addr)) {
++ dev_err(dev->dev, "dma map failed\n");
++ return;
++ }
++ dma->buf_mapped = true;
++ at91_twi_irq_restore(dev);
++ dma->sg.dma_address = dma_addr;
++ sg_dma_len(&dma->sg) = dev->buf_len - 2;
++
++ rxdesc = chan_rx->device->device_prep_slave_sg(chan_rx, &dma->sg,
++ 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK, NULL);
++ if (!rxdesc) {
++ dev_err(dev->dev, "dma prep slave sg failed\n");
++ goto error;
++ }
++
++ rxdesc->callback = at91_twi_read_data_dma_callback;
++ rxdesc->callback_param = dev;
++
++ dma->xfer_in_progress = true;
++ cookie = rxdesc->tx_submit(rxdesc);
++ if (dma_submit_error(cookie)) {
++ dev_err(dev->dev, "dma submit error\n");
++ goto error;
++ }
++ dma->chan_rx->device->device_issue_pending(dma->chan_rx);
++
++ return;
++
++error:
++ at91_twi_dma_cleanup(dev);
++}
++
+ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
+ {
+ struct at91_twi_dev *dev = dev_id;
+@@ -224,12 +397,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
+ if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
+ start_flags |= AT91_TWI_STOP;
+ at91_twi_write(dev, AT91_TWI_CR, start_flags);
+- at91_twi_write(dev, AT91_TWI_IER,
++ /*
++ * When using dma, the last byte has to be read manually in
++ * order to not send the stop command too late and then
++ * to receive extra data. In practice, there are some issues
++ * if you use the dma to read n-1 bytes because of latency.
++ * Reading n-2 bytes with dma and the two last ones manually
++ * seems to be the best solution.
++ */
++ if (dev->use_dma && (dev->buf_len > 2)) {
++ at91_twi_read_data_dma(dev);
++ /*
++ * It is important to enable TXCOMP irq here because
++ * doing it only when transferring the last two bytes
++ * will mask NACK errors since TXCOMP is set when a
++ * NACK occurs.
++ */
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP);
++ } else
++ at91_twi_write(dev, AT91_TWI_IER,
+ AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
+ } else {
+- at91_twi_write_next_byte(dev);
+- at91_twi_write(dev, AT91_TWI_IER,
+- AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ if (dev->use_dma) {
++ at91_twi_write_data_dma(dev);
++ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
++ } else {
++ at91_twi_write_next_byte(dev);
++ at91_twi_write(dev, AT91_TWI_IER,
++ AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
++ }
+ }
+
+ ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+@@ -237,23 +434,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
+ if (ret == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ at91_init_twi_bus(dev);
+- return -ETIMEDOUT;
++ ret = -ETIMEDOUT;
++ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_NACK) {
+ dev_dbg(dev->dev, "received nack\n");
+- return -EREMOTEIO;
++ ret = -EREMOTEIO;
++ goto error;
+ }
+ if (dev->transfer_status & AT91_TWI_OVRE) {
+ dev_err(dev->dev, "overrun while reading\n");
+- return -EIO;
++ ret = -EIO;
++ goto error;
+ }
+ if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
+ dev_err(dev->dev, "underrun while writing\n");
+- return -EIO;
++ ret = -EIO;
++ goto error;
+ }
+ dev_dbg(dev->dev, "transfer complete\n");
+
+ return 0;
++
++error:
++ at91_twi_dma_cleanup(dev);
++ return ret;
+ }
+
+ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
+@@ -324,36 +529,42 @@ static struct at91_twi_pdata at91rm9200_config = {
+ .clk_max_div = 5,
+ .clk_offset = 3,
+ .has_unre_flag = true,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9261_config = {
+ .clk_max_div = 5,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9260_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9g20_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9g10_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = false,
+ };
+
+ static struct at91_twi_pdata at91sam9x5_config = {
+ .clk_max_div = 7,
+ .clk_offset = 4,
+ .has_unre_flag = false,
++ .has_dma_support = true,
+ };
+
+ static const struct platform_device_id at91_twi_devtypes[] = {
+@@ -400,6 +611,90 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+ #define atmel_twi_dt_ids NULL
+ #endif
+
++static bool __devinit filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int __devinit at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
++{
++ int ret = 0;
++ struct at_dma_slave *sdata;
++ struct dma_slave_config slave_config;
++ struct at91_twi_dma *dma = &dev->dma;
++
++ sdata = &dev->pdata->dma_slave;
++
++ memset(&slave_config, 0, sizeof(slave_config));
++ slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
++ slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave_config.src_maxburst = 1;
++ slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
++ slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
++ slave_config.dst_maxburst = 1;
++ slave_config.device_fc = false;
++
++ if (sdata && sdata->dma_dev) {
++ dma_cap_mask_t mask;
++
++ dma_cap_zero(mask);
++ dma_cap_set(DMA_SLAVE, mask);
++ dma->chan_tx = dma_request_channel(mask, filter, sdata);
++ if (!dma->chan_tx) {
++ dev_err(dev->dev, "no DMA channel available for tx\n");
++ ret = -EBUSY;
++ goto error;
++ }
++ dma->chan_rx = dma_request_channel(mask, filter, sdata);
++ if (!dma->chan_rx) {
++ dev_err(dev->dev, "no DMA channel available for rx\n");
++ ret = -EBUSY;
++ goto error;
++ }
++ } else {
++ ret = -EINVAL;
++ goto error;
++ }
++
++ slave_config.direction = DMA_TO_DEVICE;
++ if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
++ dev_err(dev->dev, "failed to configure tx channel\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ slave_config.direction = DMA_FROM_DEVICE;
++ if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
++ dev_err(dev->dev, "failed to configure rx channel\n");
++ ret = -EINVAL;
++ goto error;
++ }
++
++ sg_init_table(&dma->sg, 1);
++ dma->buf_mapped = false;
++ dma->xfer_in_progress = false;
++
++ dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
++ dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
++
++ return ret;
++
++error:
++ dev_info(dev->dev, "can't use DMA\n");
++ if (dma->chan_rx)
++ dma_release_channel(dma->chan_rx);
++ if (dma->chan_tx)
++ dma_release_channel(dma->chan_tx);
++ return ret;
++}
++
+ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
+ struct platform_device *pdev)
+ {
+@@ -418,6 +713,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ struct at91_twi_dev *dev;
+ struct resource *mem;
+ int rc;
++ u32 phy_addr;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+@@ -428,6 +724,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem)
+ return -ENODEV;
++ phy_addr = mem->start;
+
+ dev->pdata = at91_twi_get_driver_data(pdev);
+ if (!dev->pdata)
+@@ -457,6 +754,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ }
+ clk_prepare_enable(dev->clk);
+
++ if (dev->pdata->has_dma_support) {
++ if (at91_twi_configure_dma(dev, phy_addr) == 0)
++ dev->use_dma = true;
++ }
++
+ at91_calc_twi_clock(dev, TWI_CLK_HZ);
+ at91_init_twi_bus(dev);
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 3d0dc28cd259b675bf98fa158c9a6cb800c40683 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:06 +0200
-Subject: crypto: add Atmel SHA1/SHA256 driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/Kconfig | 14 +
- drivers/crypto/Makefile | 1 +
- drivers/crypto/atmel-sha-regs.h | 46 ++
- drivers/crypto/atmel-sha.c | 1112 +++++++++++++++++++++++++++++++++++++++
- 4 files changed, 1173 insertions(+)
- create mode 100644 drivers/crypto/atmel-sha-regs.h
- create mode 100644 drivers/crypto/atmel-sha.c
-
-diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
-index 2124898..2339add 100644
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -329,4 +329,18 @@ config CRYPTO_DEV_ATMEL_TDES
- To compile this driver as a module, choose M here: the module
- will be called atmel-tdes.
-
-+config CRYPTO_DEV_ATMEL_SHA
-+ tristate "Support for Atmel SHA1/SHA256 hw accelerator"
-+ depends on ARCH_AT91
-+ select CRYPTO_SHA1
-+ select CRYPTO_SHA256
-+ select CRYPTO_ALGAPI
-+ help
-+ Some Atmel processors have SHA1/SHA256 hw accelerator.
-+ Select this if you want to use the Atmel module for
-+ SHA1/SHA256 algorithms.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called atmel-sha.
-+
- endif # CRYPTO_HW
-diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
-index 443bf4d..d355c25 100644
---- a/drivers/crypto/Makefile
-+++ b/drivers/crypto/Makefile
-@@ -16,3 +16,4 @@ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
- obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
-+obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
-diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
-new file mode 100644
-index 0000000..dc53a20
---- /dev/null
-+++ b/drivers/crypto/atmel-sha-regs.h
-@@ -0,0 +1,46 @@
-+#ifndef __ATMEL_SHA_REGS_H__
-+#define __ATMEL_SHA_REGS_H__
-+
-+#define SHA_REG_DIGEST(x) (0x80 + ((x) * 0x04))
-+#define SHA_REG_DIN(x) (0x40 + ((x) * 0x04))
-+
-+#define SHA_CR 0x00
-+#define SHA_CR_START (1 << 0)
-+#define SHA_CR_FIRST (1 << 4)
-+#define SHA_CR_SWRST (1 << 8)
-+
-+#define SHA_MR 0x04
-+#define SHA_MR_MODE_MASK (0x3 << 0)
-+#define SHA_MR_MODE_MANUAL 0x0
-+#define SHA_MR_MODE_AUTO 0x1
-+#define SHA_MR_MODE_PDC 0x2
-+#define SHA_MR_DUALBUFF (1 << 3)
-+#define SHA_MR_PROCDLY (1 << 4)
-+#define SHA_MR_ALGO_SHA1 (0 << 8)
-+#define SHA_MR_ALGO_SHA256 (1 << 8)
-+
-+#define SHA_IER 0x10
-+#define SHA_IDR 0x14
-+#define SHA_IMR 0x18
-+#define SHA_ISR 0x1C
-+#define SHA_INT_DATARDY (1 << 0)
-+#define SHA_INT_ENDTX (1 << 1)
-+#define SHA_INT_TXBUFE (1 << 2)
-+#define SHA_INT_URAD (1 << 8)
-+#define SHA_ISR_URAT_MASK (0x7 << 12)
-+#define SHA_ISR_URAT_IDR (0x0 << 12)
-+#define SHA_ISR_URAT_ODR (0x1 << 12)
-+#define SHA_ISR_URAT_MR (0x2 << 12)
-+#define SHA_ISR_URAT_WO (0x5 << 12)
-+
-+#define SHA_TPR 0x108
-+#define SHA_TCR 0x10C
-+#define SHA_TNPR 0x118
-+#define SHA_TNCR 0x11C
-+#define SHA_PTCR 0x120
-+#define SHA_PTCR_TXTEN (1 << 8)
-+#define SHA_PTCR_TXTDIS (1 << 9)
-+#define SHA_PTSR 0x124
-+#define SHA_PTSR_TXTEN (1 << 8)
-+
-+#endif /* __ATMEL_SHA_REGS_H__ */
-diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
-new file mode 100644
-index 0000000..f938b9d
---- /dev/null
-+++ b/drivers/crypto/atmel-sha.c
-@@ -0,0 +1,1112 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * Support for ATMEL SHA1/SHA256 HW acceleration.
-+ *
-+ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
-+ * Author: Nicolas Royer <nicolas@eukrea.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ * Some ideas are from omap-sham.c drivers.
-+ */
-+
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/hw_random.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/kernel.h>
-+#include <linux/clk.h>
-+#include <linux/irq.h>
-+#include <linux/io.h>
-+#include <linux/platform_device.h>
-+#include <linux/scatterlist.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/delay.h>
-+#include <linux/crypto.h>
-+#include <linux/cryptohash.h>
-+#include <crypto/scatterwalk.h>
-+#include <crypto/algapi.h>
-+#include <crypto/sha.h>
-+#include <crypto/hash.h>
-+#include <crypto/internal/hash.h>
-+#include "atmel-sha-regs.h"
-+
-+/* SHA flags */
-+#define SHA_FLAGS_BUSY BIT(0)
-+#define SHA_FLAGS_FINAL BIT(1)
-+#define SHA_FLAGS_DMA_ACTIVE BIT(2)
-+#define SHA_FLAGS_OUTPUT_READY BIT(3)
-+#define SHA_FLAGS_INIT BIT(4)
-+#define SHA_FLAGS_CPU BIT(5)
-+#define SHA_FLAGS_DMA_READY BIT(6)
-+
-+#define SHA_FLAGS_FINUP BIT(16)
-+#define SHA_FLAGS_SG BIT(17)
-+#define SHA_FLAGS_SHA1 BIT(18)
-+#define SHA_FLAGS_SHA256 BIT(19)
-+#define SHA_FLAGS_ERROR BIT(20)
-+#define SHA_FLAGS_PAD BIT(21)
-+
-+#define SHA_FLAGS_DUALBUFF BIT(24)
-+
-+#define SHA_OP_UPDATE 1
-+#define SHA_OP_FINAL 2
-+
-+#define SHA_BUFFER_LEN PAGE_SIZE
-+
-+#define ATMEL_SHA_DMA_THRESHOLD 56
-+
-+
-+struct atmel_sha_dev;
-+
-+struct atmel_sha_reqctx {
-+ struct atmel_sha_dev *dd;
-+ unsigned long flags;
-+ unsigned long op;
-+
-+ u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
-+ size_t digcnt;
-+ size_t bufcnt;
-+ size_t buflen;
-+ dma_addr_t dma_addr;
-+
-+ /* walk state */
-+ struct scatterlist *sg;
-+ unsigned int offset; /* offset in current sg */
-+ unsigned int total; /* total request */
-+
-+ u8 buffer[0] __aligned(sizeof(u32));
-+};
-+
-+struct atmel_sha_ctx {
-+ struct atmel_sha_dev *dd;
-+
-+ unsigned long flags;
-+
-+ /* fallback stuff */
-+ struct crypto_shash *fallback;
-+
-+};
-+
-+#define ATMEL_SHA_QUEUE_LENGTH 1
-+
-+struct atmel_sha_dev {
-+ struct list_head list;
-+ unsigned long phys_base;
-+ struct device *dev;
-+ struct clk *iclk;
-+ int irq;
-+ void __iomem *io_base;
-+
-+ spinlock_t lock;
-+ int err;
-+ struct tasklet_struct done_task;
-+
-+ unsigned long flags;
-+ struct crypto_queue queue;
-+ struct ahash_request *req;
-+};
-+
-+struct atmel_sha_drv {
-+ struct list_head dev_list;
-+ spinlock_t lock;
-+};
-+
-+static struct atmel_sha_drv atmel_sha = {
-+ .dev_list = LIST_HEAD_INIT(atmel_sha.dev_list),
-+ .lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock),
-+};
-+
-+static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset)
-+{
-+ return readl_relaxed(dd->io_base + offset);
-+}
-+
-+static inline void atmel_sha_write(struct atmel_sha_dev *dd,
-+ u32 offset, u32 value)
-+{
-+ writel_relaxed(value, dd->io_base + offset);
-+}
-+
-+static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
-+{
-+ atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
-+
-+ if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
-+ dd->flags |= SHA_FLAGS_DUALBUFF;
-+}
-+
-+static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
-+{
-+ size_t count;
-+
-+ while ((ctx->bufcnt < ctx->buflen) && ctx->total) {
-+ count = min(ctx->sg->length - ctx->offset, ctx->total);
-+ count = min(count, ctx->buflen - ctx->bufcnt);
-+
-+ if (count <= 0)
-+ break;
-+
-+ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
-+ ctx->offset, count, 0);
-+
-+ ctx->bufcnt += count;
-+ ctx->offset += count;
-+ ctx->total -= count;
-+
-+ if (ctx->offset == ctx->sg->length) {
-+ ctx->sg = sg_next(ctx->sg);
-+ if (ctx->sg)
-+ ctx->offset = 0;
-+ else
-+ ctx->total = 0;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+ * The purpose of this padding is to ensure that the padded message
-+ * is a multiple of 512 bits. The bit "1" is appended at the end of
-+ * the message followed by "padlen-1" zero bits. Then a 64 bits block
-+ * equals to the message length in bits is appended.
-+ *
-+ * padlen is calculated as followed:
-+ * - if message length < 56 bytes then padlen = 56 - message length
-+ * - else padlen = 64 + 56 - message length
-+ */
-+static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
-+{
-+ unsigned int index, padlen;
-+ u64 bits;
-+ u64 size;
-+
-+ bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
-+ size = cpu_to_be64(bits);
-+
-+ index = ctx->bufcnt & 0x3f;
-+ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-+ *(ctx->buffer + ctx->bufcnt) = 0x80;
-+ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
-+ memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
-+ ctx->bufcnt += padlen + 8;
-+ ctx->flags |= SHA_FLAGS_PAD;
-+}
-+
-+static int atmel_sha_init(struct ahash_request *req)
-+{
-+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
-+ struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm);
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ struct atmel_sha_dev *dd = NULL;
-+ struct atmel_sha_dev *tmp;
-+
-+ spin_lock_bh(&atmel_sha.lock);
-+ if (!tctx->dd) {
-+ list_for_each_entry(tmp, &atmel_sha.dev_list, list) {
-+ dd = tmp;
-+ break;
-+ }
-+ tctx->dd = dd;
-+ } else {
-+ dd = tctx->dd;
-+ }
-+
-+ spin_unlock_bh(&atmel_sha.lock);
-+
-+ ctx->dd = dd;
-+
-+ ctx->flags = 0;
-+
-+ dev_dbg(dd->dev, "init: digest size: %d\n",
-+ crypto_ahash_digestsize(tfm));
-+
-+ if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
-+ ctx->flags |= SHA_FLAGS_SHA1;
-+ else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
-+ ctx->flags |= SHA_FLAGS_SHA256;
-+
-+ ctx->bufcnt = 0;
-+ ctx->digcnt = 0;
-+ ctx->buflen = SHA_BUFFER_LEN;
-+
-+ return 0;
-+}
-+
-+static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
-+
-+ if (likely(dma)) {
-+ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
-+ valmr = SHA_MR_MODE_PDC;
-+ if (dd->flags & SHA_FLAGS_DUALBUFF)
-+ valmr = SHA_MR_DUALBUFF;
-+ } else {
-+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
-+ }
-+
-+ if (ctx->flags & SHA_FLAGS_SHA256)
-+ valmr |= SHA_MR_ALGO_SHA256;
-+
-+ /* Setting CR_FIRST only for the first iteration */
-+ if (!ctx->digcnt)
-+ valcr = SHA_CR_FIRST;
-+
-+ atmel_sha_write(dd, SHA_CR, valcr);
-+ atmel_sha_write(dd, SHA_MR, valmr);
-+}
-+
-+static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
-+ size_t length, int final)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ int count, len32;
-+ const u32 *buffer = (const u32 *)buf;
-+
-+ dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
-+ ctx->digcnt, length, final);
-+
-+ atmel_sha_write_ctrl(dd, 0);
-+
-+ /* should be non-zero before next lines to disable clocks later */
-+ ctx->digcnt += length;
-+
-+ if (final)
-+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
-+
-+ len32 = DIV_ROUND_UP(length, sizeof(u32));
-+
-+ dd->flags |= SHA_FLAGS_CPU;
-+
-+ for (count = 0; count < len32; count++)
-+ atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]);
-+
-+ return -EINPROGRESS;
-+}
-+
-+static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
-+ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ int len32;
-+
-+ dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
-+ ctx->digcnt, length1, final);
-+
-+ len32 = DIV_ROUND_UP(length1, sizeof(u32));
-+ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
-+ atmel_sha_write(dd, SHA_TPR, dma_addr1);
-+ atmel_sha_write(dd, SHA_TCR, len32);
-+
-+ len32 = DIV_ROUND_UP(length2, sizeof(u32));
-+ atmel_sha_write(dd, SHA_TNPR, dma_addr2);
-+ atmel_sha_write(dd, SHA_TNCR, len32);
-+
-+ atmel_sha_write_ctrl(dd, 1);
-+
-+ /* should be non-zero before next lines to disable clocks later */
-+ ctx->digcnt += length1;
-+
-+ if (final)
-+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
-+
-+ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
-+
-+ /* Start DMA transfer */
-+ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN);
-+
-+ return -EINPROGRESS;
-+}
-+
-+static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ int bufcnt;
-+
-+ atmel_sha_append_sg(ctx);
-+ atmel_sha_fill_padding(ctx, 0);
-+
-+ bufcnt = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+
-+ return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
-+}
-+
-+static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
-+ struct atmel_sha_reqctx *ctx,
-+ size_t length, int final)
-+{
-+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
-+ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
-+ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
-+ SHA1_BLOCK_SIZE);
-+ return -EINVAL;
-+ }
-+
-+ ctx->flags &= ~SHA_FLAGS_SG;
-+
-+ /* next call does not fail... so no unmap in the case of error */
-+ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
-+}
-+
-+static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ unsigned int final;
-+ size_t count;
-+
-+ atmel_sha_append_sg(ctx);
-+
-+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
-+
-+ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
-+ ctx->bufcnt, ctx->digcnt, final);
-+
-+ if (final)
-+ atmel_sha_fill_padding(ctx, 0);
-+
-+ if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
-+ count = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+ return atmel_sha_xmit_dma_map(dd, ctx, count, final);
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ unsigned int length, final, tail;
-+ struct scatterlist *sg;
-+ unsigned int count;
-+
-+ if (!ctx->total)
-+ return 0;
-+
-+ if (ctx->bufcnt || ctx->offset)
-+ return atmel_sha_update_dma_slow(dd);
-+
-+ dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
-+ ctx->digcnt, ctx->bufcnt, ctx->total);
-+
-+ sg = ctx->sg;
-+
-+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
-+ return atmel_sha_update_dma_slow(dd);
-+
-+ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
-+ /* size is not SHA1_BLOCK_SIZE aligned */
-+ return atmel_sha_update_dma_slow(dd);
-+
-+ length = min(ctx->total, sg->length);
-+
-+ if (sg_is_last(sg)) {
-+ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
-+ /* not last sg must be SHA1_BLOCK_SIZE aligned */
-+ tail = length & (SHA1_BLOCK_SIZE - 1);
-+ length -= tail;
-+ if (length == 0) {
-+ /* offset where to start slow */
-+ ctx->offset = length;
-+ return atmel_sha_update_dma_slow(dd);
-+ }
-+ }
-+ }
-+
-+ ctx->total -= length;
-+ ctx->offset = length; /* offset where to start slow */
-+
-+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
-+
-+ /* Add padding */
-+ if (final) {
-+ tail = length & (SHA1_BLOCK_SIZE - 1);
-+ length -= tail;
-+ ctx->total += tail;
-+ ctx->offset = length; /* offset where to start slow */
-+
-+ sg = ctx->sg;
-+ atmel_sha_append_sg(ctx);
-+
-+ atmel_sha_fill_padding(ctx, length);
-+
-+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
-+ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
-+ dev_err(dd->dev, "dma %u bytes error\n",
-+ ctx->buflen + SHA1_BLOCK_SIZE);
-+ return -EINVAL;
-+ }
-+
-+ if (length == 0) {
-+ ctx->flags &= ~SHA_FLAGS_SG;
-+ count = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
-+ 0, final);
-+ } else {
-+ ctx->sg = sg;
-+ if (!dma_map_sg(dd->dev, ctx->sg, 1,
-+ DMA_TO_DEVICE)) {
-+ dev_err(dd->dev, "dma_map_sg error\n");
-+ return -EINVAL;
-+ }
-+
-+ ctx->flags |= SHA_FLAGS_SG;
-+
-+ count = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
-+ length, ctx->dma_addr, count, final);
-+ }
-+ }
-+
-+ if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
-+ dev_err(dd->dev, "dma_map_sg error\n");
-+ return -EINVAL;
-+ }
-+
-+ ctx->flags |= SHA_FLAGS_SG;
-+
-+ /* next call does not fail... so no unmap in the case of error */
-+ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
-+ 0, final);
-+}
-+
-+static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+
-+ if (ctx->flags & SHA_FLAGS_SG) {
-+ dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
-+ if (ctx->sg->length == ctx->offset) {
-+ ctx->sg = sg_next(ctx->sg);
-+ if (ctx->sg)
-+ ctx->offset = 0;
-+ }
-+ if (ctx->flags & SHA_FLAGS_PAD)
-+ dma_unmap_single(dd->dev, ctx->dma_addr,
-+ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ } else {
-+ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
-+ SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_sha_update_req(struct atmel_sha_dev *dd)
-+{
-+ struct ahash_request *req = dd->req;
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ int err;
-+
-+ dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
-+ ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
-+
-+ if (ctx->flags & SHA_FLAGS_CPU)
-+ err = atmel_sha_update_cpu(dd);
-+ else
-+ err = atmel_sha_update_dma_start(dd);
-+
-+ /* wait for dma completion before can take more data */
-+ dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
-+ err, ctx->digcnt);
-+
-+ return err;
-+}
-+
-+static int atmel_sha_final_req(struct atmel_sha_dev *dd)
-+{
-+ struct ahash_request *req = dd->req;
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ int err = 0;
-+ int count;
-+
-+ if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) {
-+ atmel_sha_fill_padding(ctx, 0);
-+ count = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+ err = atmel_sha_xmit_dma_map(dd, ctx, count, 1);
-+ }
-+ /* faster to handle last block with cpu */
-+ else {
-+ atmel_sha_fill_padding(ctx, 0);
-+ count = ctx->bufcnt;
-+ ctx->bufcnt = 0;
-+ err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1);
-+ }
-+
-+ dev_dbg(dd->dev, "final_req: err: %d\n", err);
-+
-+ return err;
-+}
-+
-+static void atmel_sha_copy_hash(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ u32 *hash = (u32 *)ctx->digest;
-+ int i;
-+
-+ if (likely(ctx->flags & SHA_FLAGS_SHA1))
-+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
-+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-+ else
-+ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
-+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-+}
-+
-+static void atmel_sha_copy_ready_hash(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+
-+ if (!req->result)
-+ return;
-+
-+ if (likely(ctx->flags & SHA_FLAGS_SHA1))
-+ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
-+ else
-+ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
-+}
-+
-+static int atmel_sha_finish(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ struct atmel_sha_dev *dd = ctx->dd;
-+ int err = 0;
-+
-+ if (ctx->digcnt)
-+ atmel_sha_copy_ready_hash(req);
-+
-+ dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
-+ ctx->bufcnt);
-+
-+ return err;
-+}
-+
-+static void atmel_sha_finish_req(struct ahash_request *req, int err)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ struct atmel_sha_dev *dd = ctx->dd;
-+
-+ if (!err) {
-+ atmel_sha_copy_hash(req);
-+ if (SHA_FLAGS_FINAL & dd->flags)
-+ err = atmel_sha_finish(req);
-+ } else {
-+ ctx->flags |= SHA_FLAGS_ERROR;
-+ }
-+
-+ /* atomic operation is not needed here */
-+ dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
-+ SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
-+
-+ clk_disable_unprepare(dd->iclk);
-+
-+ if (req->base.complete)
-+ req->base.complete(&req->base, err);
-+
-+ /* handle new request */
-+ tasklet_schedule(&dd->done_task);
-+}
-+
-+static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
-+{
-+ clk_prepare_enable(dd->iclk);
-+
-+ if (SHA_FLAGS_INIT & dd->flags) {
-+ atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
-+ atmel_sha_dualbuff_test(dd);
-+ dd->flags |= SHA_FLAGS_INIT;
-+ dd->err = 0;
-+ }
-+
-+ return 0;
-+}
-+
-+static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
-+ struct ahash_request *req)
-+{
-+ struct crypto_async_request *async_req, *backlog;
-+ struct atmel_sha_reqctx *ctx;
-+ unsigned long flags;
-+ int err = 0, ret = 0;
-+
-+ spin_lock_irqsave(&dd->lock, flags);
-+ if (req)
-+ ret = ahash_enqueue_request(&dd->queue, req);
-+
-+ if (SHA_FLAGS_BUSY & dd->flags) {
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+ return ret;
-+ }
-+
-+ backlog = crypto_get_backlog(&dd->queue);
-+ async_req = crypto_dequeue_request(&dd->queue);
-+ if (async_req)
-+ dd->flags |= SHA_FLAGS_BUSY;
-+
-+ spin_unlock_irqrestore(&dd->lock, flags);
-+
-+ if (!async_req)
-+ return ret;
-+
-+ if (backlog)
-+ backlog->complete(backlog, -EINPROGRESS);
-+
-+ req = ahash_request_cast(async_req);
-+ dd->req = req;
-+ ctx = ahash_request_ctx(req);
-+
-+ dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
-+ ctx->op, req->nbytes);
-+
-+ err = atmel_sha_hw_init(dd);
-+
-+ if (err)
-+ goto err1;
-+
-+ if (ctx->op == SHA_OP_UPDATE) {
-+ err = atmel_sha_update_req(dd);
-+ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
-+ /* no final() after finup() */
-+ err = atmel_sha_final_req(dd);
-+ }
-+ } else if (ctx->op == SHA_OP_FINAL) {
-+ err = atmel_sha_final_req(dd);
-+ }
-+
-+err1:
-+ if (err != -EINPROGRESS)
-+ /* done_task will not finish it, so do it here */
-+ atmel_sha_finish_req(req, err);
-+
-+ dev_dbg(dd->dev, "exit, err: %d\n", err);
-+
-+ return ret;
-+}
-+
-+static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
-+ struct atmel_sha_dev *dd = tctx->dd;
-+
-+ ctx->op = op;
-+
-+ return atmel_sha_handle_queue(dd, req);
-+}
-+
-+static int atmel_sha_update(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+
-+ if (!req->nbytes)
-+ return 0;
-+
-+ ctx->total = req->nbytes;
-+ ctx->sg = req->src;
-+ ctx->offset = 0;
-+
-+ if (ctx->flags & SHA_FLAGS_FINUP) {
-+ if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD)
-+ /* faster to use CPU for short transfers */
-+ ctx->flags |= SHA_FLAGS_CPU;
-+ } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
-+ atmel_sha_append_sg(ctx);
-+ return 0;
-+ }
-+ return atmel_sha_enqueue(req, SHA_OP_UPDATE);
-+}
-+
-+static int atmel_sha_final(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
-+ struct atmel_sha_dev *dd = tctx->dd;
-+
-+ int err = 0;
-+
-+ ctx->flags |= SHA_FLAGS_FINUP;
-+
-+ if (ctx->flags & SHA_FLAGS_ERROR)
-+ return 0; /* uncompleted hash is not needed */
-+
-+ if (ctx->bufcnt) {
-+ return atmel_sha_enqueue(req, SHA_OP_FINAL);
-+ } else if (!(ctx->flags & SHA_FLAGS_PAD)) { /* add padding */
-+ err = atmel_sha_hw_init(dd);
-+ if (err)
-+ goto err1;
-+
-+ dd->flags |= SHA_FLAGS_BUSY;
-+ err = atmel_sha_final_req(dd);
-+ } else {
-+ /* copy ready hash (+ finalize hmac) */
-+ return atmel_sha_finish(req);
-+ }
-+
-+err1:
-+ if (err != -EINPROGRESS)
-+ /* done_task will not finish it, so do it here */
-+ atmel_sha_finish_req(req, err);
-+
-+ return err;
-+}
-+
-+static int atmel_sha_finup(struct ahash_request *req)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
-+ int err1, err2;
-+
-+ ctx->flags |= SHA_FLAGS_FINUP;
-+
-+ err1 = atmel_sha_update(req);
-+ if (err1 == -EINPROGRESS || err1 == -EBUSY)
-+ return err1;
-+
-+ /*
-+ * final() has to be always called to cleanup resources
-+ * even if udpate() failed, except EINPROGRESS
-+ */
-+ err2 = atmel_sha_final(req);
-+
-+ return err1 ?: err2;
-+}
-+
-+static int atmel_sha_digest(struct ahash_request *req)
-+{
-+ return atmel_sha_init(req) ?: atmel_sha_finup(req);
-+}
-+
-+static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
-+{
-+ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
-+ const char *alg_name = crypto_tfm_alg_name(tfm);
-+
-+ /* Allocate a fallback and abort if it failed. */
-+ tctx->fallback = crypto_alloc_shash(alg_name, 0,
-+ CRYPTO_ALG_NEED_FALLBACK);
-+ if (IS_ERR(tctx->fallback)) {
-+ pr_err("atmel-sha: fallback driver '%s' could not be loaded.\n",
-+ alg_name);
-+ return PTR_ERR(tctx->fallback);
-+ }
-+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
-+ sizeof(struct atmel_sha_reqctx) +
-+ SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
-+
-+ return 0;
-+}
-+
-+static int atmel_sha_cra_init(struct crypto_tfm *tfm)
-+{
-+ return atmel_sha_cra_init_alg(tfm, NULL);
-+}
-+
-+static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
-+{
-+ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
-+
-+ crypto_free_shash(tctx->fallback);
-+ tctx->fallback = NULL;
-+}
-+
-+static struct ahash_alg sha_algs[] = {
-+{
-+ .init = atmel_sha_init,
-+ .update = atmel_sha_update,
-+ .final = atmel_sha_final,
-+ .finup = atmel_sha_finup,
-+ .digest = atmel_sha_digest,
-+ .halg = {
-+ .digestsize = SHA1_DIGEST_SIZE,
-+ .base = {
-+ .cra_name = "sha1",
-+ .cra_driver_name = "atmel-sha1",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = SHA1_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
-+ .cra_alignmask = 0,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_sha_cra_init,
-+ .cra_exit = atmel_sha_cra_exit,
-+ }
-+ }
-+},
-+{
-+ .init = atmel_sha_init,
-+ .update = atmel_sha_update,
-+ .final = atmel_sha_final,
-+ .finup = atmel_sha_finup,
-+ .digest = atmel_sha_digest,
-+ .halg = {
-+ .digestsize = SHA256_DIGEST_SIZE,
-+ .base = {
-+ .cra_name = "sha256",
-+ .cra_driver_name = "atmel-sha256",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = SHA256_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
-+ .cra_alignmask = 0,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_sha_cra_init,
-+ .cra_exit = atmel_sha_cra_exit,
-+ }
-+ }
-+},
-+};
-+
-+static void atmel_sha_done_task(unsigned long data)
-+{
-+ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
-+ int err = 0;
-+
-+ if (!(SHA_FLAGS_BUSY & dd->flags)) {
-+ atmel_sha_handle_queue(dd, NULL);
-+ return;
-+ }
-+
-+ if (SHA_FLAGS_CPU & dd->flags) {
-+ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
-+ dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
-+ goto finish;
-+ }
-+ } else if (SHA_FLAGS_DMA_READY & dd->flags) {
-+ if (SHA_FLAGS_DMA_ACTIVE & dd->flags) {
-+ dd->flags &= ~SHA_FLAGS_DMA_ACTIVE;
-+ atmel_sha_update_dma_stop(dd);
-+ if (dd->err) {
-+ err = dd->err;
-+ goto finish;
-+ }
-+ }
-+ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
-+ /* hash or semi-hash ready */
-+ dd->flags &= ~(SHA_FLAGS_DMA_READY |
-+ SHA_FLAGS_OUTPUT_READY);
-+ err = atmel_sha_update_dma_start(dd);
-+ if (err != -EINPROGRESS)
-+ goto finish;
-+ }
-+ }
-+ return;
-+
-+finish:
-+ /* finish curent request */
-+ atmel_sha_finish_req(dd->req, err);
-+}
-+
-+static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
-+{
-+ struct atmel_sha_dev *sha_dd = dev_id;
-+ u32 reg;
-+
-+ reg = atmel_sha_read(sha_dd, SHA_ISR);
-+ if (reg & atmel_sha_read(sha_dd, SHA_IMR)) {
-+ atmel_sha_write(sha_dd, SHA_IDR, reg);
-+ if (SHA_FLAGS_BUSY & sha_dd->flags) {
-+ sha_dd->flags |= SHA_FLAGS_OUTPUT_READY;
-+ if (!(SHA_FLAGS_CPU & sha_dd->flags))
-+ sha_dd->flags |= SHA_FLAGS_DMA_READY;
-+ tasklet_schedule(&sha_dd->done_task);
-+ } else {
-+ dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n");
-+ }
-+ return IRQ_HANDLED;
-+ }
-+
-+ return IRQ_NONE;
-+}
-+
-+static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
-+{
-+ int i;
-+
-+ for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
-+ crypto_unregister_ahash(&sha_algs[i]);
-+}
-+
-+static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
-+{
-+ int err, i, j;
-+
-+ for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
-+ err = crypto_register_ahash(&sha_algs[i]);
-+ if (err)
-+ goto err_sha_algs;
-+ }
-+
-+ return 0;
-+
-+err_sha_algs:
-+ for (j = 0; j < i; j++)
-+ crypto_unregister_ahash(&sha_algs[j]);
-+
-+ return err;
-+}
-+
-+static int __devinit atmel_sha_probe(struct platform_device *pdev)
-+{
-+ struct atmel_sha_dev *sha_dd;
-+ struct device *dev = &pdev->dev;
-+ struct resource *sha_res;
-+ unsigned long sha_phys_size;
-+ int err;
-+
-+ sha_dd = kzalloc(sizeof(struct atmel_sha_dev), GFP_KERNEL);
-+ if (sha_dd == NULL) {
-+ dev_err(dev, "unable to alloc data struct.\n");
-+ err = -ENOMEM;
-+ goto sha_dd_err;
-+ }
-+
-+ sha_dd->dev = dev;
-+
-+ platform_set_drvdata(pdev, sha_dd);
-+
-+ INIT_LIST_HEAD(&sha_dd->list);
-+
-+ tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
-+ (unsigned long)sha_dd);
-+
-+ crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
-+
-+ sha_dd->irq = -1;
-+
-+ /* Get the base address */
-+ sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!sha_res) {
-+ dev_err(dev, "no MEM resource info\n");
-+ err = -ENODEV;
-+ goto res_err;
-+ }
-+ sha_dd->phys_base = sha_res->start;
-+ sha_phys_size = resource_size(sha_res);
-+
-+ /* Get the IRQ */
-+ sha_dd->irq = platform_get_irq(pdev, 0);
-+ if (sha_dd->irq < 0) {
-+ dev_err(dev, "no IRQ resource info\n");
-+ err = sha_dd->irq;
-+ goto res_err;
-+ }
-+
-+ err = request_irq(sha_dd->irq, atmel_sha_irq, IRQF_SHARED, "atmel-sha",
-+ sha_dd);
-+ if (err) {
-+ dev_err(dev, "unable to request sha irq.\n");
-+ goto res_err;
-+ }
-+
-+ /* Initializing the clock */
-+ sha_dd->iclk = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(sha_dd->iclk)) {
-+ dev_err(dev, "clock intialization failed.\n");
-+ err = PTR_ERR(sha_dd->iclk);
-+ goto clk_err;
-+ }
-+
-+ sha_dd->io_base = ioremap(sha_dd->phys_base, sha_phys_size);
-+ if (!sha_dd->io_base) {
-+ dev_err(dev, "can't ioremap\n");
-+ err = -ENOMEM;
-+ goto sha_io_err;
-+ }
-+
-+ spin_lock(&atmel_sha.lock);
-+ list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
-+ spin_unlock(&atmel_sha.lock);
-+
-+ err = atmel_sha_register_algs(sha_dd);
-+ if (err)
-+ goto err_algs;
-+
-+ dev_info(dev, "Atmel SHA1/SHA256\n");
-+
-+ return 0;
-+
-+err_algs:
-+ spin_lock(&atmel_sha.lock);
-+ list_del(&sha_dd->list);
-+ spin_unlock(&atmel_sha.lock);
-+ iounmap(sha_dd->io_base);
-+sha_io_err:
-+ clk_put(sha_dd->iclk);
-+clk_err:
-+ free_irq(sha_dd->irq, sha_dd);
-+res_err:
-+ tasklet_kill(&sha_dd->done_task);
-+ kfree(sha_dd);
-+ sha_dd = NULL;
-+sha_dd_err:
-+ dev_err(dev, "initialization failed.\n");
-+
-+ return err;
-+}
-+
-+static int __devexit atmel_sha_remove(struct platform_device *pdev)
-+{
-+ static struct atmel_sha_dev *sha_dd;
-+
-+ sha_dd = platform_get_drvdata(pdev);
-+ if (!sha_dd)
-+ return -ENODEV;
-+ spin_lock(&atmel_sha.lock);
-+ list_del(&sha_dd->list);
-+ spin_unlock(&atmel_sha.lock);
-+
-+ atmel_sha_unregister_algs(sha_dd);
-+
-+ tasklet_kill(&sha_dd->done_task);
-+
-+ iounmap(sha_dd->io_base);
-+
-+ clk_put(sha_dd->iclk);
-+
-+ if (sha_dd->irq >= 0)
-+ free_irq(sha_dd->irq, sha_dd);
-+
-+ kfree(sha_dd);
-+ sha_dd = NULL;
-+
-+ return 0;
-+}
-+
-+static struct platform_driver atmel_sha_driver = {
-+ .probe = atmel_sha_probe,
-+ .remove = __devexit_p(atmel_sha_remove),
-+ .driver = {
-+ .name = "atmel_sha",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+module_platform_driver(atmel_sha_driver);
-+
-+MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 864c6c3dcb6dbdd5ff29c3ddd2a43aa758b9d9ea Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Tue, 18 Sep 2012 18:32:38 +0200
+Subject: i2c: at91: backport fix for devm_clk_get
+
+i2c-at91 is backported from a 3.6, devm_clk_get is not yet implemented
+on 3.4.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ drivers/i2c/busses/i2c-at91.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 33219f8..296c430 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -747,7 +747,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, dev);
+
+- dev->clk = devm_clk_get(dev->dev, NULL);
++ dev->clk = clk_get(dev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(dev->dev, "no clock defined\n");
+ return -ENODEV;
+@@ -777,6 +777,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ dev_err(dev->dev, "Adapter %s registration failed\n",
+ dev->adapter.name);
+ clk_disable_unprepare(dev->clk);
++ clk_put(dev->clk);
+ return rc;
+ }
+
+@@ -793,6 +794,7 @@ static int __devexit at91_twi_remove(struct platform_device *pdev)
+
+ rc = i2c_del_adapter(&dev->adapter);
+ clk_disable_unprepare(dev->clk);
++ clk_put(dev->clk);
+
+ return rc;
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 84820a1650d935f04a4a1e4b95905c7bc7b47d71 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:07 +0200
-Subject: crypto: add atmel-test driver
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/Kconfig | 12 ++
- drivers/crypto/Makefile | 1 +
- drivers/crypto/atmel-test.c | 444 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 457 insertions(+)
- create mode 100644 drivers/crypto/atmel-test.c
-
-diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
-index 2339add..7a356fe 100644
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -343,4 +343,16 @@ config CRYPTO_DEV_ATMEL_SHA
- To compile this driver as a module, choose M here: the module
- will be called atmel-sha.
-
-+config CRYPTO_DEV_ATMEL_TEST
-+ tristate "TEST MODULE"
-+ depends on ARCH_AT91
-+ select CRYPTO_SHA1
-+ select CRYPTO_SHA256
-+ help
-+ Some Atmel processors have SHA1/SHA256/TDES/AES hw accelerator.
-+ Select this if you want to test SHA1/SHA256/TDES/AES drivers.
-+
-+ To compile this driver as a module, choose M here: the module
-+ will be called atmel-test.
-+
- endif # CRYPTO_HW
-diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
-index d355c25..bbe005b 100644
---- a/drivers/crypto/Makefile
-+++ b/drivers/crypto/Makefile
-@@ -17,3 +17,4 @@ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
- obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
-+obj-$(CONFIG_CRYPTO_DEV_ATMEL_TEST) += atmel-test.o
-diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
-new file mode 100644
-index 0000000..4a23db5
---- /dev/null
-+++ b/drivers/crypto/atmel-test.c
-@@ -0,0 +1,444 @@
-+/*
-+ * Cryptographic API.
-+ *
-+ * ATMEL SHA1/SHA256/TDES/AES HW acceleration test.
-+ *
-+ * Author: Nicolas Royer - Eukréa Electromatique
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as published
-+ * by the Free Software Foundation.
-+ *
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/crypto.h>
-+#include <linux/err.h>
-+#include <linux/scatterlist.h>
-+#include <linux/gfp.h>
-+#include <crypto/hash.h>
-+
-+static char *pattern64 =
-+ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
-+ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
-+ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
-+ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
-+ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
-+ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
-+ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
-+ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
-+
-+static char *key32 =
-+ "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
-+ "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
-+ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
-+ "\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
-+
-+static char *iv16 =
-+ "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
-+ "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58";
-+
-+#define SHA1_MSG_LEN 20
-+#define SHA256_MSG_LEN 32
-+static char sha_out_buf[SHA256_MSG_LEN];
-+
-+#define TVMEMSIZE 4
-+static char *tvmem[TVMEMSIZE];
-+
-+
-+static void hexdump(unsigned char *buf, unsigned int len)
-+{
-+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
-+ 16, 1,
-+ buf, len, false);
-+}
-+
-+struct hmac_sha_result {
-+ struct completion completion;
-+ int err;
-+};
-+
-+static void hmac_sha_complete(struct crypto_async_request *req, int err)
-+{
-+ struct hmac_sha_result *r = req->data;
-+ if (err == -EINPROGRESS)
-+ return;
-+ r->err = err;
-+ complete(&r->completion);
-+}
-+
-+static inline int do_one_ahash_op(struct ahash_request *req, int ret)
-+{
-+ if (ret == -EINPROGRESS || ret == -EBUSY) {
-+ struct hmac_sha_result *tr = req->base.data;
-+
-+ ret = wait_for_completion_interruptible(&tr->completion);
-+ if (!ret)
-+ ret = tr->err;
-+ INIT_COMPLETION(tr->completion);
-+ }
-+ return ret;
-+}
-+
-+static int hmac_sha_update(const char *algo, char *data_in, size_t dlen,
-+ char *hash_out, size_t outlen)
-+{
-+ int rc = 0;
-+ struct crypto_ahash *tfm;
-+ struct scatterlist sg[TVMEMSIZE];
-+ struct ahash_request *req;
-+ struct hmac_sha_result tresult;
-+ int i, j;
-+
-+ /* Set hash output to 0 initially */
-+ memset(hash_out, 0, outlen);
-+
-+ init_completion(&tresult.completion);
-+ tfm = crypto_alloc_ahash(algo, 0, 0);
-+ if (IS_ERR(tfm)) {
-+ printk(KERN_ERR "crypto_alloc_ahash failed\n");
-+ rc = PTR_ERR(tfm);
-+ goto err_tfm;
-+ }
-+ req = ahash_request_alloc(tfm, GFP_KERNEL);
-+ if (!req) {
-+ printk(KERN_ERR "failed to allocate request\n");
-+ rc = -ENOMEM;
-+ goto err_req;
-+ }
-+ if (crypto_ahash_digestsize(tfm) > outlen) {
-+ printk(KERN_ERR "tfm size > result buffer\n");
-+ rc = -EINVAL;
-+ goto err_req;
-+ }
-+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-+ hmac_sha_complete, &tresult);
-+
-+ sg_init_table(sg, TVMEMSIZE);
-+
-+ i = 0;
-+ j = dlen;
-+
-+ while (j > PAGE_SIZE) {
-+ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
-+ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
-+ i++;
-+ j -= PAGE_SIZE;
-+ }
-+ sg_set_buf(sg + i, tvmem[i], j);
-+ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
-+
-+ crypto_ahash_clear_flags(tfm, -0);
-+ ahash_request_set_crypt(req, sg, hash_out, dlen);
-+ rc = crypto_ahash_init(req);
-+ rc = do_one_ahash_op(req, crypto_ahash_update(req));
-+ if (rc)
-+ goto out;
-+
-+ rc = do_one_ahash_op(req, crypto_ahash_final(req));
-+
-+out:
-+ ahash_request_free(req);
-+err_req:
-+ crypto_free_ahash(tfm);
-+err_tfm:
-+ return rc;
-+}
-+
-+static int hmac_sha_digest(const char *algo, char *data_in, size_t dlen,
-+ char *hash_out, size_t outlen)
-+{
-+ int rc = 0;
-+ struct crypto_ahash *tfm;
-+ struct scatterlist sg;
-+ struct ahash_request *req;
-+ struct hmac_sha_result tresult;
-+
-+ /* Set hash output to 0 initially */
-+ memset(hash_out, 0, outlen);
-+
-+ init_completion(&tresult.completion);
-+ tfm = crypto_alloc_ahash(algo, 0, 0);
-+ if (IS_ERR(tfm)) {
-+ printk(KERN_ERR "crypto_alloc_ahash failed\n");
-+ rc = PTR_ERR(tfm);
-+ goto err_tfm;
-+ }
-+ req = ahash_request_alloc(tfm, GFP_KERNEL);
-+ if (!req) {
-+ printk(KERN_ERR "failed to allocate request\n");
-+ rc = -ENOMEM;
-+ goto err_req;
-+ }
-+ if (crypto_ahash_digestsize(tfm) > outlen) {
-+ printk(KERN_ERR "tfm size > result buffer\n");
-+ rc = -EINVAL;
-+ goto err_req;
-+ }
-+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-+ hmac_sha_complete, &tresult);
-+
-+ sg_init_one(&sg, data_in, dlen);
-+
-+ crypto_ahash_clear_flags(tfm, -0);
-+ ahash_request_set_crypt(req, &sg, hash_out, dlen);
-+ rc = do_one_ahash_op(req, crypto_ahash_digest(req));
-+
-+ ahash_request_free(req);
-+err_req:
-+ crypto_free_ahash(tfm);
-+err_tfm:
-+ return rc;
-+}
-+
-+struct tcrypt_result {
-+ struct completion completion;
-+ int err;
-+};
-+
-+static void tcrypt_complete(struct crypto_async_request *req, int err)
-+{
-+ struct tcrypt_result *res = req->data;
-+
-+ if (err == -EINPROGRESS)
-+ return;
-+
-+ res->err = err;
-+ complete(&res->completion);
-+}
-+
-+static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret)
-+{
-+ if (ret == -EINPROGRESS || ret == -EBUSY) {
-+ struct tcrypt_result *tr = req->base.data;
-+
-+ ret = wait_for_completion_interruptible(&tr->completion);
-+ if (!ret)
-+ ret = tr->err;
-+ INIT_COMPLETION(tr->completion);
-+ }
-+ return ret;
-+}
-+
-+static int test_acipher(const char *algo, int enc, char *data_in,
-+ char *data_out, size_t data_len, char *key, int keysize)
-+ {
-+ struct crypto_ablkcipher *tfm;
-+ struct tcrypt_result tresult;
-+ struct ablkcipher_request *req;
-+ struct scatterlist sg[TVMEMSIZE];
-+ unsigned int ret, i, j, iv_len;
-+ char iv[128];
-+
-+ ret = -EAGAIN;
-+
-+ init_completion(&tresult.completion);
-+
-+ tfm = crypto_alloc_ablkcipher(algo, 0, 0);
-+ if (IS_ERR(tfm)) {
-+ printk(KERN_ERR "failed to load transform for %s: %ld\n",
-+ algo, PTR_ERR(tfm));
-+ return ret;
-+ }
-+
-+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
-+ if (!req) {
-+ printk(KERN_ERR "tcrypt: skcipher: Failed to allocate request for %s\n",
-+ algo);
-+ goto out;
-+ }
-+
-+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
-+ tcrypt_complete, &tresult);
-+
-+ crypto_ablkcipher_clear_flags(tfm, ~0);
-+
-+ ret = crypto_ablkcipher_setkey(tfm, key, keysize);
-+ if (ret) {
-+ printk(KERN_ERR "setkey() failed flags=%x\n",
-+ crypto_ablkcipher_get_flags(tfm));
-+ goto out_free_req;
-+ }
-+
-+ printk(KERN_INFO "KEY:\n");
-+ hexdump(key, keysize);
-+
-+ sg_init_table(sg, TVMEMSIZE);
-+
-+ i = 0;
-+ j = data_len;
-+
-+ while (j > PAGE_SIZE) {
-+ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
-+ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
-+ i++;
-+ j -= PAGE_SIZE;
-+ }
-+ sg_set_buf(sg + i, tvmem[i], j);
-+ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
-+
-+ iv_len = crypto_ablkcipher_ivsize(tfm);
-+ memcpy(iv, iv16, iv_len);
-+
-+ printk(KERN_INFO "IV:\n");
-+ hexdump(iv, iv_len);
-+
-+ ablkcipher_request_set_crypt(req, sg, sg, data_len, iv);
-+
-+ printk(KERN_INFO "IN:\n");
-+ hexdump(data_in, data_len);
-+
-+ if (enc)
-+ ret = do_one_acipher_op(req, crypto_ablkcipher_encrypt(req));
-+ else
-+ ret = do_one_acipher_op(req, crypto_ablkcipher_decrypt(req));
-+
-+ if (ret)
-+ printk(KERN_ERR "failed flags=%x\n",
-+ crypto_ablkcipher_get_flags(tfm));
-+ else {
-+ i = 0;
-+ j = data_len;
-+ while (j > PAGE_SIZE) {
-+ memcpy(data_out + i * PAGE_SIZE, tvmem[i], PAGE_SIZE);
-+ i++;
-+ j -= PAGE_SIZE;
-+ }
-+ memcpy(data_out + i * PAGE_SIZE, tvmem[i], j);
-+
-+ printk(KERN_INFO "OUT:\n");
-+ hexdump(data_out, data_len);
-+ }
-+
-+out_free_req:
-+ ablkcipher_request_free(req);
-+out:
-+ crypto_free_ablkcipher(tfm);
-+
-+ return ret;
-+}
-+
-+static int mode = 10;
-+module_param_named(mode, mode, int,
-+ S_IRUGO | S_IWUSR | S_IWGRP);
-+
-+static int keylen = 8;
-+module_param_named(keylen, keylen, int,
-+ S_IRUGO | S_IWUSR | S_IWGRP);
-+
-+static int dlen = 64;
-+module_param_named(dlen, dlen, int,
-+ S_IRUGO | S_IWUSR | S_IWGRP);
-+
-+char *ahash_algs[] = {"sha1", "sha256"};
-+
-+char *acipher_algs[] = {
-+ "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
-+ "cfb16(des)", "cfb8(des)", "ofb(des)", "ecb(des3_ede)",
-+ "cbc(des3_ede)", "cfb(des3_ede)", "cfb32(des3_ede)", "cfb16(des3_ede)",
-+ "cfb8(des3_ede)", "ofb(des3_ede)", "ecb(aes)", "cbc(aes)",
-+ "ofb(aes)", "cfb(aes)", "cfb64(aes)", "cfb32(aes)",
-+ "cfb16(aes)", "cfb8(aes)", "ctr(aes)"};
-+
-+static int __init init_main(void)
-+{
-+ unsigned int i;
-+ char *buf_in;
-+ char *buf_out;
-+ char *buf_res;
-+
-+ if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
-+ printk(KERN_ERR " 0 < dlen <= %i\n",
-+ (int) (TVMEMSIZE*PAGE_SIZE));
-+ return -EAGAIN;
-+ }
-+
-+ for (i = 0; i < TVMEMSIZE; i++) {
-+ tvmem[i] = (void *)__get_free_page(GFP_KERNEL);
-+ if (!tvmem[i])
-+ goto err_free_tv;
-+ }
-+
-+ buf_in = kzalloc(dlen, GFP_KERNEL);
-+ if (!buf_in)
-+ goto err_buf_in_alloc;
-+ buf_out = kzalloc(dlen, GFP_KERNEL);
-+ if (!buf_out)
-+ goto err_buf_out_alloc;
-+ buf_res = kzalloc(dlen, GFP_KERNEL);
-+ if (!buf_res)
-+ goto err_buf_res_alloc;
-+
-+ if (dlen > 64) {
-+ memcpy(buf_in, pattern64, 64);
-+ memset(buf_in+64, 0xFF, dlen-64);
-+ } else
-+ memcpy(buf_in, pattern64, dlen);
-+
-+ if (mode < 10) {
-+ if (mode >= ARRAY_SIZE(ahash_algs)) {
-+ printk(KERN_ERR "mode must be < %d or > 10\n",
-+ ARRAY_SIZE(ahash_algs));
-+ goto exit;
-+ }
-+ printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
-+ hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
-+ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+
-+ printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
-+ hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
-+ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+ } else {
-+ mode -= 10;
-+
-+ if (mode >= ARRAY_SIZE(acipher_algs)) {
-+ printk(KERN_ERR "mode must be < %d\n",
-+ ARRAY_SIZE(acipher_algs) + 10);
-+ goto exit;
-+ }
-+
-+ printk(KERN_INFO "\n%s encrypt\n", acipher_algs[mode]);
-+ if (test_acipher(acipher_algs[mode], 1, buf_in, buf_out,
-+ dlen, key32, keylen))
-+ goto exit;
-+
-+ printk(KERN_INFO "\n%s decrypt\n", acipher_algs[mode]);
-+ if (test_acipher(acipher_algs[mode], 0, buf_out, buf_res,
-+ dlen, key32, keylen))
-+ goto exit;
-+
-+ if (memcmp(buf_in, buf_res, dlen))
-+ printk(KERN_INFO "\n%s test failed\n\n",
-+ acipher_algs[mode]);
-+ else
-+ printk(KERN_INFO "\n%s test OK\n\n",
-+ acipher_algs[mode]);
-+ }
-+
-+exit:
-+ kfree(buf_res);
-+err_buf_res_alloc:
-+ kfree(buf_out);
-+err_buf_out_alloc:
-+ kfree(buf_in);
-+err_buf_in_alloc:
-+err_free_tv:
-+ for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
-+ free_page((unsigned long)tvmem[i]);
-+
-+ return -EAGAIN;
-+}
-+
-+static void __exit cleanup_main(void)
-+{
-+}
-+
-+module_init(init_main);
-+module_exit(cleanup_main);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
-+MODULE_DESCRIPTION("Atmel HW crypto test");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 2fcde4a50eec3c26971c7c2095f56b6d9f21b1c7 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:00:47 +0200
+Subject: i2c: at91: add dt property for DMA configuration
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9x5.dtsi
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 5 ++++
+ drivers/i2c/busses/i2c-at91.c | 56 ++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 60 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index fec3316..79718e7 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -103,12 +103,14 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4 0>;
++ #dma-cells = <1>;
+ };
+
+ dma1: dma-controller@ffffee00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffee00 0x200>;
+ interrupts = <21 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff400 {
+@@ -221,6 +223,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8010000 0x100>;
+ interrupts = <9 4 6>;
++ dma = <&dma0 0x10002278>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+@@ -230,6 +233,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8014000 0x100>;
+ interrupts = <10 4 6>;
++ dma = <&dma1 0x10002256>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+@@ -239,6 +243,7 @@
+ compatible = "atmel,at91sam9x5-i2c";
+ reg = <0xf8018000 0x100>;
+ interrupts = <11 4 6>;
++ dma = <&dma0 0x1000229A>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
+index 296c430..c004b34 100644
+--- a/drivers/i2c/busses/i2c-at91.c
++++ b/drivers/i2c/busses/i2c-at91.c
+@@ -589,6 +589,55 @@ static const struct platform_device_id at91_twi_devtypes[] = {
+ };
+
+ #if defined(CONFIG_OF)
++static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n", np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
+ static const struct of_device_id atmel_twi_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9260-i2c",
+@@ -608,6 +657,10 @@ static const struct of_device_id atmel_twi_dt_ids[] = {
+ };
+ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
+ #else
++static int at91_twi_of_init(struct device_node *np, struct at_dma_slave *atslave)
++{
++ return -ENODEV;
++}
+ #define atmel_twi_dt_ids NULL
+ #endif
+
+@@ -755,7 +808,8 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
+ clk_prepare_enable(dev->clk);
+
+ if (dev->pdata->has_dma_support) {
+- if (at91_twi_configure_dma(dev, phy_addr) == 0)
++ if ( at91_twi_of_init(pdev->dev.of_node, &dev->pdata->dma_slave) == 0
++ && at91_twi_configure_dma(dev, phy_addr) == 0)
+ dev->use_dma = true;
+ }
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From a68cb9084fc130e4137f2050cee1de250f038899 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 12:12:27 +0200
+Subject: ARM: at91: add MCI DMA for at91sam9x5.dtsi
+
+Temporary cfg hack
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 79718e7..88907db 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -208,6 +208,7 @@
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
++ dma = <&dma0 0x10002200>;
+ };
+
+ mmc1: mmc@f000c000 {
+@@ -217,6 +218,7 @@
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
++ dma = <&dma1 0x10002200>;
+ };
+
+ i2c0: i2c@f8010000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 50f0d2ac8726776a89f503e21cbfa3a070d2c87a Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:08 +0200
-Subject: crypto: add new tests to tcrypt
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-- set sg buffers size equals to message size
-- add cfb & ofb tests for AES, DES & TDES
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- crypto/tcrypt.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
- 1 file changed, 45 insertions(+), 5 deletions(-)
-
-diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
-index 8f147bf..a9296bd 100644
---- a/crypto/tcrypt.c
-+++ b/crypto/tcrypt.c
-@@ -809,7 +809,7 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
- struct cipher_speed_template *template,
- unsigned int tcount, u8 *keysize)
- {
-- unsigned int ret, i, j, iv_len;
-+ unsigned int ret, i, j, k, iv_len;
- struct tcrypt_result tresult;
- const char *key;
- char iv[128];
-@@ -883,11 +883,23 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
- }
-
- sg_init_table(sg, TVMEMSIZE);
-- sg_set_buf(sg, tvmem[0] + *keysize,
-+
-+ k = *keysize + *b_size;
-+ if (k > PAGE_SIZE) {
-+ sg_set_buf(sg, tvmem[0] + *keysize,
- PAGE_SIZE - *keysize);
-- for (j = 1; j < TVMEMSIZE; j++) {
-- sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
-- memset(tvmem[j], 0xff, PAGE_SIZE);
-+ k -= PAGE_SIZE;
-+ j = 1;
-+ while (k > PAGE_SIZE) {
-+ sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
-+ memset(tvmem[j], 0xff, PAGE_SIZE);
-+ j++;
-+ k -= PAGE_SIZE;
-+ }
-+ sg_set_buf(sg + j, tvmem[j], k);
-+ memset(tvmem[j], 0xff, k);
-+ } else {
-+ sg_set_buf(sg, tvmem[0] + *keysize, *b_size);
- }
-
- iv_len = crypto_ablkcipher_ivsize(tfm);
-@@ -1512,6 +1524,14 @@ static int do_test(int m)
- speed_template_16_24_32);
- test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
- speed_template_16_24_32);
-+ test_acipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0,
-+ speed_template_16_24_32);
-+ test_acipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0,
-+ speed_template_16_24_32);
-+ test_acipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0,
-+ speed_template_16_24_32);
-+ test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0,
-+ speed_template_16_24_32);
- break;
-
- case 501:
-@@ -1527,6 +1547,18 @@ static int do_test(int m)
- test_acipher_speed("cbc(des3_ede)", DECRYPT, sec,
- des3_speed_template, DES3_SPEED_VECTORS,
- speed_template_24);
-+ test_acipher_speed("cfb(des3_ede)", ENCRYPT, sec,
-+ des3_speed_template, DES3_SPEED_VECTORS,
-+ speed_template_24);
-+ test_acipher_speed("cfb(des3_ede)", DECRYPT, sec,
-+ des3_speed_template, DES3_SPEED_VECTORS,
-+ speed_template_24);
-+ test_acipher_speed("ofb(des3_ede)", ENCRYPT, sec,
-+ des3_speed_template, DES3_SPEED_VECTORS,
-+ speed_template_24);
-+ test_acipher_speed("ofb(des3_ede)", DECRYPT, sec,
-+ des3_speed_template, DES3_SPEED_VECTORS,
-+ speed_template_24);
- break;
-
- case 502:
-@@ -1538,6 +1570,14 @@ static int do_test(int m)
- speed_template_8);
- test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0,
- speed_template_8);
-+ test_acipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0,
-+ speed_template_8);
-+ test_acipher_speed("cfb(des)", DECRYPT, sec, NULL, 0,
-+ speed_template_8);
-+ test_acipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0,
-+ speed_template_8);
-+ test_acipher_speed("ofb(des)", DECRYPT, sec, NULL, 0,
-+ speed_template_8);
- break;
-
- case 503:
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 68814f3931e1e284d2f8270218f83333765b8c00 Mon Sep 17 00:00:00 2001
+From: Ludovic Desroches <ludovic.desroches@atmel.com>
+Date: Wed, 19 Sep 2012 09:27:02 +0200
+Subject: ARM: at91: add i2c and qt1070 pin muxing
+
+Pin mux is temporary done in board-dt file.
+
+Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index e8f45c4..9355d77 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -43,6 +43,14 @@ static void __init at91_dt_init_irq(void)
+ static void __init at91_dt_device_init(void)
+ {
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
++ /* Temporary pin mux stuff */
++ if (of_machine_is_compatible("atmel,at91sam9x5")) {
++ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
++ at91_set_A_periph(AT91_PIN_PA31, 0); /* TWCK */
++ printk("AT91: i2c pin mux done\n");
++ at91_set_gpio_input(AT91_PIN_PA7, 1);
++ printk("AT91: qt1070 pin mux done\n");
++ }
+ }
+
+ static const char *at91_dt_board_compat[] __initdata = {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 308c14408fc521e386e512fb6d8dfafce1b59dd9 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:09 +0200
-Subject: AT91SAM9G45: crypto: same platform data header for all crypto
- peripherals
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- arch/arm/mach-at91/at91sam9g45_devices.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
-index 3d523f0..896088d 100644
---- a/arch/arm/mach-at91/at91sam9g45_devices.c
-+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
-@@ -31,7 +31,7 @@
- #include <mach/at91sam9_smc.h>
- #include <mach/at_hdmac.h>
- #include <mach/atmel-mci.h>
--#include <linux/platform_data/atmel-aes.h>
-+#include <linux/platform_data/atmel-crypto.h>
- #include <media/atmel-isi.h>
-
- #include "generic.h"
-@@ -584,7 +584,7 @@ static void __init at91_add_device_tdes(void) {}
- * -------------------------------------------------------------------- */
-
- #if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
--static struct aes_platform_data aes_data;
-+static struct crypto_platform_data aes_data;
- static u64 aes_dmamask = DMA_BIT_MASK(32);
-
- static struct resource aes_resources[] = {
-@@ -615,9 +615,9 @@ static struct platform_device at91sam9g45_aes_device = {
- static void __init at91_add_device_aes(void)
- {
- struct at_dma_slave *atslave;
-- struct aes_dma_data *alt_atslave;
-+ struct crypto_dma_data *alt_atslave;
-
-- alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
-+ alt_atslave = kzalloc(sizeof(struct crypto_dma_data), GFP_KERNEL);
-
- /* DMA TX slave channel configuration */
- atslave = &alt_atslave->txdata;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 3d6072e790e82ecbfbb3dfc84e22ba325db16f92 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 24 Sep 2012 12:27:10 +0200
+Subject: AT91: board-dt add mci pinmux for 9x5
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index 9355d77..15830cb 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -50,6 +50,30 @@ static void __init at91_dt_device_init(void)
+ printk("AT91: i2c pin mux done\n");
+ at91_set_gpio_input(AT91_PIN_PA7, 1);
+ printk("AT91: qt1070 pin mux done\n");
++
++ at91_set_gpio_input(AT91_PIN_PD14, 1);
++ at91_set_deglitch(AT91_PIN_PD14, 1);
++ at91_set_gpio_input(AT91_PIN_PD15, 1);
++ at91_set_deglitch(AT91_PIN_PD15, 1);
++ /* CLK */
++ at91_set_A_periph(AT91_PIN_PA17, 0);
++ /* CMD */
++ at91_set_A_periph(AT91_PIN_PA16, 1);
++ /* DAT0, DAT1..DAT3 */
++ at91_set_A_periph(AT91_PIN_PA15, 1);
++ at91_set_A_periph(AT91_PIN_PA18, 1);
++ at91_set_A_periph(AT91_PIN_PA19, 1);
++ at91_set_A_periph(AT91_PIN_PA20, 1);
++ /* CLK */
++ at91_set_B_periph(AT91_PIN_PA13, 0);
++ /* CMD */
++ at91_set_B_periph(AT91_PIN_PA12, 1);
++ /* DAT0, DAT1..DAT3 */
++ at91_set_B_periph(AT91_PIN_PA11, 1);
++ at91_set_B_periph(AT91_PIN_PA2, 1);
++ at91_set_B_periph(AT91_PIN_PA3, 1);
++ at91_set_B_periph(AT91_PIN_PA4, 1);
++ printk("AT91: mci0/1 pin mux done\n");
+ }
+ }
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 5a8755b4c17d6199200486a431020afb42ad9122 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 16:05:01 +0200
-Subject: AT91SAM9G45: dts: add crypto peripherals
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9g45.dtsi
----
- arch/arm/boot/dts/at91sam9g45.dtsi | 25 +++++++++++++++++++++++++
- 1 file changed, 25 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index b032a8c..948dc96 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -106,6 +106,7 @@
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
- interrupts = <21 4 0>;
-+ #dma-cells = <1>;
- };
-
- pioA: gpio@fffff200 {
-@@ -243,6 +244,30 @@
- #size-cells = <0>;
- status = "disabled";
- };
-+
-+ aes@fffc0000 {
-+ compatible = "atmel,sam9g46-aes";
-+ reg = <0xfffc0000 0x100>;
-+ interrupts = <28 4 0>;
-+ dma = <&dma 0x2000020c /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20006020
-+ | ATC_DST_H2SEL_HW
-+ | ATC_DST_PER(AT_DMA_ID_AES_TX); */
-+ &dma 0x200020b0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20000603
-+ | ATC_SRC_H2SEL_HW
-+ | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
-+ >;
-+ dma-name = "tx", "rx";
-+ };
-+ tdes@0xfffc4000 {
-+ compatible = "atmel,sam9g46-tdes";
-+ reg = <0xfffc4000 0x130>;
-+ interrupts = <28 4 0>;
-+ };
-+ sha@0xfffc8000 {
-+ compatible = "atmel,sam9g46-sha";
-+ reg = <0xfffc8000 0x130>;
-+ interrupts = <28 4 0>;
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From c3c525946e9afc0597632c3f0cee06be156ad9f8 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:13 +0200
-Subject: AT91SAM9N12: add crypto peripherals
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- arch/arm/mach-at91/at91sam9n12.c | 17 +++++++++++++++++
- arch/arm/mach-at91/include/mach/at91sam9n12.h | 2 ++
- 2 files changed, 19 insertions(+)
-
-diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
-index ebe94bb..d09baf1 100644
---- a/arch/arm/mach-at91/at91sam9n12.c
-+++ b/arch/arm/mach-at91/at91sam9n12.c
-@@ -17,6 +17,7 @@
- #include <mach/cpu.h>
- #include <mach/board.h>
-
-+
- #include "soc.h"
- #include "generic.h"
- #include "clock.h"
-@@ -134,6 +135,17 @@ static struct clk ssc_clk = {
- .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
- .type = CLK_TYPE_PERIPHERAL,
- };
-+static struct clk aes_clk = {
-+ .name = "aes_clk",
-+ .pmc_mask = 1 << AT91SAM9N12_ID_AES,
-+ .type = CLK_TYPE_PERIPHERAL,
-+};
-+static struct clk sha_clk = {
-+ .name = "sha_clk",
-+ .pmc_mask = 1 << AT91SAM9N12_ID_SHA,
-+ .type = CLK_TYPE_PERIPHERAL,
-+};
-+
-
- static struct clk *periph_clocks[] __initdata = {
- &pioAB_clk,
-@@ -157,6 +169,8 @@ static struct clk *periph_clocks[] __initdata = {
- &uhp_clk,
- &udp_clk,
- &ssc_clk,
-+ &aes_clk,
-+ &sha_clk,
- };
-
- static struct clk_lookup periph_clocks_lookups[] = {
-@@ -176,6 +190,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
- CLKDEV_CON_ID("pioD", &pioCD_clk),
-+ CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
-+ CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
- /* additional fake clock for macb_hclk */
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
- CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
-@@ -219,6 +235,7 @@ static void __init at91sam9n12_register_clocks(void)
- static void __init at91sam9n12_map_io(void)
- {
- at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
-+ init_consistent_dma_size(SZ_4M);
- }
-
- void __init at91sam9n12_initialize(void)
-diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
-index d374b87..e07b0de 100644
---- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
-+++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
-@@ -36,7 +36,9 @@
- #define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
- #define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
- #define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
-+#define AT91SAM9N12_ID_SHA 27 /* SHA */
- #define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
-+#define AT91SAM9N12_ID_AES 29 /* AES */
- #define AT91SAM9N12_ID_TRNG 30 /* TRNG */
- #define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 1a4758d4c8790c591d2be79382e878526f6dfcb6 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 24 Sep 2012 14:50:45 +0800
+Subject: mtd: atmel_nand: add 4k page nand flash support for PMECC.
+
+---
+ drivers/mtd/nand/atmel_nand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index a92f603..e881c15 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -952,6 +952,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ /* set ECC page size and oob layout */
+ switch (mtd->writesize) {
+ case 2048:
++ case 4096:
+ host->pmecc_degree = PMECC_GF_DIMENSION_13;
+ host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
+ host->pmecc_sector_number = mtd->writesize / sector_size;
+@@ -977,7 +978,6 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+ break;
+ case 512:
+ case 1024:
+- case 4096:
+ /* TODO */
+ dev_warn(host->dev,
+ "Unsupported page size for PMECC, use Software ECC\n");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 212c6c62a492e7c01b036db250ad522e86303163 Mon Sep 17 00:00:00 2001
-From: Nicolas Ferre <nicolas.ferre@atmel.com>
-Date: Mon, 22 Oct 2012 16:05:17 +0200
-Subject: AT91SAM9N12: dts: add crypto peripherals
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
-
-Conflicts:
- arch/arm/boot/dts/at91sam9n12.dtsi
----
- arch/arm/boot/dts/at91sam9n12.dtsi | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index 0d08c4e..42b53bd 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -109,6 +109,7 @@
- compatible = "atmel,at91sam9g45-dma";
- reg = <0xffffec00 0x200>;
- interrupts = <20 4 0>;
-+ #dma-cells = <1>;
- };
-
- pioA: gpio@fffff400 {
-@@ -211,6 +212,29 @@
- #size-cells = <0>;
- status = "disabled";
- };
-+
-+ aes@f000c000 {
-+ compatible = "atmel,sam9g46-aes";
-+ reg = <0xf000c000 0x100>;
-+ interrupts = <29 4 0>;
-+ dma = <&dma 0x2000060B /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE */
-+ /* | ATC_DST_H2SEL_HW */
-+ /* | ATC_DST_PER(AT_DMA_ID_AES_TX); */
-+ &dma 0x200060A0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
-+ /* | ATC_SRC_H2SEL_HW */
-+ /* | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
-+ >;
-+ dma-name = "tx", "rx";
-+ };
-+
-+ sha@f0014000 {
-+ compatible = "atmel,sam9g46-sha";
-+ reg = <0xf0014000 0x100>;
-+ interrupts = <27 4 0>;
-+ dma = <&dma 0x200060C0>; /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
-+ /* | ATC_SRC_H2SEL_HW */
-+ /* | ATC_SRC_PER(AT_DMA_ID_SHA_RX); */
-+ };
- };
-
- nand0: nand@40000000 {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 56a1ff8d7f47a95326ee0eb59209031d3b4a98c9 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Mon, 24 Sep 2012 14:58:38 +0800
+Subject: mtd: atmel_nand: incease the chip_delay time(tR) for support big
+ flash chips such like MT29F8G08ABABA.
+
+---
+ drivers/mtd/nand/atmel_nand.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
+index e881c15..3978336 100644
+--- a/drivers/mtd/nand/atmel_nand.c
++++ b/drivers/mtd/nand/atmel_nand.c
+@@ -1448,7 +1448,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
+ }
+
+ nand_chip->ecc.mode = host->board.ecc_mode;
+- nand_chip->chip_delay = 20; /* 20us command delay time */
++
++ /* For support 4k-page flash, incease the delay time to 25us.
++ * In P.108 of MT29F8G08ABABA datasheet, tR max is 25us.
++ */
++ nand_chip->chip_delay = 25;
+
+ if (host->board.bus_width_16) /* 16-bit bus width */
+ nand_chip->options |= NAND_BUSWIDTH_16;
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From ab8f5cfc534946bd9627feee2a4b10398a1ca789 Mon Sep 17 00:00:00 2001
+From: Josh Wu <josh.wu@atmel.com>
+Date: Tue, 25 Sep 2012 10:40:22 +0800
+Subject: at91: 9x5: add DT parameters to enable PMECC
+
+Signed-off-by: Josh Wu <josh.wu@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x5.dtsi | 4 ++++
+ arch/arm/boot/dts/at91sam9x5cm.dtsi | 5 ++++-
+ 2 files changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 88907db..2cefd49 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -257,7 +257,11 @@
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000
++ 0xffffe000 0x600 /* PMECC Registers */
++ 0xffffe600 0x200 /* PMECC Error Location Registers */
++ 0x00100000 0x100000 /* ROM code */
+ >;
++ atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ gpios = <&pioD 5 0
+diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+index 31e7be2..4027ac7 100644
+--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
+@@ -26,7 +26,10 @@
+ ahb {
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+- nand-ecc-mode = "soft";
++ nand-ecc-mode = "hw";
++ atmel,has-pmecc; /* Enable PMECC */
++ atmel,pmecc-cap = <2>;
++ atmel,pmecc-sector-size = <512>;
+ nand-on-flash-bbt;
+ status = "okay";
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 6dcba1a5e5b0cda9490f78b46b282ec3ec39f22c Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:15 +0200
-Subject: crypto: Atmel AES; add device tree support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/atmel-aes.c | 626 +++++++++++++++++++++++------
- include/linux/platform_data/atmel-aes.h | 22 -
- include/linux/platform_data/atmel-crypto.h | 22 +
- 3 files changed, 524 insertions(+), 146 deletions(-)
- delete mode 100644 include/linux/platform_data/atmel-aes.h
- create mode 100644 include/linux/platform_data/atmel-crypto.h
-
-diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
-index 6bb20ff..035b87a 100644
---- a/drivers/crypto/atmel-aes.c
-+++ b/drivers/crypto/atmel-aes.c
-@@ -43,16 +43,19 @@
- #include <crypto/aes.h>
- #include <crypto/hash.h>
- #include <crypto/internal/hash.h>
--#include <linux/platform_data/atmel-aes.h>
-+#include <linux/platform_data/atmel-crypto.h>
- #include "atmel-aes-regs.h"
-
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+
- #define CFB8_BLOCK_SIZE 1
- #define CFB16_BLOCK_SIZE 2
- #define CFB32_BLOCK_SIZE 4
- #define CFB64_BLOCK_SIZE 8
-
- /* AES flags */
--#define AES_FLAGS_MODE_MASK 0x01ff
-+#define AES_FLAGS_MODE_MASK 0x03ff
- #define AES_FLAGS_ENCRYPT BIT(0)
- #define AES_FLAGS_CBC BIT(1)
- #define AES_FLAGS_CFB BIT(2)
-@@ -60,21 +63,26 @@
- #define AES_FLAGS_CFB16 BIT(4)
- #define AES_FLAGS_CFB32 BIT(5)
- #define AES_FLAGS_CFB64 BIT(6)
--#define AES_FLAGS_OFB BIT(7)
--#define AES_FLAGS_CTR BIT(8)
-+#define AES_FLAGS_CFB128 BIT(7)
-+#define AES_FLAGS_OFB BIT(8)
-+#define AES_FLAGS_CTR BIT(9)
-
- #define AES_FLAGS_INIT BIT(16)
- #define AES_FLAGS_DMA BIT(17)
- #define AES_FLAGS_BUSY BIT(18)
-+#define AES_FLAGS_FAST BIT(19)
-
--#define AES_FLAGS_DUALBUFF BIT(24)
--
--#define ATMEL_AES_QUEUE_LENGTH 1
--#define ATMEL_AES_CACHE_SIZE 0
-+#define ATMEL_AES_QUEUE_LENGTH 50
-
- #define ATMEL_AES_DMA_THRESHOLD 16
-
-
-+struct atmel_aes_caps {
-+ bool has_dualbuff;
-+ bool has_cfb64;
-+ u32 max_burst_size;
-+};
-+
- struct atmel_aes_dev;
-
- struct atmel_aes_ctx {
-@@ -82,6 +90,8 @@ struct atmel_aes_ctx {
-
- int keylen;
- u32 key[AES_KEYSIZE_256 / sizeof(u32)];
-+
-+ u16 block_size;
- };
-
- struct atmel_aes_reqctx {
-@@ -117,20 +127,27 @@ struct atmel_aes_dev {
-
- struct scatterlist *in_sg;
- unsigned int nb_in_sg;
--
-+ size_t in_offset;
- struct scatterlist *out_sg;
- unsigned int nb_out_sg;
-+ size_t out_offset;
-
- size_t bufcnt;
-+ size_t buflen;
-+ size_t dma_size;
-
-- u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
-- int dma_in;
-+ void *buf_in;
-+ int dma_in;
-+ dma_addr_t dma_addr_in;
- struct atmel_aes_dma dma_lch_in;
-
-- u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
-- int dma_out;
-+ void *buf_out;
-+ int dma_out;
-+ dma_addr_t dma_addr_out;
- struct atmel_aes_dma dma_lch_out;
-
-+ struct atmel_aes_caps caps;
-+
- u32 hw_version;
- };
-
-@@ -170,6 +187,37 @@ static int atmel_aes_sg_length(struct ablkcipher_request *req,
- return sg_nb;
- }
-
-+static int atmel_aes_sg_copy(struct scatterlist **sg, size_t *offset,
-+ void *buf, size_t buflen, size_t total, int out)
-+{
-+ unsigned int count, off = 0;
-+
-+ while (buflen && total) {
-+ count = min((*sg)->length - *offset, total);
-+ count = min(count, buflen);
-+
-+ if (!count)
-+ return off;
-+
-+ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
-+
-+ off += count;
-+ buflen -= count;
-+ *offset += count;
-+ total -= count;
-+
-+ if (*offset == (*sg)->length) {
-+ *sg = sg_next(*sg);
-+ if (*sg)
-+ *offset = 0;
-+ else
-+ total = 0;
-+ }
-+ }
-+
-+ return off;
-+}
-+
- static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
- {
- return readl_relaxed(dd->io_base + offset);
-@@ -195,14 +243,6 @@ static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
- atmel_aes_write(dd, offset, *value);
- }
-
--static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
--{
-- atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
--
-- if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
-- dd->flags |= AES_FLAGS_DUALBUFF;
--}
--
- static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
- {
- struct atmel_aes_dev *aes_dd = NULL;
-@@ -230,7 +270,6 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
-
- if (!(dd->flags & AES_FLAGS_INIT)) {
- atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
-- atmel_aes_dualbuff_test(dd);
- dd->flags |= AES_FLAGS_INIT;
- dd->err = 0;
- }
-@@ -238,11 +277,19 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
- return 0;
- }
-
-+static inline unsigned int atmel_aes_get_version(struct atmel_aes_dev *dd)
-+{
-+ return atmel_aes_read(dd, AES_HW_VERSION) & 0x00000fff;
-+}
-+
- static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
- {
- atmel_aes_hw_init(dd);
-
-- dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
-+ dd->hw_version = atmel_aes_get_version(dd);
-+
-+ dev_info(dd->dev,
-+ "version: 0x%x\n", dd->hw_version);
-
- clk_disable_unprepare(dd->iclk);
- }
-@@ -265,50 +312,77 @@ static void atmel_aes_dma_callback(void *data)
- tasklet_schedule(&dd->done_task);
- }
-
--static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
-+static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd,
-+ dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length)
- {
-+ struct scatterlist sg[2];
- struct dma_async_tx_descriptor *in_desc, *out_desc;
-- int nb_dma_sg_in, nb_dma_sg_out;
-
-- dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
-- if (!dd->nb_in_sg)
-- goto exit_err;
-+ dd->dma_size = length;
-
-- nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
-- DMA_TO_DEVICE);
-- if (!nb_dma_sg_in)
-- goto exit_err;
-+ if (!(dd->flags & AES_FLAGS_FAST)) {
-+ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
-+ DMA_TO_DEVICE);
-+ }
-
-- in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
-- nb_dma_sg_in, DMA_MEM_TO_DEV,
-- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ if (dd->flags & AES_FLAGS_CFB8) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ } else if (dd->flags & AES_FLAGS_CFB16) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ } else {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ }
-
-- if (!in_desc)
-- goto unmap_in;
-+ if (dd->flags & (AES_FLAGS_CFB8 | AES_FLAGS_CFB16 |
-+ AES_FLAGS_CFB32 | AES_FLAGS_CFB64)) {
-+ dd->dma_lch_in.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
-+ } else {
-+ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
-+ }
-
-- /* callback not needed */
-+ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
-+ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
-
-- dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
-- if (!dd->nb_out_sg)
-- goto unmap_in;
-+ dd->flags |= AES_FLAGS_DMA;
-
-- nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
-- DMA_FROM_DEVICE);
-- if (!nb_dma_sg_out)
-- goto unmap_out;
-+ sg_init_table(&sg[0], 1);
-+ sg_dma_address(&sg[0]) = dma_addr_in;
-+ sg_dma_len(&sg[0]) = length;
-
-- out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
-- nb_dma_sg_out, DMA_DEV_TO_MEM,
-- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ sg_init_table(&sg[1], 1);
-+ sg_dma_address(&sg[1]) = dma_addr_out;
-+ sg_dma_len(&sg[1]) = length;
-
-+ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
-+ 1, DMA_MEM_TO_DEV,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ if (!in_desc)
-+ return -EINVAL;
-+
-+ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
-+ 1, DMA_DEV_TO_MEM,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!out_desc)
-- goto unmap_out;
-+ return -EINVAL;
-
- out_desc->callback = atmel_aes_dma_callback;
- out_desc->callback_param = dd;
-
-- dd->total -= dd->req->nbytes;
--
- dmaengine_submit(out_desc);
- dma_async_issue_pending(dd->dma_lch_out.chan);
-
-@@ -316,15 +390,6 @@ static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
- dma_async_issue_pending(dd->dma_lch_in.chan);
-
- return 0;
--
--unmap_out:
-- dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
-- DMA_FROM_DEVICE);
--unmap_in:
-- dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
-- DMA_TO_DEVICE);
--exit_err:
-- return -EINVAL;
- }
-
- static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
-@@ -357,30 +422,66 @@ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
-
- static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
- {
-- int err;
-+ int err, fast = 0, in, out;
-+ size_t count;
-+ dma_addr_t addr_in, addr_out;
-+
-+ if ((!dd->in_offset) && (!dd->out_offset)) {
-+ /* check for alignment */
-+ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
-+ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
-+ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
-+ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
-+ fast = in && out;
-+
-+ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
-+ fast = 0;
-+ }
-+
-+
-+ if (fast) {
-+ count = min(dd->total, sg_dma_len(dd->in_sg));
-+ count = min(count, sg_dma_len(dd->out_sg));
-+
-+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ if (!err) {
-+ dev_err(dd->dev, "dma_map_sg() error\n");
-+ return -EINVAL;
-+ }
-+
-+ err = dma_map_sg(dd->dev, dd->out_sg, 1,
-+ DMA_FROM_DEVICE);
-+ if (!err) {
-+ dev_err(dd->dev, "dma_map_sg() error\n");
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1,
-+ DMA_TO_DEVICE);
-+ return -EINVAL;
-+ }
-+
-+ addr_in = sg_dma_address(dd->in_sg);
-+ addr_out = sg_dma_address(dd->out_sg);
-+
-+ dd->flags |= AES_FLAGS_FAST;
-
-- if (dd->flags & AES_FLAGS_CFB8) {
-- dd->dma_lch_in.dma_conf.dst_addr_width =
-- DMA_SLAVE_BUSWIDTH_1_BYTE;
-- dd->dma_lch_out.dma_conf.src_addr_width =
-- DMA_SLAVE_BUSWIDTH_1_BYTE;
-- } else if (dd->flags & AES_FLAGS_CFB16) {
-- dd->dma_lch_in.dma_conf.dst_addr_width =
-- DMA_SLAVE_BUSWIDTH_2_BYTES;
-- dd->dma_lch_out.dma_conf.src_addr_width =
-- DMA_SLAVE_BUSWIDTH_2_BYTES;
- } else {
-- dd->dma_lch_in.dma_conf.dst_addr_width =
-- DMA_SLAVE_BUSWIDTH_4_BYTES;
-- dd->dma_lch_out.dma_conf.src_addr_width =
-- DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ /* use cache buffers */
-+ count = atmel_aes_sg_copy(&dd->in_sg, &dd->in_offset,
-+ dd->buf_in, dd->buflen, dd->total, 0);
-+
-+ addr_in = dd->dma_addr_in;
-+ addr_out = dd->dma_addr_out;
-+
-+ dd->flags &= ~AES_FLAGS_FAST;
- }
-
-- dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
-- dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
-+ dd->total -= count;
-
-- dd->flags |= AES_FLAGS_DMA;
-- err = atmel_aes_crypt_dma(dd);
-+ err = atmel_aes_crypt_dma(dd, addr_in, addr_out, count);
-+
-+ if (err && (dd->flags & AES_FLAGS_FAST)) {
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
-+ }
-
- return err;
- }
-@@ -415,6 +516,8 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
- valmr |= AES_MR_CFBS_32b;
- else if (dd->flags & AES_FLAGS_CFB64)
- valmr |= AES_MR_CFBS_64b;
-+ else if (dd->flags & AES_FLAGS_CFB128)
-+ valmr |= AES_MR_CFBS_128b;
- } else if (dd->flags & AES_FLAGS_OFB) {
- valmr |= AES_MR_OPMOD_OFB;
- } else if (dd->flags & AES_FLAGS_CTR) {
-@@ -428,7 +531,7 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
-
- if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
- valmr |= AES_MR_SMOD_IDATAR0;
-- if (dd->flags & AES_FLAGS_DUALBUFF)
-+ if (dd->caps.has_dualbuff)
- valmr |= AES_MR_DUALBUFF;
- } else {
- valmr |= AES_MR_SMOD_AUTO;
-@@ -482,7 +585,9 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
- /* assign new request to device */
- dd->req = req;
- dd->total = req->nbytes;
-+ dd->in_offset = 0;
- dd->in_sg = req->src;
-+ dd->out_offset = 0;
- dd->out_sg = req->dst;
-
- rctx = ablkcipher_request_ctx(req);
-@@ -511,18 +616,86 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
- static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
- {
- int err = -EINVAL;
-+ size_t count;
-
- if (dd->flags & AES_FLAGS_DMA) {
-- dma_unmap_sg(dd->dev, dd->out_sg,
-- dd->nb_out_sg, DMA_FROM_DEVICE);
-- dma_unmap_sg(dd->dev, dd->in_sg,
-- dd->nb_in_sg, DMA_TO_DEVICE);
- err = 0;
-+ if (dd->flags & AES_FLAGS_FAST) {
-+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ } else {
-+ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
-+ dd->dma_size, DMA_FROM_DEVICE);
-+
-+ /* copy data */
-+ count = atmel_aes_sg_copy(&dd->out_sg, &dd->out_offset,
-+ dd->buf_out, dd->buflen, dd->dma_size, 1);
-+ if (count != dd->dma_size) {
-+ err = -EINVAL;
-+ pr_err("not all data converted: %u\n", count);
-+ }
-+ }
-+ }
-+
-+ return err;
-+}
-+
-+
-+static int atmel_aes_buff_init(struct atmel_aes_dev *dd)
-+{
-+ int err = -ENOMEM;
-+
-+ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
-+ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
-+ dd->buflen = PAGE_SIZE;
-+ dd->buflen &= ~(AES_BLOCK_SIZE - 1);
-+
-+ if (!dd->buf_in || !dd->buf_out) {
-+ dev_err(dd->dev, "unable to alloc pages.\n");
-+ goto err_alloc;
- }
-
-+ /* MAP here */
-+ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
-+ dd->buflen, DMA_TO_DEVICE);
-+ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
-+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-+ err = -EINVAL;
-+ goto err_map_in;
-+ }
-+
-+ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
-+ dd->buflen, DMA_FROM_DEVICE);
-+ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
-+ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
-+ err = -EINVAL;
-+ goto err_map_out;
-+ }
-+
-+ return 0;
-+
-+err_map_out:
-+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
-+ DMA_TO_DEVICE);
-+err_map_in:
-+ free_page((unsigned long)dd->buf_out);
-+ free_page((unsigned long)dd->buf_in);
-+err_alloc:
-+ if (err)
-+ pr_err("error: %d\n", err);
- return err;
- }
-
-+static void atmel_aes_buff_cleanup(struct atmel_aes_dev *dd)
-+{
-+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
-+ DMA_FROM_DEVICE);
-+ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
-+ DMA_TO_DEVICE);
-+ free_page((unsigned long)dd->buf_out);
-+ free_page((unsigned long)dd->buf_in);
-+}
-+
- static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
- {
- struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
-@@ -530,9 +703,30 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
- struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
- struct atmel_aes_dev *dd;
-
-- if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
-- pr_err("request size is not exact amount of AES blocks\n");
-- return -EINVAL;
-+ if (mode & AES_FLAGS_CFB8) {
-+ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB8 blocks\n");
-+ return -EINVAL;
-+ }
-+ ctx->block_size = CFB8_BLOCK_SIZE;
-+ } else if (mode & AES_FLAGS_CFB16) {
-+ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB16 blocks\n");
-+ return -EINVAL;
-+ }
-+ ctx->block_size = CFB16_BLOCK_SIZE;
-+ } else if (mode & AES_FLAGS_CFB32) {
-+ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of CFB32 blocks\n");
-+ return -EINVAL;
-+ }
-+ ctx->block_size = CFB32_BLOCK_SIZE;
-+ } else {
-+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of AES blocks\n");
-+ return -EINVAL;
-+ }
-+ ctx->block_size = AES_BLOCK_SIZE;
- }
-
- dd = atmel_aes_find_dev(ctx);
-@@ -556,14 +750,12 @@ static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
- }
- }
-
--static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
-+static int atmel_aes_dma_init(struct atmel_aes_dev *dd,
-+ struct crypto_platform_data *pdata)
- {
- int err = -ENOMEM;
-- struct aes_platform_data *pdata;
- dma_cap_mask_t mask_in, mask_out;
-
-- pdata = dd->dev->platform_data;
--
- if (pdata && pdata->dma_slave->txdata.dma_dev &&
- pdata->dma_slave->rxdata.dma_dev) {
-
-@@ -573,28 +765,38 @@ static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
-
- dd->dma_lch_in.chan = dma_request_channel(mask_in,
- atmel_aes_filter, &pdata->dma_slave->rxdata);
-+
- if (!dd->dma_lch_in.chan)
- goto err_dma_in;
-
- dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
- dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
- AES_IDATAR(0);
-- dd->dma_lch_in.dma_conf.src_maxburst = 1;
-- dd->dma_lch_in.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_in.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
- dd->dma_lch_in.dma_conf.device_fc = false;
-
- dma_cap_zero(mask_out);
- dma_cap_set(DMA_SLAVE, mask_out);
- dd->dma_lch_out.chan = dma_request_channel(mask_out,
- atmel_aes_filter, &pdata->dma_slave->txdata);
-+
- if (!dd->dma_lch_out.chan)
- goto err_dma_out;
-
- dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
- dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
- AES_ODATAR(0);
-- dd->dma_lch_out.dma_conf.src_maxburst = 1;
-- dd->dma_lch_out.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
-+ dd->dma_lch_out.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
- dd->dma_lch_out.dma_conf.device_fc = false;
-
- return 0;
-@@ -670,13 +872,13 @@ static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
- static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
- {
- return atmel_aes_crypt(req,
-- AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
-+ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB128);
- }
-
- static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
- {
- return atmel_aes_crypt(req,
-- AES_FLAGS_CFB);
-+ AES_FLAGS_CFB | AES_FLAGS_CFB128);
- }
-
- static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
-@@ -758,7 +960,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0xf,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -778,7 +980,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0xf,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -799,7 +1001,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0xf,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -820,7 +1022,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0xf,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -841,7 +1043,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB32_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0x3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -862,7 +1064,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB16_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0x1,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -904,7 +1106,7 @@ static struct crypto_alg aes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0xf,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -920,15 +1122,14 @@ static struct crypto_alg aes_algs[] = {
- },
- };
-
--static struct crypto_alg aes_cfb64_alg[] = {
--{
-+static struct crypto_alg aes_cfb64_alg = {
- .cra_name = "cfb64(aes)",
- .cra_driver_name = "atmel-cfb64-aes",
- .cra_priority = 100,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB64_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_aes_ctx),
-- .cra_alignmask = 0x0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_aes_cra_init,
-@@ -941,7 +1142,6 @@ static struct crypto_alg aes_cfb64_alg[] = {
- .encrypt = atmel_aes_cfb64_encrypt,
- .decrypt = atmel_aes_cfb64_decrypt,
- }
--},
- };
-
- static void atmel_aes_queue_task(unsigned long data)
-@@ -974,7 +1174,14 @@ static void atmel_aes_done_task(unsigned long data)
- err = dd->err ? : err;
-
- if (dd->total && !err) {
-- err = atmel_aes_crypt_dma_start(dd);
-+ if (dd->flags & AES_FLAGS_FAST) {
-+ dd->in_sg = sg_next(dd->in_sg);
-+ dd->out_sg = sg_next(dd->out_sg);
-+ if (!dd->in_sg || !dd->out_sg)
-+ err = -EINVAL;
-+ }
-+ if (!err)
-+ err = atmel_aes_crypt_dma_start(dd);
- if (!err)
- return; /* DMA started. Not fininishing. */
- }
-@@ -1008,8 +1215,8 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
-
- for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
- crypto_unregister_alg(&aes_algs[i]);
-- if (dd->hw_version >= 0x130)
-- crypto_unregister_alg(&aes_cfb64_alg[0]);
-+ if (dd->caps.has_cfb64)
-+ crypto_unregister_alg(&aes_cfb64_alg);
- }
-
- static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
-@@ -1023,11 +1230,9 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
- goto err_aes_algs;
- }
-
-- atmel_aes_hw_version_init(dd);
--
-- if (dd->hw_version >= 0x130) {
-- INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
-- err = crypto_register_alg(&aes_cfb64_alg[0]);
-+ if (dd->caps.has_cfb64) {
-+ INIT_LIST_HEAD(&aes_cfb64_alg.cra_list);
-+ err = crypto_register_alg(&aes_cfb64_alg);
- if (err)
- goto err_aes_cfb64_alg;
- }
-@@ -1043,10 +1248,158 @@ err_aes_algs:
- return err;
- }
-
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id atmel_aes_dt_ids[] = {
-+ { .compatible = "atmel,sam9g46-aes" },
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids);
-+
-+static int atmel_aes_dma_of_init(struct device_node *np,
-+ struct at_dma_slave *atslave, const char *name)
-+{
-+ struct of_phandle_args dma_spec;
-+ struct device_node *dmac_np;
-+ struct platform_device *dmac_pdev;
-+ const __be32 *nbcells;
-+ int ret;
-+ int index;
-+
-+ index = of_property_match_string(np, "dma-name", name);
-+ if (index < 0) {
-+ pr_err("%s: dma-name property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err0;
-+ }
-+
-+ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
-+ index, &dma_spec);
-+ if (ret || !dma_spec.np) {
-+ pr_err("%s: can't parse dma property (%d)\n",
-+ np->full_name, ret);
-+ goto err0;
-+ }
-+ dmac_np = dma_spec.np;
-+
-+ /* check property format */
-+ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
-+ if (!nbcells) {
-+ pr_err("%s: #dma-cells property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ if (dma_spec.args_count != be32_to_cpup(nbcells)
-+ || dma_spec.args_count != 1) {
-+ pr_err("%s: wrong #dma-cells for %s\n",
-+ np->full_name, dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* retreive DMA controller information */
-+ dmac_pdev = of_find_device_by_node(dmac_np);
-+ if (!dmac_pdev) {
-+ pr_err("%s: unable to find pdev from DMA controller\n",
-+ dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* now fill in the at_dma_slave structure */
-+ atslave->dma_dev = &dmac_pdev->dev;
-+ atslave->cfg = dma_spec.args[0];
-+
-+err1:
-+ of_node_put(dma_spec.np);
-+err0:
-+ pr_debug("%s exited with status %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+static struct crypto_platform_data __devinit*
-+atmel_aes_of_init(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct crypto_platform_data *pdata;
-+ struct at_dma_slave *atslave;
-+
-+ if (!np) {
-+ dev_err(&pdev->dev, "device node not found\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-+ if (!pdata) {
-+ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ pdata->dma_slave = devm_kzalloc(&pdev->dev,
-+ sizeof(*(pdata->dma_slave)),
-+ GFP_KERNEL);
-+ if (!pdata->dma_slave) {
-+ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ atslave = &pdata->dma_slave->txdata;
-+ /* retrieve TX DMA configuration first */
-+ if (atmel_aes_dma_of_init(np, atslave, "tx")) {
-+ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
-+ devm_kfree(&pdev->dev, pdata->dma_slave);
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ atslave = &pdata->dma_slave->rxdata;
-+ /* retrieve RX DMA configuration first */
-+ if (atmel_aes_dma_of_init(np, atslave, "rx")) {
-+ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
-+ devm_kfree(&pdev->dev, pdata->dma_slave);
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return pdata;
-+}
-+#else /* CONFIG_OF */
-+static inline struct crypto_platform_data*
-+atmel_aes_of_init(struct platform_device *dev)
-+{
-+ return ERR_PTR(-EINVAL);
-+}
-+#endif
-+
-+static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
-+{
-+ dd->caps.has_dualbuff = 0;
-+ dd->caps.has_cfb64 = 0;
-+ dd->caps.max_burst_size = 1;
-+
-+ /* keep only major version number */
-+ switch (dd->hw_version & 0xff0) {
-+ case 0x130:
-+ dd->caps.has_dualbuff = 1;
-+ dd->caps.has_cfb64 = 1;
-+ dd->caps.max_burst_size = 4;
-+ break;
-+ case 0x120:
-+ break;
-+ default:
-+ dev_warn(dd->dev,
-+ "Unmanaged aes version, set minimum capabilities\n");
-+ break;
-+ }
-+}
-+
- static int __devinit atmel_aes_probe(struct platform_device *pdev)
- {
- struct atmel_aes_dev *aes_dd;
-- struct aes_platform_data *pdata;
-+ struct crypto_platform_data *pdata;
- struct device *dev = &pdev->dev;
- struct resource *aes_res;
- unsigned long aes_phys_size;
-@@ -1054,8 +1407,11 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
-
- pdata = pdev->dev.platform_data;
- if (!pdata) {
-- err = -ENXIO;
-- goto aes_dd_err;
-+ pdata = atmel_aes_of_init(pdev);
-+ if (IS_ERR(pdata)) {
-+ dev_err(&pdev->dev, "platform data not available\n");
-+ return PTR_ERR(pdata);
-+ }
- }
-
- aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
-@@ -1106,7 +1462,7 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
- }
-
- /* Initializing the clock */
-- aes_dd->iclk = clk_get(&pdev->dev, NULL);
-+ aes_dd->iclk = clk_get(&pdev->dev, "aes_clk");
- if (IS_ERR(aes_dd->iclk)) {
- dev_err(dev, "clock intialization failed.\n");
- err = PTR_ERR(aes_dd->iclk);
-@@ -1120,7 +1476,15 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
- goto aes_io_err;
- }
-
-- err = atmel_aes_dma_init(aes_dd);
-+ atmel_aes_hw_version_init(aes_dd);
-+
-+ atmel_aes_get_cap(aes_dd);
-+
-+ err = atmel_aes_buff_init(aes_dd);
-+ if (err)
-+ goto err_aes_buff;
-+
-+ err = atmel_aes_dma_init(aes_dd, pdata);
- if (err)
- goto err_aes_dma;
-
-@@ -1142,6 +1506,8 @@ err_algs:
- spin_unlock(&atmel_aes.lock);
- atmel_aes_dma_cleanup(aes_dd);
- err_aes_dma:
-+ atmel_aes_buff_cleanup(aes_dd);
-+err_aes_buff:
- iounmap(aes_dd->io_base);
- aes_io_err:
- clk_put(aes_dd->iclk);
-@@ -1191,15 +1557,27 @@ static int __devexit atmel_aes_remove(struct platform_device *pdev)
- }
-
- static struct platform_driver atmel_aes_driver = {
-- .probe = atmel_aes_probe,
- .remove = __devexit_p(atmel_aes_remove),
- .driver = {
- .name = "atmel_aes",
-- .owner = THIS_MODULE,
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(atmel_aes_dt_ids),
- },
- };
-
--module_platform_driver(atmel_aes_driver);
-+static int __init atmel_aes_init(void)
-+{
-+ return platform_driver_probe(&atmel_aes_driver, atmel_aes_probe);
-+}
-+
-+static void __exit atmel_aes_exit(void)
-+{
-+ platform_driver_unregister(&atmel_aes_driver);
-+}
-+
-+late_initcall(atmel_aes_init); /* try to load after dma driver when built-in */
-+module_exit(atmel_aes_exit);
-+
-
- MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
- MODULE_LICENSE("GPL v2");
-diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
-deleted file mode 100644
-index e7a1949..0000000
---- a/include/linux/platform_data/atmel-aes.h
-+++ /dev/null
-@@ -1,22 +0,0 @@
--#ifndef __LINUX_ATMEL_AES_H
--#define __LINUX_ATMEL_AES_H
--
--#include <mach/at_hdmac.h>
--
--/**
-- * struct aes_dma_data - DMA data for AES
-- */
--struct aes_dma_data {
-- struct at_dma_slave txdata;
-- struct at_dma_slave rxdata;
--};
--
--/**
-- * struct aes_platform_data - board-specific AES configuration
-- * @dma_slave: DMA slave interface to use in data transfers.
-- */
--struct aes_platform_data {
-- struct aes_dma_data *dma_slave;
--};
--
--#endif /* __LINUX_ATMEL_AES_H */
-diff --git a/include/linux/platform_data/atmel-crypto.h b/include/linux/platform_data/atmel-crypto.h
-new file mode 100644
-index 0000000..eddfca7
---- /dev/null
-+++ b/include/linux/platform_data/atmel-crypto.h
-@@ -0,0 +1,22 @@
-+#ifndef __LINUX_ATMEL_CRYPTO_H
-+#define __LINUX_ATMEL_CRYPTO_H
-+
-+#include <mach/at_hdmac.h>
-+
-+/**
-+ * struct crypto_dma_data - DMA data for AES/TDES/SHA
-+ */
-+struct crypto_dma_data {
-+ struct at_dma_slave txdata;
-+ struct at_dma_slave rxdata;
-+};
-+
-+/**
-+ * struct tdes_platform_data - board-specific AES/TDES/SHA configuration
-+ * @dma_slave: DMA slave interface to use in data transfers.
-+ */
-+struct crypto_platform_data {
-+ struct crypto_dma_data *dma_slave;
-+};
-+
-+#endif /* __LINUX_ATMEL_CRYPTO_H */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From b91b13d77cdd19b1fdbd1ba82111370f2cc124a9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 2 Oct 2012 11:50:15 +0200
+Subject: ARM: at91: split 9x5 dts/dtsi in a "common" set of peripherals
+
+Creating this new at91sam9x5_common.dtsi, will allow to cover the
+whole at91sam9x5 family of SoCs without having to duplicate nodes.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g25ek.dts
+---
+ arch/arm/boot/dts/at91sam9g25ek.dts | 19 +----------
+ arch/arm/boot/dts/at91sam9x5_common.dtsi | 54 ++++++++++++++++++++++++++++++++
+ 2 files changed, 55 insertions(+), 18 deletions(-)
+ create mode 100644 arch/arm/boot/dts/at91sam9x5_common.dtsi
+
+diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
+index 5b054e4..91c0f02 100644
+--- a/arch/arm/boot/dts/at91sam9g25ek.dts
++++ b/arch/arm/boot/dts/at91sam9g25ek.dts
+@@ -7,8 +7,7 @@
+ * Licensed under GPLv2 or later.
+ */
+ /dts-v1/;
+-/include/ "at91sam9x5.dtsi"
+-/include/ "at91sam9x5cm.dtsi"
++/include/ "at91sam9x5_common.dtsi"
+
+ / {
+ model = "Atmel AT91SAM9G25-EK";
+@@ -20,10 +19,6 @@
+
+ ahb {
+ apb {
+- dbgu: serial@fffff200 {
+- status = "okay";
+- };
+-
+ usart0: serial@f801c000 {
+ status = "okay";
+ };
+@@ -63,17 +58,5 @@
+ status = "okay";
+ };
+ };
+-
+- usb0: ohci@00600000 {
+- status = "okay";
+- num-ports = <2>;
+- atmel,vbus-gpio = <&pioD 19 1
+- &pioD 20 1
+- >;
+- };
+-
+- usb1: ehci@00700000 {
+- status = "okay";
+- };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5_common.dtsi b/arch/arm/boot/dts/at91sam9x5_common.dtsi
+new file mode 100644
+index 0000000..b805425
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x5_common.dtsi
+@@ -0,0 +1,54 @@
++/*
++ * at91sam9x5_common.dtsi - Device Tree Include file for AT91SAM9x5 Evaluation Kit:
++ * common peripherals.
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/include/ "at91sam9x5.dtsi"
++/include/ "at91sam9x5cm.dtsi"
++
++/ {
++ ahb {
++ apb {
++ dbgu: serial@fffff200 {
++ status = "okay";
++ };
++
++ mmc0: mmc@f0008000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 15 0>;
++ };
++ };
++
++ i2c0: i2c@f8010000 {
++ status = "okay";
++ };
++
++ i2c1: i2c@f8014000 {
++ status = "okay";
++ };
++
++ i2c2: i2c@f8018000 {
++ status = "okay";
++ };
++ };
++
++ usb0: ohci@00600000 {
++ status = "okay";
++ num-ports = <2>;
++ atmel,vbus-gpio = <&pioD 19 1
++ &pioD 20 1
++ >;
++ };
++
++ usb1: ehci@00700000 {
++ status = "okay";
++ };
++ };
++};
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ba14d3bcc1c0a32bec0a0c1b8bb8035abef12fbc Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:16 +0200
-Subject: crypto: Atmel TDES; add device tree support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/atmel-tdes-regs.h | 2 +
- drivers/crypto/atmel-tdes.c | 541 +++++++++++++++++++++++++++++++++++----
- 2 files changed, 487 insertions(+), 56 deletions(-)
-
-diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
-index 5ac2a90..f86734d 100644
---- a/drivers/crypto/atmel-tdes-regs.h
-+++ b/drivers/crypto/atmel-tdes-regs.h
-@@ -69,6 +69,8 @@
- #define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
- #define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
-
-+#define TDES_HW_VERSION 0xFC
-+
- #define TDES_RPR 0x100
- #define TDES_RCR 0x104
- #define TDES_TPR 0x108
-diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
-index eb2b61e..9de10bd 100644
---- a/drivers/crypto/atmel-tdes.c
-+++ b/drivers/crypto/atmel-tdes.c
-@@ -43,29 +43,37 @@
- #include <crypto/des.h>
- #include <crypto/hash.h>
- #include <crypto/internal/hash.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_data/atmel-crypto.h>
- #include "atmel-tdes-regs.h"
-
- /* TDES flags */
--#define TDES_FLAGS_MODE_MASK 0x007f
-+#define TDES_FLAGS_MODE_MASK 0x00ff
- #define TDES_FLAGS_ENCRYPT BIT(0)
- #define TDES_FLAGS_CBC BIT(1)
- #define TDES_FLAGS_CFB BIT(2)
- #define TDES_FLAGS_CFB8 BIT(3)
- #define TDES_FLAGS_CFB16 BIT(4)
- #define TDES_FLAGS_CFB32 BIT(5)
--#define TDES_FLAGS_OFB BIT(6)
-+#define TDES_FLAGS_CFB64 BIT(6)
-+#define TDES_FLAGS_OFB BIT(7)
-
- #define TDES_FLAGS_INIT BIT(16)
- #define TDES_FLAGS_FAST BIT(17)
- #define TDES_FLAGS_BUSY BIT(18)
-+#define TDES_FLAGS_DMA BIT(19)
-
--#define ATMEL_TDES_QUEUE_LENGTH 1
-+#define ATMEL_TDES_QUEUE_LENGTH 50
-
- #define CFB8_BLOCK_SIZE 1
- #define CFB16_BLOCK_SIZE 2
- #define CFB32_BLOCK_SIZE 4
--#define CFB64_BLOCK_SIZE 8
-
-+struct atmel_tdes_caps {
-+ bool has_dma;
-+ u32 has_cfb_3keys;
-+};
-
- struct atmel_tdes_dev;
-
-@@ -75,12 +83,19 @@ struct atmel_tdes_ctx {
- int keylen;
- u32 key[3*DES_KEY_SIZE / sizeof(u32)];
- unsigned long flags;
-+
-+ u16 block_size;
- };
-
- struct atmel_tdes_reqctx {
- unsigned long mode;
- };
-
-+struct atmel_tdes_dma {
-+ struct dma_chan *chan;
-+ struct dma_slave_config dma_conf;
-+};
-+
- struct atmel_tdes_dev {
- struct list_head list;
- unsigned long phys_base;
-@@ -104,8 +119,10 @@ struct atmel_tdes_dev {
- size_t total;
-
- struct scatterlist *in_sg;
-+ unsigned int nb_in_sg;
- size_t in_offset;
- struct scatterlist *out_sg;
-+ unsigned int nb_out_sg;
- size_t out_offset;
-
- size_t buflen;
-@@ -114,10 +131,16 @@ struct atmel_tdes_dev {
- void *buf_in;
- int dma_in;
- dma_addr_t dma_addr_in;
-+ struct atmel_tdes_dma dma_lch_in;
-
- void *buf_out;
- int dma_out;
- dma_addr_t dma_addr_out;
-+ struct atmel_tdes_dma dma_lch_out;
-+
-+ struct atmel_tdes_caps caps;
-+
-+ u32 hw_version;
- };
-
- struct atmel_tdes_drv {
-@@ -212,6 +235,31 @@ static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
- return 0;
- }
-
-+static inline unsigned int atmel_tdes_get_version(struct atmel_tdes_dev *dd)
-+{
-+ return atmel_tdes_read(dd, TDES_HW_VERSION) & 0x00000fff;
-+}
-+
-+static void atmel_tdes_hw_version_init(struct atmel_tdes_dev *dd)
-+{
-+ atmel_tdes_hw_init(dd);
-+
-+ dd->hw_version = atmel_tdes_get_version(dd);
-+
-+ dev_info(dd->dev,
-+ "version: 0x%x\n", dd->hw_version);
-+
-+ clk_disable_unprepare(dd->iclk);
-+}
-+
-+static void atmel_tdes_dma_callback(void *data)
-+{
-+ struct atmel_tdes_dev *dd = data;
-+
-+ /* dma_lch_out - completed */
-+ tasklet_schedule(&dd->done_task);
-+}
-+
- static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
- {
- int err;
-@@ -222,7 +270,9 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
- if (err)
- return err;
-
-- atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
-+ if (!dd->caps.has_dma)
-+ atmel_tdes_write(dd, TDES_PTCR,
-+ TDES_PTCR_TXTDIS | TDES_PTCR_RXTDIS);
-
- /* MR register must be set before IV registers */
- if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
-@@ -246,6 +296,8 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
- valmr |= TDES_MR_CFBS_16b;
- else if (dd->flags & TDES_FLAGS_CFB32)
- valmr |= TDES_MR_CFBS_32b;
-+ else if (dd->flags & TDES_FLAGS_CFB64)
-+ valmr |= TDES_MR_CFBS_64b;
- } else if (dd->flags & TDES_FLAGS_OFB) {
- valmr |= TDES_MR_OPMOD_OFB;
- }
-@@ -267,7 +319,7 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
- return 0;
- }
-
--static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
-+static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd)
- {
- int err = 0;
- size_t count;
-@@ -293,7 +345,7 @@ static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
- return err;
- }
-
--static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
-+static int atmel_tdes_buff_init(struct atmel_tdes_dev *dd)
- {
- int err = -ENOMEM;
-
-@@ -338,7 +390,7 @@ err_alloc:
- return err;
- }
-
--static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
-+static void atmel_tdes_buff_cleanup(struct atmel_tdes_dev *dd)
- {
- dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
- DMA_FROM_DEVICE);
-@@ -348,7 +400,7 @@ static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
- free_page((unsigned long)dd->buf_in);
- }
-
--static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
-+static int atmel_tdes_crypt_pdc(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
- dma_addr_t dma_addr_out, int length)
- {
- struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
-@@ -384,7 +436,76 @@ static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
- return 0;
- }
-
--static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
-+static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
-+ dma_addr_t dma_addr_out, int length)
-+{
-+ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
-+ struct atmel_tdes_dev *dd = ctx->dd;
-+ struct scatterlist sg[2];
-+ struct dma_async_tx_descriptor *in_desc, *out_desc;
-+
-+ dd->dma_size = length;
-+
-+ if (!(dd->flags & TDES_FLAGS_FAST)) {
-+ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
-+ DMA_TO_DEVICE);
-+ }
-+
-+ if (dd->flags & TDES_FLAGS_CFB8) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_1_BYTE;
-+ } else if (dd->flags & TDES_FLAGS_CFB16) {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_2_BYTES;
-+ } else {
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ }
-+
-+ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
-+ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
-+
-+ dd->flags |= TDES_FLAGS_DMA;
-+
-+ sg_init_table(&sg[0], 1);
-+ sg_dma_address(&sg[0]) = dma_addr_in;
-+ sg_dma_len(&sg[0]) = length;
-+
-+ sg_init_table(&sg[1], 1);
-+ sg_dma_address(&sg[1]) = dma_addr_out;
-+ sg_dma_len(&sg[1]) = length;
-+
-+ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
-+ 1, DMA_MEM_TO_DEV,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ if (!in_desc)
-+ return -EINVAL;
-+
-+ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
-+ 1, DMA_DEV_TO_MEM,
-+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ if (!out_desc)
-+ return -EINVAL;
-+
-+ out_desc->callback = atmel_tdes_dma_callback;
-+ out_desc->callback_param = dd;
-+
-+ dmaengine_submit(out_desc);
-+ dma_async_issue_pending(dd->dma_lch_out.chan);
-+
-+ dmaengine_submit(in_desc);
-+ dma_async_issue_pending(dd->dma_lch_in.chan);
-+
-+ return 0;
-+}
-+
-+static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd)
- {
- struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
- crypto_ablkcipher_reqtfm(dd->req));
-@@ -392,23 +513,23 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
- size_t count;
- dma_addr_t addr_in, addr_out;
-
-- if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
-+ if ((!dd->in_offset) && (!dd->out_offset)) {
- /* check for alignment */
-- in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
-- out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
--
-+ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
-+ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
-+ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
-+ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
- fast = in && out;
-+
-+ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
-+ fast = 0;
- }
-
-+
- if (fast) {
- count = min(dd->total, sg_dma_len(dd->in_sg));
- count = min(count, sg_dma_len(dd->out_sg));
-
-- if (count != dd->total) {
-- pr_err("request length != buffer length\n");
-- return -EINVAL;
-- }
--
- err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
- if (!err) {
- dev_err(dd->dev, "dma_map_sg() error\n");
-@@ -438,13 +559,16 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
- addr_out = dd->dma_addr_out;
-
- dd->flags &= ~TDES_FLAGS_FAST;
--
- }
-
- dd->total -= count;
-
-- err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
-- if (err) {
-+ if (dd->caps.has_dma)
-+ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
-+ else
-+ err = atmel_tdes_crypt_pdc(tfm, addr_in, addr_out, count);
-+
-+ if (err && (dd->flags & TDES_FLAGS_FAST)) {
- dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
- dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
- }
-@@ -452,7 +576,6 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
- return err;
- }
-
--
- static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
- {
- struct ablkcipher_request *req = dd->req;
-@@ -511,7 +634,7 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
-
- err = atmel_tdes_write_ctrl(dd);
- if (!err)
-- err = atmel_tdes_crypt_dma_start(dd);
-+ err = atmel_tdes_crypt_start(dd);
- if (err) {
- /* des_task will not finish it, so do it here */
- atmel_tdes_finish_req(dd, err);
-@@ -521,41 +644,145 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
- return ret;
- }
-
-+static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
-+{
-+ int err = -EINVAL;
-+ size_t count;
-+
-+ if (dd->flags & TDES_FLAGS_DMA) {
-+ err = 0;
-+ if (dd->flags & TDES_FLAGS_FAST) {
-+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
-+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
-+ } else {
-+ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
-+ dd->dma_size, DMA_FROM_DEVICE);
-+
-+ /* copy data */
-+ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
-+ dd->buf_out, dd->buflen, dd->dma_size, 1);
-+ if (count != dd->dma_size) {
-+ err = -EINVAL;
-+ pr_err("not all data converted: %u\n", count);
-+ }
-+ }
-+ }
-+ return err;
-+}
-
- static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
- {
- struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
- crypto_ablkcipher_reqtfm(req));
- struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
-- struct atmel_tdes_dev *dd;
-
- if (mode & TDES_FLAGS_CFB8) {
- if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
- pr_err("request size is not exact amount of CFB8 blocks\n");
- return -EINVAL;
- }
-+ ctx->block_size = CFB8_BLOCK_SIZE;
- } else if (mode & TDES_FLAGS_CFB16) {
- if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
- pr_err("request size is not exact amount of CFB16 blocks\n");
- return -EINVAL;
- }
-+ ctx->block_size = CFB16_BLOCK_SIZE;
- } else if (mode & TDES_FLAGS_CFB32) {
- if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
- pr_err("request size is not exact amount of CFB32 blocks\n");
- return -EINVAL;
- }
-- } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
-- pr_err("request size is not exact amount of DES blocks\n");
-- return -EINVAL;
-+ ctx->block_size = CFB32_BLOCK_SIZE;
-+ } else {
-+ if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
-+ pr_err("request size is not exact amount of DES blocks\n");
-+ return -EINVAL;
-+ }
-+ ctx->block_size = DES_BLOCK_SIZE;
- }
-
-- dd = atmel_tdes_find_dev(ctx);
-- if (!dd)
-+ rctx->mode = mode;
-+
-+ return atmel_tdes_handle_queue(ctx->dd, req);
-+}
-+
-+static bool atmel_tdes_filter(struct dma_chan *chan, void *slave)
-+{
-+ struct at_dma_slave *sl = slave;
-+
-+ if (sl && sl->dma_dev == chan->device->dev) {
-+ chan->private = sl;
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
-+static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd,
-+ struct crypto_platform_data *pdata)
-+{
-+ int err = -ENOMEM;
-+ dma_cap_mask_t mask_in, mask_out;
-+
-+ if (pdata && pdata->dma_slave->txdata.dma_dev &&
-+ pdata->dma_slave->rxdata.dma_dev) {
-+
-+ /* Try to grab 2 DMA channels */
-+ dma_cap_zero(mask_in);
-+ dma_cap_set(DMA_SLAVE, mask_in);
-+
-+ dd->dma_lch_in.chan = dma_request_channel(mask_in,
-+ atmel_tdes_filter, &pdata->dma_slave->rxdata);
-+
-+ if (!dd->dma_lch_in.chan)
-+ goto err_dma_in;
-+
-+ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
-+ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
-+ TDES_IDATA1R;
-+ dd->dma_lch_in.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_in.dma_conf.device_fc = false;
-+
-+ dma_cap_zero(mask_out);
-+ dma_cap_set(DMA_SLAVE, mask_out);
-+ dd->dma_lch_out.chan = dma_request_channel(mask_out,
-+ atmel_tdes_filter, &pdata->dma_slave->txdata);
-+
-+ if (!dd->dma_lch_out.chan)
-+ goto err_dma_out;
-+
-+ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
-+ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
-+ TDES_ODATA1R;
-+ dd->dma_lch_out.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_out.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_out.dma_conf.device_fc = false;
-+
-+ return 0;
-+ } else {
- return -ENODEV;
-+ }
-
-- rctx->mode = mode;
-+err_dma_out:
-+ dma_release_channel(dd->dma_lch_in.chan);
-+err_dma_in:
-+ return err;
-+}
-
-- return atmel_tdes_handle_queue(dd, req);
-+static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
-+{
-+ dma_release_channel(dd->dma_lch_in.chan);
-+ dma_release_channel(dd->dma_lch_out.chan);
- }
-
- static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
-@@ -595,7 +822,8 @@ static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
- /*
- * HW bug in cfb 3-keys mode.
- */
-- if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
-+ if (!ctx->dd->caps.has_cfb_3keys && strstr(alg_name, "cfb")
-+ && (keylen != 2*DES_KEY_SIZE)) {
- crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
- return -EINVAL;
- } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
-@@ -683,8 +911,15 @@ static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
-
- static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
- {
-+ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
-+ struct atmel_tdes_dev *dd;
-+
- tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
-
-+ dd = atmel_tdes_find_dev(ctx);
-+ if (!dd)
-+ return -ENODEV;
-+
- return 0;
- }
-
-@@ -700,7 +935,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -720,7 +955,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -741,7 +976,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -783,7 +1018,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB16_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x1,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -804,7 +1039,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB32_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -825,7 +1060,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -846,7 +1081,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -866,7 +1101,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -887,7 +1122,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -929,7 +1164,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB16_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x1,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -950,7 +1185,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = CFB32_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x3,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -971,7 +1206,7 @@ static struct crypto_alg tdes_algs[] = {
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
-- .cra_alignmask = 0,
-+ .cra_alignmask = 0x7,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = atmel_tdes_cra_init,
-@@ -999,14 +1234,24 @@ static void atmel_tdes_done_task(unsigned long data)
- struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
- int err;
-
-- err = atmel_tdes_crypt_dma_stop(dd);
-+ if (!(dd->flags & TDES_FLAGS_DMA))
-+ err = atmel_tdes_crypt_pdc_stop(dd);
-+ else
-+ err = atmel_tdes_crypt_dma_stop(dd);
-
- err = dd->err ? : err;
-
- if (dd->total && !err) {
-- err = atmel_tdes_crypt_dma_start(dd);
-+ if (dd->flags & TDES_FLAGS_FAST) {
-+ dd->in_sg = sg_next(dd->in_sg);
-+ dd->out_sg = sg_next(dd->out_sg);
-+ if (!dd->in_sg || !dd->out_sg)
-+ err = -EINVAL;
-+ }
-+ if (!err)
-+ err = atmel_tdes_crypt_start(dd);
- if (!err)
-- return;
-+ return; /* DMA started. Not fininishing. */
- }
-
- atmel_tdes_finish_req(dd, err);
-@@ -1059,9 +1304,157 @@ err_tdes_algs:
- return err;
- }
-
-+#ifdef CONFIG_OF
-+static const struct of_device_id atmel_tdes_dt_ids[] = {
-+ { .compatible = "atmel,sam9g46-tdes" },
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids);
-+
-+static int atmel_tdes_dma_of_init(struct device_node *np,
-+ struct at_dma_slave *atslave, const char *name)
-+{
-+ struct of_phandle_args dma_spec;
-+ struct device_node *dmac_np;
-+ struct platform_device *dmac_pdev;
-+ const __be32 *nbcells;
-+ int ret;
-+ int index;
-+
-+ index = of_property_match_string(np, "dma-name", name);
-+ if (index < 0) {
-+ pr_err("%s: dma-name property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err0;
-+ }
-+
-+ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
-+ index, &dma_spec);
-+ if (ret || !dma_spec.np) {
-+ pr_err("%s: can't parse dma property (%d)\n",
-+ np->full_name, ret);
-+ goto err0;
-+ }
-+ dmac_np = dma_spec.np;
-+
-+ /* check property format */
-+ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
-+ if (!nbcells) {
-+ pr_err("%s: #dma-cells property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ if (dma_spec.args_count != be32_to_cpup(nbcells)
-+ || dma_spec.args_count != 1) {
-+ pr_err("%s: wrong #dma-cells for %s\n",
-+ np->full_name, dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* retreive DMA controller information */
-+ dmac_pdev = of_find_device_by_node(dmac_np);
-+ if (!dmac_pdev) {
-+ pr_err("%s: unable to find pdev from DMA controller\n",
-+ dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* now fill in the at_dma_slave structure */
-+ atslave->dma_dev = &dmac_pdev->dev;
-+ atslave->cfg = dma_spec.args[0];
-+
-+err1:
-+ of_node_put(dma_spec.np);
-+err0:
-+ pr_debug("%s exited with status %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+
-+static struct crypto_platform_data __devinit*
-+atmel_tdes_of_init(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct crypto_platform_data *pdata;
-+ struct at_dma_slave *atslave;
-+
-+ if (!np) {
-+ dev_err(&pdev->dev, "device node not found\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-+ if (!pdata) {
-+ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ pdata->dma_slave = devm_kzalloc(&pdev->dev,
-+ sizeof(*(pdata->dma_slave)),
-+ GFP_KERNEL);
-+ if (!pdata->dma_slave) {
-+ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ atslave = &pdata->dma_slave->txdata;
-+ /* retrieve TX DMA configuration first */
-+ if (atmel_tdes_dma_of_init(np, atslave, "tx")) {
-+ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
-+ devm_kfree(&pdev->dev, pdata->dma_slave);
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ atslave = &pdata->dma_slave->rxdata;
-+ /* retrieve RX DMA configuration first */
-+ if (atmel_tdes_dma_of_init(np, atslave, "rx")) {
-+ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
-+ devm_kfree(&pdev->dev, pdata->dma_slave);
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return pdata;
-+}
-+#else /* CONFIG_OF */
-+static inline struct crypto_platform_data*
-+atmel_tdes_of_init(struct platform_device *dev)
-+{
-+ return ERR_PTR(-EINVAL);
-+}
-+#endif
-+
-+static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd)
-+{
-+
-+ dd->caps.has_dma = 0;
-+ dd->caps.has_cfb_3keys = 0;
-+
-+ /* keep only major version number */
-+ switch (dd->hw_version & 0xf00) {
-+ case 0x700:
-+ dd->caps.has_dma = 1;
-+ dd->caps.has_cfb_3keys = 1;
-+ break;
-+ case 0x600:
-+ break;
-+ default:
-+ dev_warn(dd->dev,
-+ "Unmanaged tdes version, set minimum capabilities\n");
-+ break;
-+ }
-+}
-+
- static int __devinit atmel_tdes_probe(struct platform_device *pdev)
- {
- struct atmel_tdes_dev *tdes_dd;
-+ struct crypto_platform_data *pdata;
- struct device *dev = &pdev->dev;
- struct resource *tdes_res;
- unsigned long tdes_phys_size;
-@@ -1115,7 +1508,7 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
- }
-
- /* Initializing the clock */
-- tdes_dd->iclk = clk_get(&pdev->dev, NULL);
-+ tdes_dd->iclk = clk_get(&pdev->dev, "tdes_clk");
- if (IS_ERR(tdes_dd->iclk)) {
- dev_err(dev, "clock intialization failed.\n");
- err = PTR_ERR(tdes_dd->iclk);
-@@ -1129,9 +1522,27 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
- goto tdes_io_err;
- }
-
-- err = atmel_tdes_dma_init(tdes_dd);
-+ atmel_tdes_hw_version_init(tdes_dd);
-+
-+ atmel_tdes_get_cap(tdes_dd);
-+
-+ err = atmel_tdes_buff_init(tdes_dd);
- if (err)
-- goto err_tdes_dma;
-+ goto err_tdes_buff;
-+
-+ if (tdes_dd->caps.has_dma) {
-+ pdata = pdev->dev.platform_data;
-+ if (!pdata) {
-+ pdata = atmel_tdes_of_init(pdev);
-+ if (IS_ERR(pdata)) {
-+ dev_err(&pdev->dev, "platform data not available\n");
-+ goto err_pdata;
-+ }
-+ }
-+ err = atmel_tdes_dma_init(tdes_dd, pdata);
-+ if (err)
-+ goto err_tdes_dma;
-+ }
-
- spin_lock(&atmel_tdes.lock);
- list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
-@@ -1149,8 +1560,12 @@ err_algs:
- spin_lock(&atmel_tdes.lock);
- list_del(&tdes_dd->list);
- spin_unlock(&atmel_tdes.lock);
-- atmel_tdes_dma_cleanup(tdes_dd);
-+ if (tdes_dd->caps.has_dma)
-+ atmel_tdes_dma_cleanup(tdes_dd);
- err_tdes_dma:
-+err_pdata:
-+ atmel_tdes_buff_cleanup(tdes_dd);
-+err_tdes_buff:
- iounmap(tdes_dd->io_base);
- tdes_io_err:
- clk_put(tdes_dd->iclk);
-@@ -1184,7 +1599,10 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
- tasklet_kill(&tdes_dd->done_task);
- tasklet_kill(&tdes_dd->queue_task);
-
-- atmel_tdes_dma_cleanup(tdes_dd);
-+ if (tdes_dd->caps.has_dma)
-+ atmel_tdes_dma_cleanup(tdes_dd);
-+
-+ atmel_tdes_buff_cleanup(tdes_dd);
-
- iounmap(tdes_dd->io_base);
-
-@@ -1200,15 +1618,26 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
- }
-
- static struct platform_driver atmel_tdes_driver = {
-- .probe = atmel_tdes_probe,
- .remove = __devexit_p(atmel_tdes_remove),
- .driver = {
- .name = "atmel_tdes",
-- .owner = THIS_MODULE,
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(atmel_tdes_dt_ids),
- },
- };
-
--module_platform_driver(atmel_tdes_driver);
-+static int __init atmel_tdes_init(void)
-+{
-+ return platform_driver_probe(&atmel_tdes_driver, atmel_tdes_probe);
-+}
-+
-+static void __exit atmel_tdes_exit(void)
-+{
-+ platform_driver_unregister(&atmel_tdes_driver);
-+}
-+
-+late_initcall(atmel_tdes_init); /* try to load after dma driver when built-in */
-+module_exit(atmel_tdes_exit);
-
- MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
- MODULE_LICENSE("GPL v2");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From c21000658bdd029faf2054f0fffa9672152ac1e9 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 2 Oct 2012 11:55:18 +0200
+Subject: ARM: at91/9x5 family: add at91sam9x25ek.dts
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9x25ek.dts | 46 +++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 2 files changed, 47 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9x25ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
+new file mode 100644
+index 0000000..cf903f5
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9x25ek.dts
+@@ -0,0 +1,46 @@
++/*
++ * at91sam9x25ek.dts - Device Tree file for AT91SAM9X25-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9x5_common.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9X25-EK";
++ compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ };
++
++ ahb {
++ apb {
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
++
++ usart0: serial@f801c000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@f802c000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ macb1: ethernet@f8030000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++ };
++ };
++};
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 9e84fe4..9532f93 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -34,3 +34,4 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 8d47f5d2568287ff9d0cddc524939d9cb1f6db72 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:17 +0200
-Subject: crypto: Atmel SHA; add device tree support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/atmel-sha-regs.h | 7 +-
- drivers/crypto/atmel-sha.c | 698 ++++++++++++++++++++++++++++++++++------
- 2 files changed, 608 insertions(+), 97 deletions(-)
-
-diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
-index dc53a20..83b2d74 100644
---- a/drivers/crypto/atmel-sha-regs.h
-+++ b/drivers/crypto/atmel-sha-regs.h
-@@ -14,10 +14,13 @@
- #define SHA_MR_MODE_MANUAL 0x0
- #define SHA_MR_MODE_AUTO 0x1
- #define SHA_MR_MODE_PDC 0x2
--#define SHA_MR_DUALBUFF (1 << 3)
- #define SHA_MR_PROCDLY (1 << 4)
- #define SHA_MR_ALGO_SHA1 (0 << 8)
- #define SHA_MR_ALGO_SHA256 (1 << 8)
-+#define SHA_MR_ALGO_SHA384 (2 << 8)
-+#define SHA_MR_ALGO_SHA512 (3 << 8)
-+#define SHA_MR_ALGO_SHA224 (4 << 8)
-+#define SHA_MR_DUALBUFF (1 << 16)
-
- #define SHA_IER 0x10
- #define SHA_IDR 0x14
-@@ -33,6 +36,8 @@
- #define SHA_ISR_URAT_MR (0x2 << 12)
- #define SHA_ISR_URAT_WO (0x5 << 12)
-
-+#define SHA_HW_VERSION 0xFC
-+
- #define SHA_TPR 0x108
- #define SHA_TCR 0x10C
- #define SHA_TNPR 0x118
-diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
-index f938b9d..f66f1c8 100644
---- a/drivers/crypto/atmel-sha.c
-+++ b/drivers/crypto/atmel-sha.c
-@@ -43,6 +43,9 @@
- #include <crypto/sha.h>
- #include <crypto/hash.h>
- #include <crypto/internal/hash.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_data/atmel-crypto.h>
- #include "atmel-sha-regs.h"
-
- /* SHA flags */
-@@ -57,11 +60,12 @@
- #define SHA_FLAGS_FINUP BIT(16)
- #define SHA_FLAGS_SG BIT(17)
- #define SHA_FLAGS_SHA1 BIT(18)
--#define SHA_FLAGS_SHA256 BIT(19)
--#define SHA_FLAGS_ERROR BIT(20)
--#define SHA_FLAGS_PAD BIT(21)
--
--#define SHA_FLAGS_DUALBUFF BIT(24)
-+#define SHA_FLAGS_SHA224 BIT(19)
-+#define SHA_FLAGS_SHA256 BIT(20)
-+#define SHA_FLAGS_SHA384 BIT(21)
-+#define SHA_FLAGS_SHA512 BIT(22)
-+#define SHA_FLAGS_ERROR BIT(23)
-+#define SHA_FLAGS_PAD BIT(24)
-
- #define SHA_OP_UPDATE 1
- #define SHA_OP_FINAL 2
-@@ -70,6 +74,12 @@
-
- #define ATMEL_SHA_DMA_THRESHOLD 56
-
-+struct atmel_sha_caps {
-+ bool has_dma;
-+ bool has_dualbuff;
-+ bool has_sha224;
-+ bool has_sha_384_512;
-+};
-
- struct atmel_sha_dev;
-
-@@ -78,8 +88,8 @@ struct atmel_sha_reqctx {
- unsigned long flags;
- unsigned long op;
-
-- u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
-- size_t digcnt;
-+ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
-+ u64 digcnt[2];
- size_t bufcnt;
- size_t buflen;
- dma_addr_t dma_addr;
-@@ -89,6 +99,8 @@ struct atmel_sha_reqctx {
- unsigned int offset; /* offset in current sg */
- unsigned int total; /* total request */
-
-+ size_t block_size;
-+
- u8 buffer[0] __aligned(sizeof(u32));
- };
-
-@@ -102,7 +114,12 @@ struct atmel_sha_ctx {
-
- };
-
--#define ATMEL_SHA_QUEUE_LENGTH 1
-+#define ATMEL_SHA_QUEUE_LENGTH 50
-+
-+struct atmel_sha_dma {
-+ struct dma_chan *chan;
-+ struct dma_slave_config dma_conf;
-+};
-
- struct atmel_sha_dev {
- struct list_head list;
-@@ -119,6 +136,12 @@ struct atmel_sha_dev {
- unsigned long flags;
- struct crypto_queue queue;
- struct ahash_request *req;
-+
-+ struct atmel_sha_dma dma_lch_in;
-+
-+ struct atmel_sha_caps caps;
-+
-+ u32 hw_version;
- };
-
- struct atmel_sha_drv {
-@@ -142,14 +165,6 @@ static inline void atmel_sha_write(struct atmel_sha_dev *dd,
- writel_relaxed(value, dd->io_base + offset);
- }
-
--static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
--{
-- atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
--
-- if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
-- dd->flags |= SHA_FLAGS_DUALBUFF;
--}
--
- static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
- {
- size_t count;
-@@ -193,19 +208,40 @@ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
- static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
- {
- unsigned int index, padlen;
-- u64 bits;
-- u64 size;
--
-- bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
-- size = cpu_to_be64(bits);
--
-- index = ctx->bufcnt & 0x3f;
-- padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-- *(ctx->buffer + ctx->bufcnt) = 0x80;
-- memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
-- memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
-- ctx->bufcnt += padlen + 8;
-- ctx->flags |= SHA_FLAGS_PAD;
-+ u64 bits[2];
-+ u64 size[2];
-+
-+ size[0] = ctx->digcnt[0];
-+ size[1] = ctx->digcnt[1];
-+
-+ size[0] += ctx->bufcnt;
-+ if (size[0] < ctx->bufcnt)
-+ size[1]++;
-+
-+ size[0] += length;
-+ if (size[0] < length)
-+ size[1]++;
-+
-+ bits[1] = cpu_to_be64(size[0] << 3);
-+ bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61);
-+
-+ if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
-+ index = ctx->bufcnt & 0x7f;
-+ padlen = (index < 112) ? (112 - index) : ((128+112) - index);
-+ *(ctx->buffer + ctx->bufcnt) = 0x80;
-+ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
-+ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
-+ ctx->bufcnt += padlen + 16;
-+ ctx->flags |= SHA_FLAGS_PAD;
-+ } else {
-+ index = ctx->bufcnt & 0x3f;
-+ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
-+ *(ctx->buffer + ctx->bufcnt) = 0x80;
-+ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
-+ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
-+ ctx->bufcnt += padlen + 8;
-+ ctx->flags |= SHA_FLAGS_PAD;
-+ }
- }
-
- static int atmel_sha_init(struct ahash_request *req)
-@@ -236,13 +272,35 @@ static int atmel_sha_init(struct ahash_request *req)
- dev_dbg(dd->dev, "init: digest size: %d\n",
- crypto_ahash_digestsize(tfm));
-
-- if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
-+ switch (crypto_ahash_digestsize(tfm)) {
-+ case SHA1_DIGEST_SIZE:
- ctx->flags |= SHA_FLAGS_SHA1;
-- else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
-+ ctx->block_size = SHA1_BLOCK_SIZE;
-+ break;
-+ case SHA224_DIGEST_SIZE:
-+ ctx->flags |= SHA_FLAGS_SHA224;
-+ ctx->block_size = SHA224_BLOCK_SIZE;
-+ break;
-+ case SHA256_DIGEST_SIZE:
- ctx->flags |= SHA_FLAGS_SHA256;
-+ ctx->block_size = SHA256_BLOCK_SIZE;
-+ break;
-+ case SHA384_DIGEST_SIZE:
-+ ctx->flags |= SHA_FLAGS_SHA384;
-+ ctx->block_size = SHA384_BLOCK_SIZE;
-+ break;
-+ case SHA512_DIGEST_SIZE:
-+ ctx->flags |= SHA_FLAGS_SHA512;
-+ ctx->block_size = SHA512_BLOCK_SIZE;
-+ break;
-+ default:
-+ return -EINVAL;
-+ break;
-+ }
-
- ctx->bufcnt = 0;
-- ctx->digcnt = 0;
-+ ctx->digcnt[0] = 0;
-+ ctx->digcnt[1] = 0;
- ctx->buflen = SHA_BUFFER_LEN;
-
- return 0;
-@@ -254,19 +312,28 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
- u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
-
- if (likely(dma)) {
-- atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
-+ if (!dd->caps.has_dma)
-+ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
- valmr = SHA_MR_MODE_PDC;
-- if (dd->flags & SHA_FLAGS_DUALBUFF)
-- valmr = SHA_MR_DUALBUFF;
-+ if (dd->caps.has_dualbuff)
-+ valmr |= SHA_MR_DUALBUFF;
- } else {
- atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
- }
-
-- if (ctx->flags & SHA_FLAGS_SHA256)
-+ if (ctx->flags & SHA_FLAGS_SHA1)
-+ valmr |= SHA_MR_ALGO_SHA1;
-+ else if (ctx->flags & SHA_FLAGS_SHA224)
-+ valmr |= SHA_MR_ALGO_SHA224;
-+ else if (ctx->flags & SHA_FLAGS_SHA256)
- valmr |= SHA_MR_ALGO_SHA256;
-+ else if (ctx->flags & SHA_FLAGS_SHA384)
-+ valmr |= SHA_MR_ALGO_SHA384;
-+ else if (ctx->flags & SHA_FLAGS_SHA512)
-+ valmr |= SHA_MR_ALGO_SHA512;
-
- /* Setting CR_FIRST only for the first iteration */
-- if (!ctx->digcnt)
-+ if (!(ctx->digcnt[0] || ctx->digcnt[1]))
- valcr = SHA_CR_FIRST;
-
- atmel_sha_write(dd, SHA_CR, valcr);
-@@ -280,13 +347,15 @@ static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
- int count, len32;
- const u32 *buffer = (const u32 *)buf;
-
-- dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
-- ctx->digcnt, length, final);
-+ dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
-+ ctx->digcnt[1], ctx->digcnt[0], length, final);
-
- atmel_sha_write_ctrl(dd, 0);
-
- /* should be non-zero before next lines to disable clocks later */
-- ctx->digcnt += length;
-+ ctx->digcnt[0] += length;
-+ if (ctx->digcnt[0] < length)
-+ ctx->digcnt[1]++;
-
- if (final)
- dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
-@@ -307,8 +376,8 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
- struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
- int len32;
-
-- dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
-- ctx->digcnt, length1, final);
-+ dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
-+ ctx->digcnt[1], ctx->digcnt[0], length1, final);
-
- len32 = DIV_ROUND_UP(length1, sizeof(u32));
- atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
-@@ -322,7 +391,9 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
- atmel_sha_write_ctrl(dd, 1);
-
- /* should be non-zero before next lines to disable clocks later */
-- ctx->digcnt += length1;
-+ ctx->digcnt[0] += length1;
-+ if (ctx->digcnt[0] < length1)
-+ ctx->digcnt[1]++;
-
- if (final)
- dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
-@@ -335,6 +406,86 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
- return -EINPROGRESS;
- }
-
-+static void atmel_sha_dma_callback(void *data)
-+{
-+ struct atmel_sha_dev *dd = data;
-+
-+ /* dma_lch_in - completed - wait DATRDY */
-+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
-+}
-+
-+static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
-+ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
-+{
-+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-+ struct dma_async_tx_descriptor *in_desc;
-+ struct scatterlist sg[2];
-+
-+ dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
-+ ctx->digcnt[1], ctx->digcnt[0], length1, final);
-+
-+ if (ctx->flags & (SHA_FLAGS_SHA1 | SHA_FLAGS_SHA224 |
-+ SHA_FLAGS_SHA256)) {
-+ dd->dma_lch_in.dma_conf.src_maxburst = 16;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 16;
-+ } else {
-+ dd->dma_lch_in.dma_conf.src_maxburst = 32;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 32;
-+ }
-+
-+ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
-+
-+ if (length2) {
-+ sg_init_table(sg, 2);
-+ sg_dma_address(&sg[0]) = dma_addr1;
-+ sg_dma_len(&sg[0]) = length1;
-+ sg_dma_address(&sg[1]) = dma_addr2;
-+ sg_dma_len(&sg[1]) = length2;
-+ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2,
-+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ } else {
-+ sg_init_table(sg, 1);
-+ sg_dma_address(&sg[0]) = dma_addr1;
-+ sg_dma_len(&sg[0]) = length1;
-+ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1,
-+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-+ }
-+ if (!in_desc)
-+ return -EINVAL;
-+
-+ in_desc->callback = atmel_sha_dma_callback;
-+ in_desc->callback_param = dd;
-+
-+ atmel_sha_write_ctrl(dd, 1);
-+
-+ /* should be non-zero before next lines to disable clocks later */
-+ ctx->digcnt[0] += length1;
-+ if (ctx->digcnt[0] < length1)
-+ ctx->digcnt[1]++;
-+
-+ if (final)
-+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
-+
-+ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
-+
-+ /* Start DMA transfer */
-+ dmaengine_submit(in_desc);
-+ dma_async_issue_pending(dd->dma_lch_in.chan);
-+
-+ return -EINPROGRESS;
-+}
-+
-+static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
-+ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
-+{
-+ if (dd->caps.has_dma)
-+ return atmel_sha_xmit_dma(dd, dma_addr1, length1,
-+ dma_addr2, length2, final);
-+ else
-+ return atmel_sha_xmit_pdc(dd, dma_addr1, length1,
-+ dma_addr2, length2, final);
-+}
-+
- static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
- {
- struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
-@@ -342,7 +493,6 @@ static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
-
- atmel_sha_append_sg(ctx);
- atmel_sha_fill_padding(ctx, 0);
--
- bufcnt = ctx->bufcnt;
- ctx->bufcnt = 0;
-
-@@ -354,17 +504,17 @@ static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
- size_t length, int final)
- {
- ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
-- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
- if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
- dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
-- SHA1_BLOCK_SIZE);
-+ ctx->block_size);
- return -EINVAL;
- }
-
- ctx->flags &= ~SHA_FLAGS_SG;
-
- /* next call does not fail... so no unmap in the case of error */
-- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
-+ return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final);
- }
-
- static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
-@@ -377,8 +527,8 @@ static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
-
- final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
-
-- dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
-- ctx->bufcnt, ctx->digcnt, final);
-+ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
-+ ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final);
-
- if (final)
- atmel_sha_fill_padding(ctx, 0);
-@@ -405,30 +555,25 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
- if (ctx->bufcnt || ctx->offset)
- return atmel_sha_update_dma_slow(dd);
-
-- dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
-- ctx->digcnt, ctx->bufcnt, ctx->total);
-+ dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
-+ ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total);
-
- sg = ctx->sg;
-
- if (!IS_ALIGNED(sg->offset, sizeof(u32)))
- return atmel_sha_update_dma_slow(dd);
-
-- if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
-- /* size is not SHA1_BLOCK_SIZE aligned */
-+ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size))
-+ /* size is not ctx->block_size aligned */
- return atmel_sha_update_dma_slow(dd);
-
- length = min(ctx->total, sg->length);
-
- if (sg_is_last(sg)) {
- if (!(ctx->flags & SHA_FLAGS_FINUP)) {
-- /* not last sg must be SHA1_BLOCK_SIZE aligned */
-- tail = length & (SHA1_BLOCK_SIZE - 1);
-+ /* not last sg must be ctx->block_size aligned */
-+ tail = length & (ctx->block_size - 1);
- length -= tail;
-- if (length == 0) {
-- /* offset where to start slow */
-- ctx->offset = length;
-- return atmel_sha_update_dma_slow(dd);
-- }
- }
- }
-
-@@ -439,7 +584,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
-
- /* Add padding */
- if (final) {
-- tail = length & (SHA1_BLOCK_SIZE - 1);
-+ tail = length & (ctx->block_size - 1);
- length -= tail;
- ctx->total += tail;
- ctx->offset = length; /* offset where to start slow */
-@@ -450,10 +595,10 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
- atmel_sha_fill_padding(ctx, length);
-
- ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
-- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
- if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
- dev_err(dd->dev, "dma %u bytes error\n",
-- ctx->buflen + SHA1_BLOCK_SIZE);
-+ ctx->buflen + ctx->block_size);
- return -EINVAL;
- }
-
-@@ -461,7 +606,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
- ctx->flags &= ~SHA_FLAGS_SG;
- count = ctx->bufcnt;
- ctx->bufcnt = 0;
-- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
-+ return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0,
- 0, final);
- } else {
- ctx->sg = sg;
-@@ -475,7 +620,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
-
- count = ctx->bufcnt;
- ctx->bufcnt = 0;
-- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
-+ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg),
- length, ctx->dma_addr, count, final);
- }
- }
-@@ -488,7 +633,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
- ctx->flags |= SHA_FLAGS_SG;
-
- /* next call does not fail... so no unmap in the case of error */
-- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
-+ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0,
- 0, final);
- }
-
-@@ -503,12 +648,13 @@ static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
- if (ctx->sg)
- ctx->offset = 0;
- }
-- if (ctx->flags & SHA_FLAGS_PAD)
-+ if (ctx->flags & SHA_FLAGS_PAD) {
- dma_unmap_single(dd->dev, ctx->dma_addr,
-- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
-+ }
- } else {
- dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
-- SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
-+ ctx->block_size, DMA_TO_DEVICE);
- }
-
- return 0;
-@@ -520,8 +666,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
- struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
- int err;
-
-- dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
-- ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
-+ dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n",
-+ ctx->total, ctx->digcnt[1], ctx->digcnt[0]);
-
- if (ctx->flags & SHA_FLAGS_CPU)
- err = atmel_sha_update_cpu(dd);
-@@ -529,8 +675,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
- err = atmel_sha_update_dma_start(dd);
-
- /* wait for dma completion before can take more data */
-- dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
-- err, ctx->digcnt);
-+ dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n",
-+ err, ctx->digcnt[1], ctx->digcnt[0]);
-
- return err;
- }
-@@ -567,12 +713,21 @@ static void atmel_sha_copy_hash(struct ahash_request *req)
- u32 *hash = (u32 *)ctx->digest;
- int i;
-
-- if (likely(ctx->flags & SHA_FLAGS_SHA1))
-+ if (ctx->flags & SHA_FLAGS_SHA1)
- for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-- else
-+ else if (ctx->flags & SHA_FLAGS_SHA224)
-+ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++)
-+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-+ else if (ctx->flags & SHA_FLAGS_SHA256)
- for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
- hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-+ else if (ctx->flags & SHA_FLAGS_SHA384)
-+ for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++)
-+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
-+ else
-+ for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++)
-+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
- }
-
- static void atmel_sha_copy_ready_hash(struct ahash_request *req)
-@@ -582,10 +737,16 @@ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
- if (!req->result)
- return;
-
-- if (likely(ctx->flags & SHA_FLAGS_SHA1))
-+ if (ctx->flags & SHA_FLAGS_SHA1)
- memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
-- else
-+ else if (ctx->flags & SHA_FLAGS_SHA224)
-+ memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE);
-+ else if (ctx->flags & SHA_FLAGS_SHA256)
- memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
-+ else if (ctx->flags & SHA_FLAGS_SHA384)
-+ memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE);
-+ else
-+ memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE);
- }
-
- static int atmel_sha_finish(struct ahash_request *req)
-@@ -594,11 +755,11 @@ static int atmel_sha_finish(struct ahash_request *req)
- struct atmel_sha_dev *dd = ctx->dd;
- int err = 0;
-
-- if (ctx->digcnt)
-+ if (ctx->digcnt[0] || ctx->digcnt[1])
- atmel_sha_copy_ready_hash(req);
-
-- dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
-- ctx->bufcnt);
-+ dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
-+ ctx->digcnt[0], ctx->bufcnt);
-
- return err;
- }
-@@ -633,9 +794,8 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
- {
- clk_prepare_enable(dd->iclk);
-
-- if (SHA_FLAGS_INIT & dd->flags) {
-+ if (!(SHA_FLAGS_INIT & dd->flags)) {
- atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
-- atmel_sha_dualbuff_test(dd);
- dd->flags |= SHA_FLAGS_INIT;
- dd->err = 0;
- }
-@@ -643,6 +803,23 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
- return 0;
- }
-
-+static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd)
-+{
-+ return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff;
-+}
-+
-+static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd)
-+{
-+ atmel_sha_hw_init(dd);
-+
-+ dd->hw_version = atmel_sha_get_version(dd);
-+
-+ dev_info(dd->dev,
-+ "version: 0x%x\n", dd->hw_version);
-+
-+ clk_disable_unprepare(dd->iclk);
-+}
-+
- static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
- struct ahash_request *req)
- {
-@@ -687,10 +864,9 @@ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
-
- if (ctx->op == SHA_OP_UPDATE) {
- err = atmel_sha_update_req(dd);
-- if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
-+ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
- /* no final() after finup() */
- err = atmel_sha_final_req(dd);
-- }
- } else if (ctx->op == SHA_OP_FINAL) {
- err = atmel_sha_final_req(dd);
- }
-@@ -813,7 +989,7 @@ static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
- }
- crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
- sizeof(struct atmel_sha_reqctx) +
-- SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
-+ SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
-
- return 0;
- }
-@@ -831,7 +1007,7 @@ static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
- tctx->fallback = NULL;
- }
-
--static struct ahash_alg sha_algs[] = {
-+static struct ahash_alg sha_1_256_algs[] = {
- {
- .init = atmel_sha_init,
- .update = atmel_sha_update,
-@@ -880,6 +1056,79 @@ static struct ahash_alg sha_algs[] = {
- },
- };
-
-+static struct ahash_alg sha_224_alg = {
-+ .init = atmel_sha_init,
-+ .update = atmel_sha_update,
-+ .final = atmel_sha_final,
-+ .finup = atmel_sha_finup,
-+ .digest = atmel_sha_digest,
-+ .halg = {
-+ .digestsize = SHA224_DIGEST_SIZE,
-+ .base = {
-+ .cra_name = "sha224",
-+ .cra_driver_name = "atmel-sha224",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = SHA224_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
-+ .cra_alignmask = 0,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_sha_cra_init,
-+ .cra_exit = atmel_sha_cra_exit,
-+ }
-+ }
-+};
-+
-+static struct ahash_alg sha_384_512_algs[] = {
-+{
-+ .init = atmel_sha_init,
-+ .update = atmel_sha_update,
-+ .final = atmel_sha_final,
-+ .finup = atmel_sha_finup,
-+ .digest = atmel_sha_digest,
-+ .halg = {
-+ .digestsize = SHA384_DIGEST_SIZE,
-+ .base = {
-+ .cra_name = "sha384",
-+ .cra_driver_name = "atmel-sha384",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = SHA384_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
-+ .cra_alignmask = 0x3,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_sha_cra_init,
-+ .cra_exit = atmel_sha_cra_exit,
-+ }
-+ }
-+},
-+{
-+ .init = atmel_sha_init,
-+ .update = atmel_sha_update,
-+ .final = atmel_sha_final,
-+ .finup = atmel_sha_finup,
-+ .digest = atmel_sha_digest,
-+ .halg = {
-+ .digestsize = SHA512_DIGEST_SIZE,
-+ .base = {
-+ .cra_name = "sha512",
-+ .cra_driver_name = "atmel-sha512",
-+ .cra_priority = 100,
-+ .cra_flags = CRYPTO_ALG_ASYNC |
-+ CRYPTO_ALG_NEED_FALLBACK,
-+ .cra_blocksize = SHA512_BLOCK_SIZE,
-+ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
-+ .cra_alignmask = 0x3,
-+ .cra_module = THIS_MODULE,
-+ .cra_init = atmel_sha_cra_init,
-+ .cra_exit = atmel_sha_cra_exit,
-+ }
-+ }
-+},
-+};
-+
- static void atmel_sha_done_task(unsigned long data)
- {
- struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
-@@ -946,32 +1195,251 @@ static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
- {
- int i;
-
-- for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
-- crypto_unregister_ahash(&sha_algs[i]);
-+ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++)
-+ crypto_unregister_ahash(&sha_1_256_algs[i]);
-+
-+ if (dd->caps.has_sha224)
-+ crypto_unregister_ahash(&sha_224_alg);
-+
-+ if (dd->caps.has_sha_384_512) {
-+ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++)
-+ crypto_unregister_ahash(&sha_384_512_algs[i]);
-+ }
- }
-
- static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
- {
- int err, i, j;
-
-- for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
-- err = crypto_register_ahash(&sha_algs[i]);
-+ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) {
-+ err = crypto_register_ahash(&sha_1_256_algs[i]);
- if (err)
-- goto err_sha_algs;
-+ goto err_sha_1_256_algs;
-+ }
-+
-+ if (dd->caps.has_sha224) {
-+ err = crypto_register_ahash(&sha_224_alg);
-+ if (err)
-+ goto err_sha_224_algs;
-+ }
-+
-+ if (dd->caps.has_sha_384_512) {
-+ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) {
-+ err = crypto_register_ahash(&sha_384_512_algs[i]);
-+ if (err)
-+ goto err_sha_384_512_algs;
-+ }
- }
-
- return 0;
-
--err_sha_algs:
-+err_sha_384_512_algs:
-+ for (j = 0; j < i; j++)
-+ crypto_unregister_ahash(&sha_384_512_algs[j]);
-+ crypto_unregister_ahash(&sha_224_alg);
-+err_sha_224_algs:
-+ i = ARRAY_SIZE(sha_1_256_algs);
-+err_sha_1_256_algs:
- for (j = 0; j < i; j++)
-- crypto_unregister_ahash(&sha_algs[j]);
-+ crypto_unregister_ahash(&sha_1_256_algs[j]);
-
- return err;
- }
-
-+static bool atmel_sha_filter(struct dma_chan *chan, void *slave)
-+{
-+ struct at_dma_slave *sl = slave;
-+
-+ if (sl && sl->dma_dev == chan->device->dev) {
-+ chan->private = sl;
-+ return true;
-+ } else {
-+ return false;
-+ }
-+}
-+
-+static int atmel_sha_dma_init(struct atmel_sha_dev *dd,
-+ struct crypto_platform_data *pdata)
-+{
-+ int err = -ENOMEM;
-+ dma_cap_mask_t mask_in;
-+
-+ if (pdata && pdata->dma_slave->rxdata.dma_dev) {
-+ /* Try to grab DMA channel */
-+ dma_cap_zero(mask_in);
-+ dma_cap_set(DMA_SLAVE, mask_in);
-+
-+ dd->dma_lch_in.chan = dma_request_channel(mask_in,
-+ atmel_sha_filter, &pdata->dma_slave->rxdata);
-+
-+ if (!dd->dma_lch_in.chan)
-+ return err;
-+
-+ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
-+ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
-+ SHA_REG_DIN(0);
-+ dd->dma_lch_in.dma_conf.src_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.src_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
-+ dd->dma_lch_in.dma_conf.dst_addr_width =
-+ DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ dd->dma_lch_in.dma_conf.device_fc = false;
-+
-+ return 0;
-+ }
-+
-+ return -ENODEV;
-+}
-+
-+static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd)
-+{
-+ dma_release_channel(dd->dma_lch_in.chan);
-+}
-+
-+
-+#ifdef CONFIG_OF
-+static const struct of_device_id atmel_sha_dt_ids[] = {
-+ { .compatible = "atmel,sam9g46-sha" },
-+ { /* sentinel */ }
-+};
-+
-+MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids);
-+
-+static int atmel_sha_dma_of_init(struct device_node *np,
-+ struct at_dma_slave *atslave)
-+{
-+ struct of_phandle_args dma_spec;
-+ struct device_node *dmac_np;
-+ struct platform_device *dmac_pdev;
-+ const __be32 *nbcells;
-+ int ret;
-+
-+ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
-+ if (ret || !dma_spec.np) {
-+ pr_err("%s: can't parse dma property (%d)\n",
-+ np->full_name, ret);
-+ goto err0;
-+ }
-+ dmac_np = dma_spec.np;
-+
-+ /* check property format */
-+ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
-+ if (!nbcells) {
-+ pr_err("%s: #dma-cells property is required\n", np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ if (dma_spec.args_count != be32_to_cpup(nbcells)
-+ || dma_spec.args_count != 1) {
-+ pr_err("%s: wrong #dma-cells for %s\n",
-+ np->full_name, dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* retreive DMA controller information */
-+ dmac_pdev = of_find_device_by_node(dmac_np);
-+ if (!dmac_pdev) {
-+ pr_err("%s: unable to find pdev from DMA controller\n",
-+ dmac_np->full_name);
-+ ret = -EINVAL;
-+ goto err1;
-+ }
-+
-+ /* now fill in the at_dma_slave structure */
-+ atslave->dma_dev = &dmac_pdev->dev;
-+ atslave->cfg = dma_spec.args[0];
-+
-+err1:
-+ of_node_put(dma_spec.np);
-+err0:
-+ pr_debug("%s exited with status %d\n", __func__, ret);
-+ return ret;
-+}
-+
-+
-+static struct crypto_platform_data __devinit*
-+atmel_sha_of_init(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct crypto_platform_data *pdata;
-+ struct at_dma_slave *atslave;
-+
-+ if (!np) {
-+ dev_err(&pdev->dev, "device node not found\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-+ if (!pdata) {
-+ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ pdata->dma_slave = devm_kzalloc(&pdev->dev,
-+ sizeof(*(pdata->dma_slave)),
-+ GFP_KERNEL);
-+ if (!pdata->dma_slave) {
-+ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ atslave = &pdata->dma_slave->rxdata;
-+ /* retrieve RX DMA configuration first */
-+ if (atmel_sha_dma_of_init(np, atslave)) {
-+ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
-+ devm_kfree(&pdev->dev, pdata->dma_slave);
-+ devm_kfree(&pdev->dev, pdata);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return pdata;
-+}
-+#else /* CONFIG_OF */
-+static inline struct crypto_platform_data*
-+atmel_sha_of_init(struct platform_device *dev)
-+{
-+ return ERR_PTR(-EINVAL);
-+}
-+#endif
-+
-+static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
-+{
-+
-+ dd->caps.has_dma = 0;
-+ dd->caps.has_dualbuff = 0;
-+ dd->caps.has_sha224 = 0;
-+ dd->caps.has_sha_384_512 = 0;
-+
-+ /* keep only major version number */
-+ switch (dd->hw_version & 0xff0) {
-+ case 0x410:
-+ dd->caps.has_dma = 1;
-+ dd->caps.has_dualbuff = 1;
-+ dd->caps.has_sha224 = 1;
-+ dd->caps.has_sha_384_512 = 1;
-+ break;
-+ case 0x400:
-+ dd->caps.has_dma = 1;
-+ dd->caps.has_dualbuff = 1;
-+ dd->caps.has_sha224 = 1;
-+ break;
-+ case 0x320:
-+ break;
-+ default:
-+ dev_warn(dd->dev,
-+ "Unmanaged sha version, set minimum capabilities\n");
-+ break;
-+ }
-+}
-+
- static int __devinit atmel_sha_probe(struct platform_device *pdev)
- {
- struct atmel_sha_dev *sha_dd;
-+ struct crypto_platform_data *pdata;
- struct device *dev = &pdev->dev;
- struct resource *sha_res;
- unsigned long sha_phys_size;
-@@ -1023,7 +1491,7 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
- }
-
- /* Initializing the clock */
-- sha_dd->iclk = clk_get(&pdev->dev, NULL);
-+ sha_dd->iclk = clk_get(&pdev->dev, "sha_clk");
- if (IS_ERR(sha_dd->iclk)) {
- dev_err(dev, "clock intialization failed.\n");
- err = PTR_ERR(sha_dd->iclk);
-@@ -1037,6 +1505,24 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
- goto sha_io_err;
- }
-
-+ atmel_sha_hw_version_init(sha_dd);
-+
-+ atmel_sha_get_cap(sha_dd);
-+
-+ if (sha_dd->caps.has_dma) {
-+ pdata = pdev->dev.platform_data;
-+ if (!pdata) {
-+ pdata = atmel_sha_of_init(pdev);
-+ if (IS_ERR(pdata)) {
-+ dev_err(&pdev->dev, "platform data not available\n");
-+ goto err_pdata;
-+ }
-+ }
-+ err = atmel_sha_dma_init(sha_dd, pdata);
-+ if (err)
-+ goto err_sha_dma;
-+ }
-+
- spin_lock(&atmel_sha.lock);
- list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
- spin_unlock(&atmel_sha.lock);
-@@ -1053,6 +1539,10 @@ err_algs:
- spin_lock(&atmel_sha.lock);
- list_del(&sha_dd->list);
- spin_unlock(&atmel_sha.lock);
-+ if (sha_dd->caps.has_dma)
-+ atmel_sha_dma_cleanup(sha_dd);
-+err_sha_dma:
-+err_pdata:
- iounmap(sha_dd->io_base);
- sha_io_err:
- clk_put(sha_dd->iclk);
-@@ -1083,6 +1573,9 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
-
- tasklet_kill(&sha_dd->done_task);
-
-+ if (sha_dd->caps.has_dma)
-+ atmel_sha_dma_cleanup(sha_dd);
-+
- iounmap(sha_dd->io_base);
-
- clk_put(sha_dd->iclk);
-@@ -1097,15 +1590,28 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
- }
-
- static struct platform_driver atmel_sha_driver = {
-- .probe = atmel_sha_probe,
- .remove = __devexit_p(atmel_sha_remove),
- .driver = {
- .name = "atmel_sha",
-+ .of_match_table = of_match_ptr(atmel_sha_dt_ids),
- .owner = THIS_MODULE,
- },
- };
-
--module_platform_driver(atmel_sha_driver);
-+static int __init atmel_sha_drv_init(void)
-+{
-+ return platform_driver_probe(&atmel_sha_driver, atmel_sha_probe);
-+}
-+
-+static void __exit atmel_sha_drv_exit(void)
-+{
-+ platform_driver_unregister(&atmel_sha_driver);
-+}
-+
-+/* try to load after dma driver when built-in */
-+late_initcall(atmel_sha_drv_init);
-+module_exit(atmel_sha_drv_exit);
-+
-
- MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
- MODULE_LICENSE("GPL v2");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 245b4491a6575ca148b06d29400c1f87bc9408d8 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 19:04:39 +0200
+Subject: ARM: at91: add new at91sam9g35ek.dts
+
+With LCD DT definition
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g35ek.dts | 49 +++++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 15 ++++++++++++
+ arch/arm/mach-at91/Makefile.boot | 1 +
+ 3 files changed, 65 insertions(+)
+ create mode 100644 arch/arm/boot/dts/at91sam9g35ek.dts
+
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+new file mode 100644
+index 0000000..f2c3341
+--- /dev/null
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -0,0 +1,49 @@
++/*
++ * at91sam9g35ek.dts - Device Tree file for AT91SAM9G35-EK board
++ *
++ * Copyright (C) 2012 Atmel,
++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
++ *
++ * Licensed under GPLv2 or later.
++ */
++/dts-v1/;
++/include/ "at91sam9x5_common.dtsi"
++
++/ {
++ model = "Atmel AT91SAM9G35-EK";
++ compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
++
++ chosen {
++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
++ };
++
++ ahb {
++ apb {
++ mmc1: mmc@f000c000 {
++ status = "okay";
++ slot@0 {
++ reg = <0>;
++ bus-width = <4>;
++ cd-gpios = <&pioD 14 0>;
++ };
++ };
++
++ usart0: serial@f801c000 {
++ status = "okay";
++ };
++
++ macb0: ethernet@f802c000 {
++ phy-mode = "rmii";
++ status = "okay";
++ };
++
++ lcd@f8038000 {
++ status = "okay";
++ };
++
++ lcdovl1@f8038100 {
++ status = "okay";
++ };
++ };
++ };
++};
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 2cefd49..50388fd 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -250,6 +250,21 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ lcd@f8038000 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038000 0xff
++ 0xf8038400 0x3ff>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
++
++ lcdovl1@f8038100 {
++ compatible = "atmel,at91sam9x5-lcd";
++ reg = <0xf8038100 0xff
++ 0xf8038800 0x3ff>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
+index 9532f93..410485a 100644
+--- a/arch/arm/mach-at91/Makefile.boot
++++ b/arch/arm/mach-at91/Makefile.boot
+@@ -34,4 +34,5 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
+ # sam9x5
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g35ek.dtb
+ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 352ab878f8ee1afe1f15dc14bb8c9ced486f5316 Mon Sep 17 00:00:00 2001
-From: Nicolas Royer <nicolas@eukrea.com>
-Date: Mon, 17 Sep 2012 18:26:18 +0200
-Subject: crypto: Atmel Test; add SHA224, SHA384 and SHA512 support
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Eric Bénard <eric@eukrea.com>
-Tested-by: Eric Bénard <eric@eukrea.com>
----
- drivers/crypto/atmel-test.c | 25 +++++++++++++++++++------
- 1 file changed, 19 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
-index 4a23db5..d9eb80d 100644
---- a/drivers/crypto/atmel-test.c
-+++ b/drivers/crypto/atmel-test.c
-@@ -41,7 +41,11 @@ static char *iv16 =
-
- #define SHA1_MSG_LEN 20
- #define SHA256_MSG_LEN 32
--static char sha_out_buf[SHA256_MSG_LEN];
-+#define SHA224_MSG_LEN 28
-+#define SHA384_MSG_LEN 48
-+#define SHA512_MSG_LEN 64
-+
-+static char sha_out_buf[SHA512_MSG_LEN];
-
- #define TVMEMSIZE 4
- static char *tvmem[TVMEMSIZE];
-@@ -331,7 +335,7 @@ static int dlen = 64;
- module_param_named(dlen, dlen, int,
- S_IRUGO | S_IWUSR | S_IWGRP);
-
--char *ahash_algs[] = {"sha1", "sha256"};
-+char *ahash_algs[] = {"sha1", "sha256", "sha224", "sha384", "sha512"};
-
- char *acipher_algs[] = {
- "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
-@@ -347,6 +351,7 @@ static int __init init_main(void)
- char *buf_in;
- char *buf_out;
- char *buf_res;
-+ size_t outlen;
-
- if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
- printk(KERN_ERR " 0 < dlen <= %i\n",
-@@ -382,15 +387,23 @@ static int __init init_main(void)
- ARRAY_SIZE(ahash_algs));
- goto exit;
- }
-+ switch (mode) {
-+ case 0:outlen = SHA1_MSG_LEN; break;
-+ case 1:outlen = SHA256_MSG_LEN; break;
-+ case 2:outlen = SHA224_MSG_LEN; break;
-+ case 3:outlen = SHA384_MSG_LEN; break;
-+ case 4:outlen = SHA512_MSG_LEN; break;
-+ }
-+
- printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
- hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
-- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+ outlen);
-+ hexdump(sha_out_buf, outlen);
-
- printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
- hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
-- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
-+ outlen);
-+ hexdump(sha_out_buf, outlen);
- } else {
- mode -= 10;
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From f0e81f4a05048c4b863e2b3afd5b114e489a7887 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Tue, 16 Oct 2012 19:05:25 +0200
+Subject: ARM: at91: add pinmux for 9x5 LCD
+
+Temporaty in board-dt
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/mach-at91/board-dt.c | 102 +++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 101 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index 15830cb..c0d242c 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -26,6 +26,103 @@
+
+ #include "generic.h"
+
++#include <linux/fb.h>
++
++#include <video/atmel_lcdfb.h>
++#include <mach/atmel_hlcdc.h>
++
++/*
++ * LCD Controller
++ */
++static struct fb_videomode at91_tft_vga_modes[] = {
++ {
++ .name = "LG",
++ .refresh = 60,
++ .xres = 800, .yres = 480,
++ .pixclock = KHZ2PICOS(33260),
++
++ .left_margin = 88, .right_margin = 168,
++ .upper_margin = 8, .lower_margin = 37,
++ .hsync_len = 128, .vsync_len = 2,
++
++ .sync = 0,
++ .vmode = FB_VMODE_NONINTERLACED,
++ },
++};
++
++static struct fb_monspecs at91fb_default_monspecs = {
++ .manufacturer = "LG",
++ .monitor = "LB043WQ1",
++
++ .modedb = at91_tft_vga_modes,
++ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
++ .hfmin = 15000,
++ .hfmax = 17640,
++ .vfmin = 57,
++ .vfmax = 67,
++};
++
++/* Default output mode is TFT 24 bit */
++#define BPP_OUT_DEFAULT_LCDCFG5 (LCDC_LCDCFG5_MODE_OUTPUT_24BPP)
++
++/* Driver datas */
++static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
++ .lcdcon_is_backlight = true,
++ .alpha_enabled = false,
++ .default_bpp = 16,
++ /* Reserve enough memory for 32bpp */
++ .smem_len = 800 * 480 * 4,
++ /* default_lcdcon2 is used for LCDCFG5 */
++ .default_lcdcon2 = BPP_OUT_DEFAULT_LCDCFG5,
++ .default_monspecs = &at91fb_default_monspecs,
++ .guard_time = 9,
++ .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
++};
++
++void __init at91sam9x5_pinmux_lcd(void)
++{
++ at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDPWM */
++
++ at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDVSYNC */
++ at91_set_A_periph(AT91_PIN_PC28, 0); /* LCDHSYNC */
++
++ at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDDISP */
++ at91_set_A_periph(AT91_PIN_PC29, 0); /* LCDDEN */
++ at91_set_A_periph(AT91_PIN_PC30, 0); /* LCDPCK */
++
++ at91_set_A_periph(AT91_PIN_PC0, 0); /* LCDD0 */
++ at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDD1 */
++ at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDD2 */
++ at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDD3 */
++ at91_set_A_periph(AT91_PIN_PC4, 0); /* LCDD4 */
++ at91_set_A_periph(AT91_PIN_PC5, 0); /* LCDD5 */
++ at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD6 */
++ at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD7 */
++ at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD8 */
++ at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD9 */
++ at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD10 */
++ at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD11 */
++ at91_set_A_periph(AT91_PIN_PC12, 0); /* LCDD12 */
++ at91_set_A_periph(AT91_PIN_PC13, 0); /* LCDD13 */
++ at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD14 */
++ at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD15 */
++ at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD16 */
++ at91_set_A_periph(AT91_PIN_PC17, 0); /* LCDD17 */
++ at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD18 */
++ at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD19 */
++ at91_set_A_periph(AT91_PIN_PC20, 0); /* LCDD20 */
++ at91_set_A_periph(AT91_PIN_PC21, 0); /* LCDD21 */
++ at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD22 */
++ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD23 */
++
++ printk("AT91: lcd pin mux done\n");
++}
++
++struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
++ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038000, "atmel_hlcdfb_base", &ek_lcdc_data),
++ OF_DEV_AUXDATA("atmel,at91sam9x5-lcd", 0xf8038100, "atmel_hlcdfb_ovl", &ek_lcdc_data),
++ { /* sentinel */ }
++};
+
+ static const struct of_device_id irq_of_match[] __initconst = {
+
+@@ -42,7 +139,6 @@ static void __init at91_dt_init_irq(void)
+
+ static void __init at91_dt_device_init(void)
+ {
+- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ /* Temporary pin mux stuff */
+ if (of_machine_is_compatible("atmel,at91sam9x5")) {
+ at91_set_A_periph(AT91_PIN_PA30, 0); /* TWD */
+@@ -74,7 +170,11 @@ static void __init at91_dt_device_init(void)
+ at91_set_B_periph(AT91_PIN_PA3, 1);
+ at91_set_B_periph(AT91_PIN_PA4, 1);
+ printk("AT91: mci0/1 pin mux done\n");
++
++ at91sam9x5_pinmux_lcd();
+ }
++
++ of_platform_populate(NULL, of_default_bus_match_table, at91_auxdata_lookup, NULL);
+ }
+
+ static const char *at91_dt_board_compat[] __initdata = {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From f67e075c4847120d480cd6347da04359f4fd7f8c Mon Sep 17 00:00:00 2001
-From: Stephen Warren <swarren@wwwdotorg.org>
-Date: Fri, 23 Mar 2012 10:29:46 -0600
-Subject: pinctrl: core device tree mapping table parsing support
-
-During pinctrl_get(), if the client device has a device tree node, look
-for the common pinctrl properties there. If found, parse the referenced
-device tree nodes, with the help of the pinctrl drivers, and generate
-mapping table entries from them.
-
-During pinctrl_put(), free any results of device tree parsing.
-
-Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/Makefile | 1 +
- drivers/pinctrl/core.c | 72 +++++++++---
- drivers/pinctrl/core.h | 11 +-
- drivers/pinctrl/devicetree.c | 249 ++++++++++++++++++++++++++++++++++++++++
- drivers/pinctrl/devicetree.h | 35 ++++++
- include/linux/pinctrl/pinctrl.h | 7 ++
- 6 files changed, 357 insertions(+), 18 deletions(-)
- create mode 100644 drivers/pinctrl/devicetree.c
- create mode 100644 drivers/pinctrl/devicetree.h
-
-diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
-index 6d4150b..049c9fb 100644
---- a/drivers/pinctrl/Makefile
-+++ b/drivers/pinctrl/Makefile
-@@ -5,6 +5,7 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
- obj-$(CONFIG_PINCTRL) += core.o
- obj-$(CONFIG_PINMUX) += pinmux.o
- obj-$(CONFIG_PINCONF) += pinconf.o
-+obj-$(CONFIG_OF) += devicetree.o
- obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
- obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
- obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index df6296c..832f71d 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -26,6 +26,7 @@
- #include <linux/pinctrl/pinctrl.h>
- #include <linux/pinctrl/machine.h>
- #include "core.h"
-+#include "devicetree.h"
- #include "pinmux.h"
- #include "pinconf.h"
-
-@@ -45,7 +46,7 @@ struct pinctrl_maps {
- DEFINE_MUTEX(pinctrl_mutex);
-
- /* Global list of pin control devices (struct pinctrl_dev) */
--static LIST_HEAD(pinctrldev_list);
-+LIST_HEAD(pinctrldev_list);
-
- /* List of pin controller handles (struct pinctrl) */
- static LIST_HEAD(pinctrl_list);
-@@ -579,6 +580,13 @@ static struct pinctrl *create_pinctrl(struct device *dev)
- }
- p->dev = dev;
- INIT_LIST_HEAD(&p->states);
-+ INIT_LIST_HEAD(&p->dt_maps);
-+
-+ ret = pinctrl_dt_to_map(p);
-+ if (ret < 0) {
-+ kfree(p);
-+ return ERR_PTR(ret);
-+ }
-
- devname = dev_name(dev);
-
-@@ -662,6 +670,8 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
- kfree(state);
- }
-
-+ pinctrl_dt_free_maps(p);
-+
- if (inlist)
- list_del(&p->node);
- kfree(p);
-@@ -787,15 +797,8 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
- }
- EXPORT_SYMBOL_GPL(pinctrl_select_state);
-
--/**
-- * pinctrl_register_mappings() - register a set of pin controller mappings
-- * @maps: the pincontrol mappings table to register. This should probably be
-- * marked with __initdata so it can be discarded after boot. This
-- * function will perform a shallow copy for the mapping entries.
-- * @num_maps: the number of maps in the mapping table
-- */
--int pinctrl_register_mappings(struct pinctrl_map const *maps,
-- unsigned num_maps)
-+int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
-+ bool dup, bool locked)
- {
- int i, ret;
- struct pinctrl_maps *maps_node;
-@@ -851,20 +854,52 @@ int pinctrl_register_mappings(struct pinctrl_map const *maps,
- }
-
- maps_node->num_maps = num_maps;
-- maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps, GFP_KERNEL);
-- if (!maps_node->maps) {
-- pr_err("failed to duplicate mapping table\n");
-- kfree(maps_node);
-- return -ENOMEM;
-+ if (dup) {
-+ maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
-+ GFP_KERNEL);
-+ if (!maps_node->maps) {
-+ pr_err("failed to duplicate mapping table\n");
-+ kfree(maps_node);
-+ return -ENOMEM;
-+ }
-+ } else {
-+ maps_node->maps = maps;
- }
-
-- mutex_lock(&pinctrl_mutex);
-+ if (!locked)
-+ mutex_lock(&pinctrl_mutex);
- list_add_tail(&maps_node->node, &pinctrl_maps);
-- mutex_unlock(&pinctrl_mutex);
-+ if (!locked)
-+ mutex_unlock(&pinctrl_mutex);
-
- return 0;
- }
-
-+/**
-+ * pinctrl_register_mappings() - register a set of pin controller mappings
-+ * @maps: the pincontrol mappings table to register. This should probably be
-+ * marked with __initdata so it can be discarded after boot. This
-+ * function will perform a shallow copy for the mapping entries.
-+ * @num_maps: the number of maps in the mapping table
-+ */
-+int pinctrl_register_mappings(struct pinctrl_map const *maps,
-+ unsigned num_maps)
-+{
-+ return pinctrl_register_map(maps, num_maps, true, false);
-+}
-+
-+void pinctrl_unregister_map(struct pinctrl_map const *map)
-+{
-+ struct pinctrl_maps *maps_node;
-+
-+ list_for_each_entry(maps_node, &pinctrl_maps, node) {
-+ if (maps_node->maps == map) {
-+ list_del(&maps_node->node);
-+ return;
-+ }
-+ }
-+}
-+
- #ifdef CONFIG_DEBUG_FS
-
- static int pinctrl_pins_show(struct seq_file *s, void *what)
-@@ -1231,6 +1266,9 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
- !ops->get_group_pins)
- return -EINVAL;
-
-+ if (ops->dt_node_to_map && !ops->dt_free_map)
-+ return -EINVAL;
-+
- return 0;
- }
-
-diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
-index 17ecf65..98ae808 100644
---- a/drivers/pinctrl/core.h
-+++ b/drivers/pinctrl/core.h
-@@ -52,12 +52,15 @@ struct pinctrl_dev {
- * @dev: the device using this pin control handle
- * @states: a list of states for this device
- * @state: the current state
-+ * @dt_maps: the mapping table chunks dynamically parsed from device tree for
-+ * this device, if any
- */
- struct pinctrl {
- struct list_head node;
- struct device *dev;
- struct list_head states;
- struct pinctrl_state *state;
-+ struct list_head dt_maps;
- };
-
- /**
-@@ -100,7 +103,8 @@ struct pinctrl_setting_configs {
- * struct pinctrl_setting - an individual mux or config setting
- * @node: list node for struct pinctrl_settings's @settings field
- * @type: the type of setting
-- * @pctldev: pin control device handling to be programmed
-+ * @pctldev: pin control device handling to be programmed. Not used for
-+ * PIN_MAP_TYPE_DUMMY_STATE.
- * @data: Data specific to the setting type
- */
- struct pinctrl_setting {
-@@ -153,4 +157,9 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
- return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
- }
-
-+int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
-+ bool dup, bool locked);
-+void pinctrl_unregister_map(struct pinctrl_map const *map);
-+
- extern struct mutex pinctrl_mutex;
-+extern struct list_head pinctrldev_list;
-diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
-new file mode 100644
-index 0000000..5ef2feb
---- /dev/null
-+++ b/drivers/pinctrl/devicetree.c
-@@ -0,0 +1,249 @@
-+/*
-+ * Device tree integration for the pin control subsystem
-+ *
-+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms and conditions of the GNU General Public License,
-+ * version 2, as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/of.h>
-+#include <linux/pinctrl/pinctrl.h>
-+#include <linux/slab.h>
-+
-+#include "core.h"
-+#include "devicetree.h"
-+
-+/**
-+ * struct pinctrl_dt_map - mapping table chunk parsed from device tree
-+ * @node: list node for struct pinctrl's @dt_maps field
-+ * @pctldev: the pin controller that allocated this struct, and will free it
-+ * @maps: the mapping table entries
-+ */
-+struct pinctrl_dt_map {
-+ struct list_head node;
-+ struct pinctrl_dev *pctldev;
-+ struct pinctrl_map *map;
-+ unsigned num_maps;
-+};
-+
-+static void dt_free_map(struct pinctrl_dev *pctldev,
-+ struct pinctrl_map *map, unsigned num_maps)
-+{
-+ if (pctldev) {
-+ struct pinctrl_ops *ops = pctldev->desc->pctlops;
-+ ops->dt_free_map(pctldev, map, num_maps);
-+ } else {
-+ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
-+ kfree(map);
-+ }
-+}
-+
-+void pinctrl_dt_free_maps(struct pinctrl *p)
-+{
-+ struct pinctrl_dt_map *dt_map, *n1;
-+
-+ list_for_each_entry_safe(dt_map, n1, &p->dt_maps, node) {
-+ pinctrl_unregister_map(dt_map->map);
-+ list_del(&dt_map->node);
-+ dt_free_map(dt_map->pctldev, dt_map->map,
-+ dt_map->num_maps);
-+ kfree(dt_map);
-+ }
-+
-+ of_node_put(p->dev->of_node);
-+}
-+
-+static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
-+ struct pinctrl_dev *pctldev,
-+ struct pinctrl_map *map, unsigned num_maps)
-+{
-+ int i;
-+ struct pinctrl_dt_map *dt_map;
-+
-+ /* Initialize common mapping table entry fields */
-+ for (i = 0; i < num_maps; i++) {
-+ map[i].dev_name = dev_name(p->dev);
-+ map[i].name = statename;
-+ if (pctldev)
-+ map[i].ctrl_dev_name = dev_name(pctldev->dev);
-+ }
-+
-+ /* Remember the converted mapping table entries */
-+ dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
-+ if (!dt_map) {
-+ dev_err(p->dev, "failed to alloc struct pinctrl_dt_map\n");
-+ dt_free_map(pctldev, map, num_maps);
-+ return -ENOMEM;
-+ }
-+
-+ dt_map->pctldev = pctldev;
-+ dt_map->map = map;
-+ dt_map->num_maps = num_maps;
-+ list_add_tail(&dt_map->node, &p->dt_maps);
-+
-+ return pinctrl_register_map(map, num_maps, false, true);
-+}
-+
-+static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
-+{
-+ struct pinctrl_dev *pctldev;
-+
-+ list_for_each_entry(pctldev, &pinctrldev_list, node)
-+ if (pctldev->dev->of_node == np)
-+ return pctldev;
-+
-+ return NULL;
-+}
-+
-+static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
-+ struct device_node *np_config)
-+{
-+ struct device_node *np_pctldev;
-+ struct pinctrl_dev *pctldev;
-+ struct pinctrl_ops *ops;
-+ int ret;
-+ struct pinctrl_map *map;
-+ unsigned num_maps;
-+
-+ /* Find the pin controller containing np_config */
-+ np_pctldev = of_node_get(np_config);
-+ for (;;) {
-+ np_pctldev = of_get_next_parent(np_pctldev);
-+ if (!np_pctldev || of_node_is_root(np_pctldev)) {
-+ dev_err(p->dev, "could not find pctldev for node %s\n",
-+ np_config->full_name);
-+ of_node_put(np_pctldev);
-+ /* FIXME: This should trigger deferrered probe */
-+ return -ENODEV;
-+ }
-+ pctldev = find_pinctrl_by_of_node(np_pctldev);
-+ if (pctldev)
-+ break;
-+ }
-+ of_node_put(np_pctldev);
-+
-+ /*
-+ * Call pinctrl driver to parse device tree node, and
-+ * generate mapping table entries
-+ */
-+ ops = pctldev->desc->pctlops;
-+ if (!ops->dt_node_to_map) {
-+ dev_err(p->dev, "pctldev %s doesn't support DT\n",
-+ dev_name(pctldev->dev));
-+ return -ENODEV;
-+ }
-+ ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* Stash the mapping table chunk away for later use */
-+ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
-+}
-+
-+static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
-+{
-+ struct pinctrl_map *map;
-+
-+ map = kzalloc(sizeof(*map), GFP_KERNEL);
-+ if (!map) {
-+ dev_err(p->dev, "failed to alloc struct pinctrl_map\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
-+ map->type = PIN_MAP_TYPE_DUMMY_STATE;
-+
-+ return dt_remember_or_free_map(p, statename, NULL, map, 1);
-+}
-+
-+int pinctrl_dt_to_map(struct pinctrl *p)
-+{
-+ struct device_node *np = p->dev->of_node;
-+ int state, ret;
-+ char *propname;
-+ struct property *prop;
-+ const char *statename;
-+ const __be32 *list;
-+ int size, config;
-+ phandle phandle;
-+ struct device_node *np_config;
-+
-+ /* CONFIG_OF enabled, p->dev not instantiated from DT */
-+ if (!np) {
-+ dev_dbg(p->dev, "no of_node; not parsing pinctrl DT\n");
-+ return 0;
-+ }
-+
-+ /* We may store pointers to property names within the node */
-+ of_node_get(np);
-+
-+ /* For each defined state ID */
-+ for (state = 0; ; state++) {
-+ /* Retrieve the pinctrl-* property */
-+ propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
-+ prop = of_find_property(np, propname, &size);
-+ kfree(propname);
-+ if (!prop)
-+ break;
-+ list = prop->value;
-+ size /= sizeof(*list);
-+
-+ /* Determine whether pinctrl-names property names the state */
-+ ret = of_property_read_string_index(np, "pinctrl-names",
-+ state, &statename);
-+ /*
-+ * If not, statename is just the integer state ID. But rather
-+ * than dynamically allocate it and have to free it later,
-+ * just point part way into the property name for the string.
-+ */
-+ if (ret < 0) {
-+ /* strlen("pinctrl-") == 8 */
-+ statename = prop->name + 8;
-+ }
-+
-+ /* For every referenced pin configuration node in it */
-+ for (config = 0; config < size; config++) {
-+ phandle = be32_to_cpup(list++);
-+
-+ /* Look up the pin configuration node */
-+ np_config = of_find_node_by_phandle(phandle);
-+ if (!np_config) {
-+ dev_err(p->dev,
-+ "prop %s index %i invalid phandle\n",
-+ prop->name, config);
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ /* Parse the node */
-+ ret = dt_to_map_one_config(p, statename, np_config);
-+ of_node_put(np_config);
-+ if (ret < 0)
-+ goto err;
-+ }
-+
-+ /* No entries in DT? Generate a dummy state table entry */
-+ if (!size) {
-+ ret = dt_remember_dummy_state(p, statename);
-+ if (ret < 0)
-+ goto err;
-+ }
-+ }
-+
-+ return 0;
-+
-+err:
-+ pinctrl_dt_free_maps(p);
-+ return ret;
-+}
-diff --git a/drivers/pinctrl/devicetree.h b/drivers/pinctrl/devicetree.h
-new file mode 100644
-index 0000000..760bc49
---- /dev/null
-+++ b/drivers/pinctrl/devicetree.h
-@@ -0,0 +1,35 @@
-+/*
-+ * Internal interface to pinctrl device tree integration
-+ *
-+ * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms and conditions of the GNU General Public License,
-+ * version 2, as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope it will be useful, but WITHOUT
-+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ * more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifdef CONFIG_OF
-+
-+void pinctrl_dt_free_maps(struct pinctrl *p);
-+int pinctrl_dt_to_map(struct pinctrl *p);
-+
-+#else
-+
-+static inline int pinctrl_dt_to_map(struct pinctrl *p)
-+{
-+ return 0;
-+}
-+
-+static inline void pinctrl_dt_free_maps(struct pinctrl *p)
-+{
-+}
-+
-+#endif
-diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
-index 4e9f078..aa92cde 100644
---- a/include/linux/pinctrl/pinctrl.h
-+++ b/include/linux/pinctrl/pinctrl.h
-@@ -21,9 +21,11 @@
-
- struct device;
- struct pinctrl_dev;
-+struct pinctrl_map;
- struct pinmux_ops;
- struct pinconf_ops;
- struct gpio_chip;
-+struct device_node;
-
- /**
- * struct pinctrl_pin_desc - boards/machines provide information on their
-@@ -83,6 +85,11 @@ struct pinctrl_ops {
- unsigned *num_pins);
- void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
- unsigned offset);
-+ int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
-+ struct device_node *np_config,
-+ struct pinctrl_map **map, unsigned *num_maps);
-+ void (*dt_free_map) (struct pinctrl_dev *pctldev,
-+ struct pinctrl_map *map, unsigned num_maps);
- };
-
- /**
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From d97e19aab9e85eb9c7acd60af983a82f8384d702 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Wed, 17 Oct 2012 10:14:48 +0200
+Subject: ARM: at91: add LCD HEO DT entry for at91sam9x5
+
+At91sam9x5.dtsi entry and activated in sam9g35ek.dts.
+
+Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+---
+ arch/arm/boot/dts/at91sam9g35ek.dts | 4 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 7 +++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
+index f2c3341..0cb762e 100644
+--- a/arch/arm/boot/dts/at91sam9g35ek.dts
++++ b/arch/arm/boot/dts/at91sam9g35ek.dts
+@@ -44,6 +44,10 @@
+ lcdovl1@f8038100 {
+ status = "okay";
+ };
++
++ lcdheo1@f8038280 {
++ status = "okay";
++ };
+ };
+ };
+ };
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 50388fd..027b9eb 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -265,6 +265,13 @@
+ 0xf8038800 0x3ff>;
+ status = "disabled";
+ };
++
++ lcdheo1@f8038280 {
++ compatible = "atmel,at91sam9x5-heo";
++ reg = <0xf8038280 0xbf>;
++ interrupts = <25 4 3>;
++ status = "disabled";
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 71404155915a36c279030254266350255058b89a Mon Sep 17 00:00:00 2001
-From: Stephen Warren <swarren@nvidia.com>
-Date: Tue, 3 Apr 2012 21:53:56 -0600
-Subject: pinctrl: fix build when CONFIG_OF && !CONFIG_PINCTRL
-
-pinctrl/devicetree.c won't compile when !CONFIG_PINCTRL, since the
-pinctrl headers don't declare some types when !PINCTRL. Make sure
-pinctrl/Makefile only attempts to compile devicetree.c when OF &&
-PINCTRL.
-
-Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Stephen Warren <swarren@nvidia.com>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/Makefile | 4 +++-
- 1 file changed, 3 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
-index 049c9fb..8e3c95a 100644
---- a/drivers/pinctrl/Makefile
-+++ b/drivers/pinctrl/Makefile
-@@ -5,7 +5,9 @@ ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
- obj-$(CONFIG_PINCTRL) += core.o
- obj-$(CONFIG_PINMUX) += pinmux.o
- obj-$(CONFIG_PINCONF) += pinconf.o
--obj-$(CONFIG_OF) += devicetree.o
-+ifeq ($(CONFIG_OF),y)
-+obj-$(CONFIG_PINCTRL) += devicetree.o
-+endif
- obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
- obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
- obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 9b5d8f610459f6a0f3a506642681ecac65664293 Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:04:42 +0200
+Subject: AT91SAM9G45: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 815e972110052e8da68b5b5298ca2cd69cb7c3c0 upstream.
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9g45.c
+---
+ arch/arm/mach-at91/at91sam9g45.c | 16 +++-
+ arch/arm/mach-at91/at91sam9g45_devices.c | 131 +++++++++++++++++++++++++-
+ arch/arm/mach-at91/include/mach/at91sam9g45.h | 2 +
+ 3 files changed, 147 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 7ccbf9c..4b791bf 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -177,6 +177,13 @@ static struct clk vdec_clk = {
+ .type = CLK_TYPE_PERIPHERAL,
+ };
+
++/* AES/TDES/SHA clock - Only for sam9m11/sam9g56 */
++static struct clk aestdessha_clk = {
++ .name = "aestdessha_clk",
++ .pmc_mask = 1 << AT91SAM9G45_ID_AESTDESSHA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
+ static struct clk *periph_clocks[] __initdata = {
+ &pioA_clk,
+ &pioB_clk,
+@@ -205,6 +212,7 @@ static struct clk *periph_clocks[] __initdata = {
+ &isi_clk,
+ &udphs_clk,
+ &mmc1_clk,
++ &aestdessha_clk,
+ // irq0
+ };
+
+@@ -226,6 +234,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+ CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "atmel_sha", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("tdes_clk", "atmel_tdes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "atmel_aes", &aestdessha_clk),
+ CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
+@@ -242,6 +253,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "fffc0000.aes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("tdes_clk", "fffc4000.tdes", &aestdessha_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+@@ -387,7 +401,7 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 2, /* USB Device High speed port */
+ 0,
+ 0, /* Multimedia Card Interface 1 */
+- 0,
++ 0, /* AESTDESSHA Crypto HW Accelerators */
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ };
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 29f334c..3d523f0 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -31,7 +31,7 @@
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+-
++#include <linux/platform_data/atmel-aes.h>
+ #include <media/atmel-isi.h>
+
+ #include "generic.h"
+@@ -514,6 +514,132 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+
+
+ /* --------------------------------------------------------------------
++ * SHA1/SHA256
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_SHA) || defined(CONFIG_CRYPTO_DEV_ATMEL_SHA_MODULE)
++static struct resource sha_resources[] = {
++ {
++ .start = AT91SAM9G45_BASE_SHA,
++ .end = AT91SAM9G45_BASE_SHA + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_sha_device = {
++ .name = "atmel_sha",
++ .id = -1,
++ .resource = sha_resources,
++ .num_resources = ARRAY_SIZE(sha_resources),
++};
++
++static void __init at91_add_device_sha(void)
++{
++ platform_device_register(&at91sam9g45_sha_device);
++}
++#else
++static void __init at91_add_device_sha(void) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * DES/TDES
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_TDES) || defined(CONFIG_CRYPTO_DEV_ATMEL_TDES_MODULE)
++static struct resource tdes_resources[] = {
++ [0] = {
++ .start = AT91SAM9G45_BASE_TDES,
++ .end = AT91SAM9G45_BASE_TDES + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_tdes_device = {
++ .name = "atmel_tdes",
++ .id = -1,
++ .resource = tdes_resources,
++ .num_resources = ARRAY_SIZE(tdes_resources),
++};
++
++static void __init at91_add_device_tdes(void)
++{
++ platform_device_register(&at91sam9g45_tdes_device);
++}
++#else
++static void __init at91_add_device_tdes(void) {}
++#endif
++
++/* --------------------------------------------------------------------
++ * AES
++ * -------------------------------------------------------------------- */
++
++#if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
++static struct aes_platform_data aes_data;
++static u64 aes_dmamask = DMA_BIT_MASK(32);
++
++static struct resource aes_resources[] = {
++ [0] = {
++ .start = AT91SAM9G45_BASE_AES,
++ .end = AT91SAM9G45_BASE_AES + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct platform_device at91sam9g45_aes_device = {
++ .name = "atmel_aes",
++ .id = -1,
++ .dev = {
++ .dma_mask = &aes_dmamask,
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &aes_data,
++ },
++ .resource = aes_resources,
++ .num_resources = ARRAY_SIZE(aes_resources),
++};
++
++static void __init at91_add_device_aes(void)
++{
++ struct at_dma_slave *atslave;
++ struct aes_dma_data *alt_atslave;
++
++ alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
++
++ /* DMA TX slave channel configuration */
++ atslave = &alt_atslave->txdata;
++ atslave->dma_dev = &at_hdmac_device.dev;
++ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_SRC_H2SEL_HW |
++ ATC_SRC_PER(AT_DMA_ID_AES_RX);
++
++ /* DMA RX slave channel configuration */
++ atslave = &alt_atslave->rxdata;
++ atslave->dma_dev = &at_hdmac_device.dev;
++ atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_DST_H2SEL_HW |
++ ATC_DST_PER(AT_DMA_ID_AES_TX);
++
++ aes_data.dma_slave = alt_atslave;
++ platform_device_register(&at91sam9g45_aes_device);
++}
++#else
++static void __init at91_add_device_aes(void) {}
++#endif
++
++
++/* --------------------------------------------------------------------
+ * NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+@@ -1742,6 +1868,9 @@ static int __init at91_add_standard_devices(void)
+ at91_add_device_trng();
+ at91_add_device_watchdog();
+ at91_add_device_tc();
++ at91_add_device_sha();
++ at91_add_device_tdes();
++ at91_add_device_aes();
+ return 0;
+ }
+
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+index 3a4da24..8eba102 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
+@@ -136,6 +136,8 @@
+ #define AT_DMA_ID_SSC1_RX 8
+ #define AT_DMA_ID_AC97_TX 9
+ #define AT_DMA_ID_AC97_RX 10
++#define AT_DMA_ID_AES_TX 11
++#define AT_DMA_ID_AES_RX 12
+ #define AT_DMA_ID_MCI1 13
+
+ #endif
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 51c38f7a1e3171e80e2c4c3db1bf6276a2711298 Mon Sep 17 00:00:00 2001
-From: Linus Walleij <linus.walleij@linaro.org>
-Date: Tue, 24 Apr 2012 15:20:02 +0200
-Subject: pinctrl: fix dangling comment
-
-This comment was referring to an older PINMUX define, it should
-be PINCTRL now.
-
-Reported-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- include/linux/pinctrl/machine.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
-index e4d1de7..9c4a198 100644
---- a/include/linux/pinctrl/machine.h
-+++ b/include/linux/pinctrl/machine.h
-@@ -163,5 +163,5 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
- return 0;
- }
-
--#endif /* !CONFIG_PINMUX */
-+#endif /* !CONFIG_PINCTRL */
- #endif
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6b9039aedd996147b5146b74594a69221d0873d8 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:04 +0200
+Subject: crypto: add Atmel AES driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit bd3c7b5c2aba0d806285700848f588ca482094d8 upstream.
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 17 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-aes-regs.h | 62 ++
+ drivers/crypto/atmel-aes.c | 1206 +++++++++++++++++++++++++++++++
+ include/linux/platform_data/atmel-aes.h | 22 +
+ 5 files changed, 1308 insertions(+)
+ create mode 100644 drivers/crypto/atmel-aes-regs.h
+ create mode 100644 drivers/crypto/atmel-aes.c
+ create mode 100644 include/linux/platform_data/atmel-aes.h
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index dd414d9..98c7da5 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -296,4 +296,21 @@ config CRYPTO_DEV_TEGRA_AES
+ To compile this driver as a module, choose M here: the module
+ will be called tegra-aes.
+
++config CRYPTO_DEV_ATMEL_AES
++ tristate "Support for Atmel AES hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_CBC
++ select CRYPTO_ECB
++ select CRYPTO_AES
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
++ select AT_HDMAC
++ help
++ Some Atmel processors have AES hw accelerator.
++ Select this if you want to use the Atmel module for
++ AES algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-aes.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index f3e64ea..73ad830 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -14,3 +14,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
+ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h
+new file mode 100644
+index 0000000..2786bb1
+--- /dev/null
++++ b/drivers/crypto/atmel-aes-regs.h
+@@ -0,0 +1,62 @@
++#ifndef __ATMEL_AES_REGS_H__
++#define __ATMEL_AES_REGS_H__
++
++#define AES_CR 0x00
++#define AES_CR_START (1 << 0)
++#define AES_CR_SWRST (1 << 8)
++#define AES_CR_LOADSEED (1 << 16)
++
++#define AES_MR 0x04
++#define AES_MR_CYPHER_DEC (0 << 0)
++#define AES_MR_CYPHER_ENC (1 << 0)
++#define AES_MR_DUALBUFF (1 << 3)
++#define AES_MR_PROCDLY_MASK (0xF << 4)
++#define AES_MR_PROCDLY_OFFSET 4
++#define AES_MR_SMOD_MASK (0x3 << 8)
++#define AES_MR_SMOD_MANUAL (0x0 << 8)
++#define AES_MR_SMOD_AUTO (0x1 << 8)
++#define AES_MR_SMOD_IDATAR0 (0x2 << 8)
++#define AES_MR_KEYSIZE_MASK (0x3 << 10)
++#define AES_MR_KEYSIZE_128 (0x0 << 10)
++#define AES_MR_KEYSIZE_192 (0x1 << 10)
++#define AES_MR_KEYSIZE_256 (0x2 << 10)
++#define AES_MR_OPMOD_MASK (0x7 << 12)
++#define AES_MR_OPMOD_ECB (0x0 << 12)
++#define AES_MR_OPMOD_CBC (0x1 << 12)
++#define AES_MR_OPMOD_OFB (0x2 << 12)
++#define AES_MR_OPMOD_CFB (0x3 << 12)
++#define AES_MR_OPMOD_CTR (0x4 << 12)
++#define AES_MR_LOD (0x1 << 15)
++#define AES_MR_CFBS_MASK (0x7 << 16)
++#define AES_MR_CFBS_128b (0x0 << 16)
++#define AES_MR_CFBS_64b (0x1 << 16)
++#define AES_MR_CFBS_32b (0x2 << 16)
++#define AES_MR_CFBS_16b (0x3 << 16)
++#define AES_MR_CFBS_8b (0x4 << 16)
++#define AES_MR_CKEY_MASK (0xF << 20)
++#define AES_MR_CKEY_OFFSET 20
++#define AES_MR_CMTYP_MASK (0x1F << 24)
++#define AES_MR_CMTYP_OFFSET 24
++
++#define AES_IER 0x10
++#define AES_IDR 0x14
++#define AES_IMR 0x18
++#define AES_ISR 0x1C
++#define AES_INT_DATARDY (1 << 0)
++#define AES_INT_URAD (1 << 8)
++#define AES_ISR_URAT_MASK (0xF << 12)
++#define AES_ISR_URAT_IDR_WR_PROC (0x0 << 12)
++#define AES_ISR_URAT_ODR_RD_PROC (0x1 << 12)
++#define AES_ISR_URAT_MR_WR_PROC (0x2 << 12)
++#define AES_ISR_URAT_ODR_RD_SUBK (0x3 << 12)
++#define AES_ISR_URAT_MR_WR_SUBK (0x4 << 12)
++#define AES_ISR_URAT_WOR_RD (0x5 << 12)
++
++#define AES_KEYWR(x) (0x20 + ((x) * 0x04))
++#define AES_IDATAR(x) (0x40 + ((x) * 0x04))
++#define AES_ODATAR(x) (0x50 + ((x) * 0x04))
++#define AES_IVR(x) (0x60 + ((x) * 0x04))
++
++#define AES_HW_VERSION 0xFC
++
++#endif /* __ATMEL_AES_REGS_H__ */
+diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
+new file mode 100644
+index 0000000..6bb20ff
+--- /dev/null
++++ b/drivers/crypto/atmel-aes.c
+@@ -0,0 +1,1206 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL AES HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Some ideas are from omap-aes.c driver.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/aes.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include <linux/platform_data/atmel-aes.h>
++#include "atmel-aes-regs.h"
++
++#define CFB8_BLOCK_SIZE 1
++#define CFB16_BLOCK_SIZE 2
++#define CFB32_BLOCK_SIZE 4
++#define CFB64_BLOCK_SIZE 8
++
++/* AES flags */
++#define AES_FLAGS_MODE_MASK 0x01ff
++#define AES_FLAGS_ENCRYPT BIT(0)
++#define AES_FLAGS_CBC BIT(1)
++#define AES_FLAGS_CFB BIT(2)
++#define AES_FLAGS_CFB8 BIT(3)
++#define AES_FLAGS_CFB16 BIT(4)
++#define AES_FLAGS_CFB32 BIT(5)
++#define AES_FLAGS_CFB64 BIT(6)
++#define AES_FLAGS_OFB BIT(7)
++#define AES_FLAGS_CTR BIT(8)
++
++#define AES_FLAGS_INIT BIT(16)
++#define AES_FLAGS_DMA BIT(17)
++#define AES_FLAGS_BUSY BIT(18)
++
++#define AES_FLAGS_DUALBUFF BIT(24)
++
++#define ATMEL_AES_QUEUE_LENGTH 1
++#define ATMEL_AES_CACHE_SIZE 0
++
++#define ATMEL_AES_DMA_THRESHOLD 16
++
++
++struct atmel_aes_dev;
++
++struct atmel_aes_ctx {
++ struct atmel_aes_dev *dd;
++
++ int keylen;
++ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
++};
++
++struct atmel_aes_reqctx {
++ unsigned long mode;
++};
++
++struct atmel_aes_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
++
++struct atmel_aes_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ void __iomem *io_base;
++
++ struct atmel_aes_ctx *ctx;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++
++ unsigned long flags;
++ int err;
++
++ spinlock_t lock;
++ struct crypto_queue queue;
++
++ struct tasklet_struct done_task;
++ struct tasklet_struct queue_task;
++
++ struct ablkcipher_request *req;
++ size_t total;
++
++ struct scatterlist *in_sg;
++ unsigned int nb_in_sg;
++
++ struct scatterlist *out_sg;
++ unsigned int nb_out_sg;
++
++ size_t bufcnt;
++
++ u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
++ int dma_in;
++ struct atmel_aes_dma dma_lch_in;
++
++ u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
++ int dma_out;
++ struct atmel_aes_dma dma_lch_out;
++
++ u32 hw_version;
++};
++
++struct atmel_aes_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_aes_drv atmel_aes = {
++ .dev_list = LIST_HEAD_INIT(atmel_aes.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_aes.lock),
++};
++
++static int atmel_aes_sg_length(struct ablkcipher_request *req,
++ struct scatterlist *sg)
++{
++ unsigned int total = req->nbytes;
++ int sg_nb;
++ unsigned int len;
++ struct scatterlist *sg_list;
++
++ sg_nb = 0;
++ sg_list = sg;
++ total = req->nbytes;
++
++ while (total) {
++ len = min(sg_list->length, total);
++
++ sg_nb++;
++ total -= len;
++
++ sg_list = sg_next(sg_list);
++ if (!sg_list)
++ total = 0;
++ }
++
++ return sg_nb;
++}
++
++static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_aes_write(struct atmel_aes_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_aes_read_n(struct atmel_aes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ *value = atmel_aes_read(dd, offset);
++}
++
++static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ atmel_aes_write(dd, offset, *value);
++}
++
++static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
++{
++ atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
++
++ if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
++ dd->flags |= AES_FLAGS_DUALBUFF;
++}
++
++static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
++{
++ struct atmel_aes_dev *aes_dd = NULL;
++ struct atmel_aes_dev *tmp;
++
++ spin_lock_bh(&atmel_aes.lock);
++ if (!ctx->dd) {
++ list_for_each_entry(tmp, &atmel_aes.dev_list, list) {
++ aes_dd = tmp;
++ break;
++ }
++ ctx->dd = aes_dd;
++ } else {
++ aes_dd = ctx->dd;
++ }
++
++ spin_unlock_bh(&atmel_aes.lock);
++
++ return aes_dd;
++}
++
++static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (!(dd->flags & AES_FLAGS_INIT)) {
++ atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
++ atmel_aes_dualbuff_test(dd);
++ dd->flags |= AES_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
++{
++ atmel_aes_hw_init(dd);
++
++ dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
++static void atmel_aes_finish_req(struct atmel_aes_dev *dd, int err)
++{
++ struct ablkcipher_request *req = dd->req;
++
++ clk_disable_unprepare(dd->iclk);
++ dd->flags &= ~AES_FLAGS_BUSY;
++
++ req->base.complete(&req->base, err);
++}
++
++static void atmel_aes_dma_callback(void *data)
++{
++ struct atmel_aes_dev *dd = data;
++
++ /* dma_lch_out - completed */
++ tasklet_schedule(&dd->done_task);
++}
++
++static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
++{
++ struct dma_async_tx_descriptor *in_desc, *out_desc;
++ int nb_dma_sg_in, nb_dma_sg_out;
++
++ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
++ if (!dd->nb_in_sg)
++ goto exit_err;
++
++ nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
++ DMA_TO_DEVICE);
++ if (!nb_dma_sg_in)
++ goto exit_err;
++
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
++ nb_dma_sg_in, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++
++ if (!in_desc)
++ goto unmap_in;
++
++ /* callback not needed */
++
++ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
++ if (!dd->nb_out_sg)
++ goto unmap_in;
++
++ nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
++ DMA_FROM_DEVICE);
++ if (!nb_dma_sg_out)
++ goto unmap_out;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
++ nb_dma_sg_out, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++
++ if (!out_desc)
++ goto unmap_out;
++
++ out_desc->callback = atmel_aes_dma_callback;
++ out_desc->callback_param = dd;
++
++ dd->total -= dd->req->nbytes;
++
++ dmaengine_submit(out_desc);
++ dma_async_issue_pending(dd->dma_lch_out.chan);
++
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return 0;
++
++unmap_out:
++ dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
++ DMA_FROM_DEVICE);
++unmap_in:
++ dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
++ DMA_TO_DEVICE);
++exit_err:
++ return -EINVAL;
++}
++
++static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
++{
++ dd->flags &= ~AES_FLAGS_DMA;
++
++ /* use cache buffers */
++ dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
++ if (!dd->nb_in_sg)
++ return -EINVAL;
++
++ dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
++ if (!dd->nb_in_sg)
++ return -EINVAL;
++
++ dd->bufcnt = sg_copy_to_buffer(dd->in_sg, dd->nb_in_sg,
++ dd->buf_in, dd->total);
++
++ if (!dd->bufcnt)
++ return -EINVAL;
++
++ dd->total -= dd->bufcnt;
++
++ atmel_aes_write(dd, AES_IER, AES_INT_DATARDY);
++ atmel_aes_write_n(dd, AES_IDATAR(0), (u32 *) dd->buf_in,
++ dd->bufcnt >> 2);
++
++ return 0;
++}
++
++static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
++{
++ int err;
++
++ if (dd->flags & AES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & AES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++
++ dd->flags |= AES_FLAGS_DMA;
++ err = atmel_aes_crypt_dma(dd);
++
++ return err;
++}
++
++static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
++{
++ int err;
++ u32 valcr = 0, valmr = 0;
++
++ err = atmel_aes_hw_init(dd);
++
++ if (err)
++ return err;
++
++ /* MR register must be set before IV registers */
++ if (dd->ctx->keylen == AES_KEYSIZE_128)
++ valmr |= AES_MR_KEYSIZE_128;
++ else if (dd->ctx->keylen == AES_KEYSIZE_192)
++ valmr |= AES_MR_KEYSIZE_192;
++ else
++ valmr |= AES_MR_KEYSIZE_256;
++
++ if (dd->flags & AES_FLAGS_CBC) {
++ valmr |= AES_MR_OPMOD_CBC;
++ } else if (dd->flags & AES_FLAGS_CFB) {
++ valmr |= AES_MR_OPMOD_CFB;
++ if (dd->flags & AES_FLAGS_CFB8)
++ valmr |= AES_MR_CFBS_8b;
++ else if (dd->flags & AES_FLAGS_CFB16)
++ valmr |= AES_MR_CFBS_16b;
++ else if (dd->flags & AES_FLAGS_CFB32)
++ valmr |= AES_MR_CFBS_32b;
++ else if (dd->flags & AES_FLAGS_CFB64)
++ valmr |= AES_MR_CFBS_64b;
++ } else if (dd->flags & AES_FLAGS_OFB) {
++ valmr |= AES_MR_OPMOD_OFB;
++ } else if (dd->flags & AES_FLAGS_CTR) {
++ valmr |= AES_MR_OPMOD_CTR;
++ } else {
++ valmr |= AES_MR_OPMOD_ECB;
++ }
++
++ if (dd->flags & AES_FLAGS_ENCRYPT)
++ valmr |= AES_MR_CYPHER_ENC;
++
++ if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
++ valmr |= AES_MR_SMOD_IDATAR0;
++ if (dd->flags & AES_FLAGS_DUALBUFF)
++ valmr |= AES_MR_DUALBUFF;
++ } else {
++ valmr |= AES_MR_SMOD_AUTO;
++ }
++
++ atmel_aes_write(dd, AES_CR, valcr);
++ atmel_aes_write(dd, AES_MR, valmr);
++
++ atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key,
++ dd->ctx->keylen >> 2);
++
++ if (((dd->flags & AES_FLAGS_CBC) || (dd->flags & AES_FLAGS_CFB) ||
++ (dd->flags & AES_FLAGS_OFB) || (dd->flags & AES_FLAGS_CTR)) &&
++ dd->req->info) {
++ atmel_aes_write_n(dd, AES_IVR(0), dd->req->info, 4);
++ }
++
++ return 0;
++}
++
++static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
++ struct ablkcipher_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_aes_ctx *ctx;
++ struct atmel_aes_reqctx *rctx;
++ unsigned long flags;
++ int err, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ablkcipher_enqueue_request(&dd->queue, req);
++ if (dd->flags & AES_FLAGS_BUSY) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= AES_FLAGS_BUSY;
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ablkcipher_request_cast(async_req);
++
++ /* assign new request to device */
++ dd->req = req;
++ dd->total = req->nbytes;
++ dd->in_sg = req->src;
++ dd->out_sg = req->dst;
++
++ rctx = ablkcipher_request_ctx(req);
++ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
++ rctx->mode &= AES_FLAGS_MODE_MASK;
++ dd->flags = (dd->flags & ~AES_FLAGS_MODE_MASK) | rctx->mode;
++ dd->ctx = ctx;
++ ctx->dd = dd;
++
++ err = atmel_aes_write_ctrl(dd);
++ if (!err) {
++ if (dd->total > ATMEL_AES_DMA_THRESHOLD)
++ err = atmel_aes_crypt_dma_start(dd);
++ else
++ err = atmel_aes_crypt_cpu_start(dd);
++ }
++ if (err) {
++ /* aes_task will not finish it, so do it here */
++ atmel_aes_finish_req(dd, err);
++ tasklet_schedule(&dd->queue_task);
++ }
++
++ return ret;
++}
++
++static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
++{
++ int err = -EINVAL;
++
++ if (dd->flags & AES_FLAGS_DMA) {
++ dma_unmap_sg(dd->dev, dd->out_sg,
++ dd->nb_out_sg, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg,
++ dd->nb_in_sg, DMA_TO_DEVICE);
++ err = 0;
++ }
++
++ return err;
++}
++
++static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
++{
++ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
++ crypto_ablkcipher_reqtfm(req));
++ struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
++ struct atmel_aes_dev *dd;
++
++ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of AES blocks\n");
++ return -EINVAL;
++ }
++
++ dd = atmel_aes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
++ rctx->mode = mode;
++
++ return atmel_aes_handle_queue(dd, req);
++}
++
++static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
++{
++ int err = -ENOMEM;
++ struct aes_platform_data *pdata;
++ dma_cap_mask_t mask_in, mask_out;
++
++ pdata = dd->dev->platform_data;
++
++ if (pdata && pdata->dma_slave->txdata.dma_dev &&
++ pdata->dma_slave->rxdata.dma_dev) {
++
++ /* Try to grab 2 DMA channels */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_aes_filter, &pdata->dma_slave->rxdata);
++ if (!dd->dma_lch_in.chan)
++ goto err_dma_in;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ AES_IDATAR(0);
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ dma_cap_zero(mask_out);
++ dma_cap_set(DMA_SLAVE, mask_out);
++ dd->dma_lch_out.chan = dma_request_channel(mask_out,
++ atmel_aes_filter, &pdata->dma_slave->txdata);
++ if (!dd->dma_lch_out.chan)
++ goto err_dma_out;
++
++ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
++ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
++ AES_ODATAR(0);
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.device_fc = false;
++
++ return 0;
++ } else {
++ return -ENODEV;
++ }
++
++err_dma_out:
++ dma_release_channel(dd->dma_lch_in.chan);
++err_dma_in:
++ return err;
++}
++
++static void atmel_aes_dma_cleanup(struct atmel_aes_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++ dma_release_channel(dd->dma_lch_out.chan);
++}
++
++static int atmel_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != AES_KEYSIZE_128 && keylen != AES_KEYSIZE_192 &&
++ keylen != AES_KEYSIZE_256) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_aes_ecb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT);
++}
++
++static int atmel_aes_ecb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ 0);
++}
++
++static int atmel_aes_cbc_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CBC);
++}
++
++static int atmel_aes_cbc_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CBC);
++}
++
++static int atmel_aes_ofb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_OFB);
++}
++
++static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_OFB);
++}
++
++static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
++}
++
++static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB);
++}
++
++static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB64);
++}
++
++static int atmel_aes_cfb64_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB64);
++}
++
++static int atmel_aes_cfb32_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB32);
++}
++
++static int atmel_aes_cfb32_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB32);
++}
++
++static int atmel_aes_cfb16_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB16);
++}
++
++static int atmel_aes_cfb16_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB16);
++}
++
++static int atmel_aes_cfb8_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB8);
++}
++
++static int atmel_aes_cfb8_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CFB | AES_FLAGS_CFB8);
++}
++
++static int atmel_aes_ctr_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CTR);
++}
++
++static int atmel_aes_ctr_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_aes_crypt(req,
++ AES_FLAGS_CTR);
++}
++
++static int atmel_aes_cra_init(struct crypto_tfm *tfm)
++{
++ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_aes_reqctx);
++
++ return 0;
++}
++
++static void atmel_aes_cra_exit(struct crypto_tfm *tfm)
++{
++}
++
++static struct crypto_alg aes_algs[] = {
++{
++ .cra_name = "ecb(aes)",
++ .cra_driver_name = "atmel-ecb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ecb_encrypt,
++ .decrypt = atmel_aes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "atmel-cbc-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cbc_encrypt,
++ .decrypt = atmel_aes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(aes)",
++ .cra_driver_name = "atmel-ofb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ofb_encrypt,
++ .decrypt = atmel_aes_ofb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(aes)",
++ .cra_driver_name = "atmel-cfb-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb_encrypt,
++ .decrypt = atmel_aes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(aes)",
++ .cra_driver_name = "atmel-cfb32-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb32_encrypt,
++ .decrypt = atmel_aes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(aes)",
++ .cra_driver_name = "atmel-cfb16-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb16_encrypt,
++ .decrypt = atmel_aes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(aes)",
++ .cra_driver_name = "atmel-cfb8-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB64_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb8_encrypt,
++ .decrypt = atmel_aes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "ctr(aes)",
++ .cra_driver_name = "atmel-ctr-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_ctr_encrypt,
++ .decrypt = atmel_aes_ctr_decrypt,
++ }
++},
++};
++
++static struct crypto_alg aes_cfb64_alg[] = {
++{
++ .cra_name = "cfb64(aes)",
++ .cra_driver_name = "atmel-cfb64-aes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB64_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
++ .cra_alignmask = 0x0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_aes_cra_init,
++ .cra_exit = atmel_aes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = atmel_aes_setkey,
++ .encrypt = atmel_aes_cfb64_encrypt,
++ .decrypt = atmel_aes_cfb64_decrypt,
++ }
++},
++};
++
++static void atmel_aes_queue_task(unsigned long data)
++{
++ struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data;
++
++ atmel_aes_handle_queue(dd, NULL);
++}
++
++static void atmel_aes_done_task(unsigned long data)
++{
++ struct atmel_aes_dev *dd = (struct atmel_aes_dev *) data;
++ int err;
++
++ if (!(dd->flags & AES_FLAGS_DMA)) {
++ atmel_aes_read_n(dd, AES_ODATAR(0), (u32 *) dd->buf_out,
++ dd->bufcnt >> 2);
++
++ if (sg_copy_from_buffer(dd->out_sg, dd->nb_out_sg,
++ dd->buf_out, dd->bufcnt))
++ err = 0;
++ else
++ err = -EINVAL;
++
++ goto cpu_end;
++ }
++
++ err = atmel_aes_crypt_dma_stop(dd);
++
++ err = dd->err ? : err;
++
++ if (dd->total && !err) {
++ err = atmel_aes_crypt_dma_start(dd);
++ if (!err)
++ return; /* DMA started. Not fininishing. */
++ }
++
++cpu_end:
++ atmel_aes_finish_req(dd, err);
++ atmel_aes_handle_queue(dd, NULL);
++}
++
++static irqreturn_t atmel_aes_irq(int irq, void *dev_id)
++{
++ struct atmel_aes_dev *aes_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_aes_read(aes_dd, AES_ISR);
++ if (reg & atmel_aes_read(aes_dd, AES_IMR)) {
++ atmel_aes_write(aes_dd, AES_IDR, reg);
++ if (AES_FLAGS_BUSY & aes_dd->flags)
++ tasklet_schedule(&aes_dd->done_task);
++ else
++ dev_warn(aes_dd->dev, "AES interrupt when no active requests.\n");
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
++ crypto_unregister_alg(&aes_algs[i]);
++ if (dd->hw_version >= 0x130)
++ crypto_unregister_alg(&aes_cfb64_alg[0]);
++}
++
++static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
++ INIT_LIST_HEAD(&aes_algs[i].cra_list);
++ err = crypto_register_alg(&aes_algs[i]);
++ if (err)
++ goto err_aes_algs;
++ }
++
++ atmel_aes_hw_version_init(dd);
++
++ if (dd->hw_version >= 0x130) {
++ INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
++ err = crypto_register_alg(&aes_cfb64_alg[0]);
++ if (err)
++ goto err_aes_cfb64_alg;
++ }
++
++ return 0;
++
++err_aes_cfb64_alg:
++ i = ARRAY_SIZE(aes_algs);
++err_aes_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_alg(&aes_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_aes_probe(struct platform_device *pdev)
++{
++ struct atmel_aes_dev *aes_dd;
++ struct aes_platform_data *pdata;
++ struct device *dev = &pdev->dev;
++ struct resource *aes_res;
++ unsigned long aes_phys_size;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ err = -ENXIO;
++ goto aes_dd_err;
++ }
++
++ aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
++ if (aes_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto aes_dd_err;
++ }
++
++ aes_dd->dev = dev;
++
++ platform_set_drvdata(pdev, aes_dd);
++
++ INIT_LIST_HEAD(&aes_dd->list);
++
++ tasklet_init(&aes_dd->done_task, atmel_aes_done_task,
++ (unsigned long)aes_dd);
++ tasklet_init(&aes_dd->queue_task, atmel_aes_queue_task,
++ (unsigned long)aes_dd);
++
++ crypto_init_queue(&aes_dd->queue, ATMEL_AES_QUEUE_LENGTH);
++
++ aes_dd->irq = -1;
++
++ /* Get the base address */
++ aes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!aes_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ aes_dd->phys_base = aes_res->start;
++ aes_phys_size = resource_size(aes_res);
++
++ /* Get the IRQ */
++ aes_dd->irq = platform_get_irq(pdev, 0);
++ if (aes_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = aes_dd->irq;
++ goto aes_irq_err;
++ }
++
++ err = request_irq(aes_dd->irq, atmel_aes_irq, IRQF_SHARED, "atmel-aes",
++ aes_dd);
++ if (err) {
++ dev_err(dev, "unable to request aes irq.\n");
++ goto aes_irq_err;
++ }
++
++ /* Initializing the clock */
++ aes_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(aes_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(aes_dd->iclk);
++ goto clk_err;
++ }
++
++ aes_dd->io_base = ioremap(aes_dd->phys_base, aes_phys_size);
++ if (!aes_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto aes_io_err;
++ }
++
++ err = atmel_aes_dma_init(aes_dd);
++ if (err)
++ goto err_aes_dma;
++
++ spin_lock(&atmel_aes.lock);
++ list_add_tail(&aes_dd->list, &atmel_aes.dev_list);
++ spin_unlock(&atmel_aes.lock);
++
++ err = atmel_aes_register_algs(aes_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel AES\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_aes.lock);
++ list_del(&aes_dd->list);
++ spin_unlock(&atmel_aes.lock);
++ atmel_aes_dma_cleanup(aes_dd);
++err_aes_dma:
++ iounmap(aes_dd->io_base);
++aes_io_err:
++ clk_put(aes_dd->iclk);
++clk_err:
++ free_irq(aes_dd->irq, aes_dd);
++aes_irq_err:
++res_err:
++ tasklet_kill(&aes_dd->done_task);
++ tasklet_kill(&aes_dd->queue_task);
++ kfree(aes_dd);
++ aes_dd = NULL;
++aes_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_aes_remove(struct platform_device *pdev)
++{
++ static struct atmel_aes_dev *aes_dd;
++
++ aes_dd = platform_get_drvdata(pdev);
++ if (!aes_dd)
++ return -ENODEV;
++ spin_lock(&atmel_aes.lock);
++ list_del(&aes_dd->list);
++ spin_unlock(&atmel_aes.lock);
++
++ atmel_aes_unregister_algs(aes_dd);
++
++ tasklet_kill(&aes_dd->done_task);
++ tasklet_kill(&aes_dd->queue_task);
++
++ atmel_aes_dma_cleanup(aes_dd);
++
++ iounmap(aes_dd->io_base);
++
++ clk_put(aes_dd->iclk);
++
++ if (aes_dd->irq > 0)
++ free_irq(aes_dd->irq, aes_dd);
++
++ kfree(aes_dd);
++ aes_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_aes_driver = {
++ .probe = atmel_aes_probe,
++ .remove = __devexit_p(atmel_aes_remove),
++ .driver = {
++ .name = "atmel_aes",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_aes_driver);
++
++MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
+new file mode 100644
+index 0000000..e7a1949
+--- /dev/null
++++ b/include/linux/platform_data/atmel-aes.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_ATMEL_AES_H
++#define __LINUX_ATMEL_AES_H
++
++#include <mach/at_hdmac.h>
++
++/**
++ * struct aes_dma_data - DMA data for AES
++ */
++struct aes_dma_data {
++ struct at_dma_slave txdata;
++ struct at_dma_slave rxdata;
++};
++
++/**
++ * struct aes_platform_data - board-specific AES configuration
++ * @dma_slave: DMA slave interface to use in data transfers.
++ */
++struct aes_platform_data {
++ struct aes_dma_data *dma_slave;
++};
++
++#endif /* __LINUX_ATMEL_AES_H */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 51da4591803af89917c5ef0f8b1e36b2f1398883 Mon Sep 17 00:00:00 2001
-From: Stephen Warren <swarren@nvidia.com>
-Date: Mon, 16 Apr 2012 10:51:00 -0600
-Subject: pinctrl: implement devm_pinctrl_get()/put()
-
-These functions allow the driver core to automatically clean up any
-allocations made by drivers, thus leading to simplified drivers.
-
-Signed-off-by: Stephen Warren <swarren@nvidia.com>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- Documentation/driver-model/devres.txt | 4 +++
- Documentation/pinctrl.txt | 48 ++++++++++++++++++------------
- drivers/pinctrl/core.c | 56 +++++++++++++++++++++++++++++++++++
- include/linux/pinctrl/consumer.h | 44 +++++++++++++++++++++++++++
- 4 files changed, 133 insertions(+), 19 deletions(-)
-
-diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
-index 2a596a4..ef4fa7b 100644
---- a/Documentation/driver-model/devres.txt
-+++ b/Documentation/driver-model/devres.txt
-@@ -276,3 +276,7 @@ REGULATOR
- devm_regulator_get()
- devm_regulator_put()
- devm_regulator_bulk_get()
-+
-+PINCTRL
-+ devm_pinctrl_get()
-+ devm_pinctrl_put()
-diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
-index d97bccf..fa829f1 100644
---- a/Documentation/pinctrl.txt
-+++ b/Documentation/pinctrl.txt
-@@ -952,13 +952,13 @@ case), we define a mapping like this:
- The result of grabbing this mapping from the device with something like
- this (see next paragraph):
-
-- p = pinctrl_get(dev);
-+ p = devm_pinctrl_get(dev);
- s = pinctrl_lookup_state(p, "8bit");
- ret = pinctrl_select_state(p, s);
-
- or more simply:
-
-- p = pinctrl_get_select(dev, "8bit");
-+ p = devm_pinctrl_get_select(dev, "8bit");
-
- Will be that you activate all the three bottom records in the mapping at
- once. Since they share the same name, pin controller device, function and
-@@ -992,7 +992,7 @@ foo_probe()
- /* Allocate a state holder named "foo" etc */
- struct foo_state *foo = ...;
-
-- foo->p = pinctrl_get(&device);
-+ foo->p = devm_pinctrl_get(&device);
- if (IS_ERR(foo->p)) {
- /* FIXME: clean up "foo" here */
- return PTR_ERR(foo->p);
-@@ -1000,24 +1000,17 @@ foo_probe()
-
- foo->s = pinctrl_lookup_state(foo->p, PINCTRL_STATE_DEFAULT);
- if (IS_ERR(foo->s)) {
-- pinctrl_put(foo->p);
- /* FIXME: clean up "foo" here */
- return PTR_ERR(s);
- }
-
- ret = pinctrl_select_state(foo->s);
- if (ret < 0) {
-- pinctrl_put(foo->p);
- /* FIXME: clean up "foo" here */
- return ret;
- }
- }
-
--foo_remove()
--{
-- pinctrl_put(state->p);
--}
--
- This get/lookup/select/put sequence can just as well be handled by bus drivers
- if you don't want each and every driver to handle it and you know the
- arrangement on your bus.
-@@ -1029,6 +1022,11 @@ The semantics of the pinctrl APIs are:
- kernel memory to hold the pinmux state. All mapping table parsing or similar
- slow operations take place within this API.
-
-+- devm_pinctrl_get() is a variant of pinctrl_get() that causes pinctrl_put()
-+ to be called automatically on the retrieved pointer when the associated
-+ device is removed. It is recommended to use this function over plain
-+ pinctrl_get().
-+
- - pinctrl_lookup_state() is called in process context to obtain a handle to a
- specific state for a the client device. This operation may be slow too.
-
-@@ -1041,14 +1039,25 @@ The semantics of the pinctrl APIs are:
-
- - pinctrl_put() frees all information associated with a pinctrl handle.
-
-+- devm_pinctrl_put() is a variant of pinctrl_put() that may be used to
-+ explicitly destroy a pinctrl object returned by devm_pinctrl_get().
-+ However, use of this function will be rare, due to the automatic cleanup
-+ that will occur even without calling it.
-+
-+ pinctrl_get() must be paired with a plain pinctrl_put().
-+ pinctrl_get() may not be paired with devm_pinctrl_put().
-+ devm_pinctrl_get() can optionally be paired with devm_pinctrl_put().
-+ devm_pinctrl_get() may not be paired with plain pinctrl_put().
-+
- Usually the pin control core handled the get/put pair and call out to the
- device drivers bookkeeping operations, like checking available functions and
- the associated pins, whereas the enable/disable pass on to the pin controller
- driver which takes care of activating and/or deactivating the mux setting by
- quickly poking some registers.
-
--The pins are allocated for your device when you issue the pinctrl_get() call,
--after this you should be able to see this in the debugfs listing of all pins.
-+The pins are allocated for your device when you issue the devm_pinctrl_get()
-+call, after this you should be able to see this in the debugfs listing of all
-+pins.
-
-
- System pin control hogging
-@@ -1094,13 +1103,13 @@ it, disables and releases it, and muxes it in on the pins defined by group B:
-
- #include <linux/pinctrl/consumer.h>
-
--foo_switch()
--{
-- struct pinctrl *p;
-- struct pinctrl_state *s1, *s2;
-+struct pinctrl *p;
-+struct pinctrl_state *s1, *s2;
-
-+foo_probe()
-+{
- /* Setup */
-- p = pinctrl_get(&device);
-+ p = devm_pinctrl_get(&device);
- if (IS_ERR(p))
- ...
-
-@@ -1111,7 +1120,10 @@ foo_switch()
- s2 = pinctrl_lookup_state(foo->p, "pos-B");
- if (IS_ERR(s2))
- ...
-+}
-
-+foo_switch()
-+{
- /* Enable on position A */
- ret = pinctrl_select_state(s1);
- if (ret < 0)
-@@ -1125,8 +1137,6 @@ foo_switch()
- ...
-
- ...
--
-- pinctrl_put(p);
- }
-
- The above has to be done from process context.
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index 832f71d..f4544f4 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -23,6 +23,7 @@
- #include <linux/sysfs.h>
- #include <linux/debugfs.h>
- #include <linux/seq_file.h>
-+#include <linux/pinctrl/consumer.h>
- #include <linux/pinctrl/pinctrl.h>
- #include <linux/pinctrl/machine.h>
- #include "core.h"
-@@ -797,6 +798,61 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
- }
- EXPORT_SYMBOL_GPL(pinctrl_select_state);
-
-+static void devm_pinctrl_release(struct device *dev, void *res)
-+{
-+ pinctrl_put(*(struct pinctrl **)res);
-+}
-+
-+/**
-+ * struct devm_pinctrl_get() - Resource managed pinctrl_get()
-+ * @dev: the device to obtain the handle for
-+ *
-+ * If there is a need to explicitly destroy the returned struct pinctrl,
-+ * devm_pinctrl_put() should be used, rather than plain pinctrl_put().
-+ */
-+struct pinctrl *devm_pinctrl_get(struct device *dev)
-+{
-+ struct pinctrl **ptr, *p;
-+
-+ ptr = devres_alloc(devm_pinctrl_release, sizeof(*ptr), GFP_KERNEL);
-+ if (!ptr)
-+ return ERR_PTR(-ENOMEM);
-+
-+ p = pinctrl_get(dev);
-+ if (!IS_ERR(p)) {
-+ *ptr = p;
-+ devres_add(dev, ptr);
-+ } else {
-+ devres_free(ptr);
-+ }
-+
-+ return p;
-+}
-+EXPORT_SYMBOL_GPL(devm_pinctrl_get);
-+
-+static int devm_pinctrl_match(struct device *dev, void *res, void *data)
-+{
-+ struct pinctrl **p = res;
-+
-+ return *p == data;
-+}
-+
-+/**
-+ * devm_pinctrl_put() - Resource managed pinctrl_put()
-+ * @p: the pinctrl handle to release
-+ *
-+ * Deallocate a struct pinctrl obtained via devm_pinctrl_get(). Normally
-+ * this function will not need to be called and the resource management
-+ * code will ensure that the resource is freed.
-+ */
-+void devm_pinctrl_put(struct pinctrl *p)
-+{
-+ WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
-+ devm_pinctrl_match, p));
-+ pinctrl_put(p);
-+}
-+EXPORT_SYMBOL_GPL(devm_pinctrl_put);
-+
- int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
- bool dup, bool locked)
- {
-diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
-index 191e726..6dd96fb 100644
---- a/include/linux/pinctrl/consumer.h
-+++ b/include/linux/pinctrl/consumer.h
-@@ -36,6 +36,9 @@ extern struct pinctrl_state * __must_check pinctrl_lookup_state(
- const char *name);
- extern int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *s);
-
-+extern struct pinctrl * __must_check devm_pinctrl_get(struct device *dev);
-+extern void devm_pinctrl_put(struct pinctrl *p);
-+
- #else /* !CONFIG_PINCTRL */
-
- static inline int pinctrl_request_gpio(unsigned gpio)
-@@ -79,6 +82,15 @@ static inline int pinctrl_select_state(struct pinctrl *p,
- return 0;
- }
-
-+static inline struct pinctrl * __must_check devm_pinctrl_get(struct device *dev)
-+{
-+ return NULL;
-+}
-+
-+static inline void devm_pinctrl_put(struct pinctrl *p)
-+{
-+}
-+
- #endif /* CONFIG_PINCTRL */
-
- static inline struct pinctrl * __must_check pinctrl_get_select(
-@@ -113,6 +125,38 @@ static inline struct pinctrl * __must_check pinctrl_get_select_default(
- return pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
- }
-
-+static inline struct pinctrl * __must_check devm_pinctrl_get_select(
-+ struct device *dev, const char *name)
-+{
-+ struct pinctrl *p;
-+ struct pinctrl_state *s;
-+ int ret;
-+
-+ p = devm_pinctrl_get(dev);
-+ if (IS_ERR(p))
-+ return p;
-+
-+ s = pinctrl_lookup_state(p, name);
-+ if (IS_ERR(s)) {
-+ devm_pinctrl_put(p);
-+ return ERR_PTR(PTR_ERR(s));
-+ }
-+
-+ ret = pinctrl_select_state(p, s);
-+ if (ret < 0) {
-+ devm_pinctrl_put(p);
-+ return ERR_PTR(ret);
-+ }
-+
-+ return p;
-+}
-+
-+static inline struct pinctrl * __must_check devm_pinctrl_get_select_default(
-+ struct device *dev)
-+{
-+ return devm_pinctrl_get_select(dev, PINCTRL_STATE_DEFAULT);
-+}
-+
- #ifdef CONFIG_PINCONF
-
- extern int pin_config_get(const char *dev_name, const char *name,
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 7ba996263729126963359429782339ddf8705333 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:05 +0200
+Subject: crypto: add Atmel DES/TDES driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit 13802005d8f2db244ec1f5d7f6923de8f7a463db upstream.
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 16 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-tdes-regs.h | 89 +++
+ drivers/crypto/atmel-tdes.c | 1215 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1321 insertions(+)
+ create mode 100644 drivers/crypto/atmel-tdes-regs.h
+ create mode 100644 drivers/crypto/atmel-tdes.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 98c7da5..2124898 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -313,4 +313,20 @@ config CRYPTO_DEV_ATMEL_AES
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-aes.
+
++config CRYPTO_DEV_ATMEL_TDES
++ tristate "Support for Atmel DES/TDES hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_DES
++ select CRYPTO_CBC
++ select CRYPTO_ECB
++ select CRYPTO_ALGAPI
++ select CRYPTO_BLKCIPHER
++ help
++ Some Atmel processors have DES/TDES hw accelerator.
++ Select this if you want to use the Atmel module for
++ DES/TDES algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-tdes.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 73ad830..443bf4d 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -15,3 +15,4 @@ obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
+ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
+diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
+new file mode 100644
+index 0000000..5ac2a90
+--- /dev/null
++++ b/drivers/crypto/atmel-tdes-regs.h
+@@ -0,0 +1,89 @@
++#ifndef __ATMEL_TDES_REGS_H__
++#define __ATMEL_TDES_REGS_H__
++
++#define TDES_CR 0x00
++#define TDES_CR_START (1 << 0)
++#define TDES_CR_SWRST (1 << 8)
++#define TDES_CR_LOADSEED (1 << 16)
++
++#define TDES_MR 0x04
++#define TDES_MR_CYPHER_DEC (0 << 0)
++#define TDES_MR_CYPHER_ENC (1 << 0)
++#define TDES_MR_TDESMOD_MASK (0x3 << 1)
++#define TDES_MR_TDESMOD_DES (0x0 << 1)
++#define TDES_MR_TDESMOD_TDES (0x1 << 1)
++#define TDES_MR_TDESMOD_XTEA (0x2 << 1)
++#define TDES_MR_KEYMOD_3KEY (0 << 4)
++#define TDES_MR_KEYMOD_2KEY (1 << 4)
++#define TDES_MR_SMOD_MASK (0x3 << 8)
++#define TDES_MR_SMOD_MANUAL (0x0 << 8)
++#define TDES_MR_SMOD_AUTO (0x1 << 8)
++#define TDES_MR_SMOD_PDC (0x2 << 8)
++#define TDES_MR_OPMOD_MASK (0x3 << 12)
++#define TDES_MR_OPMOD_ECB (0x0 << 12)
++#define TDES_MR_OPMOD_CBC (0x1 << 12)
++#define TDES_MR_OPMOD_OFB (0x2 << 12)
++#define TDES_MR_OPMOD_CFB (0x3 << 12)
++#define TDES_MR_LOD (0x1 << 15)
++#define TDES_MR_CFBS_MASK (0x3 << 16)
++#define TDES_MR_CFBS_64b (0x0 << 16)
++#define TDES_MR_CFBS_32b (0x1 << 16)
++#define TDES_MR_CFBS_16b (0x2 << 16)
++#define TDES_MR_CFBS_8b (0x3 << 16)
++#define TDES_MR_CKEY_MASK (0xF << 20)
++#define TDES_MR_CKEY_OFFSET 20
++#define TDES_MR_CTYPE_MASK (0x3F << 24)
++#define TDES_MR_CTYPE_OFFSET 24
++
++#define TDES_IER 0x10
++#define TDES_IDR 0x14
++#define TDES_IMR 0x18
++#define TDES_ISR 0x1C
++#define TDES_INT_DATARDY (1 << 0)
++#define TDES_INT_ENDRX (1 << 1)
++#define TDES_INT_ENDTX (1 << 2)
++#define TDES_INT_RXBUFF (1 << 3)
++#define TDES_INT_TXBUFE (1 << 4)
++#define TDES_INT_URAD (1 << 8)
++#define TDES_ISR_URAT_MASK (0x3 << 12)
++#define TDES_ISR_URAT_IDR (0x0 << 12)
++#define TDES_ISR_URAT_ODR (0x1 << 12)
++#define TDES_ISR_URAT_MR (0x2 << 12)
++#define TDES_ISR_URAT_WO (0x3 << 12)
++
++
++#define TDES_KEY1W1R 0x20
++#define TDES_KEY1W2R 0x24
++#define TDES_KEY2W1R 0x28
++#define TDES_KEY2W2R 0x2C
++#define TDES_KEY3W1R 0x30
++#define TDES_KEY3W2R 0x34
++#define TDES_IDATA1R 0x40
++#define TDES_IDATA2R 0x44
++#define TDES_ODATA1R 0x50
++#define TDES_ODATA2R 0x54
++#define TDES_IV1R 0x60
++#define TDES_IV2R 0x64
++
++#define TDES_XTEARNDR 0x70
++#define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
++#define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
++
++#define TDES_RPR 0x100
++#define TDES_RCR 0x104
++#define TDES_TPR 0x108
++#define TDES_TCR 0x10C
++#define TDES_RNPR 0x118
++#define TDES_RNCR 0x11C
++#define TDES_TNPR 0x118
++#define TDES_TNCR 0x11C
++#define TDES_PTCR 0x120
++#define TDES_PTCR_RXTEN (1 << 0)
++#define TDES_PTCR_RXTDIS (1 << 1)
++#define TDES_PTCR_TXTEN (1 << 8)
++#define TDES_PTCR_TXTDIS (1 << 9)
++#define TDES_PTSR 0x124
++#define TDES_PTSR_RXTEN (1 << 0)
++#define TDES_PTSR_TXTEN (1 << 8)
++
++#endif /* __ATMEL_TDES_REGS_H__ */
+diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
+new file mode 100644
+index 0000000..eb2b61e
+--- /dev/null
++++ b/drivers/crypto/atmel-tdes.c
+@@ -0,0 +1,1215 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL DES/TDES HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Some ideas are from omap-aes.c drivers.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/des.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include "atmel-tdes-regs.h"
++
++/* TDES flags */
++#define TDES_FLAGS_MODE_MASK 0x007f
++#define TDES_FLAGS_ENCRYPT BIT(0)
++#define TDES_FLAGS_CBC BIT(1)
++#define TDES_FLAGS_CFB BIT(2)
++#define TDES_FLAGS_CFB8 BIT(3)
++#define TDES_FLAGS_CFB16 BIT(4)
++#define TDES_FLAGS_CFB32 BIT(5)
++#define TDES_FLAGS_OFB BIT(6)
++
++#define TDES_FLAGS_INIT BIT(16)
++#define TDES_FLAGS_FAST BIT(17)
++#define TDES_FLAGS_BUSY BIT(18)
++
++#define ATMEL_TDES_QUEUE_LENGTH 1
++
++#define CFB8_BLOCK_SIZE 1
++#define CFB16_BLOCK_SIZE 2
++#define CFB32_BLOCK_SIZE 4
++#define CFB64_BLOCK_SIZE 8
++
++
++struct atmel_tdes_dev;
++
++struct atmel_tdes_ctx {
++ struct atmel_tdes_dev *dd;
++
++ int keylen;
++ u32 key[3*DES_KEY_SIZE / sizeof(u32)];
++ unsigned long flags;
++};
++
++struct atmel_tdes_reqctx {
++ unsigned long mode;
++};
++
++struct atmel_tdes_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ void __iomem *io_base;
++
++ struct atmel_tdes_ctx *ctx;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++
++ unsigned long flags;
++ int err;
++
++ spinlock_t lock;
++ struct crypto_queue queue;
++
++ struct tasklet_struct done_task;
++ struct tasklet_struct queue_task;
++
++ struct ablkcipher_request *req;
++ size_t total;
++
++ struct scatterlist *in_sg;
++ size_t in_offset;
++ struct scatterlist *out_sg;
++ size_t out_offset;
++
++ size_t buflen;
++ size_t dma_size;
++
++ void *buf_in;
++ int dma_in;
++ dma_addr_t dma_addr_in;
++
++ void *buf_out;
++ int dma_out;
++ dma_addr_t dma_addr_out;
++};
++
++struct atmel_tdes_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_tdes_drv atmel_tdes = {
++ .dev_list = LIST_HEAD_INIT(atmel_tdes.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_tdes.lock),
++};
++
++static int atmel_tdes_sg_copy(struct scatterlist **sg, size_t *offset,
++ void *buf, size_t buflen, size_t total, int out)
++{
++ unsigned int count, off = 0;
++
++ while (buflen && total) {
++ count = min((*sg)->length - *offset, total);
++ count = min(count, buflen);
++
++ if (!count)
++ return off;
++
++ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
++
++ off += count;
++ buflen -= count;
++ *offset += count;
++ total -= count;
++
++ if (*offset == (*sg)->length) {
++ *sg = sg_next(*sg);
++ if (*sg)
++ *offset = 0;
++ else
++ total = 0;
++ }
++ }
++
++ return off;
++}
++
++static inline u32 atmel_tdes_read(struct atmel_tdes_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_tdes_write(struct atmel_tdes_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset,
++ u32 *value, int count)
++{
++ for (; count--; value++, offset += 4)
++ atmel_tdes_write(dd, offset, *value);
++}
++
++static struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx)
++{
++ struct atmel_tdes_dev *tdes_dd = NULL;
++ struct atmel_tdes_dev *tmp;
++
++ spin_lock_bh(&atmel_tdes.lock);
++ if (!ctx->dd) {
++ list_for_each_entry(tmp, &atmel_tdes.dev_list, list) {
++ tdes_dd = tmp;
++ break;
++ }
++ ctx->dd = tdes_dd;
++ } else {
++ tdes_dd = ctx->dd;
++ }
++ spin_unlock_bh(&atmel_tdes.lock);
++
++ return tdes_dd;
++}
++
++static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (!(dd->flags & TDES_FLAGS_INIT)) {
++ atmel_tdes_write(dd, TDES_CR, TDES_CR_SWRST);
++ dd->flags |= TDES_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
++{
++ int err;
++ u32 valcr = 0, valmr = TDES_MR_SMOD_PDC;
++
++ err = atmel_tdes_hw_init(dd);
++
++ if (err)
++ return err;
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++
++ /* MR register must be set before IV registers */
++ if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
++ valmr |= TDES_MR_KEYMOD_3KEY;
++ valmr |= TDES_MR_TDESMOD_TDES;
++ } else if (dd->ctx->keylen > DES_KEY_SIZE) {
++ valmr |= TDES_MR_KEYMOD_2KEY;
++ valmr |= TDES_MR_TDESMOD_TDES;
++ } else {
++ valmr |= TDES_MR_TDESMOD_DES;
++ }
++
++ if (dd->flags & TDES_FLAGS_CBC) {
++ valmr |= TDES_MR_OPMOD_CBC;
++ } else if (dd->flags & TDES_FLAGS_CFB) {
++ valmr |= TDES_MR_OPMOD_CFB;
++
++ if (dd->flags & TDES_FLAGS_CFB8)
++ valmr |= TDES_MR_CFBS_8b;
++ else if (dd->flags & TDES_FLAGS_CFB16)
++ valmr |= TDES_MR_CFBS_16b;
++ else if (dd->flags & TDES_FLAGS_CFB32)
++ valmr |= TDES_MR_CFBS_32b;
++ } else if (dd->flags & TDES_FLAGS_OFB) {
++ valmr |= TDES_MR_OPMOD_OFB;
++ }
++
++ if ((dd->flags & TDES_FLAGS_ENCRYPT) || (dd->flags & TDES_FLAGS_OFB))
++ valmr |= TDES_MR_CYPHER_ENC;
++
++ atmel_tdes_write(dd, TDES_CR, valcr);
++ atmel_tdes_write(dd, TDES_MR, valmr);
++
++ atmel_tdes_write_n(dd, TDES_KEY1W1R, dd->ctx->key,
++ dd->ctx->keylen >> 2);
++
++ if (((dd->flags & TDES_FLAGS_CBC) || (dd->flags & TDES_FLAGS_CFB) ||
++ (dd->flags & TDES_FLAGS_OFB)) && dd->req->info) {
++ atmel_tdes_write_n(dd, TDES_IV1R, dd->req->info, 2);
++ }
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++{
++ int err = 0;
++ size_t count;
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++
++ return err;
++}
++
++static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
++{
++ int err = -ENOMEM;
++
++ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buflen = PAGE_SIZE;
++ dd->buflen &= ~(DES_BLOCK_SIZE - 1);
++
++ if (!dd->buf_in || !dd->buf_out) {
++ dev_err(dd->dev, "unable to alloc pages.\n");
++ goto err_alloc;
++ }
++
++ /* MAP here */
++ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
++ dd->buflen, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_in;
++ }
++
++ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
++ dd->buflen, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_out;
++ }
++
++ return 0;
++
++err_map_out:
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++err_map_in:
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++err_alloc:
++ if (err)
++ pr_err("error: %d\n", err);
++ return err;
++}
++
++static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++{
++ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
++ DMA_FROM_DEVICE);
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++}
++
++static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++ dma_addr_t dma_addr_out, int length)
++{
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd = ctx->dd;
++ int len32;
++
++ dd->dma_size = length;
++
++ if (!(dd->flags & TDES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
++
++ if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB8))
++ len32 = DIV_ROUND_UP(length, sizeof(u8));
++ else if ((dd->flags & TDES_FLAGS_CFB) && (dd->flags & TDES_FLAGS_CFB16))
++ len32 = DIV_ROUND_UP(length, sizeof(u16));
++ else
++ len32 = DIV_ROUND_UP(length, sizeof(u32));
++
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++ atmel_tdes_write(dd, TDES_TPR, dma_addr_in);
++ atmel_tdes_write(dd, TDES_TCR, len32);
++ atmel_tdes_write(dd, TDES_RPR, dma_addr_out);
++ atmel_tdes_write(dd, TDES_RCR, len32);
++
++ /* Enable Interrupt */
++ atmel_tdes_write(dd, TDES_IER, TDES_INT_ENDRX);
++
++ /* Start DMA transfer */
++ atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTEN | TDES_PTCR_RXTEN);
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
++{
++ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
++ crypto_ablkcipher_reqtfm(dd->req));
++ int err, fast = 0, in, out;
++ size_t count;
++ dma_addr_t addr_in, addr_out;
++
++ if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
++ /* check for alignment */
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
++
++ fast = in && out;
++ }
++
++ if (fast) {
++ count = min(dd->total, sg_dma_len(dd->in_sg));
++ count = min(count, sg_dma_len(dd->out_sg));
++
++ if (count != dd->total) {
++ pr_err("request length != buffer length\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->out_sg, 1,
++ DMA_FROM_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ dma_unmap_sg(dd->dev, dd->in_sg, 1,
++ DMA_TO_DEVICE);
++ return -EINVAL;
++ }
++
++ addr_in = sg_dma_address(dd->in_sg);
++ addr_out = sg_dma_address(dd->out_sg);
++
++ dd->flags |= TDES_FLAGS_FAST;
++
++ } else {
++ /* use cache buffers */
++ count = atmel_tdes_sg_copy(&dd->in_sg, &dd->in_offset,
++ dd->buf_in, dd->buflen, dd->total, 0);
++
++ addr_in = dd->dma_addr_in;
++ addr_out = dd->dma_addr_out;
++
++ dd->flags &= ~TDES_FLAGS_FAST;
++
++ }
++
++ dd->total -= count;
++
++ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
++ if (err) {
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
++ }
++
++ return err;
++}
++
++
++static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
++{
++ struct ablkcipher_request *req = dd->req;
++
++ clk_disable_unprepare(dd->iclk);
++
++ dd->flags &= ~TDES_FLAGS_BUSY;
++
++ req->base.complete(&req->base, err);
++}
++
++static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
++ struct ablkcipher_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_tdes_ctx *ctx;
++ struct atmel_tdes_reqctx *rctx;
++ unsigned long flags;
++ int err, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ablkcipher_enqueue_request(&dd->queue, req);
++ if (dd->flags & TDES_FLAGS_BUSY) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= TDES_FLAGS_BUSY;
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ablkcipher_request_cast(async_req);
++
++ /* assign new request to device */
++ dd->req = req;
++ dd->total = req->nbytes;
++ dd->in_offset = 0;
++ dd->in_sg = req->src;
++ dd->out_offset = 0;
++ dd->out_sg = req->dst;
++
++ rctx = ablkcipher_request_ctx(req);
++ ctx = crypto_ablkcipher_ctx(crypto_ablkcipher_reqtfm(req));
++ rctx->mode &= TDES_FLAGS_MODE_MASK;
++ dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode;
++ dd->ctx = ctx;
++ ctx->dd = dd;
++
++ err = atmel_tdes_write_ctrl(dd);
++ if (!err)
++ err = atmel_tdes_crypt_dma_start(dd);
++ if (err) {
++ /* des_task will not finish it, so do it here */
++ atmel_tdes_finish_req(dd, err);
++ tasklet_schedule(&dd->queue_task);
++ }
++
++ return ret;
++}
++
++
++static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
++{
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
++ crypto_ablkcipher_reqtfm(req));
++ struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
++ struct atmel_tdes_dev *dd;
++
++ if (mode & TDES_FLAGS_CFB8) {
++ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB8 blocks\n");
++ return -EINVAL;
++ }
++ } else if (mode & TDES_FLAGS_CFB16) {
++ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB16 blocks\n");
++ return -EINVAL;
++ }
++ } else if (mode & TDES_FLAGS_CFB32) {
++ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB32 blocks\n");
++ return -EINVAL;
++ }
++ } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of DES blocks\n");
++ return -EINVAL;
++ }
++
++ dd = atmel_tdes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
++ rctx->mode = mode;
++
++ return atmel_tdes_handle_queue(dd, req);
++}
++
++static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ u32 tmp[DES_EXPKEY_WORDS];
++ int err;
++ struct crypto_tfm *ctfm = crypto_ablkcipher_tfm(tfm);
++
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != DES_KEY_SIZE) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ err = des_ekey(tmp, key);
++ if (err == 0 && (ctfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
++ ctfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
++ const char *alg_name;
++
++ alg_name = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
++
++ /*
++ * HW bug in cfb 3-keys mode.
++ */
++ if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ return -EINVAL;
++ }
++
++ memcpy(ctx->key, key, keylen);
++ ctx->keylen = keylen;
++
++ return 0;
++}
++
++static int atmel_tdes_ecb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT);
++}
++
++static int atmel_tdes_ecb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, 0);
++}
++
++static int atmel_tdes_cbc_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CBC);
++}
++
++static int atmel_tdes_cbc_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CBC);
++}
++static int atmel_tdes_cfb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB);
++}
++
++static int atmel_tdes_cfb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB);
++}
++
++static int atmel_tdes_cfb8_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB8);
++}
++
++static int atmel_tdes_cfb8_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB8);
++}
++
++static int atmel_tdes_cfb16_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB16);
++}
++
++static int atmel_tdes_cfb16_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB16);
++}
++
++static int atmel_tdes_cfb32_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_CFB |
++ TDES_FLAGS_CFB32);
++}
++
++static int atmel_tdes_cfb32_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_CFB | TDES_FLAGS_CFB32);
++}
++
++static int atmel_tdes_ofb_encrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_ENCRYPT | TDES_FLAGS_OFB);
++}
++
++static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
++{
++ return atmel_tdes_crypt(req, TDES_FLAGS_OFB);
++}
++
++static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
++{
++ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
++
++ return 0;
++}
++
++static void atmel_tdes_cra_exit(struct crypto_tfm *tfm)
++{
++}
++
++static struct crypto_alg tdes_algs[] = {
++{
++ .cra_name = "ecb(des)",
++ .cra_driver_name = "atmel-ecb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_ecb_encrypt,
++ .decrypt = atmel_tdes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "atmel-cbc-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cbc_encrypt,
++ .decrypt = atmel_tdes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(des)",
++ .cra_driver_name = "atmel-cfb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb_encrypt,
++ .decrypt = atmel_tdes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(des)",
++ .cra_driver_name = "atmel-cfb8-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB8_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb8_encrypt,
++ .decrypt = atmel_tdes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(des)",
++ .cra_driver_name = "atmel-cfb16-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb16_encrypt,
++ .decrypt = atmel_tdes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(des)",
++ .cra_driver_name = "atmel-cfb32-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_cfb32_encrypt,
++ .decrypt = atmel_tdes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(des)",
++ .cra_driver_name = "atmel-ofb-des",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_des_setkey,
++ .encrypt = atmel_tdes_ofb_encrypt,
++ .decrypt = atmel_tdes_ofb_decrypt,
++ }
++},
++{
++ .cra_name = "ecb(des3_ede)",
++ .cra_driver_name = "atmel-ecb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2 * DES_KEY_SIZE,
++ .max_keysize = 3 * DES_KEY_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_ecb_encrypt,
++ .decrypt = atmel_tdes_ecb_decrypt,
++ }
++},
++{
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "atmel-cbc-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 3*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cbc_encrypt,
++ .decrypt = atmel_tdes_cbc_decrypt,
++ }
++},
++{
++ .cra_name = "cfb(des3_ede)",
++ .cra_driver_name = "atmel-cfb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb_encrypt,
++ .decrypt = atmel_tdes_cfb_decrypt,
++ }
++},
++{
++ .cra_name = "cfb8(des3_ede)",
++ .cra_driver_name = "atmel-cfb8-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB8_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb8_encrypt,
++ .decrypt = atmel_tdes_cfb8_decrypt,
++ }
++},
++{
++ .cra_name = "cfb16(des3_ede)",
++ .cra_driver_name = "atmel-cfb16-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB16_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb16_encrypt,
++ .decrypt = atmel_tdes_cfb16_decrypt,
++ }
++},
++{
++ .cra_name = "cfb32(des3_ede)",
++ .cra_driver_name = "atmel-cfb32-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = CFB32_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 2*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_cfb32_encrypt,
++ .decrypt = atmel_tdes_cfb32_decrypt,
++ }
++},
++{
++ .cra_name = "ofb(des3_ede)",
++ .cra_driver_name = "atmel-ofb-tdes",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
++ .cra_alignmask = 0,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_tdes_cra_init,
++ .cra_exit = atmel_tdes_cra_exit,
++ .cra_u.ablkcipher = {
++ .min_keysize = 2*DES_KEY_SIZE,
++ .max_keysize = 3*DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = atmel_tdes_setkey,
++ .encrypt = atmel_tdes_ofb_encrypt,
++ .decrypt = atmel_tdes_ofb_decrypt,
++ }
++},
++};
++
++static void atmel_tdes_queue_task(unsigned long data)
++{
++ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *)data;
++
++ atmel_tdes_handle_queue(dd, NULL);
++}
++
++static void atmel_tdes_done_task(unsigned long data)
++{
++ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
++ int err;
++
++ err = atmel_tdes_crypt_dma_stop(dd);
++
++ err = dd->err ? : err;
++
++ if (dd->total && !err) {
++ err = atmel_tdes_crypt_dma_start(dd);
++ if (!err)
++ return;
++ }
++
++ atmel_tdes_finish_req(dd, err);
++ atmel_tdes_handle_queue(dd, NULL);
++}
++
++static irqreturn_t atmel_tdes_irq(int irq, void *dev_id)
++{
++ struct atmel_tdes_dev *tdes_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_tdes_read(tdes_dd, TDES_ISR);
++ if (reg & atmel_tdes_read(tdes_dd, TDES_IMR)) {
++ atmel_tdes_write(tdes_dd, TDES_IDR, reg);
++ if (TDES_FLAGS_BUSY & tdes_dd->flags)
++ tasklet_schedule(&tdes_dd->done_task);
++ else
++ dev_warn(tdes_dd->dev, "TDES interrupt when no active requests.\n");
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_tdes_unregister_algs(struct atmel_tdes_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++)
++ crypto_unregister_alg(&tdes_algs[i]);
++}
++
++static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
++ INIT_LIST_HEAD(&tdes_algs[i].cra_list);
++ err = crypto_register_alg(&tdes_algs[i]);
++ if (err)
++ goto err_tdes_algs;
++ }
++
++ return 0;
++
++err_tdes_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_alg(&tdes_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_tdes_probe(struct platform_device *pdev)
++{
++ struct atmel_tdes_dev *tdes_dd;
++ struct device *dev = &pdev->dev;
++ struct resource *tdes_res;
++ unsigned long tdes_phys_size;
++ int err;
++
++ tdes_dd = kzalloc(sizeof(struct atmel_tdes_dev), GFP_KERNEL);
++ if (tdes_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto tdes_dd_err;
++ }
++
++ tdes_dd->dev = dev;
++
++ platform_set_drvdata(pdev, tdes_dd);
++
++ INIT_LIST_HEAD(&tdes_dd->list);
++
++ tasklet_init(&tdes_dd->done_task, atmel_tdes_done_task,
++ (unsigned long)tdes_dd);
++ tasklet_init(&tdes_dd->queue_task, atmel_tdes_queue_task,
++ (unsigned long)tdes_dd);
++
++ crypto_init_queue(&tdes_dd->queue, ATMEL_TDES_QUEUE_LENGTH);
++
++ tdes_dd->irq = -1;
++
++ /* Get the base address */
++ tdes_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!tdes_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ tdes_dd->phys_base = tdes_res->start;
++ tdes_phys_size = resource_size(tdes_res);
++
++ /* Get the IRQ */
++ tdes_dd->irq = platform_get_irq(pdev, 0);
++ if (tdes_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = tdes_dd->irq;
++ goto res_err;
++ }
++
++ err = request_irq(tdes_dd->irq, atmel_tdes_irq, IRQF_SHARED,
++ "atmel-tdes", tdes_dd);
++ if (err) {
++ dev_err(dev, "unable to request tdes irq.\n");
++ goto tdes_irq_err;
++ }
++
++ /* Initializing the clock */
++ tdes_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(tdes_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(tdes_dd->iclk);
++ goto clk_err;
++ }
++
++ tdes_dd->io_base = ioremap(tdes_dd->phys_base, tdes_phys_size);
++ if (!tdes_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto tdes_io_err;
++ }
++
++ err = atmel_tdes_dma_init(tdes_dd);
++ if (err)
++ goto err_tdes_dma;
++
++ spin_lock(&atmel_tdes.lock);
++ list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
++ spin_unlock(&atmel_tdes.lock);
++
++ err = atmel_tdes_register_algs(tdes_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel DES/TDES\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_tdes.lock);
++ list_del(&tdes_dd->list);
++ spin_unlock(&atmel_tdes.lock);
++ atmel_tdes_dma_cleanup(tdes_dd);
++err_tdes_dma:
++ iounmap(tdes_dd->io_base);
++tdes_io_err:
++ clk_put(tdes_dd->iclk);
++clk_err:
++ free_irq(tdes_dd->irq, tdes_dd);
++tdes_irq_err:
++res_err:
++ tasklet_kill(&tdes_dd->done_task);
++ tasklet_kill(&tdes_dd->queue_task);
++ kfree(tdes_dd);
++ tdes_dd = NULL;
++tdes_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_tdes_remove(struct platform_device *pdev)
++{
++ static struct atmel_tdes_dev *tdes_dd;
++
++ tdes_dd = platform_get_drvdata(pdev);
++ if (!tdes_dd)
++ return -ENODEV;
++ spin_lock(&atmel_tdes.lock);
++ list_del(&tdes_dd->list);
++ spin_unlock(&atmel_tdes.lock);
++
++ atmel_tdes_unregister_algs(tdes_dd);
++
++ tasklet_kill(&tdes_dd->done_task);
++ tasklet_kill(&tdes_dd->queue_task);
++
++ atmel_tdes_dma_cleanup(tdes_dd);
++
++ iounmap(tdes_dd->io_base);
++
++ clk_put(tdes_dd->iclk);
++
++ if (tdes_dd->irq >= 0)
++ free_irq(tdes_dd->irq, tdes_dd);
++
++ kfree(tdes_dd);
++ tdes_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_tdes_driver = {
++ .probe = atmel_tdes_probe,
++ .remove = __devexit_p(atmel_tdes_remove),
++ .driver = {
++ .name = "atmel_tdes",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_tdes_driver);
++
++MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 489c95dd039fae25e560ef219754a3ce4f9fd501 Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Thu, 26 Apr 2012 16:15:50 +0800
-Subject: pinctrl: add pinctrl_provide_dummies interface for platforms to use
-
-Add a interface pinctrl_provide_dummies for platform to indicate
-whether it needs use pinctrl dummy state.
-
-ChangeLog v3->v4:
-* remove dummy gpio support in pinctrl subsystem.
- Let gpio driver decide whether it wants to use pinctrl gpio mux
- function.
-ChangeLog v2->v3:
-* Also changed the missed pinctrl gpio APIs in v1.
-ChangeLog v1->v2:
-* Based on sascha's suggestion, drop using kconfig since it will hide
- pinctrl errors on all other boards.
- See: https://lkml.org/lkml/2012/4/18/282
- It seemed both Linus and Stephen agreed with this way, so i'm ok
- with it too.
-* Add dummy gpio support.
- pinctrl gpio in the same situation as state.
-* Patch name changed.
- Original is pinctrl: handle dummy state in core.
-* Split removing old dt dummy interface into a separate patch
-
-Cc: Linus Walleij <linus.walleij@linaro.org>
-Cc: Sascha Hauer <s.hauer@pengutronix.de>
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 29 +++++++++++++++++++++++++++--
- include/linux/pinctrl/machine.h | 5 ++++-
- 2 files changed, 31 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index f4544f4..2b6363c5 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -43,6 +43,8 @@ struct pinctrl_maps {
- unsigned num_maps;
- };
-
-+static bool pinctrl_dummy_state;
-+
- /* Mutex taken by all entry points */
- DEFINE_MUTEX(pinctrl_mutex);
-
-@@ -61,6 +63,19 @@ static LIST_HEAD(pinctrl_maps);
- _i_ < _maps_node_->num_maps; \
- i++, _map_ = &_maps_node_->maps[_i_])
-
-+/**
-+ * pinctrl_provide_dummies() - indicate if pinctrl provides dummy state support
-+ *
-+ * Usually this function is called by platforms without pinctrl driver support
-+ * but run with some shared drivers using pinctrl APIs.
-+ * After calling this function, the pinctrl core will return successfully
-+ * with creating a dummy state for the driver to keep going smoothly.
-+ */
-+void pinctrl_provide_dummies(void)
-+{
-+ pinctrl_dummy_state = true;
-+}
-+
- const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev)
- {
- /* We're not allowed to register devices without name */
-@@ -696,8 +711,18 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
- struct pinctrl_state *state;
-
- state = find_state(p, name);
-- if (!state)
-- return ERR_PTR(-ENODEV);
-+ if (!state) {
-+ if (pinctrl_dummy_state) {
-+ /* create dummy state */
-+ dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
-+ name);
-+ state = create_state(p, name);
-+ if (IS_ERR(state))
-+ return state;
-+ } else {
-+ return ERR_PTR(-ENODEV);
-+ }
-+ }
-
- return state;
- }
-diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
-index 9c4a198..7d22ab0 100644
---- a/include/linux/pinctrl/machine.h
-+++ b/include/linux/pinctrl/machine.h
-@@ -154,7 +154,7 @@ struct pinctrl_map {
-
- extern int pinctrl_register_mappings(struct pinctrl_map const *map,
- unsigned num_maps);
--
-+extern void pinctrl_provide_dummies(void);
- #else
-
- static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
-@@ -163,5 +163,8 @@ static inline int pinctrl_register_mappings(struct pinctrl_map const *map,
- return 0;
- }
-
-+static inline void pinctrl_provide_dummies(void)
-+{
-+}
- #endif /* !CONFIG_PINCTRL */
- #endif
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 08f29ab9122d183ff7b1d1057cd9f172748a6026 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:06 +0200
+Subject: crypto: add Atmel SHA1/SHA256 driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit ebc82efa1cd64efba0f41455460411b852b5b89c upstream.
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 14 +
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-sha-regs.h | 46 ++
+ drivers/crypto/atmel-sha.c | 1112 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 1173 insertions(+)
+ create mode 100644 drivers/crypto/atmel-sha-regs.h
+ create mode 100644 drivers/crypto/atmel-sha.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 2124898..2339add 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -329,4 +329,18 @@ config CRYPTO_DEV_ATMEL_TDES
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-tdes.
+
++config CRYPTO_DEV_ATMEL_SHA
++ tristate "Support for Atmel SHA1/SHA256 hw accelerator"
++ depends on ARCH_AT91
++ select CRYPTO_SHA1
++ select CRYPTO_SHA256
++ select CRYPTO_ALGAPI
++ help
++ Some Atmel processors have SHA1/SHA256 hw accelerator.
++ Select this if you want to use the Atmel module for
++ SHA1/SHA256 algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-sha.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 443bf4d..d355c25 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -16,3 +16,4 @@ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
+diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
+new file mode 100644
+index 0000000..dc53a20
+--- /dev/null
++++ b/drivers/crypto/atmel-sha-regs.h
+@@ -0,0 +1,46 @@
++#ifndef __ATMEL_SHA_REGS_H__
++#define __ATMEL_SHA_REGS_H__
++
++#define SHA_REG_DIGEST(x) (0x80 + ((x) * 0x04))
++#define SHA_REG_DIN(x) (0x40 + ((x) * 0x04))
++
++#define SHA_CR 0x00
++#define SHA_CR_START (1 << 0)
++#define SHA_CR_FIRST (1 << 4)
++#define SHA_CR_SWRST (1 << 8)
++
++#define SHA_MR 0x04
++#define SHA_MR_MODE_MASK (0x3 << 0)
++#define SHA_MR_MODE_MANUAL 0x0
++#define SHA_MR_MODE_AUTO 0x1
++#define SHA_MR_MODE_PDC 0x2
++#define SHA_MR_DUALBUFF (1 << 3)
++#define SHA_MR_PROCDLY (1 << 4)
++#define SHA_MR_ALGO_SHA1 (0 << 8)
++#define SHA_MR_ALGO_SHA256 (1 << 8)
++
++#define SHA_IER 0x10
++#define SHA_IDR 0x14
++#define SHA_IMR 0x18
++#define SHA_ISR 0x1C
++#define SHA_INT_DATARDY (1 << 0)
++#define SHA_INT_ENDTX (1 << 1)
++#define SHA_INT_TXBUFE (1 << 2)
++#define SHA_INT_URAD (1 << 8)
++#define SHA_ISR_URAT_MASK (0x7 << 12)
++#define SHA_ISR_URAT_IDR (0x0 << 12)
++#define SHA_ISR_URAT_ODR (0x1 << 12)
++#define SHA_ISR_URAT_MR (0x2 << 12)
++#define SHA_ISR_URAT_WO (0x5 << 12)
++
++#define SHA_TPR 0x108
++#define SHA_TCR 0x10C
++#define SHA_TNPR 0x118
++#define SHA_TNCR 0x11C
++#define SHA_PTCR 0x120
++#define SHA_PTCR_TXTEN (1 << 8)
++#define SHA_PTCR_TXTDIS (1 << 9)
++#define SHA_PTSR 0x124
++#define SHA_PTSR_TXTEN (1 << 8)
++
++#endif /* __ATMEL_SHA_REGS_H__ */
+diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
+new file mode 100644
+index 0000000..f938b9d
+--- /dev/null
++++ b/drivers/crypto/atmel-sha.c
+@@ -0,0 +1,1112 @@
++/*
++ * Cryptographic API.
++ *
++ * Support for ATMEL SHA1/SHA256 HW acceleration.
++ *
++ * Copyright (c) 2012 Eukréa Electromatique - ATMEL
++ * Author: Nicolas Royer <nicolas@eukrea.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ * Some ideas are from omap-sham.c drivers.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/hw_random.h>
++#include <linux/platform_device.h>
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/delay.h>
++#include <linux/crypto.h>
++#include <linux/cryptohash.h>
++#include <crypto/scatterwalk.h>
++#include <crypto/algapi.h>
++#include <crypto/sha.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include "atmel-sha-regs.h"
++
++/* SHA flags */
++#define SHA_FLAGS_BUSY BIT(0)
++#define SHA_FLAGS_FINAL BIT(1)
++#define SHA_FLAGS_DMA_ACTIVE BIT(2)
++#define SHA_FLAGS_OUTPUT_READY BIT(3)
++#define SHA_FLAGS_INIT BIT(4)
++#define SHA_FLAGS_CPU BIT(5)
++#define SHA_FLAGS_DMA_READY BIT(6)
++
++#define SHA_FLAGS_FINUP BIT(16)
++#define SHA_FLAGS_SG BIT(17)
++#define SHA_FLAGS_SHA1 BIT(18)
++#define SHA_FLAGS_SHA256 BIT(19)
++#define SHA_FLAGS_ERROR BIT(20)
++#define SHA_FLAGS_PAD BIT(21)
++
++#define SHA_FLAGS_DUALBUFF BIT(24)
++
++#define SHA_OP_UPDATE 1
++#define SHA_OP_FINAL 2
++
++#define SHA_BUFFER_LEN PAGE_SIZE
++
++#define ATMEL_SHA_DMA_THRESHOLD 56
++
++
++struct atmel_sha_dev;
++
++struct atmel_sha_reqctx {
++ struct atmel_sha_dev *dd;
++ unsigned long flags;
++ unsigned long op;
++
++ u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
++ size_t digcnt;
++ size_t bufcnt;
++ size_t buflen;
++ dma_addr_t dma_addr;
++
++ /* walk state */
++ struct scatterlist *sg;
++ unsigned int offset; /* offset in current sg */
++ unsigned int total; /* total request */
++
++ u8 buffer[0] __aligned(sizeof(u32));
++};
++
++struct atmel_sha_ctx {
++ struct atmel_sha_dev *dd;
++
++ unsigned long flags;
++
++ /* fallback stuff */
++ struct crypto_shash *fallback;
++
++};
++
++#define ATMEL_SHA_QUEUE_LENGTH 1
++
++struct atmel_sha_dev {
++ struct list_head list;
++ unsigned long phys_base;
++ struct device *dev;
++ struct clk *iclk;
++ int irq;
++ void __iomem *io_base;
++
++ spinlock_t lock;
++ int err;
++ struct tasklet_struct done_task;
++
++ unsigned long flags;
++ struct crypto_queue queue;
++ struct ahash_request *req;
++};
++
++struct atmel_sha_drv {
++ struct list_head dev_list;
++ spinlock_t lock;
++};
++
++static struct atmel_sha_drv atmel_sha = {
++ .dev_list = LIST_HEAD_INIT(atmel_sha.dev_list),
++ .lock = __SPIN_LOCK_UNLOCKED(atmel_sha.lock),
++};
++
++static inline u32 atmel_sha_read(struct atmel_sha_dev *dd, u32 offset)
++{
++ return readl_relaxed(dd->io_base + offset);
++}
++
++static inline void atmel_sha_write(struct atmel_sha_dev *dd,
++ u32 offset, u32 value)
++{
++ writel_relaxed(value, dd->io_base + offset);
++}
++
++static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
++{
++ atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
++
++ if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
++ dd->flags |= SHA_FLAGS_DUALBUFF;
++}
++
++static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
++{
++ size_t count;
++
++ while ((ctx->bufcnt < ctx->buflen) && ctx->total) {
++ count = min(ctx->sg->length - ctx->offset, ctx->total);
++ count = min(count, ctx->buflen - ctx->bufcnt);
++
++ if (count <= 0)
++ break;
++
++ scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, ctx->sg,
++ ctx->offset, count, 0);
++
++ ctx->bufcnt += count;
++ ctx->offset += count;
++ ctx->total -= count;
++
++ if (ctx->offset == ctx->sg->length) {
++ ctx->sg = sg_next(ctx->sg);
++ if (ctx->sg)
++ ctx->offset = 0;
++ else
++ ctx->total = 0;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * The purpose of this padding is to ensure that the padded message
++ * is a multiple of 512 bits. The bit "1" is appended at the end of
++ * the message followed by "padlen-1" zero bits. Then a 64 bits block
++ * equals to the message length in bits is appended.
++ *
++ * padlen is calculated as followed:
++ * - if message length < 56 bytes then padlen = 56 - message length
++ * - else padlen = 64 + 56 - message length
++ */
++static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
++{
++ unsigned int index, padlen;
++ u64 bits;
++ u64 size;
++
++ bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
++ size = cpu_to_be64(bits);
++
++ index = ctx->bufcnt & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
++ ctx->bufcnt += padlen + 8;
++ ctx->flags |= SHA_FLAGS_PAD;
++}
++
++static int atmel_sha_init(struct ahash_request *req)
++{
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
++ struct atmel_sha_ctx *tctx = crypto_ahash_ctx(tfm);
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = NULL;
++ struct atmel_sha_dev *tmp;
++
++ spin_lock_bh(&atmel_sha.lock);
++ if (!tctx->dd) {
++ list_for_each_entry(tmp, &atmel_sha.dev_list, list) {
++ dd = tmp;
++ break;
++ }
++ tctx->dd = dd;
++ } else {
++ dd = tctx->dd;
++ }
++
++ spin_unlock_bh(&atmel_sha.lock);
++
++ ctx->dd = dd;
++
++ ctx->flags = 0;
++
++ dev_dbg(dd->dev, "init: digest size: %d\n",
++ crypto_ahash_digestsize(tfm));
++
++ if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
++ ctx->flags |= SHA_FLAGS_SHA1;
++ else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
++ ctx->flags |= SHA_FLAGS_SHA256;
++
++ ctx->bufcnt = 0;
++ ctx->digcnt = 0;
++ ctx->buflen = SHA_BUFFER_LEN;
++
++ return 0;
++}
++
++static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
++
++ if (likely(dma)) {
++ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
++ valmr = SHA_MR_MODE_PDC;
++ if (dd->flags & SHA_FLAGS_DUALBUFF)
++ valmr = SHA_MR_DUALBUFF;
++ } else {
++ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
++ }
++
++ if (ctx->flags & SHA_FLAGS_SHA256)
++ valmr |= SHA_MR_ALGO_SHA256;
++
++ /* Setting CR_FIRST only for the first iteration */
++ if (!ctx->digcnt)
++ valcr = SHA_CR_FIRST;
++
++ atmel_sha_write(dd, SHA_CR, valcr);
++ atmel_sha_write(dd, SHA_MR, valmr);
++}
++
++static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
++ size_t length, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int count, len32;
++ const u32 *buffer = (const u32 *)buf;
++
++ dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
++ ctx->digcnt, length, final);
++
++ atmel_sha_write_ctrl(dd, 0);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt += length;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ len32 = DIV_ROUND_UP(length, sizeof(u32));
++
++ dd->flags |= SHA_FLAGS_CPU;
++
++ for (count = 0; count < len32; count++)
++ atmel_sha_write(dd, SHA_REG_DIN(count), buffer[count]);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int len32;
++
++ dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
++ ctx->digcnt, length1, final);
++
++ len32 = DIV_ROUND_UP(length1, sizeof(u32));
++ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
++ atmel_sha_write(dd, SHA_TPR, dma_addr1);
++ atmel_sha_write(dd, SHA_TCR, len32);
++
++ len32 = DIV_ROUND_UP(length2, sizeof(u32));
++ atmel_sha_write(dd, SHA_TNPR, dma_addr2);
++ atmel_sha_write(dd, SHA_TNCR, len32);
++
++ atmel_sha_write_ctrl(dd, 1);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt += length1;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
++
++ /* Start DMA transfer */
++ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTEN);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ int bufcnt;
++
++ atmel_sha_append_sg(ctx);
++ atmel_sha_fill_padding(ctx, 0);
++
++ bufcnt = ctx->bufcnt;
++ ctx->bufcnt = 0;
++
++ return atmel_sha_xmit_cpu(dd, ctx->buffer, bufcnt, 1);
++}
++
++static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
++ struct atmel_sha_reqctx *ctx,
++ size_t length, int final)
++{
++ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
++ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
++ SHA1_BLOCK_SIZE);
++ return -EINVAL;
++ }
++
++ ctx->flags &= ~SHA_FLAGS_SG;
++
++ /* next call does not fail... so no unmap in the case of error */
++ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
++}
++
++static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ unsigned int final;
++ size_t count;
++
++ atmel_sha_append_sg(ctx);
++
++ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
++
++ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
++ ctx->bufcnt, ctx->digcnt, final);
++
++ if (final)
++ atmel_sha_fill_padding(ctx, 0);
++
++ if (final || (ctx->bufcnt == ctx->buflen && ctx->total)) {
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_dma_map(dd, ctx, count, final);
++ }
++
++ return 0;
++}
++
++static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ unsigned int length, final, tail;
++ struct scatterlist *sg;
++ unsigned int count;
++
++ if (!ctx->total)
++ return 0;
++
++ if (ctx->bufcnt || ctx->offset)
++ return atmel_sha_update_dma_slow(dd);
++
++ dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
++ ctx->digcnt, ctx->bufcnt, ctx->total);
++
++ sg = ctx->sg;
++
++ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
++ return atmel_sha_update_dma_slow(dd);
++
++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
++ /* size is not SHA1_BLOCK_SIZE aligned */
++ return atmel_sha_update_dma_slow(dd);
++
++ length = min(ctx->total, sg->length);
++
++ if (sg_is_last(sg)) {
++ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
++ /* not last sg must be SHA1_BLOCK_SIZE aligned */
++ tail = length & (SHA1_BLOCK_SIZE - 1);
++ length -= tail;
++ if (length == 0) {
++ /* offset where to start slow */
++ ctx->offset = length;
++ return atmel_sha_update_dma_slow(dd);
++ }
++ }
++ }
++
++ ctx->total -= length;
++ ctx->offset = length; /* offset where to start slow */
++
++ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
++
++ /* Add padding */
++ if (final) {
++ tail = length & (SHA1_BLOCK_SIZE - 1);
++ length -= tail;
++ ctx->total += tail;
++ ctx->offset = length; /* offset where to start slow */
++
++ sg = ctx->sg;
++ atmel_sha_append_sg(ctx);
++
++ atmel_sha_fill_padding(ctx, length);
++
++ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
++ dev_err(dd->dev, "dma %u bytes error\n",
++ ctx->buflen + SHA1_BLOCK_SIZE);
++ return -EINVAL;
++ }
++
++ if (length == 0) {
++ ctx->flags &= ~SHA_FLAGS_SG;
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
++ 0, final);
++ } else {
++ ctx->sg = sg;
++ if (!dma_map_sg(dd->dev, ctx->sg, 1,
++ DMA_TO_DEVICE)) {
++ dev_err(dd->dev, "dma_map_sg error\n");
++ return -EINVAL;
++ }
++
++ ctx->flags |= SHA_FLAGS_SG;
++
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
++ length, ctx->dma_addr, count, final);
++ }
++ }
++
++ if (!dma_map_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE)) {
++ dev_err(dd->dev, "dma_map_sg error\n");
++ return -EINVAL;
++ }
++
++ ctx->flags |= SHA_FLAGS_SG;
++
++ /* next call does not fail... so no unmap in the case of error */
++ return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
++ 0, final);
++}
++
++static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++
++ if (ctx->flags & SHA_FLAGS_SG) {
++ dma_unmap_sg(dd->dev, ctx->sg, 1, DMA_TO_DEVICE);
++ if (ctx->sg->length == ctx->offset) {
++ ctx->sg = sg_next(ctx->sg);
++ if (ctx->sg)
++ ctx->offset = 0;
++ }
++ if (ctx->flags & SHA_FLAGS_PAD)
++ dma_unmap_single(dd->dev, ctx->dma_addr,
++ ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ } else {
++ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
++ SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ }
++
++ return 0;
++}
++
++static int atmel_sha_update_req(struct atmel_sha_dev *dd)
++{
++ struct ahash_request *req = dd->req;
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err;
++
++ dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
++ ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
++
++ if (ctx->flags & SHA_FLAGS_CPU)
++ err = atmel_sha_update_cpu(dd);
++ else
++ err = atmel_sha_update_dma_start(dd);
++
++ /* wait for dma completion before can take more data */
++ dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
++ err, ctx->digcnt);
++
++ return err;
++}
++
++static int atmel_sha_final_req(struct atmel_sha_dev *dd)
++{
++ struct ahash_request *req = dd->req;
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err = 0;
++ int count;
++
++ if (ctx->bufcnt >= ATMEL_SHA_DMA_THRESHOLD) {
++ atmel_sha_fill_padding(ctx, 0);
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ err = atmel_sha_xmit_dma_map(dd, ctx, count, 1);
++ }
++ /* faster to handle last block with cpu */
++ else {
++ atmel_sha_fill_padding(ctx, 0);
++ count = ctx->bufcnt;
++ ctx->bufcnt = 0;
++ err = atmel_sha_xmit_cpu(dd, ctx->buffer, count, 1);
++ }
++
++ dev_dbg(dd->dev, "final_req: err: %d\n", err);
++
++ return err;
++}
++
++static void atmel_sha_copy_hash(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ u32 *hash = (u32 *)ctx->digest;
++ int i;
++
++ if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else
++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++}
++
++static void atmel_sha_copy_ready_hash(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++
++ if (!req->result)
++ return;
++
++ if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
++ else
++ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
++}
++
++static int atmel_sha_finish(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = ctx->dd;
++ int err = 0;
++
++ if (ctx->digcnt)
++ atmel_sha_copy_ready_hash(req);
++
++ dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
++ ctx->bufcnt);
++
++ return err;
++}
++
++static void atmel_sha_finish_req(struct ahash_request *req, int err)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_dev *dd = ctx->dd;
++
++ if (!err) {
++ atmel_sha_copy_hash(req);
++ if (SHA_FLAGS_FINAL & dd->flags)
++ err = atmel_sha_finish(req);
++ } else {
++ ctx->flags |= SHA_FLAGS_ERROR;
++ }
++
++ /* atomic operation is not needed here */
++ dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU |
++ SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY);
++
++ clk_disable_unprepare(dd->iclk);
++
++ if (req->base.complete)
++ req->base.complete(&req->base, err);
++
++ /* handle new request */
++ tasklet_schedule(&dd->done_task);
++}
++
++static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
++{
++ clk_prepare_enable(dd->iclk);
++
++ if (SHA_FLAGS_INIT & dd->flags) {
++ atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
++ atmel_sha_dualbuff_test(dd);
++ dd->flags |= SHA_FLAGS_INIT;
++ dd->err = 0;
++ }
++
++ return 0;
++}
++
++static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
++ struct ahash_request *req)
++{
++ struct crypto_async_request *async_req, *backlog;
++ struct atmel_sha_reqctx *ctx;
++ unsigned long flags;
++ int err = 0, ret = 0;
++
++ spin_lock_irqsave(&dd->lock, flags);
++ if (req)
++ ret = ahash_enqueue_request(&dd->queue, req);
++
++ if (SHA_FLAGS_BUSY & dd->flags) {
++ spin_unlock_irqrestore(&dd->lock, flags);
++ return ret;
++ }
++
++ backlog = crypto_get_backlog(&dd->queue);
++ async_req = crypto_dequeue_request(&dd->queue);
++ if (async_req)
++ dd->flags |= SHA_FLAGS_BUSY;
++
++ spin_unlock_irqrestore(&dd->lock, flags);
++
++ if (!async_req)
++ return ret;
++
++ if (backlog)
++ backlog->complete(backlog, -EINPROGRESS);
++
++ req = ahash_request_cast(async_req);
++ dd->req = req;
++ ctx = ahash_request_ctx(req);
++
++ dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
++ ctx->op, req->nbytes);
++
++ err = atmel_sha_hw_init(dd);
++
++ if (err)
++ goto err1;
++
++ if (ctx->op == SHA_OP_UPDATE) {
++ err = atmel_sha_update_req(dd);
++ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
++ /* no final() after finup() */
++ err = atmel_sha_final_req(dd);
++ }
++ } else if (ctx->op == SHA_OP_FINAL) {
++ err = atmel_sha_final_req(dd);
++ }
++
++err1:
++ if (err != -EINPROGRESS)
++ /* done_task will not finish it, so do it here */
++ atmel_sha_finish_req(req, err);
++
++ dev_dbg(dd->dev, "exit, err: %d\n", err);
++
++ return ret;
++}
++
++static int atmel_sha_enqueue(struct ahash_request *req, unsigned int op)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
++ struct atmel_sha_dev *dd = tctx->dd;
++
++ ctx->op = op;
++
++ return atmel_sha_handle_queue(dd, req);
++}
++
++static int atmel_sha_update(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++
++ if (!req->nbytes)
++ return 0;
++
++ ctx->total = req->nbytes;
++ ctx->sg = req->src;
++ ctx->offset = 0;
++
++ if (ctx->flags & SHA_FLAGS_FINUP) {
++ if (ctx->bufcnt + ctx->total < ATMEL_SHA_DMA_THRESHOLD)
++ /* faster to use CPU for short transfers */
++ ctx->flags |= SHA_FLAGS_CPU;
++ } else if (ctx->bufcnt + ctx->total < ctx->buflen) {
++ atmel_sha_append_sg(ctx);
++ return 0;
++ }
++ return atmel_sha_enqueue(req, SHA_OP_UPDATE);
++}
++
++static int atmel_sha_final(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
++ struct atmel_sha_dev *dd = tctx->dd;
++
++ int err = 0;
++
++ ctx->flags |= SHA_FLAGS_FINUP;
++
++ if (ctx->flags & SHA_FLAGS_ERROR)
++ return 0; /* uncompleted hash is not needed */
++
++ if (ctx->bufcnt) {
++ return atmel_sha_enqueue(req, SHA_OP_FINAL);
++ } else if (!(ctx->flags & SHA_FLAGS_PAD)) { /* add padding */
++ err = atmel_sha_hw_init(dd);
++ if (err)
++ goto err1;
++
++ dd->flags |= SHA_FLAGS_BUSY;
++ err = atmel_sha_final_req(dd);
++ } else {
++ /* copy ready hash (+ finalize hmac) */
++ return atmel_sha_finish(req);
++ }
++
++err1:
++ if (err != -EINPROGRESS)
++ /* done_task will not finish it, so do it here */
++ atmel_sha_finish_req(req, err);
++
++ return err;
++}
++
++static int atmel_sha_finup(struct ahash_request *req)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
++ int err1, err2;
++
++ ctx->flags |= SHA_FLAGS_FINUP;
++
++ err1 = atmel_sha_update(req);
++ if (err1 == -EINPROGRESS || err1 == -EBUSY)
++ return err1;
++
++ /*
++ * final() has to be always called to cleanup resources
++ * even if udpate() failed, except EINPROGRESS
++ */
++ err2 = atmel_sha_final(req);
++
++ return err1 ?: err2;
++}
++
++static int atmel_sha_digest(struct ahash_request *req)
++{
++ return atmel_sha_init(req) ?: atmel_sha_finup(req);
++}
++
++static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
++{
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
++ const char *alg_name = crypto_tfm_alg_name(tfm);
++
++ /* Allocate a fallback and abort if it failed. */
++ tctx->fallback = crypto_alloc_shash(alg_name, 0,
++ CRYPTO_ALG_NEED_FALLBACK);
++ if (IS_ERR(tctx->fallback)) {
++ pr_err("atmel-sha: fallback driver '%s' could not be loaded.\n",
++ alg_name);
++ return PTR_ERR(tctx->fallback);
++ }
++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
++ sizeof(struct atmel_sha_reqctx) +
++ SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
++
++ return 0;
++}
++
++static int atmel_sha_cra_init(struct crypto_tfm *tfm)
++{
++ return atmel_sha_cra_init_alg(tfm, NULL);
++}
++
++static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
++{
++ struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
++
++ crypto_free_shash(tctx->fallback);
++ tctx->fallback = NULL;
++}
++
++static struct ahash_alg sha_algs[] = {
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha1",
++ .cra_driver_name = "atmel-sha1",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA1_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA256_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha256",
++ .cra_driver_name = "atmel-sha256",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA256_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++};
++
++static void atmel_sha_done_task(unsigned long data)
++{
++ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
++ int err = 0;
++
++ if (!(SHA_FLAGS_BUSY & dd->flags)) {
++ atmel_sha_handle_queue(dd, NULL);
++ return;
++ }
++
++ if (SHA_FLAGS_CPU & dd->flags) {
++ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
++ dd->flags &= ~SHA_FLAGS_OUTPUT_READY;
++ goto finish;
++ }
++ } else if (SHA_FLAGS_DMA_READY & dd->flags) {
++ if (SHA_FLAGS_DMA_ACTIVE & dd->flags) {
++ dd->flags &= ~SHA_FLAGS_DMA_ACTIVE;
++ atmel_sha_update_dma_stop(dd);
++ if (dd->err) {
++ err = dd->err;
++ goto finish;
++ }
++ }
++ if (SHA_FLAGS_OUTPUT_READY & dd->flags) {
++ /* hash or semi-hash ready */
++ dd->flags &= ~(SHA_FLAGS_DMA_READY |
++ SHA_FLAGS_OUTPUT_READY);
++ err = atmel_sha_update_dma_start(dd);
++ if (err != -EINPROGRESS)
++ goto finish;
++ }
++ }
++ return;
++
++finish:
++ /* finish curent request */
++ atmel_sha_finish_req(dd->req, err);
++}
++
++static irqreturn_t atmel_sha_irq(int irq, void *dev_id)
++{
++ struct atmel_sha_dev *sha_dd = dev_id;
++ u32 reg;
++
++ reg = atmel_sha_read(sha_dd, SHA_ISR);
++ if (reg & atmel_sha_read(sha_dd, SHA_IMR)) {
++ atmel_sha_write(sha_dd, SHA_IDR, reg);
++ if (SHA_FLAGS_BUSY & sha_dd->flags) {
++ sha_dd->flags |= SHA_FLAGS_OUTPUT_READY;
++ if (!(SHA_FLAGS_CPU & sha_dd->flags))
++ sha_dd->flags |= SHA_FLAGS_DMA_READY;
++ tasklet_schedule(&sha_dd->done_task);
++ } else {
++ dev_warn(sha_dd->dev, "SHA interrupt when no active requests.\n");
++ }
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
++ crypto_unregister_ahash(&sha_algs[i]);
++}
++
++static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
++{
++ int err, i, j;
++
++ for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
++ err = crypto_register_ahash(&sha_algs[i]);
++ if (err)
++ goto err_sha_algs;
++ }
++
++ return 0;
++
++err_sha_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_ahash(&sha_algs[j]);
++
++ return err;
++}
++
++static int __devinit atmel_sha_probe(struct platform_device *pdev)
++{
++ struct atmel_sha_dev *sha_dd;
++ struct device *dev = &pdev->dev;
++ struct resource *sha_res;
++ unsigned long sha_phys_size;
++ int err;
++
++ sha_dd = kzalloc(sizeof(struct atmel_sha_dev), GFP_KERNEL);
++ if (sha_dd == NULL) {
++ dev_err(dev, "unable to alloc data struct.\n");
++ err = -ENOMEM;
++ goto sha_dd_err;
++ }
++
++ sha_dd->dev = dev;
++
++ platform_set_drvdata(pdev, sha_dd);
++
++ INIT_LIST_HEAD(&sha_dd->list);
++
++ tasklet_init(&sha_dd->done_task, atmel_sha_done_task,
++ (unsigned long)sha_dd);
++
++ crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH);
++
++ sha_dd->irq = -1;
++
++ /* Get the base address */
++ sha_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!sha_res) {
++ dev_err(dev, "no MEM resource info\n");
++ err = -ENODEV;
++ goto res_err;
++ }
++ sha_dd->phys_base = sha_res->start;
++ sha_phys_size = resource_size(sha_res);
++
++ /* Get the IRQ */
++ sha_dd->irq = platform_get_irq(pdev, 0);
++ if (sha_dd->irq < 0) {
++ dev_err(dev, "no IRQ resource info\n");
++ err = sha_dd->irq;
++ goto res_err;
++ }
++
++ err = request_irq(sha_dd->irq, atmel_sha_irq, IRQF_SHARED, "atmel-sha",
++ sha_dd);
++ if (err) {
++ dev_err(dev, "unable to request sha irq.\n");
++ goto res_err;
++ }
++
++ /* Initializing the clock */
++ sha_dd->iclk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(sha_dd->iclk)) {
++ dev_err(dev, "clock intialization failed.\n");
++ err = PTR_ERR(sha_dd->iclk);
++ goto clk_err;
++ }
++
++ sha_dd->io_base = ioremap(sha_dd->phys_base, sha_phys_size);
++ if (!sha_dd->io_base) {
++ dev_err(dev, "can't ioremap\n");
++ err = -ENOMEM;
++ goto sha_io_err;
++ }
++
++ spin_lock(&atmel_sha.lock);
++ list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
++ spin_unlock(&atmel_sha.lock);
++
++ err = atmel_sha_register_algs(sha_dd);
++ if (err)
++ goto err_algs;
++
++ dev_info(dev, "Atmel SHA1/SHA256\n");
++
++ return 0;
++
++err_algs:
++ spin_lock(&atmel_sha.lock);
++ list_del(&sha_dd->list);
++ spin_unlock(&atmel_sha.lock);
++ iounmap(sha_dd->io_base);
++sha_io_err:
++ clk_put(sha_dd->iclk);
++clk_err:
++ free_irq(sha_dd->irq, sha_dd);
++res_err:
++ tasklet_kill(&sha_dd->done_task);
++ kfree(sha_dd);
++ sha_dd = NULL;
++sha_dd_err:
++ dev_err(dev, "initialization failed.\n");
++
++ return err;
++}
++
++static int __devexit atmel_sha_remove(struct platform_device *pdev)
++{
++ static struct atmel_sha_dev *sha_dd;
++
++ sha_dd = platform_get_drvdata(pdev);
++ if (!sha_dd)
++ return -ENODEV;
++ spin_lock(&atmel_sha.lock);
++ list_del(&sha_dd->list);
++ spin_unlock(&atmel_sha.lock);
++
++ atmel_sha_unregister_algs(sha_dd);
++
++ tasklet_kill(&sha_dd->done_task);
++
++ iounmap(sha_dd->io_base);
++
++ clk_put(sha_dd->iclk);
++
++ if (sha_dd->irq >= 0)
++ free_irq(sha_dd->irq, sha_dd);
++
++ kfree(sha_dd);
++ sha_dd = NULL;
++
++ return 0;
++}
++
++static struct platform_driver atmel_sha_driver = {
++ .probe = atmel_sha_probe,
++ .remove = __devexit_p(atmel_sha_remove),
++ .driver = {
++ .name = "atmel_sha",
++ .owner = THIS_MODULE,
++ },
++};
++
++module_platform_driver(atmel_sha_driver);
++
++MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 1332062fec70ff4fc2f3dd9360911a59ba78bcaf Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Wed, 23 May 2012 21:22:40 +0800
-Subject: pinctrl: remove pinctrl_remove_gpio_range
-
-The gpio ranges will be automatically removed when the pinctrl
-driver is unregistered.
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 19 +++++--------------
- drivers/pinctrl/pinctrl-tegra.c | 1 -
- drivers/pinctrl/pinctrl-u300.c | 2 --
- include/linux/pinctrl/pinctrl.h | 2 --
- 4 files changed, 5 insertions(+), 19 deletions(-)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index 2b6363c5..7b3fc93 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -313,20 +313,6 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
- EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
-
- /**
-- * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
-- * @pctldev: pin controller device to remove the range from
-- * @range: the GPIO range to remove
-- */
--void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
-- struct pinctrl_gpio_range *range)
--{
-- mutex_lock(&pinctrl_mutex);
-- list_del(&range->node);
-- mutex_unlock(&pinctrl_mutex);
--}
--EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
--
--/**
- * pinctrl_get_group_selector() - returns the group selector for a group
- * @pctldev: the pin controller handling the group
- * @pin_group: the pin group to look up
-@@ -1456,6 +1442,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
- */
- void pinctrl_unregister(struct pinctrl_dev *pctldev)
- {
-+ struct pinctrl_gpio_range *range, *n;
- if (pctldev == NULL)
- return;
-
-@@ -1471,6 +1458,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
- /* Destroy descriptor tree */
- pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
- pctldev->desc->npins);
-+ /* remove gpio ranges map */
-+ list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
-+ list_del(&range->node);
-+
- kfree(pctldev);
-
- mutex_unlock(&pinctrl_mutex);
-diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
-index 9b32968..0b3c02f 100644
---- a/drivers/pinctrl/pinctrl-tegra.c
-+++ b/drivers/pinctrl/pinctrl-tegra.c
-@@ -525,7 +525,6 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
- {
- struct tegra_pmx *pmx = platform_get_drvdata(pdev);
-
-- pinctrl_remove_gpio_range(pmx->pctl, &tegra_pinctrl_gpio_range);
- pinctrl_unregister(pmx->pctl);
-
- return 0;
-diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
-index 26eb8cc..9ff6207 100644
---- a/drivers/pinctrl/pinctrl-u300.c
-+++ b/drivers/pinctrl/pinctrl-u300.c
-@@ -1185,8 +1185,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
- struct u300_pmx *upmx = platform_get_drvdata(pdev);
- int i;
-
-- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
-- pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
- pinctrl_unregister(upmx->pctl);
- iounmap(upmx->virtbase);
- release_mem_region(upmx->phybase, upmx->physize);
-diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
-index aa92cde..6e30132 100644
---- a/include/linux/pinctrl/pinctrl.h
-+++ b/include/linux/pinctrl/pinctrl.h
-@@ -124,8 +124,6 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
- extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
- extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range);
--extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
-- struct pinctrl_gpio_range *range);
- extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
- extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
- #else
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6cfecc127971e728597592ccfaafc2527cdf2d1a Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:07 +0200
+Subject: crypto: add atmel-test driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/Kconfig | 12 ++
+ drivers/crypto/Makefile | 1 +
+ drivers/crypto/atmel-test.c | 444 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 457 insertions(+)
+ create mode 100644 drivers/crypto/atmel-test.c
+
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 2339add..7a356fe 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -343,4 +343,16 @@ config CRYPTO_DEV_ATMEL_SHA
+ To compile this driver as a module, choose M here: the module
+ will be called atmel-sha.
+
++config CRYPTO_DEV_ATMEL_TEST
++ tristate "TEST MODULE"
++ depends on ARCH_AT91
++ select CRYPTO_SHA1
++ select CRYPTO_SHA256
++ help
++ Some Atmel processors have SHA1/SHA256/TDES/AES hw accelerator.
++ Select this if you want to test SHA1/SHA256/TDES/AES drivers.
++
++ To compile this driver as a module, choose M here: the module
++ will be called atmel-test.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index d355c25..bbe005b 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -17,3 +17,4 @@ obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o
+ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o
++obj-$(CONFIG_CRYPTO_DEV_ATMEL_TEST) += atmel-test.o
+diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
+new file mode 100644
+index 0000000..4a23db5
+--- /dev/null
++++ b/drivers/crypto/atmel-test.c
+@@ -0,0 +1,444 @@
++/*
++ * Cryptographic API.
++ *
++ * ATMEL SHA1/SHA256/TDES/AES HW acceleration test.
++ *
++ * Author: Nicolas Royer - Eukréa Electromatique
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/crypto.h>
++#include <linux/err.h>
++#include <linux/scatterlist.h>
++#include <linux/gfp.h>
++#include <crypto/hash.h>
++
++static char *pattern64 =
++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
++ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
++ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
++ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
++
++static char *key32 =
++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe"
++ "\x2b\x73\xae\xf0\x85\x7d\x77\x81"
++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7"
++ "\x2d\x98\x10\xa3\x09\x14\xdf\xf4";
++
++static char *iv16 =
++ "\x56\x2e\x17\x99\x6d\x09\x3d\x28"
++ "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58";
++
++#define SHA1_MSG_LEN 20
++#define SHA256_MSG_LEN 32
++static char sha_out_buf[SHA256_MSG_LEN];
++
++#define TVMEMSIZE 4
++static char *tvmem[TVMEMSIZE];
++
++
++static void hexdump(unsigned char *buf, unsigned int len)
++{
++ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
++ 16, 1,
++ buf, len, false);
++}
++
++struct hmac_sha_result {
++ struct completion completion;
++ int err;
++};
++
++static void hmac_sha_complete(struct crypto_async_request *req, int err)
++{
++ struct hmac_sha_result *r = req->data;
++ if (err == -EINPROGRESS)
++ return;
++ r->err = err;
++ complete(&r->completion);
++}
++
++static inline int do_one_ahash_op(struct ahash_request *req, int ret)
++{
++ if (ret == -EINPROGRESS || ret == -EBUSY) {
++ struct hmac_sha_result *tr = req->base.data;
++
++ ret = wait_for_completion_interruptible(&tr->completion);
++ if (!ret)
++ ret = tr->err;
++ INIT_COMPLETION(tr->completion);
++ }
++ return ret;
++}
++
++static int hmac_sha_update(const char *algo, char *data_in, size_t dlen,
++ char *hash_out, size_t outlen)
++{
++ int rc = 0;
++ struct crypto_ahash *tfm;
++ struct scatterlist sg[TVMEMSIZE];
++ struct ahash_request *req;
++ struct hmac_sha_result tresult;
++ int i, j;
++
++ /* Set hash output to 0 initially */
++ memset(hash_out, 0, outlen);
++
++ init_completion(&tresult.completion);
++ tfm = crypto_alloc_ahash(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "crypto_alloc_ahash failed\n");
++ rc = PTR_ERR(tfm);
++ goto err_tfm;
++ }
++ req = ahash_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "failed to allocate request\n");
++ rc = -ENOMEM;
++ goto err_req;
++ }
++ if (crypto_ahash_digestsize(tfm) > outlen) {
++ printk(KERN_ERR "tfm size > result buffer\n");
++ rc = -EINVAL;
++ goto err_req;
++ }
++ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ hmac_sha_complete, &tresult);
++
++ sg_init_table(sg, TVMEMSIZE);
++
++ i = 0;
++ j = dlen;
++
++ while (j > PAGE_SIZE) {
++ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + i, tvmem[i], j);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
++
++ crypto_ahash_clear_flags(tfm, -0);
++ ahash_request_set_crypt(req, sg, hash_out, dlen);
++ rc = crypto_ahash_init(req);
++ rc = do_one_ahash_op(req, crypto_ahash_update(req));
++ if (rc)
++ goto out;
++
++ rc = do_one_ahash_op(req, crypto_ahash_final(req));
++
++out:
++ ahash_request_free(req);
++err_req:
++ crypto_free_ahash(tfm);
++err_tfm:
++ return rc;
++}
++
++static int hmac_sha_digest(const char *algo, char *data_in, size_t dlen,
++ char *hash_out, size_t outlen)
++{
++ int rc = 0;
++ struct crypto_ahash *tfm;
++ struct scatterlist sg;
++ struct ahash_request *req;
++ struct hmac_sha_result tresult;
++
++ /* Set hash output to 0 initially */
++ memset(hash_out, 0, outlen);
++
++ init_completion(&tresult.completion);
++ tfm = crypto_alloc_ahash(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "crypto_alloc_ahash failed\n");
++ rc = PTR_ERR(tfm);
++ goto err_tfm;
++ }
++ req = ahash_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "failed to allocate request\n");
++ rc = -ENOMEM;
++ goto err_req;
++ }
++ if (crypto_ahash_digestsize(tfm) > outlen) {
++ printk(KERN_ERR "tfm size > result buffer\n");
++ rc = -EINVAL;
++ goto err_req;
++ }
++ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ hmac_sha_complete, &tresult);
++
++ sg_init_one(&sg, data_in, dlen);
++
++ crypto_ahash_clear_flags(tfm, -0);
++ ahash_request_set_crypt(req, &sg, hash_out, dlen);
++ rc = do_one_ahash_op(req, crypto_ahash_digest(req));
++
++ ahash_request_free(req);
++err_req:
++ crypto_free_ahash(tfm);
++err_tfm:
++ return rc;
++}
++
++struct tcrypt_result {
++ struct completion completion;
++ int err;
++};
++
++static void tcrypt_complete(struct crypto_async_request *req, int err)
++{
++ struct tcrypt_result *res = req->data;
++
++ if (err == -EINPROGRESS)
++ return;
++
++ res->err = err;
++ complete(&res->completion);
++}
++
++static inline int do_one_acipher_op(struct ablkcipher_request *req, int ret)
++{
++ if (ret == -EINPROGRESS || ret == -EBUSY) {
++ struct tcrypt_result *tr = req->base.data;
++
++ ret = wait_for_completion_interruptible(&tr->completion);
++ if (!ret)
++ ret = tr->err;
++ INIT_COMPLETION(tr->completion);
++ }
++ return ret;
++}
++
++static int test_acipher(const char *algo, int enc, char *data_in,
++ char *data_out, size_t data_len, char *key, int keysize)
++ {
++ struct crypto_ablkcipher *tfm;
++ struct tcrypt_result tresult;
++ struct ablkcipher_request *req;
++ struct scatterlist sg[TVMEMSIZE];
++ unsigned int ret, i, j, iv_len;
++ char iv[128];
++
++ ret = -EAGAIN;
++
++ init_completion(&tresult.completion);
++
++ tfm = crypto_alloc_ablkcipher(algo, 0, 0);
++ if (IS_ERR(tfm)) {
++ printk(KERN_ERR "failed to load transform for %s: %ld\n",
++ algo, PTR_ERR(tfm));
++ return ret;
++ }
++
++ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
++ if (!req) {
++ printk(KERN_ERR "tcrypt: skcipher: Failed to allocate request for %s\n",
++ algo);
++ goto out;
++ }
++
++ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
++ tcrypt_complete, &tresult);
++
++ crypto_ablkcipher_clear_flags(tfm, ~0);
++
++ ret = crypto_ablkcipher_setkey(tfm, key, keysize);
++ if (ret) {
++ printk(KERN_ERR "setkey() failed flags=%x\n",
++ crypto_ablkcipher_get_flags(tfm));
++ goto out_free_req;
++ }
++
++ printk(KERN_INFO "KEY:\n");
++ hexdump(key, keysize);
++
++ sg_init_table(sg, TVMEMSIZE);
++
++ i = 0;
++ j = data_len;
++
++ while (j > PAGE_SIZE) {
++ sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + i, tvmem[i], j);
++ memcpy(tvmem[i], data_in + i * PAGE_SIZE, j);
++
++ iv_len = crypto_ablkcipher_ivsize(tfm);
++ memcpy(iv, iv16, iv_len);
++
++ printk(KERN_INFO "IV:\n");
++ hexdump(iv, iv_len);
++
++ ablkcipher_request_set_crypt(req, sg, sg, data_len, iv);
++
++ printk(KERN_INFO "IN:\n");
++ hexdump(data_in, data_len);
++
++ if (enc)
++ ret = do_one_acipher_op(req, crypto_ablkcipher_encrypt(req));
++ else
++ ret = do_one_acipher_op(req, crypto_ablkcipher_decrypt(req));
++
++ if (ret)
++ printk(KERN_ERR "failed flags=%x\n",
++ crypto_ablkcipher_get_flags(tfm));
++ else {
++ i = 0;
++ j = data_len;
++ while (j > PAGE_SIZE) {
++ memcpy(data_out + i * PAGE_SIZE, tvmem[i], PAGE_SIZE);
++ i++;
++ j -= PAGE_SIZE;
++ }
++ memcpy(data_out + i * PAGE_SIZE, tvmem[i], j);
++
++ printk(KERN_INFO "OUT:\n");
++ hexdump(data_out, data_len);
++ }
++
++out_free_req:
++ ablkcipher_request_free(req);
++out:
++ crypto_free_ablkcipher(tfm);
++
++ return ret;
++}
++
++static int mode = 10;
++module_param_named(mode, mode, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++static int keylen = 8;
++module_param_named(keylen, keylen, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++static int dlen = 64;
++module_param_named(dlen, dlen, int,
++ S_IRUGO | S_IWUSR | S_IWGRP);
++
++char *ahash_algs[] = {"sha1", "sha256"};
++
++char *acipher_algs[] = {
++ "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
++ "cfb16(des)", "cfb8(des)", "ofb(des)", "ecb(des3_ede)",
++ "cbc(des3_ede)", "cfb(des3_ede)", "cfb32(des3_ede)", "cfb16(des3_ede)",
++ "cfb8(des3_ede)", "ofb(des3_ede)", "ecb(aes)", "cbc(aes)",
++ "ofb(aes)", "cfb(aes)", "cfb64(aes)", "cfb32(aes)",
++ "cfb16(aes)", "cfb8(aes)", "ctr(aes)"};
++
++static int __init init_main(void)
++{
++ unsigned int i;
++ char *buf_in;
++ char *buf_out;
++ char *buf_res;
++
++ if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
++ printk(KERN_ERR " 0 < dlen <= %i\n",
++ (int) (TVMEMSIZE*PAGE_SIZE));
++ return -EAGAIN;
++ }
++
++ for (i = 0; i < TVMEMSIZE; i++) {
++ tvmem[i] = (void *)__get_free_page(GFP_KERNEL);
++ if (!tvmem[i])
++ goto err_free_tv;
++ }
++
++ buf_in = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_in)
++ goto err_buf_in_alloc;
++ buf_out = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_out)
++ goto err_buf_out_alloc;
++ buf_res = kzalloc(dlen, GFP_KERNEL);
++ if (!buf_res)
++ goto err_buf_res_alloc;
++
++ if (dlen > 64) {
++ memcpy(buf_in, pattern64, 64);
++ memset(buf_in+64, 0xFF, dlen-64);
++ } else
++ memcpy(buf_in, pattern64, dlen);
++
++ if (mode < 10) {
++ if (mode >= ARRAY_SIZE(ahash_algs)) {
++ printk(KERN_ERR "mode must be < %d or > 10\n",
++ ARRAY_SIZE(ahash_algs));
++ goto exit;
++ }
++ printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
++ hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
++ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++
++ printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
++ hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
++ mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ } else {
++ mode -= 10;
++
++ if (mode >= ARRAY_SIZE(acipher_algs)) {
++ printk(KERN_ERR "mode must be < %d\n",
++ ARRAY_SIZE(acipher_algs) + 10);
++ goto exit;
++ }
++
++ printk(KERN_INFO "\n%s encrypt\n", acipher_algs[mode]);
++ if (test_acipher(acipher_algs[mode], 1, buf_in, buf_out,
++ dlen, key32, keylen))
++ goto exit;
++
++ printk(KERN_INFO "\n%s decrypt\n", acipher_algs[mode]);
++ if (test_acipher(acipher_algs[mode], 0, buf_out, buf_res,
++ dlen, key32, keylen))
++ goto exit;
++
++ if (memcmp(buf_in, buf_res, dlen))
++ printk(KERN_INFO "\n%s test failed\n\n",
++ acipher_algs[mode]);
++ else
++ printk(KERN_INFO "\n%s test OK\n\n",
++ acipher_algs[mode]);
++ }
++
++exit:
++ kfree(buf_res);
++err_buf_res_alloc:
++ kfree(buf_out);
++err_buf_out_alloc:
++ kfree(buf_in);
++err_buf_in_alloc:
++err_free_tv:
++ for (i = 0; i < TVMEMSIZE && tvmem[i]; i++)
++ free_page((unsigned long)tvmem[i]);
++
++ return -EAGAIN;
++}
++
++static void __exit cleanup_main(void)
++{
++}
++
++module_init(init_main);
++module_exit(cleanup_main);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Nicolas Royer - Eukréa Electromatique");
++MODULE_DESCRIPTION("Atmel HW crypto test");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From d52a7f1a57f4ffda01f648c2ae986ab52edaa517 Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Wed, 23 May 2012 21:22:41 +0800
-Subject: pinctrl: add pinctrl_add_gpio_ranges function
-
-Often GPIO ranges are added in batch, so create a special
-function for that.
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 11 +++++++++++
- include/linux/pinctrl/pinctrl.h | 3 +++
- 2 files changed, 14 insertions(+)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index 7b3fc93..fa8a440 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -312,6 +312,17 @@ void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
- }
- EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
-
-+void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
-+ struct pinctrl_gpio_range *ranges,
-+ unsigned nranges)
-+{
-+ int i;
-+
-+ for (i = 0; i < nranges; i++)
-+ pinctrl_add_gpio_range(pctldev, &ranges[i]);
-+}
-+EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
-+
- /**
- * pinctrl_get_group_selector() - returns the group selector for a group
- * @pctldev: the pin controller handling the group
-diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
-index 6e30132..e162710 100644
---- a/include/linux/pinctrl/pinctrl.h
-+++ b/include/linux/pinctrl/pinctrl.h
-@@ -124,6 +124,9 @@ extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
- extern bool pin_is_valid(struct pinctrl_dev *pctldev, int pin);
- extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range);
-+extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
-+ struct pinctrl_gpio_range *ranges,
-+ unsigned nranges);
- extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
- extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
- #else
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 6f6e5ce06de79a8b3bf26062a01bece308994236 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:08 +0200
+Subject: crypto: add new tests to tcrypt
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+commit de197533485c09598215802b0e401a688e172573 upstream.
+
+- set sg buffers size equals to message size
+- add cfb & ofb tests for AES, DES & TDES
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ crypto/tcrypt.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 45 insertions(+), 5 deletions(-)
+
+diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
+index 8f147bf..a9296bd 100644
+--- a/crypto/tcrypt.c
++++ b/crypto/tcrypt.c
+@@ -809,7 +809,7 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
+ struct cipher_speed_template *template,
+ unsigned int tcount, u8 *keysize)
+ {
+- unsigned int ret, i, j, iv_len;
++ unsigned int ret, i, j, k, iv_len;
+ struct tcrypt_result tresult;
+ const char *key;
+ char iv[128];
+@@ -883,11 +883,23 @@ static void test_acipher_speed(const char *algo, int enc, unsigned int sec,
+ }
+
+ sg_init_table(sg, TVMEMSIZE);
+- sg_set_buf(sg, tvmem[0] + *keysize,
++
++ k = *keysize + *b_size;
++ if (k > PAGE_SIZE) {
++ sg_set_buf(sg, tvmem[0] + *keysize,
+ PAGE_SIZE - *keysize);
+- for (j = 1; j < TVMEMSIZE; j++) {
+- sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
+- memset(tvmem[j], 0xff, PAGE_SIZE);
++ k -= PAGE_SIZE;
++ j = 1;
++ while (k > PAGE_SIZE) {
++ sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);
++ memset(tvmem[j], 0xff, PAGE_SIZE);
++ j++;
++ k -= PAGE_SIZE;
++ }
++ sg_set_buf(sg + j, tvmem[j], k);
++ memset(tvmem[j], 0xff, k);
++ } else {
++ sg_set_buf(sg, tvmem[0] + *keysize, *b_size);
+ }
+
+ iv_len = crypto_ablkcipher_ivsize(tfm);
+@@ -1512,6 +1524,14 @@ static int do_test(int m)
+ speed_template_16_24_32);
+ test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
+ speed_template_16_24_32);
++ test_acipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
++ test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0,
++ speed_template_16_24_32);
+ break;
+
+ case 501:
+@@ -1527,6 +1547,18 @@ static int do_test(int m)
+ test_acipher_speed("cbc(des3_ede)", DECRYPT, sec,
+ des3_speed_template, DES3_SPEED_VECTORS,
+ speed_template_24);
++ test_acipher_speed("cfb(des3_ede)", ENCRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("cfb(des3_ede)", DECRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("ofb(des3_ede)", ENCRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
++ test_acipher_speed("ofb(des3_ede)", DECRYPT, sec,
++ des3_speed_template, DES3_SPEED_VECTORS,
++ speed_template_24);
+ break;
+
+ case 502:
+@@ -1538,6 +1570,14 @@ static int do_test(int m)
+ speed_template_8);
+ test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0,
+ speed_template_8);
++ test_acipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("cfb(des)", DECRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0,
++ speed_template_8);
++ test_acipher_speed("ofb(des)", DECRYPT, sec, NULL, 0,
++ speed_template_8);
+ break;
+
+ case 503:
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From d834e7a76cf4e427904024a9b5b32f80a8f085a6 Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Wed, 25 Apr 2012 19:38:13 +0800
-Subject: pinctrl: support gpio request deferred probing
-
-As pinctrl handles, it may be possible the pinctrl gpio ranges
-are still not got registered when user call pinctrl_gpio_request.
-Thus, add defer support for it too.
-
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index fa8a440..c9c74dc 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -272,7 +272,8 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
- *
- * Find the pin controller handling a certain GPIO pin from the pinspace of
- * the GPIO subsystem, return the device and the matching GPIO range. Returns
-- * negative if the GPIO range could not be found in any device.
-+ * -EPROBE_DEFER if the GPIO range could not be found in any device since it
-+ * may still have not been registered.
- */
- static int pinctrl_get_device_gpio_range(unsigned gpio,
- struct pinctrl_dev **outdev,
-@@ -292,7 +293,7 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
- }
- }
-
-- return -EINVAL;
-+ return -EPROBE_DEFER;
- }
-
- /**
-@@ -374,7 +375,7 @@ int pinctrl_request_gpio(unsigned gpio)
- ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
- if (ret) {
- mutex_unlock(&pinctrl_mutex);
-- return -EINVAL;
-+ return ret;
- }
-
- /* Convert to the pin controllers number space */
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 499af8e10dac88ff1e4586930d7a157b2e38a893 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:09 +0200
+Subject: AT91SAM9G45: crypto: same platform data header for all crypto
+ peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ arch/arm/mach-at91/at91sam9g45_devices.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
+index 3d523f0..896088d 100644
+--- a/arch/arm/mach-at91/at91sam9g45_devices.c
++++ b/arch/arm/mach-at91/at91sam9g45_devices.c
+@@ -31,7 +31,7 @@
+ #include <mach/at91sam9_smc.h>
+ #include <mach/at_hdmac.h>
+ #include <mach/atmel-mci.h>
+-#include <linux/platform_data/atmel-aes.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include <media/atmel-isi.h>
+
+ #include "generic.h"
+@@ -584,7 +584,7 @@ static void __init at91_add_device_tdes(void) {}
+ * -------------------------------------------------------------------- */
+
+ #if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
+-static struct aes_platform_data aes_data;
++static struct crypto_platform_data aes_data;
+ static u64 aes_dmamask = DMA_BIT_MASK(32);
+
+ static struct resource aes_resources[] = {
+@@ -615,9 +615,9 @@ static struct platform_device at91sam9g45_aes_device = {
+ static void __init at91_add_device_aes(void)
+ {
+ struct at_dma_slave *atslave;
+- struct aes_dma_data *alt_atslave;
++ struct crypto_dma_data *alt_atslave;
+
+- alt_atslave = kzalloc(sizeof(struct aes_dma_data), GFP_KERNEL);
++ alt_atslave = kzalloc(sizeof(struct crypto_dma_data), GFP_KERNEL);
+
+ /* DMA TX slave channel configuration */
+ atslave = &alt_atslave->txdata;
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 1f8eba396ef610c82faaf227a8b76e98cdf90afd Mon Sep 17 00:00:00 2001
-From: Stephen Warren <swarren@nvidia.com>
-Date: Wed, 25 Apr 2012 10:32:16 -0600
-Subject: pinctrl: propagate map validation errors
-
-pinctrl_register_map() was returning early if pinmux_validate_map() or
-pinconf_validate_map() failed, but was not actually returning the error
-code.
-
-Signed-off-by: Stephen Warren <swarren@nvidia.com>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index c9c74dc..6ae3a33 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -911,13 +911,13 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
- case PIN_MAP_TYPE_MUX_GROUP:
- ret = pinmux_validate_map(&maps[i], i);
- if (ret < 0)
-- return 0;
-+ return ret;
- break;
- case PIN_MAP_TYPE_CONFIGS_PIN:
- case PIN_MAP_TYPE_CONFIGS_GROUP:
- ret = pinconf_validate_map(&maps[i], i);
- if (ret < 0)
-- return 0;
-+ return ret;
- break;
- default:
- pr_err("failed to register map %s (%d): invalid type given\n",
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 29e5c6be830144305786ffb9143c06a9e96846ce Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:05:01 +0200
+Subject: AT91SAM9G45: dts: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9g45.dtsi
+---
+ arch/arm/boot/dts/at91sam9g45.dtsi | 25 +++++++++++++++++++++++++
+ 1 file changed, 25 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index b032a8c..948dc96 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -106,6 +106,7 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <21 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff200 {
+@@ -243,6 +244,30 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ aes@fffc0000 {
++ compatible = "atmel,sam9g46-aes";
++ reg = <0xfffc0000 0x100>;
++ interrupts = <28 4 0>;
++ dma = <&dma 0x2000020c /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20006020
++ | ATC_DST_H2SEL_HW
++ | ATC_DST_PER(AT_DMA_ID_AES_TX); */
++ &dma 0x200020b0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE 0x20000603
++ | ATC_SRC_H2SEL_HW
++ | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
++ >;
++ dma-name = "tx", "rx";
++ };
++ tdes@0xfffc4000 {
++ compatible = "atmel,sam9g46-tdes";
++ reg = <0xfffc4000 0x130>;
++ interrupts = <28 4 0>;
++ };
++ sha@0xfffc8000 {
++ compatible = "atmel,sam9g46-sha";
++ reg = <0xfffc8000 0x130>;
++ interrupts = <28 4 0>;
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From ac7194c8e5bc5956a26b7460b7e58b22504a375d Mon Sep 17 00:00:00 2001
-From: Linus Walleij <linus.walleij@linaro.org>
-Date: Thu, 12 Apr 2012 19:48:42 +0200
-Subject: pinctrl: mark non-EXPERIMENTAL
-
-With the finalization of the external driver API and the device
-tree support, this subsystem is now mature and can be promoted to
-non-experimental status.
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/Kconfig | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
-index abfb964..f73a5ea 100644
---- a/drivers/pinctrl/Kconfig
-+++ b/drivers/pinctrl/Kconfig
-@@ -4,7 +4,6 @@
-
- config PINCTRL
- bool
-- depends on EXPERIMENTAL
-
- if PINCTRL
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 4d751232a49a7f677bd665ca70c2887e6d2537d5 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:13 +0200
+Subject: AT91SAM9N12: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ arch/arm/mach-at91/at91sam9n12.c | 17 +++++++++++++++++
+ arch/arm/mach-at91/include/mach/at91sam9n12.h | 2 ++
+ 2 files changed, 19 insertions(+)
+
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index ebe94bb..d09baf1 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -17,6 +17,7 @@
+ #include <mach/cpu.h>
+ #include <mach/board.h>
+
++
+ #include "soc.h"
+ #include "generic.h"
+ #include "clock.h"
+@@ -134,6 +135,17 @@ static struct clk ssc_clk = {
+ .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
+ .type = CLK_TYPE_PERIPHERAL,
+ };
++static struct clk aes_clk = {
++ .name = "aes_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_AES,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++static struct clk sha_clk = {
++ .name = "sha_clk",
++ .pmc_mask = 1 << AT91SAM9N12_ID_SHA,
++ .type = CLK_TYPE_PERIPHERAL,
++};
++
+
+ static struct clk *periph_clocks[] __initdata = {
+ &pioAB_clk,
+@@ -157,6 +169,8 @@ static struct clk *periph_clocks[] __initdata = {
+ &uhp_clk,
+ &udp_clk,
+ &ssc_clk,
++ &aes_clk,
++ &sha_clk,
+ };
+
+ static struct clk_lookup periph_clocks_lookups[] = {
+@@ -176,6 +190,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+ CLKDEV_CON_ID("pioD", &pioCD_clk),
++ CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
++ CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+@@ -219,6 +235,7 @@ static void __init at91sam9n12_register_clocks(void)
+ static void __init at91sam9n12_map_io(void)
+ {
+ at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
++ init_consistent_dma_size(SZ_4M);
+ }
+
+ void __init at91sam9n12_initialize(void)
+diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+index d374b87..e07b0de 100644
+--- a/arch/arm/mach-at91/include/mach/at91sam9n12.h
++++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
+@@ -36,7 +36,9 @@
+ #define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
+ #define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
+ #define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
++#define AT91SAM9N12_ID_SHA 27 /* SHA */
+ #define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
++#define AT91SAM9N12_ID_AES 29 /* AES */
+ #define AT91SAM9N12_ID_TRNG 30 /* TRNG */
+ #define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From c74f8821901c3338e120844cbff9bf0676243451 Mon Sep 17 00:00:00 2001
-From: Linus Walleij <linus.walleij@linaro.org>
-Date: Tue, 10 Apr 2012 10:00:38 +0200
-Subject: pinctrl: implement pinctrl deferred probing
-
-If drivers try to obtain pinctrl handles for a pin controller that
-has not yet registered to the subsystem, we need to be able to
-back out and retry with deferred probing. So let's return
--EPROBE_DEFER whenever this location fails. Also downgrade the
-errors to info, maybe we will even set them to debug once the
-deferred probing is commonplace.
-
-Cc: Arnd Bergmann <arnd@arndb.de>
-Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- Documentation/pinctrl.txt | 5 +++++
- drivers/pinctrl/core.c | 9 ++++++---
- drivers/pinctrl/devicetree.c | 6 +++---
- 3 files changed, 14 insertions(+), 6 deletions(-)
-
-diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
-index fa829f1..b85f0bd 100644
---- a/Documentation/pinctrl.txt
-+++ b/Documentation/pinctrl.txt
-@@ -1059,6 +1059,11 @@ The pins are allocated for your device when you issue the devm_pinctrl_get()
- call, after this you should be able to see this in the debugfs listing of all
- pins.
-
-+NOTE: the pinctrl system will return -EPROBE_DEFER if it cannot find the
-+requested pinctrl handles, for example if the pinctrl driver has not yet
-+registered. Thus make sure that the error path in your driver gracefully
-+cleans up and is ready to retry the probing later in the startup process.
-+
-
- System pin control hogging
- ==========================
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index 6ae3a33..ff78028 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -531,11 +531,14 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
-
- setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
- if (setting->pctldev == NULL) {
-- dev_err(p->dev, "unknown pinctrl device %s in map entry",
-+ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe",
- map->ctrl_dev_name);
- kfree(setting);
-- /* Eventually, this should trigger deferred probe */
-- return -ENODEV;
-+ /*
-+ * OK let us guess that the driver is not there yet, and
-+ * let's defer obtaining this pinctrl handle to later...
-+ */
-+ return -EPROBE_DEFER;
- }
-
- switch (map->type) {
-diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
-index 5ef2feb..fcb1de4 100644
---- a/drivers/pinctrl/devicetree.c
-+++ b/drivers/pinctrl/devicetree.c
-@@ -121,11 +121,11 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
- for (;;) {
- np_pctldev = of_get_next_parent(np_pctldev);
- if (!np_pctldev || of_node_is_root(np_pctldev)) {
-- dev_err(p->dev, "could not find pctldev for node %s\n",
-+ dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
- np_config->full_name);
- of_node_put(np_pctldev);
-- /* FIXME: This should trigger deferrered probe */
-- return -ENODEV;
-+ /* OK let's just assume this will appear later then */
-+ return -EPROBE_DEFER;
- }
- pctldev = find_pinctrl_by_of_node(np_pctldev);
- if (pctldev)
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 13559e1bdab3b9d165dd3e4949b38f7102c48a1a Mon Sep 17 00:00:00 2001
+From: Nicolas Ferre <nicolas.ferre@atmel.com>
+Date: Mon, 22 Oct 2012 16:05:17 +0200
+Subject: AT91SAM9N12: dts: add crypto peripherals
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+
+Conflicts:
+ arch/arm/boot/dts/at91sam9n12.dtsi
+---
+ arch/arm/boot/dts/at91sam9n12.dtsi | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 0d08c4e..42b53bd 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -109,6 +109,7 @@
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4 0>;
++ #dma-cells = <1>;
+ };
+
+ pioA: gpio@fffff400 {
+@@ -211,6 +212,29 @@
+ #size-cells = <0>;
+ status = "disabled";
+ };
++
++ aes@f000c000 {
++ compatible = "atmel,sam9g46-aes";
++ reg = <0xf000c000 0x100>;
++ interrupts = <29 4 0>;
++ dma = <&dma 0x2000060B /* tx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_DST_H2SEL_HW */
++ /* | ATC_DST_PER(AT_DMA_ID_AES_TX); */
++ &dma 0x200060A0 /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_SRC_H2SEL_HW */
++ /* | ATC_SRC_PER(AT_DMA_ID_AES_RX); */
++ >;
++ dma-name = "tx", "rx";
++ };
++
++ sha@f0014000 {
++ compatible = "atmel,sam9g46-sha";
++ reg = <0xf0014000 0x100>;
++ interrupts = <27 4 0>;
++ dma = <&dma 0x200060C0>; /* rx cfg = ATC_FIFOCFG_ENOUGHSPACE */
++ /* | ATC_SRC_H2SEL_HW */
++ /* | ATC_SRC_PER(AT_DMA_ID_SHA_RX); */
++ };
+ };
+
+ nand0: nand@40000000 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 0fb545a399810ecbb6b81899a36c95671bc5dfc6 Mon Sep 17 00:00:00 2001
-From: Viresh Kumar <viresh.kumar@st.com>
-Date: Fri, 30 Mar 2012 11:25:40 +0530
-Subject: pinctrl: replace list_*() with get_*_count()
-
-Most of the SoC drivers implement list_groups() and list_functions()
-routines for pinctrl and pinmux. These routines continue returning
-zero until the selector argument is greater than total count of
-available groups or functions.
-
-This patch replaces these list_*() routines with get_*_count()
-routines, which returns the number of available selection for SoC
-driver. pinctrl layer will use this value to check the range it can
-choose.
-
-This patch fixes all user drivers for this change. There are other
-routines in user drivers, which have checks to check validity of
-selector passed to them. It is also no more required and hence
-removed.
-
-Documentation updated as well.
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Viresh Kumar <viresh.kumar@st.com>
-[Folded in fix and fixed a minor merge artifact manually]
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- Documentation/pinctrl.txt | 37 +++++++++++++++----------------------
- drivers/pinctrl/core.c | 10 ++++++----
- drivers/pinctrl/pinconf.c | 3 ++-
- drivers/pinctrl/pinctrl-pxa3xx.c | 24 ++++++++++--------------
- drivers/pinctrl/pinctrl-sirf.c | 20 ++++++--------------
- drivers/pinctrl/pinctrl-tegra.c | 40 ++++++----------------------------------
- drivers/pinctrl/pinctrl-u300.c | 20 ++++++--------------
- drivers/pinctrl/pinmux.c | 11 +++++++----
- include/linux/pinctrl/pinctrl.h | 6 ++----
- include/linux/pinctrl/pinmux.h | 7 +++----
- 10 files changed, 63 insertions(+), 115 deletions(-)
-
-diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
-index b85f0bd..f5add79 100644
---- a/Documentation/pinctrl.txt
-+++ b/Documentation/pinctrl.txt
-@@ -152,11 +152,9 @@ static const struct foo_group foo_groups[] = {
- };
-
-
--static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
-+static int foo_get_groups_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(foo_groups))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(foo_groups);
- }
-
- static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
-@@ -175,7 +173,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
- }
-
- static struct pinctrl_ops foo_pctrl_ops = {
-- .list_groups = foo_list_groups,
-+ .get_groups_count = foo_get_groups_count,
- .get_group_name = foo_get_group_name,
- .get_group_pins = foo_get_group_pins,
- };
-@@ -186,13 +184,12 @@ static struct pinctrl_desc foo_desc = {
- .pctlops = &foo_pctrl_ops,
- };
-
--The pin control subsystem will call the .list_groups() function repeatedly
--beginning on 0 until it returns non-zero to determine legal selectors, then
--it will call the other functions to retrieve the name and pins of the group.
--Maintaining the data structure of the groups is up to the driver, this is
--just a simple example - in practice you may need more entries in your group
--structure, for example specific register ranges associated with each group
--and so on.
-+The pin control subsystem will call the .get_groups_count() function to
-+determine total number of legal selectors, then it will call the other functions
-+to retrieve the name and pins of the group. Maintaining the data structure of
-+the groups is up to the driver, this is just a simple example - in practice you
-+may need more entries in your group structure, for example specific register
-+ranges associated with each group and so on.
-
-
- Pin configuration
-@@ -606,11 +603,9 @@ static const struct foo_group foo_groups[] = {
- };
-
-
--static int foo_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
-+static int foo_get_groups_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(foo_groups))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(foo_groups);
- }
-
- static const char *foo_get_group_name(struct pinctrl_dev *pctldev,
-@@ -629,7 +624,7 @@ static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
- }
-
- static struct pinctrl_ops foo_pctrl_ops = {
-- .list_groups = foo_list_groups,
-+ .get_groups_count = foo_get_groups_count,
- .get_group_name = foo_get_group_name,
- .get_group_pins = foo_get_group_pins,
- };
-@@ -663,11 +658,9 @@ static const struct foo_pmx_func foo_functions[] = {
- },
- };
-
--int foo_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
-+int foo_get_functions_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(foo_functions))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(foo_functions);
- }
-
- const char *foo_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
-@@ -703,7 +696,7 @@ void foo_disable(struct pinctrl_dev *pctldev, unsigned selector,
- }
-
- struct pinmux_ops foo_pmxops = {
-- .list_functions = foo_list_funcs,
-+ .get_functions_count = foo_get_functions_count,
- .get_function_name = foo_get_fname,
- .get_function_groups = foo_get_groups,
- .enable = foo_enable,
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index ff78028..c70ae2d 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -333,9 +333,10 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
- const char *pin_group)
- {
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
-+ unsigned ngroups = pctlops->get_groups_count(pctldev);
- unsigned group_selector = 0;
-
-- while (pctlops->list_groups(pctldev, group_selector) >= 0) {
-+ while (group_selector < ngroups) {
- const char *gname = pctlops->get_group_name(pctldev,
- group_selector);
- if (!strcmp(gname, pin_group)) {
-@@ -1023,12 +1024,13 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
- {
- struct pinctrl_dev *pctldev = s->private;
- const struct pinctrl_ops *ops = pctldev->desc->pctlops;
-- unsigned selector = 0;
-+ unsigned ngroups, selector = 0;
-
-+ ngroups = ops->get_groups_count(pctldev);
- mutex_lock(&pinctrl_mutex);
-
- seq_puts(s, "registered pin groups:\n");
-- while (ops->list_groups(pctldev, selector) >= 0) {
-+ while (selector < ngroups) {
- const unsigned *pins;
- unsigned num_pins;
- const char *gname = ops->get_group_name(pctldev, selector);
-@@ -1343,7 +1345,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
- const struct pinctrl_ops *ops = pctldev->desc->pctlops;
-
- if (!ops ||
-- !ops->list_groups ||
-+ !ops->get_groups_count ||
- !ops->get_group_name ||
- !ops->get_group_pins)
- return -EINVAL;
-diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
-index 7321e86..eb3a14f4 100644
---- a/drivers/pinctrl/pinconf.c
-+++ b/drivers/pinctrl/pinconf.c
-@@ -495,6 +495,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
- struct pinctrl_dev *pctldev = s->private;
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- const struct pinconf_ops *ops = pctldev->desc->confops;
-+ unsigned ngroups = pctlops->get_groups_count(pctldev);
- unsigned selector = 0;
-
- if (!ops || !ops->pin_config_group_get)
-@@ -505,7 +506,7 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
-
- mutex_lock(&pinctrl_mutex);
-
-- while (pctlops->list_groups(pctldev, selector) >= 0) {
-+ while (selector < ngroups) {
- const char *gname = pctlops->get_group_name(pctldev, selector);
-
- seq_printf(s, "%u (%s):", selector, gname);
-diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
-index 079dce0..7644e42 100644
---- a/drivers/pinctrl/pinctrl-pxa3xx.c
-+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
-@@ -25,20 +25,18 @@ static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
- .pin_base = 0,
- };
-
--static int pxa3xx_list_groups(struct pinctrl_dev *pctrldev, unsigned selector)
-+static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
- {
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-- if (selector >= info->num_grps)
-- return -EINVAL;
-- return 0;
-+
-+ return info->num_grps;
- }
-
- static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
- unsigned selector)
- {
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-- if (selector >= info->num_grps)
-- return NULL;
-+
- return info->grps[selector].name;
- }
-
-@@ -48,25 +46,23 @@ static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
- unsigned *num_pins)
- {
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-- if (selector >= info->num_grps)
-- return -EINVAL;
-+
- *pins = info->grps[selector].pins;
- *num_pins = info->grps[selector].npins;
- return 0;
- }
-
- static struct pinctrl_ops pxa3xx_pctrl_ops = {
-- .list_groups = pxa3xx_list_groups,
-+ .get_groups_count = pxa3xx_get_groups_count,
- .get_group_name = pxa3xx_get_group_name,
- .get_group_pins = pxa3xx_get_group_pins,
- };
-
--static int pxa3xx_pmx_list_func(struct pinctrl_dev *pctrldev, unsigned func)
-+static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
- {
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-- if (func >= info->num_funcs)
-- return -EINVAL;
-- return 0;
-+
-+ return info->num_funcs;
- }
-
- static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
-@@ -170,7 +166,7 @@ static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
- }
-
- static struct pinmux_ops pxa3xx_pmx_ops = {
-- .list_functions = pxa3xx_pmx_list_func,
-+ .get_functions_count = pxa3xx_pmx_get_funcs_count,
- .get_function_name = pxa3xx_pmx_get_func_name,
- .get_function_groups = pxa3xx_pmx_get_groups,
- .enable = pxa3xx_pmx_enable,
-diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
-index 6b3534c..ba15b1a 100644
---- a/drivers/pinctrl/pinctrl-sirf.c
-+++ b/drivers/pinctrl/pinctrl-sirf.c
-@@ -853,18 +853,14 @@ static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
- SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
- };
-
--static int sirfsoc_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
-+static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(sirfsoc_pin_groups);
- }
-
- static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
- unsigned selector)
- {
-- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
-- return NULL;
- return sirfsoc_pin_groups[selector].name;
- }
-
-@@ -872,8 +868,6 @@ static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector
- const unsigned **pins,
- unsigned *num_pins)
- {
-- if (selector >= ARRAY_SIZE(sirfsoc_pin_groups))
-- return -EINVAL;
- *pins = sirfsoc_pin_groups[selector].pins;
- *num_pins = sirfsoc_pin_groups[selector].num_pins;
- return 0;
-@@ -886,7 +880,7 @@ static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s
- }
-
- static struct pinctrl_ops sirfsoc_pctrl_ops = {
-- .list_groups = sirfsoc_list_groups,
-+ .get_groups_count = sirfsoc_get_groups_count,
- .get_group_name = sirfsoc_get_group_name,
- .get_group_pins = sirfsoc_get_group_pins,
- .pin_dbg_show = sirfsoc_pin_dbg_show,
-@@ -1033,11 +1027,9 @@ static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector
- sirfsoc_pinmux_endisable(spmx, selector, false);
- }
-
--static int sirfsoc_pinmux_list_funcs(struct pinctrl_dev *pmxdev, unsigned selector)
-+static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
- {
-- if (selector >= ARRAY_SIZE(sirfsoc_pmx_functions))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(sirfsoc_pmx_functions);
- }
-
- static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
-@@ -1074,9 +1066,9 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
- }
-
- static struct pinmux_ops sirfsoc_pinmux_ops = {
-- .list_functions = sirfsoc_pinmux_list_funcs,
- .enable = sirfsoc_pinmux_enable,
- .disable = sirfsoc_pinmux_disable,
-+ .get_functions_count = sirfsoc_pinmux_get_funcs_count,
- .get_function_name = sirfsoc_pinmux_get_func_name,
- .get_function_groups = sirfsoc_pinmux_get_groups,
- .gpio_request_enable = sirfsoc_pinmux_request_gpio,
-diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
-index 0b3c02f..c4c47c5 100644
---- a/drivers/pinctrl/pinctrl-tegra.c
-+++ b/drivers/pinctrl/pinctrl-tegra.c
-@@ -53,15 +53,11 @@ static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg)
- writel(val, pmx->regs[bank] + reg);
- }
-
--static int tegra_pinctrl_list_groups(struct pinctrl_dev *pctldev,
-- unsigned group)
-+static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (group >= pmx->soc->ngroups)
-- return -EINVAL;
--
-- return 0;
-+ return pmx->soc->ngroups;
- }
-
- static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
-@@ -69,9 +65,6 @@ static const char *tegra_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (group >= pmx->soc->ngroups)
-- return NULL;
--
- return pmx->soc->groups[group].name;
- }
-
-@@ -82,9 +75,6 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (group >= pmx->soc->ngroups)
-- return -EINVAL;
--
- *pins = pmx->soc->groups[group].pins;
- *num_pins = pmx->soc->groups[group].npins;
-
-@@ -99,21 +89,17 @@ static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
- }
-
- static struct pinctrl_ops tegra_pinctrl_ops = {
-- .list_groups = tegra_pinctrl_list_groups,
-+ .get_groups_count = tegra_pinctrl_get_groups_count,
- .get_group_name = tegra_pinctrl_get_group_name,
- .get_group_pins = tegra_pinctrl_get_group_pins,
- .pin_dbg_show = tegra_pinctrl_pin_dbg_show,
- };
-
--static int tegra_pinctrl_list_funcs(struct pinctrl_dev *pctldev,
-- unsigned function)
-+static int tegra_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (function >= pmx->soc->nfunctions)
-- return -EINVAL;
--
-- return 0;
-+ return pmx->soc->nfunctions;
- }
-
- static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
-@@ -121,9 +107,6 @@ static const char *tegra_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (function >= pmx->soc->nfunctions)
-- return NULL;
--
- return pmx->soc->functions[function].name;
- }
-
-@@ -134,9 +117,6 @@ static int tegra_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
- {
- struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
-
-- if (function >= pmx->soc->nfunctions)
-- return -EINVAL;
--
- *groups = pmx->soc->functions[function].groups;
- *num_groups = pmx->soc->functions[function].ngroups;
-
-@@ -151,8 +131,6 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
- int i;
- u32 val;
-
-- if (group >= pmx->soc->ngroups)
-- return -EINVAL;
- g = &pmx->soc->groups[group];
-
- if (g->mux_reg < 0)
-@@ -180,8 +158,6 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
- const struct tegra_pingroup *g;
- u32 val;
-
-- if (group >= pmx->soc->ngroups)
-- return;
- g = &pmx->soc->groups[group];
-
- if (g->mux_reg < 0)
-@@ -194,7 +170,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
- }
-
- static struct pinmux_ops tegra_pinmux_ops = {
-- .list_functions = tegra_pinctrl_list_funcs,
-+ .get_functions_count = tegra_pinctrl_get_funcs_count,
- .get_function_name = tegra_pinctrl_get_func_name,
- .get_function_groups = tegra_pinctrl_get_func_groups,
- .enable = tegra_pinctrl_enable,
-@@ -324,8 +300,6 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
- s16 reg;
- u32 val, mask;
-
-- if (group >= pmx->soc->ngroups)
-- return -EINVAL;
- g = &pmx->soc->groups[group];
-
- ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
-@@ -353,8 +327,6 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
- s16 reg;
- u32 val, mask;
-
-- if (group >= pmx->soc->ngroups)
-- return -EINVAL;
- g = &pmx->soc->groups[group];
-
- ret = tegra_pinconf_reg(pmx, g, param, &bank, ®, &bit, &width);
-diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
-index 9ff6207..10de43c 100644
---- a/drivers/pinctrl/pinctrl-u300.c
-+++ b/drivers/pinctrl/pinctrl-u300.c
-@@ -836,18 +836,14 @@ static const struct u300_pin_group u300_pin_groups[] = {
- },
- };
-
--static int u300_list_groups(struct pinctrl_dev *pctldev, unsigned selector)
-+static int u300_get_groups_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(u300_pin_groups))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(u300_pin_groups);
- }
-
- static const char *u300_get_group_name(struct pinctrl_dev *pctldev,
- unsigned selector)
- {
-- if (selector >= ARRAY_SIZE(u300_pin_groups))
-- return NULL;
- return u300_pin_groups[selector].name;
- }
-
-@@ -855,8 +851,6 @@ static int u300_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
- const unsigned **pins,
- unsigned *num_pins)
- {
-- if (selector >= ARRAY_SIZE(u300_pin_groups))
-- return -EINVAL;
- *pins = u300_pin_groups[selector].pins;
- *num_pins = u300_pin_groups[selector].num_pins;
- return 0;
-@@ -869,7 +863,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
- }
-
- static struct pinctrl_ops u300_pctrl_ops = {
-- .list_groups = u300_list_groups,
-+ .get_groups_count = u300_get_groups_count,
- .get_group_name = u300_get_group_name,
- .get_group_pins = u300_get_group_pins,
- .pin_dbg_show = u300_pin_dbg_show,
-@@ -991,11 +985,9 @@ static void u300_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
- u300_pmx_endisable(upmx, selector, false);
- }
-
--static int u300_pmx_list_funcs(struct pinctrl_dev *pctldev, unsigned selector)
-+static int u300_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
- {
-- if (selector >= ARRAY_SIZE(u300_pmx_functions))
-- return -EINVAL;
-- return 0;
-+ return ARRAY_SIZE(u300_pmx_functions);
- }
-
- static const char *u300_pmx_get_func_name(struct pinctrl_dev *pctldev,
-@@ -1014,7 +1006,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
- }
-
- static struct pinmux_ops u300_pmx_ops = {
-- .list_functions = u300_pmx_list_funcs,
-+ .get_functions_count = u300_pmx_get_funcs_count,
- .get_function_name = u300_pmx_get_func_name,
- .get_function_groups = u300_pmx_get_groups,
- .enable = u300_pmx_enable,
-diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
-index 4e62783..375b214 100644
---- a/drivers/pinctrl/pinmux.c
-+++ b/drivers/pinctrl/pinmux.c
-@@ -33,10 +33,11 @@
- int pinmux_check_ops(struct pinctrl_dev *pctldev)
- {
- const struct pinmux_ops *ops = pctldev->desc->pmxops;
-+ unsigned nfuncs = ops->get_functions_count(pctldev);
- unsigned selector = 0;
-
- /* Check that we implement required operations */
-- if (!ops->list_functions ||
-+ if (!ops->get_functions_count ||
- !ops->get_function_name ||
- !ops->get_function_groups ||
- !ops->enable ||
-@@ -44,7 +45,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev)
- return -EINVAL;
-
- /* Check that all functions registered have names */
-- while (ops->list_functions(pctldev, selector) >= 0) {
-+ while (selector < nfuncs) {
- const char *fname = ops->get_function_name(pctldev,
- selector);
- if (!fname) {
-@@ -287,10 +288,11 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
- const char *function)
- {
- const struct pinmux_ops *ops = pctldev->desc->pmxops;
-+ unsigned nfuncs = ops->get_functions_count(pctldev);
- unsigned selector = 0;
-
- /* See if this pctldev has this function */
-- while (ops->list_functions(pctldev, selector) >= 0) {
-+ while (selector < nfuncs) {
- const char *fname = ops->get_function_name(pctldev,
- selector);
-
-@@ -477,11 +479,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
- {
- struct pinctrl_dev *pctldev = s->private;
- const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
-+ unsigned nfuncs = pmxops->get_functions_count(pctldev);
- unsigned func_selector = 0;
-
- mutex_lock(&pinctrl_mutex);
-
-- while (pmxops->list_functions(pctldev, func_selector) >= 0) {
-+ while (func_selector < nfuncs) {
- const char *func = pmxops->get_function_name(pctldev,
- func_selector);
- const char * const *groups;
-diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
-index e162710..ba08516 100644
---- a/include/linux/pinctrl/pinctrl.h
-+++ b/include/linux/pinctrl/pinctrl.h
-@@ -66,9 +66,7 @@ struct pinctrl_gpio_range {
- /**
- * struct pinctrl_ops - global pin control operations, to be implemented by
- * pin controller drivers.
-- * @list_groups: list the number of selectable named groups available
-- * in this pinmux driver, the core will begin on 0 and call this
-- * repeatedly as long as it returns >= 0 to enumerate the groups
-+ * @get_groups_count: Returns the count of total number of groups registered.
- * @get_group_name: return the group name of the pin group
- * @get_group_pins: return an array of pins corresponding to a certain
- * group selector @pins, and the size of the array in @num_pins
-@@ -76,7 +74,7 @@ struct pinctrl_gpio_range {
- * info for a certain pin in debugfs
- */
- struct pinctrl_ops {
-- int (*list_groups) (struct pinctrl_dev *pctldev, unsigned selector);
-+ int (*get_groups_count) (struct pinctrl_dev *pctldev);
- const char *(*get_group_name) (struct pinctrl_dev *pctldev,
- unsigned selector);
- int (*get_group_pins) (struct pinctrl_dev *pctldev,
-diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
-index 47e9237..dd7bef6 100644
---- a/include/linux/pinctrl/pinmux.h
-+++ b/include/linux/pinctrl/pinmux.h
-@@ -29,9 +29,8 @@ struct pinctrl_dev;
- * is allowed to answer "no" by returning a negative error code
- * @free: the reverse function of the request() callback, frees a pin after
- * being requested
-- * @list_functions: list the number of selectable named functions available
-- * in this pinmux driver, the core will begin on 0 and call this
-- * repeatedly as long as it returns >= 0 to enumerate mux settings
-+ * @get_functions_count: returns number of selectable named functions available
-+ * in this pinmux driver
- * @get_function_name: return the function name of the muxing selector,
- * called by the core to figure out which mux setting it shall map a
- * certain device to
-@@ -62,7 +61,7 @@ struct pinctrl_dev;
- struct pinmux_ops {
- int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
- int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
-- int (*list_functions) (struct pinctrl_dev *pctldev, unsigned selector);
-+ int (*get_functions_count) (struct pinctrl_dev *pctldev);
- const char *(*get_function_name) (struct pinctrl_dev *pctldev,
- unsigned selector);
- int (*get_function_groups) (struct pinctrl_dev *pctldev,
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 79aedf981e952379dd4538f85b1c62467eaa84ab Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:15 +0200
+Subject: crypto: Atmel AES; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-aes.c | 626 +++++++++++++++++++++++------
+ include/linux/platform_data/atmel-aes.h | 22 -
+ include/linux/platform_data/atmel-crypto.h | 22 +
+ 3 files changed, 524 insertions(+), 146 deletions(-)
+ delete mode 100644 include/linux/platform_data/atmel-aes.h
+ create mode 100644 include/linux/platform_data/atmel-crypto.h
+
+diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
+index 6bb20ff..035b87a 100644
+--- a/drivers/crypto/atmel-aes.c
++++ b/drivers/crypto/atmel-aes.c
+@@ -43,16 +43,19 @@
+ #include <crypto/aes.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
+-#include <linux/platform_data/atmel-aes.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-aes-regs.h"
+
++#include <linux/of.h>
++#include <linux/of_device.h>
++
+ #define CFB8_BLOCK_SIZE 1
+ #define CFB16_BLOCK_SIZE 2
+ #define CFB32_BLOCK_SIZE 4
+ #define CFB64_BLOCK_SIZE 8
+
+ /* AES flags */
+-#define AES_FLAGS_MODE_MASK 0x01ff
++#define AES_FLAGS_MODE_MASK 0x03ff
+ #define AES_FLAGS_ENCRYPT BIT(0)
+ #define AES_FLAGS_CBC BIT(1)
+ #define AES_FLAGS_CFB BIT(2)
+@@ -60,21 +63,26 @@
+ #define AES_FLAGS_CFB16 BIT(4)
+ #define AES_FLAGS_CFB32 BIT(5)
+ #define AES_FLAGS_CFB64 BIT(6)
+-#define AES_FLAGS_OFB BIT(7)
+-#define AES_FLAGS_CTR BIT(8)
++#define AES_FLAGS_CFB128 BIT(7)
++#define AES_FLAGS_OFB BIT(8)
++#define AES_FLAGS_CTR BIT(9)
+
+ #define AES_FLAGS_INIT BIT(16)
+ #define AES_FLAGS_DMA BIT(17)
+ #define AES_FLAGS_BUSY BIT(18)
++#define AES_FLAGS_FAST BIT(19)
+
+-#define AES_FLAGS_DUALBUFF BIT(24)
+-
+-#define ATMEL_AES_QUEUE_LENGTH 1
+-#define ATMEL_AES_CACHE_SIZE 0
++#define ATMEL_AES_QUEUE_LENGTH 50
+
+ #define ATMEL_AES_DMA_THRESHOLD 16
+
+
++struct atmel_aes_caps {
++ bool has_dualbuff;
++ bool has_cfb64;
++ u32 max_burst_size;
++};
++
+ struct atmel_aes_dev;
+
+ struct atmel_aes_ctx {
+@@ -82,6 +90,8 @@ struct atmel_aes_ctx {
+
+ int keylen;
+ u32 key[AES_KEYSIZE_256 / sizeof(u32)];
++
++ u16 block_size;
+ };
+
+ struct atmel_aes_reqctx {
+@@ -117,20 +127,27 @@ struct atmel_aes_dev {
+
+ struct scatterlist *in_sg;
+ unsigned int nb_in_sg;
+-
++ size_t in_offset;
+ struct scatterlist *out_sg;
+ unsigned int nb_out_sg;
++ size_t out_offset;
+
+ size_t bufcnt;
++ size_t buflen;
++ size_t dma_size;
+
+- u8 buf_in[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
+- int dma_in;
++ void *buf_in;
++ int dma_in;
++ dma_addr_t dma_addr_in;
+ struct atmel_aes_dma dma_lch_in;
+
+- u8 buf_out[ATMEL_AES_DMA_THRESHOLD] __aligned(sizeof(u32));
+- int dma_out;
++ void *buf_out;
++ int dma_out;
++ dma_addr_t dma_addr_out;
+ struct atmel_aes_dma dma_lch_out;
+
++ struct atmel_aes_caps caps;
++
+ u32 hw_version;
+ };
+
+@@ -170,6 +187,37 @@ static int atmel_aes_sg_length(struct ablkcipher_request *req,
+ return sg_nb;
+ }
+
++static int atmel_aes_sg_copy(struct scatterlist **sg, size_t *offset,
++ void *buf, size_t buflen, size_t total, int out)
++{
++ unsigned int count, off = 0;
++
++ while (buflen && total) {
++ count = min((*sg)->length - *offset, total);
++ count = min(count, buflen);
++
++ if (!count)
++ return off;
++
++ scatterwalk_map_and_copy(buf + off, *sg, *offset, count, out);
++
++ off += count;
++ buflen -= count;
++ *offset += count;
++ total -= count;
++
++ if (*offset == (*sg)->length) {
++ *sg = sg_next(*sg);
++ if (*sg)
++ *offset = 0;
++ else
++ total = 0;
++ }
++ }
++
++ return off;
++}
++
+ static inline u32 atmel_aes_read(struct atmel_aes_dev *dd, u32 offset)
+ {
+ return readl_relaxed(dd->io_base + offset);
+@@ -195,14 +243,6 @@ static void atmel_aes_write_n(struct atmel_aes_dev *dd, u32 offset,
+ atmel_aes_write(dd, offset, *value);
+ }
+
+-static void atmel_aes_dualbuff_test(struct atmel_aes_dev *dd)
+-{
+- atmel_aes_write(dd, AES_MR, AES_MR_DUALBUFF);
+-
+- if (atmel_aes_read(dd, AES_MR) & AES_MR_DUALBUFF)
+- dd->flags |= AES_FLAGS_DUALBUFF;
+-}
+-
+ static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_ctx *ctx)
+ {
+ struct atmel_aes_dev *aes_dd = NULL;
+@@ -230,7 +270,6 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
+
+ if (!(dd->flags & AES_FLAGS_INIT)) {
+ atmel_aes_write(dd, AES_CR, AES_CR_SWRST);
+- atmel_aes_dualbuff_test(dd);
+ dd->flags |= AES_FLAGS_INIT;
+ dd->err = 0;
+ }
+@@ -238,11 +277,19 @@ static int atmel_aes_hw_init(struct atmel_aes_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_aes_get_version(struct atmel_aes_dev *dd)
++{
++ return atmel_aes_read(dd, AES_HW_VERSION) & 0x00000fff;
++}
++
+ static void atmel_aes_hw_version_init(struct atmel_aes_dev *dd)
+ {
+ atmel_aes_hw_init(dd);
+
+- dd->hw_version = atmel_aes_read(dd, AES_HW_VERSION);
++ dd->hw_version = atmel_aes_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
+
+ clk_disable_unprepare(dd->iclk);
+ }
+@@ -265,50 +312,77 @@ static void atmel_aes_dma_callback(void *data)
+ tasklet_schedule(&dd->done_task);
+ }
+
+-static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
++static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd,
++ dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length)
+ {
++ struct scatterlist sg[2];
+ struct dma_async_tx_descriptor *in_desc, *out_desc;
+- int nb_dma_sg_in, nb_dma_sg_out;
+
+- dd->nb_in_sg = atmel_aes_sg_length(dd->req, dd->in_sg);
+- if (!dd->nb_in_sg)
+- goto exit_err;
++ dd->dma_size = length;
+
+- nb_dma_sg_in = dma_map_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
+- DMA_TO_DEVICE);
+- if (!nb_dma_sg_in)
+- goto exit_err;
++ if (!(dd->flags & AES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
+
+- in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, dd->in_sg,
+- nb_dma_sg_in, DMA_MEM_TO_DEV,
+- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (dd->flags & AES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & AES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
+
+- if (!in_desc)
+- goto unmap_in;
++ if (dd->flags & (AES_FLAGS_CFB8 | AES_FLAGS_CFB16 |
++ AES_FLAGS_CFB32 | AES_FLAGS_CFB64)) {
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ } else {
++ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ }
+
+- /* callback not needed */
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
+
+- dd->nb_out_sg = atmel_aes_sg_length(dd->req, dd->out_sg);
+- if (!dd->nb_out_sg)
+- goto unmap_in;
++ dd->flags |= AES_FLAGS_DMA;
+
+- nb_dma_sg_out = dma_map_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
+- DMA_FROM_DEVICE);
+- if (!nb_dma_sg_out)
+- goto unmap_out;
++ sg_init_table(&sg[0], 1);
++ sg_dma_address(&sg[0]) = dma_addr_in;
++ sg_dma_len(&sg[0]) = length;
+
+- out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, dd->out_sg,
+- nb_dma_sg_out, DMA_DEV_TO_MEM,
+- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ sg_init_table(&sg[1], 1);
++ sg_dma_address(&sg[1]) = dma_addr_out;
++ sg_dma_len(&sg[1]) = length;
+
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
++ 1, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!in_desc)
++ return -EINVAL;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
++ 1, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!out_desc)
+- goto unmap_out;
++ return -EINVAL;
+
+ out_desc->callback = atmel_aes_dma_callback;
+ out_desc->callback_param = dd;
+
+- dd->total -= dd->req->nbytes;
+-
+ dmaengine_submit(out_desc);
+ dma_async_issue_pending(dd->dma_lch_out.chan);
+
+@@ -316,15 +390,6 @@ static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd)
+ dma_async_issue_pending(dd->dma_lch_in.chan);
+
+ return 0;
+-
+-unmap_out:
+- dma_unmap_sg(dd->dev, dd->out_sg, dd->nb_out_sg,
+- DMA_FROM_DEVICE);
+-unmap_in:
+- dma_unmap_sg(dd->dev, dd->in_sg, dd->nb_in_sg,
+- DMA_TO_DEVICE);
+-exit_err:
+- return -EINVAL;
+ }
+
+ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
+@@ -357,30 +422,66 @@ static int atmel_aes_crypt_cpu_start(struct atmel_aes_dev *dd)
+
+ static int atmel_aes_crypt_dma_start(struct atmel_aes_dev *dd)
+ {
+- int err;
++ int err, fast = 0, in, out;
++ size_t count;
++ dma_addr_t addr_in, addr_out;
++
++ if ((!dd->in_offset) && (!dd->out_offset)) {
++ /* check for alignment */
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
++ fast = in && out;
++
++ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
++ fast = 0;
++ }
++
++
++ if (fast) {
++ count = min(dd->total, sg_dma_len(dd->in_sg));
++ count = min(count, sg_dma_len(dd->out_sg));
++
++ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ return -EINVAL;
++ }
++
++ err = dma_map_sg(dd->dev, dd->out_sg, 1,
++ DMA_FROM_DEVICE);
++ if (!err) {
++ dev_err(dd->dev, "dma_map_sg() error\n");
++ dma_unmap_sg(dd->dev, dd->in_sg, 1,
++ DMA_TO_DEVICE);
++ return -EINVAL;
++ }
++
++ addr_in = sg_dma_address(dd->in_sg);
++ addr_out = sg_dma_address(dd->out_sg);
++
++ dd->flags |= AES_FLAGS_FAST;
+
+- if (dd->flags & AES_FLAGS_CFB8) {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_1_BYTE;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_1_BYTE;
+- } else if (dd->flags & AES_FLAGS_CFB16) {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_2_BYTES;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_2_BYTES;
+ } else {
+- dd->dma_lch_in.dma_conf.dst_addr_width =
+- DMA_SLAVE_BUSWIDTH_4_BYTES;
+- dd->dma_lch_out.dma_conf.src_addr_width =
+- DMA_SLAVE_BUSWIDTH_4_BYTES;
++ /* use cache buffers */
++ count = atmel_aes_sg_copy(&dd->in_sg, &dd->in_offset,
++ dd->buf_in, dd->buflen, dd->total, 0);
++
++ addr_in = dd->dma_addr_in;
++ addr_out = dd->dma_addr_out;
++
++ dd->flags &= ~AES_FLAGS_FAST;
+ }
+
+- dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
+- dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++ dd->total -= count;
+
+- dd->flags |= AES_FLAGS_DMA;
+- err = atmel_aes_crypt_dma(dd);
++ err = atmel_aes_crypt_dma(dd, addr_in, addr_out, count);
++
++ if (err && (dd->flags & AES_FLAGS_FAST)) {
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
++ }
+
+ return err;
+ }
+@@ -415,6 +516,8 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
+ valmr |= AES_MR_CFBS_32b;
+ else if (dd->flags & AES_FLAGS_CFB64)
+ valmr |= AES_MR_CFBS_64b;
++ else if (dd->flags & AES_FLAGS_CFB128)
++ valmr |= AES_MR_CFBS_128b;
+ } else if (dd->flags & AES_FLAGS_OFB) {
+ valmr |= AES_MR_OPMOD_OFB;
+ } else if (dd->flags & AES_FLAGS_CTR) {
+@@ -428,7 +531,7 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd)
+
+ if (dd->total > ATMEL_AES_DMA_THRESHOLD) {
+ valmr |= AES_MR_SMOD_IDATAR0;
+- if (dd->flags & AES_FLAGS_DUALBUFF)
++ if (dd->caps.has_dualbuff)
+ valmr |= AES_MR_DUALBUFF;
+ } else {
+ valmr |= AES_MR_SMOD_AUTO;
+@@ -482,7 +585,9 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
+ /* assign new request to device */
+ dd->req = req;
+ dd->total = req->nbytes;
++ dd->in_offset = 0;
+ dd->in_sg = req->src;
++ dd->out_offset = 0;
+ dd->out_sg = req->dst;
+
+ rctx = ablkcipher_request_ctx(req);
+@@ -511,18 +616,86 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd,
+ static int atmel_aes_crypt_dma_stop(struct atmel_aes_dev *dd)
+ {
+ int err = -EINVAL;
++ size_t count;
+
+ if (dd->flags & AES_FLAGS_DMA) {
+- dma_unmap_sg(dd->dev, dd->out_sg,
+- dd->nb_out_sg, DMA_FROM_DEVICE);
+- dma_unmap_sg(dd->dev, dd->in_sg,
+- dd->nb_in_sg, DMA_TO_DEVICE);
+ err = 0;
++ if (dd->flags & AES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_aes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++ }
++
++ return err;
++}
++
++
++static int atmel_aes_buff_init(struct atmel_aes_dev *dd)
++{
++ int err = -ENOMEM;
++
++ dd->buf_in = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buf_out = (void *)__get_free_pages(GFP_KERNEL, 0);
++ dd->buflen = PAGE_SIZE;
++ dd->buflen &= ~(AES_BLOCK_SIZE - 1);
++
++ if (!dd->buf_in || !dd->buf_out) {
++ dev_err(dd->dev, "unable to alloc pages.\n");
++ goto err_alloc;
+ }
+
++ /* MAP here */
++ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in,
++ dd->buflen, DMA_TO_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_in)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_in;
++ }
++
++ dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out,
++ dd->buflen, DMA_FROM_DEVICE);
++ if (dma_mapping_error(dd->dev, dd->dma_addr_out)) {
++ dev_err(dd->dev, "dma %d bytes error\n", dd->buflen);
++ err = -EINVAL;
++ goto err_map_out;
++ }
++
++ return 0;
++
++err_map_out:
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++err_map_in:
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++err_alloc:
++ if (err)
++ pr_err("error: %d\n", err);
+ return err;
+ }
+
++static void atmel_aes_buff_cleanup(struct atmel_aes_dev *dd)
++{
++ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
++ DMA_FROM_DEVICE);
++ dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
++ DMA_TO_DEVICE);
++ free_page((unsigned long)dd->buf_out);
++ free_page((unsigned long)dd->buf_in);
++}
++
+ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ {
+ struct atmel_aes_ctx *ctx = crypto_ablkcipher_ctx(
+@@ -530,9 +703,30 @@ static int atmel_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req);
+ struct atmel_aes_dev *dd;
+
+- if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+- pr_err("request size is not exact amount of AES blocks\n");
+- return -EINVAL;
++ if (mode & AES_FLAGS_CFB8) {
++ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB8 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB8_BLOCK_SIZE;
++ } else if (mode & AES_FLAGS_CFB16) {
++ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB16 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB16_BLOCK_SIZE;
++ } else if (mode & AES_FLAGS_CFB32) {
++ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of CFB32 blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = CFB32_BLOCK_SIZE;
++ } else {
++ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of AES blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = AES_BLOCK_SIZE;
+ }
+
+ dd = atmel_aes_find_dev(ctx);
+@@ -556,14 +750,12 @@ static bool atmel_aes_filter(struct dma_chan *chan, void *slave)
+ }
+ }
+
+-static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
++static int atmel_aes_dma_init(struct atmel_aes_dev *dd,
++ struct crypto_platform_data *pdata)
+ {
+ int err = -ENOMEM;
+- struct aes_platform_data *pdata;
+ dma_cap_mask_t mask_in, mask_out;
+
+- pdata = dd->dev->platform_data;
+-
+ if (pdata && pdata->dma_slave->txdata.dma_dev &&
+ pdata->dma_slave->rxdata.dma_dev) {
+
+@@ -573,28 +765,38 @@ static int atmel_aes_dma_init(struct atmel_aes_dev *dd)
+
+ dd->dma_lch_in.chan = dma_request_channel(mask_in,
+ atmel_aes_filter, &pdata->dma_slave->rxdata);
++
+ if (!dd->dma_lch_in.chan)
+ goto err_dma_in;
+
+ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
+ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
+ AES_IDATAR(0);
+- dd->dma_lch_in.dma_conf.src_maxburst = 1;
+- dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dd->dma_lch_in.dma_conf.device_fc = false;
+
+ dma_cap_zero(mask_out);
+ dma_cap_set(DMA_SLAVE, mask_out);
+ dd->dma_lch_out.chan = dma_request_channel(mask_out,
+ atmel_aes_filter, &pdata->dma_slave->txdata);
++
+ if (!dd->dma_lch_out.chan)
+ goto err_dma_out;
+
+ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
+ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
+ AES_ODATAR(0);
+- dd->dma_lch_out.dma_conf.src_maxburst = 1;
+- dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.dst_maxburst = dd->caps.max_burst_size;
++ dd->dma_lch_out.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dd->dma_lch_out.dma_conf.device_fc = false;
+
+ return 0;
+@@ -670,13 +872,13 @@ static int atmel_aes_ofb_decrypt(struct ablkcipher_request *req)
+ static int atmel_aes_cfb_encrypt(struct ablkcipher_request *req)
+ {
+ return atmel_aes_crypt(req,
+- AES_FLAGS_ENCRYPT | AES_FLAGS_CFB);
++ AES_FLAGS_ENCRYPT | AES_FLAGS_CFB | AES_FLAGS_CFB128);
+ }
+
+ static int atmel_aes_cfb_decrypt(struct ablkcipher_request *req)
+ {
+ return atmel_aes_crypt(req,
+- AES_FLAGS_CFB);
++ AES_FLAGS_CFB | AES_FLAGS_CFB128);
+ }
+
+ static int atmel_aes_cfb64_encrypt(struct ablkcipher_request *req)
+@@ -758,7 +960,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -778,7 +980,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -799,7 +1001,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -820,7 +1022,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -841,7 +1043,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -862,7 +1064,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -904,7 +1106,7 @@ static struct crypto_alg aes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0xf,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -920,15 +1122,14 @@ static struct crypto_alg aes_algs[] = {
+ },
+ };
+
+-static struct crypto_alg aes_cfb64_alg[] = {
+-{
++static struct crypto_alg aes_cfb64_alg = {
+ .cra_name = "cfb64(aes)",
+ .cra_driver_name = "atmel-cfb64-aes",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB64_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_aes_ctx),
+- .cra_alignmask = 0x0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_aes_cra_init,
+@@ -941,7 +1142,6 @@ static struct crypto_alg aes_cfb64_alg[] = {
+ .encrypt = atmel_aes_cfb64_encrypt,
+ .decrypt = atmel_aes_cfb64_decrypt,
+ }
+-},
+ };
+
+ static void atmel_aes_queue_task(unsigned long data)
+@@ -974,7 +1174,14 @@ static void atmel_aes_done_task(unsigned long data)
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+- err = atmel_aes_crypt_dma_start(dd);
++ if (dd->flags & AES_FLAGS_FAST) {
++ dd->in_sg = sg_next(dd->in_sg);
++ dd->out_sg = sg_next(dd->out_sg);
++ if (!dd->in_sg || !dd->out_sg)
++ err = -EINVAL;
++ }
++ if (!err)
++ err = atmel_aes_crypt_dma_start(dd);
+ if (!err)
+ return; /* DMA started. Not fininishing. */
+ }
+@@ -1008,8 +1215,8 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd)
+
+ for (i = 0; i < ARRAY_SIZE(aes_algs); i++)
+ crypto_unregister_alg(&aes_algs[i]);
+- if (dd->hw_version >= 0x130)
+- crypto_unregister_alg(&aes_cfb64_alg[0]);
++ if (dd->caps.has_cfb64)
++ crypto_unregister_alg(&aes_cfb64_alg);
+ }
+
+ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
+@@ -1023,11 +1230,9 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
+ goto err_aes_algs;
+ }
+
+- atmel_aes_hw_version_init(dd);
+-
+- if (dd->hw_version >= 0x130) {
+- INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
+- err = crypto_register_alg(&aes_cfb64_alg[0]);
++ if (dd->caps.has_cfb64) {
++ INIT_LIST_HEAD(&aes_cfb64_alg.cra_list);
++ err = crypto_register_alg(&aes_cfb64_alg);
+ if (err)
+ goto err_aes_cfb64_alg;
+ }
+@@ -1043,10 +1248,158 @@ err_aes_algs:
+ return err;
+ }
+
++
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_aes_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-aes" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_aes_dt_ids);
++
++static int atmel_aes_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave, const char *name)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++ int index;
++
++ index = of_property_match_string(np, "dma-name", name);
++ if (index < 0) {
++ pr_err("%s: dma-name property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err0;
++ }
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
++ index, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++static struct crypto_platform_data __devinit*
++atmel_aes_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->txdata;
++ /* retrieve TX DMA configuration first */
++ if (atmel_aes_dma_of_init(np, atslave, "tx")) {
++ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_aes_dma_of_init(np, atslave, "rx")) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_aes_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_aes_get_cap(struct atmel_aes_dev *dd)
++{
++ dd->caps.has_dualbuff = 0;
++ dd->caps.has_cfb64 = 0;
++ dd->caps.max_burst_size = 1;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xff0) {
++ case 0x130:
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_cfb64 = 1;
++ dd->caps.max_burst_size = 4;
++ break;
++ case 0x120:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged aes version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ {
+ struct atmel_aes_dev *aes_dd;
+- struct aes_platform_data *pdata;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *aes_res;
+ unsigned long aes_phys_size;
+@@ -1054,8 +1407,11 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+- err = -ENXIO;
+- goto aes_dd_err;
++ pdata = atmel_aes_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ return PTR_ERR(pdata);
++ }
+ }
+
+ aes_dd = kzalloc(sizeof(struct atmel_aes_dev), GFP_KERNEL);
+@@ -1106,7 +1462,7 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- aes_dd->iclk = clk_get(&pdev->dev, NULL);
++ aes_dd->iclk = clk_get(&pdev->dev, "aes_clk");
+ if (IS_ERR(aes_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(aes_dd->iclk);
+@@ -1120,7 +1476,15 @@ static int __devinit atmel_aes_probe(struct platform_device *pdev)
+ goto aes_io_err;
+ }
+
+- err = atmel_aes_dma_init(aes_dd);
++ atmel_aes_hw_version_init(aes_dd);
++
++ atmel_aes_get_cap(aes_dd);
++
++ err = atmel_aes_buff_init(aes_dd);
++ if (err)
++ goto err_aes_buff;
++
++ err = atmel_aes_dma_init(aes_dd, pdata);
+ if (err)
+ goto err_aes_dma;
+
+@@ -1142,6 +1506,8 @@ err_algs:
+ spin_unlock(&atmel_aes.lock);
+ atmel_aes_dma_cleanup(aes_dd);
+ err_aes_dma:
++ atmel_aes_buff_cleanup(aes_dd);
++err_aes_buff:
+ iounmap(aes_dd->io_base);
+ aes_io_err:
+ clk_put(aes_dd->iclk);
+@@ -1191,15 +1557,27 @@ static int __devexit atmel_aes_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_aes_driver = {
+- .probe = atmel_aes_probe,
+ .remove = __devexit_p(atmel_aes_remove),
+ .driver = {
+ .name = "atmel_aes",
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_aes_dt_ids),
+ },
+ };
+
+-module_platform_driver(atmel_aes_driver);
++static int __init atmel_aes_init(void)
++{
++ return platform_driver_probe(&atmel_aes_driver, atmel_aes_probe);
++}
++
++static void __exit atmel_aes_exit(void)
++{
++ platform_driver_unregister(&atmel_aes_driver);
++}
++
++late_initcall(atmel_aes_init); /* try to load after dma driver when built-in */
++module_exit(atmel_aes_exit);
++
+
+ MODULE_DESCRIPTION("Atmel AES hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/platform_data/atmel-aes.h b/include/linux/platform_data/atmel-aes.h
+deleted file mode 100644
+index e7a1949..0000000
+--- a/include/linux/platform_data/atmel-aes.h
++++ /dev/null
+@@ -1,22 +0,0 @@
+-#ifndef __LINUX_ATMEL_AES_H
+-#define __LINUX_ATMEL_AES_H
+-
+-#include <mach/at_hdmac.h>
+-
+-/**
+- * struct aes_dma_data - DMA data for AES
+- */
+-struct aes_dma_data {
+- struct at_dma_slave txdata;
+- struct at_dma_slave rxdata;
+-};
+-
+-/**
+- * struct aes_platform_data - board-specific AES configuration
+- * @dma_slave: DMA slave interface to use in data transfers.
+- */
+-struct aes_platform_data {
+- struct aes_dma_data *dma_slave;
+-};
+-
+-#endif /* __LINUX_ATMEL_AES_H */
+diff --git a/include/linux/platform_data/atmel-crypto.h b/include/linux/platform_data/atmel-crypto.h
+new file mode 100644
+index 0000000..eddfca7
+--- /dev/null
++++ b/include/linux/platform_data/atmel-crypto.h
+@@ -0,0 +1,22 @@
++#ifndef __LINUX_ATMEL_CRYPTO_H
++#define __LINUX_ATMEL_CRYPTO_H
++
++#include <mach/at_hdmac.h>
++
++/**
++ * struct crypto_dma_data - DMA data for AES/TDES/SHA
++ */
++struct crypto_dma_data {
++ struct at_dma_slave txdata;
++ struct at_dma_slave rxdata;
++};
++
++/**
++ * struct tdes_platform_data - board-specific AES/TDES/SHA configuration
++ * @dma_slave: DMA slave interface to use in data transfers.
++ */
++struct crypto_platform_data {
++ struct crypto_dma_data *dma_slave;
++};
++
++#endif /* __LINUX_ATMEL_CRYPTO_H */
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 347e1c7f02beed8503937c53ecb23007970668ac Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Tue, 17 Apr 2012 15:00:45 +0800
-Subject: pinctrl: show pin name when request pins
-
-Pin name is more useful to users.
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/pinmux.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
-index 375b214..d6f6823 100644
---- a/drivers/pinctrl/pinmux.c
-+++ b/drivers/pinctrl/pinmux.c
-@@ -86,8 +86,6 @@ static int pin_request(struct pinctrl_dev *pctldev,
- const struct pinmux_ops *ops = pctldev->desc->pmxops;
- int status = -EINVAL;
-
-- dev_dbg(pctldev->dev, "request pin %d for %s\n", pin, owner);
--
- desc = pin_desc_get(pctldev, pin);
- if (desc == NULL) {
- dev_err(pctldev->dev,
-@@ -95,6 +93,9 @@ static int pin_request(struct pinctrl_dev *pctldev,
- goto out;
- }
-
-+ dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n",
-+ pin, desc->name, owner);
-+
- if (gpio_range) {
- /* There's no need to support multiple GPIO requests */
- if (desc->gpio_owner) {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 0de4fb161bfb4a5bdf3deec1d94015435f428e88 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:16 +0200
+Subject: crypto: Atmel TDES; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-tdes-regs.h | 2 +
+ drivers/crypto/atmel-tdes.c | 541 +++++++++++++++++++++++++++++++++++----
+ 2 files changed, 487 insertions(+), 56 deletions(-)
+
+diff --git a/drivers/crypto/atmel-tdes-regs.h b/drivers/crypto/atmel-tdes-regs.h
+index 5ac2a90..f86734d 100644
+--- a/drivers/crypto/atmel-tdes-regs.h
++++ b/drivers/crypto/atmel-tdes-regs.h
+@@ -69,6 +69,8 @@
+ #define TDES_XTEARNDR_XTEA_RNDS_MASK (0x3F << 0)
+ #define TDES_XTEARNDR_XTEA_RNDS_OFFSET 0
+
++#define TDES_HW_VERSION 0xFC
++
+ #define TDES_RPR 0x100
+ #define TDES_RCR 0x104
+ #define TDES_TPR 0x108
+diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
+index eb2b61e..9de10bd 100644
+--- a/drivers/crypto/atmel-tdes.c
++++ b/drivers/crypto/atmel-tdes.c
+@@ -43,29 +43,37 @@
+ #include <crypto/des.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-tdes-regs.h"
+
+ /* TDES flags */
+-#define TDES_FLAGS_MODE_MASK 0x007f
++#define TDES_FLAGS_MODE_MASK 0x00ff
+ #define TDES_FLAGS_ENCRYPT BIT(0)
+ #define TDES_FLAGS_CBC BIT(1)
+ #define TDES_FLAGS_CFB BIT(2)
+ #define TDES_FLAGS_CFB8 BIT(3)
+ #define TDES_FLAGS_CFB16 BIT(4)
+ #define TDES_FLAGS_CFB32 BIT(5)
+-#define TDES_FLAGS_OFB BIT(6)
++#define TDES_FLAGS_CFB64 BIT(6)
++#define TDES_FLAGS_OFB BIT(7)
+
+ #define TDES_FLAGS_INIT BIT(16)
+ #define TDES_FLAGS_FAST BIT(17)
+ #define TDES_FLAGS_BUSY BIT(18)
++#define TDES_FLAGS_DMA BIT(19)
+
+-#define ATMEL_TDES_QUEUE_LENGTH 1
++#define ATMEL_TDES_QUEUE_LENGTH 50
+
+ #define CFB8_BLOCK_SIZE 1
+ #define CFB16_BLOCK_SIZE 2
+ #define CFB32_BLOCK_SIZE 4
+-#define CFB64_BLOCK_SIZE 8
+
++struct atmel_tdes_caps {
++ bool has_dma;
++ u32 has_cfb_3keys;
++};
+
+ struct atmel_tdes_dev;
+
+@@ -75,12 +83,19 @@ struct atmel_tdes_ctx {
+ int keylen;
+ u32 key[3*DES_KEY_SIZE / sizeof(u32)];
+ unsigned long flags;
++
++ u16 block_size;
+ };
+
+ struct atmel_tdes_reqctx {
+ unsigned long mode;
+ };
+
++struct atmel_tdes_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
++
+ struct atmel_tdes_dev {
+ struct list_head list;
+ unsigned long phys_base;
+@@ -104,8 +119,10 @@ struct atmel_tdes_dev {
+ size_t total;
+
+ struct scatterlist *in_sg;
++ unsigned int nb_in_sg;
+ size_t in_offset;
+ struct scatterlist *out_sg;
++ unsigned int nb_out_sg;
+ size_t out_offset;
+
+ size_t buflen;
+@@ -114,10 +131,16 @@ struct atmel_tdes_dev {
+ void *buf_in;
+ int dma_in;
+ dma_addr_t dma_addr_in;
++ struct atmel_tdes_dma dma_lch_in;
+
+ void *buf_out;
+ int dma_out;
+ dma_addr_t dma_addr_out;
++ struct atmel_tdes_dma dma_lch_out;
++
++ struct atmel_tdes_caps caps;
++
++ u32 hw_version;
+ };
+
+ struct atmel_tdes_drv {
+@@ -212,6 +235,31 @@ static int atmel_tdes_hw_init(struct atmel_tdes_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_tdes_get_version(struct atmel_tdes_dev *dd)
++{
++ return atmel_tdes_read(dd, TDES_HW_VERSION) & 0x00000fff;
++}
++
++static void atmel_tdes_hw_version_init(struct atmel_tdes_dev *dd)
++{
++ atmel_tdes_hw_init(dd);
++
++ dd->hw_version = atmel_tdes_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
++static void atmel_tdes_dma_callback(void *data)
++{
++ struct atmel_tdes_dev *dd = data;
++
++ /* dma_lch_out - completed */
++ tasklet_schedule(&dd->done_task);
++}
++
+ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ {
+ int err;
+@@ -222,7 +270,9 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ if (err)
+ return err;
+
+- atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS);
++ if (!dd->caps.has_dma)
++ atmel_tdes_write(dd, TDES_PTCR,
++ TDES_PTCR_TXTDIS | TDES_PTCR_RXTDIS);
+
+ /* MR register must be set before IV registers */
+ if (dd->ctx->keylen > (DES_KEY_SIZE << 1)) {
+@@ -246,6 +296,8 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ valmr |= TDES_MR_CFBS_16b;
+ else if (dd->flags & TDES_FLAGS_CFB32)
+ valmr |= TDES_MR_CFBS_32b;
++ else if (dd->flags & TDES_FLAGS_CFB64)
++ valmr |= TDES_MR_CFBS_64b;
+ } else if (dd->flags & TDES_FLAGS_OFB) {
+ valmr |= TDES_MR_OPMOD_OFB;
+ }
+@@ -267,7 +319,7 @@ static int atmel_tdes_write_ctrl(struct atmel_tdes_dev *dd)
+ return 0;
+ }
+
+-static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd)
+ {
+ int err = 0;
+ size_t count;
+@@ -293,7 +345,7 @@ static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
+ return err;
+ }
+
+-static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd)
++static int atmel_tdes_buff_init(struct atmel_tdes_dev *dd)
+ {
+ int err = -ENOMEM;
+
+@@ -338,7 +390,7 @@ err_alloc:
+ return err;
+ }
+
+-static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++static void atmel_tdes_buff_cleanup(struct atmel_tdes_dev *dd)
+ {
+ dma_unmap_single(dd->dev, dd->dma_addr_out, dd->buflen,
+ DMA_FROM_DEVICE);
+@@ -348,7 +400,7 @@ static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
+ free_page((unsigned long)dd->buf_in);
+ }
+
+-static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++static int atmel_tdes_crypt_pdc(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ dma_addr_t dma_addr_out, int length)
+ {
+ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
+@@ -384,7 +436,76 @@ static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
+ return 0;
+ }
+
+-static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
++static int atmel_tdes_crypt_dma(struct crypto_tfm *tfm, dma_addr_t dma_addr_in,
++ dma_addr_t dma_addr_out, int length)
++{
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd = ctx->dd;
++ struct scatterlist sg[2];
++ struct dma_async_tx_descriptor *in_desc, *out_desc;
++
++ dd->dma_size = length;
++
++ if (!(dd->flags & TDES_FLAGS_FAST)) {
++ dma_sync_single_for_device(dd->dev, dma_addr_in, length,
++ DMA_TO_DEVICE);
++ }
++
++ if (dd->flags & TDES_FLAGS_CFB8) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_1_BYTE;
++ } else if (dd->flags & TDES_FLAGS_CFB16) {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_2_BYTES;
++ } else {
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++ dmaengine_slave_config(dd->dma_lch_out.chan, &dd->dma_lch_out.dma_conf);
++
++ dd->flags |= TDES_FLAGS_DMA;
++
++ sg_init_table(&sg[0], 1);
++ sg_dma_address(&sg[0]) = dma_addr_in;
++ sg_dma_len(&sg[0]) = length;
++
++ sg_init_table(&sg[1], 1);
++ sg_dma_address(&sg[1]) = dma_addr_out;
++ sg_dma_len(&sg[1]) = length;
++
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, &sg[0],
++ 1, DMA_MEM_TO_DEV,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!in_desc)
++ return -EINVAL;
++
++ out_desc = dmaengine_prep_slave_sg(dd->dma_lch_out.chan, &sg[1],
++ 1, DMA_DEV_TO_MEM,
++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ if (!out_desc)
++ return -EINVAL;
++
++ out_desc->callback = atmel_tdes_dma_callback;
++ out_desc->callback_param = dd;
++
++ dmaengine_submit(out_desc);
++ dma_async_issue_pending(dd->dma_lch_out.chan);
++
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return 0;
++}
++
++static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd)
+ {
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(
+ crypto_ablkcipher_reqtfm(dd->req));
+@@ -392,23 +513,23 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ size_t count;
+ dma_addr_t addr_in, addr_out;
+
+- if (sg_is_last(dd->in_sg) && sg_is_last(dd->out_sg)) {
++ if ((!dd->in_offset) && (!dd->out_offset)) {
+ /* check for alignment */
+- in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32));
+- out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32));
+-
++ in = IS_ALIGNED((u32)dd->in_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->in_sg->length, dd->ctx->block_size);
++ out = IS_ALIGNED((u32)dd->out_sg->offset, sizeof(u32)) &&
++ IS_ALIGNED(dd->out_sg->length, dd->ctx->block_size);
+ fast = in && out;
++
++ if (sg_dma_len(dd->in_sg) != sg_dma_len(dd->out_sg))
++ fast = 0;
+ }
+
++
+ if (fast) {
+ count = min(dd->total, sg_dma_len(dd->in_sg));
+ count = min(count, sg_dma_len(dd->out_sg));
+
+- if (count != dd->total) {
+- pr_err("request length != buffer length\n");
+- return -EINVAL;
+- }
+-
+ err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ if (!err) {
+ dev_err(dd->dev, "dma_map_sg() error\n");
+@@ -438,13 +559,16 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ addr_out = dd->dma_addr_out;
+
+ dd->flags &= ~TDES_FLAGS_FAST;
+-
+ }
+
+ dd->total -= count;
+
+- err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
+- if (err) {
++ if (dd->caps.has_dma)
++ err = atmel_tdes_crypt_dma(tfm, addr_in, addr_out, count);
++ else
++ err = atmel_tdes_crypt_pdc(tfm, addr_in, addr_out, count);
++
++ if (err && (dd->flags & TDES_FLAGS_FAST)) {
+ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
+ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_TO_DEVICE);
+ }
+@@ -452,7 +576,6 @@ static int atmel_tdes_crypt_dma_start(struct atmel_tdes_dev *dd)
+ return err;
+ }
+
+-
+ static void atmel_tdes_finish_req(struct atmel_tdes_dev *dd, int err)
+ {
+ struct ablkcipher_request *req = dd->req;
+@@ -511,7 +634,7 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
+
+ err = atmel_tdes_write_ctrl(dd);
+ if (!err)
+- err = atmel_tdes_crypt_dma_start(dd);
++ err = atmel_tdes_crypt_start(dd);
+ if (err) {
+ /* des_task will not finish it, so do it here */
+ atmel_tdes_finish_req(dd, err);
+@@ -521,41 +644,145 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd,
+ return ret;
+ }
+
++static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd)
++{
++ int err = -EINVAL;
++ size_t count;
++
++ if (dd->flags & TDES_FLAGS_DMA) {
++ err = 0;
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dma_unmap_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE);
++ dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE);
++ } else {
++ dma_sync_single_for_device(dd->dev, dd->dma_addr_out,
++ dd->dma_size, DMA_FROM_DEVICE);
++
++ /* copy data */
++ count = atmel_tdes_sg_copy(&dd->out_sg, &dd->out_offset,
++ dd->buf_out, dd->buflen, dd->dma_size, 1);
++ if (count != dd->dma_size) {
++ err = -EINVAL;
++ pr_err("not all data converted: %u\n", count);
++ }
++ }
++ }
++ return err;
++}
+
+ static int atmel_tdes_crypt(struct ablkcipher_request *req, unsigned long mode)
+ {
+ struct atmel_tdes_ctx *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+ struct atmel_tdes_reqctx *rctx = ablkcipher_request_ctx(req);
+- struct atmel_tdes_dev *dd;
+
+ if (mode & TDES_FLAGS_CFB8) {
+ if (!IS_ALIGNED(req->nbytes, CFB8_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB8 blocks\n");
+ return -EINVAL;
+ }
++ ctx->block_size = CFB8_BLOCK_SIZE;
+ } else if (mode & TDES_FLAGS_CFB16) {
+ if (!IS_ALIGNED(req->nbytes, CFB16_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB16 blocks\n");
+ return -EINVAL;
+ }
++ ctx->block_size = CFB16_BLOCK_SIZE;
+ } else if (mode & TDES_FLAGS_CFB32) {
+ if (!IS_ALIGNED(req->nbytes, CFB32_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of CFB32 blocks\n");
+ return -EINVAL;
+ }
+- } else if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
+- pr_err("request size is not exact amount of DES blocks\n");
+- return -EINVAL;
++ ctx->block_size = CFB32_BLOCK_SIZE;
++ } else {
++ if (!IS_ALIGNED(req->nbytes, DES_BLOCK_SIZE)) {
++ pr_err("request size is not exact amount of DES blocks\n");
++ return -EINVAL;
++ }
++ ctx->block_size = DES_BLOCK_SIZE;
+ }
+
+- dd = atmel_tdes_find_dev(ctx);
+- if (!dd)
++ rctx->mode = mode;
++
++ return atmel_tdes_handle_queue(ctx->dd, req);
++}
++
++static bool atmel_tdes_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_tdes_dma_init(struct atmel_tdes_dev *dd,
++ struct crypto_platform_data *pdata)
++{
++ int err = -ENOMEM;
++ dma_cap_mask_t mask_in, mask_out;
++
++ if (pdata && pdata->dma_slave->txdata.dma_dev &&
++ pdata->dma_slave->rxdata.dma_dev) {
++
++ /* Try to grab 2 DMA channels */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_tdes_filter, &pdata->dma_slave->rxdata);
++
++ if (!dd->dma_lch_in.chan)
++ goto err_dma_in;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ TDES_IDATA1R;
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ dma_cap_zero(mask_out);
++ dma_cap_set(DMA_SLAVE, mask_out);
++ dd->dma_lch_out.chan = dma_request_channel(mask_out,
++ atmel_tdes_filter, &pdata->dma_slave->txdata);
++
++ if (!dd->dma_lch_out.chan)
++ goto err_dma_out;
++
++ dd->dma_lch_out.dma_conf.direction = DMA_DEV_TO_MEM;
++ dd->dma_lch_out.dma_conf.src_addr = dd->phys_base +
++ TDES_ODATA1R;
++ dd->dma_lch_out.dma_conf.src_maxburst = 1;
++ dd->dma_lch_out.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_out.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_out.dma_conf.device_fc = false;
++
++ return 0;
++ } else {
+ return -ENODEV;
++ }
+
+- rctx->mode = mode;
++err_dma_out:
++ dma_release_channel(dd->dma_lch_in.chan);
++err_dma_in:
++ return err;
++}
+
+- return atmel_tdes_handle_queue(dd, req);
++static void atmel_tdes_dma_cleanup(struct atmel_tdes_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++ dma_release_channel(dd->dma_lch_out.chan);
+ }
+
+ static int atmel_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+@@ -595,7 +822,8 @@ static int atmel_tdes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ /*
+ * HW bug in cfb 3-keys mode.
+ */
+- if (strstr(alg_name, "cfb") && (keylen != 2*DES_KEY_SIZE)) {
++ if (!ctx->dd->caps.has_cfb_3keys && strstr(alg_name, "cfb")
++ && (keylen != 2*DES_KEY_SIZE)) {
+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ } else if ((keylen != 2*DES_KEY_SIZE) && (keylen != 3*DES_KEY_SIZE)) {
+@@ -683,8 +911,15 @@ static int atmel_tdes_ofb_decrypt(struct ablkcipher_request *req)
+
+ static int atmel_tdes_cra_init(struct crypto_tfm *tfm)
+ {
++ struct atmel_tdes_ctx *ctx = crypto_tfm_ctx(tfm);
++ struct atmel_tdes_dev *dd;
++
+ tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_tdes_reqctx);
+
++ dd = atmel_tdes_find_dev(ctx);
++ if (!dd)
++ return -ENODEV;
++
+ return 0;
+ }
+
+@@ -700,7 +935,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -720,7 +955,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -741,7 +976,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -783,7 +1018,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -804,7 +1039,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -825,7 +1060,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -846,7 +1081,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -866,7 +1101,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -887,7 +1122,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -929,7 +1164,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB16_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x1,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -950,7 +1185,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = CFB32_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -971,7 +1206,7 @@ static struct crypto_alg tdes_algs[] = {
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct atmel_tdes_ctx),
+- .cra_alignmask = 0,
++ .cra_alignmask = 0x7,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = atmel_tdes_cra_init,
+@@ -999,14 +1234,24 @@ static void atmel_tdes_done_task(unsigned long data)
+ struct atmel_tdes_dev *dd = (struct atmel_tdes_dev *) data;
+ int err;
+
+- err = atmel_tdes_crypt_dma_stop(dd);
++ if (!(dd->flags & TDES_FLAGS_DMA))
++ err = atmel_tdes_crypt_pdc_stop(dd);
++ else
++ err = atmel_tdes_crypt_dma_stop(dd);
+
+ err = dd->err ? : err;
+
+ if (dd->total && !err) {
+- err = atmel_tdes_crypt_dma_start(dd);
++ if (dd->flags & TDES_FLAGS_FAST) {
++ dd->in_sg = sg_next(dd->in_sg);
++ dd->out_sg = sg_next(dd->out_sg);
++ if (!dd->in_sg || !dd->out_sg)
++ err = -EINVAL;
++ }
++ if (!err)
++ err = atmel_tdes_crypt_start(dd);
+ if (!err)
+- return;
++ return; /* DMA started. Not fininishing. */
+ }
+
+ atmel_tdes_finish_req(dd, err);
+@@ -1059,9 +1304,157 @@ err_tdes_algs:
+ return err;
+ }
+
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_tdes_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-tdes" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_tdes_dt_ids);
++
++static int atmel_tdes_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave, const char *name)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++ int index;
++
++ index = of_property_match_string(np, "dma-name", name);
++ if (index < 0) {
++ pr_err("%s: dma-name property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err0;
++ }
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells",
++ index, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++
++static struct crypto_platform_data __devinit*
++atmel_tdes_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->txdata;
++ /* retrieve TX DMA configuration first */
++ if (atmel_tdes_dma_of_init(np, atslave, "tx")) {
++ dev_err(&pdev->dev, "could not find TX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_tdes_dma_of_init(np, atslave, "rx")) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_tdes_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd)
++{
++
++ dd->caps.has_dma = 0;
++ dd->caps.has_cfb_3keys = 0;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xf00) {
++ case 0x700:
++ dd->caps.has_dma = 1;
++ dd->caps.has_cfb_3keys = 1;
++ break;
++ case 0x600:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged tdes version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ {
+ struct atmel_tdes_dev *tdes_dd;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *tdes_res;
+ unsigned long tdes_phys_size;
+@@ -1115,7 +1508,7 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- tdes_dd->iclk = clk_get(&pdev->dev, NULL);
++ tdes_dd->iclk = clk_get(&pdev->dev, "tdes_clk");
+ if (IS_ERR(tdes_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(tdes_dd->iclk);
+@@ -1129,9 +1522,27 @@ static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+ goto tdes_io_err;
+ }
+
+- err = atmel_tdes_dma_init(tdes_dd);
++ atmel_tdes_hw_version_init(tdes_dd);
++
++ atmel_tdes_get_cap(tdes_dd);
++
++ err = atmel_tdes_buff_init(tdes_dd);
+ if (err)
+- goto err_tdes_dma;
++ goto err_tdes_buff;
++
++ if (tdes_dd->caps.has_dma) {
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ pdata = atmel_tdes_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ goto err_pdata;
++ }
++ }
++ err = atmel_tdes_dma_init(tdes_dd, pdata);
++ if (err)
++ goto err_tdes_dma;
++ }
+
+ spin_lock(&atmel_tdes.lock);
+ list_add_tail(&tdes_dd->list, &atmel_tdes.dev_list);
+@@ -1149,8 +1560,12 @@ err_algs:
+ spin_lock(&atmel_tdes.lock);
+ list_del(&tdes_dd->list);
+ spin_unlock(&atmel_tdes.lock);
+- atmel_tdes_dma_cleanup(tdes_dd);
++ if (tdes_dd->caps.has_dma)
++ atmel_tdes_dma_cleanup(tdes_dd);
+ err_tdes_dma:
++err_pdata:
++ atmel_tdes_buff_cleanup(tdes_dd);
++err_tdes_buff:
+ iounmap(tdes_dd->io_base);
+ tdes_io_err:
+ clk_put(tdes_dd->iclk);
+@@ -1184,7 +1599,10 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
+ tasklet_kill(&tdes_dd->done_task);
+ tasklet_kill(&tdes_dd->queue_task);
+
+- atmel_tdes_dma_cleanup(tdes_dd);
++ if (tdes_dd->caps.has_dma)
++ atmel_tdes_dma_cleanup(tdes_dd);
++
++ atmel_tdes_buff_cleanup(tdes_dd);
+
+ iounmap(tdes_dd->io_base);
+
+@@ -1200,15 +1618,26 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_tdes_driver = {
+- .probe = atmel_tdes_probe,
+ .remove = __devexit_p(atmel_tdes_remove),
+ .driver = {
+ .name = "atmel_tdes",
+- .owner = THIS_MODULE,
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(atmel_tdes_dt_ids),
+ },
+ };
+
+-module_platform_driver(atmel_tdes_driver);
++static int __init atmel_tdes_init(void)
++{
++ return platform_driver_probe(&atmel_tdes_driver, atmel_tdes_probe);
++}
++
++static void __exit atmel_tdes_exit(void)
++{
++ platform_driver_unregister(&atmel_tdes_driver);
++}
++
++late_initcall(atmel_tdes_init); /* try to load after dma driver when built-in */
++module_exit(atmel_tdes_exit);
+
+ MODULE_DESCRIPTION("Atmel DES/TDES hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 7e6ef22d45a1c112647e4a671442647f938602a4 Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Tue, 17 Apr 2012 15:00:46 +0800
-Subject: pinctrl: show pin name for pingroups in sysfs
-
-Pin name is more useful to users.
-
-After change, when cat pingroups in sysfs, it becomes:
-root@freescale /sys/kernel/debug/pinctrl/20e0000.iomuxc$ cat pingroups
-registered pin groups:
-group: uart4grp-1
-pin 219 (MX6Q_PAD_KEY_ROW0)
-pin 218 (MX6Q_PAD_KEY_COL0)
-
-group: usdhc4grp-1
-pin 305 (MX6Q_PAD_SD4_CMD)
-pin 306 (MX6Q_PAD_SD4_CLK)
-pin 315 (MX6Q_PAD_SD4_DAT0)
-pin 316 (MX6Q_PAD_SD4_DAT1)
-pin 317 (MX6Q_PAD_SD4_DAT2)
-pin 318 (MX6Q_PAD_SD4_DAT3)
-pin 319 (MX6Q_PAD_SD4_DAT4)
-pin 320 (MX6Q_PAD_SD4_DAT5)
-pin 321 (MX6Q_PAD_SD4_DAT6)
-pin 322 (MX6Q_PAD_SD4_DAT7)
-
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- drivers/pinctrl/core.c | 32 ++++++++++++++++++++++++++++----
- drivers/pinctrl/core.h | 1 +
- 2 files changed, 29 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
-index c70ae2d..5f8a7d2 100644
---- a/drivers/pinctrl/core.c
-+++ b/drivers/pinctrl/core.c
-@@ -141,6 +141,25 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
- }
-
- /**
-+ * pin_get_name_from_id() - look up a pin name from a pin id
-+ * @pctldev: the pin control device to lookup the pin on
-+ * @name: the name of the pin to look up
-+ */
-+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
-+{
-+ const struct pin_desc *desc;
-+
-+ desc = pin_desc_get(pctldev, pin);
-+ if (desc == NULL) {
-+ dev_err(pctldev->dev, "failed to get pin(%d) name\n",
-+ pin);
-+ return NULL;
-+ }
-+
-+ return desc->name;
-+}
-+
-+/**
- * pin_is_valid() - check if pin exists on controller
- * @pctldev: the pin control device to check the pin on
- * @pin: pin to check, use the local pin controller index number
-@@ -1034,6 +1053,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
- const unsigned *pins;
- unsigned num_pins;
- const char *gname = ops->get_group_name(pctldev, selector);
-+ const char *pname;
- int ret;
- int i;
-
-@@ -1043,10 +1063,14 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
- seq_printf(s, "%s [ERROR GETTING PINS]\n",
- gname);
- else {
-- seq_printf(s, "group: %s, pins = [ ", gname);
-- for (i = 0; i < num_pins; i++)
-- seq_printf(s, "%d ", pins[i]);
-- seq_puts(s, "]\n");
-+ seq_printf(s, "group: %s\n", gname);
-+ for (i = 0; i < num_pins; i++) {
-+ pname = pin_get_name(pctldev, pins[i]);
-+ if (WARN_ON(!pname))
-+ return -EINVAL;
-+ seq_printf(s, "pin %d (%s)\n", pins[i], pname);
-+ }
-+ seq_puts(s, "\n");
- }
- selector++;
- }
-diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
-index 98ae808..1f40ff6 100644
---- a/drivers/pinctrl/core.h
-+++ b/drivers/pinctrl/core.h
-@@ -148,6 +148,7 @@ struct pin_desc {
-
- struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
- int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
-+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
- int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
- const char *pin_group);
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 35a5e22b90101fbaf150d1ac05f740da3f840779 Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:17 +0200
+Subject: crypto: Atmel SHA; add device tree support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-sha-regs.h | 7 +-
+ drivers/crypto/atmel-sha.c | 698 ++++++++++++++++++++++++++++++++++------
+ 2 files changed, 608 insertions(+), 97 deletions(-)
+
+diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h
+index dc53a20..83b2d74 100644
+--- a/drivers/crypto/atmel-sha-regs.h
++++ b/drivers/crypto/atmel-sha-regs.h
+@@ -14,10 +14,13 @@
+ #define SHA_MR_MODE_MANUAL 0x0
+ #define SHA_MR_MODE_AUTO 0x1
+ #define SHA_MR_MODE_PDC 0x2
+-#define SHA_MR_DUALBUFF (1 << 3)
+ #define SHA_MR_PROCDLY (1 << 4)
+ #define SHA_MR_ALGO_SHA1 (0 << 8)
+ #define SHA_MR_ALGO_SHA256 (1 << 8)
++#define SHA_MR_ALGO_SHA384 (2 << 8)
++#define SHA_MR_ALGO_SHA512 (3 << 8)
++#define SHA_MR_ALGO_SHA224 (4 << 8)
++#define SHA_MR_DUALBUFF (1 << 16)
+
+ #define SHA_IER 0x10
+ #define SHA_IDR 0x14
+@@ -33,6 +36,8 @@
+ #define SHA_ISR_URAT_MR (0x2 << 12)
+ #define SHA_ISR_URAT_WO (0x5 << 12)
+
++#define SHA_HW_VERSION 0xFC
++
+ #define SHA_TPR 0x108
+ #define SHA_TCR 0x10C
+ #define SHA_TNPR 0x118
+diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
+index f938b9d..f66f1c8 100644
+--- a/drivers/crypto/atmel-sha.c
++++ b/drivers/crypto/atmel-sha.c
+@@ -43,6 +43,9 @@
+ #include <crypto/sha.h>
+ #include <crypto/hash.h>
+ #include <crypto/internal/hash.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_data/atmel-crypto.h>
+ #include "atmel-sha-regs.h"
+
+ /* SHA flags */
+@@ -57,11 +60,12 @@
+ #define SHA_FLAGS_FINUP BIT(16)
+ #define SHA_FLAGS_SG BIT(17)
+ #define SHA_FLAGS_SHA1 BIT(18)
+-#define SHA_FLAGS_SHA256 BIT(19)
+-#define SHA_FLAGS_ERROR BIT(20)
+-#define SHA_FLAGS_PAD BIT(21)
+-
+-#define SHA_FLAGS_DUALBUFF BIT(24)
++#define SHA_FLAGS_SHA224 BIT(19)
++#define SHA_FLAGS_SHA256 BIT(20)
++#define SHA_FLAGS_SHA384 BIT(21)
++#define SHA_FLAGS_SHA512 BIT(22)
++#define SHA_FLAGS_ERROR BIT(23)
++#define SHA_FLAGS_PAD BIT(24)
+
+ #define SHA_OP_UPDATE 1
+ #define SHA_OP_FINAL 2
+@@ -70,6 +74,12 @@
+
+ #define ATMEL_SHA_DMA_THRESHOLD 56
+
++struct atmel_sha_caps {
++ bool has_dma;
++ bool has_dualbuff;
++ bool has_sha224;
++ bool has_sha_384_512;
++};
+
+ struct atmel_sha_dev;
+
+@@ -78,8 +88,8 @@ struct atmel_sha_reqctx {
+ unsigned long flags;
+ unsigned long op;
+
+- u8 digest[SHA256_DIGEST_SIZE] __aligned(sizeof(u32));
+- size_t digcnt;
++ u8 digest[SHA512_DIGEST_SIZE] __aligned(sizeof(u32));
++ u64 digcnt[2];
+ size_t bufcnt;
+ size_t buflen;
+ dma_addr_t dma_addr;
+@@ -89,6 +99,8 @@ struct atmel_sha_reqctx {
+ unsigned int offset; /* offset in current sg */
+ unsigned int total; /* total request */
+
++ size_t block_size;
++
+ u8 buffer[0] __aligned(sizeof(u32));
+ };
+
+@@ -102,7 +114,12 @@ struct atmel_sha_ctx {
+
+ };
+
+-#define ATMEL_SHA_QUEUE_LENGTH 1
++#define ATMEL_SHA_QUEUE_LENGTH 50
++
++struct atmel_sha_dma {
++ struct dma_chan *chan;
++ struct dma_slave_config dma_conf;
++};
+
+ struct atmel_sha_dev {
+ struct list_head list;
+@@ -119,6 +136,12 @@ struct atmel_sha_dev {
+ unsigned long flags;
+ struct crypto_queue queue;
+ struct ahash_request *req;
++
++ struct atmel_sha_dma dma_lch_in;
++
++ struct atmel_sha_caps caps;
++
++ u32 hw_version;
+ };
+
+ struct atmel_sha_drv {
+@@ -142,14 +165,6 @@ static inline void atmel_sha_write(struct atmel_sha_dev *dd,
+ writel_relaxed(value, dd->io_base + offset);
+ }
+
+-static void atmel_sha_dualbuff_test(struct atmel_sha_dev *dd)
+-{
+- atmel_sha_write(dd, SHA_MR, SHA_MR_DUALBUFF);
+-
+- if (atmel_sha_read(dd, SHA_MR) & SHA_MR_DUALBUFF)
+- dd->flags |= SHA_FLAGS_DUALBUFF;
+-}
+-
+ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
+ {
+ size_t count;
+@@ -193,19 +208,40 @@ static size_t atmel_sha_append_sg(struct atmel_sha_reqctx *ctx)
+ static void atmel_sha_fill_padding(struct atmel_sha_reqctx *ctx, int length)
+ {
+ unsigned int index, padlen;
+- u64 bits;
+- u64 size;
+-
+- bits = (ctx->bufcnt + ctx->digcnt + length) << 3;
+- size = cpu_to_be64(bits);
+-
+- index = ctx->bufcnt & 0x3f;
+- padlen = (index < 56) ? (56 - index) : ((64+56) - index);
+- *(ctx->buffer + ctx->bufcnt) = 0x80;
+- memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
+- memcpy(ctx->buffer + ctx->bufcnt + padlen, &size, 8);
+- ctx->bufcnt += padlen + 8;
+- ctx->flags |= SHA_FLAGS_PAD;
++ u64 bits[2];
++ u64 size[2];
++
++ size[0] = ctx->digcnt[0];
++ size[1] = ctx->digcnt[1];
++
++ size[0] += ctx->bufcnt;
++ if (size[0] < ctx->bufcnt)
++ size[1]++;
++
++ size[0] += length;
++ if (size[0] < length)
++ size[1]++;
++
++ bits[1] = cpu_to_be64(size[0] << 3);
++ bits[0] = cpu_to_be64(size[1] << 3 | size[0] >> 61);
++
++ if (ctx->flags & (SHA_FLAGS_SHA384 | SHA_FLAGS_SHA512)) {
++ index = ctx->bufcnt & 0x7f;
++ padlen = (index < 112) ? (112 - index) : ((128+112) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, bits, 16);
++ ctx->bufcnt += padlen + 16;
++ ctx->flags |= SHA_FLAGS_PAD;
++ } else {
++ index = ctx->bufcnt & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
++ *(ctx->buffer + ctx->bufcnt) = 0x80;
++ memset(ctx->buffer + ctx->bufcnt + 1, 0, padlen-1);
++ memcpy(ctx->buffer + ctx->bufcnt + padlen, &bits[1], 8);
++ ctx->bufcnt += padlen + 8;
++ ctx->flags |= SHA_FLAGS_PAD;
++ }
+ }
+
+ static int atmel_sha_init(struct ahash_request *req)
+@@ -236,13 +272,35 @@ static int atmel_sha_init(struct ahash_request *req)
+ dev_dbg(dd->dev, "init: digest size: %d\n",
+ crypto_ahash_digestsize(tfm));
+
+- if (crypto_ahash_digestsize(tfm) == SHA1_DIGEST_SIZE)
++ switch (crypto_ahash_digestsize(tfm)) {
++ case SHA1_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA1;
+- else if (crypto_ahash_digestsize(tfm) == SHA256_DIGEST_SIZE)
++ ctx->block_size = SHA1_BLOCK_SIZE;
++ break;
++ case SHA224_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA224;
++ ctx->block_size = SHA224_BLOCK_SIZE;
++ break;
++ case SHA256_DIGEST_SIZE:
+ ctx->flags |= SHA_FLAGS_SHA256;
++ ctx->block_size = SHA256_BLOCK_SIZE;
++ break;
++ case SHA384_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA384;
++ ctx->block_size = SHA384_BLOCK_SIZE;
++ break;
++ case SHA512_DIGEST_SIZE:
++ ctx->flags |= SHA_FLAGS_SHA512;
++ ctx->block_size = SHA512_BLOCK_SIZE;
++ break;
++ default:
++ return -EINVAL;
++ break;
++ }
+
+ ctx->bufcnt = 0;
+- ctx->digcnt = 0;
++ ctx->digcnt[0] = 0;
++ ctx->digcnt[1] = 0;
+ ctx->buflen = SHA_BUFFER_LEN;
+
+ return 0;
+@@ -254,19 +312,28 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
+ u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
+
+ if (likely(dma)) {
+- atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
++ if (!dd->caps.has_dma)
++ atmel_sha_write(dd, SHA_IER, SHA_INT_TXBUFE);
+ valmr = SHA_MR_MODE_PDC;
+- if (dd->flags & SHA_FLAGS_DUALBUFF)
+- valmr = SHA_MR_DUALBUFF;
++ if (dd->caps.has_dualbuff)
++ valmr |= SHA_MR_DUALBUFF;
+ } else {
+ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
+ }
+
+- if (ctx->flags & SHA_FLAGS_SHA256)
++ if (ctx->flags & SHA_FLAGS_SHA1)
++ valmr |= SHA_MR_ALGO_SHA1;
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ valmr |= SHA_MR_ALGO_SHA224;
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ valmr |= SHA_MR_ALGO_SHA256;
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ valmr |= SHA_MR_ALGO_SHA384;
++ else if (ctx->flags & SHA_FLAGS_SHA512)
++ valmr |= SHA_MR_ALGO_SHA512;
+
+ /* Setting CR_FIRST only for the first iteration */
+- if (!ctx->digcnt)
++ if (!(ctx->digcnt[0] || ctx->digcnt[1]))
+ valcr = SHA_CR_FIRST;
+
+ atmel_sha_write(dd, SHA_CR, valcr);
+@@ -280,13 +347,15 @@ static int atmel_sha_xmit_cpu(struct atmel_sha_dev *dd, const u8 *buf,
+ int count, len32;
+ const u32 *buffer = (const u32 *)buf;
+
+- dev_dbg(dd->dev, "xmit_cpu: digcnt: %d, length: %d, final: %d\n",
+- ctx->digcnt, length, final);
++ dev_dbg(dd->dev, "xmit_cpu: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length, final);
+
+ atmel_sha_write_ctrl(dd, 0);
+
+ /* should be non-zero before next lines to disable clocks later */
+- ctx->digcnt += length;
++ ctx->digcnt[0] += length;
++ if (ctx->digcnt[0] < length)
++ ctx->digcnt[1]++;
+
+ if (final)
+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
+@@ -307,8 +376,8 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
+ int len32;
+
+- dev_dbg(dd->dev, "xmit_pdc: digcnt: %d, length: %d, final: %d\n",
+- ctx->digcnt, length1, final);
++ dev_dbg(dd->dev, "xmit_pdc: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length1, final);
+
+ len32 = DIV_ROUND_UP(length1, sizeof(u32));
+ atmel_sha_write(dd, SHA_PTCR, SHA_PTCR_TXTDIS);
+@@ -322,7 +391,9 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ atmel_sha_write_ctrl(dd, 1);
+
+ /* should be non-zero before next lines to disable clocks later */
+- ctx->digcnt += length1;
++ ctx->digcnt[0] += length1;
++ if (ctx->digcnt[0] < length1)
++ ctx->digcnt[1]++;
+
+ if (final)
+ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
+@@ -335,6 +406,86 @@ static int atmel_sha_xmit_pdc(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
+ return -EINPROGRESS;
+ }
+
++static void atmel_sha_dma_callback(void *data)
++{
++ struct atmel_sha_dev *dd = data;
++
++ /* dma_lch_in - completed - wait DATRDY */
++ atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
++}
++
++static int atmel_sha_xmit_dma(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
++ struct dma_async_tx_descriptor *in_desc;
++ struct scatterlist sg[2];
++
++ dev_dbg(dd->dev, "xmit_dma: digcnt: 0x%llx 0x%llx, length: %d, final: %d\n",
++ ctx->digcnt[1], ctx->digcnt[0], length1, final);
++
++ if (ctx->flags & (SHA_FLAGS_SHA1 | SHA_FLAGS_SHA224 |
++ SHA_FLAGS_SHA256)) {
++ dd->dma_lch_in.dma_conf.src_maxburst = 16;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 16;
++ } else {
++ dd->dma_lch_in.dma_conf.src_maxburst = 32;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 32;
++ }
++
++ dmaengine_slave_config(dd->dma_lch_in.chan, &dd->dma_lch_in.dma_conf);
++
++ if (length2) {
++ sg_init_table(sg, 2);
++ sg_dma_address(&sg[0]) = dma_addr1;
++ sg_dma_len(&sg[0]) = length1;
++ sg_dma_address(&sg[1]) = dma_addr2;
++ sg_dma_len(&sg[1]) = length2;
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 2,
++ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ } else {
++ sg_init_table(sg, 1);
++ sg_dma_address(&sg[0]) = dma_addr1;
++ sg_dma_len(&sg[0]) = length1;
++ in_desc = dmaengine_prep_slave_sg(dd->dma_lch_in.chan, sg, 1,
++ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
++ }
++ if (!in_desc)
++ return -EINVAL;
++
++ in_desc->callback = atmel_sha_dma_callback;
++ in_desc->callback_param = dd;
++
++ atmel_sha_write_ctrl(dd, 1);
++
++ /* should be non-zero before next lines to disable clocks later */
++ ctx->digcnt[0] += length1;
++ if (ctx->digcnt[0] < length1)
++ ctx->digcnt[1]++;
++
++ if (final)
++ dd->flags |= SHA_FLAGS_FINAL; /* catch last interrupt */
++
++ dd->flags |= SHA_FLAGS_DMA_ACTIVE;
++
++ /* Start DMA transfer */
++ dmaengine_submit(in_desc);
++ dma_async_issue_pending(dd->dma_lch_in.chan);
++
++ return -EINPROGRESS;
++}
++
++static int atmel_sha_xmit_start(struct atmel_sha_dev *dd, dma_addr_t dma_addr1,
++ size_t length1, dma_addr_t dma_addr2, size_t length2, int final)
++{
++ if (dd->caps.has_dma)
++ return atmel_sha_xmit_dma(dd, dma_addr1, length1,
++ dma_addr2, length2, final);
++ else
++ return atmel_sha_xmit_pdc(dd, dma_addr1, length1,
++ dma_addr2, length2, final);
++}
++
+ static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
+ {
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
+@@ -342,7 +493,6 @@ static int atmel_sha_update_cpu(struct atmel_sha_dev *dd)
+
+ atmel_sha_append_sg(ctx);
+ atmel_sha_fill_padding(ctx, 0);
+-
+ bufcnt = ctx->bufcnt;
+ ctx->bufcnt = 0;
+
+@@ -354,17 +504,17 @@ static int atmel_sha_xmit_dma_map(struct atmel_sha_dev *dd,
+ size_t length, int final)
+ {
+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
+ dev_err(dd->dev, "dma %u bytes error\n", ctx->buflen +
+- SHA1_BLOCK_SIZE);
++ ctx->block_size);
+ return -EINVAL;
+ }
+
+ ctx->flags &= ~SHA_FLAGS_SG;
+
+ /* next call does not fail... so no unmap in the case of error */
+- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, length, 0, 0, final);
++ return atmel_sha_xmit_start(dd, ctx->dma_addr, length, 0, 0, final);
+ }
+
+ static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
+@@ -377,8 +527,8 @@ static int atmel_sha_update_dma_slow(struct atmel_sha_dev *dd)
+
+ final = (ctx->flags & SHA_FLAGS_FINUP) && !ctx->total;
+
+- dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: %d, final: %d\n",
+- ctx->bufcnt, ctx->digcnt, final);
++ dev_dbg(dd->dev, "slow: bufcnt: %u, digcnt: 0x%llx 0x%llx, final: %d\n",
++ ctx->bufcnt, ctx->digcnt[1], ctx->digcnt[0], final);
+
+ if (final)
+ atmel_sha_fill_padding(ctx, 0);
+@@ -405,30 +555,25 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ if (ctx->bufcnt || ctx->offset)
+ return atmel_sha_update_dma_slow(dd);
+
+- dev_dbg(dd->dev, "fast: digcnt: %d, bufcnt: %u, total: %u\n",
+- ctx->digcnt, ctx->bufcnt, ctx->total);
++ dev_dbg(dd->dev, "fast: digcnt: 0x%llx 0x%llx, bufcnt: %u, total: %u\n",
++ ctx->digcnt[1], ctx->digcnt[0], ctx->bufcnt, ctx->total);
+
+ sg = ctx->sg;
+
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return atmel_sha_update_dma_slow(dd);
+
+- if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, SHA1_BLOCK_SIZE))
+- /* size is not SHA1_BLOCK_SIZE aligned */
++ if (!sg_is_last(sg) && !IS_ALIGNED(sg->length, ctx->block_size))
++ /* size is not ctx->block_size aligned */
+ return atmel_sha_update_dma_slow(dd);
+
+ length = min(ctx->total, sg->length);
+
+ if (sg_is_last(sg)) {
+ if (!(ctx->flags & SHA_FLAGS_FINUP)) {
+- /* not last sg must be SHA1_BLOCK_SIZE aligned */
+- tail = length & (SHA1_BLOCK_SIZE - 1);
++ /* not last sg must be ctx->block_size aligned */
++ tail = length & (ctx->block_size - 1);
+ length -= tail;
+- if (length == 0) {
+- /* offset where to start slow */
+- ctx->offset = length;
+- return atmel_sha_update_dma_slow(dd);
+- }
+ }
+ }
+
+@@ -439,7 +584,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+
+ /* Add padding */
+ if (final) {
+- tail = length & (SHA1_BLOCK_SIZE - 1);
++ tail = length & (ctx->block_size - 1);
+ length -= tail;
+ ctx->total += tail;
+ ctx->offset = length; /* offset where to start slow */
+@@ -450,10 +595,10 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ atmel_sha_fill_padding(ctx, length);
+
+ ctx->dma_addr = dma_map_single(dd->dev, ctx->buffer,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dd->dev, ctx->dma_addr)) {
+ dev_err(dd->dev, "dma %u bytes error\n",
+- ctx->buflen + SHA1_BLOCK_SIZE);
++ ctx->buflen + ctx->block_size);
+ return -EINVAL;
+ }
+
+@@ -461,7 +606,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ ctx->flags &= ~SHA_FLAGS_SG;
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+- return atmel_sha_xmit_pdc(dd, ctx->dma_addr, count, 0,
++ return atmel_sha_xmit_start(dd, ctx->dma_addr, count, 0,
+ 0, final);
+ } else {
+ ctx->sg = sg;
+@@ -475,7 +620,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+
+ count = ctx->bufcnt;
+ ctx->bufcnt = 0;
+- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg),
++ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg),
+ length, ctx->dma_addr, count, final);
+ }
+ }
+@@ -488,7 +633,7 @@ static int atmel_sha_update_dma_start(struct atmel_sha_dev *dd)
+ ctx->flags |= SHA_FLAGS_SG;
+
+ /* next call does not fail... so no unmap in the case of error */
+- return atmel_sha_xmit_pdc(dd, sg_dma_address(ctx->sg), length, 0,
++ return atmel_sha_xmit_start(dd, sg_dma_address(ctx->sg), length, 0,
+ 0, final);
+ }
+
+@@ -503,12 +648,13 @@ static int atmel_sha_update_dma_stop(struct atmel_sha_dev *dd)
+ if (ctx->sg)
+ ctx->offset = 0;
+ }
+- if (ctx->flags & SHA_FLAGS_PAD)
++ if (ctx->flags & SHA_FLAGS_PAD) {
+ dma_unmap_single(dd->dev, ctx->dma_addr,
+- ctx->buflen + SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->buflen + ctx->block_size, DMA_TO_DEVICE);
++ }
+ } else {
+ dma_unmap_single(dd->dev, ctx->dma_addr, ctx->buflen +
+- SHA1_BLOCK_SIZE, DMA_TO_DEVICE);
++ ctx->block_size, DMA_TO_DEVICE);
+ }
+
+ return 0;
+@@ -520,8 +666,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
+ struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
+ int err;
+
+- dev_dbg(dd->dev, "update_req: total: %u, digcnt: %d, finup: %d\n",
+- ctx->total, ctx->digcnt, (ctx->flags & SHA_FLAGS_FINUP) != 0);
++ dev_dbg(dd->dev, "update_req: total: %u, digcnt: 0x%llx 0x%llx\n",
++ ctx->total, ctx->digcnt[1], ctx->digcnt[0]);
+
+ if (ctx->flags & SHA_FLAGS_CPU)
+ err = atmel_sha_update_cpu(dd);
+@@ -529,8 +675,8 @@ static int atmel_sha_update_req(struct atmel_sha_dev *dd)
+ err = atmel_sha_update_dma_start(dd);
+
+ /* wait for dma completion before can take more data */
+- dev_dbg(dd->dev, "update: err: %d, digcnt: %d\n",
+- err, ctx->digcnt);
++ dev_dbg(dd->dev, "update: err: %d, digcnt: 0x%llx 0%llx\n",
++ err, ctx->digcnt[1], ctx->digcnt[0]);
+
+ return err;
+ }
+@@ -567,12 +713,21 @@ static void atmel_sha_copy_hash(struct ahash_request *req)
+ u32 *hash = (u32 *)ctx->digest;
+ int i;
+
+- if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ if (ctx->flags & SHA_FLAGS_SHA1)
+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+- else
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
+ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
++ else
++ for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++)
++ hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
+ }
+
+ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
+@@ -582,10 +737,16 @@ static void atmel_sha_copy_ready_hash(struct ahash_request *req)
+ if (!req->result)
+ return;
+
+- if (likely(ctx->flags & SHA_FLAGS_SHA1))
++ if (ctx->flags & SHA_FLAGS_SHA1)
+ memcpy(req->result, ctx->digest, SHA1_DIGEST_SIZE);
+- else
++ else if (ctx->flags & SHA_FLAGS_SHA224)
++ memcpy(req->result, ctx->digest, SHA224_DIGEST_SIZE);
++ else if (ctx->flags & SHA_FLAGS_SHA256)
+ memcpy(req->result, ctx->digest, SHA256_DIGEST_SIZE);
++ else if (ctx->flags & SHA_FLAGS_SHA384)
++ memcpy(req->result, ctx->digest, SHA384_DIGEST_SIZE);
++ else
++ memcpy(req->result, ctx->digest, SHA512_DIGEST_SIZE);
+ }
+
+ static int atmel_sha_finish(struct ahash_request *req)
+@@ -594,11 +755,11 @@ static int atmel_sha_finish(struct ahash_request *req)
+ struct atmel_sha_dev *dd = ctx->dd;
+ int err = 0;
+
+- if (ctx->digcnt)
++ if (ctx->digcnt[0] || ctx->digcnt[1])
+ atmel_sha_copy_ready_hash(req);
+
+- dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt,
+- ctx->bufcnt);
++ dev_dbg(dd->dev, "digcnt: 0x%llx 0x%llx, bufcnt: %d\n", ctx->digcnt[1],
++ ctx->digcnt[0], ctx->bufcnt);
+
+ return err;
+ }
+@@ -633,9 +794,8 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
+ {
+ clk_prepare_enable(dd->iclk);
+
+- if (SHA_FLAGS_INIT & dd->flags) {
++ if (!(SHA_FLAGS_INIT & dd->flags)) {
+ atmel_sha_write(dd, SHA_CR, SHA_CR_SWRST);
+- atmel_sha_dualbuff_test(dd);
+ dd->flags |= SHA_FLAGS_INIT;
+ dd->err = 0;
+ }
+@@ -643,6 +803,23 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd)
+ return 0;
+ }
+
++static inline unsigned int atmel_sha_get_version(struct atmel_sha_dev *dd)
++{
++ return atmel_sha_read(dd, SHA_HW_VERSION) & 0x00000fff;
++}
++
++static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd)
++{
++ atmel_sha_hw_init(dd);
++
++ dd->hw_version = atmel_sha_get_version(dd);
++
++ dev_info(dd->dev,
++ "version: 0x%x\n", dd->hw_version);
++
++ clk_disable_unprepare(dd->iclk);
++}
++
+ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
+ struct ahash_request *req)
+ {
+@@ -687,10 +864,9 @@ static int atmel_sha_handle_queue(struct atmel_sha_dev *dd,
+
+ if (ctx->op == SHA_OP_UPDATE) {
+ err = atmel_sha_update_req(dd);
+- if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP)) {
++ if (err != -EINPROGRESS && (ctx->flags & SHA_FLAGS_FINUP))
+ /* no final() after finup() */
+ err = atmel_sha_final_req(dd);
+- }
+ } else if (ctx->op == SHA_OP_FINAL) {
+ err = atmel_sha_final_req(dd);
+ }
+@@ -813,7 +989,7 @@ static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
+ }
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct atmel_sha_reqctx) +
+- SHA_BUFFER_LEN + SHA256_BLOCK_SIZE);
++ SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
+
+ return 0;
+ }
+@@ -831,7 +1007,7 @@ static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
+ tctx->fallback = NULL;
+ }
+
+-static struct ahash_alg sha_algs[] = {
++static struct ahash_alg sha_1_256_algs[] = {
+ {
+ .init = atmel_sha_init,
+ .update = atmel_sha_update,
+@@ -880,6 +1056,79 @@ static struct ahash_alg sha_algs[] = {
+ },
+ };
+
++static struct ahash_alg sha_224_alg = {
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA224_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha224",
++ .cra_driver_name = "atmel-sha224",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA224_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++};
++
++static struct ahash_alg sha_384_512_algs[] = {
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA384_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha384",
++ .cra_driver_name = "atmel-sha384",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA384_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0x3,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++{
++ .init = atmel_sha_init,
++ .update = atmel_sha_update,
++ .final = atmel_sha_final,
++ .finup = atmel_sha_finup,
++ .digest = atmel_sha_digest,
++ .halg = {
++ .digestsize = SHA512_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha512",
++ .cra_driver_name = "atmel-sha512",
++ .cra_priority = 100,
++ .cra_flags = CRYPTO_ALG_ASYNC |
++ CRYPTO_ALG_NEED_FALLBACK,
++ .cra_blocksize = SHA512_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct atmel_sha_ctx),
++ .cra_alignmask = 0x3,
++ .cra_module = THIS_MODULE,
++ .cra_init = atmel_sha_cra_init,
++ .cra_exit = atmel_sha_cra_exit,
++ }
++ }
++},
++};
++
+ static void atmel_sha_done_task(unsigned long data)
+ {
+ struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data;
+@@ -946,32 +1195,251 @@ static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd)
+ {
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(sha_algs); i++)
+- crypto_unregister_ahash(&sha_algs[i]);
++ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++)
++ crypto_unregister_ahash(&sha_1_256_algs[i]);
++
++ if (dd->caps.has_sha224)
++ crypto_unregister_ahash(&sha_224_alg);
++
++ if (dd->caps.has_sha_384_512) {
++ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++)
++ crypto_unregister_ahash(&sha_384_512_algs[i]);
++ }
+ }
+
+ static int atmel_sha_register_algs(struct atmel_sha_dev *dd)
+ {
+ int err, i, j;
+
+- for (i = 0; i < ARRAY_SIZE(sha_algs); i++) {
+- err = crypto_register_ahash(&sha_algs[i]);
++ for (i = 0; i < ARRAY_SIZE(sha_1_256_algs); i++) {
++ err = crypto_register_ahash(&sha_1_256_algs[i]);
+ if (err)
+- goto err_sha_algs;
++ goto err_sha_1_256_algs;
++ }
++
++ if (dd->caps.has_sha224) {
++ err = crypto_register_ahash(&sha_224_alg);
++ if (err)
++ goto err_sha_224_algs;
++ }
++
++ if (dd->caps.has_sha_384_512) {
++ for (i = 0; i < ARRAY_SIZE(sha_384_512_algs); i++) {
++ err = crypto_register_ahash(&sha_384_512_algs[i]);
++ if (err)
++ goto err_sha_384_512_algs;
++ }
+ }
+
+ return 0;
+
+-err_sha_algs:
++err_sha_384_512_algs:
++ for (j = 0; j < i; j++)
++ crypto_unregister_ahash(&sha_384_512_algs[j]);
++ crypto_unregister_ahash(&sha_224_alg);
++err_sha_224_algs:
++ i = ARRAY_SIZE(sha_1_256_algs);
++err_sha_1_256_algs:
+ for (j = 0; j < i; j++)
+- crypto_unregister_ahash(&sha_algs[j]);
++ crypto_unregister_ahash(&sha_1_256_algs[j]);
+
+ return err;
+ }
+
++static bool atmel_sha_filter(struct dma_chan *chan, void *slave)
++{
++ struct at_dma_slave *sl = slave;
++
++ if (sl && sl->dma_dev == chan->device->dev) {
++ chan->private = sl;
++ return true;
++ } else {
++ return false;
++ }
++}
++
++static int atmel_sha_dma_init(struct atmel_sha_dev *dd,
++ struct crypto_platform_data *pdata)
++{
++ int err = -ENOMEM;
++ dma_cap_mask_t mask_in;
++
++ if (pdata && pdata->dma_slave->rxdata.dma_dev) {
++ /* Try to grab DMA channel */
++ dma_cap_zero(mask_in);
++ dma_cap_set(DMA_SLAVE, mask_in);
++
++ dd->dma_lch_in.chan = dma_request_channel(mask_in,
++ atmel_sha_filter, &pdata->dma_slave->rxdata);
++
++ if (!dd->dma_lch_in.chan)
++ return err;
++
++ dd->dma_lch_in.dma_conf.direction = DMA_MEM_TO_DEV;
++ dd->dma_lch_in.dma_conf.dst_addr = dd->phys_base +
++ SHA_REG_DIN(0);
++ dd->dma_lch_in.dma_conf.src_maxburst = 1;
++ dd->dma_lch_in.dma_conf.src_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.dst_maxburst = 1;
++ dd->dma_lch_in.dma_conf.dst_addr_width =
++ DMA_SLAVE_BUSWIDTH_4_BYTES;
++ dd->dma_lch_in.dma_conf.device_fc = false;
++
++ return 0;
++ }
++
++ return -ENODEV;
++}
++
++static void atmel_sha_dma_cleanup(struct atmel_sha_dev *dd)
++{
++ dma_release_channel(dd->dma_lch_in.chan);
++}
++
++
++#ifdef CONFIG_OF
++static const struct of_device_id atmel_sha_dt_ids[] = {
++ { .compatible = "atmel,sam9g46-sha" },
++ { /* sentinel */ }
++};
++
++MODULE_DEVICE_TABLE(of, atmel_sha_dt_ids);
++
++static int atmel_sha_dma_of_init(struct device_node *np,
++ struct at_dma_slave *atslave)
++{
++ struct of_phandle_args dma_spec;
++ struct device_node *dmac_np;
++ struct platform_device *dmac_pdev;
++ const __be32 *nbcells;
++ int ret;
++
++ ret = of_parse_phandle_with_args(np, "dma", "#dma-cells", 0, &dma_spec);
++ if (ret || !dma_spec.np) {
++ pr_err("%s: can't parse dma property (%d)\n",
++ np->full_name, ret);
++ goto err0;
++ }
++ dmac_np = dma_spec.np;
++
++ /* check property format */
++ nbcells = of_get_property(dmac_np, "#dma-cells", NULL);
++ if (!nbcells) {
++ pr_err("%s: #dma-cells property is required\n", np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ if (dma_spec.args_count != be32_to_cpup(nbcells)
++ || dma_spec.args_count != 1) {
++ pr_err("%s: wrong #dma-cells for %s\n",
++ np->full_name, dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* retreive DMA controller information */
++ dmac_pdev = of_find_device_by_node(dmac_np);
++ if (!dmac_pdev) {
++ pr_err("%s: unable to find pdev from DMA controller\n",
++ dmac_np->full_name);
++ ret = -EINVAL;
++ goto err1;
++ }
++
++ /* now fill in the at_dma_slave structure */
++ atslave->dma_dev = &dmac_pdev->dev;
++ atslave->cfg = dma_spec.args[0];
++
++err1:
++ of_node_put(dma_spec.np);
++err0:
++ pr_debug("%s exited with status %d\n", __func__, ret);
++ return ret;
++}
++
++
++static struct crypto_platform_data __devinit*
++atmel_sha_of_init(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct crypto_platform_data *pdata;
++ struct at_dma_slave *atslave;
++
++ if (!np) {
++ dev_err(&pdev->dev, "device node not found\n");
++ return ERR_PTR(-EINVAL);
++ }
++
++ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
++ if (!pdata) {
++ dev_err(&pdev->dev, "could not allocate memory for pdata\n");
++ return ERR_PTR(-ENOMEM);
++ }
++
++ pdata->dma_slave = devm_kzalloc(&pdev->dev,
++ sizeof(*(pdata->dma_slave)),
++ GFP_KERNEL);
++ if (!pdata->dma_slave) {
++ dev_err(&pdev->dev, "could not allocate memory for dma_slave\n");
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ atslave = &pdata->dma_slave->rxdata;
++ /* retrieve RX DMA configuration first */
++ if (atmel_sha_dma_of_init(np, atslave)) {
++ dev_err(&pdev->dev, "could not find RX DMA parameters\n");
++ devm_kfree(&pdev->dev, pdata->dma_slave);
++ devm_kfree(&pdev->dev, pdata);
++ return ERR_PTR(-EINVAL);
++ }
++
++ return pdata;
++}
++#else /* CONFIG_OF */
++static inline struct crypto_platform_data*
++atmel_sha_of_init(struct platform_device *dev)
++{
++ return ERR_PTR(-EINVAL);
++}
++#endif
++
++static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
++{
++
++ dd->caps.has_dma = 0;
++ dd->caps.has_dualbuff = 0;
++ dd->caps.has_sha224 = 0;
++ dd->caps.has_sha_384_512 = 0;
++
++ /* keep only major version number */
++ switch (dd->hw_version & 0xff0) {
++ case 0x410:
++ dd->caps.has_dma = 1;
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_sha224 = 1;
++ dd->caps.has_sha_384_512 = 1;
++ break;
++ case 0x400:
++ dd->caps.has_dma = 1;
++ dd->caps.has_dualbuff = 1;
++ dd->caps.has_sha224 = 1;
++ break;
++ case 0x320:
++ break;
++ default:
++ dev_warn(dd->dev,
++ "Unmanaged sha version, set minimum capabilities\n");
++ break;
++ }
++}
++
+ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ {
+ struct atmel_sha_dev *sha_dd;
++ struct crypto_platform_data *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *sha_res;
+ unsigned long sha_phys_size;
+@@ -1023,7 +1491,7 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ }
+
+ /* Initializing the clock */
+- sha_dd->iclk = clk_get(&pdev->dev, NULL);
++ sha_dd->iclk = clk_get(&pdev->dev, "sha_clk");
+ if (IS_ERR(sha_dd->iclk)) {
+ dev_err(dev, "clock intialization failed.\n");
+ err = PTR_ERR(sha_dd->iclk);
+@@ -1037,6 +1505,24 @@ static int __devinit atmel_sha_probe(struct platform_device *pdev)
+ goto sha_io_err;
+ }
+
++ atmel_sha_hw_version_init(sha_dd);
++
++ atmel_sha_get_cap(sha_dd);
++
++ if (sha_dd->caps.has_dma) {
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ pdata = atmel_sha_of_init(pdev);
++ if (IS_ERR(pdata)) {
++ dev_err(&pdev->dev, "platform data not available\n");
++ goto err_pdata;
++ }
++ }
++ err = atmel_sha_dma_init(sha_dd, pdata);
++ if (err)
++ goto err_sha_dma;
++ }
++
+ spin_lock(&atmel_sha.lock);
+ list_add_tail(&sha_dd->list, &atmel_sha.dev_list);
+ spin_unlock(&atmel_sha.lock);
+@@ -1053,6 +1539,10 @@ err_algs:
+ spin_lock(&atmel_sha.lock);
+ list_del(&sha_dd->list);
+ spin_unlock(&atmel_sha.lock);
++ if (sha_dd->caps.has_dma)
++ atmel_sha_dma_cleanup(sha_dd);
++err_sha_dma:
++err_pdata:
+ iounmap(sha_dd->io_base);
+ sha_io_err:
+ clk_put(sha_dd->iclk);
+@@ -1083,6 +1573,9 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
+
+ tasklet_kill(&sha_dd->done_task);
+
++ if (sha_dd->caps.has_dma)
++ atmel_sha_dma_cleanup(sha_dd);
++
+ iounmap(sha_dd->io_base);
+
+ clk_put(sha_dd->iclk);
+@@ -1097,15 +1590,28 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
+ }
+
+ static struct platform_driver atmel_sha_driver = {
+- .probe = atmel_sha_probe,
+ .remove = __devexit_p(atmel_sha_remove),
+ .driver = {
+ .name = "atmel_sha",
++ .of_match_table = of_match_ptr(atmel_sha_dt_ids),
+ .owner = THIS_MODULE,
+ },
+ };
+
+-module_platform_driver(atmel_sha_driver);
++static int __init atmel_sha_drv_init(void)
++{
++ return platform_driver_probe(&atmel_sha_driver, atmel_sha_probe);
++}
++
++static void __exit atmel_sha_drv_exit(void)
++{
++ platform_driver_unregister(&atmel_sha_driver);
++}
++
++/* try to load after dma driver when built-in */
++late_initcall(atmel_sha_drv_init);
++module_exit(atmel_sha_drv_exit);
++
+
+ MODULE_DESCRIPTION("Atmel SHA1/SHA256 hw acceleration support.");
+ MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From bbc91a68271eb2285968c7f68f8325d781d1e3b0 Mon Sep 17 00:00:00 2001
-From: Dong Aisheng <dong.aisheng@linaro.org>
-Date: Fri, 27 Apr 2012 11:36:20 +0800
-Subject: dt: add of_get_child_count helper function
-
-Currently most code to get child count in kernel are almost same,
-add a helper to implement this function for dt to use.
-
-Cc: Grant Likely <grant.likely@secretlab.ca>
-Acked-by: Rob Herring <rob.herring@calxeda.com>
-Acked-by: Stephen Warren <swarren@wwwdotorg.org>
-Signed-off-by: Dong Aisheng <dong.aisheng@linaro.org>
-Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
----
- include/linux/of.h | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
---- a/include/linux/of.h
-+++ b/include/linux/of.h
-@@ -194,6 +194,17 @@ extern struct device_node *of_get_next_c
- for (child = of_get_next_child(parent, NULL); child != NULL; \
- child = of_get_next_child(parent, child))
-
-+static inline int of_get_child_count(const struct device_node *np)
-+{
-+ struct device_node *child;
-+ int num = 0;
-+
-+ for_each_child_of_node(np, child)
-+ num++;
-+
-+ return num;
-+}
-+
- extern struct device_node *of_find_node_with_property(
- struct device_node *from, const char *prop_name);
- #define for_each_node_with_property(dn, prop_name) \
-@@ -306,6 +317,11 @@ static inline bool of_have_populated_dt(
- #define for_each_child_of_node(parent, child) \
- while (0)
-
-+static inline int of_get_child_count(const struct device_node *np)
-+{
-+ return 0;
-+}
-+
- static inline int of_device_is_compatible(const struct device_node *device,
- const char *name)
- {
+++ /dev/null
-From f0e343643120ab803373244ed2996b9dd169a850 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Thu, 16 Aug 2012 17:36:55 +0800
-Subject: arm: at91: use macro to declare soc boot data
-
-Instead of check the pointer of the init function, check the new builtin bool
-to known if the soc is enabled.
-
-This is needed as with the switch to the pinctrl the init will be NULL on pure
-DT SoC.
-
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/mach-at91/at91rm9200.c | 4 ++--
- arch/arm/mach-at91/at91sam9260.c | 4 ++--
- arch/arm/mach-at91/at91sam9261.c | 4 ++--
- arch/arm/mach-at91/at91sam9263.c | 4 ++--
- arch/arm/mach-at91/at91sam9g45.c | 4 ++--
- arch/arm/mach-at91/at91sam9n12.c | 4 ++--
- arch/arm/mach-at91/at91sam9rl.c | 4 ++--
- arch/arm/mach-at91/at91sam9x5.c | 4 ++--
- arch/arm/mach-at91/soc.h | 12 +++++++++++-
- 9 files changed, 27 insertions(+), 17 deletions(-)
-
-diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
-index b4f0565..a454734 100644
---- a/arch/arm/mach-at91/at91rm9200.c
-+++ b/arch/arm/mach-at91/at91rm9200.c
-@@ -361,10 +361,10 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0 /* Advanced Interrupt Controller (IRQ6) */
- };
-
--struct at91_init_soc __initdata at91rm9200_soc = {
-+AT91_SOC_START(rm9200)
- .map_io = at91rm9200_map_io,
- .default_irq_priority = at91rm9200_default_irq_priority,
- .ioremap_registers = at91rm9200_ioremap_registers,
- .register_clocks = at91rm9200_register_clocks,
- .init = at91rm9200_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index 040f79a..bb9bc50 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -383,10 +383,10 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0, /* Advanced Interrupt Controller */
- };
-
--struct at91_init_soc __initdata at91sam9260_soc = {
-+AT91_SOC_START(sam9260)
- .map_io = at91sam9260_map_io,
- .default_irq_priority = at91sam9260_default_irq_priority,
- .ioremap_registers = at91sam9260_ioremap_registers,
- .register_clocks = at91sam9260_register_clocks,
- .init = at91sam9260_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
-index 8d999eb..93a24e9 100644
---- a/arch/arm/mach-at91/at91sam9261.c
-+++ b/arch/arm/mach-at91/at91sam9261.c
-@@ -334,10 +334,10 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0, /* Advanced Interrupt Controller */
- };
-
--struct at91_init_soc __initdata at91sam9261_soc = {
-+AT91_SOC_START(sam9261)
- .map_io = at91sam9261_map_io,
- .default_irq_priority = at91sam9261_default_irq_priority,
- .ioremap_registers = at91sam9261_ioremap_registers,
- .register_clocks = at91sam9261_register_clocks,
- .init = at91sam9261_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index 00723ec..76499a6 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -367,10 +367,10 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0, /* Advanced Interrupt Controller (IRQ1) */
- };
-
--struct at91_init_soc __initdata at91sam9263_soc = {
-+AT91_SOC_START(sam9263)
- .map_io = at91sam9263_map_io,
- .default_irq_priority = at91sam9263_default_irq_priority,
- .ioremap_registers = at91sam9263_ioremap_registers,
- .register_clocks = at91sam9263_register_clocks,
- .init = at91sam9263_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index 4b791bf..5e7a1dd 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -405,10 +405,10 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0, /* Advanced Interrupt Controller (IRQ0) */
- };
-
--struct at91_init_soc __initdata at91sam9g45_soc = {
-+AT91_SOC_START(sam9g45)
- .map_io = at91sam9g45_map_io,
- .default_irq_priority = at91sam9g45_default_irq_priority,
- .ioremap_registers = at91sam9g45_ioremap_registers,
- .register_clocks = at91sam9g45_register_clocks,
- .init = at91sam9g45_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
-index d09baf1..6fa0df1 100644
---- a/arch/arm/mach-at91/at91sam9n12.c
-+++ b/arch/arm/mach-at91/at91sam9n12.c
-@@ -246,8 +246,8 @@ void __init at91sam9n12_initialize(void)
- at91_gpio_init(NULL, 0);
- }
-
--struct at91_init_soc __initdata at91sam9n12_soc = {
-+AT91_SOC_START(sam9n12)
- .map_io = at91sam9n12_map_io,
- .register_clocks = at91sam9n12_register_clocks,
- .init = at91sam9n12_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
-index 72e9084..cbe72e4 100644
---- a/arch/arm/mach-at91/at91sam9rl.c
-+++ b/arch/arm/mach-at91/at91sam9rl.c
-@@ -338,10 +338,10 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 0, /* Advanced Interrupt Controller */
- };
-
--struct at91_init_soc __initdata at91sam9rl_soc = {
-+AT91_SOC_START(sam9rl)
- .map_io = at91sam9rl_map_io,
- .default_irq_priority = at91sam9rl_default_irq_priority,
- .ioremap_registers = at91sam9rl_ioremap_registers,
- .register_clocks = at91sam9rl_register_clocks,
- .init = at91sam9rl_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index f40c1ab..af00de4 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -323,8 +323,8 @@ void __init at91sam9x5_initialize(void)
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
--struct at91_init_soc __initdata at91sam9x5_soc = {
-+AT91_SOC_START(sam9x5)
- .map_io = at91sam9x5_map_io,
- .register_clocks = at91sam9x5_register_clocks,
- .init = at91sam9x5_initialize,
--};
-+AT91_SOC_END
-diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
-index a9cfeb1..9c6d3d4 100644
---- a/arch/arm/mach-at91/soc.h
-+++ b/arch/arm/mach-at91/soc.h
-@@ -5,6 +5,7 @@
- */
-
- struct at91_init_soc {
-+ int builtin;
- unsigned int *default_irq_priority;
- void (*map_io)(void);
- void (*ioremap_registers)(void);
-@@ -22,9 +23,18 @@ extern struct at91_init_soc at91sam9rl_soc;
- extern struct at91_init_soc at91sam9x5_soc;
- extern struct at91_init_soc at91sam9n12_soc;
-
-+#define AT91_SOC_START(_name) \
-+struct at91_init_soc __initdata at91##_name##_soc \
-+ __used \
-+ = { \
-+ .builtin = 1, \
-+
-+#define AT91_SOC_END \
-+};
-+
- static inline int at91_soc_is_enabled(void)
- {
-- return at91_boot_soc.init != NULL;
-+ return at91_boot_soc.builtin;
- }
-
- #if !defined(CONFIG_SOC_AT91RM9200)
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From a025a84b58085328fc8a963088c70cb00ada2bae Mon Sep 17 00:00:00 2001
+From: Nicolas Royer <nicolas@eukrea.com>
+Date: Mon, 17 Sep 2012 18:26:18 +0200
+Subject: crypto: Atmel Test; add SHA224, SHA384 and SHA512 support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Nicolas Royer <nicolas@eukrea.com>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Eric Bénard <eric@eukrea.com>
+Tested-by: Eric Bénard <eric@eukrea.com>
+---
+ drivers/crypto/atmel-test.c | 25 +++++++++++++++++++------
+ 1 file changed, 19 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/crypto/atmel-test.c b/drivers/crypto/atmel-test.c
+index 4a23db5..d9eb80d 100644
+--- a/drivers/crypto/atmel-test.c
++++ b/drivers/crypto/atmel-test.c
+@@ -41,7 +41,11 @@ static char *iv16 =
+
+ #define SHA1_MSG_LEN 20
+ #define SHA256_MSG_LEN 32
+-static char sha_out_buf[SHA256_MSG_LEN];
++#define SHA224_MSG_LEN 28
++#define SHA384_MSG_LEN 48
++#define SHA512_MSG_LEN 64
++
++static char sha_out_buf[SHA512_MSG_LEN];
+
+ #define TVMEMSIZE 4
+ static char *tvmem[TVMEMSIZE];
+@@ -331,7 +335,7 @@ static int dlen = 64;
+ module_param_named(dlen, dlen, int,
+ S_IRUGO | S_IWUSR | S_IWGRP);
+
+-char *ahash_algs[] = {"sha1", "sha256"};
++char *ahash_algs[] = {"sha1", "sha256", "sha224", "sha384", "sha512"};
+
+ char *acipher_algs[] = {
+ "ecb(des)", "cbc(des)", "cfb(des)", "cfb32(des)",
+@@ -347,6 +351,7 @@ static int __init init_main(void)
+ char *buf_in;
+ char *buf_out;
+ char *buf_res;
++ size_t outlen;
+
+ if ((dlen <= 0) || (dlen > TVMEMSIZE*PAGE_SIZE)) {
+ printk(KERN_ERR " 0 < dlen <= %i\n",
+@@ -382,15 +387,23 @@ static int __init init_main(void)
+ ARRAY_SIZE(ahash_algs));
+ goto exit;
+ }
++ switch (mode) {
++ case 0:outlen = SHA1_MSG_LEN; break;
++ case 1:outlen = SHA256_MSG_LEN; break;
++ case 2:outlen = SHA224_MSG_LEN; break;
++ case 3:outlen = SHA384_MSG_LEN; break;
++ case 4:outlen = SHA512_MSG_LEN; break;
++ }
++
+ printk(KERN_INFO "\n%s digest_req\n", ahash_algs[mode]);
+ hmac_sha_digest(ahash_algs[mode], buf_in, dlen, sha_out_buf,
+- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
+- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ outlen);
++ hexdump(sha_out_buf, outlen);
+
+ printk(KERN_INFO "\n%s update_req\n", ahash_algs[mode]);
+ hmac_sha_update(ahash_algs[mode], buf_in, dlen, sha_out_buf,
+- mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
+- hexdump(sha_out_buf, mode ? SHA256_MSG_LEN : SHA1_MSG_LEN);
++ outlen);
++ hexdump(sha_out_buf, outlen);
+ } else {
+ mode -= 10;
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 0fac5d6d7ef4c0cd717f58efa59df743cb5621a4 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Fri, 6 Jul 2012 06:48:33 +0800
-Subject: ARM: at91: gpio: implement request
-
-Configure the pin as pio when requested.
-
-It is needed to configure the pin as PIO at "request time" when we are
-using DT. Indeed, the muxing via old AT91 API is not allowed anymore if
-we are using the plain gpiolib.
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/mach-at91/gpio.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
-index be42cf0..3b8f463 100644
---- a/arch/arm/mach-at91/gpio.c
-+++ b/arch/arm/mach-at91/gpio.c
-@@ -46,6 +46,7 @@ struct at91_gpio_chip {
-
- #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
-
-+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
- static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
- static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
- static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
-@@ -59,6 +60,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
- { \
- .chip = { \
- .label = name, \
-+ .request = at91_gpiolib_request, \
- .direction_input = at91_gpiolib_direction_input, \
- .direction_output = at91_gpiolib_direction_output, \
- .get = at91_gpiolib_get, \
-@@ -862,6 +864,16 @@ void __init at91_gpio_irq_setup(void)
- }
-
- /* gpiolib support */
-+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << offset;
-+
-+ __raw_writel(mask, pio + PIO_PER);
-+ return 0;
-+}
-+
- static int at91_gpiolib_direction_input(struct gpio_chip *chip,
- unsigned offset)
- {
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 72689543bfd43fa0c87169fdd66c4e17deb6309d Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 16 Aug 2012 17:36:55 +0800
+Subject: arm: at91: use macro to declare soc boot data
+
+Instead of check the pointer of the init function, check the new builtin bool
+to known if the soc is enabled.
+
+This is needed as with the switch to the pinctrl the init will be NULL on pure
+DT SoC.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/at91rm9200.c | 4 ++--
+ arch/arm/mach-at91/at91sam9260.c | 4 ++--
+ arch/arm/mach-at91/at91sam9261.c | 4 ++--
+ arch/arm/mach-at91/at91sam9263.c | 4 ++--
+ arch/arm/mach-at91/at91sam9g45.c | 4 ++--
+ arch/arm/mach-at91/at91sam9n12.c | 4 ++--
+ arch/arm/mach-at91/at91sam9rl.c | 4 ++--
+ arch/arm/mach-at91/at91sam9x5.c | 4 ++--
+ arch/arm/mach-at91/soc.h | 12 +++++++++++-
+ 9 files changed, 27 insertions(+), 17 deletions(-)
+
+diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
+index b4f0565..a454734 100644
+--- a/arch/arm/mach-at91/at91rm9200.c
++++ b/arch/arm/mach-at91/at91rm9200.c
+@@ -361,10 +361,10 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0 /* Advanced Interrupt Controller (IRQ6) */
+ };
+
+-struct at91_init_soc __initdata at91rm9200_soc = {
++AT91_SOC_START(rm9200)
+ .map_io = at91rm9200_map_io,
+ .default_irq_priority = at91rm9200_default_irq_priority,
+ .ioremap_registers = at91rm9200_ioremap_registers,
+ .register_clocks = at91rm9200_register_clocks,
+ .init = at91rm9200_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index 040f79a..bb9bc50 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -383,10 +383,10 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9260_soc = {
++AT91_SOC_START(sam9260)
+ .map_io = at91sam9260_map_io,
+ .default_irq_priority = at91sam9260_default_irq_priority,
+ .ioremap_registers = at91sam9260_ioremap_registers,
+ .register_clocks = at91sam9260_register_clocks,
+ .init = at91sam9260_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
+index 8d999eb..93a24e9 100644
+--- a/arch/arm/mach-at91/at91sam9261.c
++++ b/arch/arm/mach-at91/at91sam9261.c
+@@ -334,10 +334,10 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9261_soc = {
++AT91_SOC_START(sam9261)
+ .map_io = at91sam9261_map_io,
+ .default_irq_priority = at91sam9261_default_irq_priority,
+ .ioremap_registers = at91sam9261_ioremap_registers,
+ .register_clocks = at91sam9261_register_clocks,
+ .init = at91sam9261_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 00723ec..76499a6 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -367,10 +367,10 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller (IRQ1) */
+ };
+
+-struct at91_init_soc __initdata at91sam9263_soc = {
++AT91_SOC_START(sam9263)
+ .map_io = at91sam9263_map_io,
+ .default_irq_priority = at91sam9263_default_irq_priority,
+ .ioremap_registers = at91sam9263_ioremap_registers,
+ .register_clocks = at91sam9263_register_clocks,
+ .init = at91sam9263_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 4b791bf..5e7a1dd 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -405,10 +405,10 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+ };
+
+-struct at91_init_soc __initdata at91sam9g45_soc = {
++AT91_SOC_START(sam9g45)
+ .map_io = at91sam9g45_map_io,
+ .default_irq_priority = at91sam9g45_default_irq_priority,
+ .ioremap_registers = at91sam9g45_ioremap_registers,
+ .register_clocks = at91sam9g45_register_clocks,
+ .init = at91sam9g45_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index d09baf1..6fa0df1 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -246,8 +246,8 @@ void __init at91sam9n12_initialize(void)
+ at91_gpio_init(NULL, 0);
+ }
+
+-struct at91_init_soc __initdata at91sam9n12_soc = {
++AT91_SOC_START(sam9n12)
+ .map_io = at91sam9n12_map_io,
+ .register_clocks = at91sam9n12_register_clocks,
+ .init = at91sam9n12_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
+index 72e9084..cbe72e4 100644
+--- a/arch/arm/mach-at91/at91sam9rl.c
++++ b/arch/arm/mach-at91/at91sam9rl.c
+@@ -338,10 +338,10 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 0, /* Advanced Interrupt Controller */
+ };
+
+-struct at91_init_soc __initdata at91sam9rl_soc = {
++AT91_SOC_START(sam9rl)
+ .map_io = at91sam9rl_map_io,
+ .default_irq_priority = at91sam9rl_default_irq_priority,
+ .ioremap_registers = at91sam9rl_ioremap_registers,
+ .register_clocks = at91sam9rl_register_clocks,
+ .init = at91sam9rl_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index f40c1ab..af00de4 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -323,8 +323,8 @@ void __init at91sam9x5_initialize(void)
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+-struct at91_init_soc __initdata at91sam9x5_soc = {
++AT91_SOC_START(sam9x5)
+ .map_io = at91sam9x5_map_io,
+ .register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
+-};
++AT91_SOC_END
+diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
+index a9cfeb1..9c6d3d4 100644
+--- a/arch/arm/mach-at91/soc.h
++++ b/arch/arm/mach-at91/soc.h
+@@ -5,6 +5,7 @@
+ */
+
+ struct at91_init_soc {
++ int builtin;
+ unsigned int *default_irq_priority;
+ void (*map_io)(void);
+ void (*ioremap_registers)(void);
+@@ -22,9 +23,18 @@ extern struct at91_init_soc at91sam9rl_soc;
+ extern struct at91_init_soc at91sam9x5_soc;
+ extern struct at91_init_soc at91sam9n12_soc;
+
++#define AT91_SOC_START(_name) \
++struct at91_init_soc __initdata at91##_name##_soc \
++ __used \
++ = { \
++ .builtin = 1, \
++
++#define AT91_SOC_END \
++};
++
+ static inline int at91_soc_is_enabled(void)
+ {
+- return at91_boot_soc.init != NULL;
++ return at91_boot_soc.builtin;
+ }
+
+ #if !defined(CONFIG_SOC_AT91RM9200)
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 76c442f41acf1572f18ca23d8a7755b5f292e979 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 06:48:33 +0800
+Subject: ARM: at91: gpio: implement request
+
+Configure the pin as pio when requested.
+
+It is needed to configure the pin as PIO at "request time" when we are
+using DT. Indeed, the muxing via old AT91 API is not allowed anymore if
+we are using the plain gpiolib.
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/gpio.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index be42cf0..3b8f463 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -46,6 +46,7 @@ struct at91_gpio_chip {
+
+ #define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
++static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
+ static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
+ static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
+ static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
+@@ -59,6 +60,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+ { \
+ .chip = { \
+ .label = name, \
++ .request = at91_gpiolib_request, \
+ .direction_input = at91_gpiolib_direction_input, \
+ .direction_output = at91_gpiolib_direction_output, \
+ .get = at91_gpiolib_get, \
+@@ -862,6 +864,16 @@ void __init at91_gpio_irq_setup(void)
+ }
+
+ /* gpiolib support */
++static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ __raw_writel(mask, pio + PIO_PER);
++ return 0;
++}
++
+ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+ {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 7355b7402f8791117cdb9086cf45eb02a65b4cf0 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Wed, 4 Jul 2012 17:20:46 +0800
-Subject: at91: regroup gpio and pinctrl under the same ranges
-
-Fix also the reg size as we have 512 bytes bank not 256 bytes per gpio/mux
-controller
-
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/boot/dts/at91sam9260.dtsi | 59 +++++++++++----------
- arch/arm/boot/dts/at91sam9263.dtsi | 94 +++++++++++++++++----------------
- arch/arm/boot/dts/at91sam9g45.dtsi | 103 ++++++++++++++++++++-----------------
- arch/arm/boot/dts/at91sam9n12.dtsi | 83 ++++++++++++++++--------------
- arch/arm/boot/dts/at91sam9x5.dtsi | 83 ++++++++++++++++--------------
- 5 files changed, 228 insertions(+), 194 deletions(-)
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index 0352bf8..e50261d 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -98,34 +98,41 @@
- interrupts = <26 4 0 27 4 0 28 4 0>;
- };
-
-- pioA: gpio@fffff400 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff400 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pinctrl@fffff400 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ ranges = <0xfffff400 0xfffff400 0x600>;
-
-- pioB: gpio@fffff600 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff600 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pioA: gpio@fffff400 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff400 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-
-- pioC: gpio@fffff800 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff800 0x100>;
-- interrupts = <4 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-+ pioB: gpio@fffff600 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff600 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioC: gpio@fffff800 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff800 0x200>;
-+ interrupts = <4 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
- };
-
- dbgu: serial@fffff200 {
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 26ab452..45e5363 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -89,54 +89,60 @@
- reg = <0xfffffd10 0x10>;
- };
-
-- pioA: gpio@fffff200 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff200 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pinctrl@fffff200 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ ranges = <0xfffff200 0xfffff200 0xa00>;
-
-- pioB: gpio@fffff400 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff400 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pioA: gpio@fffff200 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff200 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-
-- pioC: gpio@fffff600 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff600 0x100>;
-- interrupts = <4 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pioB: gpio@fffff400 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff400 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-
-- pioD: gpio@fffff800 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff800 0x100>;
-- interrupts = <4 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
-+ pioC: gpio@fffff600 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff600 0x200>;
-+ interrupts = <4 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-
-- pioE: gpio@fffffa00 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffffa00 0x100>;
-- interrupts = <4 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-+ pioD: gpio@fffff800 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff800 0x200>;
-+ interrupts = <4 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioE: gpio@fffffa00 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffffa00 0x200>;
-+ interrupts = <4 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
- };
-
- dbgu: serial@ffffee00 {
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index 948dc96..59a21c1 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -109,54 +109,61 @@
- #dma-cells = <1>;
- };
-
-- pioA: gpio@fffff200 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff200 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioB: gpio@fffff400 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff400 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioC: gpio@fffff600 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff600 0x100>;
-- interrupts = <4 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioD: gpio@fffff800 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffff800 0x100>;
-- interrupts = <5 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioE: gpio@fffffa00 {
-- compatible = "atmel,at91rm9200-gpio";
-- reg = <0xfffffa00 0x100>;
-- interrupts = <5 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-+ pinctrl@fffff200 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ ranges = <0xfffff200 0xfffff200 0xa00>;
-+
-+ pioA: gpio@fffff200 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff200 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioB: gpio@fffff400 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff400 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioC: gpio@fffff600 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff600 0x200>;
-+ interrupts = <4 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioD: gpio@fffff800 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffff800 0x200>;
-+ interrupts = <5 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioE: gpio@fffffa00 {
-+ compatible = "atmel,at91rm9200-gpio";
-+ reg = <0xfffffa00 0x200>;
-+ interrupts = <5 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
- };
-
- dbgu: serial@ffffee00 {
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index 42b53bd..135ecef 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -112,44 +112,51 @@
- #dma-cells = <1>;
- };
-
-- pioA: gpio@fffff400 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff400 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioB: gpio@fffff600 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff600 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioC: gpio@fffff800 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff800 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioD: gpio@fffffa00 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffffa00 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-+ pinctrl@fffff400 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ ranges = <0xfffff400 0xfffff400 0x800>;
-+
-+ pioA: gpio@fffff400 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff400 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioB: gpio@fffff600 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff600 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioC: gpio@fffff800 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff800 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioD: gpio@fffffa00 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffffa00 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
- };
-
- dbgu: serial@fffff200 {
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 027b9eb..df5f307 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -113,44 +113,51 @@
- #dma-cells = <1>;
- };
-
-- pioA: gpio@fffff400 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff400 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioB: gpio@fffff600 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff600 0x100>;
-- interrupts = <2 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioC: gpio@fffff800 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffff800 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-- };
--
-- pioD: gpio@fffffa00 {
-- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-- reg = <0xfffffa00 0x100>;
-- interrupts = <3 4 1>;
-- #gpio-cells = <2>;
-- gpio-controller;
-- interrupt-controller;
-- #interrupt-cells = <2>;
-+ pinctrl@fffff200 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ ranges = <0xfffff400 0xfffff400 0x800>;
-+
-+ pioA: gpio@fffff400 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff400 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioB: gpio@fffff600 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff600 0x200>;
-+ interrupts = <2 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioC: gpio@fffff800 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffff800 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
-+
-+ pioD: gpio@fffffa00 {
-+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
-+ reg = <0xfffffa00 0x200>;
-+ interrupts = <3 4 1>;
-+ #gpio-cells = <2>;
-+ gpio-controller;
-+ interrupt-controller;
-+ #interrupt-cells = <2>;
-+ };
- };
-
- dbgu: serial@fffff200 {
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 00cd8cb7267db4aa30fa31dd14ec41c7f86198ab Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Sat, 14 Jul 2012 15:26:08 +0800
-Subject: arm: at91: at91sam9x5: fix gpio number per bank
-
-On the at91sam9x5 SoC series, GPIO banks B and D only have 19 and 22
-pins. So add a property to set this parameter.
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- .../devicetree/bindings/gpio/gpio_atmel.txt | 5 ++++
- arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
- arch/arm/mach-at91/gpio.c | 33 ++++++++++++++--------
- 3 files changed, 29 insertions(+), 11 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
-index 66efc80..85f8c0d 100644
---- a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
-+++ b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
-@@ -9,6 +9,10 @@ Required properties:
- unused).
- - gpio-controller: Marks the device node as a GPIO controller.
-
-+optional properties:
-+- #gpio-lines: Number of gpio if absent 32.
-+
-+
- Example:
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
-@@ -16,5 +20,6 @@ Example:
- interrupts = <2 4>;
- #gpio-cells = <2>;
- gpio-controller;
-+ #gpio-lines = <19>;
- };
-
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index df5f307..4e61a5d 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -135,6 +135,7 @@
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
-+ #gpio-lines = <19>;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
-@@ -155,6 +156,7 @@
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
-+ #gpio-lines = <22>;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
-diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
-index 3b8f463..a34f0ed 100644
---- a/arch/arm/mach-at91/gpio.c
-+++ b/arch/arm/mach-at91/gpio.c
-@@ -33,6 +33,8 @@
-
- #include "generic.h"
-
-+#define MAX_NB_GPIO_PER_BANK 32
-+
- struct at91_gpio_chip {
- struct gpio_chip chip;
- struct at91_gpio_chip *next; /* Bank sharing same clock */
-@@ -56,7 +58,7 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
- unsigned offset);
- static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
-
--#define AT91_GPIO_CHIP(name, nr_gpio) \
-+#define AT91_GPIO_CHIP(name) \
- { \
- .chip = { \
- .label = name, \
-@@ -67,16 +69,16 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
- .set = at91_gpiolib_set, \
- .dbg_show = at91_gpiolib_dbg_show, \
- .to_irq = at91_gpiolib_to_irq, \
-- .ngpio = nr_gpio, \
-+ .ngpio = MAX_NB_GPIO_PER_BANK, \
- }, \
- }
-
- static struct at91_gpio_chip gpio_chip[] = {
-- AT91_GPIO_CHIP("pioA", 32),
-- AT91_GPIO_CHIP("pioB", 32),
-- AT91_GPIO_CHIP("pioC", 32),
-- AT91_GPIO_CHIP("pioD", 32),
-- AT91_GPIO_CHIP("pioE", 32),
-+ AT91_GPIO_CHIP("pioA"),
-+ AT91_GPIO_CHIP("pioB"),
-+ AT91_GPIO_CHIP("pioC"),
-+ AT91_GPIO_CHIP("pioD"),
-+ AT91_GPIO_CHIP("pioE"),
- };
-
- static int gpio_banks;
-@@ -91,7 +93,7 @@ static unsigned long at91_gpio_caps;
-
- static inline void __iomem *pin_to_controller(unsigned pin)
- {
-- pin /= 32;
-+ pin /= MAX_NB_GPIO_PER_BANK;
- if (likely(pin < gpio_banks))
- return gpio_chip[pin].regbase;
-
-@@ -100,7 +102,7 @@ static inline void __iomem *pin_to_controller(unsigned pin)
-
- static inline unsigned pin_to_mask(unsigned pin)
- {
-- return 1 << (pin % 32);
-+ return 1 << (pin % MAX_NB_GPIO_PER_BANK);
- }
-
-
-@@ -992,6 +994,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
- {
- int alias_idx;
- struct at91_gpio_chip *at91_gpio;
-+ uint32_t ngpio;
-
- if (!np)
- return;
-@@ -1004,7 +1007,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
- }
-
- at91_gpio = &gpio_chip[alias_idx];
-- at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
-+ at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
-
- at91_gpio->regbase = of_iomap(np, 0);
- if (!at91_gpio->regbase) {
-@@ -1024,6 +1027,14 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
- if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
- at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
-
-+ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
-+ if (ngpio >= MAX_NB_GPIO_PER_BANK)
-+ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
-+ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
-+ else
-+ at91_gpio->chip.ngpio = ngpio;
-+ }
-+
- /* Setup clock */
- if (at91_gpio_setup_clk(alias_idx))
- goto ioremap_err;
-@@ -1061,7 +1072,7 @@ static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
- {
- struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
-
-- at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
-+ at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
- at91_gpio->pioc_hwirq = pioc_hwirq;
- at91_gpio->pioc_idx = idx;
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 72453e8a1a0bb1784b533f53454b08081cf7ec5b Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Wed, 4 Jul 2012 17:20:46 +0800
+Subject: at91: regroup gpio and pinctrl under the same ranges
+
+Fix also the reg size as we have 512 bytes bank not 256 bytes per gpio/mux
+controller
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9260.dtsi | 59 +++++++++++----------
+ arch/arm/boot/dts/at91sam9263.dtsi | 94 +++++++++++++++++----------------
+ arch/arm/boot/dts/at91sam9g45.dtsi | 103 ++++++++++++++++++++-----------------
+ arch/arm/boot/dts/at91sam9n12.dtsi | 83 ++++++++++++++++--------------
+ arch/arm/boot/dts/at91sam9x5.dtsi | 83 ++++++++++++++++--------------
+ 5 files changed, 228 insertions(+), 194 deletions(-)
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index 0352bf8..e50261d 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -98,34 +98,41 @@
+ interrupts = <26 4 0 27 4 0 28 4 0>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x600>;
+
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 26ab452..45e5363 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -89,54 +89,60 @@
+ reg = <0xfffffd10 0x10>;
+ };
+
+- pioA: gpio@fffff200 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff200 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff200 0xfffff200 0xa00>;
+
+- pioB: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioA: gpio@fffff200 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff200 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioC: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioB: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioD: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
++ pioC: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+
+- pioE: gpio@fffffa00 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pioD: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioE: gpio@fffffa00 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 948dc96..59a21c1 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -109,54 +109,61 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff200 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff200 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff400 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff600 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <4 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffff800 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <5 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioE: gpio@fffffa00 {
+- compatible = "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <5 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff200 0xfffff200 0xa00>;
++
++ pioA: gpio@fffff200 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff200 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff400 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff600 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <4 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffff800 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <5 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioE: gpio@fffffa00 {
++ compatible = "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <5 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 42b53bd..135ecef 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -112,44 +112,51 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffffa00 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x800>;
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffffa00 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 027b9eb..df5f307 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -113,44 +113,51 @@
+ #dma-cells = <1>;
+ };
+
+- pioA: gpio@fffff400 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff400 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioB: gpio@fffff600 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff600 0x100>;
+- interrupts = <2 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioC: gpio@fffff800 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffff800 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
+- };
+-
+- pioD: gpio@fffffa00 {
+- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+- reg = <0xfffffa00 0x100>;
+- interrupts = <3 4 1>;
+- #gpio-cells = <2>;
+- gpio-controller;
+- interrupt-controller;
+- #interrupt-cells = <2>;
++ pinctrl@fffff200 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ ranges = <0xfffff400 0xfffff400 0x800>;
++
++ pioA: gpio@fffff400 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff400 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioB: gpio@fffff600 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff600 0x200>;
++ interrupts = <2 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioC: gpio@fffff800 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffff800 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
++
++ pioD: gpio@fffffa00 {
++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
++ reg = <0xfffffa00 0x200>;
++ interrupts = <3 4 1>;
++ #gpio-cells = <2>;
++ gpio-controller;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@fffff200 {
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 76aa1bd70d58b3bdbf4bdf271b04807421d0a4d4 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Thu, 12 Jul 2012 23:35:02 +0800
-Subject: ARM: at91: add dummies pinctrl for non dt platform
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/mach-at91/setup.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
-index 944bffb..50c69b5 100644
---- a/arch/arm/mach-at91/setup.c
-+++ b/arch/arm/mach-at91/setup.c
-@@ -10,6 +10,7 @@
- #include <linux/mm.h>
- #include <linux/pm.h>
- #include <linux/of_address.h>
-+#include <linux/pinctrl/machine.h>
-
- #include <asm/system_misc.h>
- #include <asm/mach/map.h>
-@@ -463,4 +464,6 @@ void __init at91_initialize(unsigned long main_clock)
- at91_boot_soc.register_clocks();
-
- at91_boot_soc.init();
-+
-+ pinctrl_provide_dummies();
- }
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 4c602f8997780f19f61b8fdfb7e751ac04b2b850 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Sat, 14 Jul 2012 15:26:08 +0800
+Subject: arm: at91: at91sam9x5: fix gpio number per bank
+
+On the at91sam9x5 SoC series, GPIO banks B and D only have 19 and 22
+pins. So add a property to set this parameter.
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ .../devicetree/bindings/gpio/gpio_atmel.txt | 5 ++++
+ arch/arm/boot/dts/at91sam9x5.dtsi | 2 ++
+ arch/arm/mach-at91/gpio.c | 33 ++++++++++++++--------
+ 3 files changed, 29 insertions(+), 11 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
+index 66efc80..85f8c0d 100644
+--- a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
++++ b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
+@@ -9,6 +9,10 @@ Required properties:
+ unused).
+ - gpio-controller: Marks the device node as a GPIO controller.
+
++optional properties:
++- #gpio-lines: Number of gpio if absent 32.
++
++
+ Example:
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+@@ -16,5 +20,6 @@ Example:
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <19>;
+ };
+
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index df5f307..4e61a5d 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -135,6 +135,7 @@
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <19>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+@@ -155,6 +156,7 @@
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
++ #gpio-lines = <22>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index 3b8f463..a34f0ed 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -33,6 +33,8 @@
+
+ #include "generic.h"
+
++#define MAX_NB_GPIO_PER_BANK 32
++
+ struct at91_gpio_chip {
+ struct gpio_chip chip;
+ struct at91_gpio_chip *next; /* Bank sharing same clock */
+@@ -56,7 +58,7 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+ unsigned offset);
+ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+
+-#define AT91_GPIO_CHIP(name, nr_gpio) \
++#define AT91_GPIO_CHIP(name) \
+ { \
+ .chip = { \
+ .label = name, \
+@@ -67,16 +69,16 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
+ .set = at91_gpiolib_set, \
+ .dbg_show = at91_gpiolib_dbg_show, \
+ .to_irq = at91_gpiolib_to_irq, \
+- .ngpio = nr_gpio, \
++ .ngpio = MAX_NB_GPIO_PER_BANK, \
+ }, \
+ }
+
+ static struct at91_gpio_chip gpio_chip[] = {
+- AT91_GPIO_CHIP("pioA", 32),
+- AT91_GPIO_CHIP("pioB", 32),
+- AT91_GPIO_CHIP("pioC", 32),
+- AT91_GPIO_CHIP("pioD", 32),
+- AT91_GPIO_CHIP("pioE", 32),
++ AT91_GPIO_CHIP("pioA"),
++ AT91_GPIO_CHIP("pioB"),
++ AT91_GPIO_CHIP("pioC"),
++ AT91_GPIO_CHIP("pioD"),
++ AT91_GPIO_CHIP("pioE"),
+ };
+
+ static int gpio_banks;
+@@ -91,7 +93,7 @@ static unsigned long at91_gpio_caps;
+
+ static inline void __iomem *pin_to_controller(unsigned pin)
+ {
+- pin /= 32;
++ pin /= MAX_NB_GPIO_PER_BANK;
+ if (likely(pin < gpio_banks))
+ return gpio_chip[pin].regbase;
+
+@@ -100,7 +102,7 @@ static inline void __iomem *pin_to_controller(unsigned pin)
+
+ static inline unsigned pin_to_mask(unsigned pin)
+ {
+- return 1 << (pin % 32);
++ return 1 << (pin % MAX_NB_GPIO_PER_BANK);
+ }
+
+
+@@ -992,6 +994,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ {
+ int alias_idx;
+ struct at91_gpio_chip *at91_gpio;
++ uint32_t ngpio;
+
+ if (!np)
+ return;
+@@ -1004,7 +1007,7 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ }
+
+ at91_gpio = &gpio_chip[alias_idx];
+- at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
++ at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
+
+ at91_gpio->regbase = of_iomap(np, 0);
+ if (!at91_gpio->regbase) {
+@@ -1024,6 +1027,14 @@ static void __init of_at91_gpio_init_one(struct device_node *np)
+ if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+ at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+
++ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
++ if (ngpio >= MAX_NB_GPIO_PER_BANK)
++ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
++ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
++ else
++ at91_gpio->chip.ngpio = ngpio;
++ }
++
+ /* Setup clock */
+ if (at91_gpio_setup_clk(alias_idx))
+ goto ioremap_err;
+@@ -1061,7 +1072,7 @@ static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+ {
+ struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+
+- at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
++ at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
+ at91_gpio->pioc_hwirq = pioc_hwirq;
+ at91_gpio->pioc_idx = idx;
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From 51011b0c7102852db8fdc5617a971c3873ba5d7e Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 12 Jul 2012 23:35:02 +0800
+Subject: ARM: at91: add dummies pinctrl for non dt platform
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/mach-at91/setup.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index 944bffb..50c69b5 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -10,6 +10,7 @@
+ #include <linux/mm.h>
+ #include <linux/pm.h>
+ #include <linux/of_address.h>
++#include <linux/pinctrl/machine.h>
+
+ #include <asm/system_misc.h>
+ #include <asm/mach/map.h>
+@@ -463,4 +464,6 @@ void __init at91_initialize(unsigned long main_clock)
+ at91_boot_soc.register_clocks();
+
+ at91_boot_soc.init();
++
++ pinctrl_provide_dummies();
+ }
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 88a0c589d8c7e8e3a2c93012a28978855f5e32d8 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Thu, 18 Oct 2012 17:48:34 +0200
-Subject: ARM: at91: add pinctrl support
-
-This is also include the gpio controller as the IP share both.
-Each soc will have to describe the SoC limitation and pin configuration via
-DT.
-
-This will allow to do not need to touch the C code when adding new SoC if the
-IP version is supported.
-
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-
-Conflicts:
- arch/arm/mach-at91/board-dt.c
----
- .../bindings/pinctrl/atmel,at91-pinctrl.txt | 84 ++
- arch/arm/Kconfig | 2 +
- arch/arm/mach-at91/board-dt.c | 2 -
- arch/arm/mach-at91/gpio.c | 165 +--
- drivers/pinctrl/Kconfig | 9 +
- drivers/pinctrl/Makefile | 1 +
- drivers/pinctrl/pinctrl-at91.c | 1490 ++++++++++++++++++++
- 7 files changed, 1591 insertions(+), 162 deletions(-)
- create mode 100644 Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
- create mode 100644 drivers/pinctrl/pinctrl-at91.c
-
-diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
-new file mode 100644
-index 0000000..0296ef4
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
-@@ -0,0 +1,84 @@
-+* Atmel AT91 Pinmux Controller
-+
-+The AT91 Pinmux Controler, enables the IC
-+to share one PAD to several functional blocks. The sharing is done by
-+multiplexing the PAD input/output signals. For each PAD there are up to
-+8 muxing options (called periph modes). Since different modules require
-+different PAD settings (like pull up, keeper, etc) the contoller controls
-+also the PAD settings parameters.
-+
-+Please refer to pinctrl-bindings.txt in this directory for details of the
-+common pinctrl bindings used by client devices, including the meaning of the
-+phrase "pin configuration node".
-+
-+Atmel AT91 pin configuration node is a node of a group of pins which can be
-+used for a specific device or function. This node represents both mux and config
-+of the pins in that group. The 'pins' selects the function mode(also named pin
-+mode) this pin can work on and the 'config' configures various pad settings
-+such as pull-up, multi drive, etc.
-+
-+Required properties for iomux controller:
-+- compatible: "atmel,at91rm9200-pinctrl"
-+- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
-+ configured in this periph mode. All the periph and bank need to be describe.
-+
-+Required properties for pin configuration node:
-+- atmel,pins: 4 integers array, represents a group of pins mux and config
-+ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
-+ The PERIPH 0 means gpio.
-+
-+Bits used for CONFIG:
-+PULL_UP(1 << 0): indicate this pin need a pull up.
-+MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive.
-+
-+NOTE:
-+Some requirements for using atmel,at91rm9200-pinctrl binding:
-+1. We have pin function node defined under at91 controller node to represent
-+ what pinmux functions this SoC supports.
-+2. The pin configuration node intends to work on a specific function should
-+ to be defined under that specific function node.
-+ The function node's name should represent well about what function
-+ this group of pins in this pin configuration node are working on.
-+3. The driver can use the function node's name and pin configuration node's
-+ name describe the pin function and group hierarchy.
-+ For example, Linux Iat91 pinctrl driver takes the function node's name
-+ as the function name and pin configuration node's name as group name to
-+ create the map table.
-+4. Each pin configuration node should have a phandle, devices can set pins
-+ configurations by referring to the phandle of that pin configuration node.
-+5. The gpio controller must be describe in the pinctrl simple-bus.
-+
-+Examples:
-+
-+pinctrl@fffff400 {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges;
-+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ reg = <0xfffff400 0x600>;
-+
-+ atmel,mux-mask = <
-+ /* A B */
-+ 0xffffffff 0xffc00c3b /* pioA */
-+ 0xffffffff 0x7fff3ccf /* pioB */
-+ 0xffffffff 0x007fffff /* pioC */
-+ >;
-+
-+ /* shared pinctrl settings */
-+ dbgu {
-+ pinctrl_dbgu: dbgu-0 {
-+ atmel,pins =
-+ <1 14 0x1 0x0 /* PB14 periph A */
-+ 1 15 0x1 0x1>; /* PB15 periph with pullup */
-+ };
-+ };
-+};
-+
-+dbgu: serial@fffff200 {
-+ compatible = "atmel,at91sam9260-usart";
-+ reg = <0xfffff200 0x200>;
-+ interrupts = <1 4 7>;
-+ pinctrl-names = "default";
-+ pinctrl-0 = <&pinctrl_dbgu>;
-+ status = "disabled";
-+};
-diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
-index ddef021..ea72f88 100644
---- a/arch/arm/Kconfig
-+++ b/arch/arm/Kconfig
-@@ -339,6 +339,8 @@ config ARCH_AT91
- select CLKDEV_LOOKUP
- select IRQ_DOMAIN
- select NEED_MACH_IO_H if PCCARD
-+ select PINCTRL
-+ select PINCTRL_AT91 if USE_OF
- help
- This enables support for systems based on Atmel
- AT91RM9200 and AT91SAM9* processors.
-diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
-index c0d242c..b1a5d3c 100644
---- a/arch/arm/mach-at91/board-dt.c
-+++ b/arch/arm/mach-at91/board-dt.c
-@@ -127,8 +127,6 @@ struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
- static const struct of_device_id irq_of_match[] __initconst = {
-
- { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
-- { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
-- { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
- { /*sentinel*/ }
- };
-
-diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
-index a34f0ed..c5d7e1e 100644
---- a/arch/arm/mach-at91/gpio.c
-+++ b/arch/arm/mach-at91/gpio.c
-@@ -23,8 +23,6 @@
- #include <linux/io.h>
- #include <linux/irqdomain.h>
- #include <linux/of_address.h>
--#include <linux/of_irq.h>
--#include <linux/of_gpio.h>
-
- #include <asm/mach/irq.h>
-
-@@ -717,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
- */
- static struct lock_class_key gpio_lock_class;
-
--#if defined(CONFIG_OF)
--static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-- irq_hw_number_t hw)
--{
-- struct at91_gpio_chip *at91_gpio = h->host_data;
--
-- irq_set_lockdep_class(virq, &gpio_lock_class);
--
-- /*
-- * Can use the "simple" and not "edge" handler since it's
-- * shorter, and the AIC handles interrupts sanely.
-- */
-- irq_set_chip_and_handler(virq, &gpio_irqchip,
-- handle_simple_irq);
-- set_irq_flags(virq, IRQF_VALID);
-- irq_set_chip_data(virq, at91_gpio);
--
-- return 0;
--}
--
--static struct irq_domain_ops at91_gpio_ops = {
-- .map = at91_gpio_irq_map,
-- .xlate = irq_domain_xlate_twocell,
--};
--
--int __init at91_gpio_of_irq_setup(struct device_node *node,
-- struct device_node *parent)
--{
-- struct at91_gpio_chip *prev = NULL;
-- int alias_idx = of_alias_get_id(node, "gpio");
-- struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx];
--
-- /* Setup proper .irq_set_type function */
-- if (has_pio3())
-- gpio_irqchip.irq_set_type = alt_gpio_irq_type;
-- else
-- gpio_irqchip.irq_set_type = gpio_irq_type;
--
-- /* Disable irqs of this PIO controller */
-- __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
--
-- /* Setup irq domain */
-- at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
-- &at91_gpio_ops, at91_gpio);
-- if (!at91_gpio->domain)
-- panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
-- at91_gpio->pioc_idx);
--
-- /* Setup chained handler */
-- if (at91_gpio->pioc_idx)
-- prev = &gpio_chip[at91_gpio->pioc_idx - 1];
--
-- /* The toplevel handler handles one bank of GPIOs, except
-- * on some SoC it can handles up to three...
-- * We only set up the handler for the first of the list.
-- */
-- if (prev && prev->next == at91_gpio)
-- return 0;
--
-- at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
-- at91_gpio->pioc_hwirq);
-- irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
-- irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
--
-- return 0;
--}
--#else
--int __init at91_gpio_of_irq_setup(struct device_node *node,
-- struct device_node *parent)
--{
-- return -EINVAL;
--}
--#endif
--
- /*
- * irqdomain initialization: pile up irqdomains on top of AIC range
- */
-@@ -989,85 +913,6 @@ err:
- return -EINVAL;
- }
-
--#ifdef CONFIG_OF_GPIO
--static void __init of_at91_gpio_init_one(struct device_node *np)
--{
-- int alias_idx;
-- struct at91_gpio_chip *at91_gpio;
-- uint32_t ngpio;
--
-- if (!np)
-- return;
--
-- alias_idx = of_alias_get_id(np, "gpio");
-- if (alias_idx >= MAX_GPIO_BANKS) {
-- pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
-- alias_idx, MAX_GPIO_BANKS);
-- return;
-- }
--
-- at91_gpio = &gpio_chip[alias_idx];
-- at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
--
-- at91_gpio->regbase = of_iomap(np, 0);
-- if (!at91_gpio->regbase) {
-- pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
-- alias_idx);
-- return;
-- }
--
-- /* Get the interrupts property */
-- if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
-- pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
-- alias_idx);
-- goto ioremap_err;
-- }
--
-- /* Get capabilities from compatibility property */
-- if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
-- at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
--
-- if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
-- if (ngpio >= MAX_NB_GPIO_PER_BANK)
-- pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
-- alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
-- else
-- at91_gpio->chip.ngpio = ngpio;
-- }
--
-- /* Setup clock */
-- if (at91_gpio_setup_clk(alias_idx))
-- goto ioremap_err;
--
-- at91_gpio->chip.of_node = np;
-- gpio_banks = max(gpio_banks, alias_idx + 1);
-- at91_gpio->pioc_idx = alias_idx;
-- return;
--
--ioremap_err:
-- iounmap(at91_gpio->regbase);
--}
--
--static int __init of_at91_gpio_init(void)
--{
-- struct device_node *np = NULL;
--
-- /*
-- * This isn't ideal, but it gets things hooked up until this
-- * driver is converted into a platform_device
-- */
-- for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
-- of_at91_gpio_init_one(np);
--
-- return gpio_banks > 0 ? 0 : -EINVAL;
--}
--#else
--static int __init of_at91_gpio_init(void)
--{
-- return -EINVAL;
--}
--#endif
--
- static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
- {
- struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
-@@ -1102,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
-
- BUG_ON(nr_banks > MAX_GPIO_BANKS);
-
-- if (of_at91_gpio_init() < 0) {
-- /* No GPIO controller found in device tree */
-- for (i = 0; i < nr_banks; i++)
-- at91_gpio_init_one(i, data[i].regbase, data[i].id);
-- }
-+ if (of_have_populated_dt())
-+ return;
-+
-+ for (i = 0; i < nr_banks; i++)
-+ at91_gpio_init_one(i, data[i].regbase, data[i].id);
-
- for (i = 0; i < gpio_banks; i++) {
- at91_gpio = &gpio_chip[i];
-diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
-index f73a5ea..6a03072 100644
---- a/drivers/pinctrl/Kconfig
-+++ b/drivers/pinctrl/Kconfig
-@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
- help
- Say Y here to add some extra checks and diagnostics to PINCTRL calls.
-
-+config PINCTRL_AT91
-+ bool "AT91 pinctrl driver"
-+ depends on OF
-+ depends on ARCH_AT91
-+ select PINMUX
-+ select PINCONF
-+ help
-+ Say Y here to enable the at91 pinctrl driver
-+
- config PINCTRL_PXA3xx
- bool
- select PINMUX
-diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
-index 8e3c95a..84f4670 100644
---- a/drivers/pinctrl/Makefile
-+++ b/drivers/pinctrl/Makefile
-@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
- obj-$(CONFIG_PINCTRL) += devicetree.o
- endif
- obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
-+obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
- obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
- obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
- obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
-diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
-new file mode 100644
-index 0000000..e4712d1
---- /dev/null
-+++ b/drivers/pinctrl/pinctrl-at91.c
-@@ -0,0 +1,1490 @@
-+/*
-+ * at91 pinctrl driver based on at91 pinmux core
-+ *
-+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-+ *
-+ * Under GPLv2 only
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/slab.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/irqdomain.h>
-+#include <linux/io.h>
-+#include <linux/gpio.h>
-+#include <linux/irqdomain.h>
-+#include <linux/pinctrl/machine.h>
-+#include <linux/pinctrl/pinconf.h>
-+#include <linux/pinctrl/pinctrl.h>
-+#include <linux/pinctrl/pinmux.h>
-+/* Since we request GPIOs from ourself */
-+#include <linux/pinctrl/consumer.h>
-+
-+#include <asm/mach/irq.h>
-+
-+#include <mach/hardware.h>
-+#include <mach/at91_pio.h>
-+
-+#include "core.h"
-+
-+#define MAX_NB_GPIO_PER_BANK 32
-+
-+struct at91_pinctrl_mux_ops;
-+
-+struct at91_gpio_chip {
-+ struct gpio_chip chip;
-+ struct pinctrl_gpio_range range;
-+ struct at91_gpio_chip *next; /* Bank sharing same clock */
-+ int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
-+ int pioc_virq; /* PIO bank Linux virtual interrupt */
-+ int pioc_idx; /* PIO bank index */
-+ void __iomem *regbase; /* PIO bank virtual address */
-+ struct clk *clock; /* associated clock */
-+ struct irq_domain *domain; /* associated irq domain */
-+ struct at91_pinctrl_mux_ops *ops; /* ops */
-+};
-+
-+#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
-+
-+static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
-+
-+static int gpio_banks;
-+
-+#define PULL_UP (0 << 1)
-+#define MULTI_DRIVE (1 << 1)
-+
-+/**
-+ * struct at91_pmx_func - describes AT91 pinmux functions
-+ * @name: the name of this specific function
-+ * @groups: corresponding pin groups
-+ * @ngroups: the number of groups
-+ */
-+struct at91_pmx_func {
-+ const char *name;
-+ const char **groups;
-+ unsigned ngroups;
-+};
-+
-+enum at91_mux {
-+ AT91_MUX_GPIO = 0,
-+ AT91_MUX_PERIPH_A = 1,
-+ AT91_MUX_PERIPH_B = 2,
-+ AT91_MUX_PERIPH_C = 3,
-+ AT91_MUX_PERIPH_D = 4,
-+};
-+
-+/**
-+ * struct at91_pmx_pin - describes an At91 pin mux
-+ * @bank: the bank of the pin
-+ * @pin: the pin number in the @bank
-+ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
-+ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
-+ */
-+struct at91_pmx_pin {
-+ uint32_t bank;
-+ uint32_t pin;
-+ enum at91_mux mux;
-+ unsigned long conf;
-+};
-+
-+/**
-+ * struct at91_pin_group - describes an At91 pin group
-+ * @name: the name of this specific pin group
-+ * @pins_conf: the mux mode for each pin in this group. The size of this
-+ * array is the same as pins.
-+ * @pins: an array of discrete physical pins used in this group, taken
-+ * from the driver-local pin enumeration space
-+ * @npins: the number of pins in this group array, i.e. the number of
-+ * elements in .pins so we can iterate over that array
-+ */
-+struct at91_pin_group {
-+ const char *name;
-+ struct at91_pmx_pin *pins_conf;
-+ unsigned int *pins;
-+ unsigned npins;
-+};
-+
-+/**
-+ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
-+ * on new IP with support for periph C and D the way to mux in
-+ * periph A and B has changed
-+ * So provide the right call back
-+ * if not present means the IP does not support it
-+ * @get_periph: return the periph mode configured
-+ * @mux_A_periph: mux as periph A
-+ * @mux_B_periph: mux as periph B
-+ * @mux_C_periph: mux as periph C
-+ * @mux_D_periph: mux as periph D
-+ * @irq_type: return irq type
-+ */
-+struct at91_pinctrl_mux_ops {
-+ enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
-+ void (*mux_A_periph)(void __iomem *pio, unsigned mask);
-+ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
-+ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
-+ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
-+ /* irq */
-+ int (*irq_type)(struct irq_data *d, unsigned type);
-+};
-+
-+static int gpio_irq_type(struct irq_data *d, unsigned type);
-+static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
-+
-+struct at91_pinctrl {
-+ struct device *dev;
-+ struct pinctrl_dev *pctl;
-+
-+ int nbanks;
-+
-+ uint32_t *mux_mask;
-+ int nmux;
-+
-+ struct at91_pmx_func *functions;
-+ int nfunctions;
-+
-+ struct at91_pin_group *groups;
-+ int ngroups;
-+
-+ struct at91_pinctrl_mux_ops *ops;
-+};
-+
-+static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
-+ const struct at91_pinctrl *info,
-+ const char *name)
-+{
-+ const struct at91_pin_group *grp = NULL;
-+ int i;
-+
-+ for (i = 0; i < info->ngroups; i++) {
-+ if (strcmp(info->groups[i].name, name))
-+ continue;
-+
-+ grp = &info->groups[i];
-+ dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
-+ break;
-+ }
-+
-+ return grp;
-+}
-+
-+static int at91_get_groups_count(struct pinctrl_dev *pctldev)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ return info->ngroups;
-+}
-+
-+static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
-+ unsigned selector)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ return info->groups[selector].name;
-+}
-+
-+static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
-+ const unsigned **pins,
-+ unsigned *npins)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ if (selector >= info->ngroups)
-+ return -EINVAL;
-+
-+ *pins = info->groups[selector].pins;
-+ *npins = info->groups[selector].npins;
-+
-+ return 0;
-+}
-+
-+static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
-+ unsigned offset)
-+{
-+ seq_printf(s, "%s", dev_name(pctldev->dev));
-+}
-+
-+static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
-+ struct device_node *np,
-+ struct pinctrl_map **map, unsigned *num_maps)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+ const struct at91_pin_group *grp;
-+ struct pinctrl_map *new_map;
-+ struct device_node *parent;
-+ int map_num = 1;
-+ int i;
-+ struct at91_pmx_pin *pin;
-+
-+ /*
-+ * first find the group of this node and check if we need create
-+ * config maps for pins
-+ */
-+ grp = at91_pinctrl_find_group_by_name(info, np->name);
-+ if (!grp) {
-+ dev_err(info->dev, "unable to find group for node %s\n",
-+ np->name);
-+ return -EINVAL;
-+ }
-+
-+ map_num += grp->npins;
-+ new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
-+ if (!new_map)
-+ return -ENOMEM;
-+
-+ *map = new_map;
-+ *num_maps = map_num;
-+
-+ /* create mux map */
-+ parent = of_get_parent(np);
-+ if (!parent) {
-+ kfree(new_map);
-+ return -EINVAL;
-+ }
-+ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
-+ new_map[0].data.mux.function = parent->name;
-+ new_map[0].data.mux.group = np->name;
-+ of_node_put(parent);
-+
-+ /* create config map */
-+ new_map++;
-+ for (i = 0; i < grp->npins; i++) {
-+ pin = &grp->pins_conf[i];
-+
-+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
-+ new_map[i].data.configs.group_or_pin =
-+ pin_get_name(pctldev, grp->pins[i]);
-+ new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
-+ new_map[i].data.configs.num_configs = 1;
-+ }
-+
-+ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
-+ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
-+
-+ return 0;
-+}
-+
-+static void at91_dt_free_map(struct pinctrl_dev *pctldev,
-+ struct pinctrl_map *map, unsigned num_maps)
-+{
-+}
-+
-+static struct pinctrl_ops at91_pctrl_ops = {
-+ .get_groups_count = at91_get_groups_count,
-+ .get_group_name = at91_get_group_name,
-+ .get_group_pins = at91_get_group_pins,
-+ .pin_dbg_show = at91_pin_dbg_show,
-+ .dt_node_to_map = at91_dt_node_to_map,
-+ .dt_free_map = at91_dt_free_map,
-+};
-+
-+static void __iomem * pin_to_controller(struct at91_pinctrl *info,
-+ unsigned int bank)
-+{
-+ return gpio_chips[bank]->regbase;
-+}
-+
-+static inline int pin_to_bank(unsigned pin)
-+{
-+ return pin /= MAX_NB_GPIO_PER_BANK;
-+}
-+
-+static unsigned pin_to_mask(unsigned int pin)
-+{
-+ return 1 << pin;
-+}
-+
-+static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(mask, pio + PIO_IDR);
-+}
-+
-+static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
-+{
-+ return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
-+}
-+
-+static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
-+{
-+ writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
-+}
-+
-+static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
-+{
-+ return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
-+}
-+
-+static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
-+{
-+ writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
-+}
-+
-+static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(mask, pio + PIO_ASR);
-+}
-+
-+static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(mask, pio + PIO_BSR);
-+}
-+
-+static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
-+{
-+
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
-+ pio + PIO_ABCDSR1);
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
-+ pio + PIO_ABCDSR2);
-+}
-+
-+static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
-+ pio + PIO_ABCDSR1);
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
-+ pio + PIO_ABCDSR2);
-+}
-+
-+static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
-+}
-+
-+static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
-+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
-+}
-+
-+static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
-+{
-+ unsigned select;
-+
-+ if (readl_relaxed(pio + PIO_PSR) & mask)
-+ return AT91_MUX_GPIO;
-+
-+ select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
-+ select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
-+
-+ return select + 1;
-+}
-+
-+static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
-+{
-+ unsigned select;
-+
-+ if (readl_relaxed(pio + PIO_PSR) & mask)
-+ return AT91_MUX_GPIO;
-+
-+ select = readl_relaxed(pio + PIO_ABSR) & mask;
-+
-+ return select + 1;
-+}
-+
-+static struct at91_pinctrl_mux_ops at91rm9200_ops = {
-+ .get_periph = at91_mux_get_periph,
-+ .mux_A_periph = at91_mux_set_A_periph,
-+ .mux_B_periph = at91_mux_set_B_periph,
-+ .irq_type = gpio_irq_type,
-+};
-+
-+static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
-+ .get_periph = at91_mux_pio3_get_periph,
-+ .mux_A_periph = at91_mux_pio3_set_A_periph,
-+ .mux_B_periph = at91_mux_pio3_set_B_periph,
-+ .mux_C_periph = at91_mux_pio3_set_C_periph,
-+ .mux_D_periph = at91_mux_pio3_set_D_periph,
-+ .irq_type = alt_gpio_irq_type,
-+};
-+
-+static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
-+{
-+ if (pin->mux) {
-+ dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
-+ pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
-+ } else {
-+ dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
-+ pin->bank + 'A', pin->pin, pin->conf);
-+ }
-+}
-+
-+static int pin_check_config(struct at91_pinctrl *info, const char* name,
-+ int index, const struct at91_pmx_pin *pin)
-+{
-+ int mux;
-+
-+ /* check if it's a valid config */
-+ if (pin->bank >= info->nbanks) {
-+ dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
-+ name, index, pin->bank, info->nbanks);
-+ return -EINVAL;
-+ }
-+
-+ if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
-+ dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
-+ name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
-+ return -EINVAL;
-+ }
-+
-+ if (!pin->mux)
-+ return 0;
-+
-+ mux = pin->mux - 1;
-+
-+ if (mux >= info->nmux) {
-+ dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
-+ name, index, mux, info->nmux);
-+ return -EINVAL;
-+ }
-+
-+ if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
-+ dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
-+ name, index, mux, pin->bank + 'A', pin->pin);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
-+{
-+ writel_relaxed(mask, pio + PIO_PDR);
-+}
-+
-+static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
-+{
-+ writel_relaxed(mask, pio + PIO_PER);
-+ writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
-+}
-+
-+static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
-+ unsigned group)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
-+ const struct at91_pmx_pin *pin;
-+ uint32_t npins = info->groups[group].npins;
-+ int i, ret;
-+ unsigned mask;
-+ void __iomem *pio;
-+
-+ dev_dbg(info->dev, "enable function %s group %s\n",
-+ info->functions[selector].name, info->groups[group].name);
-+
-+ /* first check that all the pins of the group are valid with a valid
-+ * paramter */
-+ for (i = 0; i < npins; i++) {
-+ pin = &pins_conf[i];
-+ ret = pin_check_config(info, info->groups[group].name, i, pin);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ for (i = 0; i < npins; i++) {
-+ pin = &pins_conf[i];
-+ at91_pin_dbg(info->dev, pin);
-+ pio = pin_to_controller(info, pin->bank);
-+ mask = pin_to_mask(pin->pin);
-+ at91_mux_disable_interrupt(pio, mask);
-+ switch(pin->mux) {
-+ case AT91_MUX_GPIO:
-+ at91_mux_gpio_enable(pio, mask, 1);
-+ break;
-+ case AT91_MUX_PERIPH_A:
-+ info->ops->mux_A_periph(pio, mask);
-+ break;
-+ case AT91_MUX_PERIPH_B:
-+ info->ops->mux_B_periph(pio, mask);
-+ break;
-+ case AT91_MUX_PERIPH_C:
-+ if (!info->ops->mux_C_periph)
-+ return -EINVAL;
-+ info->ops->mux_C_periph(pio, mask);
-+ break;
-+ case AT91_MUX_PERIPH_D:
-+ if (!info->ops->mux_D_periph)
-+ return -EINVAL;
-+ info->ops->mux_D_periph(pio, mask);
-+ break;
-+ }
-+ if (pin->mux)
-+ at91_mux_gpio_disable(pio, mask);
-+ }
-+
-+ return 0;
-+}
-+
-+static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
-+ unsigned group)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
-+ const struct at91_pmx_pin *pin;
-+ uint32_t npins = info->groups[group].npins;
-+ int i;
-+ unsigned mask;
-+ void __iomem *pio;
-+
-+ for (i = 0; i < npins; i++) {
-+ pin = &pins_conf[i];
-+ at91_pin_dbg(info->dev, pin);
-+ pio = pin_to_controller(info, pin->bank);
-+ mask = pin_to_mask(pin->pin);
-+ at91_mux_gpio_enable(pio, mask, 1);
-+ }
-+}
-+
-+static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ return info->nfunctions;
-+}
-+
-+static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
-+ unsigned selector)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ return info->functions[selector].name;
-+}
-+
-+static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
-+ const char * const **groups,
-+ unsigned * const num_groups)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+
-+ *groups = info->functions[selector].groups;
-+ *num_groups = info->functions[selector].ngroups;
-+
-+ return 0;
-+}
-+
-+int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
-+ struct pinctrl_gpio_range *range,
-+ unsigned offset)
-+{
-+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
-+ struct at91_gpio_chip *at91_chip;
-+ struct gpio_chip *chip;
-+ unsigned mask;
-+
-+ if (!range) {
-+ dev_err(npct->dev, "invalid range\n");
-+ return -EINVAL;
-+ }
-+ if (!range->gc) {
-+ dev_err(npct->dev, "missing GPIO chip in range\n");
-+ return -EINVAL;
-+ }
-+ chip = range->gc;
-+ at91_chip = container_of(chip, struct at91_gpio_chip, chip);
-+
-+ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
-+
-+ mask = 1 << (offset - chip->base);
-+
-+ dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
-+ offset, 'A' + range->id, offset - chip->base, mask);
-+
-+ writel_relaxed(mask, at91_chip->regbase + PIO_PER);
-+
-+ return 0;
-+}
-+
-+void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
-+ struct pinctrl_gpio_range *range,
-+ unsigned offset)
-+{
-+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
-+
-+ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
-+ /* Set the pin to some default state, GPIO is usually default */
-+}
-+
-+static struct pinmux_ops at91_pmx_ops = {
-+ .get_functions_count = at91_pmx_get_funcs_count,
-+ .get_function_name = at91_pmx_get_func_name,
-+ .get_function_groups = at91_pmx_get_groups,
-+ .enable = at91_pmx_enable,
-+ .disable = at91_pmx_disable,
-+ .gpio_request_enable = at91_gpio_request_enable,
-+ .gpio_disable_free = at91_gpio_disable_free,
-+};
-+
-+static int at91_pinconf_get(struct pinctrl_dev *pctldev,
-+ unsigned pin_id, unsigned long *config)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+ void __iomem *pio;
-+ unsigned pin;
-+
-+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
-+ pio = pin_to_controller(info, pin_to_bank(pin_id));
-+ pin = pin_id % MAX_NB_GPIO_PER_BANK;
-+
-+ if (at91_mux_get_multidrive(pio, pin))
-+ *config |= MULTI_DRIVE;
-+
-+ if (at91_mux_get_pullup(pio, pin))
-+ *config |= PULL_UP;
-+
-+ return 0;
-+}
-+
-+static int at91_pinconf_set(struct pinctrl_dev *pctldev,
-+ unsigned pin_id, unsigned long config)
-+{
-+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
-+ unsigned mask;
-+ void __iomem *pio;
-+
-+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
-+ pio = pin_to_controller(info, pin_to_bank(pin_id));
-+ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
-+
-+ at91_mux_set_pullup(pio, mask, config & PULL_UP);
-+ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
-+ return 0;
-+}
-+
-+static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
-+ struct seq_file *s, unsigned pin_id)
-+{
-+
-+}
-+
-+static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
-+ struct seq_file *s, unsigned group)
-+{
-+}
-+
-+struct pinconf_ops at91_pinconf_ops = {
-+ .pin_config_get = at91_pinconf_get,
-+ .pin_config_set = at91_pinconf_set,
-+ .pin_config_dbg_show = at91_pinconf_dbg_show,
-+ .pin_config_group_dbg_show = at91_pinconf_group_dbg_show,
-+};
-+
-+static struct pinctrl_desc at91_pinctrl_desc = {
-+ .pctlops = &at91_pctrl_ops,
-+ .pmxops = &at91_pmx_ops,
-+ .confops = &at91_pinconf_ops,
-+ .owner = THIS_MODULE,
-+};
-+
-+static const char *gpio_compat = "atmel,at91rm9200-gpio";
-+
-+static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
-+ struct device_node *np)
-+{
-+ struct device_node *child;
-+
-+ for_each_child_of_node(np, child) {
-+ if (of_device_is_compatible(child, gpio_compat)) {
-+ info->nbanks++;
-+ } else {
-+ info->nfunctions++;
-+ info->ngroups += of_get_child_count(child);
-+ }
-+ }
-+}
-+
-+static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
-+ struct device_node *np)
-+{
-+ int ret = 0;
-+ int size;
-+ const const __be32 *list;
-+
-+ list = of_get_property(np, "atmel,mux-mask", &size);
-+ if (!list) {
-+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
-+ return -EINVAL;
-+ }
-+
-+ size /= sizeof(*list);
-+ if (!size || size % info->nbanks) {
-+ dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
-+ return -EINVAL;
-+ }
-+ info->nmux = size / info->nbanks;
-+
-+ info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
-+ if (!info->mux_mask) {
-+ dev_err(info->dev, "could not alloc mux_mask\n");
-+ return -ENOMEM;
-+ }
-+
-+ ret = of_property_read_u32_array(np, "atmel,mux-mask",
-+ info->mux_mask, size);
-+ if (ret)
-+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
-+ return ret;
-+}
-+
-+static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
-+ struct at91_pin_group *grp,
-+ struct at91_pinctrl *info,
-+ u32 index)
-+{
-+ struct at91_pmx_pin *pin;
-+ int size;
-+ const const __be32 *list;
-+ int i, j;
-+
-+ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
-+
-+ /* Initialise group */
-+ grp->name = np->name;
-+
-+ /*
-+ * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
-+ * do sanity check and calculate pins number
-+ */
-+ list = of_get_property(np, "atmel,pins", &size);
-+ /* we do not check return since it's safe node passed down */
-+ size /= sizeof(*list);
-+ if (!size || size % 4) {
-+ dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
-+ return -EINVAL;
-+ }
-+
-+ grp->npins = size / 4;
-+ pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
-+ GFP_KERNEL);
-+ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
-+ GFP_KERNEL);
-+ if (!grp->pins_conf || !grp->pins)
-+ return -ENOMEM;
-+
-+ for (i = 0, j = 0; i < size; i += 4, j++) {
-+ pin->bank = be32_to_cpu(*list++);
-+ pin->pin = be32_to_cpu(*list++);
-+ grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
-+ pin->mux = be32_to_cpu(*list++);
-+ pin->conf = be32_to_cpu(*list++);
-+
-+ at91_pin_dbg(info->dev, pin);
-+ pin++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
-+ struct at91_pinctrl *info, u32 index)
-+{
-+ struct device_node *child;
-+ struct at91_pmx_func *func;
-+ struct at91_pin_group *grp;
-+ int ret;
-+ static u32 grp_index;
-+ u32 i = 0;
-+
-+ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
-+
-+ func = &info->functions[index];
-+
-+ /* Initialise function */
-+ func->name = np->name;
-+ func->ngroups = of_get_child_count(np);
-+ if (func->ngroups <= 0) {
-+ dev_err(info->dev, "no groups defined\n");
-+ return -EINVAL;
-+ }
-+ func->groups = devm_kzalloc(info->dev,
-+ func->ngroups * sizeof(char *), GFP_KERNEL);
-+ if (!func->groups)
-+ return -ENOMEM;
-+
-+ for_each_child_of_node(np, child) {
-+ func->groups[i] = child->name;
-+ grp = &info->groups[grp_index++];
-+ ret = at91_pinctrl_parse_groups(child, grp, info, i++);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
-+ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
-+ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
-+ { /* sentinel */ }
-+};
-+
-+static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
-+ struct at91_pinctrl *info)
-+{
-+ int ret = 0;
-+ int i, j;
-+ uint32_t *tmp;
-+ struct device_node *np = pdev->dev.of_node;
-+ struct device_node *child;
-+
-+ if (!np)
-+ return -ENODEV;
-+
-+ info->dev = &pdev->dev;
-+ info->ops =
-+ of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
-+ at91_pinctrl_child_count(info, np);
-+
-+ if (info->nbanks < 1) {
-+ dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = at91_pinctrl_mux_mask(info, np);
-+ if (ret)
-+ return ret;
-+
-+ dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
-+
-+ dev_dbg(&pdev->dev, "mux-mask\n");
-+ tmp = info->mux_mask;
-+ for (i = 0; i < info->nbanks; i++) {
-+ for (j = 0; j < info->nmux; j++, tmp++) {
-+ dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
-+ }
-+ }
-+
-+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
-+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
-+ info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
-+ GFP_KERNEL);
-+ if (!info->functions)
-+ return -ENOMEM;
-+
-+ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
-+ GFP_KERNEL);
-+ if (!info->groups)
-+ return -ENOMEM;
-+
-+ dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
-+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
-+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
-+
-+ i = 0;
-+
-+ for_each_child_of_node(np, child) {
-+ if (of_device_is_compatible(child, gpio_compat))
-+ continue;
-+ ret = at91_pinctrl_parse_functions(child, info, i++);
-+ if (ret) {
-+ dev_err(&pdev->dev, "failed to parse function\n");
-+ return ret;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
-+{
-+ struct at91_pinctrl *info;
-+ struct pinctrl_pin_desc *pdesc;
-+ int ret, i, j ,k;
-+
-+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ ret = at91_pinctrl_probe_dt(pdev, info);
-+ if (ret)
-+ return ret;
-+
-+ /*
-+ * We need all the GPIO drivers to probe FIRST, or we will not be able
-+ * to obtain references to the struct gpio_chip * for them, and we
-+ * need this to proceed.
-+ */
-+ for (i = 0; i < info->nbanks; i++) {
-+ if (!gpio_chips[i]) {
-+ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
-+ devm_kfree(&pdev->dev, info);
-+ return -EPROBE_DEFER;
-+ }
-+ }
-+
-+ at91_pinctrl_desc.name = dev_name(&pdev->dev);
-+ at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
-+ at91_pinctrl_desc.pins = pdesc =
-+ devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
-+
-+ if (!at91_pinctrl_desc.pins)
-+ return -ENOMEM;
-+
-+ for (i = 0 , k = 0; i < info->nbanks; i++) {
-+ for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
-+ pdesc->number = k;
-+ pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
-+ pdesc++;
-+ }
-+ }
-+
-+ platform_set_drvdata(pdev, info);
-+ info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
-+
-+ if (!info->pctl) {
-+ dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ /* We will handle a range of GPIO pins */
-+ for (i = 0; i < info->nbanks; i++)
-+ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
-+
-+ dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
-+
-+ return 0;
-+
-+err:
-+ return ret;
-+}
-+
-+int __devexit at91_pinctrl_remove(struct platform_device *pdev)
-+{
-+ struct at91_pinctrl *info = platform_get_drvdata(pdev);
-+
-+ pinctrl_unregister(info->pctl);
-+
-+ return 0;
-+}
-+
-+static int at91_gpio_request(struct gpio_chip *chip, unsigned offset)
-+{
-+ /*
-+ * Map back to global GPIO space and request muxing, the direction
-+ * parameter does not matter for this controller.
-+ */
-+ int gpio = chip->base + offset;
-+ int bank = chip->base / chip->ngpio;
-+
-+ dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
-+ 'A' + bank, offset, gpio);
-+
-+ return pinctrl_request_gpio(gpio);
-+}
-+
-+static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
-+{
-+ int gpio = chip->base + offset;
-+
-+ pinctrl_free_gpio(gpio);
-+}
-+
-+static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << offset;
-+
-+ writel_relaxed(mask, pio + PIO_ODR);
-+ return 0;
-+}
-+
-+static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << offset;
-+ u32 pdsr;
-+
-+ pdsr = readl_relaxed(pio + PIO_PDSR);
-+ return (pdsr & mask) != 0;
-+}
-+
-+static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
-+ int val)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << offset;
-+
-+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
-+}
-+
-+static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-+ int val)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << offset;
-+
-+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
-+ writel_relaxed(mask, pio + PIO_OER);
-+
-+ return 0;
-+}
-+
-+static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-+{
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ int virq;
-+
-+ if (offset < chip->ngpio)
-+ virq = irq_create_mapping(at91_gpio->domain, offset);
-+ else
-+ virq = -ENXIO;
-+
-+ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
-+ chip->label, offset + chip->base, virq);
-+ return virq;
-+}
-+
-+#ifdef CONFIG_DEBUG_FS
-+static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-+{
-+ enum at91_mux mode;
-+ int i;
-+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
-+ void __iomem *pio = at91_gpio->regbase;
-+
-+ for (i = 0; i < chip->ngpio; i++) {
-+ unsigned pin = chip->base + i;
-+ unsigned mask = pin_to_mask(pin);
-+ const char *gpio_label;
-+ u32 pdsr;
-+
-+ gpio_label = gpiochip_is_requested(chip, i);
-+ if (!gpio_label)
-+ continue;
-+ mode = at91_gpio->ops->get_periph(pio, mask);
-+ seq_printf(s, "[%s] GPIO%s%d: ",
-+ gpio_label, chip->label, i);
-+ if (mode == AT91_MUX_GPIO) {
-+ pdsr = readl_relaxed(pio + PIO_PDSR);
-+
-+ seq_printf(s, "[gpio] %s\n",
-+ pdsr & mask ?
-+ "set" : "clear");
-+ } else {
-+ seq_printf(s, "[periph %c]\n",
-+ mode + 'A' - 1);
-+ }
-+ }
-+}
-+#else
-+#define at91_gpio_dbg_show NULL
-+#endif
-+
-+/* Several AIC controller irqs are dispatched through this GPIO handler.
-+ * To use any AT91_PIN_* as an externally triggered IRQ, first call
-+ * at91_set_gpio_input() then maybe enable its glitch filter.
-+ * Then just request_irq() with the pin ID; it works like any ARM IRQ
-+ * handler.
-+ * First implementation always triggers on rising and falling edges
-+ * whereas the newer PIO3 can be additionally configured to trigger on
-+ * level, edge with any polarity.
-+ *
-+ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
-+ * configuring them with at91_set_a_periph() or at91_set_b_periph().
-+ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
-+ */
-+
-+static void gpio_irq_mask(struct irq_data *d)
-+{
-+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << d->hwirq;
-+
-+ if (pio)
-+ writel_relaxed(mask, pio + PIO_IDR);
-+}
-+
-+static void gpio_irq_unmask(struct irq_data *d)
-+{
-+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << d->hwirq;
-+
-+ if (pio)
-+ writel_relaxed(mask, pio + PIO_IER);
-+}
-+
-+static int gpio_irq_type(struct irq_data *d, unsigned type)
-+{
-+ switch (type) {
-+ case IRQ_TYPE_NONE:
-+ case IRQ_TYPE_EDGE_BOTH:
-+ return 0;
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+/* Alternate irq type for PIO3 support */
-+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
-+{
-+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned mask = 1 << d->hwirq;
-+
-+ switch (type) {
-+ case IRQ_TYPE_EDGE_RISING:
-+ writel_relaxed(mask, pio + PIO_ESR);
-+ writel_relaxed(mask, pio + PIO_REHLSR);
-+ break;
-+ case IRQ_TYPE_EDGE_FALLING:
-+ writel_relaxed(mask, pio + PIO_ESR);
-+ writel_relaxed(mask, pio + PIO_FELLSR);
-+ break;
-+ case IRQ_TYPE_LEVEL_LOW:
-+ writel_relaxed(mask, pio + PIO_LSR);
-+ writel_relaxed(mask, pio + PIO_FELLSR);
-+ break;
-+ case IRQ_TYPE_LEVEL_HIGH:
-+ writel_relaxed(mask, pio + PIO_LSR);
-+ writel_relaxed(mask, pio + PIO_REHLSR);
-+ break;
-+ case IRQ_TYPE_EDGE_BOTH:
-+ /*
-+ * disable additional interrupt modes:
-+ * fall back to default behavior
-+ */
-+ writel_relaxed(mask, pio + PIO_AIMDR);
-+ return 0;
-+ case IRQ_TYPE_NONE:
-+ default:
-+ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
-+ return -EINVAL;
-+ }
-+
-+ /* enable additional interrupt modes */
-+ writel_relaxed(mask, pio + PIO_AIMER);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
-+{
-+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
-+ unsigned bank = at91_gpio->pioc_idx;
-+
-+ if (unlikely(bank >= MAX_GPIO_BANKS))
-+ return -EINVAL;
-+
-+ irq_set_irq_wake(at91_gpio->pioc_virq, state);
-+
-+ return 0;
-+}
-+#else
-+#define gpio_irq_set_wake NULL
-+#endif
-+
-+static struct irq_chip gpio_irqchip = {
-+ .name = "GPIO",
-+ .irq_disable = gpio_irq_mask,
-+ .irq_mask = gpio_irq_mask,
-+ .irq_unmask = gpio_irq_unmask,
-+ /* .irq_set_type is set dynamically */
-+ .irq_set_wake = gpio_irq_set_wake,
-+};
-+
-+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
-+{
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct irq_data *idata = irq_desc_get_irq_data(desc);
-+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
-+ void __iomem *pio = at91_gpio->regbase;
-+ unsigned long isr;
-+ int n;
-+
-+ chained_irq_enter(chip, desc);
-+ for (;;) {
-+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
-+ * When there none are pending, we're finished unless we need
-+ * to process multiple banks (like ID_PIOCDE on sam9263).
-+ */
-+ isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
-+ if (!isr) {
-+ if (!at91_gpio->next)
-+ break;
-+ at91_gpio = at91_gpio->next;
-+ pio = at91_gpio->regbase;
-+ continue;
-+ }
-+
-+ n = find_first_bit(&isr, BITS_PER_LONG);
-+ while (n < BITS_PER_LONG) {
-+ generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
-+ n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
-+ }
-+ }
-+ chained_irq_exit(chip, desc);
-+ /* now it may re-trigger */
-+}
-+
-+/*
-+ * This lock class tells lockdep that GPIO irqs are in a different
-+ * category than their parents, so it won't report false recursion.
-+ */
-+static struct lock_class_key gpio_lock_class;
-+
-+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
-+ irq_hw_number_t hw)
-+{
-+ struct at91_gpio_chip *at91_gpio = h->host_data;
-+
-+ irq_set_lockdep_class(virq, &gpio_lock_class);
-+
-+ /*
-+ * Can use the "simple" and not "edge" handler since it's
-+ * shorter, and the AIC handles interrupts sanely.
-+ */
-+ irq_set_chip_and_handler(virq, &gpio_irqchip,
-+ handle_simple_irq);
-+ set_irq_flags(virq, IRQF_VALID);
-+ irq_set_chip_data(virq, at91_gpio);
-+
-+ return 0;
-+}
-+
-+static struct irq_domain_ops at91_gpio_ops = {
-+ .map = at91_gpio_irq_map,
-+ .xlate = irq_domain_xlate_twocell,
-+};
-+
-+static int at91_gpio_of_irq_setup(struct device_node *node,
-+ struct at91_gpio_chip *at91_gpio)
-+{
-+ struct at91_gpio_chip *prev = NULL;
-+ struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
-+
-+ at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
-+
-+ /* Setup proper .irq_set_type function */
-+ gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
-+
-+ /* Disable irqs of this PIO controller */
-+ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
-+
-+ /* Setup irq domain */
-+ at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
-+ &at91_gpio_ops, at91_gpio);
-+ if (!at91_gpio->domain)
-+ panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
-+ at91_gpio->pioc_idx);
-+
-+ /* Setup chained handler */
-+ if (at91_gpio->pioc_idx)
-+ prev = gpio_chips[at91_gpio->pioc_idx - 1];
-+
-+ /* The toplevel handler handles one bank of GPIOs, except
-+ * on some SoC it can handles up to three...
-+ * We only set up the handler for the first of the list.
-+ */
-+ if (prev && prev->next == at91_gpio)
-+ return 0;
-+
-+ irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
-+ irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
-+
-+ return 0;
-+}
-+
-+/* This structure is replicated for each GPIO block allocated at probe time */
-+static struct gpio_chip at91_gpio_template = {
-+ .request = at91_gpio_request,
-+ .free = at91_gpio_free,
-+ .direction_input = at91_gpio_direction_input,
-+ .get = at91_gpio_get,
-+ .direction_output = at91_gpio_direction_output,
-+ .set = at91_gpio_set,
-+ .to_irq = at91_gpio_to_irq,
-+ .dbg_show = at91_gpio_dbg_show,
-+ .can_sleep = 0,
-+ .ngpio = MAX_NB_GPIO_PER_BANK,
-+};
-+
-+static void __devinit at91_gpio_probe_fixup(void)
-+{
-+ unsigned i;
-+ struct at91_gpio_chip *at91_gpio, *last = NULL;
-+
-+ for (i = 0; i < gpio_banks; i++) {
-+ at91_gpio = gpio_chips[i];
-+
-+ /*
-+ * GPIO controller are grouped on some SoC:
-+ * PIOC, PIOD and PIOE can share the same IRQ line
-+ */
-+ if (last && last->pioc_virq == at91_gpio->pioc_virq)
-+ last->next = at91_gpio;
-+ last = at91_gpio;
-+ }
-+}
-+
-+static struct of_device_id at91_gpio_of_match[] __devinitdata = {
-+ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
-+ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
-+ { /* sentinel */ }
-+};
-+
-+static int __devinit at91_gpio_probe(struct platform_device *pdev)
-+{
-+ struct device_node *np = pdev->dev.of_node;
-+ struct resource *res;
-+ struct at91_gpio_chip *at91_chip = NULL;
-+ struct gpio_chip *chip;
-+ struct pinctrl_gpio_range *range;
-+ int ret = 0;
-+ int irq;
-+ int alias_idx = of_alias_get_id(np, "gpio");
-+ uint32_t ngpio;
-+
-+ BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
-+ if (gpio_chips[alias_idx]) {
-+ ret = -EBUSY;
-+ goto err;
-+ }
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ ret = -ENOENT;
-+ goto err;
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0) {
-+ ret = irq;
-+ goto err;
-+ }
-+
-+ at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
-+ if (!at91_chip) {
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
-+ if (!at91_chip->regbase) {
-+ dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
-+ ret = -EBUSY;
-+ goto err;
-+ }
-+
-+ at91_chip->ops =
-+ of_match_device(at91_gpio_of_match, &pdev->dev)->data;
-+ at91_chip->pioc_virq = irq;
-+ at91_chip->pioc_idx = alias_idx;
-+
-+ at91_chip->clock = clk_get(&pdev->dev, NULL);
-+ if (IS_ERR(at91_chip->clock)) {
-+ dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
-+ goto err;
-+ }
-+
-+ if (clk_prepare(at91_chip->clock))
-+ goto clk_prep_err;
-+
-+ /* enable PIO controller's clock */
-+ if (clk_enable(at91_chip->clock)) {
-+ dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
-+ goto clk_err;
-+ }
-+
-+ at91_chip->chip = at91_gpio_template;
-+
-+ chip = &at91_chip->chip;
-+ chip->of_node = np;
-+ chip->label = dev_name(&pdev->dev);
-+ chip->dev = &pdev->dev;
-+ chip->owner = THIS_MODULE;
-+ chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
-+
-+ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
-+ if (ngpio >= MAX_NB_GPIO_PER_BANK)
-+ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
-+ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
-+ else
-+ chip->ngpio = ngpio;
-+ }
-+
-+ range = &at91_chip->range;
-+ range->name = chip->label;
-+ range->id = alias_idx;
-+ range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
-+
-+ range->npins = chip->ngpio;
-+ range->gc = chip;
-+
-+ ret = gpiochip_add(chip);
-+ if (ret)
-+ goto clk_err;
-+
-+ gpio_chips[alias_idx] = at91_chip;
-+ gpio_banks = max(gpio_banks, alias_idx + 1);
-+
-+ at91_gpio_probe_fixup();
-+
-+ at91_gpio_of_irq_setup(np, at91_chip);
-+
-+ dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
-+
-+ return 0;
-+
-+clk_err:
-+ clk_unprepare(at91_chip->clock);
-+clk_prep_err:
-+ clk_put(at91_chip->clock);
-+err:
-+ dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
-+
-+ return ret;
-+}
-+
-+static struct platform_driver at91_gpio_driver = {
-+ .driver = {
-+ .name = "gpio-at91",
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(at91_gpio_of_match),
-+ },
-+ .probe = at91_gpio_probe,
-+};
-+
-+static struct platform_driver at91_pinctrl_driver = {
-+ .driver = {
-+ .name = "pinctrl-at91",
-+ .owner = THIS_MODULE,
-+ .of_match_table = of_match_ptr(at91_pinctrl_of_match),
-+ },
-+ .probe = at91_pinctrl_probe,
-+ .remove = __devexit_p(at91_pinctrl_remove),
-+};
-+
-+static int __init at91_pinctrl_init(void)
-+{
-+ int ret;
-+
-+ ret = platform_driver_register(&at91_gpio_driver);
-+ if (ret)
-+ return ret;
-+ return platform_driver_register(&at91_pinctrl_driver);
-+}
-+arch_initcall(at91_pinctrl_init);
-+
-+static void __exit at91_pinctrl_exit(void)
-+{
-+ platform_driver_unregister(&at91_pinctrl_driver);
-+}
-+
-+module_exit(at91_pinctrl_exit);
-+MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
-+MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
-+MODULE_LICENSE("GPL v2");
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From a72342c1ce82d49f1c725078239d6e5d7dfad170 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Thu, 18 Oct 2012 17:48:34 +0200
+Subject: ARM: at91: add pinctrl support
+
+This is also include the gpio controller as the IP share both.
+Each soc will have to describe the SoC limitation and pin configuration via
+DT.
+
+This will allow to do not need to touch the C code when adding new SoC if the
+IP version is supported.
+
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+Conflicts:
+ arch/arm/mach-at91/board-dt.c
+---
+ .../bindings/pinctrl/atmel,at91-pinctrl.txt | 84 ++
+ arch/arm/Kconfig | 2 +
+ arch/arm/mach-at91/board-dt.c | 2 -
+ arch/arm/mach-at91/gpio.c | 165 +--
+ drivers/pinctrl/Kconfig | 9 +
+ drivers/pinctrl/Makefile | 1 +
+ drivers/pinctrl/pinctrl-at91.c | 1490 ++++++++++++++++++++
+ 7 files changed, 1591 insertions(+), 162 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+ create mode 100644 drivers/pinctrl/pinctrl-at91.c
+
+diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+new file mode 100644
+index 0000000..0296ef4
+--- /dev/null
++++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+@@ -0,0 +1,84 @@
++* Atmel AT91 Pinmux Controller
++
++The AT91 Pinmux Controler, enables the IC
++to share one PAD to several functional blocks. The sharing is done by
++multiplexing the PAD input/output signals. For each PAD there are up to
++8 muxing options (called periph modes). Since different modules require
++different PAD settings (like pull up, keeper, etc) the contoller controls
++also the PAD settings parameters.
++
++Please refer to pinctrl-bindings.txt in this directory for details of the
++common pinctrl bindings used by client devices, including the meaning of the
++phrase "pin configuration node".
++
++Atmel AT91 pin configuration node is a node of a group of pins which can be
++used for a specific device or function. This node represents both mux and config
++of the pins in that group. The 'pins' selects the function mode(also named pin
++mode) this pin can work on and the 'config' configures various pad settings
++such as pull-up, multi drive, etc.
++
++Required properties for iomux controller:
++- compatible: "atmel,at91rm9200-pinctrl"
++- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
++ configured in this periph mode. All the periph and bank need to be describe.
++
++Required properties for pin configuration node:
++- atmel,pins: 4 integers array, represents a group of pins mux and config
++ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
++ The PERIPH 0 means gpio.
++
++Bits used for CONFIG:
++PULL_UP(1 << 0): indicate this pin need a pull up.
++MULTIDRIVE(1 << 1): indicate this pin need to be configured as multidrive.
++
++NOTE:
++Some requirements for using atmel,at91rm9200-pinctrl binding:
++1. We have pin function node defined under at91 controller node to represent
++ what pinmux functions this SoC supports.
++2. The pin configuration node intends to work on a specific function should
++ to be defined under that specific function node.
++ The function node's name should represent well about what function
++ this group of pins in this pin configuration node are working on.
++3. The driver can use the function node's name and pin configuration node's
++ name describe the pin function and group hierarchy.
++ For example, Linux Iat91 pinctrl driver takes the function node's name
++ as the function name and pin configuration node's name as group name to
++ create the map table.
++4. Each pin configuration node should have a phandle, devices can set pins
++ configurations by referring to the phandle of that pin configuration node.
++5. The gpio controller must be describe in the pinctrl simple-bus.
++
++Examples:
++
++pinctrl@fffff400 {
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ reg = <0xfffff400 0x600>;
++
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++ >;
++
++ /* shared pinctrl settings */
++ dbgu {
++ pinctrl_dbgu: dbgu-0 {
++ atmel,pins =
++ <1 14 0x1 0x0 /* PB14 periph A */
++ 1 15 0x1 0x1>; /* PB15 periph with pullup */
++ };
++ };
++};
++
++dbgu: serial@fffff200 {
++ compatible = "atmel,at91sam9260-usart";
++ reg = <0xfffff200 0x200>;
++ interrupts = <1 4 7>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_dbgu>;
++ status = "disabled";
++};
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index ddef021..ea72f88 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -339,6 +339,8 @@ config ARCH_AT91
+ select CLKDEV_LOOKUP
+ select IRQ_DOMAIN
+ select NEED_MACH_IO_H if PCCARD
++ select PINCTRL
++ select PINCTRL_AT91 if USE_OF
+ help
+ This enables support for systems based on Atmel
+ AT91RM9200 and AT91SAM9* processors.
+diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
+index c0d242c..b1a5d3c 100644
+--- a/arch/arm/mach-at91/board-dt.c
++++ b/arch/arm/mach-at91/board-dt.c
+@@ -127,8 +127,6 @@ struct of_dev_auxdata at91_auxdata_lookup[] __initdata = {
+ static const struct of_device_id irq_of_match[] __initconst = {
+
+ { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+- { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
+- { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
+ { /*sentinel*/ }
+ };
+
+diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
+index a34f0ed..c5d7e1e 100644
+--- a/arch/arm/mach-at91/gpio.c
++++ b/arch/arm/mach-at91/gpio.c
+@@ -23,8 +23,6 @@
+ #include <linux/io.h>
+ #include <linux/irqdomain.h>
+ #include <linux/of_address.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_gpio.h>
+
+ #include <asm/mach/irq.h>
+
+@@ -717,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
+ */
+ static struct lock_class_key gpio_lock_class;
+
+-#if defined(CONFIG_OF)
+-static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+- irq_hw_number_t hw)
+-{
+- struct at91_gpio_chip *at91_gpio = h->host_data;
+-
+- irq_set_lockdep_class(virq, &gpio_lock_class);
+-
+- /*
+- * Can use the "simple" and not "edge" handler since it's
+- * shorter, and the AIC handles interrupts sanely.
+- */
+- irq_set_chip_and_handler(virq, &gpio_irqchip,
+- handle_simple_irq);
+- set_irq_flags(virq, IRQF_VALID);
+- irq_set_chip_data(virq, at91_gpio);
+-
+- return 0;
+-}
+-
+-static struct irq_domain_ops at91_gpio_ops = {
+- .map = at91_gpio_irq_map,
+- .xlate = irq_domain_xlate_twocell,
+-};
+-
+-int __init at91_gpio_of_irq_setup(struct device_node *node,
+- struct device_node *parent)
+-{
+- struct at91_gpio_chip *prev = NULL;
+- int alias_idx = of_alias_get_id(node, "gpio");
+- struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx];
+-
+- /* Setup proper .irq_set_type function */
+- if (has_pio3())
+- gpio_irqchip.irq_set_type = alt_gpio_irq_type;
+- else
+- gpio_irqchip.irq_set_type = gpio_irq_type;
+-
+- /* Disable irqs of this PIO controller */
+- __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
+-
+- /* Setup irq domain */
+- at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+- &at91_gpio_ops, at91_gpio);
+- if (!at91_gpio->domain)
+- panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+- at91_gpio->pioc_idx);
+-
+- /* Setup chained handler */
+- if (at91_gpio->pioc_idx)
+- prev = &gpio_chip[at91_gpio->pioc_idx - 1];
+-
+- /* The toplevel handler handles one bank of GPIOs, except
+- * on some SoC it can handles up to three...
+- * We only set up the handler for the first of the list.
+- */
+- if (prev && prev->next == at91_gpio)
+- return 0;
+-
+- at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
+- at91_gpio->pioc_hwirq);
+- irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+- irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+-
+- return 0;
+-}
+-#else
+-int __init at91_gpio_of_irq_setup(struct device_node *node,
+- struct device_node *parent)
+-{
+- return -EINVAL;
+-}
+-#endif
+-
+ /*
+ * irqdomain initialization: pile up irqdomains on top of AIC range
+ */
+@@ -989,85 +913,6 @@ err:
+ return -EINVAL;
+ }
+
+-#ifdef CONFIG_OF_GPIO
+-static void __init of_at91_gpio_init_one(struct device_node *np)
+-{
+- int alias_idx;
+- struct at91_gpio_chip *at91_gpio;
+- uint32_t ngpio;
+-
+- if (!np)
+- return;
+-
+- alias_idx = of_alias_get_id(np, "gpio");
+- if (alias_idx >= MAX_GPIO_BANKS) {
+- pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
+- alias_idx, MAX_GPIO_BANKS);
+- return;
+- }
+-
+- at91_gpio = &gpio_chip[alias_idx];
+- at91_gpio->chip.base = alias_idx * MAX_NB_GPIO_PER_BANK;
+-
+- at91_gpio->regbase = of_iomap(np, 0);
+- if (!at91_gpio->regbase) {
+- pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
+- alias_idx);
+- return;
+- }
+-
+- /* Get the interrupts property */
+- if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
+- pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
+- alias_idx);
+- goto ioremap_err;
+- }
+-
+- /* Get capabilities from compatibility property */
+- if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
+- at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
+-
+- if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
+- if (ngpio >= MAX_NB_GPIO_PER_BANK)
+- pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
+- alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
+- else
+- at91_gpio->chip.ngpio = ngpio;
+- }
+-
+- /* Setup clock */
+- if (at91_gpio_setup_clk(alias_idx))
+- goto ioremap_err;
+-
+- at91_gpio->chip.of_node = np;
+- gpio_banks = max(gpio_banks, alias_idx + 1);
+- at91_gpio->pioc_idx = alias_idx;
+- return;
+-
+-ioremap_err:
+- iounmap(at91_gpio->regbase);
+-}
+-
+-static int __init of_at91_gpio_init(void)
+-{
+- struct device_node *np = NULL;
+-
+- /*
+- * This isn't ideal, but it gets things hooked up until this
+- * driver is converted into a platform_device
+- */
+- for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
+- of_at91_gpio_init_one(np);
+-
+- return gpio_banks > 0 ? 0 : -EINVAL;
+-}
+-#else
+-static int __init of_at91_gpio_init(void)
+-{
+- return -EINVAL;
+-}
+-#endif
+-
+ static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
+ {
+ struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
+@@ -1102,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
+
+ BUG_ON(nr_banks > MAX_GPIO_BANKS);
+
+- if (of_at91_gpio_init() < 0) {
+- /* No GPIO controller found in device tree */
+- for (i = 0; i < nr_banks; i++)
+- at91_gpio_init_one(i, data[i].regbase, data[i].id);
+- }
++ if (of_have_populated_dt())
++ return;
++
++ for (i = 0; i < nr_banks; i++)
++ at91_gpio_init_one(i, data[i].regbase, data[i].id);
+
+ for (i = 0; i < gpio_banks; i++) {
+ at91_gpio = &gpio_chip[i];
+diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
+index f73a5ea..6a03072 100644
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
+ help
+ Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+
++config PINCTRL_AT91
++ bool "AT91 pinctrl driver"
++ depends on OF
++ depends on ARCH_AT91
++ select PINMUX
++ select PINCONF
++ help
++ Say Y here to enable the at91 pinctrl driver
++
+ config PINCTRL_PXA3xx
+ bool
+ select PINMUX
+diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
+index 8e3c95a..84f4670 100644
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
+ obj-$(CONFIG_PINCTRL) += devicetree.o
+ endif
+ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
++obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
+ obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
+ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
+ obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+new file mode 100644
+index 0000000..e4712d1
+--- /dev/null
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -0,0 +1,1490 @@
++/*
++ * at91 pinctrl driver based on at91 pinmux core
++ *
++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
++ *
++ * Under GPLv2 only
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/irqdomain.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/irqdomain.h>
++#include <linux/pinctrl/machine.h>
++#include <linux/pinctrl/pinconf.h>
++#include <linux/pinctrl/pinctrl.h>
++#include <linux/pinctrl/pinmux.h>
++/* Since we request GPIOs from ourself */
++#include <linux/pinctrl/consumer.h>
++
++#include <asm/mach/irq.h>
++
++#include <mach/hardware.h>
++#include <mach/at91_pio.h>
++
++#include "core.h"
++
++#define MAX_NB_GPIO_PER_BANK 32
++
++struct at91_pinctrl_mux_ops;
++
++struct at91_gpio_chip {
++ struct gpio_chip chip;
++ struct pinctrl_gpio_range range;
++ struct at91_gpio_chip *next; /* Bank sharing same clock */
++ int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
++ int pioc_virq; /* PIO bank Linux virtual interrupt */
++ int pioc_idx; /* PIO bank index */
++ void __iomem *regbase; /* PIO bank virtual address */
++ struct clk *clock; /* associated clock */
++ struct irq_domain *domain; /* associated irq domain */
++ struct at91_pinctrl_mux_ops *ops; /* ops */
++};
++
++#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
++
++static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
++
++static int gpio_banks;
++
++#define PULL_UP (0 << 1)
++#define MULTI_DRIVE (1 << 1)
++
++/**
++ * struct at91_pmx_func - describes AT91 pinmux functions
++ * @name: the name of this specific function
++ * @groups: corresponding pin groups
++ * @ngroups: the number of groups
++ */
++struct at91_pmx_func {
++ const char *name;
++ const char **groups;
++ unsigned ngroups;
++};
++
++enum at91_mux {
++ AT91_MUX_GPIO = 0,
++ AT91_MUX_PERIPH_A = 1,
++ AT91_MUX_PERIPH_B = 2,
++ AT91_MUX_PERIPH_C = 3,
++ AT91_MUX_PERIPH_D = 4,
++};
++
++/**
++ * struct at91_pmx_pin - describes an At91 pin mux
++ * @bank: the bank of the pin
++ * @pin: the pin number in the @bank
++ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
++ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
++ */
++struct at91_pmx_pin {
++ uint32_t bank;
++ uint32_t pin;
++ enum at91_mux mux;
++ unsigned long conf;
++};
++
++/**
++ * struct at91_pin_group - describes an At91 pin group
++ * @name: the name of this specific pin group
++ * @pins_conf: the mux mode for each pin in this group. The size of this
++ * array is the same as pins.
++ * @pins: an array of discrete physical pins used in this group, taken
++ * from the driver-local pin enumeration space
++ * @npins: the number of pins in this group array, i.e. the number of
++ * elements in .pins so we can iterate over that array
++ */
++struct at91_pin_group {
++ const char *name;
++ struct at91_pmx_pin *pins_conf;
++ unsigned int *pins;
++ unsigned npins;
++};
++
++/**
++ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
++ * on new IP with support for periph C and D the way to mux in
++ * periph A and B has changed
++ * So provide the right call back
++ * if not present means the IP does not support it
++ * @get_periph: return the periph mode configured
++ * @mux_A_periph: mux as periph A
++ * @mux_B_periph: mux as periph B
++ * @mux_C_periph: mux as periph C
++ * @mux_D_periph: mux as periph D
++ * @irq_type: return irq type
++ */
++struct at91_pinctrl_mux_ops {
++ enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_A_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
++ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
++ /* irq */
++ int (*irq_type)(struct irq_data *d, unsigned type);
++};
++
++static int gpio_irq_type(struct irq_data *d, unsigned type);
++static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
++
++struct at91_pinctrl {
++ struct device *dev;
++ struct pinctrl_dev *pctl;
++
++ int nbanks;
++
++ uint32_t *mux_mask;
++ int nmux;
++
++ struct at91_pmx_func *functions;
++ int nfunctions;
++
++ struct at91_pin_group *groups;
++ int ngroups;
++
++ struct at91_pinctrl_mux_ops *ops;
++};
++
++static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
++ const struct at91_pinctrl *info,
++ const char *name)
++{
++ const struct at91_pin_group *grp = NULL;
++ int i;
++
++ for (i = 0; i < info->ngroups; i++) {
++ if (strcmp(info->groups[i].name, name))
++ continue;
++
++ grp = &info->groups[i];
++ dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
++ break;
++ }
++
++ return grp;
++}
++
++static int at91_get_groups_count(struct pinctrl_dev *pctldev)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->ngroups;
++}
++
++static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
++ unsigned selector)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->groups[selector].name;
++}
++
++static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
++ const unsigned **pins,
++ unsigned *npins)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ if (selector >= info->ngroups)
++ return -EINVAL;
++
++ *pins = info->groups[selector].pins;
++ *npins = info->groups[selector].npins;
++
++ return 0;
++}
++
++static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
++ unsigned offset)
++{
++ seq_printf(s, "%s", dev_name(pctldev->dev));
++}
++
++static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
++ struct device_node *np,
++ struct pinctrl_map **map, unsigned *num_maps)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pin_group *grp;
++ struct pinctrl_map *new_map;
++ struct device_node *parent;
++ int map_num = 1;
++ int i;
++ struct at91_pmx_pin *pin;
++
++ /*
++ * first find the group of this node and check if we need create
++ * config maps for pins
++ */
++ grp = at91_pinctrl_find_group_by_name(info, np->name);
++ if (!grp) {
++ dev_err(info->dev, "unable to find group for node %s\n",
++ np->name);
++ return -EINVAL;
++ }
++
++ map_num += grp->npins;
++ new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
++ if (!new_map)
++ return -ENOMEM;
++
++ *map = new_map;
++ *num_maps = map_num;
++
++ /* create mux map */
++ parent = of_get_parent(np);
++ if (!parent) {
++ kfree(new_map);
++ return -EINVAL;
++ }
++ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
++ new_map[0].data.mux.function = parent->name;
++ new_map[0].data.mux.group = np->name;
++ of_node_put(parent);
++
++ /* create config map */
++ new_map++;
++ for (i = 0; i < grp->npins; i++) {
++ pin = &grp->pins_conf[i];
++
++ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
++ new_map[i].data.configs.group_or_pin =
++ pin_get_name(pctldev, grp->pins[i]);
++ new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
++ new_map[i].data.configs.num_configs = 1;
++ }
++
++ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
++ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
++
++ return 0;
++}
++
++static void at91_dt_free_map(struct pinctrl_dev *pctldev,
++ struct pinctrl_map *map, unsigned num_maps)
++{
++}
++
++static struct pinctrl_ops at91_pctrl_ops = {
++ .get_groups_count = at91_get_groups_count,
++ .get_group_name = at91_get_group_name,
++ .get_group_pins = at91_get_group_pins,
++ .pin_dbg_show = at91_pin_dbg_show,
++ .dt_node_to_map = at91_dt_node_to_map,
++ .dt_free_map = at91_dt_free_map,
++};
++
++static void __iomem * pin_to_controller(struct at91_pinctrl *info,
++ unsigned int bank)
++{
++ return gpio_chips[bank]->regbase;
++}
++
++static inline int pin_to_bank(unsigned pin)
++{
++ return pin /= MAX_NB_GPIO_PER_BANK;
++}
++
++static unsigned pin_to_mask(unsigned int pin)
++{
++ return 1 << pin;
++}
++
++static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_IDR);
++}
++
++static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
++{
++ return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
++}
++
++static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
++{
++ writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
++}
++
++static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
++{
++ return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
++}
++
++static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
++{
++ writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
++}
++
++static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_ASR);
++}
++
++static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_BSR);
++}
++
++static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
++{
++
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
++ pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
++ pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
++ pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++}
++
++static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
++ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
++}
++
++static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
++{
++ unsigned select;
++
++ if (readl_relaxed(pio + PIO_PSR) & mask)
++ return AT91_MUX_GPIO;
++
++ select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
++ select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
++
++ return select + 1;
++}
++
++static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
++{
++ unsigned select;
++
++ if (readl_relaxed(pio + PIO_PSR) & mask)
++ return AT91_MUX_GPIO;
++
++ select = readl_relaxed(pio + PIO_ABSR) & mask;
++
++ return select + 1;
++}
++
++static struct at91_pinctrl_mux_ops at91rm9200_ops = {
++ .get_periph = at91_mux_get_periph,
++ .mux_A_periph = at91_mux_set_A_periph,
++ .mux_B_periph = at91_mux_set_B_periph,
++ .irq_type = gpio_irq_type,
++};
++
++static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
++ .get_periph = at91_mux_pio3_get_periph,
++ .mux_A_periph = at91_mux_pio3_set_A_periph,
++ .mux_B_periph = at91_mux_pio3_set_B_periph,
++ .mux_C_periph = at91_mux_pio3_set_C_periph,
++ .mux_D_periph = at91_mux_pio3_set_D_periph,
++ .irq_type = alt_gpio_irq_type,
++};
++
++static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
++{
++ if (pin->mux) {
++ dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
++ pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
++ } else {
++ dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
++ pin->bank + 'A', pin->pin, pin->conf);
++ }
++}
++
++static int pin_check_config(struct at91_pinctrl *info, const char* name,
++ int index, const struct at91_pmx_pin *pin)
++{
++ int mux;
++
++ /* check if it's a valid config */
++ if (pin->bank >= info->nbanks) {
++ dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
++ name, index, pin->bank, info->nbanks);
++ return -EINVAL;
++ }
++
++ if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
++ dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
++ name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
++ return -EINVAL;
++ }
++
++ if (!pin->mux)
++ return 0;
++
++ mux = pin->mux - 1;
++
++ if (mux >= info->nmux) {
++ dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
++ name, index, mux, info->nmux);
++ return -EINVAL;
++ }
++
++ if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
++ dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
++ name, index, mux, pin->bank + 'A', pin->pin);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
++{
++ writel_relaxed(mask, pio + PIO_PDR);
++}
++
++static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
++{
++ writel_relaxed(mask, pio + PIO_PER);
++ writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
++}
++
++static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
++ unsigned group)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
++ const struct at91_pmx_pin *pin;
++ uint32_t npins = info->groups[group].npins;
++ int i, ret;
++ unsigned mask;
++ void __iomem *pio;
++
++ dev_dbg(info->dev, "enable function %s group %s\n",
++ info->functions[selector].name, info->groups[group].name);
++
++ /* first check that all the pins of the group are valid with a valid
++ * paramter */
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ ret = pin_check_config(info, info->groups[group].name, i, pin);
++ if (ret)
++ return ret;
++ }
++
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ at91_pin_dbg(info->dev, pin);
++ pio = pin_to_controller(info, pin->bank);
++ mask = pin_to_mask(pin->pin);
++ at91_mux_disable_interrupt(pio, mask);
++ switch(pin->mux) {
++ case AT91_MUX_GPIO:
++ at91_mux_gpio_enable(pio, mask, 1);
++ break;
++ case AT91_MUX_PERIPH_A:
++ info->ops->mux_A_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_B:
++ info->ops->mux_B_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_C:
++ if (!info->ops->mux_C_periph)
++ return -EINVAL;
++ info->ops->mux_C_periph(pio, mask);
++ break;
++ case AT91_MUX_PERIPH_D:
++ if (!info->ops->mux_D_periph)
++ return -EINVAL;
++ info->ops->mux_D_periph(pio, mask);
++ break;
++ }
++ if (pin->mux)
++ at91_mux_gpio_disable(pio, mask);
++ }
++
++ return 0;
++}
++
++static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
++ unsigned group)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
++ const struct at91_pmx_pin *pin;
++ uint32_t npins = info->groups[group].npins;
++ int i;
++ unsigned mask;
++ void __iomem *pio;
++
++ for (i = 0; i < npins; i++) {
++ pin = &pins_conf[i];
++ at91_pin_dbg(info->dev, pin);
++ pio = pin_to_controller(info, pin->bank);
++ mask = pin_to_mask(pin->pin);
++ at91_mux_gpio_enable(pio, mask, 1);
++ }
++}
++
++static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->nfunctions;
++}
++
++static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
++ unsigned selector)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ return info->functions[selector].name;
++}
++
++static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
++ const char * const **groups,
++ unsigned * const num_groups)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++
++ *groups = info->functions[selector].groups;
++ *num_groups = info->functions[selector].ngroups;
++
++ return 0;
++}
++
++int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned offset)
++{
++ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
++ struct at91_gpio_chip *at91_chip;
++ struct gpio_chip *chip;
++ unsigned mask;
++
++ if (!range) {
++ dev_err(npct->dev, "invalid range\n");
++ return -EINVAL;
++ }
++ if (!range->gc) {
++ dev_err(npct->dev, "missing GPIO chip in range\n");
++ return -EINVAL;
++ }
++ chip = range->gc;
++ at91_chip = container_of(chip, struct at91_gpio_chip, chip);
++
++ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
++
++ mask = 1 << (offset - chip->base);
++
++ dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
++ offset, 'A' + range->id, offset - chip->base, mask);
++
++ writel_relaxed(mask, at91_chip->regbase + PIO_PER);
++
++ return 0;
++}
++
++void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
++ struct pinctrl_gpio_range *range,
++ unsigned offset)
++{
++ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
++
++ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
++ /* Set the pin to some default state, GPIO is usually default */
++}
++
++static struct pinmux_ops at91_pmx_ops = {
++ .get_functions_count = at91_pmx_get_funcs_count,
++ .get_function_name = at91_pmx_get_func_name,
++ .get_function_groups = at91_pmx_get_groups,
++ .enable = at91_pmx_enable,
++ .disable = at91_pmx_disable,
++ .gpio_request_enable = at91_gpio_request_enable,
++ .gpio_disable_free = at91_gpio_disable_free,
++};
++
++static int at91_pinconf_get(struct pinctrl_dev *pctldev,
++ unsigned pin_id, unsigned long *config)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ void __iomem *pio;
++ unsigned pin;
++
++ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
++ pio = pin_to_controller(info, pin_to_bank(pin_id));
++ pin = pin_id % MAX_NB_GPIO_PER_BANK;
++
++ if (at91_mux_get_multidrive(pio, pin))
++ *config |= MULTI_DRIVE;
++
++ if (at91_mux_get_pullup(pio, pin))
++ *config |= PULL_UP;
++
++ return 0;
++}
++
++static int at91_pinconf_set(struct pinctrl_dev *pctldev,
++ unsigned pin_id, unsigned long config)
++{
++ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
++ unsigned mask;
++ void __iomem *pio;
++
++ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
++ pio = pin_to_controller(info, pin_to_bank(pin_id));
++ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
++
++ at91_mux_set_pullup(pio, mask, config & PULL_UP);
++ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
++ return 0;
++}
++
++static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
++ struct seq_file *s, unsigned pin_id)
++{
++
++}
++
++static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
++ struct seq_file *s, unsigned group)
++{
++}
++
++struct pinconf_ops at91_pinconf_ops = {
++ .pin_config_get = at91_pinconf_get,
++ .pin_config_set = at91_pinconf_set,
++ .pin_config_dbg_show = at91_pinconf_dbg_show,
++ .pin_config_group_dbg_show = at91_pinconf_group_dbg_show,
++};
++
++static struct pinctrl_desc at91_pinctrl_desc = {
++ .pctlops = &at91_pctrl_ops,
++ .pmxops = &at91_pmx_ops,
++ .confops = &at91_pinconf_ops,
++ .owner = THIS_MODULE,
++};
++
++static const char *gpio_compat = "atmel,at91rm9200-gpio";
++
++static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
++ struct device_node *np)
++{
++ struct device_node *child;
++
++ for_each_child_of_node(np, child) {
++ if (of_device_is_compatible(child, gpio_compat)) {
++ info->nbanks++;
++ } else {
++ info->nfunctions++;
++ info->ngroups += of_get_child_count(child);
++ }
++ }
++}
++
++static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
++ struct device_node *np)
++{
++ int ret = 0;
++ int size;
++ const const __be32 *list;
++
++ list = of_get_property(np, "atmel,mux-mask", &size);
++ if (!list) {
++ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
++ return -EINVAL;
++ }
++
++ size /= sizeof(*list);
++ if (!size || size % info->nbanks) {
++ dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
++ return -EINVAL;
++ }
++ info->nmux = size / info->nbanks;
++
++ info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
++ if (!info->mux_mask) {
++ dev_err(info->dev, "could not alloc mux_mask\n");
++ return -ENOMEM;
++ }
++
++ ret = of_property_read_u32_array(np, "atmel,mux-mask",
++ info->mux_mask, size);
++ if (ret)
++ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
++ return ret;
++}
++
++static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
++ struct at91_pin_group *grp,
++ struct at91_pinctrl *info,
++ u32 index)
++{
++ struct at91_pmx_pin *pin;
++ int size;
++ const const __be32 *list;
++ int i, j;
++
++ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
++
++ /* Initialise group */
++ grp->name = np->name;
++
++ /*
++ * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
++ * do sanity check and calculate pins number
++ */
++ list = of_get_property(np, "atmel,pins", &size);
++ /* we do not check return since it's safe node passed down */
++ size /= sizeof(*list);
++ if (!size || size % 4) {
++ dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
++ return -EINVAL;
++ }
++
++ grp->npins = size / 4;
++ pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
++ GFP_KERNEL);
++ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
++ GFP_KERNEL);
++ if (!grp->pins_conf || !grp->pins)
++ return -ENOMEM;
++
++ for (i = 0, j = 0; i < size; i += 4, j++) {
++ pin->bank = be32_to_cpu(*list++);
++ pin->pin = be32_to_cpu(*list++);
++ grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
++ pin->mux = be32_to_cpu(*list++);
++ pin->conf = be32_to_cpu(*list++);
++
++ at91_pin_dbg(info->dev, pin);
++ pin++;
++ }
++
++ return 0;
++}
++
++static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
++ struct at91_pinctrl *info, u32 index)
++{
++ struct device_node *child;
++ struct at91_pmx_func *func;
++ struct at91_pin_group *grp;
++ int ret;
++ static u32 grp_index;
++ u32 i = 0;
++
++ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
++
++ func = &info->functions[index];
++
++ /* Initialise function */
++ func->name = np->name;
++ func->ngroups = of_get_child_count(np);
++ if (func->ngroups <= 0) {
++ dev_err(info->dev, "no groups defined\n");
++ return -EINVAL;
++ }
++ func->groups = devm_kzalloc(info->dev,
++ func->ngroups * sizeof(char *), GFP_KERNEL);
++ if (!func->groups)
++ return -ENOMEM;
++
++ for_each_child_of_node(np, child) {
++ func->groups[i] = child->name;
++ grp = &info->groups[grp_index++];
++ ret = at91_pinctrl_parse_groups(child, grp, info, i++);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
++ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
++ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
++ { /* sentinel */ }
++};
++
++static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
++ struct at91_pinctrl *info)
++{
++ int ret = 0;
++ int i, j;
++ uint32_t *tmp;
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *child;
++
++ if (!np)
++ return -ENODEV;
++
++ info->dev = &pdev->dev;
++ info->ops =
++ of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
++ at91_pinctrl_child_count(info, np);
++
++ if (info->nbanks < 1) {
++ dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
++ return -EINVAL;
++ }
++
++ ret = at91_pinctrl_mux_mask(info, np);
++ if (ret)
++ return ret;
++
++ dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
++
++ dev_dbg(&pdev->dev, "mux-mask\n");
++ tmp = info->mux_mask;
++ for (i = 0; i < info->nbanks; i++) {
++ for (j = 0; j < info->nmux; j++, tmp++) {
++ dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
++ }
++ }
++
++ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
++ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
++ info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
++ GFP_KERNEL);
++ if (!info->functions)
++ return -ENOMEM;
++
++ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
++ GFP_KERNEL);
++ if (!info->groups)
++ return -ENOMEM;
++
++ dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
++ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
++ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
++
++ i = 0;
++
++ for_each_child_of_node(np, child) {
++ if (of_device_is_compatible(child, gpio_compat))
++ continue;
++ ret = at91_pinctrl_parse_functions(child, info, i++);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to parse function\n");
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
++{
++ struct at91_pinctrl *info;
++ struct pinctrl_pin_desc *pdesc;
++ int ret, i, j ,k;
++
++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ ret = at91_pinctrl_probe_dt(pdev, info);
++ if (ret)
++ return ret;
++
++ /*
++ * We need all the GPIO drivers to probe FIRST, or we will not be able
++ * to obtain references to the struct gpio_chip * for them, and we
++ * need this to proceed.
++ */
++ for (i = 0; i < info->nbanks; i++) {
++ if (!gpio_chips[i]) {
++ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
++ devm_kfree(&pdev->dev, info);
++ return -EPROBE_DEFER;
++ }
++ }
++
++ at91_pinctrl_desc.name = dev_name(&pdev->dev);
++ at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
++ at91_pinctrl_desc.pins = pdesc =
++ devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
++
++ if (!at91_pinctrl_desc.pins)
++ return -ENOMEM;
++
++ for (i = 0 , k = 0; i < info->nbanks; i++) {
++ for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
++ pdesc->number = k;
++ pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
++ pdesc++;
++ }
++ }
++
++ platform_set_drvdata(pdev, info);
++ info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
++
++ if (!info->pctl) {
++ dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
++ ret = -EINVAL;
++ goto err;
++ }
++
++ /* We will handle a range of GPIO pins */
++ for (i = 0; i < info->nbanks; i++)
++ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
++
++ dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
++
++ return 0;
++
++err:
++ return ret;
++}
++
++int __devexit at91_pinctrl_remove(struct platform_device *pdev)
++{
++ struct at91_pinctrl *info = platform_get_drvdata(pdev);
++
++ pinctrl_unregister(info->pctl);
++
++ return 0;
++}
++
++static int at91_gpio_request(struct gpio_chip *chip, unsigned offset)
++{
++ /*
++ * Map back to global GPIO space and request muxing, the direction
++ * parameter does not matter for this controller.
++ */
++ int gpio = chip->base + offset;
++ int bank = chip->base / chip->ngpio;
++
++ dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
++ 'A' + bank, offset, gpio);
++
++ return pinctrl_request_gpio(gpio);
++}
++
++static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
++{
++ int gpio = chip->base + offset;
++
++ pinctrl_free_gpio(gpio);
++}
++
++static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + PIO_ODR);
++ return 0;
++}
++
++static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++ u32 pdsr;
++
++ pdsr = readl_relaxed(pio + PIO_PDSR);
++ return (pdsr & mask) != 0;
++}
++
++static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
++ int val)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
++}
++
++static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
++ int val)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << offset;
++
++ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
++ writel_relaxed(mask, pio + PIO_OER);
++
++ return 0;
++}
++
++static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ int virq;
++
++ if (offset < chip->ngpio)
++ virq = irq_create_mapping(at91_gpio->domain, offset);
++ else
++ virq = -ENXIO;
++
++ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
++ chip->label, offset + chip->base, virq);
++ return virq;
++}
++
++#ifdef CONFIG_DEBUG_FS
++static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
++{
++ enum at91_mux mode;
++ int i;
++ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
++ void __iomem *pio = at91_gpio->regbase;
++
++ for (i = 0; i < chip->ngpio; i++) {
++ unsigned pin = chip->base + i;
++ unsigned mask = pin_to_mask(pin);
++ const char *gpio_label;
++ u32 pdsr;
++
++ gpio_label = gpiochip_is_requested(chip, i);
++ if (!gpio_label)
++ continue;
++ mode = at91_gpio->ops->get_periph(pio, mask);
++ seq_printf(s, "[%s] GPIO%s%d: ",
++ gpio_label, chip->label, i);
++ if (mode == AT91_MUX_GPIO) {
++ pdsr = readl_relaxed(pio + PIO_PDSR);
++
++ seq_printf(s, "[gpio] %s\n",
++ pdsr & mask ?
++ "set" : "clear");
++ } else {
++ seq_printf(s, "[periph %c]\n",
++ mode + 'A' - 1);
++ }
++ }
++}
++#else
++#define at91_gpio_dbg_show NULL
++#endif
++
++/* Several AIC controller irqs are dispatched through this GPIO handler.
++ * To use any AT91_PIN_* as an externally triggered IRQ, first call
++ * at91_set_gpio_input() then maybe enable its glitch filter.
++ * Then just request_irq() with the pin ID; it works like any ARM IRQ
++ * handler.
++ * First implementation always triggers on rising and falling edges
++ * whereas the newer PIO3 can be additionally configured to trigger on
++ * level, edge with any polarity.
++ *
++ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
++ * configuring them with at91_set_a_periph() or at91_set_b_periph().
++ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
++ */
++
++static void gpio_irq_mask(struct irq_data *d)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ if (pio)
++ writel_relaxed(mask, pio + PIO_IDR);
++}
++
++static void gpio_irq_unmask(struct irq_data *d)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ if (pio)
++ writel_relaxed(mask, pio + PIO_IER);
++}
++
++static int gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ switch (type) {
++ case IRQ_TYPE_NONE:
++ case IRQ_TYPE_EDGE_BOTH:
++ return 0;
++ default:
++ return -EINVAL;
++ }
++}
++
++/* Alternate irq type for PIO3 support */
++static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned mask = 1 << d->hwirq;
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ writel_relaxed(mask, pio + PIO_ESR);
++ writel_relaxed(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ writel_relaxed(mask, pio + PIO_ESR);
++ writel_relaxed(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ writel_relaxed(mask, pio + PIO_LSR);
++ writel_relaxed(mask, pio + PIO_FELLSR);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ writel_relaxed(mask, pio + PIO_LSR);
++ writel_relaxed(mask, pio + PIO_REHLSR);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ /*
++ * disable additional interrupt modes:
++ * fall back to default behavior
++ */
++ writel_relaxed(mask, pio + PIO_AIMDR);
++ return 0;
++ case IRQ_TYPE_NONE:
++ default:
++ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
++ return -EINVAL;
++ }
++
++ /* enable additional interrupt modes */
++ writel_relaxed(mask, pio + PIO_AIMER);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
++{
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
++ unsigned bank = at91_gpio->pioc_idx;
++
++ if (unlikely(bank >= MAX_GPIO_BANKS))
++ return -EINVAL;
++
++ irq_set_irq_wake(at91_gpio->pioc_virq, state);
++
++ return 0;
++}
++#else
++#define gpio_irq_set_wake NULL
++#endif
++
++static struct irq_chip gpio_irqchip = {
++ .name = "GPIO",
++ .irq_disable = gpio_irq_mask,
++ .irq_mask = gpio_irq_mask,
++ .irq_unmask = gpio_irq_unmask,
++ /* .irq_set_type is set dynamically */
++ .irq_set_wake = gpio_irq_set_wake,
++};
++
++static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
++{
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct irq_data *idata = irq_desc_get_irq_data(desc);
++ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
++ void __iomem *pio = at91_gpio->regbase;
++ unsigned long isr;
++ int n;
++
++ chained_irq_enter(chip, desc);
++ for (;;) {
++ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
++ * When there none are pending, we're finished unless we need
++ * to process multiple banks (like ID_PIOCDE on sam9263).
++ */
++ isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
++ if (!isr) {
++ if (!at91_gpio->next)
++ break;
++ at91_gpio = at91_gpio->next;
++ pio = at91_gpio->regbase;
++ continue;
++ }
++
++ n = find_first_bit(&isr, BITS_PER_LONG);
++ while (n < BITS_PER_LONG) {
++ generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
++ n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
++ }
++ }
++ chained_irq_exit(chip, desc);
++ /* now it may re-trigger */
++}
++
++/*
++ * This lock class tells lockdep that GPIO irqs are in a different
++ * category than their parents, so it won't report false recursion.
++ */
++static struct lock_class_key gpio_lock_class;
++
++static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct at91_gpio_chip *at91_gpio = h->host_data;
++
++ irq_set_lockdep_class(virq, &gpio_lock_class);
++
++ /*
++ * Can use the "simple" and not "edge" handler since it's
++ * shorter, and the AIC handles interrupts sanely.
++ */
++ irq_set_chip_and_handler(virq, &gpio_irqchip,
++ handle_simple_irq);
++ set_irq_flags(virq, IRQF_VALID);
++ irq_set_chip_data(virq, at91_gpio);
++
++ return 0;
++}
++
++static struct irq_domain_ops at91_gpio_ops = {
++ .map = at91_gpio_irq_map,
++ .xlate = irq_domain_xlate_twocell,
++};
++
++static int at91_gpio_of_irq_setup(struct device_node *node,
++ struct at91_gpio_chip *at91_gpio)
++{
++ struct at91_gpio_chip *prev = NULL;
++ struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
++
++ at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
++
++ /* Setup proper .irq_set_type function */
++ gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
++
++ /* Disable irqs of this PIO controller */
++ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
++
++ /* Setup irq domain */
++ at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
++ &at91_gpio_ops, at91_gpio);
++ if (!at91_gpio->domain)
++ panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
++ at91_gpio->pioc_idx);
++
++ /* Setup chained handler */
++ if (at91_gpio->pioc_idx)
++ prev = gpio_chips[at91_gpio->pioc_idx - 1];
++
++ /* The toplevel handler handles one bank of GPIOs, except
++ * on some SoC it can handles up to three...
++ * We only set up the handler for the first of the list.
++ */
++ if (prev && prev->next == at91_gpio)
++ return 0;
++
++ irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
++ irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
++
++ return 0;
++}
++
++/* This structure is replicated for each GPIO block allocated at probe time */
++static struct gpio_chip at91_gpio_template = {
++ .request = at91_gpio_request,
++ .free = at91_gpio_free,
++ .direction_input = at91_gpio_direction_input,
++ .get = at91_gpio_get,
++ .direction_output = at91_gpio_direction_output,
++ .set = at91_gpio_set,
++ .to_irq = at91_gpio_to_irq,
++ .dbg_show = at91_gpio_dbg_show,
++ .can_sleep = 0,
++ .ngpio = MAX_NB_GPIO_PER_BANK,
++};
++
++static void __devinit at91_gpio_probe_fixup(void)
++{
++ unsigned i;
++ struct at91_gpio_chip *at91_gpio, *last = NULL;
++
++ for (i = 0; i < gpio_banks; i++) {
++ at91_gpio = gpio_chips[i];
++
++ /*
++ * GPIO controller are grouped on some SoC:
++ * PIOC, PIOD and PIOE can share the same IRQ line
++ */
++ if (last && last->pioc_virq == at91_gpio->pioc_virq)
++ last->next = at91_gpio;
++ last = at91_gpio;
++ }
++}
++
++static struct of_device_id at91_gpio_of_match[] __devinitdata = {
++ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
++ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
++ { /* sentinel */ }
++};
++
++static int __devinit at91_gpio_probe(struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ struct resource *res;
++ struct at91_gpio_chip *at91_chip = NULL;
++ struct gpio_chip *chip;
++ struct pinctrl_gpio_range *range;
++ int ret = 0;
++ int irq;
++ int alias_idx = of_alias_get_id(np, "gpio");
++ uint32_t ngpio;
++
++ BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
++ if (gpio_chips[alias_idx]) {
++ ret = -EBUSY;
++ goto err;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ ret = -ENOENT;
++ goto err;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ ret = irq;
++ goto err;
++ }
++
++ at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
++ if (!at91_chip) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
++ if (!at91_chip->regbase) {
++ dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
++ ret = -EBUSY;
++ goto err;
++ }
++
++ at91_chip->ops =
++ of_match_device(at91_gpio_of_match, &pdev->dev)->data;
++ at91_chip->pioc_virq = irq;
++ at91_chip->pioc_idx = alias_idx;
++
++ at91_chip->clock = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(at91_chip->clock)) {
++ dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
++ goto err;
++ }
++
++ if (clk_prepare(at91_chip->clock))
++ goto clk_prep_err;
++
++ /* enable PIO controller's clock */
++ if (clk_enable(at91_chip->clock)) {
++ dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
++ goto clk_err;
++ }
++
++ at91_chip->chip = at91_gpio_template;
++
++ chip = &at91_chip->chip;
++ chip->of_node = np;
++ chip->label = dev_name(&pdev->dev);
++ chip->dev = &pdev->dev;
++ chip->owner = THIS_MODULE;
++ chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
++
++ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
++ if (ngpio >= MAX_NB_GPIO_PER_BANK)
++ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
++ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
++ else
++ chip->ngpio = ngpio;
++ }
++
++ range = &at91_chip->range;
++ range->name = chip->label;
++ range->id = alias_idx;
++ range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
++
++ range->npins = chip->ngpio;
++ range->gc = chip;
++
++ ret = gpiochip_add(chip);
++ if (ret)
++ goto clk_err;
++
++ gpio_chips[alias_idx] = at91_chip;
++ gpio_banks = max(gpio_banks, alias_idx + 1);
++
++ at91_gpio_probe_fixup();
++
++ at91_gpio_of_irq_setup(np, at91_chip);
++
++ dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
++
++ return 0;
++
++clk_err:
++ clk_unprepare(at91_chip->clock);
++clk_prep_err:
++ clk_put(at91_chip->clock);
++err:
++ dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
++
++ return ret;
++}
++
++static struct platform_driver at91_gpio_driver = {
++ .driver = {
++ .name = "gpio-at91",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(at91_gpio_of_match),
++ },
++ .probe = at91_gpio_probe,
++};
++
++static struct platform_driver at91_pinctrl_driver = {
++ .driver = {
++ .name = "pinctrl-at91",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(at91_pinctrl_of_match),
++ },
++ .probe = at91_pinctrl_probe,
++ .remove = __devexit_p(at91_pinctrl_remove),
++};
++
++static int __init at91_pinctrl_init(void)
++{
++ int ret;
++
++ ret = platform_driver_register(&at91_gpio_driver);
++ if (ret)
++ return ret;
++ return platform_driver_register(&at91_pinctrl_driver);
++}
++arch_initcall(at91_pinctrl_init);
++
++static void __exit at91_pinctrl_exit(void)
++{
++ platform_driver_unregister(&at91_pinctrl_driver);
++}
++
++module_exit(at91_pinctrl_exit);
++MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
++MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
++MODULE_LICENSE("GPL v2");
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From 34452935eb56aac56b666dd664766bc115b452c6 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Mon, 22 Oct 2012 16:08:50 +0200
-Subject: arm: at91: dt: at91sam9 add pinctrl support
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-
-Conflicts:
- arch/arm/mach-at91/at91sam9263.c
- arch/arm/mach-at91/at91sam9n12.c
- arch/arm/mach-at91/at91sam9x5.c
----
- .../bindings/pinctrl/atmel,at91-pinctrl.txt | 68 +++++++++++++++++++---
- arch/arm/boot/dts/at91sam9260.dtsi | 9 +++
- arch/arm/boot/dts/at91sam9263.dtsi | 12 ++++
- arch/arm/boot/dts/at91sam9g45.dtsi | 11 ++++
- arch/arm/boot/dts/at91sam9n12.dtsi | 12 +++-
- arch/arm/boot/dts/at91sam9x5.dtsi | 12 +++-
- arch/arm/configs/at91_dt_defconfig | 1 +
- arch/arm/mach-at91/at91sam9260.c | 3 +
- arch/arm/mach-at91/at91sam9263.c | 5 ++
- arch/arm/mach-at91/at91sam9g45.c | 6 ++
- arch/arm/mach-at91/at91sam9n12.c | 11 ++--
- arch/arm/mach-at91/at91sam9x5.c | 18 ++----
- arch/arm/mach-at91/setup.c | 3 +-
- drivers/pinctrl/pinctrl-at91.c | 2 +-
- 14 files changed, 140 insertions(+), 33 deletions(-)
-
-diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
-index 0296ef4..20a987e 100644
---- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
-+++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
-@@ -22,6 +22,62 @@ Required properties for iomux controller:
- - atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
- configured in this periph mode. All the periph and bank need to be describe.
-
-+How to create such array:
-+
-+Each column will represent the possible peripheral of the pinctrl
-+Each line will represent a pio bank
-+
-+Take an example on the 9260
-+Peripheral: 2 ( A and B)
-+Bank: 3 (A, B and C)
-+=>
-+
-+ /* A B */
-+ 0xffffffff 0xffc00c3b /* pioA */
-+ 0xffffffff 0x7fff3ccf /* pioB */
-+ 0xffffffff 0x007fffff /* pioC */
-+
-+For each peripheral/bank we will descibe in a u32 if a pin can can be
-+configured in it by putting 1 to the pin bit (1 << pin)
-+
-+Let's take the pioA on peripheral B
-+From the datasheet Table 10-2.
-+Peripheral B
-+PA0 MCDB0
-+PA1 MCCDB
-+PA2
-+PA3 MCDB3
-+PA4 MCDB2
-+PA5 MCDB1
-+PA6
-+PA7
-+PA8
-+PA9
-+PA10 ETX2
-+PA11 ETX3
-+PA12
-+PA13
-+PA14
-+PA15
-+PA16
-+PA17
-+PA18
-+PA19
-+PA20
-+PA21
-+PA22 ETXER
-+PA23 ETX2
-+PA24 ETX3
-+PA25 ERX2
-+PA26 ERX3
-+PA27 ERXCK
-+PA28 ECRS
-+PA29 ECOL
-+PA30 RXD4
-+PA31 TXD4
-+
-+=> 0xffc00c3b
-+
- Required properties for pin configuration node:
- - atmel,pins: 4 integers array, represents a group of pins mux and config
- setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
-@@ -35,18 +91,14 @@ NOTE:
- Some requirements for using atmel,at91rm9200-pinctrl binding:
- 1. We have pin function node defined under at91 controller node to represent
- what pinmux functions this SoC supports.
--2. The pin configuration node intends to work on a specific function should
-- to be defined under that specific function node.
-- The function node's name should represent well about what function
-- this group of pins in this pin configuration node are working on.
--3. The driver can use the function node's name and pin configuration node's
-+2. The driver can use the function node's name and pin configuration node's
- name describe the pin function and group hierarchy.
-- For example, Linux Iat91 pinctrl driver takes the function node's name
-+ For example, Linux at91 pinctrl driver takes the function node's name
- as the function name and pin configuration node's name as group name to
- create the map table.
--4. Each pin configuration node should have a phandle, devices can set pins
-+3. Each pin configuration node should have a phandle, devices can set pins
- configurations by referring to the phandle of that pin configuration node.
--5. The gpio controller must be describe in the pinctrl simple-bus.
-+4. The gpio controller must be describe in the pinctrl simple-bus.
-
- Examples:
-
-diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
-index e50261d..3654ace 100644
---- a/arch/arm/boot/dts/at91sam9260.dtsi
-+++ b/arch/arm/boot/dts/at91sam9260.dtsi
-@@ -104,6 +104,15 @@
- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfffff400 0xfffff400 0x600>;
-
-+ atmel,mux-mask = <
-+ /* A B */
-+ 0xffffffff 0xffc00c3b /* pioA */
-+ 0xffffffff 0x7fff3ccf /* pioB */
-+ 0xffffffff 0x007fffff /* pioC */
-+ >;
-+
-+ /* shared pinctrl settings */
-+
- pioA: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x200>;
-diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
-index 45e5363..d7f416d 100644
---- a/arch/arm/boot/dts/at91sam9263.dtsi
-+++ b/arch/arm/boot/dts/at91sam9263.dtsi
-@@ -95,6 +95,17 @@
- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfffff200 0xfffff200 0xa00>;
-
-+ atmel,mux-mask = <
-+ /* A B */
-+ 0xfffffffb 0xffffe07f /* pioA */
-+ 0x0007ffff 0x39072fff /* pioB */
-+ 0xffffffff 0x3ffffff8 /* pioC */
-+ 0xfffffbff 0xffffffff /* pioD */
-+ 0xffe00fff 0xfbfcff00 /* pioE */
-+ >;
-+
-+ /* shared pinctrl settings */
-+
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x200>;
-@@ -143,6 +154,7 @@
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
-+ };
- };
-
- dbgu: serial@ffffee00 {
-diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
-index 59a21c1..e2fa457 100644
---- a/arch/arm/boot/dts/at91sam9g45.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
-@@ -115,6 +115,17 @@
- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfffff200 0xfffff200 0xa00>;
-
-+ atmel,mux-mask = <
-+ /* A B */
-+ 0xffffffff 0xffc003ff /* pioA */
-+ 0xffffffff 0x800f8f00 /* pioB */
-+ 0xffffffff 0x00000e00 /* pioC */
-+ 0xffffffff 0xff0c1381 /* pioD */
-+ 0xffffffff 0x81ffff81 /* pioE */
-+ >;
-+
-+ /* shared pinctrl settings */
-+
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x200>;
-diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
-index 135ecef..fc451f9 100644
---- a/arch/arm/boot/dts/at91sam9n12.dtsi
-+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
-@@ -115,9 +115,19 @@
- pinctrl@fffff400 {
- #address-cells = <1>;
- #size-cells = <1>;
-- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfffff400 0xfffff400 0x800>;
-
-+ atmel,mux-mask = <
-+ /* A B C */
-+ 0xffffffff 0xffe07983 0x00000000 /* pioA */
-+ 0x00040000 0x00047e0f 0x00000000 /* pioB */
-+ 0xfdffffff 0x07c00000 0xb83fffff /* pioC */
-+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
-+ >;
-+
-+ /* shared pinctrl settings */
-+
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x200>;
-diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
-index 4e61a5d..84baa90 100644
---- a/arch/arm/boot/dts/at91sam9x5.dtsi
-+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
-@@ -116,9 +116,19 @@
- pinctrl@fffff200 {
- #address-cells = <1>;
- #size-cells = <1>;
-- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
-+ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
- ranges = <0xfffff400 0xfffff400 0x800>;
-
-+ atmel,mux-mask = <
-+ /* A B C */
-+ 0xffffffff 0xffe0399f 0xc000001c /* pioA */
-+ 0xffffffff 0xffc003ff 0xffc003ff /* pioB */
-+ 0xffffffff 0xffc003ff 0xffc003ff /* pioC */
-+ 0xffffffff 0xffc003ff 0xffc003ff /* pioD */
-+ >;
-+
-+ /* shared pinctrl settings */
-+
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x200>;
-diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
-index 67bc571..b175577 100644
---- a/arch/arm/configs/at91_dt_defconfig
-+++ b/arch/arm/configs/at91_dt_defconfig
-@@ -111,6 +111,7 @@ CONFIG_I2C=y
- CONFIG_I2C_GPIO=y
- CONFIG_SPI=y
- CONFIG_SPI_ATMEL=y
-+CONFIG_PINCTRL_AT91=y
- # CONFIG_HWMON is not set
- CONFIG_WATCHDOG=y
- CONFIG_AT91SAM9X_WATCHDOG=y
-diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
-index bb9bc50..23a8cfb 100644
---- a/arch/arm/mach-at91/at91sam9260.c
-+++ b/arch/arm/mach-at91/at91sam9260.c
-@@ -228,6 +228,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
- };
-
- static struct clk_lookup usart_clocks_lookups[] = {
-diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
-index 76499a6..7639f6b 100644
---- a/arch/arm/mach-at91/at91sam9263.c
-+++ b/arch/arm/mach-at91/at91sam9263.c
-@@ -214,6 +214,11 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
- };
-
- static struct clk_lookup usart_clocks_lookups[] = {
-diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
-index 5e7a1dd..2575bbf 100644
---- a/arch/arm/mach-at91/at91sam9g45.c
-+++ b/arch/arm/mach-at91/at91sam9g45.c
-@@ -258,6 +258,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
-+
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
-diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
-index 6fa0df1..f313142 100644
---- a/arch/arm/mach-at91/at91sam9n12.c
-+++ b/arch/arm/mach-at91/at91sam9n12.c
-@@ -186,12 +186,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
-- CLKDEV_CON_ID("pioA", &pioAB_clk),
-- CLKDEV_CON_ID("pioB", &pioAB_clk),
-- CLKDEV_CON_ID("pioC", &pioCD_clk),
-- CLKDEV_CON_ID("pioD", &pioCD_clk),
- CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
- CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
- /* additional fake clock for macb_hclk */
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
- CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
-@@ -241,9 +241,6 @@ static void __init at91sam9n12_map_io(void)
- void __init at91sam9n12_initialize(void)
- {
- at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
--
-- /* Register GPIO subsystem (using DT) */
-- at91_gpio_init(NULL, 0);
- }
-
- AT91_SOC_START(sam9n12)
-diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
-index af00de4..2870367 100644
---- a/arch/arm/mach-at91/at91sam9x5.c
-+++ b/arch/arm/mach-at91/at91sam9x5.c
-@@ -227,16 +227,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
-- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
-- CLKDEV_CON_ID("pioA", &pioAB_clk),
-- CLKDEV_CON_ID("pioB", &pioAB_clk),
-- CLKDEV_CON_ID("pioC", &pioCD_clk),
-- CLKDEV_CON_ID("pioD", &pioCD_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
-+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
- /* additional fake clock for macb_hclk */
- CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
- CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
-@@ -313,12 +310,6 @@ static void __init at91sam9x5_map_io(void)
- init_consistent_dma_size(SZ_8M);
- }
-
--void __init at91sam9x5_initialize(void)
--{
-- /* Register GPIO subsystem (using DT) */
-- at91_gpio_init(NULL, 0);
--}
--
- /* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-@@ -326,5 +317,4 @@ void __init at91sam9x5_initialize(void)
- AT91_SOC_START(sam9x5)
- .map_io = at91sam9x5_map_io,
- .register_clocks = at91sam9x5_register_clocks,
-- .init = at91sam9x5_initialize,
- AT91_SOC_END
-diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
-index 50c69b5..fcb66ea 100644
---- a/arch/arm/mach-at91/setup.c
-+++ b/arch/arm/mach-at91/setup.c
-@@ -449,7 +449,8 @@ void __init at91_dt_initialize(void)
- /* Register the processor-specific clocks */
- at91_boot_soc.register_clocks();
-
-- at91_boot_soc.init();
-+ if (at91_boot_soc.init)
-+ at91_boot_soc.init();
- }
- #endif
-
-diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
-index e4712d1..9c0fe11 100644
---- a/drivers/pinctrl/pinctrl-at91.c
-+++ b/drivers/pinctrl/pinctrl-at91.c
-@@ -749,7 +749,7 @@ static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
- grp->name = np->name;
-
- /*
-- * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
-+ * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
- * do sanity check and calculate pins number
- */
- list = of_get_property(np, "atmel,pins", &size);
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 765cac5205bcee3f9c6e0fb2aa819c0136fff54f Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Mon, 22 Oct 2012 16:08:50 +0200
+Subject: arm: at91: dt: at91sam9 add pinctrl support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+
+Conflicts:
+ arch/arm/mach-at91/at91sam9263.c
+ arch/arm/mach-at91/at91sam9n12.c
+ arch/arm/mach-at91/at91sam9x5.c
+---
+ .../bindings/pinctrl/atmel,at91-pinctrl.txt | 68 +++++++++++++++++++---
+ arch/arm/boot/dts/at91sam9260.dtsi | 9 +++
+ arch/arm/boot/dts/at91sam9263.dtsi | 12 ++++
+ arch/arm/boot/dts/at91sam9g45.dtsi | 11 ++++
+ arch/arm/boot/dts/at91sam9n12.dtsi | 12 +++-
+ arch/arm/boot/dts/at91sam9x5.dtsi | 12 +++-
+ arch/arm/configs/at91_dt_defconfig | 1 +
+ arch/arm/mach-at91/at91sam9260.c | 3 +
+ arch/arm/mach-at91/at91sam9263.c | 5 ++
+ arch/arm/mach-at91/at91sam9g45.c | 6 ++
+ arch/arm/mach-at91/at91sam9n12.c | 11 ++--
+ arch/arm/mach-at91/at91sam9x5.c | 18 ++----
+ arch/arm/mach-at91/setup.c | 3 +-
+ drivers/pinctrl/pinctrl-at91.c | 2 +-
+ 14 files changed, 140 insertions(+), 33 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+index 0296ef4..20a987e 100644
+--- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
++++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+@@ -22,6 +22,62 @@ Required properties for iomux controller:
+ - atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
+ configured in this periph mode. All the periph and bank need to be describe.
+
++How to create such array:
++
++Each column will represent the possible peripheral of the pinctrl
++Each line will represent a pio bank
++
++Take an example on the 9260
++Peripheral: 2 ( A and B)
++Bank: 3 (A, B and C)
++=>
++
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++
++For each peripheral/bank we will descibe in a u32 if a pin can can be
++configured in it by putting 1 to the pin bit (1 << pin)
++
++Let's take the pioA on peripheral B
++From the datasheet Table 10-2.
++Peripheral B
++PA0 MCDB0
++PA1 MCCDB
++PA2
++PA3 MCDB3
++PA4 MCDB2
++PA5 MCDB1
++PA6
++PA7
++PA8
++PA9
++PA10 ETX2
++PA11 ETX3
++PA12
++PA13
++PA14
++PA15
++PA16
++PA17
++PA18
++PA19
++PA20
++PA21
++PA22 ETXER
++PA23 ETX2
++PA24 ETX3
++PA25 ERX2
++PA26 ERX3
++PA27 ERXCK
++PA28 ECRS
++PA29 ECOL
++PA30 RXD4
++PA31 TXD4
++
++=> 0xffc00c3b
++
+ Required properties for pin configuration node:
+ - atmel,pins: 4 integers array, represents a group of pins mux and config
+ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
+@@ -35,18 +91,14 @@ NOTE:
+ Some requirements for using atmel,at91rm9200-pinctrl binding:
+ 1. We have pin function node defined under at91 controller node to represent
+ what pinmux functions this SoC supports.
+-2. The pin configuration node intends to work on a specific function should
+- to be defined under that specific function node.
+- The function node's name should represent well about what function
+- this group of pins in this pin configuration node are working on.
+-3. The driver can use the function node's name and pin configuration node's
++2. The driver can use the function node's name and pin configuration node's
+ name describe the pin function and group hierarchy.
+- For example, Linux Iat91 pinctrl driver takes the function node's name
++ For example, Linux at91 pinctrl driver takes the function node's name
+ as the function name and pin configuration node's name as group name to
+ create the map table.
+-4. Each pin configuration node should have a phandle, devices can set pins
++3. Each pin configuration node should have a phandle, devices can set pins
+ configurations by referring to the phandle of that pin configuration node.
+-5. The gpio controller must be describe in the pinctrl simple-bus.
++4. The gpio controller must be describe in the pinctrl simple-bus.
+
+ Examples:
+
+diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
+index e50261d..3654ace 100644
+--- a/arch/arm/boot/dts/at91sam9260.dtsi
++++ b/arch/arm/boot/dts/at91sam9260.dtsi
+@@ -104,6 +104,15 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x600>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc00c3b /* pioA */
++ 0xffffffff 0x7fff3ccf /* pioB */
++ 0xffffffff 0x007fffff /* pioC */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
+index 45e5363..d7f416d 100644
+--- a/arch/arm/boot/dts/at91sam9263.dtsi
++++ b/arch/arm/boot/dts/at91sam9263.dtsi
+@@ -95,6 +95,17 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xfffffffb 0xffffe07f /* pioA */
++ 0x0007ffff 0x39072fff /* pioB */
++ 0xffffffff 0x3ffffff8 /* pioC */
++ 0xfffffbff 0xffffffff /* pioD */
++ 0xffe00fff 0xfbfcff00 /* pioE */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+@@ -143,6 +154,7 @@
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
++ };
+ };
+
+ dbgu: serial@ffffee00 {
+diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
+index 59a21c1..e2fa457 100644
+--- a/arch/arm/boot/dts/at91sam9g45.dtsi
++++ b/arch/arm/boot/dts/at91sam9g45.dtsi
+@@ -115,6 +115,17 @@
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
+
++ atmel,mux-mask = <
++ /* A B */
++ 0xffffffff 0xffc003ff /* pioA */
++ 0xffffffff 0x800f8f00 /* pioB */
++ 0xffffffff 0x00000e00 /* pioC */
++ 0xffffffff 0xff0c1381 /* pioD */
++ 0xffffffff 0x81ffff81 /* pioE */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
+index 135ecef..fc451f9 100644
+--- a/arch/arm/boot/dts/at91sam9n12.dtsi
++++ b/arch/arm/boot/dts/at91sam9n12.dtsi
+@@ -115,9 +115,19 @@
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe07983 0x00000000 /* pioA */
++ 0x00040000 0x00047e0f 0x00000000 /* pioB */
++ 0xfdffffff 0x07c00000 0xb83fffff /* pioC */
++ 0x003fffff 0x003f8000 0x00000000 /* pioD */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
+index 4e61a5d..84baa90 100644
+--- a/arch/arm/boot/dts/at91sam9x5.dtsi
++++ b/arch/arm/boot/dts/at91sam9x5.dtsi
+@@ -116,9 +116,19 @@
+ pinctrl@fffff200 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+- compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
++ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
++ atmel,mux-mask = <
++ /* A B C */
++ 0xffffffff 0xffe0399f 0xc000001c /* pioA */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioB */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioC */
++ 0xffffffff 0xffc003ff 0xffc003ff /* pioD */
++ >;
++
++ /* shared pinctrl settings */
++
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
+index 67bc571..b175577 100644
+--- a/arch/arm/configs/at91_dt_defconfig
++++ b/arch/arm/configs/at91_dt_defconfig
+@@ -111,6 +111,7 @@ CONFIG_I2C=y
+ CONFIG_I2C_GPIO=y
+ CONFIG_SPI=y
+ CONFIG_SPI_ATMEL=y
++CONFIG_PINCTRL_AT91=y
+ # CONFIG_HWMON is not set
+ CONFIG_WATCHDOG=y
+ CONFIG_AT91SAM9X_WATCHDOG=y
+diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
+index bb9bc50..23a8cfb 100644
+--- a/arch/arm/mach-at91/at91sam9260.c
++++ b/arch/arm/mach-at91/at91sam9260.c
+@@ -228,6 +228,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
+index 76499a6..7639f6b 100644
+--- a/arch/arm/mach-at91/at91sam9263.c
++++ b/arch/arm/mach-at91/at91sam9263.c
+@@ -214,6 +214,11 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
+ };
+
+ static struct clk_lookup usart_clocks_lookups[] = {
+diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
+index 5e7a1dd..2575bbf 100644
+--- a/arch/arm/mach-at91/at91sam9g45.c
++++ b/arch/arm/mach-at91/at91sam9g45.c
+@@ -258,6 +258,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("sha_clk", "fffc8000.sha", &aestdessha_clk),
+ /* fake hclk clock */
+ CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
++
+ CLKDEV_CON_ID("pioA", &pioA_clk),
+ CLKDEV_CON_ID("pioB", &pioB_clk),
+ CLKDEV_CON_ID("pioC", &pioC_clk),
+diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
+index 6fa0df1..f313142 100644
+--- a/arch/arm/mach-at91/at91sam9n12.c
++++ b/arch/arm/mach-at91/at91sam9n12.c
+@@ -186,12 +186,12 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+- CLKDEV_CON_ID("pioA", &pioAB_clk),
+- CLKDEV_CON_ID("pioB", &pioAB_clk),
+- CLKDEV_CON_ID("pioC", &pioCD_clk),
+- CLKDEV_CON_ID("pioD", &pioCD_clk),
+ CLKDEV_CON_DEV_ID("aes_clk", "f000c000.aes", &aes_clk),
+ CLKDEV_CON_DEV_ID("sha_clk", "f0014000.sha", &sha_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+@@ -241,9 +241,6 @@ static void __init at91sam9n12_map_io(void)
+ void __init at91sam9n12_initialize(void)
+ {
+ at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
+-
+- /* Register GPIO subsystem (using DT) */
+- at91_gpio_init(NULL, 0);
+ }
+
+ AT91_SOC_START(sam9n12)
+diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
+index af00de4..2870367 100644
+--- a/arch/arm/mach-at91/at91sam9x5.c
++++ b/arch/arm/mach-at91/at91sam9x5.c
+@@ -227,16 +227,13 @@ static struct clk_lookup periph_clocks_lookups[] = {
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.0", &twi0_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.1", &twi1_clk),
+- CLKDEV_CON_DEV_ID(NULL, "at91_i2c.2", &twi2_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
+- CLKDEV_CON_ID("pioA", &pioAB_clk),
+- CLKDEV_CON_ID("pioB", &pioAB_clk),
+- CLKDEV_CON_ID("pioC", &pioCD_clk),
+- CLKDEV_CON_ID("pioD", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
++ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
+ CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+@@ -313,12 +310,6 @@ static void __init at91sam9x5_map_io(void)
+ init_consistent_dma_size(SZ_8M);
+ }
+
+-void __init at91sam9x5_initialize(void)
+-{
+- /* Register GPIO subsystem (using DT) */
+- at91_gpio_init(NULL, 0);
+-}
+-
+ /* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+@@ -326,5 +317,4 @@ void __init at91sam9x5_initialize(void)
+ AT91_SOC_START(sam9x5)
+ .map_io = at91sam9x5_map_io,
+ .register_clocks = at91sam9x5_register_clocks,
+- .init = at91sam9x5_initialize,
+ AT91_SOC_END
+diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
+index 50c69b5..fcb66ea 100644
+--- a/arch/arm/mach-at91/setup.c
++++ b/arch/arm/mach-at91/setup.c
+@@ -449,7 +449,8 @@ void __init at91_dt_initialize(void)
+ /* Register the processor-specific clocks */
+ at91_boot_soc.register_clocks();
+
+- at91_boot_soc.init();
++ if (at91_boot_soc.init)
++ at91_boot_soc.init();
+ }
+ #endif
+
+diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
+index e4712d1..9c0fe11 100644
+--- a/drivers/pinctrl/pinctrl-at91.c
++++ b/drivers/pinctrl/pinctrl-at91.c
+@@ -749,7 +749,7 @@ static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
+ grp->name = np->name;
+
+ /*
+- * the binding format is fsl,pins = <bank pin mux CONFIG ...>,
++ * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, "atmel,pins", &size);
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From e56cc54a58d4f2b37ec46f5a3281ce346417a24f Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Fri, 6 Jul 2012 00:41:57 +0800
-Subject: tty: atmel_serial: add pinctrl support
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- drivers/tty/serial/atmel_serial.c | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
-index 3d7e1ee..65f891b 100644
---- a/drivers/tty/serial/atmel_serial.c
-+++ b/drivers/tty/serial/atmel_serial.c
-@@ -39,6 +39,7 @@
- #include <linux/atmel_pdc.h>
- #include <linux/atmel_serial.h>
- #include <linux/uaccess.h>
-+#include <linux/pinctrl/consumer.h>
-
- #include <asm/io.h>
- #include <asm/ioctls.h>
-@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
- struct atmel_uart_data *pdata = pdev->dev.platform_data;
- void *data;
- int ret = -ENODEV;
-+ struct pinctrl *pinctrl;
-
- BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
-
-@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
-
- atmel_init_port(port, pdev);
-
-+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-+ if (IS_ERR(pinctrl)) {
-+ ret = PTR_ERR(pinctrl);
-+ goto err;
-+ }
-+
- if (!atmel_use_dma_rx(&port->uart)) {
- ret = -ENOMEM;
- data = kmalloc(sizeof(struct atmel_uart_char)
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From d608a2b7366014469707cdbdc97753856476a35b Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Fri, 6 Jul 2012 00:41:57 +0800
-Subject: arm: at91: dt: sam9m10g45ek: use rts/cts pinctrl group for uart1
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/boot/dts/at91sam9m10g45ek.dts | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-index 6a4aedd..94a8399 100644
---- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
-+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
-@@ -39,6 +39,7 @@
- };
-
- usart1: serial@fff90000 {
-+ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart1_rts_cts>;
- status = "okay";
- };
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From afea54d51f37890af0531b619ba64331141dc5aa Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 00:41:57 +0800
+Subject: tty: atmel_serial: add pinctrl support
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ drivers/tty/serial/atmel_serial.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
+index 3d7e1ee..65f891b 100644
+--- a/drivers/tty/serial/atmel_serial.c
++++ b/drivers/tty/serial/atmel_serial.c
+@@ -39,6 +39,7 @@
+ #include <linux/atmel_pdc.h>
+ #include <linux/atmel_serial.h>
+ #include <linux/uaccess.h>
++#include <linux/pinctrl/consumer.h>
+
+ #include <asm/io.h>
+ #include <asm/ioctls.h>
+@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+ struct atmel_uart_data *pdata = pdev->dev.platform_data;
+ void *data;
+ int ret = -ENODEV;
++ struct pinctrl *pinctrl;
+
+ BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+
+@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+
+ atmel_init_port(port, pdev);
+
++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
++ if (IS_ERR(pinctrl)) {
++ ret = PTR_ERR(pinctrl);
++ goto err;
++ }
++
+ if (!atmel_use_dma_rx(&port->uart)) {
+ ret = -ENOMEM;
+ data = kmalloc(sizeof(struct atmel_uart_char)
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From e287f769608c1e8e9304f25461efecbe18362996 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Fri, 10 Aug 2012 03:38:36 +0800
-Subject: arm: at91: dt: sam9263ek: use rts/cts pinctrl group for uart0
-
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/boot/dts/at91sam9263ek.dts | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
-index 05028ed..4c25adf 100644
---- a/arch/arm/boot/dts/at91sam9263ek.dts
-+++ b/arch/arm/boot/dts/at91sam9263ek.dts
-@@ -38,6 +38,7 @@
- };
-
- usart0: serial@fff8c000 {
-+ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart0_rts_cts>;
- status = "okay";
- };
-
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From 47e8824eb5ab3ec2eaf244dd0c2f378b46e90077 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 6 Jul 2012 00:41:57 +0800
+Subject: arm: at91: dt: sam9m10g45ek: use rts/cts pinctrl group for uart1
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9m10g45ek.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+index 6a4aedd..94a8399 100644
+--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
++++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
+@@ -39,6 +39,7 @@
+ };
+
+ usart1: serial@fff90000 {
++ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart1_rts_cts>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
--- /dev/null
+From e1f12883d126b1f7c4903cd3ae3a67abf4cf6456 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 10 Aug 2012 03:38:36 +0800
+Subject: arm: at91: dt: sam9263ek: use rts/cts pinctrl group for uart0
+
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9263ek.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
+index 05028ed..4c25adf 100644
+--- a/arch/arm/boot/dts/at91sam9263ek.dts
++++ b/arch/arm/boot/dts/at91sam9263ek.dts
+@@ -38,6 +38,7 @@
+ };
+
+ usart0: serial@fff8c000 {
++ pinctrl-0 = <&pinctrl_uart0 &pinctrl_uart0_rts_cts>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
+++ /dev/null
-From bfacb28b16dac225e1c58a72f629cb0d2e9f5120 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Fri, 10 Aug 2012 13:07:57 +0800
-Subject: arm: at91: dt: sam9g20ek: use rts/cts/dtr/dsr/dcd/ri pinctrl group
- for uart0
-
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-index 7da326a..6820417 100644
---- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
-@@ -35,6 +35,12 @@
- };
-
- usart0: serial@fffb0000 {
-+ pinctrl-0 =
-+ <&pinctrl_uart0
-+ &pinctrl_uart0_rts_cts
-+ &pinctrl_uart0_dtr_dsr
-+ &pinctrl_uart0_dcd
-+ &pinctrl_uart0_ri>;
- status = "okay";
- };
-
---
-1.8.0.197.g5a90748
-
+++ /dev/null
-From 57ce21ce09125413ed6f01cd028b7721ac0abd00 Mon Sep 17 00:00:00 2001
-From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-Date: Thu, 12 Jul 2012 13:20:22 +0800
-Subject: MTD: atmel nand: fix gpio missing request
-
-without this the gpio will not be muxed as a gpio by the current custom pinmux
-or later by the pinctrl
-
-Acked-by: Linus Walleij <linus.walleij@linaro.org>
-Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
----
- drivers/mtd/nand/atmel_nand.c | 50 ++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 49 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
-index 980ffdd..3978336 100644
---- a/drivers/mtd/nand/atmel_nand.c
-+++ b/drivers/mtd/nand/atmel_nand.c
-@@ -1411,8 +1411,41 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- nand_chip->IO_ADDR_W = host->io_base;
- nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
-
-- if (gpio_is_valid(host->board.rdy_pin))
-+ if (gpio_is_valid(host->board.rdy_pin)) {
-+ res = devm_gpio_request(&pdev->dev,
-+ host->board.rdy_pin, "nand_rdy");
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request rdy gpio %d\n", host->board.rdy_pin);
-+ goto err_ecc_ioremap;
-+ }
-+
-+ res = gpio_direction_input(host->board.rdy_pin);
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request input direction rdy gpio %d\n", host->board.rdy_pin);
-+ goto err_ecc_ioremap;
-+ }
-+
- nand_chip->dev_ready = atmel_nand_device_ready;
-+ }
-+
-+ if (gpio_is_valid(host->board.enable_pin)) {
-+ res = devm_gpio_request(&pdev->dev,
-+ host->board.enable_pin, "nand_enable");
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request enable gpio %d\n", host->board.enable_pin);
-+ goto err_ecc_ioremap;
-+ }
-+
-+ res = gpio_direction_output(host->board.enable_pin, 1);
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request output direction enable gpio %d\n", host->board.enable_pin);
-+ goto err_ecc_ioremap;
-+ }
-+ }
-
- nand_chip->ecc.mode = host->board.ecc_mode;
-
-@@ -1431,6 +1464,21 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
- atmel_nand_enable(host);
-
- if (gpio_is_valid(host->board.det_pin)) {
-+ res = devm_gpio_request(&pdev->dev,
-+ host->board.det_pin, "nand_det");
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request det gpio %d\n", host->board.det_pin);
-+ goto err_no_card;
-+ }
-+
-+ res = gpio_direction_input(host->board.det_pin);
-+ if (res < 0) {
-+ dev_err(&pdev->dev,
-+ "can't request input direction det gpio %d\n", host->board.det_pin);
-+ goto err_no_card;
-+ }
-+
- if (gpio_get_value(host->board.det_pin)) {
- printk(KERN_INFO "No SmartMedia card inserted.\n");
- res = -ENXIO;
---
-1.8.0.197.g5a90748
-
--- /dev/null
+From ebb32199a57519af1f5fcbf45e14ccb6d89b5481 Mon Sep 17 00:00:00 2001
+From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Date: Fri, 10 Aug 2012 13:07:57 +0800
+Subject: arm: at91: dt: sam9g20ek: use rts/cts/dtr/dsr/dcd/ri pinctrl group
+ for uart0
+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
+Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+---
+ arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+index 7da326a..6820417 100644
+--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+@@ -35,6 +35,12 @@
+ };
+
+ usart0: serial@fffb0000 {
++ pinctrl-0 =
++ <&pinctrl_uart0
++ &pinctrl_uart0_rts_cts
++ &pinctrl_uart0_dtr_dsr
++ &pinctrl_uart0_dcd
++ &pinctrl_uart0_ri>;
+ status = "okay";
+ };
+
+--
+1.8.0.197.g5a90748
+
-From e624846db6e105762542cb6c09276609a7932ea3 Mon Sep 17 00:00:00 2001
+From 0ffceb12d5e93ea68125847c9ecc02c45f1d5d31 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 12 Jul 2012 23:36:52 +0800
Subject: arm: at91: dt: at91sam9 add nand pinctrl support
-From 38bb2e5fb1310a6e4f4a6750037dc5a824c3cfdc Mon Sep 17 00:00:00 2001
+From 8bf3e7d44fe43bcb7b5a80dddd3fc59ac748cf0a Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Thu, 12 Jul 2012 23:31:39 +0800
Subject: MTD: atmel_nand: add pinctrl consumer support
-From 07549383aa7e1b5c99ca47f9bd75600ba1b159fc Mon Sep 17 00:00:00 2001
+From 8826cf74bca084ee93056cc92da87e655b46a76c Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 26 Sep 2012 14:57:45 +0800
Subject: pinctrl: at91 add deglitch, debounce, pull down and schmitt trigger
-From 9924801dfee9489e8df05d857df0d872a4f02193 Mon Sep 17 00:00:00 2001
+From 13a4a967e2e9ef7f99ea38b2cd6b369d401d6182 Mon Sep 17 00:00:00 2001
From: Josh Wu <josh.wu@atmel.com>
Date: Mon, 24 Sep 2012 08:06:30 +0800
Subject: mtd: atmel_nand: fix the compile error which miss label
-From 31a329d0cb5502f8076601608f2591adccbda8b7 Mon Sep 17 00:00:00 2001
+From 190a3340bea144c80801b81d5caa4c6f6556bb31 Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Tue, 16 Oct 2012 17:05:33 +0200
Subject: pinctrl/at91: fix compatible order
-From 54090e0c3b619793d8058ceb1d717ea453f65893 Mon Sep 17 00:00:00 2001
+From 84fe665121d2a8f3389d33acfc29257eb8b2d8d1 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 08:45:55 +0800
Subject: pinctrl: at91: fix gpio irq support
-From 15398d1b5861b197b75d85e9cfd4c2560ecc49de Mon Sep 17 00:00:00 2001
+From 79f38b7f00e4a08e1f0066ebfcbf2540a4a8b8cb Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Tue, 16 Oct 2012 17:06:37 +0200
Subject: i2c: at91: add pinctrl
-From d7ab9be8967e1884bba0228ea65f2893b10b019e Mon Sep 17 00:00:00 2001
+From f89227d6aec0e90ca9b2969e806703e63ca2d324 Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Tue, 16 Oct 2012 17:07:17 +0200
Subject: media: atmel_isi: add pinctrl
-From 6d2ed0a1963bcf555e5cdc12035ae105a94da9cf Mon Sep 17 00:00:00 2001
+From 06938a0f16eb491a16c123065cd5cda8e4111ba2 Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Tue, 16 Oct 2012 17:08:12 +0200
Subject: mmc: at91: add pinctrl
-From 5bc80812222fefb18a5ea8b9fcf8bb93eec37942 Mon Sep 17 00:00:00 2001
+From 5c8912c7fe8e2cf9fe8e2ec695810fa72202f354 Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Date: Tue, 16 Oct 2012 17:08:54 +0200
Subject: video: atmel_lcdfb: add pinctrl
-From 56c99e16b3c2bc6e5820266d81118915508d5b08 Mon Sep 17 00:00:00 2001
+From 7fd1be019470e05075ed05e67b824c34d2f4f024 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 05:52:10 +0800
Subject: arm: at91sam9g45: add missing uart pinctrl node
-From 9f223333d037f72115defc10f27afaf6fc900721 Mon Sep 17 00:00:00 2001
+From 140ae475ee6bbf6287ccdba37173a91de2a41179 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 05:52:10 +0800
Subject: arm: at91sam9263: add missing uart pinctrl node
-From b6ce595a610de9ed6ef5b27f824f43909de0db57 Mon Sep 17 00:00:00 2001
+From a35197fd3f74ef70f53b89627df1471df405434a Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 05:52:10 +0800
Subject: arm: at91sam9260: add missing uart pinctrl node
-From b07d6cfcdf6ec210b35e05e8d6ae9dc22feffcf1 Mon Sep 17 00:00:00 2001
+From 6020cbc2ed1b39e116af501b16196f41fb02560c Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 06:08:16 +0800
Subject: arm: at91sam9x5: sync with the mainline
-From f3a49662b5055a2e766d0a9f327c51781f463283 Mon Sep 17 00:00:00 2001
+From 11835542ca3b571da8a2cf2ef0ffe65260818ff9 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 07:14:06 +0800
Subject: ARM: at91/DT: add i2c mmc nand pinctrl in device tree support
-From 0328d56fcf25103afd966706a035735d2bf77d9c Mon Sep 17 00:00:00 2001
+From 8d8a30e133d80f1d5a4f7c9a49496fadb5935018 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 13:44:54 +0800
Subject: at91sam9x5: add lcd pinctrl support
-From d97e722de56d81f2d86606ff2537c14bd7ec270f Mon Sep 17 00:00:00 2001
+From 09d9306960be4117e00c086bc90bb510e581fdc9 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 15:13:13 +0800
Subject: arm: at91sam9x5ek: drop temporary pinmux
-From e932c44de6861621566b9a74a1498c72b14dae49 Mon Sep 17 00:00:00 2001
+From ddf17dd12f2a3a717ad9b947682b5d7d3b350245 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Fri, 19 Oct 2012 14:11:05 +0800
Subject: video: atmel lcd only request the pinctrl once
-From 11e369f0f20f451f958d7ef2e37a813a9a83dcf4 Mon Sep 17 00:00:00 2001
+From d947868defbab5b064de68d4df8aaad09127c51f Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 26 Sep 2012 17:04:31 +0200
Subject: ARM: at91: add at91-3.4-trunk-contents.txt file
-From 82c87f0c1d7b1077da380336e59180e3ed4c9407 Mon Sep 17 00:00:00 2001
+From b5aefffc52ac50286873f9f5952f6bb428f822c7 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 17 Oct 2012 11:37:49 +0200
Subject: ARM: at91: add defconfig for sam9x5 family
-From ce5e15a7b1efddfd022dd72b9510b5ff85da6325 Mon Sep 17 00:00:00 2001
+From e21c824bce9438f80a402e4ac4b8b1f017964138 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 20 Jun 2012 18:05:56 +0200
Subject: MMC: atmel-mci: add device tree property for configuration
-From 0179610747d87250bfba95479c9410511c8158de Mon Sep 17 00:00:00 2001
+From 87437fe8c93900352b99d6f883e730e7577f2a22 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Tue, 23 Oct 2012 13:47:30 +0800
Subject: pinctrl: at19: fix typo on PULL_UP
-From 5adaa6978db065d84ab39eb02b1035efca7ae7c6 Mon Sep 17 00:00:00 2001
+From f5e557974fc40c9886708fba8a4ff73d88696a73 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Tue, 23 Oct 2012 14:25:36 +0800
Subject: pinctrl: at91: fix pull down support
-From 4d69b49852403ccd7ac2103908b455a65138aa95 Mon Sep 17 00:00:00 2001
+From c5e8d355aa1cc2b2fe24f55777cbc08454af9d24 Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Tue, 23 Oct 2012 15:06:54 +0800
Subject: arm: at91sam9xcm: add specific nand pinctrl
-From b325d161ba97b1a84b3dc3fc2edcb60cd4254902 Mon Sep 17 00:00:00 2001
+From 7bc6b19e0e851436b17dd40d9ec55566c19d4ceb Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 24 Oct 2012 01:15:51 +0800
Subject: pinctrl: at91: fix debounce support
-From b3b0a725ce779a5ff6fa9b05edced0ee2f9dd836 Mon Sep 17 00:00:00 2001
+From 270c2034f23b4fc57136c147f4e98daeaf28cffc Mon Sep 17 00:00:00 2001
From: Marek Belisko <marek.belisko@open-nandra.com>
Date: Mon, 1 Oct 2012 22:46:09 +0200
Subject: ARM: at91/dts: at91sam9g20ek_common: Fix typos in buttons labels.
+commit b6edfbeacd5804038ea7ea8821a83ad704c107cc upstream.
+
Signed-off-by: Marek Belisko <marek.belisko@open-nandra.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
-From 2bc3ffd68ba8a607974259eac81a93889a576c8d Mon Sep 17 00:00:00 2001
+From abf14fdfedb328e664222c2d7b6951d9d9c69a50 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 24 Oct 2012 16:19:47 +0200
Subject: ARM: at91: fix external interrupt specification in board code
+commit 69e7ea04c9365626c0963ff09bbaa3a1b49e293a upstream.
+
Since the switch to sparse irq, we have to add the NR_IRQS_LEGACY
offset to static irq numbers. It has been forgotten on these
SPI irq definitions in board code.
-From 075b74ccf13912a227ca33f103e29f3b645fb4da Mon Sep 17 00:00:00 2001
+From 028918cfee7f910c65cf0dc9b126cb391700293b Mon Sep 17 00:00:00 2001
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Date: Wed, 24 Oct 2012 18:31:50 +0200
Subject: ARM: at91: drop duplicated config SOC_AT91SAM9 entry
+commit 08d04a135a1c2e24c4d4bc7bbafee5e0e58f80c6 upstream.
+
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---
-From e5e253baa31df4db3db0db218019e425bd4df9cd Mon Sep 17 00:00:00 2001
+From 66147723d43199d5aa36937cfaf5080bba782063 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Fri, 26 Oct 2012 22:49:09 +0200
Subject: ARM: at91: fix at91x40 build
+commit 0654f4ab2baa6100dc6b0b26f4f1fa3f02d10245 upstream.
+
patch 738a0fd7 "ARM: at91: fix external interrupts in non-DT case"
fixed a run-time error on some at91 platforms but did not apply
the same change to at91x40, which now doesn't build.
-From a2dcc54f95495c63504c6ee51ff1082343e5f4be Mon Sep 17 00:00:00 2001
+From 998f85c1d457709bf7decfd45760879aa8e182df Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Wed, 24 Oct 2012 16:09:57 +0200
Subject: ARM: at91: fix external interrupts in non-DT case
+commit 738a0fd752dc60e20beeda6f2f0f62e58dc0e344 upstream.
+
Management of external interrupts has changed but the
non-DT code has not integrated these changes.
Add a mask to pass external irq specification from SoC
-From c4e770c2e3cb8a3c8372f2f7a7cddcc8aa5e1160 Mon Sep 17 00:00:00 2001
+From 71baa91ada877611e15e180b123a33e1cf92caed Mon Sep 17 00:00:00 2001
From: Bo Shen <voice.shen@atmel.com>
Date: Mon, 15 Oct 2012 17:30:28 +0800
Subject: ARM: at91/i2c: change id to let i2c-at91 work
+commit 302090a66b85bb82023b07a715f9c9a347be2ac8 upstream.
+
The i2c core driver will turn the platform device ID to busnum
When using platfrom device ID as -1, it means dynamically assigned
the busnum. When writing code, we need to make sure the busnum,
-From 550797fd7773e9ebe542e55e770381273fe1a2f7 Mon Sep 17 00:00:00 2001
+From 067de7270b3433afc244ba4a607f3491f0d0fc5c Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Fri, 16 Nov 2012 16:47:44 +0100
Subject: net/macb: align ring buffer function with mainline
-From 10c4df2b1b3697e748032c8729d26b262eca651d Mon Sep 17 00:00:00 2001
+From b89a2bd3ff16d088eca080c6ba298e097c786287 Mon Sep 17 00:00:00 2001
From: Nicolas Ferre <nicolas.ferre@atmel.com>
Date: Mon, 19 Nov 2012 16:05:28 +0100
Subject: net/macb: move to circ_buf macros and fix initial condition
#############################################################################
# LTTNG
+#
# Patches came from short-lived experiment when they were added to the staging
# tree for a week or so.
#
patches.lttng/lttng-fix-module-name-lttng-relay.ko-lttng-tracer.ko.patch
+#############################################################################
+# AF_BUS
+#
+# DBUS in the kernel patches. Rejected by upstream, but people need this
+# (GENEVI and the like), so while they are being reworked into upstream
+# acceptable format, we include them here for people who need/want them.
+#
+patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
+patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch
+patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch
+patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch
+patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch
+patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch
+patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch
+patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch
+patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch
+patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch
+patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch
+patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch
+patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch
+patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch
+patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch
+
+
+#############################################################################
+# pramfs
+#
+# Currently broken, so don't enable, but leave here for the placeholder.
+#
patches.pramfs/01-pramfs-documentation.patch
patches.pramfs/02-pramfs-super-operations.patch
patches.pramfs/03-pramfs-inode-operations.patch
patches.pramfs/17-pramfs-makefile-and-kconfig.patch
+#############################################################################
+# Marzen board support
+#
patches.marzen/0001-sh-clkfwk-Support-variable-size-accesses-for-MSTP-cl.patch
patches.marzen/0002-sh-clkfwk-Support-variable-size-accesses-for-div4-di.patch
patches.marzen/0003-sh-clkfwk-Move-to-common-clk_div_table-accessors-for.patch
patches.marzen/0099-mmc-sh_mmcif-support-generic-card-detection.patch
+#############################################################################
+# Armadillo 800 board support
+#
patches.armadillo800/0001-ARM-shmobile-add-common-DMAEngine-definitions.patch
patches.armadillo800/0002-ARM-shmobile-soc-core-add-R-mobile-PM-domain-common-.patch
patches.armadillo800/0003-media-V4L2-sh_mobile_ceu-manage-lower-8bit-bus.patch
patches.armadillo800/0107-ARM-shmobile-armadillo800eva-enable-rw-rootfs-mount.patch
+#############################################################################
+# AT91 board support
+#
patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch
patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch
patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch
patches.at91/0041-ARM-at91-remove-two-unused-headers.patch
patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch
patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch
-patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch
-patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch
-patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch
-patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch
-patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch
-patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch
-patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch
-patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch
-patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch
-patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch
-patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch
-patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch
-patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch
-patches.at91/0058-ARM-at91-sparse-irq-support.patch
-patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch
-patches.at91/0060-ARM-at91-add-AIC5-support.patch
-patches.at91/0061-dt-add-property-iteration-helpers.patch
-patches.at91/0062-ARM-at91-fix-new-build-errors.patch
-patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch
-patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch
-patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch
-patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch
-patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch
-patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch
-patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch
-patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch
-patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch
-patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch
-patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch
-patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch
-patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch
-patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch
-patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch
-patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch
-patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
-patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
-patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
-patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
-patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
-patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch
-patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch
-patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch
-patches.at91/0089-net-macb-memory-barriers-cleanup.patch
-patches.at91/0090-net-macb-change-debugging-messages.patch
-patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch
-patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch
-patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch
-patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch
-patches.at91/0095-net-macb-better-manage-tx-errors.patch
-patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch
-patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch
-patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch
-patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch
-patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch
-patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch
-patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch
-patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch
-patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch
-patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch
-patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
-patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
-patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
-patches.at91/0111-video-atmelfb-refactor-core-setup.patch
-patches.at91/0112-video-atmelfb-refactor-start-stop.patch
-patches.at91/0113-video-atmelfb-refactor-isr.patch
-patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch
-patches.at91/0115-video-atmelfb-refactor-dma_update.patch
-patches.at91/0116-video-atmelfb-refactor-LUT.patch
-patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch
-patches.at91/0118-arm-at91-refactor-lcdc-includes.patch
-patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch
-patches.at91/0120-WIP-add-clut-resource.patch
-patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
-patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch
-patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
-patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
-patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch
-patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch
-patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch
-patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch
-patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch
-patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch
-patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch
-patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch
-patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch
-patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch
-patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch
-patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch
-patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch
-patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch
-patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch
-patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch
-patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch
-patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch
-patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
-patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
-patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch
-patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch
-patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch
-patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch
-patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch
-patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch
-patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch
-patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch
-patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch
-patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch
-patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch
-patches.at91/0156-i2c-at91-remove-old-polling-driver.patch
-patches.at91/0157-i2c-at91-add-new-driver.patch
-patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch
-patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch
-patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch
-patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch
-patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch
-patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch
-patches.at91/0164-i2c-at91-add-dma-support.patch
-patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch
-patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch
-patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch
-patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch
-patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch
-patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch
-patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch
-patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch
-patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch
-patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch
-patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch
-patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch
-patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch
-patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch
-patches.at91/0179-crypto-add-Atmel-AES-driver.patch
-patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch
-patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch
-patches.at91/0182-crypto-add-atmel-test-driver.patch
-patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch
-patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch
-patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch
-patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch
-patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch
-patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch
-patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch
-patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch
-patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch
-patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch
-patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch
-patches.at91/0194-pinctrl-fix-dangling-comment.patch
-patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch
-patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch
-patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch
-patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch
-patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch
-patches.at91/0200-pinctrl-propagate-map-validation-errors.patch
-patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch
-patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch
-patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch
-patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch
-patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch
-patches.at91/0206-dt-add-of_get_child_count-helper-function.patch
-patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch
-patches.at91/0208-ARM-at91-gpio-implement-request.patch
-patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch
-patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch
-patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch
-patches.at91/0212-ARM-at91-add-pinctrl-support.patch
-patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch
-patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch
-patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch
-patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch
-patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch
-patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch
+patches.at91/0044-ARM-at91-clock-fix-PLLA-overclock-warning.patch
+patches.at91/0045-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch
+patches.at91/0046-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch
+patches.at91/0047-ARM-at91-defconfig-Remove-unaffected-config-option.patch
+patches.at91/0048-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch
+patches.at91/0050-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch
+patches.at91/0051-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch
+patches.at91/0052-ARM-at91-aic-can-use-fast-eoi-handler-type.patch
+patches.at91/0053-ARM-at91-aic-add-dt-support-for-external-irqs.patch
+patches.at91/0054-ARM-at91-add-of-irq-priorities-support.patch
+patches.at91/0055-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch
+patches.at91/0056-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch
+patches.at91/0057-ARM-at91-sparse-irq-support.patch
+patches.at91/0058-ARM-at91-remove-mach-irqs.h.patch
+patches.at91/0059-ARM-at91-add-AIC5-support.patch
+patches.at91/0060-dt-add-property-iteration-helpers.patch
+patches.at91/0061-ARM-at91-fix-new-build-errors.patch
+patches.at91/0062-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch
+patches.at91/0063-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch
+patches.at91/0064-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch
+patches.at91/0065-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch
+patches.at91/0068-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch
+patches.at91/0069-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch
+patches.at91/0070-net-macb-manage-carrier-state-with-call-to-netif_car.patch
+patches.at91/0071-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch
+patches.at91/0072-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch
+patches.at91/0073-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch
+patches.at91/0074-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch
+patches.at91/0075-MTD-nand-add-return-value-for-write_page-write_page_.patch
+patches.at91/0076-MTD-atmel-nand-fix-gpio-missing-request.patch
+patches.at91/0077-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch
+patches.at91/0079-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch
+patches.at91/0080-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch
+patches.at91/0081-USB-ohci-at91.c-remove-err-usage.patch
+patches.at91/0083-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch
+patches.at91/0084-USB-Kconfig-add-Atmel-usba-driver-entry.patch
+patches.at91/0085-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch
+patches.at91/0086-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch
+patches.at91/0087-pinctrl-fix-dangling-comment.patch
+patches.at91/0088-pinctrl-implement-devm_pinctrl_get-put.patch
+patches.at91/0089-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch
+patches.at91/0090-pinctrl-remove-pinctrl_remove_gpio_range.patch
+patches.at91/0091-pinctrl-add-pinctrl_add_gpio_ranges-function.patch
+patches.at91/0092-pinctrl-support-gpio-request-deferred-probing.patch
+patches.at91/0093-pinctrl-propagate-map-validation-errors.patch
+patches.at91/0094-pinctrl-mark-non-EXPERIMENTAL.patch
+patches.at91/0095-pinctrl-implement-pinctrl-deferred-probing.patch
+patches.at91/0096-pinctrl-replace-list_-with-get_-_count.patch
+patches.at91/0097-pinctrl-show-pin-name-when-request-pins.patch
+patches.at91/0098-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch
+patches.at91/0099-dt-add-of_get_child_count-helper-function.patch
+patches.at91/0100-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch
+patches.at91/0101-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch
+patches.at91/0102-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch
+patches.at91/0103-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch
+patches.at91/0104-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch
+patches.at91/0105-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch
+patches.at91/0106-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch
+patches.at91/0107-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch
+patches.at91/0108-input-at91-add-tsadcc_data-for-9x5.patch
+patches.at91/0109-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch
+patches.at91/0110-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch
+patches.at91/0111-net-macb-memory-barriers-cleanup.patch
+patches.at91/0112-net-macb-change-debugging-messages.patch
+patches.at91/0113-net-macb-remove-macb_get_drvinfo.patch
+patches.at91/0114-net-macb-tx-status-is-more-than-8-bits-now.patch
+patches.at91/0115-net-macb-clean-up-ring-buffer-logic.patch
+patches.at91/0116-net-macb-ethtool-interface-add-register-dump-feature.patch
+patches.at91/0117-net-macb-better-manage-tx-errors.patch
+patches.at91/0118-net-macb-Offset-first-RX-buffer-by-two-bytes.patch
+patches.at91/0119-net-macb-GEM-DMA-configuration-register-update.patch
+patches.at91/0120-net-macb-Use-non-coherent-memory-for-rx-buffers.patch
+patches.at91/0121-phy-micrel-Use-proper-phy-in-gmac.patch
+patches.at91/0122-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch
+patches.at91/0123-media-video-atmel-isi-add-dumb-set_parm.patch
+patches.at91/0124-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch
+patches.at91/0125-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch
+patches.at91/0126-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch
+patches.at91/0127-video-atmelfb-refactor-core-setup.patch
+patches.at91/0128-video-atmelfb-refactor-start-stop.patch
+patches.at91/0129-video-atmelfb-refactor-isr.patch
+patches.at91/0130-video-atmelfb-refactor-backlight-routines.patch
+patches.at91/0131-video-atmelfb-refactor-dma_update.patch
+patches.at91/0132-video-atmelfb-refactor-LUT.patch
+patches.at91/0133-video-atmelfb-refactor-limit_screeninfo.patch
+patches.at91/0134-arm-at91-refactor-lcdc-includes.patch
+patches.at91/0135-video-atmel_hlcdfb-add-new-driver.patch
+patches.at91/0136-WIP-add-clut-resource.patch
+patches.at91/0137-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch
+patches.at91/0138-video-atmel_lcdfb-HLCD-modifications.patch
+patches.at91/0139-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch
+patches.at91/0140-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch
+patches.at91/0141-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch
+patches.at91/0142-ARM-at91-9x5-modify-consistent-DMA-size.patch
+patches.at91/0143-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch
+patches.at91/0144-media-at91sam9x5-video-cleanup-modifications.patch
+patches.at91/0145-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch
+patches.at91/0146-media-at91sam9x5-video-change-scaling-factor-calcula.patch
+patches.at91/0147-media-at91sam9x5-video-add-device-tree-support.patch
+patches.at91/0148-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch
+patches.at91/0149-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch
+patches.at91/0150-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch
+patches.at91/0151-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch
+patches.at91/0152-mmc-atmel-mci-add-debug-logs.patch
+patches.at91/0153-mmc-atmel-mci-fix-data-timeout-issue.patch
+patches.at91/0154-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch
+patches.at91/0155-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch
+patches.at91/0156-mmc-atmel-mci-fix-burst-chunk-size-modification.patch
+patches.at91/0157-mmc-atmel-mci-add-device-tree-support.patch
+patches.at91/0158-ARM-at91-add-clocks-for-DT-entries.patch
+patches.at91/0159-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
+patches.at91/0160-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch
+patches.at91/0161-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch
+patches.at91/0162-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch
+patches.at91/0163-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch
+patches.at91/0164-ARM-dts-fix-add-mmc-irq-priority.patch
+patches.at91/0165-mmc-atmel-mci-support-8-bit-buswidth.patch
+patches.at91/0166-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch
+patches.at91/0167-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch
+patches.at91/0168-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch
+patches.at91/0169-mmc-atmel-mci-increase-dma-threshold.patch
+patches.at91/0170-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch
+patches.at91/0171-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch
+patches.at91/0172-i2c-at91-remove-old-polling-driver.patch
+patches.at91/0173-i2c-at91-add-new-driver.patch
+patches.at91/0174-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch
+patches.at91/0175-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch
+patches.at91/0176-i2c-at91-add-dt-support-to-i2c-at91.patch
+patches.at91/0177-ARM-at91-add-clocks-for-I2C-DT-entries.patch
+patches.at91/0178-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch
+patches.at91/0179-ARM-dts-add-twi-nodes-for-atmel-boards.patch
+patches.at91/0180-i2c-at91-add-dma-support.patch
+patches.at91/0181-i2c-at91-backport-fix-for-devm_clk_get.patch
+patches.at91/0182-i2c-at91-add-dt-property-for-DMA-configuration.patch
+patches.at91/0183-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch
+patches.at91/0184-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch
+patches.at91/0185-AT91-board-dt-add-mci-pinmux-for-9x5.patch
+patches.at91/0186-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch
+patches.at91/0187-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch
+patches.at91/0188-at91-9x5-add-DT-parameters-to-enable-PMECC.patch
+patches.at91/0189-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch
+patches.at91/0190-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch
+patches.at91/0191-ARM-at91-add-new-at91sam9g35ek.dts.patch
+patches.at91/0192-ARM-at91-add-pinmux-for-9x5-LCD.patch
+patches.at91/0193-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch
+patches.at91/0194-AT91SAM9G45-add-crypto-peripherals.patch
+patches.at91/0195-crypto-add-Atmel-AES-driver.patch
+patches.at91/0196-crypto-add-Atmel-DES-TDES-driver.patch
+patches.at91/0197-crypto-add-Atmel-SHA1-SHA256-driver.patch
+patches.at91/0198-crypto-add-atmel-test-driver.patch
+patches.at91/0199-crypto-add-new-tests-to-tcrypt.patch
+patches.at91/0200-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch
+patches.at91/0201-AT91SAM9G45-dts-add-crypto-peripherals.patch
+patches.at91/0202-AT91SAM9N12-add-crypto-peripherals.patch
+patches.at91/0203-AT91SAM9N12-dts-add-crypto-peripherals.patch
+patches.at91/0204-crypto-Atmel-AES-add-device-tree-support.patch
+patches.at91/0205-crypto-Atmel-TDES-add-device-tree-support.patch
+patches.at91/0206-crypto-Atmel-SHA-add-device-tree-support.patch
+patches.at91/0207-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch
+patches.at91/0208-arm-at91-use-macro-to-declare-soc-boot-data.patch
+patches.at91/0209-ARM-at91-gpio-implement-request.patch
+patches.at91/0210-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch
+patches.at91/0211-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch
+patches.at91/0212-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch
+patches.at91/0213-ARM-at91-add-pinctrl-support.patch
+patches.at91/0214-arm-at91-dt-at91sam9-add-pinctrl-support.patch
+patches.at91/0215-tty-atmel_serial-add-pinctrl-support.patch
+patches.at91/0216-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch
+patches.at91/0217-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch
+patches.at91/0218-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch
patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch
patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch
patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch
patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch
patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch
-
-patches.af_bus/0001-net-bus-add-the-AF_BUS-socket-address-family.patch
-patches.af_bus/0002-net-bus-Add-AF_BUS-documentation.patch
-patches.af_bus/0003-net-bus-add-af_bus-address-and-af_bus-socket-address.patch
-patches.af_bus/0004-security-Add-Linux-Security-Modules-hook-for-AF_BUS-.patch
-patches.af_bus/0005-security-selinux-Add-AF_BUS-socket-SELinux-hooks.patch
-patches.af_bus/0006-netfilter-add-NFPROTO_BUS-hook-constant-for-AF_BUS-s.patch
-patches.af_bus/0007-scm-allow-AF_BUS-sockets-to-send-ancillary-data.patch
-patches.af_bus/0008-net-bus-Add-implementation-of-Bus-domain-sockets.patch
-patches.af_bus/0009-net-bus-Add-garbage-collector-for-AF_BUS-sockets.patch
-patches.af_bus/0010-net-bus-Add-the-AF_BUS-socket-address-family-to-KBui.patch
-patches.af_bus/0011-netlink-connector-implement-cn_netlink_reply.patch
-patches.af_bus/0012-netlink-connector-Add-idx-and-val-identifiers-for-ne.patch
-patches.af_bus/0013-netfilter-nfdbus-Add-D-bus-message-parsing.patch
-patches.af_bus/0014-netfilter-nfdbus-Add-D-bus-match-rule-implementation.patch
-patches.af_bus/0015-netfilter-add-netfilter-D-Bus-module.patch