diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-12-04 09:22:29 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-12-04 09:22:29 -0800 |
commit | b5f72d1f70981e6f94668980bc50fd91acb4695b (patch) | |
tree | 174787ed4fa42d49e9bedec6daccf5c389e91ee3 | |
parent | 12e057530821c9839d0d0272cdda555fb36869d1 (diff) | |
download | ltsi-kernel-b5f72d1f70981e6f94668980bc50fd91acb4695b.tar.gz |
at91 patches added
247 files changed, 54619 insertions, 0 deletions
diff --git a/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch b/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch new file mode 100644 index 00000000000000..cf8199884a1106 --- /dev/null +++ b/patches.at91/0001-MAINTAINERS-add-entry-for-Atmel-isi-driver.patch @@ -0,0 +1,32 @@ +From f3bd6419099a0cfefc3b13cf95ba34015f06ffb3 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 + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + MAINTAINERS | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index a60009d..c7c725e 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1331,6 +1331,13 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com> + S: Supported + F: drivers/tty/serial/atmel_serial.c + ++ATMEL ISI DRIVER ++M: Josh Wu <josh.wu@atmel.com> ++L: linux-media@vger.kernel.org ++S: Supported ++F: drivers/media/video/atmel-isi.c ++F: include/media/atmel-isi.h ++ + ATMEL LCDFB DRIVER + M: Nicolas Ferre <nicolas.ferre@atmel.com> + L: linux-fbdev@vger.kernel.org +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch b/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch new file mode 100644 index 00000000000000..d4a2238d683a4a --- /dev/null +++ b/patches.at91/0002-MAINTAINERS-add-entry-for-Atmel-touch-screen-ADC-con.patch @@ -0,0 +1,31 @@ +From ef899cb1d2fda864b02a7efa424767981353f1b5 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 + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + MAINTAINERS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index c7c725e..347df81 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1355,6 +1355,12 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com> + S: Supported + F: drivers/spi/spi-atmel.* + ++ATMEL TSADCC DRIVER ++M: Josh Wu <josh.wu@atmel.com> ++L: linux-input@vger.kernel.org ++S: Supported ++F: drivers/input/touchscreen/atmel_tsadcc.c ++ + ATMEL USBA UDC DRIVER + M: Nicolas Ferre <nicolas.ferre@atmel.com> + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch b/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch new file mode 100644 index 00000000000000..68b5ddaac06d69 --- /dev/null +++ b/patches.at91/0003-MAINTAINERS-add-entry-for-Atmel-DMA-driver.patch @@ -0,0 +1,32 @@ +From 2dd30cf629c3267c2925a9925b31addf1ef168b6 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + MAINTAINERS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 347df81..5d607d2 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1331,6 +1331,14 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com> + S: Supported + F: drivers/tty/serial/atmel_serial.c + ++ATMEL DMA DRIVER ++M: Nicolas Ferre <nicolas.ferre@atmel.com> ++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ++S: Supported ++F: drivers/dma/at_hdmac.c ++F: drivers/dma/at_hdmac_regs.h ++F: arch/arm/mach-at91/include/mach/at_hdmac.h ++ + ATMEL ISI DRIVER + M: Josh Wu <josh.wu@atmel.com> + L: linux-media@vger.kernel.org +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch b/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch new file mode 100644 index 00000000000000..3f2de362ad97d9 --- /dev/null +++ b/patches.at91/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch @@ -0,0 +1,34 @@ +From 811046c42ca111ebc64328429ae035f48dddb2fd 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) + +Add an entry for the Timer Counter (TC) library and the clocksource +driver that is using this library. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + MAINTAINERS | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 5d607d2..54d18b0 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1363,6 +1363,13 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com> + S: Supported + F: drivers/spi/spi-atmel.* + ++ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS ++M: Nicolas Ferre <nicolas.ferre@atmel.com> ++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ++S: Supported ++F: drivers/misc/atmel_tclib.c ++F: drivers/clocksource/tcb_clksrc.c ++ + ATMEL TSADCC DRIVER + M: Josh Wu <josh.wu@atmel.com> + L: linux-input@vger.kernel.org +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch b/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch new file mode 100644 index 00000000000000..a516b9522b0d31 --- /dev/null +++ b/patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch @@ -0,0 +1,27 @@ +From ff97bdd9bbdcd2f550b68c11d90a3e01873933c7 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Cc: Haavard Skinnemoen <hskinnemoen@gmail.com> +Cc: Hans-Christian Egtvedt <egtvedt@samfundet.no> +--- + MAINTAINERS | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 54d18b0..9c7e7ce 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1379,7 +1379,6 @@ F: drivers/input/touchscreen/atmel_tsadcc.c + ATMEL USBA UDC DRIVER + M: Nicolas Ferre <nicolas.ferre@atmel.com> + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +-W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver + S: Supported + F: drivers/usb/gadget/atmel_usba_udc.* + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch b/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch new file mode 100644 index 00000000000000..d84aa0d952cec3 --- /dev/null +++ b/patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch @@ -0,0 +1,28 @@ +From cfcd98b36cbb2f074a06b1665727a72d3677ce64 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 7a8660a..ddef021 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -340,8 +340,8 @@ config ARCH_AT91 + select IRQ_DOMAIN + select NEED_MACH_IO_H if PCCARD + help +- This enables support for systems based on the Atmel AT91RM9200, +- AT91SAM9 processors. ++ This enables support for systems based on Atmel ++ AT91RM9200 and AT91SAM9* processors. + + config ARCH_BCMRING + bool "Broadcom BCMRING" +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch b/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch new file mode 100644 index 00000000000000..a709d75a03e1f7 --- /dev/null +++ b/patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch @@ -0,0 +1,40 @@ +From 4b6fd2b781b2091e70dbfe0d3b3bf5ad70e9664b 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 + +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 +AT91SAM9M10 and AT91SAM9M11. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 45db05d..dfbc2c5 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -89,13 +89,16 @@ config ARCH_AT91SAM9G20 + select HAVE_NET_MACB + + config ARCH_AT91SAM9G45 +- bool "AT91SAM9G45" ++ bool "AT91SAM9G45 or AT91SAM9M10 families" + select CPU_ARM926T + select GENERIC_CLOCKEVENTS + select HAVE_AT91_USART3 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU1 ++ help ++ Select this if you are using one of Atmel's AT91SAM9G45 family SoC. ++ This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. + + config ARCH_AT91SAM9X5 + bool "AT91SAM9x5 family" +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch b/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch new file mode 100644 index 00000000000000..02a7a09d9edefc --- /dev/null +++ b/patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch @@ -0,0 +1,33 @@ +From 780545021feb2796b0595ebb300522c862bafc55 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 + +Add comment to make it clear that several SoC are supported by +this generic entry. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index dfbc2c5..cad7a15 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -107,6 +107,12 @@ config ARCH_AT91SAM9X5 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU0 ++ help ++ Select this if you are using one of Atmel's AT91SAM9x5 family SoC. ++ This means that your SAM9 name finishes with a '5' (except if it is ++ AT91SAM9G45!). ++ This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35 ++ and AT91SAM9X35. + + config ARCH_AT91X40 + bool "AT91x40" +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch b/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch new file mode 100644 index 00000000000000..d5de31639952e9 --- /dev/null +++ b/patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch @@ -0,0 +1,34 @@ +From 2eb2471c5bf340e1057c2e5faba6d8b23f6f23e4 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 + +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. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index cad7a15..d2922a1 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -442,9 +442,10 @@ comment "AT91SAM9G45 Board Type" + config MACH_AT91SAM9M10G45EK + bool "Atmel AT91SAM9M10G45-EK Evaluation Kits" + help +- Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit. +- "ES" at the end of the name means that this board is an +- Engineering Sample. ++ Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit. ++ Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10 ++ families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. ++ <http://www.atmel.com/tools/SAM9M10-G45-EK.aspx> + + endif + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch b/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch new file mode 100644 index 00000000000000..48aedef8c2010e --- /dev/null +++ b/patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch @@ -0,0 +1,26 @@ +From f46c2a68a6ad0d570c5c8894d8589cb91f0e2d5f 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index d2922a1..e0b8b10 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -529,7 +529,7 @@ choice + prompt "Select a UART for early kernel messages" + + config AT91_EARLY_DBGU0 +- bool "DBGU on rm9200, 9260/9g20, 9261/9g10 and 9rl" ++ bool "DBGU on rm9200, 9260/9g20, 9261/9g10, 9rl and 9x5" + depends on HAVE_AT91_DBGU0 + + config AT91_EARLY_DBGU1 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch b/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch new file mode 100644 index 00000000000000..f43f496e1e49d1 --- /dev/null +++ b/patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch @@ -0,0 +1,25 @@ +From 761e63c4d6f8cbf48f12bc90aff9083eefb37e2c 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index e0b8b10..8acc164 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -373,6 +373,7 @@ config MACH_AT91SAM9G20EK_2MMC + Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit + with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and + onwards. ++ <http://www.atmel.com/tools/SAM9G20-EK.aspx> + + config MACH_CPU9G20 + bool "Eukrea CPU9G20 board" +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch b/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch new file mode 100644 index 00000000000000..dd918d05e054b5 --- /dev/null +++ b/patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch @@ -0,0 +1,30 @@ +From aa2c1a9a69b0a74992d2e4d129f69f58c9b9c433 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 + +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. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/rtc/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 8c8377d..4161bfe 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -838,7 +838,7 @@ config RTC_DRV_AT32AP700X + + config RTC_DRV_AT91RM9200 + tristate "AT91RM9200 or some AT91SAM9 RTC" +- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on ARCH_AT91 + help + Driver for the internal RTC (Realtime Clock) module found on + Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch b/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch new file mode 100644 index 00000000000000..f79ccb33435eb2 --- /dev/null +++ b/patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch @@ -0,0 +1,35 @@ +From 3f06a6301f2cba15b6e6f60283c5910f6383ed3f 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 + +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. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Dmitry Torokhov <dtor@mail.ru> +--- + drivers/input/touchscreen/Kconfig | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index 2a21419..75838d7 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -489,10 +489,10 @@ config TOUCHSCREEN_TI_TSCADC + + config TOUCHSCREEN_ATMEL_TSADCC + tristate "Atmel Touchscreen Interface" +- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 ++ depends on ARCH_AT91 + help + Say Y here if you have a 4-wire touchscreen connected to the +- ADC Controller on your Atmel SoC (such as the AT91SAM9RL). ++ ADC Controller on your Atmel SoC. + + If unsure, say N. + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch b/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch new file mode 100644 index 00000000000000..b2703f828ca404 --- /dev/null +++ b/patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch @@ -0,0 +1,30 @@ +From 3511638f3d8c7369a85592a17b186482c1057b99 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 + +This will allow to select this driver for newer SoCs. Make sure to +keep dependency on HAVE_CLK to avoid breaking other machines. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Herbert Xu <herbert@gondor.apana.org.au> +--- + drivers/char/hw_random/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig +index 0689bf6..b2402eb 100644 +--- a/drivers/char/hw_random/Kconfig ++++ b/drivers/char/hw_random/Kconfig +@@ -62,7 +62,7 @@ config HW_RANDOM_AMD + + config HW_RANDOM_ATMEL + tristate "Atmel Random Number Generator support" +- depends on HW_RANDOM && ARCH_AT91SAM9G45 ++ depends on HW_RANDOM && HAVE_CLK + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch b/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch new file mode 100644 index 00000000000000..bc6a6391476218 --- /dev/null +++ b/patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch @@ -0,0 +1,66 @@ +From d100869e11a7ed455412896d44314a81a386ed42 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 + +This will allow a future change to auto-detect which UART to use. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/include/mach/uncompress.h | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h +index 4218647..d985af7 100644 +--- a/arch/arm/mach-at91/include/mach/uncompress.h ++++ b/arch/arm/mach-at91/include/mach/uncompress.h +@@ -43,6 +43,14 @@ + #define UART_OFFSET AT91_USART5 + #endif + ++void __iomem *at91_uart; ++ ++static inline void arch_decomp_setup(void) ++{ ++#ifdef UART_OFFSET ++ at91_uart = (void __iomem *) UART_OFFSET; /* physical address */ ++#endif ++} + /* + * The following code assumes the serial port has already been + * initialized by the bootloader. If you didn't setup a port in +@@ -53,27 +61,21 @@ + static void putc(int c) + { + #ifdef UART_OFFSET +- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */ +- +- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY)) ++ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY)) + barrier(); +- __raw_writel(c, sys + ATMEL_US_THR); ++ __raw_writel(c, at91_uart + ATMEL_US_THR); + #endif + } + + static inline void flush(void) + { + #ifdef UART_OFFSET +- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */ +- + /* wait for transmission to complete */ +- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) ++ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) + barrier(); + #endif + } + +-#define arch_decomp_setup() +- + #define arch_decomp_wdog() + + #endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch b/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch new file mode 100644 index 00000000000000..b54384b26e4b9c --- /dev/null +++ b/patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch @@ -0,0 +1,494 @@ +From e740a739f469c0128ad12bf8388cdb69bdccc005 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 + +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). + +This also allows to include all soc headers together. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 53 -------- + arch/arm/mach-at91/include/mach/at91rm9200.h | 5 - + arch/arm/mach-at91/include/mach/at91sam9260.h | 7 -- + arch/arm/mach-at91/include/mach/at91sam9261.h | 4 - + arch/arm/mach-at91/include/mach/at91sam9263.h | 4 - + arch/arm/mach-at91/include/mach/at91sam9g45.h | 5 - + arch/arm/mach-at91/include/mach/at91sam9rl.h | 5 - + arch/arm/mach-at91/include/mach/at91sam9x5.h | 8 -- + arch/arm/mach-at91/include/mach/hardware.h | 16 +-- + arch/arm/mach-at91/include/mach/uncompress.h | 170 ++++++++++++++++++++++---- + 10 files changed, 148 insertions(+), 129 deletions(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 8acc164..885fdb9 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -9,15 +9,6 @@ config HAVE_AT91_DBGU0 + config HAVE_AT91_DBGU1 + bool + +-config HAVE_AT91_USART3 +- bool +- +-config HAVE_AT91_USART4 +- bool +- +-config HAVE_AT91_USART5 +- bool +- + config AT91_SAM9_ALT_RESET + bool + default !ARCH_AT91X40 +@@ -36,16 +27,12 @@ config ARCH_AT91RM9200 + select CPU_ARM920T + select GENERIC_CLOCKEVENTS + select HAVE_AT91_DBGU0 +- select HAVE_AT91_USART3 + + config ARCH_AT91SAM9260 + bool "AT91SAM9260 or AT91SAM9XE" + select CPU_ARM926T + select GENERIC_CLOCKEVENTS + select HAVE_AT91_DBGU0 +- select HAVE_AT91_USART3 +- select HAVE_AT91_USART4 +- select HAVE_AT91_USART5 + select HAVE_NET_MACB + + config ARCH_AT91SAM9261 +@@ -74,7 +61,6 @@ config ARCH_AT91SAM9RL + bool "AT91SAM9RL" + select CPU_ARM926T + select GENERIC_CLOCKEVENTS +- select HAVE_AT91_USART3 + select HAVE_FB_ATMEL + select HAVE_AT91_DBGU0 + +@@ -83,16 +69,12 @@ config ARCH_AT91SAM9G20 + select CPU_ARM926T + select GENERIC_CLOCKEVENTS + select HAVE_AT91_DBGU0 +- select HAVE_AT91_USART3 +- select HAVE_AT91_USART4 +- select HAVE_AT91_USART5 + select HAVE_NET_MACB + + config ARCH_AT91SAM9G45 + bool "AT91SAM9G45 or AT91SAM9M10 families" + select CPU_ARM926T + select GENERIC_CLOCKEVENTS +- select HAVE_AT91_USART3 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU1 +@@ -526,41 +508,6 @@ config AT91_TIMER_HZ + system clock (of at least several MHz), rounding is less of a + problem so it can be safer to use a decimal values like 100. + +-choice +- prompt "Select a UART for early kernel messages" +- +-config AT91_EARLY_DBGU0 +- bool "DBGU on rm9200, 9260/9g20, 9261/9g10, 9rl and 9x5" +- depends on HAVE_AT91_DBGU0 +- +-config AT91_EARLY_DBGU1 +- bool "DBGU on 9263 and 9g45" +- depends on HAVE_AT91_DBGU1 +- +-config AT91_EARLY_USART0 +- bool "USART0" +- +-config AT91_EARLY_USART1 +- bool "USART1" +- +-config AT91_EARLY_USART2 +- bool "USART2" +- depends on ! ARCH_AT91X40 +- +-config AT91_EARLY_USART3 +- bool "USART3" +- depends on HAVE_AT91_USART3 +- +-config AT91_EARLY_USART4 +- bool "USART4" +- depends on HAVE_AT91_USART4 +- +-config AT91_EARLY_USART5 +- bool "USART5" +- depends on HAVE_AT91_USART5 +- +-endchoice +- + endmenu + + endif +diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h +index 603e6aa..e67317c 100644 +--- a/arch/arm/mach-at91/include/mach/at91rm9200.h ++++ b/arch/arm/mach-at91/include/mach/at91rm9200.h +@@ -88,11 +88,6 @@ + #define AT91RM9200_BASE_RTC 0xfffffe00 /* Real-Time Clock */ + #define AT91RM9200_BASE_MC 0xffffff00 /* Memory Controllers */ + +-#define AT91_USART0 AT91RM9200_BASE_US0 +-#define AT91_USART1 AT91RM9200_BASE_US1 +-#define AT91_USART2 AT91RM9200_BASE_US2 +-#define AT91_USART3 AT91RM9200_BASE_US3 +- + /* + * Internal Memory. + */ +diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h +index 08ae9af..416c7b6 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9260.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9260.h +@@ -95,13 +95,6 @@ + #define AT91SAM9260_BASE_WDT 0xfffffd40 + #define AT91SAM9260_BASE_GPBR 0xfffffd50 + +-#define AT91_USART0 AT91SAM9260_BASE_US0 +-#define AT91_USART1 AT91SAM9260_BASE_US1 +-#define AT91_USART2 AT91SAM9260_BASE_US2 +-#define AT91_USART3 AT91SAM9260_BASE_US3 +-#define AT91_USART4 AT91SAM9260_BASE_US4 +-#define AT91_USART5 AT91SAM9260_BASE_US5 +- + + /* + * Internal Memory. +diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h +index 44fbdc1..a041406 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9261.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9261.h +@@ -79,10 +79,6 @@ + #define AT91SAM9261_BASE_WDT 0xfffffd40 + #define AT91SAM9261_BASE_GPBR 0xfffffd50 + +-#define AT91_USART0 AT91SAM9261_BASE_US0 +-#define AT91_USART1 AT91SAM9261_BASE_US1 +-#define AT91_USART2 AT91SAM9261_BASE_US2 +- + + /* + * Internal Memory. +diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h +index d96cbb2..d201029 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9263.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9263.h +@@ -95,10 +95,6 @@ + #define AT91SAM9263_BASE_RTT1 0xfffffd50 + #define AT91SAM9263_BASE_GPBR 0xfffffd60 + +-#define AT91_USART0 AT91SAM9263_BASE_US0 +-#define AT91_USART1 AT91SAM9263_BASE_US1 +-#define AT91_USART2 AT91SAM9263_BASE_US2 +- + #define AT91_SMC AT91_SMC0 + + /* +diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h +index d052abc..3a4da24 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h +@@ -106,11 +106,6 @@ + #define AT91SAM9G45_BASE_RTC 0xfffffdb0 + #define AT91SAM9G45_BASE_GPBR 0xfffffd60 + +-#define AT91_USART0 AT91SAM9G45_BASE_US0 +-#define AT91_USART1 AT91SAM9G45_BASE_US1 +-#define AT91_USART2 AT91SAM9G45_BASE_US2 +-#define AT91_USART3 AT91SAM9G45_BASE_US3 +- + /* + * Internal Memory. + */ +diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h +index e0073eb..a15db56 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9rl.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h +@@ -89,11 +89,6 @@ + #define AT91SAM9RL_BASE_GPBR 0xfffffd60 + #define AT91SAM9RL_BASE_RTC 0xfffffe00 + +-#define AT91_USART0 AT91SAM9RL_BASE_US0 +-#define AT91_USART1 AT91SAM9RL_BASE_US1 +-#define AT91_USART2 AT91SAM9RL_BASE_US2 +-#define AT91_USART3 AT91SAM9RL_BASE_US3 +- + + /* + * Internal Memory. +diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h +index 88e43d5..c75ee19 100644 +--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h ++++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h +@@ -55,14 +55,6 @@ + #define AT91SAM9X5_BASE_USART2 0xf8024000 + + /* +- * Base addresses for early serial code (uncompress.h) +- */ +-#define AT91_DBGU AT91_BASE_DBGU0 +-#define AT91_USART0 AT91SAM9X5_BASE_USART0 +-#define AT91_USART1 AT91SAM9X5_BASE_USART1 +-#define AT91_USART2 AT91SAM9X5_BASE_USART2 +- +-/* + * Internal Memory. + */ + #define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */ +diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h +index e9e29a6..3a01f8f 100644 +--- a/arch/arm/mach-at91/include/mach/hardware.h ++++ b/arch/arm/mach-at91/include/mach/hardware.h +@@ -22,27 +22,17 @@ + /* 9263, 9g45 */ + #define AT91_BASE_DBGU1 0xffffee00 + +-#if defined(CONFIG_ARCH_AT91RM9200) ++#if defined(CONFIG_ARCH_AT91X40) ++#include <mach/at91x40.h> ++#else + #include <mach/at91rm9200.h> +-#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20) + #include <mach/at91sam9260.h> +-#elif defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10) + #include <mach/at91sam9261.h> +-#elif defined(CONFIG_ARCH_AT91SAM9263) + #include <mach/at91sam9263.h> +-#elif defined(CONFIG_ARCH_AT91SAM9RL) + #include <mach/at91sam9rl.h> +-#elif defined(CONFIG_ARCH_AT91SAM9G45) + #include <mach/at91sam9g45.h> +-#elif defined(CONFIG_ARCH_AT91SAM9X5) + #include <mach/at91sam9x5.h> +-#elif defined(CONFIG_ARCH_AT91X40) +-#include <mach/at91x40.h> +-#else +-#error "Unsupported AT91 processor" +-#endif + +-#if !defined(CONFIG_ARCH_AT91X40) + /* + * On all at91 except rm9200 and x40 have the System Controller starts + * at address 0xffffc000 and has a size of 16KiB. +diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h +index d985af7..6f6118d 100644 +--- a/arch/arm/mach-at91/include/mach/uncompress.h ++++ b/arch/arm/mach-at91/include/mach/uncompress.h +@@ -1,7 +1,8 @@ + /* + * arch/arm/mach-at91/include/mach/uncompress.h + * +- * Copyright (C) 2003 SAN People ++ * Copyright (C) 2003 SAN People ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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 +@@ -25,32 +26,149 @@ + #include <linux/atmel_serial.h> + #include <mach/hardware.h> + +-#if defined(CONFIG_AT91_EARLY_DBGU0) +-#define UART_OFFSET AT91_BASE_DBGU0 +-#elif defined(CONFIG_AT91_EARLY_DBGU1) +-#define UART_OFFSET AT91_BASE_DBGU1 +-#elif defined(CONFIG_AT91_EARLY_USART0) +-#define UART_OFFSET AT91_USART0 +-#elif defined(CONFIG_AT91_EARLY_USART1) +-#define UART_OFFSET AT91_USART1 +-#elif defined(CONFIG_AT91_EARLY_USART2) +-#define UART_OFFSET AT91_USART2 +-#elif defined(CONFIG_AT91_EARLY_USART3) +-#define UART_OFFSET AT91_USART3 +-#elif defined(CONFIG_AT91_EARLY_USART4) +-#define UART_OFFSET AT91_USART4 +-#elif defined(CONFIG_AT91_EARLY_USART5) +-#define UART_OFFSET AT91_USART5 +-#endif ++#include <mach/at91_dbgu.h> ++#include <mach/cpu.h> + + void __iomem *at91_uart; + ++#if !defined(CONFIG_ARCH_AT91X40) ++static const u32 uarts_rm9200[] = { ++ AT91_BASE_DBGU0, ++ AT91RM9200_BASE_US0, ++ AT91RM9200_BASE_US1, ++ AT91RM9200_BASE_US2, ++ AT91RM9200_BASE_US3, ++ 0, ++}; ++ ++static const u32 uarts_sam9260[] = { ++ AT91_BASE_DBGU0, ++ AT91SAM9260_BASE_US0, ++ AT91SAM9260_BASE_US1, ++ AT91SAM9260_BASE_US2, ++ AT91SAM9260_BASE_US3, ++ AT91SAM9260_BASE_US4, ++ AT91SAM9260_BASE_US5, ++ 0, ++}; ++ ++static const u32 uarts_sam9261[] = { ++ AT91_BASE_DBGU0, ++ AT91SAM9261_BASE_US0, ++ AT91SAM9261_BASE_US1, ++ AT91SAM9261_BASE_US2, ++ 0, ++}; ++ ++static const u32 uarts_sam9263[] = { ++ AT91_BASE_DBGU1, ++ AT91SAM9263_BASE_US0, ++ AT91SAM9263_BASE_US1, ++ AT91SAM9263_BASE_US2, ++ 0, ++}; ++ ++static const u32 uarts_sam9g45[] = { ++ AT91_BASE_DBGU1, ++ AT91SAM9G45_BASE_US0, ++ AT91SAM9G45_BASE_US1, ++ AT91SAM9G45_BASE_US2, ++ AT91SAM9G45_BASE_US3, ++ 0, ++}; ++ ++static const u32 uarts_sam9rl[] = { ++ AT91_BASE_DBGU0, ++ AT91SAM9RL_BASE_US0, ++ AT91SAM9RL_BASE_US1, ++ AT91SAM9RL_BASE_US2, ++ AT91SAM9RL_BASE_US3, ++ 0, ++}; ++ ++static const u32 uarts_sam9x5[] = { ++ AT91_BASE_DBGU0, ++ AT91SAM9X5_BASE_USART0, ++ AT91SAM9X5_BASE_USART1, ++ AT91SAM9X5_BASE_USART2, ++ 0, ++}; ++ ++static inline const u32* decomp_soc_detect(u32 dbgu_base) ++{ ++ u32 cidr, socid; ++ ++ cidr = __raw_readl(dbgu_base + AT91_DBGU_CIDR); ++ socid = cidr & ~AT91_CIDR_VERSION; ++ ++ switch (socid) { ++ case ARCH_ID_AT91RM9200: ++ return uarts_rm9200; ++ ++ case ARCH_ID_AT91SAM9G20: ++ case ARCH_ID_AT91SAM9260: ++ return uarts_sam9260; ++ ++ case ARCH_ID_AT91SAM9261: ++ return uarts_sam9261; ++ ++ case ARCH_ID_AT91SAM9263: ++ return uarts_sam9263; ++ ++ case ARCH_ID_AT91SAM9G45: ++ return uarts_sam9g45; ++ ++ case ARCH_ID_AT91SAM9RL64: ++ return uarts_sam9rl; ++ ++ case ARCH_ID_AT91SAM9X5: ++ return uarts_sam9x5; ++ } ++ ++ /* at91sam9g10 */ ++ if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) { ++ return uarts_sam9261; ++ } ++ /* at91sam9xe */ ++ else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) { ++ return uarts_sam9260; ++ } ++ ++ return NULL; ++} ++ + static inline void arch_decomp_setup(void) + { +-#ifdef UART_OFFSET +- at91_uart = (void __iomem *) UART_OFFSET; /* physical address */ +-#endif ++ int i = 0; ++ const u32* usarts; ++ ++ usarts = decomp_soc_detect(AT91_BASE_DBGU0); ++ ++ if (!usarts) ++ usarts = decomp_soc_detect(AT91_BASE_DBGU1); ++ if (!usarts) { ++ at91_uart = NULL; ++ return; ++ } ++ ++ do { ++ /* physical address */ ++ at91_uart = (void __iomem *)usarts[i]; ++ ++ if (__raw_readl(at91_uart + ATMEL_US_BRGR)) ++ return; ++ i++; ++ } while (usarts[i]); ++ ++ at91_uart = NULL; + } ++#else ++static inline void arch_decomp_setup(void) ++{ ++ at91_uart = NULL; ++} ++#endif ++ + /* + * The following code assumes the serial port has already been + * initialized by the bootloader. If you didn't setup a port in +@@ -60,20 +178,22 @@ static inline void arch_decomp_setup(void) + */ + static void putc(int c) + { +-#ifdef UART_OFFSET ++ if (!at91_uart) ++ return; ++ + while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY)) + barrier(); + __raw_writel(c, at91_uart + ATMEL_US_THR); +-#endif + } + + static inline void flush(void) + { +-#ifdef UART_OFFSET ++ if (!at91_uart) ++ return; ++ + /* wait for transmission to complete */ + while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY)) + barrier(); +-#endif + } + + #define arch_decomp_wdog() +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch b/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch new file mode 100644 index 00000000000000..d394110e4a3018 --- /dev/null +++ b/patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch @@ -0,0 +1,882 @@ +From 9e4b59887ceab4e5a9a311f91da86196106c75c1 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 + +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. +And then the command-line arguments provided by the boot loader will be +appended to the default kernel command string. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91rm9200.c | 12 ------------ + arch/arm/mach-at91/at91rm9200_devices.c | 12 ------------ + arch/arm/mach-at91/at91sam9260.c | 12 ------------ + arch/arm/mach-at91/at91sam9260_devices.c | 12 ------------ + arch/arm/mach-at91/at91sam9261.c | 12 ------------ + arch/arm/mach-at91/at91sam9261_devices.c | 12 ------------ + arch/arm/mach-at91/at91sam9263.c | 12 ------------ + arch/arm/mach-at91/at91sam9263_devices.c | 12 ------------ + arch/arm/mach-at91/at91sam9g45.c | 12 ------------ + arch/arm/mach-at91/at91sam9g45_devices.c | 12 ------------ + arch/arm/mach-at91/at91sam9rl.c | 12 ------------ + arch/arm/mach-at91/at91sam9rl_devices.c | 12 ------------ + arch/arm/mach-at91/board-1arm.c | 3 --- + arch/arm/mach-at91/board-afeb-9260v1.c | 3 --- + arch/arm/mach-at91/board-cam60.c | 3 --- + arch/arm/mach-at91/board-carmeva.c | 3 --- + arch/arm/mach-at91/board-cpu9krea.c | 3 --- + arch/arm/mach-at91/board-cpuat91.c | 3 --- + arch/arm/mach-at91/board-csb337.c | 3 --- + arch/arm/mach-at91/board-csb637.c | 3 --- + arch/arm/mach-at91/board-eb9200.c | 3 --- + arch/arm/mach-at91/board-ecbat91.c | 3 --- + arch/arm/mach-at91/board-eco920.c | 3 --- + arch/arm/mach-at91/board-flexibity.c | 3 --- + arch/arm/mach-at91/board-foxg20.c | 3 --- + arch/arm/mach-at91/board-kafa.c | 3 --- + arch/arm/mach-at91/board-kb9202.c | 3 --- + arch/arm/mach-at91/board-neocore926.c | 3 --- + arch/arm/mach-at91/board-picotux200.c | 3 --- + arch/arm/mach-at91/board-qil-a9260.c | 4 ---- + arch/arm/mach-at91/board-rm9200dk.c | 3 --- + arch/arm/mach-at91/board-rm9200ek.c | 3 --- + arch/arm/mach-at91/board-rsi-ews.c | 3 --- + arch/arm/mach-at91/board-sam9-l9260.c | 3 --- + arch/arm/mach-at91/board-sam9260ek.c | 3 --- + arch/arm/mach-at91/board-sam9261ek.c | 3 --- + arch/arm/mach-at91/board-sam9263ek.c | 3 --- + arch/arm/mach-at91/board-sam9g20ek.c | 3 --- + arch/arm/mach-at91/board-sam9m10g45ek.c | 3 --- + arch/arm/mach-at91/board-sam9rlek.c | 3 --- + arch/arm/mach-at91/board-snapper9260.c | 1 - + arch/arm/mach-at91/board-stamp9g20.c | 3 --- + arch/arm/mach-at91/board-usb-a926x.c | 3 --- + arch/arm/mach-at91/board-yl-9200.c | 3 --- + arch/arm/mach-at91/generic.h | 11 ----------- + arch/arm/mach-at91/include/mach/board.h | 1 - + 46 files changed, 251 deletions(-) + +diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c +index 364c193..d50da1a 100644 +--- a/arch/arm/mach-at91/at91rm9200.c ++++ b/arch/arm/mach-at91/at91rm9200.c +@@ -258,18 +258,6 @@ static void __init at91rm9200_register_clocks(void) + clk_register(&pck3); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91rm9200_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c +index 05774e5..99affb5 100644 +--- a/arch/arm/mach-at91/at91rm9200_devices.c ++++ b/arch/arm/mach-at91/at91rm9200_devices.c +@@ -1152,14 +1152,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91rm9200_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1168,13 +1160,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c +index 46f7742..a27bbec 100644 +--- a/arch/arm/mach-at91/at91sam9260.c ++++ b/arch/arm/mach-at91/at91sam9260.c +@@ -268,18 +268,6 @@ static void __init at91sam9260_register_clocks(void) + clk_register(&pck1); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91sam9260_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c +index 5652dde..ad00fe9 100644 +--- a/arch/arm/mach-at91/at91sam9260_devices.c ++++ b/arch/arm/mach-at91/at91sam9260_devices.c +@@ -1229,14 +1229,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91sam9260_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1245,13 +1237,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c +index 7de81e6..c77d503 100644 +--- a/arch/arm/mach-at91/at91sam9261.c ++++ b/arch/arm/mach-at91/at91sam9261.c +@@ -239,18 +239,6 @@ static void __init at91sam9261_register_clocks(void) + clk_register(&hck1); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91sam9261_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c +index 4db961a..9295e90 100644 +--- a/arch/arm/mach-at91/at91sam9261_devices.c ++++ b/arch/arm/mach-at91/at91sam9261_devices.c +@@ -1051,14 +1051,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91sam9261_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1067,13 +1059,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c +index ef301be..7fae365 100644 +--- a/arch/arm/mach-at91/at91sam9263.c ++++ b/arch/arm/mach-at91/at91sam9263.c +@@ -255,18 +255,6 @@ static void __init at91sam9263_register_clocks(void) + clk_register(&pck3); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91sam9263_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c +index fe99206..dfe5bc0 100644 +--- a/arch/arm/mach-at91/at91sam9263_devices.c ++++ b/arch/arm/mach-at91/at91sam9263_devices.c +@@ -1461,14 +1461,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91sam9263_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1477,13 +1469,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c +index d222f83..f205449 100644 +--- a/arch/arm/mach-at91/at91sam9g45.c ++++ b/arch/arm/mach-at91/at91sam9g45.c +@@ -288,18 +288,6 @@ static void __init at91sam9g45_register_clocks(void) + clk_register(&pck1); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91sam9g45_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c +index 6b008ae..db2f88c2 100644 +--- a/arch/arm/mach-at91/at91sam9g45_devices.c ++++ b/arch/arm/mach-at91/at91sam9g45_devices.c +@@ -1741,14 +1741,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91sam9g45_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1757,13 +1749,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c +index d9f2774..e420085 100644 +--- a/arch/arm/mach-at91/at91sam9rl.c ++++ b/arch/arm/mach-at91/at91sam9rl.c +@@ -232,18 +232,6 @@ static void __init at91sam9rl_register_clocks(void) + clk_register(&pck1); + } + +-static struct clk_lookup console_clock_lookup; +- +-void __init at91sam9rl_set_console_clock(int id) +-{ +- if (id >= ARRAY_SIZE(usart_clocks_lookups)) +- return; +- +- console_clock_lookup.con_id = "usart"; +- console_clock_lookup.clk = usart_clocks_lookups[id].clk; +- clkdev_add(&console_clock_lookup); +-} +- + /* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ +diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c +index fe4ae22..9c0b148 100644 +--- a/arch/arm/mach-at91/at91sam9rl_devices.c ++++ b/arch/arm/mach-at91/at91sam9rl_devices.c +@@ -1192,14 +1192,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) + at91_uarts[portnr] = pdev; + } + +-void __init at91_set_serial_console(unsigned portnr) +-{ +- if (portnr < ATMEL_MAX_UART) { +- atmel_default_console_device = at91_uarts[portnr]; +- at91sam9rl_set_console_clock(at91_uarts[portnr]->id); +- } +-} +- + void __init at91_add_device_serial(void) + { + int i; +@@ -1208,13 +1200,9 @@ void __init at91_add_device_serial(void) + if (at91_uarts[i]) + platform_device_register(at91_uarts[i]); + } +- +- if (!atmel_default_console_device) +- printk(KERN_INFO "AT91: No default serial console defined.\n"); + } + #else + void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {} +-void __init at91_set_serial_console(unsigned portnr) {} + void __init at91_add_device_serial(void) {} + #endif + +diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c +index 2628384..f43ad91 100644 +--- a/arch/arm/mach-at91/board-1arm.c ++++ b/arch/arm/mach-at91/board-1arm.c +@@ -58,9 +58,6 @@ static void __init onearm_init_early(void) + at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata onearm_eth_data = { +diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c +index 161efba..7c7c682 100644 +--- a/arch/arm/mach-at91/board-afeb-9260v1.c ++++ b/arch/arm/mach-at91/board-afeb-9260v1.c +@@ -65,9 +65,6 @@ static void __init afeb9260_init_early(void) + /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9260_ID_US1, 2, + ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c +index c6d44ee..871717d 100644 +--- a/arch/arm/mach-at91/board-cam60.c ++++ b/arch/arm/mach-at91/board-cam60.c +@@ -52,9 +52,6 @@ static void __init cam60_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c +index 59d9cf9..168b3fa 100644 +--- a/arch/arm/mach-at91/board-carmeva.c ++++ b/arch/arm/mach-at91/board-carmeva.c +@@ -52,9 +52,6 @@ static void __init carmeva_init_early(void) + at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata carmeva_eth_data = { +diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c +index 5f3680e..4073e30 100644 +--- a/arch/arm/mach-at91/board-cpu9krea.c ++++ b/arch/arm/mach-at91/board-cpu9krea.c +@@ -77,9 +77,6 @@ static void __init cpu9krea_init_early(void) + + /* USART5 on ttyS6. (Rx, Tx) */ + at91_register_uart(AT91SAM9260_ID_US5, 6, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c +index e094cc8..76c62ed 100644 +--- a/arch/arm/mach-at91/board-cpuat91.c ++++ b/arch/arm/mach-at91/board-cpuat91.c +@@ -78,9 +78,6 @@ static void __init cpuat91_init_early(void) + /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS | + ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata cpuat91_eth_data = { +diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c +index 1a1547b..d984435 100644 +--- a/arch/arm/mach-at91/board-csb337.c ++++ b/arch/arm/mach-at91/board-csb337.c +@@ -53,9 +53,6 @@ static void __init csb337_init_early(void) + + /* DBGU on ttyS0 */ + at91_register_uart(0, 0, 0); +- +- /* make console=ttyS0 the default */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata csb337_eth_data = { +diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c +index f650bf3..0c9935d 100644 +--- a/arch/arm/mach-at91/board-csb637.c ++++ b/arch/arm/mach-at91/board-csb637.c +@@ -47,9 +47,6 @@ static void __init csb637_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* make console=ttyS0 (ie, DBGU) the default */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata csb637_eth_data = { +diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c +index d302ca3..a189b9f 100644 +--- a/arch/arm/mach-at91/board-eb9200.c ++++ b/arch/arm/mach-at91/board-eb9200.c +@@ -55,9 +55,6 @@ static void __init eb9200_init_early(void) + + /* USART2 on ttyS2. (Rx, Tx) - IRDA */ + at91_register_uart(AT91RM9200_ID_US2, 2, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata eb9200_eth_data = { +diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c +index 69966ce..307c530 100644 +--- a/arch/arm/mach-at91/board-ecbat91.c ++++ b/arch/arm/mach-at91/board-ecbat91.c +@@ -59,9 +59,6 @@ static void __init ecb_at91init_early(void) + + /* USART0 on ttyS1. (Rx & Tx only) */ + at91_register_uart(AT91RM9200_ID_US0, 1, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata ecb_at91eth_data = { +diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c +index f23aabe..7df6a9b 100644 +--- a/arch/arm/mach-at91/board-eco920.c ++++ b/arch/arm/mach-at91/board-eco920.c +@@ -43,9 +43,6 @@ static void __init eco920_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata eco920_eth_data = { +diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c +index 1815152..6dcc962 100644 +--- a/arch/arm/mach-at91/board-flexibity.c ++++ b/arch/arm/mach-at91/board-flexibity.c +@@ -44,9 +44,6 @@ static void __init flexibity_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* USB Host port */ +diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c +index caf017f..bb07807 100644 +--- a/arch/arm/mach-at91/board-foxg20.c ++++ b/arch/arm/mach-at91/board-foxg20.c +@@ -93,9 +93,6 @@ static void __init foxg20_init_early(void) + /* USART5 on ttyS6. (Rx & Tx only) */ + at91_register_uart(AT91SAM9260_ID_US5, 6, 0); + +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); +- + /* Set the internal pull-up resistor on DRXD */ + at91_set_A_periph(AT91_PIN_PB14, 1); + +diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c +index efde1b2..3e858ed 100644 +--- a/arch/arm/mach-at91/board-kafa.c ++++ b/arch/arm/mach-at91/board-kafa.c +@@ -56,9 +56,6 @@ static void __init kafa_init_early(void) + + /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata kafa_eth_data = { +diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c +index 59b92aa..ccbc8be 100644 +--- a/arch/arm/mach-at91/board-kb9202.c ++++ b/arch/arm/mach-at91/board-kb9202.c +@@ -65,9 +65,6 @@ static void __init kb9202_init_early(void) + + /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */ + at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata kb9202_eth_data = { +diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c +index 57d5f6a..c456fdc 100644 +--- a/arch/arm/mach-at91/board-neocore926.c ++++ b/arch/arm/mach-at91/board-neocore926.c +@@ -61,9 +61,6 @@ static void __init neocore926_init_early(void) + + /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c +index 59e35dd..4ca56cd 100644 +--- a/arch/arm/mach-at91/board-picotux200.c ++++ b/arch/arm/mach-at91/board-picotux200.c +@@ -56,9 +56,6 @@ static void __init picotux200_init_early(void) + at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata picotux200_eth_data = { +diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c +index b6ed5ed..189d3fe 100644 +--- a/arch/arm/mach-at91/board-qil-a9260.c ++++ b/arch/arm/mach-at91/board-qil-a9260.c +@@ -66,10 +66,6 @@ static void __init ek_init_early(void) + + /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS1 (ie, USART0) */ +- at91_set_serial_console(1); +- + } + + /* +diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c +index 01332aa..d5ce630 100644 +--- a/arch/arm/mach-at91/board-rm9200dk.c ++++ b/arch/arm/mach-at91/board-rm9200dk.c +@@ -61,9 +61,6 @@ static void __init dk_init_early(void) + at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata dk_eth_data = { +diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c +index b2e4fe2..e96d5f5 100644 +--- a/arch/arm/mach-at91/board-rm9200ek.c ++++ b/arch/arm/mach-at91/board-rm9200ek.c +@@ -61,9 +61,6 @@ static void __init ek_init_early(void) + at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS + | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD + | ATMEL_UART_RI); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static struct macb_platform_data __initdata ek_eth_data = { +diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c +index af0750f..2c84463 100644 +--- a/arch/arm/mach-at91/board-rsi-ews.c ++++ b/arch/arm/mach-at91/board-rsi-ews.c +@@ -52,9 +52,6 @@ static void __init rsi_ews_init_early(void) + /* USART3 on ttyS4. (Rx, Tx, RTS) */ + /* RS485 communication */ + at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c +index e8b116b..dee44cb 100644 +--- a/arch/arm/mach-at91/board-sam9-l9260.c ++++ b/arch/arm/mach-at91/board-sam9-l9260.c +@@ -62,9 +62,6 @@ static void __init ek_init_early(void) + + /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c +index d5aec55..6da17b5 100644 +--- a/arch/arm/mach-at91/board-sam9260ek.c ++++ b/arch/arm/mach-at91/board-sam9260ek.c +@@ -65,9 +65,6 @@ static void __init ek_init_early(void) + + /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c +index 065fed3..950c20b 100644 +--- a/arch/arm/mach-at91/board-sam9261ek.c ++++ b/arch/arm/mach-at91/board-sam9261ek.c +@@ -64,9 +64,6 @@ static void __init ek_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c +index 2ffe50f..4424873 100644 +--- a/arch/arm/mach-at91/board-sam9263ek.c ++++ b/arch/arm/mach-at91/board-sam9263ek.c +@@ -63,9 +63,6 @@ static void __init ek_init_early(void) + + /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c +index 8923ec9..05f8467 100644 +--- a/arch/arm/mach-at91/board-sam9g20ek.c ++++ b/arch/arm/mach-at91/board-sam9g20ek.c +@@ -76,9 +76,6 @@ static void __init ek_init_early(void) + + /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c +index c88e908..be2ca19 100644 +--- a/arch/arm/mach-at91/board-sam9m10g45ek.c ++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c +@@ -60,9 +60,6 @@ static void __init ek_init_early(void) + /* USART0 not connected on the -EK board */ + /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ + at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c +index b109ce2..23f383a 100644 +--- a/arch/arm/mach-at91/board-sam9rlek.c ++++ b/arch/arm/mach-at91/board-sam9rlek.c +@@ -48,9 +48,6 @@ static void __init ek_init_early(void) + + /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ + at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c +index ebc9d01..1a6774a 100644 +--- a/arch/arm/mach-at91/board-snapper9260.c ++++ b/arch/arm/mach-at91/board-snapper9260.c +@@ -46,7 +46,6 @@ static void __init snapper9260_init_early(void) + + /* Debug on ttyS0 */ + at91_register_uart(0, 0, 0); +- at91_set_serial_console(0); + + at91_register_uart(AT91SAM9260_ID_US0, 1, + ATMEL_UART_CTS | ATMEL_UART_RTS); +diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c +index 7640049..38a7ca5 100644 +--- a/arch/arm/mach-at91/board-stamp9g20.c ++++ b/arch/arm/mach-at91/board-stamp9g20.c +@@ -39,9 +39,6 @@ void __init stamp9g20_init_early(void) + + /* DGBU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + static void __init stamp9g20evb_init_early(void) +diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c +index b7483a3..ee482eb 100644 +--- a/arch/arm/mach-at91/board-usb-a926x.c ++++ b/arch/arm/mach-at91/board-usb-a926x.c +@@ -56,9 +56,6 @@ static void __init ek_init_early(void) + + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c +index 38dd279..e94a04e 100644 +--- a/arch/arm/mach-at91/board-yl-9200.c ++++ b/arch/arm/mach-at91/board-yl-9200.c +@@ -75,9 +75,6 @@ static void __init yl9200_init_early(void) + + /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */ + at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS); +- +- /* set serial console to ttyS0 (ie, DBGU) */ +- at91_set_serial_console(0); + } + + /* +diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h +index dd9b346..0a60bf8 100644 +--- a/arch/arm/mach-at91/generic.h ++++ b/arch/arm/mach-at91/generic.h +@@ -40,17 +40,6 @@ extern struct sys_timer at91sam926x_timer; + extern struct sys_timer at91x40_timer; + + /* Clocks */ +-/* +- * function to specify the clock of the default console. As we do not +- * use the device/driver bus, the dev_name is not intialize. So we need +- * to link the clock to a specific con_id only "usart" +- */ +-extern void __init at91rm9200_set_console_clock(int id); +-extern void __init at91sam9260_set_console_clock(int id); +-extern void __init at91sam9261_set_console_clock(int id); +-extern void __init at91sam9263_set_console_clock(int id); +-extern void __init at91sam9rl_set_console_clock(int id); +-extern void __init at91sam9g45_set_console_clock(int id); + #ifdef CONFIG_AT91_PMC_UNIT + extern int __init at91_clock_init(unsigned long main_clock); + extern int __init at91_dt_clock_init(void); +diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h +index 49a8211..369afc2 100644 +--- a/arch/arm/mach-at91/include/mach/board.h ++++ b/arch/arm/mach-at91/include/mach/board.h +@@ -121,7 +121,6 @@ extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_de + #define ATMEL_UART_RI 0x20 + + extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins); +-extern void __init at91_set_serial_console(unsigned portnr); + + extern struct platform_device *atmel_default_console_device; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch b/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch new file mode 100644 index 00000000000000..7e4cfed4a69939 --- /dev/null +++ b/patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch @@ -0,0 +1,1405 @@ +From 01175552b5bdf3438fa9bb6acbbfa5498414d2ab 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 + +There is no need to pinmux the UART so early in the kernel. +Move it to the board init. + +This will also allow to finally move the gpio driver to platform device/driver. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-1arm.c | 21 +++++----- + arch/arm/mach-at91/board-afeb-9260v1.c | 25 ++++++------ + arch/arm/mach-at91/board-cam60.c | 5 +-- + arch/arm/mach-at91/board-carmeva.c | 15 ++++---- + arch/arm/mach-at91/board-cpu9krea.c | 49 ++++++++++++------------ + arch/arm/mach-at91/board-cpuat91.c | 37 +++++++++--------- + arch/arm/mach-at91/board-csb337.c | 5 +-- + arch/arm/mach-at91/board-csb637.c | 5 +-- + arch/arm/mach-at91/board-eb9200.c | 21 +++++----- + arch/arm/mach-at91/board-ecbat91.c | 11 +++--- + arch/arm/mach-at91/board-eco920.c | 5 +-- + arch/arm/mach-at91/board-flexibity.c | 5 +-- + arch/arm/mach-at91/board-foxg20.c | 68 ++++++++++++++++----------------- + arch/arm/mach-at91/board-gsia18s.c | 63 +++++++++++++++--------------- + arch/arm/mach-at91/board-kafa.c | 11 +++--- + arch/arm/mach-at91/board-kb9202.c | 23 ++++++----- + arch/arm/mach-at91/board-neocore926.c | 11 +++--- + arch/arm/mach-at91/board-pcontrol-g20.c | 21 +++++----- + arch/arm/mach-at91/board-picotux200.c | 15 ++++---- + arch/arm/mach-at91/board-qil-a9260.c | 27 +++++++------ + arch/arm/mach-at91/board-rm9200dk.c | 15 ++++---- + arch/arm/mach-at91/board-rm9200ek.c | 15 ++++---- + arch/arm/mach-at91/board-rsi-ews.c | 27 +++++++------ + arch/arm/mach-at91/board-sam9-l9260.c | 21 +++++----- + arch/arm/mach-at91/board-sam9260ek.c | 21 +++++----- + arch/arm/mach-at91/board-sam9261ek.c | 5 +-- + arch/arm/mach-at91/board-sam9263ek.c | 11 +++--- + arch/arm/mach-at91/board-sam9g20ek.c | 21 +++++----- + arch/arm/mach-at91/board-sam9m10g45ek.c | 13 +++---- + arch/arm/mach-at91/board-sam9rlek.c | 11 +++--- + arch/arm/mach-at91/board-snapper9260.c | 17 ++++----- + arch/arm/mach-at91/board-stamp9g20.c | 61 ++++++++++++----------------- + arch/arm/mach-at91/board-usb-a926x.c | 5 +-- + arch/arm/mach-at91/board-yl-9200.c | 27 +++++++------ + 34 files changed, 333 insertions(+), 380 deletions(-) + +diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c +index f43ad91..271f994 100644 +--- a/arch/arm/mach-at91/board-1arm.c ++++ b/arch/arm/mach-at91/board-1arm.c +@@ -47,17 +47,6 @@ static void __init onearm_init_early(void) + + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); + } + + static struct macb_platform_data __initdata onearm_eth_data = { +@@ -79,6 +68,16 @@ static struct at91_udc_data __initdata onearm_udc_data = { + static void __init onearm_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&onearm_eth_data); +diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c +index 7c7c682..b7d8aa7 100644 +--- a/arch/arm/mach-at91/board-afeb-9260v1.c ++++ b/arch/arm/mach-at91/board-afeb-9260v1.c +@@ -52,19 +52,6 @@ static void __init afeb9260_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, +- ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR +- | ATMEL_UART_DCD | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, +- ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -180,6 +167,18 @@ static struct at91_cf_data afeb9260_cf_data = { + static void __init afeb9260_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ++ ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR ++ | ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ++ ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&afeb9260_usbh_data); +diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c +index 871717d..29d3ef0 100644 +--- a/arch/arm/mach-at91/board-cam60.c ++++ b/arch/arm/mach-at91/board-cam60.c +@@ -49,9 +49,6 @@ static void __init cam60_init_early(void) + { + /* Initialize processor: 10 MHz crystal */ + at91_initialize(10000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); + } + + /* +@@ -172,6 +169,8 @@ static void __init cam60_add_device_nand(void) + static void __init cam60_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* SPI */ + at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices)); +diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c +index 168b3fa..44328a6 100644 +--- a/arch/arm/mach-at91/board-carmeva.c ++++ b/arch/arm/mach-at91/board-carmeva.c +@@ -44,14 +44,6 @@ static void __init carmeva_init_early(void) + { + /* Initialize processor: 20.000 MHz crystal */ + at91_initialize(20000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); + } + + static struct macb_platform_data __initdata carmeva_eth_data = { +@@ -136,6 +128,13 @@ static struct gpio_led carmeva_leds[] = { + static void __init carmeva_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&carmeva_eth_data); +diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c +index 4073e30..69951ec 100644 +--- a/arch/arm/mach-at91/board-cpu9krea.c ++++ b/arch/arm/mach-at91/board-cpu9krea.c +@@ -52,31 +52,6 @@ static void __init cpu9krea_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DGBU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | +- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR | +- ATMEL_UART_DCD | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | +- ATMEL_UART_RTS); +- +- /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | +- ATMEL_UART_RTS); +- +- /* USART3 on ttyS4. (Rx, Tx) */ +- at91_register_uart(AT91SAM9260_ID_US3, 4, 0); +- +- /* USART4 on ttyS5. (Rx, Tx) */ +- at91_register_uart(AT91SAM9260_ID_US4, 5, 0); +- +- /* USART5 on ttyS6. (Rx, Tx) */ +- at91_register_uart(AT91SAM9260_ID_US5, 6, 0); + } + + /* +@@ -349,6 +324,30 @@ static void __init cpu9krea_board_init(void) + /* NOR */ + cpu9krea_add_device_nor(); + /* Serial */ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ++ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR | ++ ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ++ ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ++ ATMEL_UART_RTS); ++ ++ /* USART3 on ttyS4. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9260_ID_US3, 4, 0); ++ ++ /* USART4 on ttyS5. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0); ++ ++ /* USART5 on ttyS6. (Rx, Tx) */ ++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&cpu9krea_usbh_data); +diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c +index 76c62ed..895cf2d 100644 +--- a/arch/arm/mach-at91/board-cpuat91.c ++++ b/arch/arm/mach-at91/board-cpuat91.c +@@ -59,25 +59,6 @@ static void __init cpuat91_init_early(void) + + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | +- ATMEL_UART_RTS); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | +- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR | +- ATMEL_UART_DCD | ATMEL_UART_RI); +- +- /* USART2 on ttyS3 (Rx, Tx) */ +- at91_register_uart(AT91RM9200_ID_US2, 3, 0); +- +- /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS | +- ATMEL_UART_RTS); + } + + static struct macb_platform_data __initdata cpuat91_eth_data = { +@@ -158,6 +139,24 @@ static struct platform_device *platform_devices[] __initdata = { + static void __init cpuat91_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ++ ATMEL_UART_RTS); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ++ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR | ++ ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART2 on ttyS3 (Rx, Tx) */ ++ at91_register_uart(AT91RM9200_ID_US2, 3, 0); ++ ++ /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS | ++ ATMEL_UART_RTS); + at91_add_device_serial(); + /* LEDs. */ + at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds)); +diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c +index d984435..ad7f9f0 100644 +--- a/arch/arm/mach-at91/board-csb337.c ++++ b/arch/arm/mach-at91/board-csb337.c +@@ -50,9 +50,6 @@ static void __init csb337_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); +- +- /* DBGU on ttyS0 */ +- at91_register_uart(0, 0, 0); + } + + static struct macb_platform_data __initdata csb337_eth_data = { +@@ -226,6 +223,8 @@ static struct gpio_led csb_leds[] = { + static void __init csb337_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0 */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&csb337_eth_data); +diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c +index 0c9935d..7c8b05a 100644 +--- a/arch/arm/mach-at91/board-csb637.c ++++ b/arch/arm/mach-at91/board-csb637.c +@@ -44,9 +44,6 @@ static void __init csb637_init_early(void) + { + /* Initialize processor: 3.6864 MHz crystal */ + at91_initialize(3686400); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); + } + + static struct macb_platform_data __initdata csb637_eth_data = { +@@ -115,6 +112,8 @@ static void __init csb637_board_init(void) + /* LED(s) */ + at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds)); + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&csb637_eth_data); +diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c +index a189b9f..bd10172 100644 +--- a/arch/arm/mach-at91/board-eb9200.c ++++ b/arch/arm/mach-at91/board-eb9200.c +@@ -44,17 +44,6 @@ static void __init eb9200_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART2 on ttyS2. (Rx, Tx) - IRDA */ +- at91_register_uart(AT91RM9200_ID_US2, 2, 0); + } + + static struct macb_platform_data __initdata eb9200_eth_data = { +@@ -98,6 +87,16 @@ static struct i2c_board_info __initdata eb9200_i2c_devices[] = { + static void __init eb9200_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART2 on ttyS2. (Rx, Tx) - IRDA */ ++ at91_register_uart(AT91RM9200_ID_US2, 2, 0); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&eb9200_eth_data); +diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c +index 307c530..2510825 100644 +--- a/arch/arm/mach-at91/board-ecbat91.c ++++ b/arch/arm/mach-at91/board-ecbat91.c +@@ -53,12 +53,6 @@ static void __init ecb_at91init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx & Tx only) */ +- at91_register_uart(AT91RM9200_ID_US0, 1, 0); + } + + static struct macb_platform_data __initdata ecb_at91eth_data = { +@@ -149,6 +143,11 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = { + static void __init ecb_at91board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, 0); + at91_add_device_serial(); + + /* Ethernet */ +diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c +index 7df6a9b..bebeae8 100644 +--- a/arch/arm/mach-at91/board-eco920.c ++++ b/arch/arm/mach-at91/board-eco920.c +@@ -40,9 +40,6 @@ static void __init eco920_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); +- +- /* DBGU on ttyS0. (Rx & Tx only */ +- at91_register_uart(0, 0, 0); + } + + static struct macb_platform_data __initdata eco920_eth_data = { +@@ -100,6 +97,8 @@ static struct spi_board_info eco920_spi_devices[] = { + + static void __init eco920_board_init(void) + { ++ /* DBGU on ttyS0. (Rx & Tx only */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + at91_add_device_eth(&eco920_eth_data); + at91_add_device_usbh(&eco920_usbh_data); +diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c +index 6dcc962..47658f7 100644 +--- a/arch/arm/mach-at91/board-flexibity.c ++++ b/arch/arm/mach-at91/board-flexibity.c +@@ -41,9 +41,6 @@ static void __init flexibity_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); + } + + /* USB Host port */ +@@ -140,6 +137,8 @@ static struct gpio_led flexibity_leds[] = { + static void __init flexibity_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&flexibity_usbh_data); +diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c +index bb07807..33411e6 100644 +--- a/arch/arm/mach-at91/board-foxg20.c ++++ b/arch/arm/mach-at91/board-foxg20.c +@@ -61,41 +61,6 @@ static void __init foxg20_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, +- ATMEL_UART_CTS +- | ATMEL_UART_RTS +- | ATMEL_UART_DTR +- | ATMEL_UART_DSR +- | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, +- ATMEL_UART_CTS +- | ATMEL_UART_RTS); +- +- /* USART2 on ttyS3. (Rx & Tx only) */ +- at91_register_uart(AT91SAM9260_ID_US2, 3, 0); +- +- /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US3, 4, +- ATMEL_UART_CTS +- | ATMEL_UART_RTS); +- +- /* USART4 on ttyS5. (Rx & Tx only) */ +- at91_register_uart(AT91SAM9260_ID_US4, 5, 0); +- +- /* USART5 on ttyS6. (Rx & Tx only) */ +- at91_register_uart(AT91SAM9260_ID_US5, 6, 0); +- +- /* Set the internal pull-up resistor on DRXD */ +- at91_set_A_periph(AT91_PIN_PB14, 1); +- + } + + /* +@@ -238,6 +203,39 @@ static struct i2c_board_info __initdata foxg20_i2c_devices[] = { + static void __init foxg20_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ++ ATMEL_UART_CTS ++ | ATMEL_UART_RTS ++ | ATMEL_UART_DTR ++ | ATMEL_UART_DSR ++ | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ++ ATMEL_UART_CTS ++ | ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx & Tx only) */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, 0); ++ ++ /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US3, 4, ++ ATMEL_UART_CTS ++ | ATMEL_UART_RTS); ++ ++ /* USART4 on ttyS5. (Rx & Tx only) */ ++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0); ++ ++ /* USART5 on ttyS6. (Rx & Tx only) */ ++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0); ++ ++ /* Set the internal pull-up resistor on DRXD */ ++ at91_set_A_periph(AT91_PIN_PB14, 1); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&foxg20_usbh_data); +diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c +index 230e719..3e0dfa6 100644 +--- a/arch/arm/mach-at91/board-gsia18s.c ++++ b/arch/arm/mach-at91/board-gsia18s.c +@@ -41,38 +41,6 @@ + static void __init gsia18s_init_early(void) + { + stamp9g20_init_early(); +- +- /* +- * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI). +- * Used for Internal Analog Modem. +- */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, +- ATMEL_UART_CTS | ATMEL_UART_RTS | +- ATMEL_UART_DTR | ATMEL_UART_DSR | +- ATMEL_UART_DCD | ATMEL_UART_RI); +- /* +- * USART1 on ttyS2 (Rx, Tx, CTS, RTS). +- * Used for GPS or WiFi or Data stream. +- */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, +- ATMEL_UART_CTS | ATMEL_UART_RTS); +- /* +- * USART2 on ttyS3 (Rx, Tx, CTS, RTS). +- * Used for External Modem. +- */ +- at91_register_uart(AT91SAM9260_ID_US2, 3, +- ATMEL_UART_CTS | ATMEL_UART_RTS); +- /* +- * USART3 on ttyS4 (Rx, Tx, RTS). +- * Used for RS-485. +- */ +- at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS); +- +- /* +- * USART4 on ttyS5 (Rx, Tx). +- * Used for TRX433 Radio Module. +- */ +- at91_register_uart(AT91SAM9260_ID_US4, 5, 0); + } + + /* +@@ -558,6 +526,37 @@ static int __init gsia18s_power_off_init(void) + + static void __init gsia18s_board_init(void) + { ++ /* ++ * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI). ++ * Used for Internal Analog Modem. ++ */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ++ ATMEL_UART_CTS | ATMEL_UART_RTS | ++ ATMEL_UART_DTR | ATMEL_UART_DSR | ++ ATMEL_UART_DCD | ATMEL_UART_RI); ++ /* ++ * USART1 on ttyS2 (Rx, Tx, CTS, RTS). ++ * Used for GPS or WiFi or Data stream. ++ */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ++ ATMEL_UART_CTS | ATMEL_UART_RTS); ++ /* ++ * USART2 on ttyS3 (Rx, Tx, CTS, RTS). ++ * Used for External Modem. ++ */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, ++ ATMEL_UART_CTS | ATMEL_UART_RTS); ++ /* ++ * USART3 on ttyS4 (Rx, Tx, RTS). ++ * Used for RS-485. ++ */ ++ at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS); ++ ++ /* ++ * USART4 on ttyS5 (Rx, Tx). ++ * Used for TRX433 Radio Module. ++ */ ++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0); + stamp9g20_board_init(); + at91_add_device_usbh(&usbh_data); + at91_add_device_udc(&udc_data); +diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c +index 3e858ed..f46b3eb 100644 +--- a/arch/arm/mach-at91/board-kafa.c ++++ b/arch/arm/mach-at91/board-kafa.c +@@ -50,12 +50,6 @@ static void __init kafa_init_early(void) + + /* Set up the LEDs */ + at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + static struct macb_platform_data __initdata kafa_eth_data = { +@@ -77,6 +71,11 @@ static struct at91_udc_data __initdata kafa_udc_data = { + static void __init kafa_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&kafa_eth_data); +diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c +index ccbc8be..e71b9e1 100644 +--- a/arch/arm/mach-at91/board-kb9202.c ++++ b/arch/arm/mach-at91/board-kb9202.c +@@ -53,18 +53,6 @@ static void __init kb9202_init_early(void) + + /* Set up the LEDs */ + at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1 (Rx & Tx only) */ +- at91_register_uart(AT91RM9200_ID_US0, 1, 0); +- +- /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */ +- at91_register_uart(AT91RM9200_ID_US1, 2, 0); +- +- /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */ +- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + static struct macb_platform_data __initdata kb9202_eth_data = { +@@ -113,6 +101,17 @@ static struct atmel_nand_data __initdata kb9202_nand_data = { + static void __init kb9202_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1 (Rx & Tx only) */ ++ at91_register_uart(AT91RM9200_ID_US0, 1, 0); ++ ++ /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, 0); ++ ++ /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */ ++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&kb9202_eth_data); +diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c +index c456fdc..d2f4cc1 100644 +--- a/arch/arm/mach-at91/board-neocore926.c ++++ b/arch/arm/mach-at91/board-neocore926.c +@@ -55,12 +55,6 @@ static void __init neocore926_init_early(void) + { + /* Initialize processor: 20 MHz crystal */ + at91_initialize(20000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -338,6 +332,11 @@ static struct ac97c_platform_data neocore926_ac97_data = { + static void __init neocore926_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + + /* USB Host */ +diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c +index b4a12fc..7fe6383 100644 +--- a/arch/arm/mach-at91/board-pcontrol-g20.c ++++ b/arch/arm/mach-at91/board-pcontrol-g20.c +@@ -40,17 +40,6 @@ + static void __init pcontrol_g20_init_early(void) + { + stamp9g20_init_early(); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS +- | ATMEL_UART_RTS); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS +- | ATMEL_UART_RTS); +- +- /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */ +- at91_register_uart(AT91SAM9260_ID_US4, 3, 0); + } + + static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { { +@@ -199,6 +188,16 @@ static struct spi_board_info pcontrol_g20_spi_devices[] = { + + static void __init pcontrol_g20_board_init(void) + { ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS ++ | ATMEL_UART_RTS); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS ++ | ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */ ++ at91_register_uart(AT91SAM9260_ID_US4, 3, 0); + stamp9g20_board_init(); + at91_add_device_usbh(&usbh_data); + at91_add_device_eth(&macb_data); +diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c +index 4ca56cd..b45c0a5 100644 +--- a/arch/arm/mach-at91/board-picotux200.c ++++ b/arch/arm/mach-at91/board-picotux200.c +@@ -48,14 +48,6 @@ static void __init picotux200_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); + } + + static struct macb_platform_data __initdata picotux200_eth_data = { +@@ -103,6 +95,13 @@ static struct platform_device picotux200_flash = { + static void __init picotux200_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&picotux200_eth_data); +diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c +index 189d3fe..0c61bf0 100644 +--- a/arch/arm/mach-at91/board-qil-a9260.c ++++ b/arch/arm/mach-at91/board-qil-a9260.c +@@ -52,20 +52,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 12.000 MHz crystal */ + at91_initialize(12000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -231,6 +217,19 @@ static struct gpio_led ek_leds[] = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c +index d5ce630..4a0b097 100644 +--- a/arch/arm/mach-at91/board-rm9200dk.c ++++ b/arch/arm/mach-at91/board-rm9200dk.c +@@ -53,14 +53,6 @@ static void __init dk_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); + } + + static struct macb_platform_data __initdata dk_eth_data = { +@@ -188,6 +180,13 @@ static struct gpio_led dk_leds[] = { + static void __init dk_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&dk_eth_data); +diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c +index e96d5f5..6fa54ac 100644 +--- a/arch/arm/mach-at91/board-rm9200ek.c ++++ b/arch/arm/mach-at91/board-rm9200ek.c +@@ -53,14 +53,6 @@ static void __init ek_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); + } + + static struct macb_platform_data __initdata ek_eth_data = { +@@ -159,6 +151,13 @@ static struct gpio_led ek_leds[] = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&ek_eth_data); +diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c +index 2c84463..10d8730 100644 +--- a/arch/arm/mach-at91/board-rsi-ews.c ++++ b/arch/arm/mach-at91/board-rsi-ews.c +@@ -38,20 +38,6 @@ static void __init rsi_ews_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- /* This one is for debugging */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- /* Dialin/-out modem interface */ +- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART3 on ttyS4. (Rx, Tx, RTS) */ +- /* RS485 communication */ +- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS); + } + + /* +@@ -202,6 +188,19 @@ static struct platform_device rsiews_nor_flash = { + static void __init rsi_ews_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ /* This one is for debugging */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ /* Dialin/-out modem interface */ ++ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART3 on ttyS4. (Rx, Tx, RTS) */ ++ /* RS485 communication */ ++ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS); + at91_add_device_serial(); + at91_set_gpio_output(AT91_PIN_PA21, 0); + /* Ethernet */ +diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c +index dee44cb..5343dab 100644 +--- a/arch/arm/mach-at91/board-sam9-l9260.c ++++ b/arch/arm/mach-at91/board-sam9-l9260.c +@@ -51,17 +51,6 @@ static void __init ek_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -182,6 +171,16 @@ static struct at91_mmc_data __initdata ek_mmc_data = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c +index 6da17b5..7b3c391 100644 +--- a/arch/arm/mach-at91/board-sam9260ek.c ++++ b/arch/arm/mach-at91/board-sam9260ek.c +@@ -54,17 +54,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -317,6 +306,16 @@ static void __init ek_add_device_buttons(void) {} + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c +index 950c20b..de1ed46 100644 +--- a/arch/arm/mach-at91/board-sam9261ek.c ++++ b/arch/arm/mach-at91/board-sam9261ek.c +@@ -61,9 +61,6 @@ static void __init ek_init_early(void) + + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); + } + + /* +@@ -575,6 +572,8 @@ static struct gpio_led ek_leds[] = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c +index 4424873..983cb98 100644 +--- a/arch/arm/mach-at91/board-sam9263ek.c ++++ b/arch/arm/mach-at91/board-sam9263ek.c +@@ -57,12 +57,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 16.367 MHz crystal */ + at91_initialize(16367660); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -409,6 +403,11 @@ static struct at91_can_data ek_can_data = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c +index 05f8467..3d61553 100644 +--- a/arch/arm/mach-at91/board-sam9g20ek.c ++++ b/arch/arm/mach-at91/board-sam9g20ek.c +@@ -65,17 +65,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -369,6 +358,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c +index be2ca19..9a87f0b 100644 +--- a/arch/arm/mach-at91/board-sam9m10g45ek.c ++++ b/arch/arm/mach-at91/board-sam9m10g45ek.c +@@ -53,13 +53,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 12.000 MHz crystal */ + at91_initialize(12000000); +- +- /* DGBU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 not connected on the -EK board */ +- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ +- at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -454,6 +447,12 @@ static struct platform_device *devices[] __initdata = { + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 not connected on the -EK board */ ++ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */ ++ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB HS Host */ + at91_add_device_usbh_ohci(&ek_usbh_hs_data); +diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c +index 23f383a..be3239f 100644 +--- a/arch/arm/mach-at91/board-sam9rlek.c ++++ b/arch/arm/mach-at91/board-sam9rlek.c +@@ -42,12 +42,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 12.000 MHz crystal */ + at91_initialize(12000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + } + + /* +@@ -293,6 +287,11 @@ static void __init ek_add_device_buttons(void) {} + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS); + at91_add_device_serial(); + /* USB HS */ + at91_add_device_usba(&ek_usba_udc_data); +diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c +index 1a6774a..9d446f1 100644 +--- a/arch/arm/mach-at91/board-snapper9260.c ++++ b/arch/arm/mach-at91/board-snapper9260.c +@@ -43,15 +43,6 @@ + static void __init snapper9260_init_early(void) + { + at91_initialize(18432000); +- +- /* Debug on ttyS0 */ +- at91_register_uart(0, 0, 0); +- +- at91_register_uart(AT91SAM9260_ID_US0, 1, +- ATMEL_UART_CTS | ATMEL_UART_RTS); +- at91_register_uart(AT91SAM9260_ID_US1, 2, +- ATMEL_UART_CTS | ATMEL_UART_RTS); +- at91_register_uart(AT91SAM9260_ID_US2, 3, 0); + } + + static struct at91_usbh_data __initdata snapper9260_usbh_data = { +@@ -167,6 +158,14 @@ static void __init snapper9260_board_init(void) + snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31); + i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1); + ++ /* Debug on ttyS0 */ ++ at91_register_uart(0, 0, 0); ++ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ++ ATMEL_UART_CTS | ATMEL_UART_RTS); ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ++ ATMEL_UART_CTS | ATMEL_UART_RTS); ++ at91_register_uart(AT91SAM9260_ID_US2, 3, 0); + at91_add_device_serial(); + at91_add_device_usbh(&snapper9260_usbh_data); + at91_add_device_udc(&snapper9260_udc_data); +diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c +index 38a7ca5..ee86f9d 100644 +--- a/arch/arm/mach-at91/board-stamp9g20.c ++++ b/arch/arm/mach-at91/board-stamp9g20.c +@@ -36,41 +36,6 @@ void __init stamp9g20_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* DGBU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +-} +- +-static void __init stamp9g20evb_init_early(void) +-{ +- stamp9g20_init_early(); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR +- | ATMEL_UART_DCD | ATMEL_UART_RI); +-} +- +-static void __init portuxg20_init_early(void) +-{ +- stamp9g20_init_early(); +- +- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR +- | ATMEL_UART_DCD | ATMEL_UART_RI); +- +- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ +- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); +- +- /* USART4 on ttyS5. (Rx, Tx only) */ +- at91_register_uart(AT91SAM9260_ID_US4, 5, 0); +- +- /* USART5 on ttyS6. (Rx, Tx only) */ +- at91_register_uart(AT91SAM9260_ID_US5, 6, 0); + } + + /* +@@ -251,6 +216,8 @@ void add_w1(void) + void __init stamp9g20_board_init(void) + { + /* Serial */ ++ /* DGBU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* NAND */ + add_device_nand(); +@@ -266,6 +233,22 @@ void __init stamp9g20_board_init(void) + + static void __init portuxg20_board_init(void) + { ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR ++ | ATMEL_UART_DCD | ATMEL_UART_RI); ++ ++ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */ ++ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS); ++ ++ /* USART4 on ttyS5. (Rx, Tx only) */ ++ at91_register_uart(AT91SAM9260_ID_US4, 5, 0); ++ ++ /* USART5 on ttyS6. (Rx, Tx only) */ ++ at91_register_uart(AT91SAM9260_ID_US5, 6, 0); + stamp9g20_board_init(); + /* USB Host */ + at91_add_device_usbh(&usbh_data); +@@ -283,6 +266,10 @@ static void __init portuxg20_board_init(void) + + static void __init stamp9g20evb_board_init(void) + { ++ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR ++ | ATMEL_UART_DCD | ATMEL_UART_RI); + stamp9g20_board_init(); + /* USB Host */ + at91_add_device_usbh(&usbh_data); +@@ -300,7 +287,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20") + /* Maintainer: taskit GmbH */ + .timer = &at91sam926x_timer, + .map_io = at91_map_io, +- .init_early = portuxg20_init_early, ++ .init_early = stamp9g20_init_early, + .init_irq = at91_init_irq_default, + .init_machine = portuxg20_board_init, + MACHINE_END +@@ -309,7 +296,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20") + /* Maintainer: taskit GmbH */ + .timer = &at91sam926x_timer, + .map_io = at91_map_io, +- .init_early = stamp9g20evb_init_early, ++ .init_early = stamp9g20_init_early, + .init_irq = at91_init_irq_default, + .init_machine = stamp9g20evb_board_init, + MACHINE_END +diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c +index ee482eb..332ecd4 100644 +--- a/arch/arm/mach-at91/board-usb-a926x.c ++++ b/arch/arm/mach-at91/board-usb-a926x.c +@@ -53,9 +53,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 12.00 MHz crystal */ + at91_initialize(12000000); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); + } + + /* +@@ -322,6 +319,8 @@ static void __init ek_add_device_leds(void) + static void __init ek_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); + at91_add_device_serial(); + /* USB Host */ + at91_add_device_usbh(&ek_usbh_data); +diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c +index e94a04e..db8d25c 100644 +--- a/arch/arm/mach-at91/board-yl-9200.c ++++ b/arch/arm/mach-at91/board-yl-9200.c +@@ -61,20 +61,6 @@ static void __init yl9200_init_early(void) + + /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */ + at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17); +- +- /* DBGU on ttyS0. (Rx & Tx only) */ +- at91_register_uart(0, 0, 0); +- +- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ +- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS +- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD +- | ATMEL_UART_RI); +- +- /* USART0 on ttyS2. (Rx & Tx only to JP3) */ +- at91_register_uart(AT91RM9200_ID_US0, 2, 0); +- +- /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */ +- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS); + } + + /* +@@ -558,6 +544,19 @@ void __init yl9200_add_device_video(void) {} + static void __init yl9200_board_init(void) + { + /* Serial */ ++ /* DBGU on ttyS0. (Rx & Tx only) */ ++ at91_register_uart(0, 0, 0); ++ ++ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */ ++ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS ++ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD ++ | ATMEL_UART_RI); ++ ++ /* USART0 on ttyS2. (Rx & Tx only to JP3) */ ++ at91_register_uart(AT91RM9200_ID_US0, 2, 0); ++ ++ /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */ ++ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS); + at91_add_device_serial(); + /* Ethernet */ + at91_add_device_eth(&yl9200_eth_data); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch b/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch new file mode 100644 index 00000000000000..4e75d7d4ff617b --- /dev/null +++ b/patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch @@ -0,0 +1,288 @@ +From 0543012c6006a0638654943130daae637f764d5a 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 + +This will also allow to finally move the gpio driver to platform device/driver. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-csb337.c | 5 ++--- + arch/arm/mach-at91/board-ecbat91.c | 6 +++--- + arch/arm/mach-at91/board-eco920.c | 5 ++--- + arch/arm/mach-at91/board-kafa.c | 6 +++--- + arch/arm/mach-at91/board-kb9202.c | 6 +++--- + arch/arm/mach-at91/board-rm9200dk.c | 6 +++--- + arch/arm/mach-at91/board-rm9200ek.c | 6 +++--- + arch/arm/mach-at91/board-rsi-ews.c | 6 +++--- + arch/arm/mach-at91/board-sam9-l9260.c | 6 +++--- + arch/arm/mach-at91/board-sam9261ek.c | 6 +++--- + arch/arm/mach-at91/board-yl-9200.c | 6 +++--- + 11 files changed, 31 insertions(+), 33 deletions(-) + +diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c +index ad7f9f0..cd81336 100644 +--- a/arch/arm/mach-at91/board-csb337.c ++++ b/arch/arm/mach-at91/board-csb337.c +@@ -47,9 +47,6 @@ static void __init csb337_init_early(void) + { + /* Initialize processor: 3.6864 MHz crystal */ + at91_initialize(3686400); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); + } + + static struct macb_platform_data __initdata csb337_eth_data = { +@@ -222,6 +219,8 @@ static struct gpio_led csb_leds[] = { + + static void __init csb337_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); + /* Serial */ + /* DBGU on ttyS0 */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c +index 2510825..89cc372 100644 +--- a/arch/arm/mach-at91/board-ecbat91.c ++++ b/arch/arm/mach-at91/board-ecbat91.c +@@ -50,9 +50,6 @@ static void __init ecb_at91init_early(void) + + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); + } + + static struct macb_platform_data __initdata ecb_at91eth_data = { +@@ -142,6 +139,9 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = { + + static void __init ecb_at91board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c +index bebeae8..558546c 100644 +--- a/arch/arm/mach-at91/board-eco920.c ++++ b/arch/arm/mach-at91/board-eco920.c +@@ -37,9 +37,6 @@ static void __init eco920_init_early(void) + at91rm9200_set_type(ARCH_REVISON_9200_PQFP); + + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); + } + + static struct macb_platform_data __initdata eco920_eth_data = { +@@ -97,6 +94,8 @@ static struct spi_board_info eco920_spi_devices[] = { + + static void __init eco920_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1); + /* DBGU on ttyS0. (Rx & Tx only */ + at91_register_uart(0, 0, 0); + at91_add_device_serial(); +diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c +index f46b3eb..f260657 100644 +--- a/arch/arm/mach-at91/board-kafa.c ++++ b/arch/arm/mach-at91/board-kafa.c +@@ -47,9 +47,6 @@ static void __init kafa_init_early(void) + + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Set up the LEDs */ +- at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); + } + + static struct macb_platform_data __initdata kafa_eth_data = { +@@ -70,6 +67,9 @@ static struct at91_udc_data __initdata kafa_udc_data = { + + static void __init kafa_board_init(void) + { ++ /* Set up the LEDs */ ++ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c +index e71b9e1..ba39db5 100644 +--- a/arch/arm/mach-at91/board-kb9202.c ++++ b/arch/arm/mach-at91/board-kb9202.c +@@ -50,9 +50,6 @@ static void __init kb9202_init_early(void) + + /* Initialize processor: 10 MHz crystal */ + at91_initialize(10000000); +- +- /* Set up the LEDs */ +- at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); + } + + static struct macb_platform_data __initdata kb9202_eth_data = { +@@ -100,6 +97,9 @@ static struct atmel_nand_data __initdata kb9202_nand_data = { + + static void __init kb9202_board_init(void) + { ++ /* Set up the LEDs */ ++ at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c +index 4a0b097..afd7a47 100644 +--- a/arch/arm/mach-at91/board-rm9200dk.c ++++ b/arch/arm/mach-at91/board-rm9200dk.c +@@ -50,9 +50,6 @@ static void __init dk_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + } + + static struct macb_platform_data __initdata dk_eth_data = { +@@ -179,6 +176,9 @@ static struct gpio_led dk_leds[] = { + + static void __init dk_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c +index 6fa54ac..2b15b8a 100644 +--- a/arch/arm/mach-at91/board-rm9200ek.c ++++ b/arch/arm/mach-at91/board-rm9200ek.c +@@ -50,9 +50,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); + } + + static struct macb_platform_data __initdata ek_eth_data = { +@@ -150,6 +147,9 @@ static struct gpio_led ek_leds[] = { + + static void __init ek_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c +index 10d8730..24ab9be 100644 +--- a/arch/arm/mach-at91/board-rsi-ews.c ++++ b/arch/arm/mach-at91/board-rsi-ews.c +@@ -35,9 +35,6 @@ static void __init rsi_ews_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9); + } + + /* +@@ -187,6 +184,9 @@ static struct platform_device rsiews_nor_flash = { + */ + static void __init rsi_ews_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + /* This one is for debugging */ +diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c +index 5343dab..cdd21f2 100644 +--- a/arch/arm/mach-at91/board-sam9-l9260.c ++++ b/arch/arm/mach-at91/board-sam9-l9260.c +@@ -48,9 +48,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); + } + + /* +@@ -170,6 +167,9 @@ static struct at91_mmc_data __initdata ek_mmc_data = { + + static void __init ek_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c +index de1ed46..2736453 100644 +--- a/arch/arm/mach-at91/board-sam9261ek.c ++++ b/arch/arm/mach-at91/board-sam9261ek.c +@@ -58,9 +58,6 @@ static void __init ek_init_early(void) + { + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs */ +- at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); + } + + /* +@@ -571,6 +568,9 @@ static struct gpio_led ek_leds[] = { + + static void __init ek_board_init(void) + { ++ /* Setup the LEDs */ ++ at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c +index db8d25c..d56665e 100644 +--- a/arch/arm/mach-at91/board-yl-9200.c ++++ b/arch/arm/mach-at91/board-yl-9200.c +@@ -58,9 +58,6 @@ static void __init yl9200_init_early(void) + + /* Initialize processor: 18.432 MHz crystal */ + at91_initialize(18432000); +- +- /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */ +- at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17); + } + + /* +@@ -543,6 +540,9 @@ void __init yl9200_add_device_video(void) {} + + static void __init yl9200_board_init(void) + { ++ /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */ ++ at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17); ++ + /* Serial */ + /* DBGU on ttyS0. (Rx & Tx only) */ + at91_register_uart(0, 0, 0); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch b/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch new file mode 100644 index 00000000000000..23c7bb32643968 --- /dev/null +++ b/patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch @@ -0,0 +1,117 @@ +From e7d4df4ef74b1ed11a0e2037bc5cbe8123cf258d 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 + +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> +--- + arch/arm/mach-at91/cpuidle.c | 8 +++++++- + arch/arm/mach-at91/pm.c | 12 ++++++++---- + arch/arm/mach-at91/pm.h | 13 ------------- + 3 files changed, 15 insertions(+), 18 deletions(-) + +diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c +index ece1f9a..0c63815 100644 +--- a/arch/arm/mach-at91/cpuidle.c ++++ b/arch/arm/mach-at91/cpuidle.c +@@ -21,6 +21,7 @@ + #include <linux/export.h> + #include <asm/proc-fns.h> + #include <asm/cpuidle.h> ++#include <mach/cpu.h> + + #include "pm.h" + +@@ -33,7 +34,12 @@ static int at91_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) + { +- at91_standby(); ++ if (cpu_is_at91rm9200()) ++ at91rm9200_standby(); ++ else if (cpu_is_at91sam9g45()) ++ at91sam9g45_standby(); ++ else ++ at91sam9_standby(); + + return index; + } +diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c +index f630250..1bfaad6 100644 +--- a/arch/arm/mach-at91/pm.c ++++ b/arch/arm/mach-at91/pm.c +@@ -261,7 +261,12 @@ static int at91_pm_enter(suspend_state_t state) + * For ARM 926 based chips, this requirement is weaker + * as at91sam9 can access a RAM in self-refresh mode. + */ +- at91_standby(); ++ if (cpu_is_at91rm9200()) ++ at91rm9200_standby(); ++ else if (cpu_is_at91sam9g45()) ++ at91sam9g45_standby(); ++ else ++ at91sam9_standby(); + break; + + case PM_SUSPEND_ON: +@@ -307,10 +312,9 @@ static int __init at91_pm_init(void) + + pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : "")); + +-#ifdef CONFIG_ARCH_AT91RM9200 + /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ +- at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0); +-#endif ++ if (cpu_is_at91rm9200()) ++ at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0); + + suspend_set_ops(&at91_pm_ops); + +diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h +index 89f56f3..1b4865e 100644 +--- a/arch/arm/mach-at91/pm.h ++++ b/arch/arm/mach-at91/pm.h +@@ -12,7 +12,6 @@ + #define __ARCH_ARM_MACH_AT91_PM + + #include <mach/at91_ramc.h> +-#ifdef CONFIG_ARCH_AT91RM9200 + #include <mach/at91rm9200_sdramc.h> + + /* +@@ -43,10 +42,6 @@ static inline void at91rm9200_standby(void) + "r" (lpr)); + } + +-#define at91_standby at91rm9200_standby +- +-#elif defined(CONFIG_ARCH_AT91SAM9G45) +- + /* We manage both DDRAM/SDRAM controllers, we need more than one value to + * remember. + */ +@@ -75,10 +70,6 @@ static inline void at91sam9g45_standby(void) + at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); + } + +-#define at91_standby at91sam9g45_standby +- +-#else +- + #ifdef CONFIG_ARCH_AT91SAM9263 + /* + * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; +@@ -102,8 +93,4 @@ static inline void at91sam9_standby(void) + at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr); + } + +-#define at91_standby at91sam9_standby +- +-#endif +- + #endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch b/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch new file mode 100644 index 00000000000000..3d2ea6f94e1a5a --- /dev/null +++ b/patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch @@ -0,0 +1,133 @@ +From 54af5dc6fcc90243d7d161c83f2c94cb1ef67697 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 + +This will allow to simplify the switch to multi soc in the same kernel. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 29 +++++++++++++---------------- + arch/arm/mach-at91/Makefile | 17 +++++++++-------- + 2 files changed, 22 insertions(+), 24 deletions(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 885fdb9..40e31c7 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -17,6 +17,11 @@ config AT91_SAM9G45_RESET + bool + default !ARCH_AT91X40 + ++config SOC_AT91SAM9 ++ bool ++ select GENERIC_CLOCKEVENTS ++ select CPU_ARM926T ++ + menu "Atmel AT91 System-on-Chip" + + choice +@@ -30,51 +35,44 @@ config ARCH_AT91RM9200 + + config ARCH_AT91SAM9260 + bool "AT91SAM9260 or AT91SAM9XE" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 + select HAVE_NET_MACB + + config ARCH_AT91SAM9261 + bool "AT91SAM9261" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_FB_ATMEL + select HAVE_AT91_DBGU0 + + config ARCH_AT91SAM9G10 + bool "AT91SAM9G10" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 + select HAVE_FB_ATMEL + + config ARCH_AT91SAM9263 + bool "AT91SAM9263" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU1 + + config ARCH_AT91SAM9RL + bool "AT91SAM9RL" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_FB_ATMEL + select HAVE_AT91_DBGU0 + + config ARCH_AT91SAM9G20 + bool "AT91SAM9G20" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 + select HAVE_NET_MACB + + config ARCH_AT91SAM9G45 + bool "AT91SAM9G45 or AT91SAM9M10 families" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU1 +@@ -84,8 +82,7 @@ config ARCH_AT91SAM9G45 + + config ARCH_AT91SAM9X5 + bool "AT91SAM9x5 family" +- select CPU_ARM926T +- select GENERIC_CLOCKEVENTS ++ select SOC_AT91SAM9 + select HAVE_FB_ATMEL + select HAVE_NET_MACB + select HAVE_AT91_DBGU0 +diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile +index 8512e53..d97d0f4 100644 +--- a/arch/arm/mach-at91/Makefile ++++ b/arch/arm/mach-at91/Makefile +@@ -10,17 +10,18 @@ obj- := + obj-$(CONFIG_AT91_PMC_UNIT) += clock.o + obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o + obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o ++obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o + + # CPU-specific support + obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o +-obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o sam9_smc.o ++obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam9260_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam9261_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam9261_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam9263_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam9rl_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam9260_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam9g45_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o + obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o + + # AT91RM9200 board-specific support +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch b/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch new file mode 100644 index 00000000000000..13ba82bd936635 --- /dev/null +++ b/patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch @@ -0,0 +1,378 @@ +From 420a99e1110afb0a9a2fd8ac6e1c18ba2136002e 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 + +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 +compatibility. This will enable the plaform_device ressources. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/configs/at91rm9200_defconfig | 1 + + arch/arm/mach-at91/Kconfig | 91 ++++++++++++++++++++++++----------- + arch/arm/mach-at91/Makefile | 25 ++++++---- + arch/arm/mach-at91/include/mach/cpu.h | 28 +++++------ + arch/arm/mach-at91/pm.h | 2 +- + arch/arm/mach-at91/pm_slowclock.S | 2 +- + arch/arm/mach-at91/soc.h | 14 +++--- + 7 files changed, 101 insertions(+), 62 deletions(-) + +diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig +index bbe4e1a..d54e2ac 100644 +--- a/arch/arm/configs/at91rm9200_defconfig ++++ b/arch/arm/configs/at91rm9200_defconfig +@@ -14,6 +14,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y + # CONFIG_BLK_DEV_BSG is not set + # CONFIG_IOSCHED_CFQ is not set + CONFIG_ARCH_AT91=y ++CONFIG_ARCH_AT91RM9200=y + CONFIG_MACH_ONEARM=y + CONFIG_ARCH_AT91RM9200DK=y + CONFIG_MACH_AT91RM9200EK=y +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 40e31c7..98a42f3 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -24,68 +24,66 @@ config SOC_AT91SAM9 + + menu "Atmel AT91 System-on-Chip" + +-choice +- prompt "Atmel AT91 Processor" ++comment "Atmel AT91 Processor" + +-config ARCH_AT91RM9200 ++config SOC_AT91SAM9 ++ bool ++ select CPU_ARM926T ++ select AT91_SAM9_TIME ++ select AT91_SAM9_SMC ++ ++config SOC_AT91RM9200 + bool "AT91RM9200" + select CPU_ARM920T + select GENERIC_CLOCKEVENTS + select HAVE_AT91_DBGU0 + +-config ARCH_AT91SAM9260 +- bool "AT91SAM9260 or AT91SAM9XE" ++config SOC_AT91SAM9260 ++ bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20" + select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 + select HAVE_NET_MACB ++ help ++ Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE ++ or AT91SAM9G20 SoC. + +-config ARCH_AT91SAM9261 +- bool "AT91SAM9261" +- select SOC_AT91SAM9 +- select HAVE_FB_ATMEL +- select HAVE_AT91_DBGU0 +- +-config ARCH_AT91SAM9G10 +- bool "AT91SAM9G10" ++config SOC_AT91SAM9261 ++ bool "AT91SAM9261 or AT91SAM9G10" + select SOC_AT91SAM9 + select HAVE_AT91_DBGU0 + select HAVE_FB_ATMEL ++ help ++ Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC. + +-config ARCH_AT91SAM9263 ++config SOC_AT91SAM9263 + bool "AT91SAM9263" + select SOC_AT91SAM9 ++ select HAVE_AT91_DBGU1 + select HAVE_FB_ATMEL + select HAVE_NET_MACB +- select HAVE_AT91_DBGU1 + +-config ARCH_AT91SAM9RL ++config SOC_AT91SAM9RL + bool "AT91SAM9RL" + select SOC_AT91SAM9 +- select HAVE_FB_ATMEL + select HAVE_AT91_DBGU0 ++ select HAVE_FB_ATMEL + +-config ARCH_AT91SAM9G20 +- bool "AT91SAM9G20" +- select SOC_AT91SAM9 +- select HAVE_AT91_DBGU0 +- select HAVE_NET_MACB +- +-config ARCH_AT91SAM9G45 ++config SOC_AT91SAM9G45 + bool "AT91SAM9G45 or AT91SAM9M10 families" + select SOC_AT91SAM9 ++ select HAVE_AT91_DBGU1 + select HAVE_FB_ATMEL + select HAVE_NET_MACB +- select HAVE_AT91_DBGU1 + help + Select this if you are using one of Atmel's AT91SAM9G45 family SoC. + This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11. + +-config ARCH_AT91SAM9X5 ++config SOC_AT91SAM9X5 + bool "AT91SAM9x5 family" + select SOC_AT91SAM9 ++ select HAVE_AT91_DBGU0 + select HAVE_FB_ATMEL + select HAVE_NET_MACB +- select HAVE_AT91_DBGU0 + help + Select this if you are using one of Atmel's AT91SAM9x5 family SoC. + This means that your SAM9 name finishes with a '5' (except if it is +@@ -93,8 +91,47 @@ config ARCH_AT91SAM9X5 + This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35 + and AT91SAM9X35. + ++choice ++ prompt "Atmel AT91 Processor Devices for non DT boards" ++ ++config ARCH_AT91_NONE ++ bool "None" ++ ++config ARCH_AT91RM9200 ++ bool "AT91RM9200" ++ select SOC_AT91RM9200 ++ ++config ARCH_AT91SAM9260 ++ bool "AT91SAM9260 or AT91SAM9XE" ++ select SOC_AT91SAM9260 ++ ++config ARCH_AT91SAM9261 ++ bool "AT91SAM9261" ++ select SOC_AT91SAM9261 ++ ++config ARCH_AT91SAM9G10 ++ bool "AT91SAM9G10" ++ select SOC_AT91SAM9261 ++ ++config ARCH_AT91SAM9263 ++ bool "AT91SAM9263" ++ select SOC_AT91SAM9263 ++ ++config ARCH_AT91SAM9RL ++ bool "AT91SAM9RL" ++ select SOC_AT91SAM9RL ++ ++config ARCH_AT91SAM9G20 ++ bool "AT91SAM9G20" ++ select SOC_AT91SAM9260 ++ ++config ARCH_AT91SAM9G45 ++ bool "AT91SAM9G45" ++ select SOC_AT91SAM9G45 ++ + config ARCH_AT91X40 + bool "AT91x40" ++ depends on !MMU + select ARCH_USES_GETTIMEOFFSET + + endchoice +diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile +index d97d0f4..79d0f60 100644 +--- a/arch/arm/mach-at91/Makefile ++++ b/arch/arm/mach-at91/Makefile +@@ -13,15 +13,22 @@ obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o + obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o + + # CPU-specific support +-obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam9260_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam9261_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam9261_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam9263_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam9rl_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam9260_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam9g45_devices.o +-obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o ++obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o at91rm9200_time.o ++obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o ++obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o ++obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o ++obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o ++obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o ++obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o ++ ++obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260_devices.o ++obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45_devices.o + obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o + + # AT91RM9200 board-specific support +diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h +index 0118c33..73d2fd2 100644 +--- a/arch/arm/mach-at91/include/mach/cpu.h ++++ b/arch/arm/mach-at91/include/mach/cpu.h +@@ -54,6 +54,7 @@ + #define ARCH_REVISON_9200_BGA (0 << 0) + #define ARCH_REVISON_9200_PQFP (1 << 0) + ++#ifndef __ASSEMBLY__ + enum at91_soc_type { + /* 920T */ + AT91_SOC_RM9200, +@@ -106,7 +107,7 @@ static inline int at91_soc_is_detected(void) + return at91_soc_initdata.type != AT91_SOC_NONE; + } + +-#ifdef CONFIG_ARCH_AT91RM9200 ++#ifdef CONFIG_SOC_AT91RM9200 + #define cpu_is_at91rm9200() (at91_soc_initdata.type == AT91_SOC_RM9200) + #define cpu_is_at91rm9200_bga() (at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA) + #define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP) +@@ -116,45 +117,37 @@ static inline int at91_soc_is_detected(void) + #define cpu_is_at91rm9200_pqfp() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9260 ++#ifdef CONFIG_SOC_AT91SAM9260 + #define cpu_is_at91sam9xe() (at91_soc_initdata.subtype == AT91_SOC_SAM9XE) + #define cpu_is_at91sam9260() (at91_soc_initdata.type == AT91_SOC_SAM9260) ++#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20) + #else + #define cpu_is_at91sam9xe() (0) + #define cpu_is_at91sam9260() (0) +-#endif +- +-#ifdef CONFIG_ARCH_AT91SAM9G20 +-#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20) +-#else + #define cpu_is_at91sam9g20() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9261 ++#ifdef CONFIG_SOC_AT91SAM9261 + #define cpu_is_at91sam9261() (at91_soc_initdata.type == AT91_SOC_SAM9261) +-#else +-#define cpu_is_at91sam9261() (0) +-#endif +- +-#ifdef CONFIG_ARCH_AT91SAM9G10 + #define cpu_is_at91sam9g10() (at91_soc_initdata.type == AT91_SOC_SAM9G10) + #else ++#define cpu_is_at91sam9261() (0) + #define cpu_is_at91sam9g10() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9263 ++#ifdef CONFIG_SOC_AT91SAM9263 + #define cpu_is_at91sam9263() (at91_soc_initdata.type == AT91_SOC_SAM9263) + #else + #define cpu_is_at91sam9263() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9RL ++#ifdef CONFIG_SOC_AT91SAM9RL + #define cpu_is_at91sam9rl() (at91_soc_initdata.type == AT91_SOC_SAM9RL) + #else + #define cpu_is_at91sam9rl() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9G45 ++#ifdef CONFIG_SOC_AT91SAM9G45 + #define cpu_is_at91sam9g45() (at91_soc_initdata.type == AT91_SOC_SAM9G45) + #define cpu_is_at91sam9g45es() (at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES) + #define cpu_is_at91sam9m10() (at91_soc_initdata.subtype == AT91_SOC_SAM9M10) +@@ -168,7 +161,7 @@ static inline int at91_soc_is_detected(void) + #define cpu_is_at91sam9m11() (0) + #endif + +-#ifdef CONFIG_ARCH_AT91SAM9X5 ++#ifdef CONFIG_SOC_AT91SAM9X5 + #define cpu_is_at91sam9x5() (at91_soc_initdata.type == AT91_SOC_SAM9X5) + #define cpu_is_at91sam9g15() (at91_soc_initdata.subtype == AT91_SOC_SAM9G15) + #define cpu_is_at91sam9g35() (at91_soc_initdata.subtype == AT91_SOC_SAM9G35) +@@ -189,5 +182,6 @@ static inline int at91_soc_is_detected(void) + * definitions may reduce clutter in common drivers. + */ + #define cpu_is_at32ap7000() (0) ++#endif /* __ASSEMBLY__ */ + + #endif /* __MACH_CPU_H__ */ +diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h +index 1b4865e..38f467c 100644 +--- a/arch/arm/mach-at91/pm.h ++++ b/arch/arm/mach-at91/pm.h +@@ -70,7 +70,7 @@ static inline void at91sam9g45_standby(void) + at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); + } + +-#ifdef CONFIG_ARCH_AT91SAM9263 ++#ifdef CONFIG_SOC_AT91SAM9263 + /* + * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; + * handle those cases both here and in the Suspend-To-RAM support. +diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S +index db54521..098c28d 100644 +--- a/arch/arm/mach-at91/pm_slowclock.S ++++ b/arch/arm/mach-at91/pm_slowclock.S +@@ -18,7 +18,7 @@ + #include <mach/at91_ramc.h> + + +-#ifdef CONFIG_ARCH_AT91SAM9263 ++#ifdef CONFIG_SOC_AT91SAM9263 + /* + * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; + * handle those cases both here and in the Suspend-To-RAM support. +diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h +index 5db4aa4..683dddf 100644 +--- a/arch/arm/mach-at91/soc.h ++++ b/arch/arm/mach-at91/soc.h +@@ -26,30 +26,30 @@ static inline int at91_soc_is_enabled(void) + return at91_boot_soc.init != NULL; + } + +-#if !defined(CONFIG_ARCH_AT91RM9200) ++#if !defined(CONFIG_SOC_AT91RM9200) + #define at91rm9200_soc at91_boot_soc + #endif + +-#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)) ++#if !defined(CONFIG_SOC_AT91SAM9260) + #define at91sam9260_soc at91_boot_soc + #endif + +-#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10)) ++#if !defined(CONFIG_SOC_AT91SAM9261) + #define at91sam9261_soc at91_boot_soc + #endif + +-#if !defined(CONFIG_ARCH_AT91SAM9263) ++#if !defined(CONFIG_SOC_AT91SAM9263) + #define at91sam9263_soc at91_boot_soc + #endif + +-#if !defined(CONFIG_ARCH_AT91SAM9G45) ++#if !defined(CONFIG_SOC_AT91SAM9G45) + #define at91sam9g45_soc at91_boot_soc + #endif + +-#if !defined(CONFIG_ARCH_AT91SAM9RL) ++#if !defined(CONFIG_SOC_AT91SAM9RL) + #define at91sam9rl_soc at91_boot_soc + #endif + +-#if !defined(CONFIG_ARCH_AT91SAM9X5) ++#if !defined(CONFIG_SOC_AT91SAM9X5) + #define at91sam9x5_soc at91_boot_soc + #endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch b/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch new file mode 100644 index 00000000000000..5f968506f6d997 --- /dev/null +++ b/patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch @@ -0,0 +1,42 @@ +From 77a5977e7fdc175bb1963143b80ad2a74cf3d9b8 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 + +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> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/board-dt.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c +index c18d4d3..a1fce05 100644 +--- a/arch/arm/mach-at91/board-dt.c ++++ b/arch/arm/mach-at91/board-dt.c +@@ -1,10 +1,6 @@ + /* + * Setup code for AT91SAM Evaluation Kits with Device Tree support + * +- * Covers: * AT91SAM9G45-EKES board +- * * AT91SAM9M10-EKES board +- * * AT91SAM9M10G45-EK board +- * + * Copyright (C) 2011 Atmel, + * 2011 Nicolas Ferre <nicolas.ferre@atmel.com> + * +@@ -49,9 +45,7 @@ static void __init at91_dt_device_init(void) + } + + static const char *at91_dt_board_compat[] __initdata = { +- "atmel,at91sam9m10g45ek", +- "atmel,at91sam9x5ek", +- "calao,usb-a9g20", ++ "atmel,at91sam9", + NULL + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch b/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch new file mode 100644 index 00000000000000..9ae95597c5db5f --- /dev/null +++ b/patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch @@ -0,0 +1,220 @@ +From 73aa3911713fc739b9213475b4ff86d85d80d113 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 + +This will enable all current SoC support on DT (9260, 9g20, 9g45 family +and 9x5 family). + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/configs/at91_dt_defconfig | 196 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 196 insertions(+) + create mode 100644 arch/arm/configs/at91_dt_defconfig + +diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig +new file mode 100644 +index 0000000..67bc571 +--- /dev/null ++++ b/arch/arm/configs/at91_dt_defconfig +@@ -0,0 +1,196 @@ ++CONFIG_EXPERIMENTAL=y ++# CONFIG_LOCALVERSION_AUTO is not set ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_LBDAF is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++CONFIG_ARCH_AT91=y ++CONFIG_SOC_AT91SAM9260=y ++CONFIG_SOC_AT91SAM9263=y ++CONFIG_SOC_AT91SAM9G45=y ++CONFIG_SOC_AT91SAM9X5=y ++CONFIG_MACH_AT91SAM_DT=y ++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y ++CONFIG_AT91_TIMER_HZ=128 ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_LEDS=y ++CONFIG_LEDS_CPU=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_ARM_APPENDED_DTB=y ++CONFIG_ARM_ATAG_DTB_COMPAT=y ++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" ++CONFIG_KEXEC=y ++CONFIG_AUTO_ZRELADDR=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_PNP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_DIAG is not set ++CONFIG_IPV6=y ++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET6_XFRM_MODE_BEET is not set ++CONFIG_IPV6_SIT_6RD=y ++# CONFIG_WIRELESS is not set ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_ATMEL=y ++CONFIG_MTD_UBI=y ++CONFIG_MTD_UBI_GLUEBI=y ++CONFIG_PROC_DEVICETREE=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=4 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_ATMEL_PWM=y ++CONFIG_ATMEL_TCLIB=y ++CONFIG_EEPROM_93CX6=m ++CONFIG_SCSI=y ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_MACB=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_DAVICOM_PHY=y ++CONFIG_MICREL_PHY=y ++# CONFIG_WLAN is not set ++CONFIG_INPUT_POLLDEV=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=480 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272 ++CONFIG_INPUT_JOYDEV=y ++CONFIG_INPUT_EVDEV=y ++# CONFIG_KEYBOARD_ATKBD is not set ++CONFIG_KEYBOARD_GPIO=y ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_SERIO is not set ++CONFIG_LEGACY_PTY_COUNT=4 ++CONFIG_SERIAL_ATMEL=y ++CONFIG_SERIAL_ATMEL_CONSOLE=y ++CONFIG_HW_RANDOM=y ++CONFIG_I2C=y ++CONFIG_I2C_GPIO=y ++CONFIG_SPI=y ++CONFIG_SPI_ATMEL=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_AT91SAM9X_WATCHDOG=y ++CONFIG_SSB=m ++CONFIG_FB=y ++CONFIG_FB_MODE_HELPERS=y ++CONFIG_FB_ATMEL=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++# CONFIG_LCD_CLASS_DEVICE is not set ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_ATMEL_LCDC=y ++# CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_ACORN_8x8=y ++CONFIG_FONT_MINI_4x6=y ++CONFIG_LOGO=y ++# CONFIG_HID_SUPPORT is not set ++CONFIG_USB=y ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++CONFIG_USB_DEVICEFS=y ++# CONFIG_USB_DEVICE_CLASS is not set ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_OHCI_HCD=y ++CONFIG_USB_ACM=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_SERIAL=y ++CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_FTDI_SIO=y ++CONFIG_USB_SERIAL_PL2303=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_AT91=m ++CONFIG_USB_ATMEL_USBA=m ++CONFIG_USB_ETH=m ++CONFIG_USB_GADGETFS=m ++CONFIG_USB_CDC_COMPOSITE=m ++CONFIG_USB_G_ACM_MS=m ++CONFIG_USB_G_MULTI=m ++CONFIG_USB_G_MULTI_CDC=y ++CONFIG_MMC=y ++CONFIG_MMC_ATMELMCI=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_AT91RM9200=y ++CONFIG_RTC_DRV_AT91SAM9=y ++CONFIG_DMADEVICES=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_EXT2_FS=y ++CONFIG_FANOTIFY=y ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_CODEPAGE_850=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_FS=y ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_DEBUG_BUGVERBOSE is not set ++# CONFIG_FTRACE is not set ++CONFIG_DEBUG_USER=y ++CONFIG_CRYPTO=y ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_AES=y ++CONFIG_CRYPTO_ARC4=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_HASH=m ++CONFIG_CRYPTO_USER_API_SKCIPHER=m ++# CONFIG_CRYPTO_HW is not set ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_ITU_T=m ++CONFIG_CRC7=m ++CONFIG_AVERAGE=y +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch b/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch new file mode 100644 index 00000000000000..48bd9750d284f7 --- /dev/null +++ b/patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch @@ -0,0 +1,522 @@ +From d795dab6d067cd5734cd7af4b67634f3b3961bd7 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 + +The at91sam9260 and at91sam9g20 share most of the same IP. +So udpate the node property in the at91sam9g20 only. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/at91sam9260.dtsi | 238 +++++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/at91sam9g20.dtsi | 226 +---------------------------------- + arch/arm/mach-at91/Makefile.boot | 1 + + 3 files changed, 242 insertions(+), 223 deletions(-) + create mode 100644 arch/arm/boot/dts/at91sam9260.dtsi + +diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi +new file mode 100644 +index 0000000..f4605ff +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9260.dtsi +@@ -0,0 +1,238 @@ ++/* ++ * at91sam9260.dtsi - Device Tree Include file for AT91SAM9260 family SoC ++ * ++ * Copyright (C) 2011 Atmel, ++ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>, ++ * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++ ++/include/ "skeleton.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9260 family SoC"; ++ compatible = "atmel,at91sam9260"; ++ interrupt-parent = <&aic>; ++ ++ aliases { ++ serial0 = &dbgu; ++ serial1 = &usart0; ++ serial2 = &usart1; ++ serial3 = &usart2; ++ serial4 = &usart3; ++ serial5 = &usart4; ++ serial6 = &usart5; ++ gpio0 = &pioA; ++ gpio1 = &pioB; ++ gpio2 = &pioC; ++ tcb0 = &tcb0; ++ tcb1 = &tcb1; ++ }; ++ cpus { ++ cpu@0 { ++ compatible = "arm,arm926ejs"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x04000000>; ++ }; ++ ++ ahb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ apb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ aic: interrupt-controller@fffff000 { ++ #interrupt-cells = <2>; ++ compatible = "atmel,at91rm9200-aic"; ++ interrupt-controller; ++ reg = <0xfffff000 0x200>; ++ }; ++ ++ ramc0: ramc@ffffea00 { ++ compatible = "atmel,at91sam9260-sdramc"; ++ reg = <0xffffea00 0x200>; ++ }; ++ ++ pmc: pmc@fffffc00 { ++ compatible = "atmel,at91rm9200-pmc"; ++ reg = <0xfffffc00 0x100>; ++ }; ++ ++ rstc@fffffd00 { ++ compatible = "atmel,at91sam9260-rstc"; ++ reg = <0xfffffd00 0x10>; ++ }; ++ ++ shdwc@fffffd10 { ++ compatible = "atmel,at91sam9260-shdwc"; ++ reg = <0xfffffd10 0x10>; ++ }; ++ ++ pit: timer@fffffd30 { ++ compatible = "atmel,at91sam9260-pit"; ++ reg = <0xfffffd30 0xf>; ++ interrupts = <1 4>; ++ }; ++ ++ tcb0: timer@fffa0000 { ++ compatible = "atmel,at91rm9200-tcb"; ++ reg = <0xfffa0000 0x100>; ++ interrupts = <17 4 18 4 19 4>; ++ }; ++ ++ tcb1: timer@fffdc000 { ++ compatible = "atmel,at91rm9200-tcb"; ++ reg = <0xfffdc000 0x100>; ++ interrupts = <26 4 27 4 28 4>; ++ }; ++ ++ pioA: gpio@fffff400 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff400 0x100>; ++ interrupts = <2 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioB: gpio@fffff600 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff600 0x100>; ++ interrupts = <3 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioC: gpio@fffff800 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff800 0x100>; ++ interrupts = <4 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ dbgu: serial@fffff200 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffff200 0x200>; ++ interrupts = <1 4>; ++ status = "disabled"; ++ }; ++ ++ usart0: serial@fffb0000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffb0000 0x200>; ++ interrupts = <6 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart1: serial@fffb4000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffb4000 0x200>; ++ interrupts = <7 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart2: serial@fffb8000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffb8000 0x200>; ++ interrupts = <8 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart3: serial@fffd0000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffd0000 0x200>; ++ interrupts = <23 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart4: serial@fffd4000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffd4000 0x200>; ++ interrupts = <24 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart5: serial@fffd8000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffd8000 0x200>; ++ interrupts = <25 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ macb0: ethernet@fffc4000 { ++ compatible = "cdns,at32ap7000-macb", "cdns,macb"; ++ reg = <0xfffc4000 0x100>; ++ interrupts = <21 4>; ++ status = "disabled"; ++ }; ++ ++ usb1: gadget@fffa4000 { ++ compatible = "atmel,at91rm9200-udc"; ++ reg = <0xfffa4000 0x4000>; ++ interrupts = <10 4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ compatible = "atmel,at91rm9200-nand"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x40000000 0x10000000 ++ 0xffffe800 0x200 ++ >; ++ atmel,nand-addr-offset = <21>; ++ atmel,nand-cmd-offset = <22>; ++ gpios = <&pioC 13 0 ++ &pioC 14 0 ++ 0 ++ >; ++ status = "disabled"; ++ }; ++ ++ usb0: ohci@00500000 { ++ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; ++ reg = <0x00500000 0x100000>; ++ interrupts = <20 4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&pioA 23 0 /* sda */ ++ &pioA 24 0 /* scl */ ++ >; ++ i2c-gpio,sda-open-drain; ++ i2c-gpio,scl-open-drain; ++ i2c-gpio,delay-us = <2>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi +index 773ef48..0eb1a75 100644 +--- a/arch/arm/boot/dts/at91sam9g20.dtsi ++++ b/arch/arm/boot/dts/at91sam9g20.dtsi +@@ -1,238 +1,18 @@ + /* + * at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC + * +- * Copyright (C) 2011 Atmel, +- * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>, +- * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * +- * Licensed under GPLv2 or later. ++ * Licensed under GPLv2. + */ + +-/include/ "skeleton.dtsi" ++/include/ "at91sam9260.dtsi" + + / { + model = "Atmel AT91SAM9G20 family SoC"; + compatible = "atmel,at91sam9g20"; +- interrupt-parent = <&aic>; +- +- aliases { +- serial0 = &dbgu; +- serial1 = &usart0; +- serial2 = &usart1; +- serial3 = &usart2; +- serial4 = &usart3; +- serial5 = &usart4; +- serial6 = &usart5; +- gpio0 = &pioA; +- gpio1 = &pioB; +- gpio2 = &pioC; +- tcb0 = &tcb0; +- tcb1 = &tcb1; +- }; +- cpus { +- cpu@0 { +- compatible = "arm,arm926ejs"; +- }; +- }; + + memory { + reg = <0x20000000 0x08000000>; + }; +- +- ahb { +- compatible = "simple-bus"; +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; +- +- apb { +- compatible = "simple-bus"; +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; +- +- aic: interrupt-controller@fffff000 { +- #interrupt-cells = <2>; +- compatible = "atmel,at91rm9200-aic"; +- interrupt-controller; +- reg = <0xfffff000 0x200>; +- }; +- +- ramc0: ramc@ffffea00 { +- compatible = "atmel,at91sam9260-sdramc"; +- reg = <0xffffea00 0x200>; +- }; +- +- pmc: pmc@fffffc00 { +- compatible = "atmel,at91rm9200-pmc"; +- reg = <0xfffffc00 0x100>; +- }; +- +- rstc@fffffd00 { +- compatible = "atmel,at91sam9260-rstc"; +- reg = <0xfffffd00 0x10>; +- }; +- +- shdwc@fffffd10 { +- compatible = "atmel,at91sam9260-shdwc"; +- reg = <0xfffffd10 0x10>; +- }; +- +- pit: timer@fffffd30 { +- compatible = "atmel,at91sam9260-pit"; +- reg = <0xfffffd30 0xf>; +- interrupts = <1 4>; +- }; +- +- tcb0: timer@fffa0000 { +- compatible = "atmel,at91rm9200-tcb"; +- reg = <0xfffa0000 0x100>; +- interrupts = <17 4 18 4 19 4>; +- }; +- +- tcb1: timer@fffdc000 { +- compatible = "atmel,at91rm9200-tcb"; +- reg = <0xfffdc000 0x100>; +- interrupts = <26 4 27 4 28 4>; +- }; +- +- pioA: gpio@fffff400 { +- compatible = "atmel,at91rm9200-gpio"; +- reg = <0xfffff400 0x100>; +- interrupts = <2 4>; +- #gpio-cells = <2>; +- gpio-controller; +- interrupt-controller; +- }; +- +- pioB: gpio@fffff600 { +- compatible = "atmel,at91rm9200-gpio"; +- reg = <0xfffff600 0x100>; +- interrupts = <3 4>; +- #gpio-cells = <2>; +- gpio-controller; +- interrupt-controller; +- }; +- +- pioC: gpio@fffff800 { +- compatible = "atmel,at91rm9200-gpio"; +- reg = <0xfffff800 0x100>; +- interrupts = <4 4>; +- #gpio-cells = <2>; +- gpio-controller; +- interrupt-controller; +- }; +- +- dbgu: serial@fffff200 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffff200 0x200>; +- interrupts = <1 4>; +- status = "disabled"; +- }; +- +- usart0: serial@fffb0000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffb0000 0x200>; +- interrupts = <6 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- usart1: serial@fffb4000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffb4000 0x200>; +- interrupts = <7 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- usart2: serial@fffb8000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffb8000 0x200>; +- interrupts = <8 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- usart3: serial@fffd0000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffd0000 0x200>; +- interrupts = <23 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- usart4: serial@fffd4000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffd4000 0x200>; +- interrupts = <24 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- usart5: serial@fffd8000 { +- compatible = "atmel,at91sam9260-usart"; +- reg = <0xfffd8000 0x200>; +- interrupts = <25 4>; +- atmel,use-dma-rx; +- atmel,use-dma-tx; +- status = "disabled"; +- }; +- +- macb0: ethernet@fffc4000 { +- compatible = "cdns,at32ap7000-macb", "cdns,macb"; +- reg = <0xfffc4000 0x100>; +- interrupts = <21 4>; +- status = "disabled"; +- }; +- +- usb1: gadget@fffa4000 { +- compatible = "atmel,at91rm9200-udc"; +- reg = <0xfffa4000 0x4000>; +- interrupts = <10 4>; +- status = "disabled"; +- }; +- }; +- +- nand0: nand@40000000 { +- compatible = "atmel,at91rm9200-nand"; +- #address-cells = <1>; +- #size-cells = <1>; +- reg = <0x40000000 0x10000000 +- 0xffffe800 0x200 +- >; +- atmel,nand-addr-offset = <21>; +- atmel,nand-cmd-offset = <22>; +- gpios = <&pioC 13 0 +- &pioC 14 0 +- 0 +- >; +- status = "disabled"; +- }; +- +- usb0: ohci@00500000 { +- compatible = "atmel,at91rm9200-ohci", "usb-ohci"; +- reg = <0x00500000 0x100000>; +- interrupts = <20 4>; +- status = "disabled"; +- }; +- }; +- +- i2c@0 { +- compatible = "i2c-gpio"; +- gpios = <&pioA 23 0 /* sda */ +- &pioA 24 0 /* scl */ +- >; +- i2c-gpio,sda-open-drain; +- i2c-gpio,scl-open-drain; +- i2c-gpio,delay-us = <2>; /* ~100 kHz */ +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- }; + }; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 0da66ca..0c2336c 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -14,6 +14,7 @@ initrd_phys-y := 0x20410000 + endif + + # Keep dtb files sorted alphabetically for each SoC ++# sam9260 + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb + # sam9g45 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch b/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch new file mode 100644 index 00000000000000..002aa44882393f --- /dev/null +++ b/patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch @@ -0,0 +1,165 @@ +From 735aea5075e405af25ecdaea8a00091fa0b45c29 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/tny_a9260.dts | 15 ++++++ + arch/arm/boot/dts/tny_a9260_common.dtsi | 83 +++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/tny_a9g20.dts | 15 ++++++ + arch/arm/mach-at91/Makefile.boot | 2 + + 4 files changed, 115 insertions(+) + create mode 100644 arch/arm/boot/dts/tny_a9260.dts + create mode 100644 arch/arm/boot/dts/tny_a9260_common.dtsi + create mode 100644 arch/arm/boot/dts/tny_a9g20.dts + +diff --git a/arch/arm/boot/dts/tny_a9260.dts b/arch/arm/boot/dts/tny_a9260.dts +new file mode 100644 +index 0000000..367a16d +--- /dev/null ++++ b/arch/arm/boot/dts/tny_a9260.dts +@@ -0,0 +1,15 @@ ++/* ++ * tny_a9260.dts - Device Tree file for Caloa TNY A9260 board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9260.dtsi" ++/include/ "tny_a9260_common.dtsi" ++ ++/ { ++ model = "Calao TNY A9260"; ++ compatible = "calao,tny-a9260", "atmel,at91sam9260", "atmel,at91sam9"; ++}; +diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi +new file mode 100644 +index 0000000..0e6d3de +--- /dev/null ++++ b/arch/arm/boot/dts/tny_a9260_common.dtsi +@@ -0,0 +1,83 @@ ++/* ++ * tny_a9260_common.dtsi - Device Tree file for Caloa TNY A926x board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/ { ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock6 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/tny_a9g20.dts b/arch/arm/boot/dts/tny_a9g20.dts +new file mode 100644 +index 0000000..e1ab64c +--- /dev/null ++++ b/arch/arm/boot/dts/tny_a9g20.dts +@@ -0,0 +1,15 @@ ++/* ++ * tny_a9g20.dts - Device Tree file for Caloa TNY A9G20 board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9g20.dtsi" ++/include/ "tny_a9260_common.dtsi" ++ ++/ { ++ model = "Calao TNY A9G20"; ++ compatible = "calao,tny-a9g20", "atmel,at91sam9g20", "atmel,at91sam9"; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 0c2336c..bdf9841 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -15,7 +15,9 @@ endif + + # Keep dtb files sorted alphabetically for each SoC + # sam9260 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + # sam9g20 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb + # sam9g45 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch b/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch new file mode 100644 index 00000000000000..73d1a909e38bed --- /dev/null +++ b/patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch @@ -0,0 +1,253 @@ +From a72c0834c3f846f3fe9f2c782c8d6a67df258458 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 + +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> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/at91sam9g20ek.dts | 29 ++++++ + arch/arm/boot/dts/at91sam9g20ek_2mmc.dts | 29 ++++++ + arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 142 ++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 2 + + 4 files changed, 202 insertions(+) + create mode 100644 arch/arm/boot/dts/at91sam9g20ek.dts + create mode 100644 arch/arm/boot/dts/at91sam9g20ek_2mmc.dts + create mode 100644 arch/arm/boot/dts/at91sam9g20ek_common.dtsi + +diff --git a/arch/arm/boot/dts/at91sam9g20ek.dts b/arch/arm/boot/dts/at91sam9g20ek.dts +new file mode 100644 +index 0000000..e5324bf +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g20ek.dts +@@ -0,0 +1,29 @@ ++/* ++ * at91sam9g20ek.dts - Device Tree file for Atmel at91sam9g20ek board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9g20ek_common.dtsi" ++ ++/ { ++ model = "Atmel at91sam9g20ek"; ++ compatible = "atmel,at91sam9g20ek", "atmel,at91sam9g20", "atmel,at91sam9"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ ds1 { ++ label = "ds1"; ++ gpios = <&pioA 9 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ ds5 { ++ label = "ds5"; ++ gpios = <&pioA 6 1>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts +new file mode 100644 +index 0000000..f1b2e14 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts +@@ -0,0 +1,29 @@ ++/* ++ * at91sam9g20ek_2mmc.dts - Device Tree file for Atmel at91sam9g20ek 2 MMC board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9g20ek_common.dtsi" ++ ++/ { ++ model = "Atmel at91sam9g20ek 2 mmc"; ++ compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9"; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ ds1 { ++ label = "ds1"; ++ gpios = <&pioB 9 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ ds5 { ++ label = "ds5"; ++ gpios = <&pioB 8 1>; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +new file mode 100644 +index 0000000..b06c0db +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +@@ -0,0 +1,142 @@ ++/* ++ * at91sam9g20ek_common.dtsi - Device Tree file for Atmel at91sam9g20ek board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/include/ "at91sam9g20.dtsi" ++ ++/ { ++ ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <18432000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ ++ usart0: serial@fffb0000 { ++ status = "okay"; ++ }; ++ ++ usart1: serial@fffb4000 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffc4000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fffa4000 { ++ atmel,vbus-gpio = <&pioC 5 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ ++ usb0: ohci@00500000 { ++ num-ports = <2>; ++ status = "okay"; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ ++ 24c512@50 { ++ compatible = "24c512"; ++ reg = <0x50>; ++ }; ++ ++ wm8731@1b { ++ compatible = "wm8731"; ++ reg = <0x1b>; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ btn3 { ++ label = "Buttin 3"; ++ gpios = <&pioA 30 1>; ++ linux,code = <0x103>; ++ gpio-key,wakeup; ++ }; ++ ++ btn4 { ++ label = "Buttin 4"; ++ gpios = <&pioA 31 1>; ++ linux,code = <0x104>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index bdf9841..30d6c10 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -17,6 +17,8 @@ endif + # sam9260 + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + # sam9g20 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb + # sam9g45 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch b/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch new file mode 100644 index 00000000000000..d8029a144ce828 --- /dev/null +++ b/patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch @@ -0,0 +1,64 @@ +From b2b5334c32e6c1c8c0333279e4ee9600b3d4d34a 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 + +We now store the dtb in a nand partition. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/usb_a9g20.dts | 11 ++++++++--- + arch/arm/mach-at91/board-usb-a926x.c | 4 ++++ + 2 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts +index 7c2399c..0f88ec8 100644 +--- a/arch/arm/boot/dts/usb_a9g20.dts ++++ b/arch/arm/boot/dts/usb_a9g20.dts +@@ -74,19 +74,24 @@ + reg = <0x80000 0x20000>; + }; + ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ + kernel@a0000 { + label = "kernel"; +- reg = <0xa0000 0x400000>; ++ reg = <0xc0000 0x400000>; + }; + + rootfs@4a0000 { + label = "rootfs"; +- reg = <0x4a0000 0x7800000>; ++ reg = <0x4c0000 0x7800000>; + }; + + data@7ca0000 { + label = "data"; +- reg = <0x7ca0000 0x8360000>; ++ reg = <0x7cc0000 0x8340000>; + }; + }; + +diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c +index 332ecd4..95393fc 100644 +--- a/arch/arm/mach-at91/board-usb-a926x.c ++++ b/arch/arm/mach-at91/board-usb-a926x.c +@@ -172,6 +172,10 @@ static struct mtd_partition __initdata ek_nand_partition[] = { + .offset = MTDPART_OFS_NXTBLK, + .size = SZ_128K, + }, { ++ .name = "oftree", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_128K, ++ }, { + .name = "kernel", + .offset = MTDPART_OFS_NXTBLK, + .size = 4 * SZ_1M, +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch b/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch new file mode 100644 index 00000000000000..d3b4a11e21ff0e --- /dev/null +++ b/patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch @@ -0,0 +1,268 @@ +From 23f3c5a2f5746c2e1eca2364ea6fb3d3e4515cf3 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 + +This will simplify the adding of the A9260. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/usb_a9260_common.dtsi | 117 ++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/usb_a9g20.dts | 107 +---------------------------- + 2 files changed, 118 insertions(+), 106 deletions(-) + create mode 100644 arch/arm/boot/dts/usb_a9260_common.dtsi + +diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi +new file mode 100644 +index 0000000..e70d229 +--- /dev/null ++++ b/arch/arm/boot/dts/usb_a9260_common.dtsi +@@ -0,0 +1,117 @@ ++/* ++ * usb_a926x.dts - Device Tree file for Caloa USB A926x board ++ * ++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++ ++/ { ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffc4000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fffa4000 { ++ atmel,vbus-gpio = <&pioC 5 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ ++ usb0: ohci@00500000 { ++ num-ports = <2>; ++ status = "okay"; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ user_led { ++ label = "user_led"; ++ gpios = <&pioB 21 1>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ user_pb { ++ label = "user_pb"; ++ gpios = <&pioB 10 1>; ++ linux,code = <28>; ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts +index 0f88ec8..2dacb16c 100644 +--- a/arch/arm/boot/dts/usb_a9g20.dts ++++ b/arch/arm/boot/dts/usb_a9g20.dts +@@ -7,6 +7,7 @@ + */ + /dts-v1/; + /include/ "at91sam9g20.dtsi" ++/include/ "usb_a9260_common.dtsi" + + / { + model = "Calao USB A9G20"; +@@ -20,113 +21,7 @@ + reg = <0x20000000 0x4000000>; + }; + +- clocks { +- #address-cells = <1>; +- #size-cells = <1>; +- ranges; +- +- main_clock: clock@0 { +- compatible = "atmel,osc", "fixed-clock"; +- clock-frequency = <12000000>; +- }; +- }; +- +- ahb { +- apb { +- dbgu: serial@fffff200 { +- status = "okay"; +- }; +- +- macb0: ethernet@fffc4000 { +- phy-mode = "rmii"; +- status = "okay"; +- }; +- +- usb1: gadget@fffa4000 { +- atmel,vbus-gpio = <&pioC 5 0>; +- status = "okay"; +- }; +- }; +- +- nand0: nand@40000000 { +- nand-bus-width = <8>; +- nand-ecc-mode = "soft"; +- nand-on-flash-bbt; +- status = "okay"; +- +- at91bootstrap@0 { +- label = "at91bootstrap"; +- reg = <0x0 0x20000>; +- }; +- +- barebox@20000 { +- label = "barebox"; +- reg = <0x20000 0x40000>; +- }; +- +- bareboxenv@60000 { +- label = "bareboxenv"; +- reg = <0x60000 0x20000>; +- }; +- +- bareboxenv2@80000 { +- label = "bareboxenv2"; +- reg = <0x80000 0x20000>; +- }; +- +- oftree@80000 { +- label = "oftree"; +- reg = <0xa0000 0x20000>; +- }; +- +- kernel@a0000 { +- label = "kernel"; +- reg = <0xc0000 0x400000>; +- }; +- +- rootfs@4a0000 { +- label = "rootfs"; +- reg = <0x4c0000 0x7800000>; +- }; +- +- data@7ca0000 { +- label = "data"; +- reg = <0x7cc0000 0x8340000>; +- }; +- }; +- +- usb0: ohci@00500000 { +- num-ports = <2>; +- status = "okay"; +- }; +- }; +- +- leds { +- compatible = "gpio-leds"; +- +- user_led { +- label = "user_led"; +- gpios = <&pioB 21 1>; +- linux,default-trigger = "heartbeat"; +- }; +- }; +- +- gpio_keys { +- compatible = "gpio-keys"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- user_pb { +- label = "user_pb"; +- gpios = <&pioB 10 1>; +- linux,code = <28>; +- gpio-key,wakeup; +- }; +- }; +- + i2c@0 { +- status = "okay"; +- + rv3029c2@56 { + compatible = "rv3029c2"; + reg = <0x56>; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch b/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch new file mode 100644 index 00000000000000..e3259ae532e1d9 --- /dev/null +++ b/patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch @@ -0,0 +1,57 @@ +From 83be7b15e8dea5beb4d3299835b79347c3148fd2 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/usb_a9260.dts | 23 +++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 1 + + 2 files changed, 24 insertions(+) + create mode 100644 arch/arm/boot/dts/usb_a9260.dts + +diff --git a/arch/arm/boot/dts/usb_a9260.dts b/arch/arm/boot/dts/usb_a9260.dts +new file mode 100644 +index 0000000..2962160 +--- /dev/null ++++ b/arch/arm/boot/dts/usb_a9260.dts +@@ -0,0 +1,23 @@ ++/* ++ * usb_a9260.dts - Device Tree file for Caloa USB A9260 board ++ * ++ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++/dts-v1/; ++/include/ "at91sam9260.dtsi" ++/include/ "usb_a9260_common.dtsi" ++ ++/ { ++ model = "Calao USB A9260"; ++ compatible = "calao,usb-a9260", "atmel,at91sam9260", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 30d6c10..b2ac536 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -16,6 +16,7 @@ endif + # Keep dtb files sorted alphabetically for each SoC + # sam9260 + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch b/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch new file mode 100644 index 00000000000000..f27c8142d2baf0 --- /dev/null +++ b/patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch @@ -0,0 +1,115 @@ +From 07e34d884cb904668fe1e413fe10958a65de3c57 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. + +This will avoid the CONFIG_OF on the *_devices.c as this file is deprecated +for DT support. + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91sam9260_devices.c | 20 +++----------------- + arch/arm/mach-at91/at91sam9g45_devices.c | 30 ++++-------------------------- + 2 files changed, 7 insertions(+), 43 deletions(-) + +diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c +index ad00fe9..d556de1 100644 +--- a/arch/arm/mach-at91/at91sam9260_devices.c ++++ b/arch/arm/mach-at91/at91sam9260_devices.c +@@ -702,25 +702,8 @@ static struct platform_device at91sam9260_tcb1_device = { + .num_resources = ARRAY_SIZE(tcb1_resources), + }; + +-#if defined(CONFIG_OF) +-static struct of_device_id tcb_ids[] = { +- { .compatible = "atmel,at91rm9200-tcb" }, +- { /*sentinel*/ } +-}; +-#endif +- + static void __init at91_add_device_tc(void) + { +-#if defined(CONFIG_OF) +- struct device_node *np; +- +- np = of_find_matching_node(NULL, tcb_ids); +- if (np) { +- of_node_put(np); +- return; +- } +-#endif +- + platform_device_register(&at91sam9260_tcb0_device); + platform_device_register(&at91sam9260_tcb1_device); + } +@@ -1364,6 +1347,9 @@ void __init at91_add_device_cf(struct at91_cf_data * data) {} + */ + static int __init at91_add_standard_devices(void) + { ++ if (of_have_populated_dt()) ++ return 0; ++ + at91_add_device_rtt(); + at91_add_device_watchdog(); + at91_add_device_tc(); +diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c +index db2f88c2..35bd42d 100644 +--- a/arch/arm/mach-at91/at91sam9g45_devices.c ++++ b/arch/arm/mach-at91/at91sam9g45_devices.c +@@ -69,15 +69,7 @@ static struct platform_device at_hdmac_device = { + + void __init at91_add_device_hdmac(void) + { +-#if defined(CONFIG_OF) +- struct device_node *of_node = +- of_find_node_by_name(NULL, "dma-controller"); +- +- if (of_node) +- of_node_put(of_node); +- else +-#endif +- platform_device_register(&at_hdmac_device); ++ platform_device_register(&at_hdmac_device); + } + #else + void __init at91_add_device_hdmac(void) {} +@@ -1094,25 +1086,8 @@ static struct platform_device at91sam9g45_tcb1_device = { + .num_resources = ARRAY_SIZE(tcb1_resources), + }; + +-#if defined(CONFIG_OF) +-static struct of_device_id tcb_ids[] = { +- { .compatible = "atmel,at91rm9200-tcb" }, +- { /*sentinel*/ } +-}; +-#endif +- + static void __init at91_add_device_tc(void) + { +-#if defined(CONFIG_OF) +- struct device_node *np; +- +- np = of_find_matching_node(NULL, tcb_ids); +- if (np) { +- of_node_put(np); +- return; +- } +-#endif +- + platform_device_register(&at91sam9g45_tcb0_device); + platform_device_register(&at91sam9g45_tcb1_device); + } +@@ -1763,6 +1738,9 @@ void __init at91_add_device_serial(void) {} + */ + static int __init at91_add_standard_devices(void) + { ++ if (of_have_populated_dt()) ++ return 0; ++ + at91_add_device_hdmac(); + at91_add_device_rtc(); + at91_add_device_rtt(); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch b/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch new file mode 100644 index 00000000000000..c624252fec8306 --- /dev/null +++ b/patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch @@ -0,0 +1,304 @@ +From 6703c4d1f42cf346f9a6f5f174f46c01ece33c90 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/at91sam9263.dtsi | 220 +++++++++++++++++++++++++++++++ + arch/arm/mach-at91/at91sam9263.c | 10 ++ + arch/arm/mach-at91/at91sam9263_devices.c | 20 +++ + 3 files changed, 250 insertions(+) + create mode 100644 arch/arm/boot/dts/at91sam9263.dtsi + +diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi +new file mode 100644 +index 0000000..0209913 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9263.dtsi +@@ -0,0 +1,220 @@ ++/* ++ * at91sam9263.dtsi - Device Tree Include file for AT91SAM9263 family SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 only. ++ */ ++ ++/include/ "skeleton.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9263 family SoC"; ++ compatible = "atmel,at91sam9263"; ++ interrupt-parent = <&aic>; ++ ++ aliases { ++ serial0 = &dbgu; ++ serial1 = &usart0; ++ serial2 = &usart1; ++ serial3 = &usart2; ++ gpio0 = &pioA; ++ gpio1 = &pioB; ++ gpio2 = &pioC; ++ gpio3 = &pioD; ++ gpio4 = &pioE; ++ tcb0 = &tcb0; ++ }; ++ cpus { ++ cpu@0 { ++ compatible = "arm,arm926ejs"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x08000000>; ++ }; ++ ++ ahb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ apb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ aic: interrupt-controller@fffff000 { ++ #interrupt-cells = <2>; ++ compatible = "atmel,at91rm9200-aic"; ++ interrupt-controller; ++ reg = <0xfffff000 0x200>; ++ }; ++ ++ pmc: pmc@fffffc00 { ++ compatible = "atmel,at91rm9200-pmc"; ++ reg = <0xfffffc00 0x100>; ++ }; ++ ++ ramc: ramc@ffffe200 { ++ compatible = "atmel,at91sam9260-sdramc"; ++ reg = <0xffffe200 0x200 ++ 0xffffe800 0x200>; ++ }; ++ ++ pit: timer@fffffd30 { ++ compatible = "atmel,at91sam9260-pit"; ++ reg = <0xfffffd30 0xf>; ++ interrupts = <1 4>; ++ }; ++ ++ tcb0: timer@fff7c000 { ++ compatible = "atmel,at91rm9200-tcb"; ++ reg = <0xfff7c000 0x100>; ++ interrupts = <19 4>; ++ }; ++ ++ rstc@fffffd00 { ++ compatible = "atmel,at91sam9260-rstc"; ++ reg = <0xfffffd00 0x10>; ++ }; ++ ++ shdwc@fffffd10 { ++ compatible = "atmel,at91sam9260-shdwc"; ++ reg = <0xfffffd10 0x10>; ++ }; ++ ++ pioA: gpio@fffff200 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff200 0x100>; ++ interrupts = <2 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioB: gpio@fffff400 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff400 0x100>; ++ interrupts = <3 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioC: gpio@fffff600 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff600 0x100>; ++ interrupts = <4 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioD: gpio@fffff800 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffff800 0x100>; ++ interrupts = <4 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioE: gpio@fffffa00 { ++ compatible = "atmel,at91rm9200-gpio"; ++ reg = <0xfffffa00 0x100>; ++ interrupts = <4 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ dbgu: serial@ffffee00 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xffffee00 0x200>; ++ interrupts = <1 4>; ++ status = "disabled"; ++ }; ++ ++ usart0: serial@fff8c000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfff8c000 0x200>; ++ interrupts = <7 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart1: serial@fff90000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfff90000 0x200>; ++ interrupts = <8 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart2: serial@fff94000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfff94000 0x200>; ++ interrupts = <9 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ macb0: ethernet@fffbc000 { ++ compatible = "cdns,at32ap7000-macb", "cdns,macb"; ++ reg = <0xfffbc000 0x100>; ++ interrupts = <21 4>; ++ status = "disabled"; ++ }; ++ ++ usb1: gadget@fff78000 { ++ compatible = "atmel,at91rm9200-udc"; ++ reg = <0xfff78000 0x4000>; ++ interrupts = <24 4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ compatible = "atmel,at91rm9200-nand"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x40000000 0x10000000 ++ 0xffffe000 0x200 ++ >; ++ atmel,nand-addr-offset = <21>; ++ atmel,nand-cmd-offset = <22>; ++ gpios = <&pioA 22 0 ++ &pioD 15 0 ++ 0 ++ >; ++ status = "disabled"; ++ }; ++ ++ usb0: ohci@00a00000 { ++ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; ++ reg = <0x00a00000 0x100000>; ++ interrupts = <29 4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&pioB 4 0 /* sda */ ++ &pioB 5 0 /* scl */ ++ >; ++ i2c-gpio,sda-open-drain; ++ i2c-gpio,scl-open-drain; ++ i2c-gpio,delay-us = <2>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++}; +diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c +index 7fae365..ed91c7e 100644 +--- a/arch/arm/mach-at91/at91sam9263.c ++++ b/arch/arm/mach-at91/at91sam9263.c +@@ -199,6 +199,16 @@ static struct clk_lookup periph_clocks_lookups[] = { + CLKDEV_CON_ID("pioC", &pioCDE_clk), + CLKDEV_CON_ID("pioD", &pioCDE_clk), + CLKDEV_CON_ID("pioE", &pioCDE_clk), ++ /* more usart lookup table for DT entries */ ++ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck), ++ CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk), ++ CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk), ++ CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk), ++ /* more tc lookup table for DT entries */ ++ CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk), ++ 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), + }; + + static struct clk_lookup usart_clocks_lookups[] = { +diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c +index dfe5bc0..175e000 100644 +--- a/arch/arm/mach-at91/at91sam9263_devices.c ++++ b/arch/arm/mach-at91/at91sam9263_devices.c +@@ -953,8 +953,25 @@ static struct platform_device at91sam9263_tcb_device = { + .num_resources = ARRAY_SIZE(tcb_resources), + }; + ++#if defined(CONFIG_OF) ++static struct of_device_id tcb_ids[] = { ++ { .compatible = "atmel,at91rm9200-tcb" }, ++ { /*sentinel*/ } ++}; ++#endif ++ + static void __init at91_add_device_tc(void) + { ++#if defined(CONFIG_OF) ++ struct device_node *np; ++ ++ np = of_find_matching_node(NULL, tcb_ids); ++ if (np) { ++ of_node_put(np); ++ return; ++ } ++#endif ++ + platform_device_register(&at91sam9263_tcb_device); + } + #else +@@ -1483,6 +1500,9 @@ void __init at91_add_device_serial(void) {} + */ + static int __init at91_add_standard_devices(void) + { ++ if (of_have_populated_dt()) ++ return 0; ++ + at91_add_device_rtt(); + at91_add_device_watchdog(); + at91_add_device_tc(); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch b/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch new file mode 100644 index 00000000000000..7b9c30e1b7b634 --- /dev/null +++ b/patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch @@ -0,0 +1,191 @@ +From 57fab5b53e9cf05574fffd706373b62713eb616c 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/at91sam9263ek.dts | 156 ++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 2 + + 2 files changed, 158 insertions(+) + create mode 100644 arch/arm/boot/dts/at91sam9263ek.dts + +diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts +new file mode 100644 +index 0000000..f86ac4b +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9263ek.dts +@@ -0,0 +1,156 @@ ++/* ++ * at91sam9263ek.dts - Device Tree file for Atmel at91sam9263 reference board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 only ++ */ ++/dts-v1/; ++/include/ "at91sam9263.dtsi" ++ ++/ { ++ model = "Atmel at91sam9263ek"; ++ compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <16367660>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@ffffee00 { ++ status = "okay"; ++ }; ++ ++ usart0: serial@fff8c000 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffbc000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fff78000 { ++ atmel,vbus-gpio = <&pioA 25 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt = <1>; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ ++ usb0: ohci@00a00000 { ++ num-ports = <2>; ++ status = "okay"; ++ atmel,vbus-gpio = <&pioA 24 0 ++ &pioA 21 0 ++ >; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ d3 { ++ label = "d3"; ++ gpios = <&pioB 7 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ d2 { ++ label = "d2"; ++ gpios = <&pioC 29 1>; ++ linux,default-trigger = "nand-disk"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ left_click { ++ label = "left_click"; ++ gpios = <&pioC 5 1>; ++ linux,code = <272>; ++ gpio-key,wakeup; ++ }; ++ ++ right_click { ++ label = "right_click"; ++ gpios = <&pioC 4 1>; ++ linux,code = <273>; ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ ++ 24c512@50 { ++ compatible = "24c512"; ++ reg = <0x50>; ++ pagesize = <128>; ++ }; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index b2ac536..0c6e0e9 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -17,6 +17,8 @@ endif + # sam9260 + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb ++# sam9263 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch b/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch new file mode 100644 index 00000000000000..5ad367b549f0de --- /dev/null +++ b/patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch @@ -0,0 +1,165 @@ +From 6c84b391e098cad2350f661ebffd8b8d4f6b8981 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/usb_a9263.dts | 131 +++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 1 + + 2 files changed, 132 insertions(+) + create mode 100644 arch/arm/boot/dts/usb_a9263.dts + +diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts +new file mode 100644 +index 0000000..6fe05cc +--- /dev/null ++++ b/arch/arm/boot/dts/usb_a9263.dts +@@ -0,0 +1,131 @@ ++/* ++ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 only ++ */ ++/dts-v1/; ++/include/ "at91sam9263.dtsi" ++ ++/ { ++ model = "Calao USB A9263"; ++ compatible = "atmel,usb-a9263", "atmel,at91sam9263", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@ffffee00 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffbc000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fff78000 { ++ atmel,vbus-gpio = <&pioB 11 0>; ++ status = "okay"; ++ }; ++ ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ ++ usb0: ohci@00a00000 { ++ num-ports = <2>; ++ status = "okay"; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ user_led { ++ label = "user_led"; ++ gpios = <&pioB 21 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ user_pb { ++ label = "user_pb"; ++ gpios = <&pioB 10 1>; ++ linux,code = <28>; ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 0c6e0e9..7f0a5cb 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -19,6 +19,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb + # sam9263 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch b/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch new file mode 100644 index 00000000000000..1cdfb9cc6dc58b --- /dev/null +++ b/patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch @@ -0,0 +1,131 @@ +From 242797da12e5e34231572f9d5472ab2f80bbc301 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/boot/dts/tny_a9263.dts | 97 ++++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 1 + + 2 files changed, 98 insertions(+) + create mode 100644 arch/arm/boot/dts/tny_a9263.dts + +diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts +new file mode 100644 +index 0000000..dee9c57 +--- /dev/null ++++ b/arch/arm/boot/dts/tny_a9263.dts +@@ -0,0 +1,97 @@ ++/* ++ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2 only ++ */ ++/dts-v1/; ++/include/ "at91sam9263.dtsi" ++ ++/ { ++ model = "Calao TNY A9263"; ++ compatible = "atmel,tny-a9263", "atmel,at91sam9263", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x4000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <12000000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@ffffee00 { ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fff78000 { ++ atmel,vbus-gpio = <&pioB 11 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ at91bootstrap@0 { ++ label = "at91bootstrap"; ++ reg = <0x0 0x20000>; ++ }; ++ ++ barebox@20000 { ++ label = "barebox"; ++ reg = <0x20000 0x40000>; ++ }; ++ ++ bareboxenv@60000 { ++ label = "bareboxenv"; ++ reg = <0x60000 0x20000>; ++ }; ++ ++ bareboxenv2@80000 { ++ label = "bareboxenv2"; ++ reg = <0x80000 0x20000>; ++ }; ++ ++ oftree@80000 { ++ label = "oftree"; ++ reg = <0xa0000 0x20000>; ++ }; ++ ++ kernel@a0000 { ++ label = "kernel"; ++ reg = <0xc0000 0x400000>; ++ }; ++ ++ rootfs@4a0000 { ++ label = "rootfs"; ++ reg = <0x4c0000 0x7800000>; ++ }; ++ ++ data@7ca0000 { ++ label = "data"; ++ reg = <0x7cc0000 0x8340000>; ++ }; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 7f0a5cb..618fc5b 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -19,6 +19,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb + # sam9263 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9263.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch b/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch new file mode 100644 index 00000000000000..c6646e562f124d --- /dev/null +++ b/patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch @@ -0,0 +1,176 @@ +From 1dd636835a243a050417ff1c10f221ef545d5ab0 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. + +This patch adds support for the kizbox board (based on at91sam9g20 SoC) + +Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/kizbox.dts | 138 +++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 1 + + 2 files changed, 139 insertions(+) + create mode 100644 arch/arm/boot/dts/kizbox.dts + +diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts +new file mode 100644 +index 0000000..e8814fe +--- /dev/null ++++ b/arch/arm/boot/dts/kizbox.dts +@@ -0,0 +1,138 @@ ++/* ++ * kizbox.dts - Device Tree file for Overkiz Kizbox board ++ * ++ * Copyright (C) 2012 Boris BREZILLON <linux-arm@overkiz.com> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9g20.dtsi" ++ ++/ { ++ ++ model = "Overkiz kizbox"; ++ compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x2000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <18432000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ ++ usart0: serial@fffb0000 { ++ status = "okay"; ++ }; ++ ++ usart1: serial@fffb4000 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffc4000 { ++ phy-mode = "mii"; ++ status = "okay"; ++ }; ++ ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ status = "okay"; ++ ++ bootloaderkernel@0 { ++ label = "bootloader-kernel"; ++ reg = <0x0 0xc0000>; ++ }; ++ ++ ubi@c0000 { ++ label = "ubi"; ++ reg = <0xc0000 0x7f40000>; ++ }; ++ ++ }; ++ ++ usb0: ohci@00500000 { ++ num-ports = <1>; ++ status = "okay"; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ ++ pcf8563@51 { ++ /* nxp pcf8563 rtc */ ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++ ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led1g { ++ label = "led1:green"; ++ gpios = <&pioB 0 1>; ++ linux,default-trigger = "none"; ++ }; ++ ++ led1r { ++ label = "led1:red"; ++ gpios = <&pioB 1 1>; ++ linux,default-trigger = "none"; ++ }; ++ ++ led2g { ++ label = "led2:green"; ++ gpios = <&pioB 2 1>; ++ linux,default-trigger = "none"; ++ default-state = "on"; ++ }; ++ ++ led2r { ++ label = "led2:red"; ++ gpios = <&pioB 3 1>; ++ linux,default-trigger = "none"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reset { ++ label = "reset"; ++ gpios = <&pioB 30 1>; ++ linux,code = <0x100>; ++ gpio-key,wakeup; ++ }; ++ ++ mode { ++ label = "mode"; ++ gpios = <&pioB 31 1>; ++ linux,code = <0x101>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; +\ No newline at end of file +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 618fc5b..99e8097 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -24,6 +24,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb + # sam9g20 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += kizbox.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb + # sam9g45 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0037-Ethernut-5-board-support.patch b/patches.at91/0037-Ethernut-5-board-support.patch new file mode 100644 index 00000000000000..a3b9b10843482e --- /dev/null +++ b/patches.at91/0037-Ethernut-5-board-support.patch @@ -0,0 +1,120 @@ +From 6d9ded2c6183d8098f852b2a5dcd18454f9de0e7 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 + +Add support for the Ethernut 5 open hardware design, based +on Atmel's AT91SAM9XE512 SoC. + +Signed-off-by: Tim Schendekehl <tim.schendekehl@egnite.de> +--- + arch/arm/boot/dts/ethernut5.dts | 84 ++++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/Makefile.boot | 1 + + 2 files changed, 85 insertions(+) + create mode 100644 arch/arm/boot/dts/ethernut5.dts + +diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts +new file mode 100644 +index 0000000..1ea9d34 +--- /dev/null ++++ b/arch/arm/boot/dts/ethernut5.dts +@@ -0,0 +1,84 @@ ++/* ++ * ethernut5.dts - Device Tree file for Ethernut 5 board ++ * ++ * Copyright (C) 2012 egnite GmbH <info@egnite.de> ++ * ++ * Licensed under GPLv2. ++ */ ++/dts-v1/; ++/include/ "at91sam9260.dtsi" ++ ++/ { ++ model = "Ethernut 5"; ++ compatible = "egnite,ethernut5", "atmel,at91sam9260", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "console=ttyS0,115200 root=/dev/mtdblock0 rw rootfstype=jffs2"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x08000000>; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ ++ usart0: serial@fffb0000 { ++ status = "okay"; ++ }; ++ ++ usart1: serial@fffb4000 { ++ status = "okay"; ++ }; ++ ++ macb0: ethernet@fffc4000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ usb1: gadget@fffa4000 { ++ atmel,vbus-gpio = <&pioC 5 0>; ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ ++ gpios = <0 ++ &pioC 14 0 ++ 0 ++ >; ++ ++ root@0 { ++ label = "root"; ++ reg = <0x0 0x08000000>; ++ }; ++ ++ data@20000 { ++ label = "data"; ++ reg = <0x08000000 0x38000000>; ++ }; ++ }; ++ ++ usb0: ohci@00500000 { ++ num-ports = <2>; ++ status = "okay"; ++ }; ++ }; ++ ++ i2c@0 { ++ status = "okay"; ++ ++ pcf8563@50 { ++ compatible = "nxp,pcf8563"; ++ reg = <0x51>; ++ }; ++ }; ++}; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 99e8097..c03417d 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -15,6 +15,7 @@ endif + + # Keep dtb files sorted alphabetically for each SoC + # sam9260 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb + # sam9263 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch b/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch new file mode 100644 index 00000000000000..dc6f319c3282b6 --- /dev/null +++ b/patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch @@ -0,0 +1,213 @@ +From 771d02d8690db4118b239f864edca3d80d1c163f 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 + +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> +--- + arch/arm/mach-at91/include/mach/at91sam9n12.h | 60 ++++++++++++++++++++++ + .../mach-at91/include/mach/at91sam9n12_matrix.h | 53 +++++++++++++++++++ + arch/arm/mach-at91/include/mach/cpu.h | 10 ++++ + arch/arm/mach-at91/include/mach/hardware.h | 1 + + arch/arm/mach-at91/soc.h | 5 ++ + 5 files changed, 129 insertions(+) + create mode 100644 arch/arm/mach-at91/include/mach/at91sam9n12.h + create mode 100644 arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h + +diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h +new file mode 100644 +index 0000000..d374b87 +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h +@@ -0,0 +1,60 @@ ++/* ++ * SoC specific header file for the AT91SAM9N12 ++ * ++ * Copyright (C) 2012 Atmel Corporation ++ * ++ * Common definitions, based on AT91SAM9N12 SoC datasheet ++ * ++ * Licensed under GPLv2 or later ++ */ ++ ++#ifndef _AT91SAM9N12_H_ ++#define _AT91SAM9N12_H_ ++ ++/* ++ * Peripheral identifiers/interrupts. ++ */ ++#define AT91SAM9N12_ID_PIOAB 2 /* Parallel I/O Controller A and B */ ++#define AT91SAM9N12_ID_PIOCD 3 /* Parallel I/O Controller C and D */ ++#define AT91SAM9N12_ID_FUSE 4 /* FUSE Controller */ ++#define AT91SAM9N12_ID_USART0 5 /* USART 0 */ ++#define AT91SAM9N12_ID_USART1 6 /* USART 1 */ ++#define AT91SAM9N12_ID_USART2 7 /* USART 2 */ ++#define AT91SAM9N12_ID_USART3 8 /* USART 3 */ ++#define AT91SAM9N12_ID_TWI0 9 /* Two-Wire Interface 0 */ ++#define AT91SAM9N12_ID_TWI1 10 /* Two-Wire Interface 1 */ ++#define AT91SAM9N12_ID_MCI 12 /* High Speed Multimedia Card Interface */ ++#define AT91SAM9N12_ID_SPI0 13 /* Serial Peripheral Interface 0 */ ++#define AT91SAM9N12_ID_SPI1 14 /* Serial Peripheral Interface 1 */ ++#define AT91SAM9N12_ID_UART0 15 /* UART 0 */ ++#define AT91SAM9N12_ID_UART1 16 /* UART 1 */ ++#define AT91SAM9N12_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */ ++#define AT91SAM9N12_ID_PWM 18 /* Pulse Width Modulation Controller */ ++#define AT91SAM9N12_ID_ADC 19 /* ADC Controller */ ++#define AT91SAM9N12_ID_DMA 20 /* DMA Controller */ ++#define AT91SAM9N12_ID_UHP 22 /* USB Host High Speed */ ++#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_SSC 28 /* Synchronous Serial Controller */ ++#define AT91SAM9N12_ID_TRNG 30 /* TRNG */ ++#define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */ ++ ++/* ++ * User Peripheral physical base addresses. ++ */ ++#define AT91SAM9N12_BASE_USART0 0xf801c000 ++#define AT91SAM9N12_BASE_USART1 0xf8020000 ++#define AT91SAM9N12_BASE_USART2 0xf8024000 ++#define AT91SAM9N12_BASE_USART3 0xf8028000 ++ ++/* ++ * Internal Memory. ++ */ ++#define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */ ++#define AT91SAM9N12_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */ ++ ++#define AT91SAM9N12_ROM_BASE 0x00100000 /* Internal ROM base address */ ++#define AT91SAM9N12_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */ ++ ++#endif +diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h +new file mode 100644 +index 0000000..40060cd +--- /dev/null ++++ b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h +@@ -0,0 +1,53 @@ ++/* ++ * Matrix-centric header file for the AT91SAM9N12 ++ * ++ * Copyright (C) 2012 Atmel Corporation. ++ * ++ * Only EBI related registers. ++ * Write Protect register definitions may be useful. ++ * ++ * Licensed under GPLv2 or later. ++ */ ++ ++#ifndef _AT91SAM9N12_MATRIX_H_ ++#define _AT91SAM9N12_MATRIX_H_ ++ ++#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x118) /* EBI Chip Select Assignment Register */ ++#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */ ++#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1) ++#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1) ++#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */ ++#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3) ++#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3) ++#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */ ++#define AT91_MATRIX_EBI_DBPU_ON (0 << 8) ++#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8) ++#define AT91_MATRIX_EBI_VDDIOMSEL (1 << 16) /* Memory voltage selection */ ++#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16) ++#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16) ++#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */ ++#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17) ++#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17) ++#define AT91_MATRIX_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */ ++#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18) ++#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18) ++#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */ ++#define AT91_MATRIX_NFD0_ON_D0 (0 << 24) ++#define AT91_MATRIX_NFD0_ON_D16 (1 << 24) ++#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */ ++#define AT91_MATRIX_MP_OFF (0 << 25) ++#define AT91_MATRIX_MP_ON (1 << 25) ++ ++#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */ ++#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */ ++#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0) ++#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0) ++#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */ ++ ++#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */ ++#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */ ++#define AT91_MATRIX_WPSR_NO_WPV (0 << 0) ++#define AT91_MATRIX_WPSR_WPV (1 << 0) ++#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */ ++ ++#endif +diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h +index 73d2fd2..b6504c1 100644 +--- a/arch/arm/mach-at91/include/mach/cpu.h ++++ b/arch/arm/mach-at91/include/mach/cpu.h +@@ -25,6 +25,7 @@ + #define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */ + #define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */ + #define ARCH_ID_AT91SAM9X5 0x819a05a0 ++#define ARCH_ID_AT91SAM9N12 0x819a07a0 + + #define ARCH_ID_AT91SAM9XE128 0x329973a0 + #define ARCH_ID_AT91SAM9XE256 0x329a93a0 +@@ -71,6 +72,9 @@ enum at91_soc_type { + /* SAM9X5 */ + AT91_SOC_SAM9X5, + ++ /* SAM9N12 */ ++ AT91_SOC_SAM9N12, ++ + /* Unknown type */ + AT91_SOC_NONE + }; +@@ -177,6 +181,12 @@ static inline int at91_soc_is_detected(void) + #define cpu_is_at91sam9x25() (0) + #endif + ++#ifdef CONFIG_SOC_AT91SAM9N12 ++#define cpu_is_at91sam9n12() (at91_soc_initdata.type == AT91_SOC_SAM9N12) ++#else ++#define cpu_is_at91sam9n12() (0) ++#endif ++ + /* + * Since this is ARM, we will never run on any AVR32 CPU. But these + * definitions may reduce clutter in common drivers. +diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h +index 3a01f8f..24b46bd 100644 +--- a/arch/arm/mach-at91/include/mach/hardware.h ++++ b/arch/arm/mach-at91/include/mach/hardware.h +@@ -32,6 +32,7 @@ + #include <mach/at91sam9rl.h> + #include <mach/at91sam9g45.h> + #include <mach/at91sam9x5.h> ++#include <mach/at91sam9n12.h> + + /* + * On all at91 except rm9200 and x40 have the System Controller starts +diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h +index 683dddf..a9cfeb1 100644 +--- a/arch/arm/mach-at91/soc.h ++++ b/arch/arm/mach-at91/soc.h +@@ -20,6 +20,7 @@ extern struct at91_init_soc at91sam9263_soc; + extern struct at91_init_soc at91sam9g45_soc; + extern struct at91_init_soc at91sam9rl_soc; + extern struct at91_init_soc at91sam9x5_soc; ++extern struct at91_init_soc at91sam9n12_soc; + + static inline int at91_soc_is_enabled(void) + { +@@ -53,3 +54,7 @@ static inline int at91_soc_is_enabled(void) + #if !defined(CONFIG_SOC_AT91SAM9X5) + #define at91sam9x5_soc at91_boot_soc + #endif ++ ++#if !defined(CONFIG_SOC_AT91SAM9N12) ++#define at91sam9n12_soc at91_boot_soc ++#endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch b/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch new file mode 100644 index 00000000000000..c5a453488e8e14 --- /dev/null +++ b/patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch @@ -0,0 +1,368 @@ +From 37b8c7ad2aa24a15b778cff614913c63b7e5c505 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 + +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> +--- + arch/arm/mach-at91/Kconfig | 8 ++ + arch/arm/mach-at91/Makefile | 1 + + arch/arm/mach-at91/Makefile.boot | 2 + + arch/arm/mach-at91/at91sam9n12.c | 233 +++++++++++++++++++++++++++++++++++++++ + arch/arm/mach-at91/clock.c | 15 ++- + arch/arm/mach-at91/setup.c | 6 + + 6 files changed, 260 insertions(+), 5 deletions(-) + create mode 100644 arch/arm/mach-at91/at91sam9n12.c + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 98a42f3..19505c0 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -91,6 +91,14 @@ config SOC_AT91SAM9X5 + This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35 + and AT91SAM9X35. + ++config SOC_AT91SAM9N12 ++ bool "AT91SAM9N12 family" ++ select SOC_AT91SAM9 ++ select HAVE_AT91_DBGU0 ++ select HAVE_FB_ATMEL ++ help ++ Select this if you are using Atmel's AT91SAM9N12 SoC. ++ + choice + prompt "Atmel AT91 Processor Devices for non DT boards" + +diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile +index 79d0f60..3bb7a51 100644 +--- a/arch/arm/mach-at91/Makefile ++++ b/arch/arm/mach-at91/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o + obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o + obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o + obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o ++obj-$(CONFIG_SOC_AT91SAM9N12) += at91sam9n12.o + obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o + obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o + +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index c03417d..9e84fe4 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -30,5 +30,7 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb + # sam9g45 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb ++# sam9n12 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb + # sam9x5 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb +diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c +new file mode 100644 +index 0000000..0849466 +--- /dev/null ++++ b/arch/arm/mach-at91/at91sam9n12.c +@@ -0,0 +1,233 @@ ++/* ++ * SoC specific setup code for the AT91SAM9N12 ++ * ++ * Copyright (C) 2012 Atmel Corporation. ++ * ++ * Licensed under GPLv2 or later. ++ */ ++ ++#include <linux/module.h> ++#include <linux/dma-mapping.h> ++ ++#include <asm/irq.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <mach/at91sam9n12.h> ++#include <mach/at91_pmc.h> ++#include <mach/cpu.h> ++#include <mach/board.h> ++ ++#include "soc.h" ++#include "generic.h" ++#include "clock.h" ++#include "sam9_smc.h" ++ ++/* -------------------------------------------------------------------- ++ * Clocks ++ * -------------------------------------------------------------------- */ ++ ++/* ++ * The peripheral clocks. ++ */ ++static struct clk pioAB_clk = { ++ .name = "pioAB_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_PIOAB, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk pioCD_clk = { ++ .name = "pioCD_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_PIOCD, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart0_clk = { ++ .name = "usart0_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_USART0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart1_clk = { ++ .name = "usart1_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_USART1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart2_clk = { ++ .name = "usart2_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_USART2, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk usart3_clk = { ++ .name = "usart3_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_USART3, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk twi0_clk = { ++ .name = "twi0_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_TWI0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk twi1_clk = { ++ .name = "twi1_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_TWI1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk mmc_clk = { ++ .name = "mci_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_MCI, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk spi0_clk = { ++ .name = "spi0_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_SPI0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk spi1_clk = { ++ .name = "spi1_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_SPI1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uart0_clk = { ++ .name = "uart0_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_UART0, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uart1_clk = { ++ .name = "uart1_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_UART1, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk tcb_clk = { ++ .name = "tcb_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_TCB, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk pwm_clk = { ++ .name = "pwm_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_PWM, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk adc_clk = { ++ .name = "adc_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_ADC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk dma_clk = { ++ .name = "dma_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_DMA, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk uhp_clk = { ++ .name = "uhp", ++ .pmc_mask = 1 << AT91SAM9N12_ID_UHP, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk udp_clk = { ++ .name = "udp_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_UDP, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk lcdc_clk = { ++ .name = "lcdc_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_LCDC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++static struct clk ssc_clk = { ++ .name = "ssc_clk", ++ .pmc_mask = 1 << AT91SAM9N12_ID_SSC, ++ .type = CLK_TYPE_PERIPHERAL, ++}; ++ ++static struct clk *periph_clocks[] __initdata = { ++ &pioAB_clk, ++ &pioCD_clk, ++ &usart0_clk, ++ &usart1_clk, ++ &usart2_clk, ++ &usart3_clk, ++ &twi0_clk, ++ &twi1_clk, ++ &mmc_clk, ++ &spi0_clk, ++ &spi1_clk, ++ &lcdc_clk, ++ &uart0_clk, ++ &uart1_clk, ++ &tcb_clk, ++ &pwm_clk, ++ &adc_clk, ++ &dma_clk, ++ &uhp_clk, ++ &udp_clk, ++ &ssc_clk, ++}; ++ ++static struct clk_lookup periph_clocks_lookups[] = { ++ /* lookup table for DT entries */ ++ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck), ++ CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk), ++ CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk), ++ CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk), ++ 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("dma_clk", "ffffec00.dma-controller", &dma_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), ++ /* 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), ++}; ++ ++/* ++ * The two programmable clocks. ++ * You must configure pin multiplexing to bring these signals out. ++ */ ++static struct clk pck0 = { ++ .name = "pck0", ++ .pmc_mask = AT91_PMC_PCK0, ++ .type = CLK_TYPE_PROGRAMMABLE, ++ .id = 0, ++}; ++static struct clk pck1 = { ++ .name = "pck1", ++ .pmc_mask = AT91_PMC_PCK1, ++ .type = CLK_TYPE_PROGRAMMABLE, ++ .id = 1, ++}; ++ ++static void __init at91sam9n12_register_clocks(void) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) ++ clk_register(periph_clocks[i]); ++ clk_register(&pck0); ++ clk_register(&pck1); ++ ++ clkdev_add_table(periph_clocks_lookups, ++ ARRAY_SIZE(periph_clocks_lookups)); ++ ++} ++ ++/* -------------------------------------------------------------------- ++ * AT91SAM9N12 processor initialization ++ * -------------------------------------------------------------------- */ ++ ++static void __init at91sam9n12_map_io(void) ++{ ++ at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE); ++} ++ ++void __init at91sam9n12_initialize(void) ++{ ++ at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0); ++ ++ /* Register GPIO subsystem (using DT) */ ++ at91_gpio_init(NULL, 0); ++} ++ ++struct at91_init_soc __initdata at91sam9n12_soc = { ++ .map_io = at91sam9n12_map_io, ++ .register_clocks = at91sam9n12_register_clocks, ++ .init = at91sam9n12_initialize, ++}; +diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c +index 6b69282..de2ec6b 100644 +--- a/arch/arm/mach-at91/clock.c ++++ b/arch/arm/mach-at91/clock.c +@@ -58,13 +58,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); + + #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ + || cpu_is_at91sam9g45() \ +- || cpu_is_at91sam9x5()) ++ || cpu_is_at91sam9x5() \ ++ || cpu_is_at91sam9n12()) + + #define cpu_has_300M_plla() (cpu_is_at91sam9g10()) + + #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45() \ +- || cpu_is_at91sam9x5())) ++ || cpu_is_at91sam9x5() \ ++ || cpu_is_at91sam9n12())) + + #define cpu_has_upll() (cpu_is_at91sam9g45() \ + || cpu_is_at91sam9x5()) +@@ -78,12 +80,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); + || cpu_is_at91sam9x5())) + + #define cpu_has_plladiv2() (cpu_is_at91sam9g45() \ +- || cpu_is_at91sam9x5()) ++ || cpu_is_at91sam9x5() \ ++ || cpu_is_at91sam9n12()) + + #define cpu_has_mdiv3() (cpu_is_at91sam9g45() \ +- || cpu_is_at91sam9x5()) ++ || cpu_is_at91sam9x5() \ ++ || cpu_is_at91sam9n12()) + +-#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5()) ++#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \ ++ || cpu_is_at91sam9n12()) + + static LIST_HEAD(clocks); + static DEFINE_SPINLOCK(clk_lock); +diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c +index f44a2e7..944bffb 100644 +--- a/arch/arm/mach-at91/setup.c ++++ b/arch/arm/mach-at91/setup.c +@@ -143,6 +143,11 @@ static void __init soc_detect(u32 dbgu_base) + at91_soc_initdata.type = AT91_SOC_SAM9X5; + at91_boot_soc = at91sam9x5_soc; + break; ++ ++ case ARCH_ID_AT91SAM9N12: ++ at91_soc_initdata.type = AT91_SOC_SAM9N12; ++ at91_boot_soc = at91sam9n12_soc; ++ break; + } + + /* at91sam9g10 */ +@@ -210,6 +215,7 @@ static const char *soc_name[] = { + [AT91_SOC_SAM9G45] = "at91sam9g45", + [AT91_SOC_SAM9RL] = "at91sam9rl", + [AT91_SOC_SAM9X5] = "at91sam9x5", ++ [AT91_SOC_SAM9N12] = "at91sam9n12", + [AT91_SOC_NONE] = "Unknown" + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch b/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch new file mode 100644 index 00000000000000..b84646a52eb98a --- /dev/null +++ b/patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.patch @@ -0,0 +1,338 @@ +From 2fc9a0d7df19f33a08242efb22d64e8d3d0280de 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 + +Added AT91SAM9N12 SoC DT file, as well as the board definition +.dts file for AT91SAM9N12-EK. + +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> +--- + arch/arm/boot/dts/at91sam9n12.dtsi | 221 ++++++++++++++++++++++++++++++++++++ + arch/arm/boot/dts/at91sam9n12ek.dts | 84 ++++++++++++++ + 2 files changed, 305 insertions(+) + create mode 100644 arch/arm/boot/dts/at91sam9n12.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9n12ek.dts + +diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi +new file mode 100644 +index 0000000..cb84de7 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9n12.dtsi +@@ -0,0 +1,221 @@ ++/* ++ * at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC ++ * ++ * Copyright (C) 2012 Atmel, ++ * 2012 Hong Xu <hong.xu@atmel.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++ ++/include/ "skeleton.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9N12 SoC"; ++ compatible = "atmel,at91sam9n12"; ++ interrupt-parent = <&aic>; ++ ++ aliases { ++ serial0 = &dbgu; ++ serial1 = &usart0; ++ serial2 = &usart1; ++ serial3 = &usart2; ++ serial4 = &usart3; ++ gpio0 = &pioA; ++ gpio1 = &pioB; ++ gpio2 = &pioC; ++ gpio3 = &pioD; ++ tcb0 = &tcb0; ++ tcb1 = &tcb1; ++ }; ++ cpus { ++ cpu@0 { ++ compatible = "arm,arm926ejs"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x10000000>; ++ }; ++ ++ ahb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ apb { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ aic: interrupt-controller@fffff000 { ++ #interrupt-cells = <2>; ++ compatible = "atmel,at91rm9200-aic"; ++ interrupt-controller; ++ reg = <0xfffff000 0x200>; ++ }; ++ ++ ramc0: ramc@ffffe800 { ++ compatible = "atmel,at91sam9g45-ddramc"; ++ reg = <0xffffe800 0x200>; ++ }; ++ ++ pmc: pmc@fffffc00 { ++ compatible = "atmel,at91rm9200-pmc"; ++ reg = <0xfffffc00 0x100>; ++ }; ++ ++ rstc@fffffe00 { ++ compatible = "atmel,at91sam9g45-rstc"; ++ reg = <0xfffffe00 0x10>; ++ }; ++ ++ pit: timer@fffffe30 { ++ compatible = "atmel,at91sam9260-pit"; ++ reg = <0xfffffe30 0xf>; ++ interrupts = <1 4>; ++ }; ++ ++ shdwc@fffffe10 { ++ compatible = "atmel,at91sam9x5-shdwc"; ++ reg = <0xfffffe10 0x10>; ++ }; ++ ++ tcb0: timer@f8008000 { ++ compatible = "atmel,at91sam9x5-tcb"; ++ reg = <0xf8008000 0x100>; ++ interrupts = <17 4>; ++ }; ++ ++ tcb1: timer@f800c000 { ++ compatible = "atmel,at91sam9x5-tcb"; ++ reg = <0xf800c000 0x100>; ++ interrupts = <17 4>; ++ }; ++ ++ dma: dma-controller@ffffec00 { ++ compatible = "atmel,at91sam9g45-dma"; ++ reg = <0xffffec00 0x200>; ++ interrupts = <20 4>; ++ }; ++ ++ pioA: gpio@fffff400 { ++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; ++ reg = <0xfffff400 0x100>; ++ interrupts = <2 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioB: gpio@fffff600 { ++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; ++ reg = <0xfffff600 0x100>; ++ interrupts = <2 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioC: gpio@fffff800 { ++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; ++ reg = <0xfffff800 0x100>; ++ interrupts = <3 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ pioD: gpio@fffffa00 { ++ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; ++ reg = <0xfffffa00 0x100>; ++ interrupts = <3 4>; ++ #gpio-cells = <2>; ++ gpio-controller; ++ interrupt-controller; ++ }; ++ ++ dbgu: serial@fffff200 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xfffff200 0x200>; ++ interrupts = <1 4>; ++ status = "disabled"; ++ }; ++ ++ usart0: serial@f801c000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xf801c000 0x4000>; ++ interrupts = <5 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart1: serial@f8020000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xf8020000 0x4000>; ++ interrupts = <6 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart2: serial@f8024000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xf8024000 0x4000>; ++ interrupts = <7 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ ++ usart3: serial@f8028000 { ++ compatible = "atmel,at91sam9260-usart"; ++ reg = <0xf8028000 0x4000>; ++ interrupts = <8 4>; ++ atmel,use-dma-rx; ++ atmel,use-dma-tx; ++ status = "disabled"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ compatible = "atmel,at91rm9200-nand"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = < 0x40000000 0x10000000 ++ 0xffffe000 0x00000600 ++ 0xffffe600 0x00000200 ++ 0x00100000 0x00100000 ++ >; ++ atmel,nand-addr-offset = <21>; ++ atmel,nand-cmd-offset = <22>; ++ gpios = <&pioD 5 0 ++ &pioD 4 0 ++ 0 ++ >; ++ status = "disabled"; ++ }; ++ ++ usb0: ohci@00500000 { ++ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; ++ reg = <0x00500000 0x00100000>; ++ interrupts = <22 4>; ++ status = "disabled"; ++ }; ++ }; ++ ++ i2c@0 { ++ compatible = "i2c-gpio"; ++ gpios = <&pioA 30 0 /* sda */ ++ &pioA 31 0 /* scl */ ++ >; ++ i2c-gpio,sda-open-drain; ++ i2c-gpio,scl-open-drain; ++ i2c-gpio,delay-us = <2>; /* ~100 kHz */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts +new file mode 100644 +index 0000000..f4e43e3 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9n12ek.dts +@@ -0,0 +1,84 @@ ++/* ++ * at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board ++ * ++ * Copyright (C) 2012 Atmel, ++ * 2012 Hong Xu <hong.xu@atmel.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++/dts-v1/; ++/include/ "at91sam9n12.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9N12-EK"; ++ compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2"; ++ }; ++ ++ memory { ++ reg = <0x20000000 0x10000000>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ main_clock: clock@0 { ++ compatible = "atmel,osc", "fixed-clock"; ++ clock-frequency = <16000000>; ++ }; ++ }; ++ ++ ahb { ++ apb { ++ dbgu: serial@fffff200 { ++ status = "okay"; ++ }; ++ }; ++ ++ nand0: nand@40000000 { ++ nand-bus-width = <8>; ++ nand-ecc-mode = "soft"; ++ nand-on-flash-bbt; ++ status = "okay"; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ d8 { ++ label = "d8"; ++ gpios = <&pioB 4 1>; ++ linux,default-trigger = "mmc0"; ++ }; ++ ++ d9 { ++ label = "d6"; ++ gpios = <&pioB 5 1>; ++ linux,default-trigger = "nand-disk"; ++ }; ++ ++ d10 { ++ label = "d7"; ++ gpios = <&pioB 6 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ enter { ++ label = "Enter"; ++ gpios = <&pioB 4 1>; ++ linux,code = <28>; ++ gpio-key,wakeup; ++ }; ++ }; ++}; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch b/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch new file mode 100644 index 00000000000000..a118d5ff83b62f --- /dev/null +++ b/patches.at91/0041-ARM-at91-remove-two-unused-headers.patch @@ -0,0 +1,228 @@ +From 2d672820ba5d6f2b3be8f73decfc00d4994af6ba 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 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 +at91rm9200_spi.h and at91rm9200_ssc.h then.) That commit was added in +the v2.6.18 development cycle. + +Nothing includes them now and nothing uses the named constants they +provide. (There's no way these named constants could be used unless +these files were included somehow.) It actually seems these two headers +have never been used since they were added to the tree. They can safely +be removed. + +Signed-off-by: Paul Bolle <pebolle@tiscali.nl> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/include/mach/at91_spi.h | 81 ---------------------- + arch/arm/mach-at91/include/mach/at91_ssc.h | 106 ----------------------------- + 2 files changed, 187 deletions(-) + delete mode 100644 arch/arm/mach-at91/include/mach/at91_spi.h + delete mode 100644 arch/arm/mach-at91/include/mach/at91_ssc.h + +diff --git a/arch/arm/mach-at91/include/mach/at91_spi.h b/arch/arm/mach-at91/include/mach/at91_spi.h +deleted file mode 100644 +index 2f6ba0c..0000000 +--- a/arch/arm/mach-at91/include/mach/at91_spi.h ++++ /dev/null +@@ -1,81 +0,0 @@ +-/* +- * arch/arm/mach-at91/include/mach/at91_spi.h +- * +- * Copyright (C) 2005 Ivan Kokshaysky +- * Copyright (C) SAN People +- * +- * Serial Peripheral Interface (SPI) 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_SPI_H +-#define AT91_SPI_H +- +-#define AT91_SPI_CR 0x00 /* Control Register */ +-#define AT91_SPI_SPIEN (1 << 0) /* SPI Enable */ +-#define AT91_SPI_SPIDIS (1 << 1) /* SPI Disable */ +-#define AT91_SPI_SWRST (1 << 7) /* SPI Software Reset */ +-#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */ +- +-#define AT91_SPI_MR 0x04 /* Mode Register */ +-#define AT91_SPI_MSTR (1 << 0) /* Master/Slave Mode */ +-#define AT91_SPI_PS (1 << 1) /* Peripheral Select */ +-#define AT91_SPI_PS_FIXED (0 << 1) +-#define AT91_SPI_PS_VARIABLE (1 << 1) +-#define AT91_SPI_PCSDEC (1 << 2) /* Chip Select Decode */ +-#define AT91_SPI_DIV32 (1 << 3) /* Clock Selection [AT91RM9200 only] */ +-#define AT91_SPI_MODFDIS (1 << 4) /* Mode Fault Detection */ +-#define AT91_SPI_LLB (1 << 7) /* Local Loopback Enable */ +-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ +-#define AT91_SPI_DLYBCS (0xff << 24) /* Delay Between Chip Selects */ +- +-#define AT91_SPI_RDR 0x08 /* Receive Data Register */ +-#define AT91_SPI_RD (0xffff << 0) /* Receive Data */ +-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ +- +-#define AT91_SPI_TDR 0x0c /* Transmit Data Register */ +-#define AT91_SPI_TD (0xffff << 0) /* Transmit Data */ +-#define AT91_SPI_PCS (0xf << 16) /* Peripheral Chip Select */ +-#define AT91_SPI_LASTXFER (1 << 24) /* Last Transfer [SAM9261 only] */ +- +-#define AT91_SPI_SR 0x10 /* Status Register */ +-#define AT91_SPI_RDRF (1 << 0) /* Receive Data Register Full */ +-#define AT91_SPI_TDRE (1 << 1) /* Transmit Data Register Full */ +-#define AT91_SPI_MODF (1 << 2) /* Mode Fault Error */ +-#define AT91_SPI_OVRES (1 << 3) /* Overrun Error Status */ +-#define AT91_SPI_ENDRX (1 << 4) /* End of RX buffer */ +-#define AT91_SPI_ENDTX (1 << 5) /* End of TX buffer */ +-#define AT91_SPI_RXBUFF (1 << 6) /* RX Buffer Full */ +-#define AT91_SPI_TXBUFE (1 << 7) /* TX Buffer Empty */ +-#define AT91_SPI_NSSR (1 << 8) /* NSS Rising [SAM9261 only] */ +-#define AT91_SPI_TXEMPTY (1 << 9) /* Transmission Register Empty [SAM9261 only] */ +-#define AT91_SPI_SPIENS (1 << 16) /* SPI Enable Status */ +- +-#define AT91_SPI_IER 0x14 /* Interrupt Enable Register */ +-#define AT91_SPI_IDR 0x18 /* Interrupt Disable Register */ +-#define AT91_SPI_IMR 0x1c /* Interrupt Mask Register */ +- +-#define AT91_SPI_CSR(n) (0x30 + ((n) * 4)) /* Chip Select Registers 0-3 */ +-#define AT91_SPI_CPOL (1 << 0) /* Clock Polarity */ +-#define AT91_SPI_NCPHA (1 << 1) /* Clock Phase */ +-#define AT91_SPI_CSAAT (1 << 3) /* Chip Select Active After Transfer [SAM9261 only] */ +-#define AT91_SPI_BITS (0xf << 4) /* Bits Per Transfer */ +-#define AT91_SPI_BITS_8 (0 << 4) +-#define AT91_SPI_BITS_9 (1 << 4) +-#define AT91_SPI_BITS_10 (2 << 4) +-#define AT91_SPI_BITS_11 (3 << 4) +-#define AT91_SPI_BITS_12 (4 << 4) +-#define AT91_SPI_BITS_13 (5 << 4) +-#define AT91_SPI_BITS_14 (6 << 4) +-#define AT91_SPI_BITS_15 (7 << 4) +-#define AT91_SPI_BITS_16 (8 << 4) +-#define AT91_SPI_SCBR (0xff << 8) /* Serial Clock Baud Rate */ +-#define AT91_SPI_DLYBS (0xff << 16) /* Delay before SPCK */ +-#define AT91_SPI_DLYBCT (0xff << 24) /* Delay between Consecutive Transfers */ +- +-#endif +diff --git a/arch/arm/mach-at91/include/mach/at91_ssc.h b/arch/arm/mach-at91/include/mach/at91_ssc.h +deleted file mode 100644 +index a81114c..0000000 +--- a/arch/arm/mach-at91/include/mach/at91_ssc.h ++++ /dev/null +@@ -1,106 +0,0 @@ +-/* +- * arch/arm/mach-at91/include/mach/at91_ssc.h +- * +- * Copyright (C) SAN People +- * +- * Serial Synchronous Controller (SSC) 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_SSC_H +-#define AT91_SSC_H +- +-#define AT91_SSC_CR 0x00 /* Control Register */ +-#define AT91_SSC_RXEN (1 << 0) /* Receive Enable */ +-#define AT91_SSC_RXDIS (1 << 1) /* Receive Disable */ +-#define AT91_SSC_TXEN (1 << 8) /* Transmit Enable */ +-#define AT91_SSC_TXDIS (1 << 9) /* Transmit Disable */ +-#define AT91_SSC_SWRST (1 << 15) /* Software Reset */ +- +-#define AT91_SSC_CMR 0x04 /* Clock Mode Register */ +-#define AT91_SSC_CMR_DIV (0xfff << 0) /* Clock Divider */ +- +-#define AT91_SSC_RCMR 0x10 /* Receive Clock Mode Register */ +-#define AT91_SSC_CKS (3 << 0) /* Clock Selection */ +-#define AT91_SSC_CKS_DIV (0 << 0) +-#define AT91_SSC_CKS_CLOCK (1 << 0) +-#define AT91_SSC_CKS_PIN (2 << 0) +-#define AT91_SSC_CKO (7 << 2) /* Clock Output Mode Selection */ +-#define AT91_SSC_CKO_NONE (0 << 2) +-#define AT91_SSC_CKO_CONTINUOUS (1 << 2) +-#define AT91_SSC_CKI (1 << 5) /* Clock Inversion */ +-#define AT91_SSC_CKI_FALLING (0 << 5) +-#define AT91_SSC_CK_RISING (1 << 5) +-#define AT91_SSC_CKG (1 << 6) /* Receive Clock Gating Selection [AT91SAM9261 only] */ +-#define AT91_SSC_CKG_NONE (0 << 6) +-#define AT91_SSC_CKG_RFLOW (1 << 6) +-#define AT91_SSC_CKG_RFHIGH (2 << 6) +-#define AT91_SSC_START (0xf << 8) /* Start Selection */ +-#define AT91_SSC_START_CONTINUOUS (0 << 8) +-#define AT91_SSC_START_TX_RX (1 << 8) +-#define AT91_SSC_START_LOW_RF (2 << 8) +-#define AT91_SSC_START_HIGH_RF (3 << 8) +-#define AT91_SSC_START_FALLING_RF (4 << 8) +-#define AT91_SSC_START_RISING_RF (5 << 8) +-#define AT91_SSC_START_LEVEL_RF (6 << 8) +-#define AT91_SSC_START_EDGE_RF (7 << 8) +-#define AT91_SSC_STOP (1 << 12) /* Receive Stop Selection [AT91SAM9261 only] */ +-#define AT91_SSC_STTDLY (0xff << 16) /* Start Delay */ +-#define AT91_SSC_PERIOD (0xff << 24) /* Period Divider Selection */ +- +-#define AT91_SSC_RFMR 0x14 /* Receive Frame Mode Register */ +-#define AT91_SSC_DATALEN (0x1f << 0) /* Data Length */ +-#define AT91_SSC_LOOP (1 << 5) /* Loop Mode */ +-#define AT91_SSC_MSBF (1 << 7) /* Most Significant Bit First */ +-#define AT91_SSC_DATNB (0xf << 8) /* Data Number per Frame */ +-#define AT91_SSC_FSLEN (0xf << 16) /* Frame Sync Length */ +-#define AT91_SSC_FSOS (7 << 20) /* Frame Sync Output Selection */ +-#define AT91_SSC_FSOS_NONE (0 << 20) +-#define AT91_SSC_FSOS_NEGATIVE (1 << 20) +-#define AT91_SSC_FSOS_POSITIVE (2 << 20) +-#define AT91_SSC_FSOS_LOW (3 << 20) +-#define AT91_SSC_FSOS_HIGH (4 << 20) +-#define AT91_SSC_FSOS_TOGGLE (5 << 20) +-#define AT91_SSC_FSEDGE (1 << 24) /* Frame Sync Edge Detection */ +-#define AT91_SSC_FSEDGE_POSITIVE (0 << 24) +-#define AT91_SSC_FSEDGE_NEGATIVE (1 << 24) +- +-#define AT91_SSC_TCMR 0x18 /* Transmit Clock Mode Register */ +-#define AT91_SSC_TFMR 0x1c /* Transmit Fram Mode Register */ +-#define AT91_SSC_DATDEF (1 << 5) /* Data Default Value */ +-#define AT91_SSC_FSDEN (1 << 23) /* Frame Sync Data Enable */ +- +-#define AT91_SSC_RHR 0x20 /* Receive Holding Register */ +-#define AT91_SSC_THR 0x24 /* Transmit Holding Register */ +-#define AT91_SSC_RSHR 0x30 /* Receive Sync Holding Register */ +-#define AT91_SSC_TSHR 0x34 /* Transmit Sync Holding Register */ +- +-#define AT91_SSC_RC0R 0x38 /* Receive Compare 0 Register [AT91SAM9261 only] */ +-#define AT91_SSC_RC1R 0x3c /* Receive Compare 1 Register [AT91SAM9261 only] */ +- +-#define AT91_SSC_SR 0x40 /* Status Register */ +-#define AT91_SSC_TXRDY (1 << 0) /* Transmit Ready */ +-#define AT91_SSC_TXEMPTY (1 << 1) /* Transmit Empty */ +-#define AT91_SSC_ENDTX (1 << 2) /* End of Transmission */ +-#define AT91_SSC_TXBUFE (1 << 3) /* Transmit Buffer Empty */ +-#define AT91_SSC_RXRDY (1 << 4) /* Receive Ready */ +-#define AT91_SSC_OVRUN (1 << 5) /* Receive Overrun */ +-#define AT91_SSC_ENDRX (1 << 6) /* End of Reception */ +-#define AT91_SSC_RXBUFF (1 << 7) /* Receive Buffer Full */ +-#define AT91_SSC_CP0 (1 << 8) /* Compare 0 [AT91SAM9261 only] */ +-#define AT91_SSC_CP1 (1 << 9) /* Compare 1 [AT91SAM9261 only] */ +-#define AT91_SSC_TXSYN (1 << 10) /* Transmit Sync */ +-#define AT91_SSC_RXSYN (1 << 11) /* Receive Sync */ +-#define AT91_SSC_TXENA (1 << 16) /* Transmit Enable */ +-#define AT91_SSC_RXENA (1 << 17) /* Receive Enable */ +- +-#define AT91_SSC_IER 0x44 /* Interrupt Enable Register */ +-#define AT91_SSC_IDR 0x48 /* Interrupt Disable Register */ +-#define AT91_SSC_IMR 0x4c /* Interrupt Mask Register */ +- +-#endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch b/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch new file mode 100644 index 00000000000000..c5cb945c019f7f --- /dev/null +++ b/patches.at91/0042-ARM-at91-fix-at91_aic_write-macro.patch @@ -0,0 +1,29 @@ +From f7a7be1650e7160181c9ab1c4aeb5dd8b67ac939 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 + +Fix at91_aic_write macro to avoid potential issues. + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/include/mach/at91_aic.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h +index 3045781..c1413ed 100644 +--- a/arch/arm/mach-at91/include/mach/at91_aic.h ++++ b/arch/arm/mach-at91/include/mach/at91_aic.h +@@ -23,7 +23,7 @@ extern void __iomem *at91_aic_base; + __raw_readl(at91_aic_base + field) + + #define at91_aic_write(field, value) \ +- __raw_writel(value, at91_aic_base + field); ++ __raw_writel(value, at91_aic_base + field) + #else + .extern at91_aic_base + #endif +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch b/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch new file mode 100644 index 00000000000000..2f65c9fa765120 --- /dev/null +++ b/patches.at91/0043-USB-ohci-at91-use-resource_size-for-memory-io-resour.patch @@ -0,0 +1,27 @@ +From 6b36e56532a5b9d9f2311165a95f2a0d31c40464 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + drivers/usb/host/ohci-at91.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c +index 55d3d64..84901c3 100644 +--- a/drivers/usb/host/ohci-at91.c ++++ b/drivers/usb/host/ohci-at91.c +@@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver, + if (!hcd) + return -ENOMEM; + hcd->rsrc_start = pdev->resource[0].start; +- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; ++ hcd->rsrc_len = resource_size(&pdev->resource[0]); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed\n"); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch b/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch new file mode 100644 index 00000000000000..782778b7ce0dc8 --- /dev/null +++ b/patches.at91/0044-USB-Kconfig-add-Atmel-usba-driver-entry.patch @@ -0,0 +1,29 @@ +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 + diff --git a/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch b/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch new file mode 100644 index 00000000000000..50009b45b6faed --- /dev/null +++ b/patches.at91/0045-ARM-at91-clock-fix-PLLA-overclock-warning.patch @@ -0,0 +1,47 @@ +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 + diff --git a/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch b/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch new file mode 100644 index 00000000000000..721fb1e214f3d3 --- /dev/null +++ b/patches.at91/0046-ARM-at91-dts-remove-partial-parameter-in-at91sam9g25.patch @@ -0,0 +1,29 @@ +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 + diff --git a/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch b/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch new file mode 100644 index 00000000000000..503985d9b9f9a5 --- /dev/null +++ b/patches.at91/0047-ARM-at91-set-i2c_board_info.type-to-ds1339-directly.patch @@ -0,0 +1,33 @@ +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 + diff --git a/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch b/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch new file mode 100644 index 00000000000000..2a84b809661f54 --- /dev/null +++ b/patches.at91/0048-ARM-at91-defconfig-Remove-unaffected-config-option.patch @@ -0,0 +1,123 @@ +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 + diff --git a/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch b/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch new file mode 100644 index 00000000000000..06db420f8ecdea --- /dev/null +++ b/patches.at91/0049-ARM-at91-fix-missing-interrupt-cells-on-gpio-control.patch @@ -0,0 +1,207 @@ +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 + diff --git a/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch b/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch new file mode 100644 index 00000000000000..157177082280d2 --- /dev/null +++ b/patches.at91/0051-ARM-at91-missing-header-file-for-rtc-at91rm9200.c.patch @@ -0,0 +1,28 @@ +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 + diff --git a/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch b/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch new file mode 100644 index 00000000000000..f5e8dcfeb5ac08 --- /dev/null +++ b/patches.at91/0052-ASoC-atmel-ssc-include-linux-io.h-for-raw-io.patch @@ -0,0 +1,37 @@ +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 + diff --git a/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch b/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch new file mode 100644 index 00000000000000..6003ca8075efdc --- /dev/null +++ b/patches.at91/0053-ARM-at91-aic-can-use-fast-eoi-handler-type.patch @@ -0,0 +1,158 @@ +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 + diff --git a/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch b/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch new file mode 100644 index 00000000000000..4850ef400ae862 --- /dev/null +++ b/patches.at91/0054-ARM-at91-aic-add-dt-support-for-external-irqs.patch @@ -0,0 +1,122 @@ +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 + diff --git a/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch b/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch new file mode 100644 index 00000000000000..ed2769e343edb5 --- /dev/null +++ b/patches.at91/0055-ARM-at91-add-of-irq-priorities-support.patch @@ -0,0 +1,883 @@ +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 + diff --git a/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch b/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch new file mode 100644 index 00000000000000..395295b3151bb4 --- /dev/null +++ b/patches.at91/0056-ARM-at91-remove-static-irq-priorities-for-sam9x5.patch @@ -0,0 +1,69 @@ +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 + diff --git a/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch b/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch new file mode 100644 index 00000000000000..a02a21ce88c4bd --- /dev/null +++ b/patches.at91/0057-ARM-at91-at91-based-machines-specify-their-own-irq-h.patch @@ -0,0 +1,903 @@ +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 + diff --git a/patches.at91/0058-ARM-at91-sparse-irq-support.patch b/patches.at91/0058-ARM-at91-sparse-irq-support.patch new file mode 100644 index 00000000000000..0947785f2886a0 --- /dev/null +++ b/patches.at91/0058-ARM-at91-sparse-irq-support.patch @@ -0,0 +1,1578 @@ +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 + diff --git a/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch b/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch new file mode 100644 index 00000000000000..17aa40e9ef3034 --- /dev/null +++ b/patches.at91/0059-ARM-at91-remove-mach-irqs.h.patch @@ -0,0 +1,53 @@ +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 + diff --git a/patches.at91/0060-ARM-at91-add-AIC5-support.patch b/patches.at91/0060-ARM-at91-add-AIC5-support.patch new file mode 100644 index 00000000000000..feaacd1db0f4ae --- /dev/null +++ b/patches.at91/0060-ARM-at91-add-AIC5-support.patch @@ -0,0 +1,606 @@ +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 + diff --git a/patches.at91/0061-dt-add-property-iteration-helpers.patch b/patches.at91/0061-dt-add-property-iteration-helpers.patch new file mode 100644 index 00000000000000..40f12e568a1529 --- /dev/null +++ b/patches.at91/0061-dt-add-property-iteration-helpers.patch @@ -0,0 +1,129 @@ +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 diff --git a/patches.at91/0062-ARM-at91-fix-new-build-errors.patch b/patches.at91/0062-ARM-at91-fix-new-build-errors.patch new file mode 100644 index 00000000000000..b26870b9f081b0 --- /dev/null +++ b/patches.at91/0062-ARM-at91-fix-new-build-errors.patch @@ -0,0 +1,95 @@ +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 + diff --git a/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch b/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch new file mode 100644 index 00000000000000..64a2b3ea490bfa --- /dev/null +++ b/patches.at91/0063-dmaengine-at_hdmac-remove-some-at_dma_slave-comments.patch @@ -0,0 +1,32 @@ +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 + diff --git a/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch b/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch new file mode 100644 index 00000000000000..ff3c21c85f24bb --- /dev/null +++ b/patches.at91/0064-dmaengine-at_hdmac-remove-ATC_DEFAULT_CTRLA-constant.patch @@ -0,0 +1,66 @@ +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; diff --git a/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch b/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch new file mode 100644 index 00000000000000..2dc96e7fde2fb6 --- /dev/null +++ b/patches.at91/0065-dmaengine-at_hdmac-take-maxburst-from-slave-configur.patch @@ -0,0 +1,129 @@ +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) diff --git a/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch b/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch new file mode 100644 index 00000000000000..60572dc4f2a8d5 --- /dev/null +++ b/patches.at91/0066-dmaengine-at_hdmac-trivial-fix-comment-in-header.patch @@ -0,0 +1,36 @@ +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 + diff --git a/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch b/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch new file mode 100644 index 00000000000000..d2942666314b6f --- /dev/null +++ b/patches.at91/0069-AT91-Remove-fixed-mapping-for-AT91RM9200-ethernet.patch @@ -0,0 +1,1121 @@ +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 + diff --git a/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch b/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch new file mode 100644 index 00000000000000..07c79ae379694e --- /dev/null +++ b/patches.at91/0070-net-at91_ether-use-gpio_to_irq-for-phy-IRQ-line.patch @@ -0,0 +1,62 @@ +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 + diff --git a/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch b/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch new file mode 100644 index 00000000000000..de3a73a9d785bf --- /dev/null +++ b/patches.at91/0071-net-macb-manage-carrier-state-with-call-to-netif_car.patch @@ -0,0 +1,67 @@ +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 + diff --git a/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch b/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch new file mode 100644 index 00000000000000..d8a89a2cc95341 --- /dev/null +++ b/patches.at91/0072-ALSA-atmel-ac97c-correct-the-unexpected-behavior-whe.patch @@ -0,0 +1,35 @@ +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 + diff --git a/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch b/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch new file mode 100644 index 00000000000000..436c88279c1fde --- /dev/null +++ b/patches.at91/0073-MTD-at91-extract-hw-ecc-initialization-to-one-functi.patch @@ -0,0 +1,188 @@ +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 + diff --git a/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch b/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch new file mode 100644 index 00000000000000..b1711f6c37c108 --- /dev/null +++ b/patches.at91/0074-MTD-at91-add-dt-parameters-for-Atmel-PMECC.patch @@ -0,0 +1,157 @@ +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 + diff --git a/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch b/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch new file mode 100644 index 00000000000000..df8ea11c4f2dcb --- /dev/null +++ b/patches.at91/0075-MTD-at91-atmel_nand-Update-driver-to-support-Program.patch @@ -0,0 +1,959 @@ +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 + diff --git a/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch b/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch new file mode 100644 index 00000000000000..af5354607adb12 --- /dev/null +++ b/patches.at91/0076-MTD-nand-add-return-value-for-write_page-write_page_.patch @@ -0,0 +1,153 @@ +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); diff --git a/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch b/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch new file mode 100644 index 00000000000000..bdccc954ab88b0 --- /dev/null +++ b/patches.at91/0077-MTD-atmel_nand-revet-the-oob_required-parameter-in-e.patch @@ -0,0 +1,38 @@ +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 + diff --git a/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch b/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch new file mode 100644 index 00000000000000..052f8ee81486ce --- /dev/null +++ b/patches.at91/0078-MTD-atmel_nand-add-9x5-to-list-of-SoC-with-DMA.patch @@ -0,0 +1,28 @@ +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 + diff --git a/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch b/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch new file mode 100644 index 00000000000000..cbecb401cca41d --- /dev/null +++ b/patches.at91/0079-MTD-atmel_nand-POI-fall-back-is-not-an-issue-change-.patch @@ -0,0 +1,26 @@ +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 + diff --git a/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch b/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch new file mode 100644 index 00000000000000..0b9ce93686f38f --- /dev/null +++ b/patches.at91/0080-MTD-atmel_nand-add-9n12-to-list-of-SoC-with-DMA.patch @@ -0,0 +1,29 @@ +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 + diff --git a/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch b/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch new file mode 100644 index 00000000000000..e0fbdeb181a8df --- /dev/null +++ b/patches.at91/0081-input-atmel_tsadcc-add-support-for-ARCH_AT91SAM9X5.patch @@ -0,0 +1,392 @@ +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 + diff --git a/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch b/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch new file mode 100644 index 00000000000000..c9e59344022416 --- /dev/null +++ b/patches.at91/0082-input-atmel_tsadcc-add-touch-screen-pressure-measure.patch @@ -0,0 +1,104 @@ +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 + diff --git a/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch b/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch new file mode 100644 index 00000000000000..f368baf433b557 --- /dev/null +++ b/patches.at91/0083-input-atmel_tsadcc-enable-touchscreen-averaging-and-.patch @@ -0,0 +1,77 @@ +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 + diff --git a/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch b/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch new file mode 100644 index 00000000000000..82ce0dbcb7ee06 --- /dev/null +++ b/patches.at91/0084-input-atmel_tsadcc-add-ACR-register-and-change-trigg.patch @@ -0,0 +1,92 @@ +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 + diff --git a/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch b/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch new file mode 100644 index 00000000000000..a42080f6c46216 --- /dev/null +++ b/patches.at91/0085-AT91-input-atmel_tsadcc-rework-irq-infrastructure-an.patch @@ -0,0 +1,168 @@ +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 + diff --git a/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch b/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch new file mode 100644 index 00000000000000..3b361bce87d490 --- /dev/null +++ b/patches.at91/0086-input-at91-add-tsadcc_data-for-9x5.patch @@ -0,0 +1,27 @@ +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 + diff --git a/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch b/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch new file mode 100644 index 00000000000000..1a432fc8060284 --- /dev/null +++ b/patches.at91/0087-input-at91-add-dt-support-for-atmel-touch-screen-adc.patch @@ -0,0 +1,157 @@ +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 + diff --git a/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch b/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch new file mode 100644 index 00000000000000..df89e312b3d33e --- /dev/null +++ b/patches.at91/0088-net-macb-Add-support-for-Gigabit-Ethernet-mode.patch @@ -0,0 +1,85 @@ +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 + diff --git a/patches.at91/0089-net-macb-memory-barriers-cleanup.patch b/patches.at91/0089-net-macb-memory-barriers-cleanup.patch new file mode 100644 index 00000000000000..7950edb7c417f5 --- /dev/null +++ b/patches.at91/0089-net-macb-memory-barriers-cleanup.patch @@ -0,0 +1,96 @@ +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 + diff --git a/patches.at91/0090-net-macb-change-debugging-messages.patch b/patches.at91/0090-net-macb-change-debugging-messages.patch new file mode 100644 index 00000000000000..014d00ddc601be --- /dev/null +++ b/patches.at91/0090-net-macb-change-debugging-messages.patch @@ -0,0 +1,112 @@ +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 + diff --git a/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch b/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch new file mode 100644 index 00000000000000..c9e7cdb252c15b --- /dev/null +++ b/patches.at91/0091-net-macb-remove-macb_get_drvinfo.patch @@ -0,0 +1,41 @@ +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 + diff --git a/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch b/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch new file mode 100644 index 00000000000000..9c0d4ce58f495b --- /dev/null +++ b/patches.at91/0092-net-macb-tx-status-is-more-than-8-bits-now.patch @@ -0,0 +1,28 @@ +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 + diff --git a/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch b/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch new file mode 100644 index 00000000000000..4e781ee0d84477 --- /dev/null +++ b/patches.at91/0093-net-macb-clean-up-ring-buffer-logic.patch @@ -0,0 +1,409 @@ +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 + diff --git a/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch b/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch new file mode 100644 index 00000000000000..0b4bc9cbb76af4 --- /dev/null +++ b/patches.at91/0094-net-macb-ethtool-interface-add-register-dump-feature.patch @@ -0,0 +1,88 @@ +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 + diff --git a/patches.at91/0095-net-macb-better-manage-tx-errors.patch b/patches.at91/0095-net-macb-better-manage-tx-errors.patch new file mode 100644 index 00000000000000..1be968b607b33c --- /dev/null +++ b/patches.at91/0095-net-macb-better-manage-tx-errors.patch @@ -0,0 +1,257 @@ +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 + diff --git a/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch b/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch new file mode 100644 index 00000000000000..8037759a4005e6 --- /dev/null +++ b/patches.at91/0096-net-macb-Offset-first-RX-buffer-by-two-bytes.patch @@ -0,0 +1,94 @@ +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 + diff --git a/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch b/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch new file mode 100644 index 00000000000000..2cfd5c29859c8d --- /dev/null +++ b/patches.at91/0097-net-macb-GEM-DMA-configuration-register-update.patch @@ -0,0 +1,71 @@ +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 + diff --git a/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch b/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch new file mode 100644 index 00000000000000..19fb2b0a74abfa --- /dev/null +++ b/patches.at91/0098-net-macb-Use-non-coherent-memory-for-rx-buffers.patch @@ -0,0 +1,378 @@ +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 + diff --git a/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch b/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch new file mode 100644 index 00000000000000..2c1d4bb38c472d --- /dev/null +++ b/patches.at91/0099-phy-micrel-Use-proper-phy-in-gmac.patch @@ -0,0 +1,49 @@ +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 + diff --git a/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch b/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch new file mode 100644 index 00000000000000..32d46d482232f8 --- /dev/null +++ b/patches.at91/0100-phy-micrel-we-need-to-register-ks8051-phy-for-emac.patch @@ -0,0 +1,39 @@ +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 + diff --git a/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch b/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch new file mode 100644 index 00000000000000..b28e71bae4041a --- /dev/null +++ b/patches.at91/0101-usb-gadget-at91_udc-move-the-dereference-below-the-N.patch @@ -0,0 +1,40 @@ +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 + diff --git a/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch b/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch new file mode 100644 index 00000000000000..4f7467a03a8c14 --- /dev/null +++ b/patches.at91/0103-USB-ohci-at91-fix-PIO-handling-in-relation-with-numb.patch @@ -0,0 +1,41 @@ +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); diff --git a/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch b/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch new file mode 100644 index 00000000000000..014d66dc902dc5 --- /dev/null +++ b/patches.at91/0104-usb-gadget-at91_udc-Propagate-devicetree-to-gadget-d.patch @@ -0,0 +1,28 @@ +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 + diff --git a/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch b/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch new file mode 100644 index 00000000000000..c90aef45d3d88b --- /dev/null +++ b/patches.at91/0105-USB-ohci-at91.c-remove-err-usage.patch @@ -0,0 +1,34 @@ +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 + diff --git a/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch b/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch new file mode 100644 index 00000000000000..d61092555b688a --- /dev/null +++ b/patches.at91/0107-media-video-atmel-isi-add-dumb-set_parm.patch @@ -0,0 +1,42 @@ +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 + diff --git a/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch b/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch new file mode 100644 index 00000000000000..4e4c77bc85b99b --- /dev/null +++ b/patches.at91/0108-video-atmel_lcdfb-add-support-for-AT91SAM9x5.patch @@ -0,0 +1,1810 @@ +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 + diff --git a/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch b/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch new file mode 100644 index 00000000000000..b7357c71772d21 --- /dev/null +++ b/patches.at91/0109-video-atmel_lcdfb-The-output-bpp-should-not-change-a.patch @@ -0,0 +1,66 @@ +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 + diff --git a/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch b/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch new file mode 100644 index 00000000000000..51c6f1091d3355 --- /dev/null +++ b/patches.at91/0110-video-atmelfb-initially-split-atmelfb-into-a-driver-.patch @@ -0,0 +1,2643 @@ +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 + diff --git a/patches.at91/0111-video-atmelfb-refactor-core-setup.patch b/patches.at91/0111-video-atmelfb-refactor-core-setup.patch new file mode 100644 index 00000000000000..c45df550414cc8 --- /dev/null +++ b/patches.at91/0111-video-atmelfb-refactor-core-setup.patch @@ -0,0 +1,403 @@ +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 + diff --git a/patches.at91/0112-video-atmelfb-refactor-start-stop.patch b/patches.at91/0112-video-atmelfb-refactor-start-stop.patch new file mode 100644 index 00000000000000..7fe9e81a7e6ff2 --- /dev/null +++ b/patches.at91/0112-video-atmelfb-refactor-start-stop.patch @@ -0,0 +1,196 @@ +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 + diff --git a/patches.at91/0113-video-atmelfb-refactor-isr.patch b/patches.at91/0113-video-atmelfb-refactor-isr.patch new file mode 100644 index 00000000000000..8601fec22aa699 --- /dev/null +++ b/patches.at91/0113-video-atmelfb-refactor-isr.patch @@ -0,0 +1,154 @@ +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 + diff --git a/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch b/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch new file mode 100644 index 00000000000000..95fb0aa4a6457d --- /dev/null +++ b/patches.at91/0114-video-atmelfb-refactor-backlight-routines.patch @@ -0,0 +1,256 @@ +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 + diff --git a/patches.at91/0115-video-atmelfb-refactor-dma_update.patch b/patches.at91/0115-video-atmelfb-refactor-dma_update.patch new file mode 100644 index 00000000000000..e4f46be359de0a --- /dev/null +++ b/patches.at91/0115-video-atmelfb-refactor-dma_update.patch @@ -0,0 +1,211 @@ +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 + diff --git a/patches.at91/0116-video-atmelfb-refactor-LUT.patch b/patches.at91/0116-video-atmelfb-refactor-LUT.patch new file mode 100644 index 00000000000000..e8c12dea2ab83d --- /dev/null +++ b/patches.at91/0116-video-atmelfb-refactor-LUT.patch @@ -0,0 +1,80 @@ +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 + diff --git a/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch b/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch new file mode 100644 index 00000000000000..ed6800e75428da --- /dev/null +++ b/patches.at91/0117-video-atmelfb-refactor-limit_screeninfo.patch @@ -0,0 +1,92 @@ +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 + diff --git a/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch b/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch new file mode 100644 index 00000000000000..031e89fff7c0a3 --- /dev/null +++ b/patches.at91/0118-arm-at91-refactor-lcdc-includes.patch @@ -0,0 +1,804 @@ +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 + diff --git a/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch b/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch new file mode 100644 index 00000000000000..72eb3a079a7243 --- /dev/null +++ b/patches.at91/0119-video-atmel_hlcdfb-add-new-driver.patch @@ -0,0 +1,606 @@ +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 + diff --git a/patches.at91/0120-WIP-add-clut-resource.patch b/patches.at91/0120-WIP-add-clut-resource.patch new file mode 100644 index 00000000000000..0cee03c10be08d --- /dev/null +++ b/patches.at91/0120-WIP-add-clut-resource.patch @@ -0,0 +1,167 @@ +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 + diff --git a/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch b/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch new file mode 100644 index 00000000000000..e2a279bc687d6e --- /dev/null +++ b/patches.at91/0121-video-atmel_lcdfb-add-error-msg-when-out-of-memory.patch @@ -0,0 +1,33 @@ +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 + diff --git a/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch b/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch new file mode 100644 index 00000000000000..f8311916d7d182 --- /dev/null +++ b/patches.at91/0122-video-atmel_lcdfb-HLCD-modifications.patch @@ -0,0 +1,238 @@ +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 + diff --git a/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch b/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch new file mode 100644 index 00000000000000..aad35a8cab5ed2 --- /dev/null +++ b/patches.at91/0123-atmel_lcdfb-change-pixel-clock-ratio-calculation.patch @@ -0,0 +1,31 @@ +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 + diff --git a/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch b/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch new file mode 100644 index 00000000000000..0ec35eef617c46 --- /dev/null +++ b/patches.at91/0124-media-at91sam9x5-video-new-driver-for-the-high-end-o.patch @@ -0,0 +1,1498 @@ +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 + diff --git a/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch b/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch new file mode 100644 index 00000000000000..6051fc3303766b --- /dev/null +++ b/patches.at91/0125-video-atmel_lcdfb-protect-bl_power-with-CONFIG_BACKL.patch @@ -0,0 +1,112 @@ +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 + diff --git a/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch b/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch new file mode 100644 index 00000000000000..28b3ae3463c365 --- /dev/null +++ b/patches.at91/0126-ARM-at91-9x5-modify-consistent-DMA-size.patch @@ -0,0 +1,27 @@ +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 + diff --git a/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch b/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch new file mode 100644 index 00000000000000..73d0832e574e20 --- /dev/null +++ b/patches.at91/0127-video-atmel_lcdfb-adapt-to-all-IP-configurations.patch @@ -0,0 +1,63 @@ +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 + diff --git a/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch b/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch new file mode 100644 index 00000000000000..1ab43917919d56 --- /dev/null +++ b/patches.at91/0128-media-at91sam9x5-video-cleanup-modifications.patch @@ -0,0 +1,100 @@ +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 + diff --git a/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch b/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch new file mode 100644 index 00000000000000..81ae75b4bbf6a5 --- /dev/null +++ b/patches.at91/0129-media-at91sam9x5-video-align-DMA-descriptors-on-64-b.patch @@ -0,0 +1,134 @@ +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 + diff --git a/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch b/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch new file mode 100644 index 00000000000000..496f8567b42dcc --- /dev/null +++ b/patches.at91/0130-media-at91sam9x5-video-change-scaling-factor-calcula.patch @@ -0,0 +1,76 @@ +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 + diff --git a/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch b/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch new file mode 100644 index 00000000000000..97c546f872a985 --- /dev/null +++ b/patches.at91/0131-media-at91sam9x5-video-add-device-tree-support.patch @@ -0,0 +1,102 @@ +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 + diff --git a/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch b/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch new file mode 100644 index 00000000000000..51e04c6ab858a9 --- /dev/null +++ b/patches.at91/0132-ARM-at91-video-Atmel-HLCD-is-only-selected-by-newer-.patch @@ -0,0 +1,59 @@ +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 + diff --git a/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch b/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch new file mode 100644 index 00000000000000..cf0ad036e3099c --- /dev/null +++ b/patches.at91/0133-mmc-atmel-mci-the-r-w-proof-capability-lack-was-not-.patch @@ -0,0 +1,208 @@ +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 + diff --git a/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch b/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch new file mode 100644 index 00000000000000..b05b19e9bfd16d --- /dev/null +++ b/patches.at91/0134-mmc-atmel-mci-change-the-state-machine-for-compatibi.patch @@ -0,0 +1,469 @@ +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 + diff --git a/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch b/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch new file mode 100644 index 00000000000000..2ebd933ba7e085 --- /dev/null +++ b/patches.at91/0135-mmc-atmel-mci-add-support-for-version-lower-than-v2x.patch @@ -0,0 +1,189 @@ +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 + diff --git a/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch b/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch new file mode 100644 index 00000000000000..f3108718390678 --- /dev/null +++ b/patches.at91/0136-mmc-atmel-mci-add-debug-logs.patch @@ -0,0 +1,250 @@ +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 + diff --git a/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch b/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch new file mode 100644 index 00000000000000..6963d4f412ae5c --- /dev/null +++ b/patches.at91/0137-mmc-atmel-mci-fix-data-timeout-issue.patch @@ -0,0 +1,39 @@ +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 + diff --git a/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch b/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch new file mode 100644 index 00000000000000..30d19734e188eb --- /dev/null +++ b/patches.at91/0138-ARM-at91-add-atmel-mci-support-for-chips-and-boards-.patch @@ -0,0 +1,1554 @@ +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 + diff --git a/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch b/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch new file mode 100644 index 00000000000000..520ada50fc6298 --- /dev/null +++ b/patches.at91/0139-ARM-at91-defconfig-change-the-MCI-driver-to-use-in-d.patch @@ -0,0 +1,140 @@ +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 + diff --git a/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch b/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch new file mode 100644 index 00000000000000..4eba7949f7b48a --- /dev/null +++ b/patches.at91/0140-mmc-atmel-mci-fix-burst-chunk-size-modification.patch @@ -0,0 +1,75 @@ +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 + diff --git a/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch b/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch new file mode 100644 index 00000000000000..ac074187dc919c --- /dev/null +++ b/patches.at91/0141-mmc-atmel-mci-add-device-tree-support.patch @@ -0,0 +1,212 @@ +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 + diff --git a/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch b/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch new file mode 100644 index 00000000000000..c068b20389ffa2 --- /dev/null +++ b/patches.at91/0142-ARM-at91-add-clocks-for-DT-entries.patch @@ -0,0 +1,83 @@ +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 + diff --git a/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch b/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch new file mode 100644 index 00000000000000..bb912527fea773 --- /dev/null +++ b/patches.at91/0143-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch @@ -0,0 +1,152 @@ +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 + diff --git a/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch b/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch new file mode 100644 index 00000000000000..0a6fc2bc7a9104 --- /dev/null +++ b/patches.at91/0144-ARM-dts-add-nodes-for-atmel-hsmci-controllers-for-at.patch @@ -0,0 +1,163 @@ +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 + diff --git a/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch b/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch new file mode 100644 index 00000000000000..d65baa1e50f304 --- /dev/null +++ b/patches.at91/0145-mmc-atmel-mci-remove-not-needed-DMA-capability-test.patch @@ -0,0 +1,32 @@ +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 + diff --git a/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch b/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch new file mode 100644 index 00000000000000..a995d815741207 --- /dev/null +++ b/patches.at91/0146-ARM-at91-atmel-mci-remove-unused-setup_dma_addr-macr.patch @@ -0,0 +1,39 @@ +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 + diff --git a/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch b/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch new file mode 100644 index 00000000000000..f16fcf81625c44 --- /dev/null +++ b/patches.at91/0147-mmc-atmel-mci-remove-the-need-for-CONFIG_MMC_ATMELMC.patch @@ -0,0 +1,57 @@ +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 + diff --git a/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch b/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch new file mode 100644 index 00000000000000..d1bb11b17c0705 --- /dev/null +++ b/patches.at91/0148-ARM-dts-fix-add-mmc-irq-priority.patch @@ -0,0 +1,109 @@ +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 + diff --git a/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch b/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch new file mode 100644 index 00000000000000..61f22aeb84b565 --- /dev/null +++ b/patches.at91/0149-mmc-atmel-mci-support-8-bit-buswidth.patch @@ -0,0 +1,32 @@ +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 + diff --git a/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch b/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch new file mode 100644 index 00000000000000..d124a4651dbfdd --- /dev/null +++ b/patches.at91/0150-mmc-atmel-mci-fix-incorrect-setting-of-host-data-to-.patch @@ -0,0 +1,40 @@ +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 + diff --git a/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch b/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch new file mode 100644 index 00000000000000..2518b687566835 --- /dev/null +++ b/patches.at91/0151-mmc-block-fix-the-data-timeout-issue-with-ACMD22.patch @@ -0,0 +1,71 @@ +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 + diff --git a/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch b/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch new file mode 100644 index 00000000000000..e848423656839c --- /dev/null +++ b/patches.at91/0152-mmc-atmel-mci-modify-CLKDIV-displaying-in-debugfs.patch @@ -0,0 +1,42 @@ +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 + diff --git a/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch b/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch new file mode 100644 index 00000000000000..362ec2a042e578 --- /dev/null +++ b/patches.at91/0153-mmc-atmel-mci-increase-dma-threshold.patch @@ -0,0 +1,31 @@ +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 + diff --git a/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch b/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch new file mode 100644 index 00000000000000..32ca75a4c78f80 --- /dev/null +++ b/patches.at91/0154-mmc-atmel-mci-not-busy-flag-has-also-to-be-used-for-.patch @@ -0,0 +1,56 @@ +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 + diff --git a/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch b/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch new file mode 100644 index 00000000000000..bf54a48103a57f --- /dev/null +++ b/patches.at91/0155-Replace-clk_lookup.con_id-with-clk_lookup.dev_id-ent.patch @@ -0,0 +1,116 @@ +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 + diff --git a/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch b/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch new file mode 100644 index 00000000000000..6344648882d190 --- /dev/null +++ b/patches.at91/0156-i2c-at91-remove-old-polling-driver.patch @@ -0,0 +1,432 @@ +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 + diff --git a/patches.at91/0157-i2c-at91-add-new-driver.patch b/patches.at91/0157-i2c-at91-add-new-driver.patch new file mode 100644 index 00000000000000..b2590271424a38 --- /dev/null +++ b/patches.at91/0157-i2c-at91-add-new-driver.patch @@ -0,0 +1,774 @@ +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"); diff --git a/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch b/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch new file mode 100644 index 00000000000000..1bab30a731353e --- /dev/null +++ b/patches.at91/0158-arm-at91-G45-TWI-remove-open-drain-setting-for-twi-f.patch @@ -0,0 +1,42 @@ +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 + diff --git a/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch b/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch new file mode 100644 index 00000000000000..54fa4e23231e4f --- /dev/null +++ b/patches.at91/0159-ARM-at91-do-not-configure-at91sam9g10-twi-pio-as-ope.patch @@ -0,0 +1,43 @@ +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 + diff --git a/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch b/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch new file mode 100644 index 00000000000000..da445e204b00e0 --- /dev/null +++ b/patches.at91/0160-i2c-at91-add-dt-support-to-i2c-at91.patch @@ -0,0 +1,149 @@ +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 + diff --git a/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch b/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch new file mode 100644 index 00000000000000..56157945cb8440 --- /dev/null +++ b/patches.at91/0161-ARM-at91-add-clocks-for-I2C-DT-entries.patch @@ -0,0 +1,89 @@ +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 + diff --git a/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch b/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch new file mode 100644 index 00000000000000..e9e18e418c3ff4 --- /dev/null +++ b/patches.at91/0162-ARM-dts-add-twi-nodes-for-atmel-SoCs.patch @@ -0,0 +1,220 @@ +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 + diff --git a/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch b/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch new file mode 100644 index 00000000000000..7272e41efaecc5 --- /dev/null +++ b/patches.at91/0163-ARM-dts-add-twi-nodes-for-atmel-boards.patch @@ -0,0 +1,86 @@ +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 + diff --git a/patches.at91/0164-i2c-at91-add-dma-support.patch b/patches.at91/0164-i2c-at91-add-dma-support.patch new file mode 100644 index 00000000000000..1c81f5e4db4835 --- /dev/null +++ b/patches.at91/0164-i2c-at91-add-dma-support.patch @@ -0,0 +1,504 @@ +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 + diff --git a/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch b/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch new file mode 100644 index 00000000000000..4a548a12419d48 --- /dev/null +++ b/patches.at91/0165-i2c-at91-backport-fix-for-devm_clk_get.patch @@ -0,0 +1,45 @@ +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 + diff --git a/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch b/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch new file mode 100644 index 00000000000000..fe5b5721d1ae36 --- /dev/null +++ b/patches.at91/0166-i2c-at91-add-dt-property-for-DMA-configuration.patch @@ -0,0 +1,141 @@ +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 + diff --git a/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch b/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch new file mode 100644 index 00000000000000..ddb7adc15f9c6a --- /dev/null +++ b/patches.at91/0167-ARM-at91-add-MCI-DMA-for-at91sam9x5.dtsi.patch @@ -0,0 +1,35 @@ +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 + diff --git a/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch b/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch new file mode 100644 index 00000000000000..7143451676f391 --- /dev/null +++ b/patches.at91/0168-ARM-at91-add-i2c-and-qt1070-pin-muxing.patch @@ -0,0 +1,34 @@ +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 + diff --git a/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch b/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch new file mode 100644 index 00000000000000..ee7f27824d69fc --- /dev/null +++ b/patches.at91/0169-AT91-board-dt-add-mci-pinmux-for-9x5.patch @@ -0,0 +1,48 @@ +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 + diff --git a/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch b/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch new file mode 100644 index 00000000000000..5699167b8a1da4 --- /dev/null +++ b/patches.at91/0170-mtd-atmel_nand-add-4k-page-nand-flash-support-for-PM.patch @@ -0,0 +1,32 @@ +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 + diff --git a/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch b/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch new file mode 100644 index 00000000000000..4f9475ad06ce76 --- /dev/null +++ b/patches.at91/0171-mtd-atmel_nand-incease-the-chip_delay-time-tR-for-su.patch @@ -0,0 +1,30 @@ +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 + diff --git a/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch b/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch new file mode 100644 index 00000000000000..594b3c1165ca7c --- /dev/null +++ b/patches.at91/0172-at91-9x5-add-DT-parameters-to-enable-PMECC.patch @@ -0,0 +1,46 @@ +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 + diff --git a/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch b/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch new file mode 100644 index 00000000000000..e1f272c6dfd826 --- /dev/null +++ b/patches.at91/0173-ARM-at91-split-9x5-dts-dtsi-in-a-common-set-of-perip.patch @@ -0,0 +1,124 @@ +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 + diff --git a/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch b/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch new file mode 100644 index 00000000000000..e0894417481942 --- /dev/null +++ b/patches.at91/0174-ARM-at91-9x5-family-add-at91sam9x25ek.dts.patch @@ -0,0 +1,76 @@ +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 + diff --git a/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch b/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch new file mode 100644 index 00000000000000..867d9fb47688f8 --- /dev/null +++ b/patches.at91/0175-ARM-at91-add-new-at91sam9g35ek.dts.patch @@ -0,0 +1,109 @@ +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 + diff --git a/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch b/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch new file mode 100644 index 00000000000000..cd8efe71f2a230 --- /dev/null +++ b/patches.at91/0176-ARM-at91-add-pinmux-for-9x5-LCD.patch @@ -0,0 +1,143 @@ +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 + diff --git a/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch b/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch new file mode 100644 index 00000000000000..949486e352d66f --- /dev/null +++ b/patches.at91/0177-ARM-at91-add-LCD-HEO-DT-entry-for-at91sam9x5.patch @@ -0,0 +1,49 @@ +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 + diff --git a/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch b/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch new file mode 100644 index 00000000000000..6f92f29532c65e --- /dev/null +++ b/patches.at91/0178-AT91SAM9G45-add-crypto-peripherals.patch @@ -0,0 +1,248 @@ +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 + diff --git a/patches.at91/0179-crypto-add-Atmel-AES-driver.patch b/patches.at91/0179-crypto-add-Atmel-AES-driver.patch new file mode 100644 index 00000000000000..aee86623dac40c --- /dev/null +++ b/patches.at91/0179-crypto-add-Atmel-AES-driver.patch @@ -0,0 +1,1369 @@ +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 + diff --git a/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch b/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch new file mode 100644 index 00000000000000..ea752b963ea19e --- /dev/null +++ b/patches.at91/0180-crypto-add-Atmel-DES-TDES-driver.patch @@ -0,0 +1,1374 @@ +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 + diff --git a/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch b/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch new file mode 100644 index 00000000000000..56b9a474fa4eaf --- /dev/null +++ b/patches.at91/0181-crypto-add-Atmel-SHA1-SHA256-driver.patch @@ -0,0 +1,1226 @@ +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 + diff --git a/patches.at91/0182-crypto-add-atmel-test-driver.patch b/patches.at91/0182-crypto-add-atmel-test-driver.patch new file mode 100644 index 00000000000000..7080cbc8bfe663 --- /dev/null +++ b/patches.at91/0182-crypto-add-atmel-test-driver.patch @@ -0,0 +1,502 @@ +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 + diff --git a/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch b/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch new file mode 100644 index 00000000000000..d267bb0c8b6d30 --- /dev/null +++ b/patches.at91/0183-crypto-add-new-tests-to-tcrypt.patch @@ -0,0 +1,112 @@ +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 + diff --git a/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch b/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch new file mode 100644 index 00000000000000..219273142a74c0 --- /dev/null +++ b/patches.at91/0184-AT91SAM9G45-crypto-same-platform-data-header-for-all.patch @@ -0,0 +1,54 @@ +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 + diff --git a/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch b/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch new file mode 100644 index 00000000000000..ddaee7925cdad8 --- /dev/null +++ b/patches.at91/0185-AT91SAM9G45-dts-add-crypto-peripherals.patch @@ -0,0 +1,65 @@ +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 + diff --git a/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch b/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch new file mode 100644 index 00000000000000..57fb37802ddaa6 --- /dev/null +++ b/patches.at91/0186-AT91SAM9N12-add-crypto-peripherals.patch @@ -0,0 +1,90 @@ +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 + diff --git a/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch b/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch new file mode 100644 index 00000000000000..912398c1a600bf --- /dev/null +++ b/patches.at91/0187-AT91SAM9N12-dts-add-crypto-peripherals.patch @@ -0,0 +1,64 @@ +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 + diff --git a/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch b/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch new file mode 100644 index 00000000000000..a7878b662f12fd --- /dev/null +++ b/patches.at91/0188-crypto-Atmel-AES-add-device-tree-support.patch @@ -0,0 +1,1070 @@ +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 + diff --git a/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch b/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch new file mode 100644 index 00000000000000..217ea3b27e17f7 --- /dev/null +++ b/patches.at91/0189-crypto-Atmel-TDES-add-device-tree-support.patch @@ -0,0 +1,932 @@ +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 + diff --git a/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch b/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch new file mode 100644 index 00000000000000..d1db361f3bfaf8 --- /dev/null +++ b/patches.at91/0190-crypto-Atmel-SHA-add-device-tree-support.patch @@ -0,0 +1,1123 @@ +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 + diff --git a/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch b/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch new file mode 100644 index 00000000000000..2184541b65f28d --- /dev/null +++ b/patches.at91/0191-crypto-Atmel-Test-add-SHA224-SHA384-and-SHA512-suppo.patch @@ -0,0 +1,81 @@ +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 + diff --git a/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch b/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch new file mode 100644 index 00000000000000..e6c070d8a77dcb --- /dev/null +++ b/patches.at91/0192-pinctrl-core-device-tree-mapping-table-parsing-suppo.patch @@ -0,0 +1,537 @@ +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 + diff --git a/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch b/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch new file mode 100644 index 00000000000000..2a91bb276917fc --- /dev/null +++ b/patches.at91/0193-pinctrl-fix-build-when-CONFIG_OF-CONFIG_PINCTRL.patch @@ -0,0 +1,35 @@ +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 + diff --git a/patches.at91/0194-pinctrl-fix-dangling-comment.patch b/patches.at91/0194-pinctrl-fix-dangling-comment.patch new file mode 100644 index 00000000000000..af511327d20267 --- /dev/null +++ b/patches.at91/0194-pinctrl-fix-dangling-comment.patch @@ -0,0 +1,29 @@ +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 + diff --git a/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch b/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch new file mode 100644 index 00000000000000..fab78ce91b335c --- /dev/null +++ b/patches.at91/0195-pinctrl-implement-devm_pinctrl_get-put.patch @@ -0,0 +1,308 @@ +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 + diff --git a/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch b/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch new file mode 100644 index 00000000000000..e3fcb3b56a10b2 --- /dev/null +++ b/patches.at91/0196-pinctrl-add-pinctrl_provide_dummies-interface-for-pl.patch @@ -0,0 +1,115 @@ +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 + diff --git a/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch b/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch new file mode 100644 index 00000000000000..fc5a9090200fd6 --- /dev/null +++ b/patches.at91/0197-pinctrl-remove-pinctrl_remove_gpio_range.patch @@ -0,0 +1,103 @@ +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 + diff --git a/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch b/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch new file mode 100644 index 00000000000000..ab6bf0ed17326a --- /dev/null +++ b/patches.at91/0198-pinctrl-add-pinctrl_add_gpio_ranges-function.patch @@ -0,0 +1,55 @@ +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 + diff --git a/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch b/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch new file mode 100644 index 00000000000000..1776c362f2a99b --- /dev/null +++ b/patches.at91/0199-pinctrl-support-gpio-request-deferred-probing.patch @@ -0,0 +1,51 @@ +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 + diff --git a/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch b/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch new file mode 100644 index 00000000000000..5d7c39c308249e --- /dev/null +++ b/patches.at91/0200-pinctrl-propagate-map-validation-errors.patch @@ -0,0 +1,38 @@ +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 + diff --git a/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch b/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch new file mode 100644 index 00000000000000..f30229d20be909 --- /dev/null +++ b/patches.at91/0201-pinctrl-mark-non-EXPERIMENTAL.patch @@ -0,0 +1,30 @@ +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 + diff --git a/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch b/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch new file mode 100644 index 00000000000000..a97355b89ac48e --- /dev/null +++ b/patches.at91/0202-pinctrl-implement-pinctrl-deferred-probing.patch @@ -0,0 +1,82 @@ +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 + diff --git a/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch b/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch new file mode 100644 index 00000000000000..beed95932c6ad9 --- /dev/null +++ b/patches.at91/0203-pinctrl-replace-list_-with-get_-_count.patch @@ -0,0 +1,634 @@ +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 + diff --git a/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch b/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch new file mode 100644 index 00000000000000..d5517298ba2e87 --- /dev/null +++ b/patches.at91/0204-pinctrl-show-pin-name-when-request-pins.patch @@ -0,0 +1,40 @@ +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 + diff --git a/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch b/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch new file mode 100644 index 00000000000000..dbf7a4cbe7812a --- /dev/null +++ b/patches.at91/0205-pinctrl-show-pin-name-for-pingroups-in-sysfs.patch @@ -0,0 +1,106 @@ +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 + diff --git a/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch b/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch new file mode 100644 index 00000000000000..a388df0d017af8 --- /dev/null +++ b/patches.at91/0206-dt-add-of_get_child_count-helper-function.patch @@ -0,0 +1,49 @@ +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) + { diff --git a/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch b/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch new file mode 100644 index 00000000000000..d76e21996c4bf7 --- /dev/null +++ b/patches.at91/0207-arm-at91-use-macro-to-declare-soc-boot-data.patch @@ -0,0 +1,191 @@ +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 + diff --git a/patches.at91/0208-ARM-at91-gpio-implement-request.patch b/patches.at91/0208-ARM-at91-gpio-implement-request.patch new file mode 100644 index 00000000000000..076f49b820badb --- /dev/null +++ b/patches.at91/0208-ARM-at91-gpio-implement-request.patch @@ -0,0 +1,58 @@ +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 + diff --git a/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch b/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch new file mode 100644 index 00000000000000..ef367698120efa --- /dev/null +++ b/patches.at91/0209-at91-regroup-gpio-and-pinctrl-under-the-same-ranges.patch @@ -0,0 +1,505 @@ +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 + diff --git a/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch b/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch new file mode 100644 index 00000000000000..6a5f3c16513fa5 --- /dev/null +++ b/patches.at91/0210-arm-at91-at91sam9x5-fix-gpio-number-per-bank.patch @@ -0,0 +1,166 @@ +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 + diff --git a/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch b/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch new file mode 100644 index 00000000000000..0b7c5df3dd94f4 --- /dev/null +++ b/patches.at91/0211-ARM-at91-add-dummies-pinctrl-for-non-dt-platform.patch @@ -0,0 +1,34 @@ +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 + diff --git a/patches.at91/0212-ARM-at91-add-pinctrl-support.patch b/patches.at91/0212-ARM-at91-add-pinctrl-support.patch new file mode 100644 index 00000000000000..9db9121984947b --- /dev/null +++ b/patches.at91/0212-ARM-at91-add-pinctrl-support.patch @@ -0,0 +1,1872 @@ +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 + diff --git a/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch b/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch new file mode 100644 index 00000000000000..0e84ffca60ce92 --- /dev/null +++ b/patches.at91/0213-arm-at91-dt-at91sam9-add-pinctrl-support.patch @@ -0,0 +1,405 @@ +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 + diff --git a/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch b/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch new file mode 100644 index 00000000000000..c0bbc438a91bb0 --- /dev/null +++ b/patches.at91/0214-tty-atmel_serial-add-pinctrl-support.patch @@ -0,0 +1,49 @@ +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 + diff --git a/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch b/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch new file mode 100644 index 00000000000000..4cfbed0ae4d573 --- /dev/null +++ b/patches.at91/0215-arm-at91-dt-sam9m10g45ek-use-rts-cts-pinctrl-group-f.patch @@ -0,0 +1,27 @@ +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 + diff --git a/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch b/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch new file mode 100644 index 00000000000000..19082b15459a48 --- /dev/null +++ b/patches.at91/0216-arm-at91-dt-sam9263ek-use-rts-cts-pinctrl-group-for-.patch @@ -0,0 +1,27 @@ +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 + diff --git a/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch b/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch new file mode 100644 index 00000000000000..c1f8c4c922c74b --- /dev/null +++ b/patches.at91/0217-arm-at91-dt-sam9g20ek-use-rts-cts-dtr-dsr-dcd-ri-pin.patch @@ -0,0 +1,33 @@ +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 + diff --git a/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch b/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch new file mode 100644 index 00000000000000..88a7d8f648baee --- /dev/null +++ b/patches.at91/0218-MTD-atmel-nand-fix-gpio-missing-request.patch @@ -0,0 +1,86 @@ +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 + diff --git a/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch b/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch new file mode 100644 index 00000000000000..eff83224f66176 --- /dev/null +++ b/patches.at91/0219-arm-at91-dt-at91sam9-add-nand-pinctrl-support.patch @@ -0,0 +1,158 @@ +From e624846db6e105762542cb6c09276609a7932ea3 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 + +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++ + arch/arm/boot/dts/at91sam9263.dtsi | 10 ++++++++++ + arch/arm/boot/dts/at91sam9g45.dtsi | 10 ++++++++++ + arch/arm/boot/dts/at91sam9n12.dtsi | 10 ++++++++++ + arch/arm/boot/dts/at91sam9x5.dtsi | 10 ++++++++++ + 5 files changed, 50 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi +index 3654ace..2dd4e0b 100644 +--- a/arch/arm/boot/dts/at91sam9260.dtsi ++++ b/arch/arm/boot/dts/at91sam9260.dtsi +@@ -113,6 +113,14 @@ + + /* shared pinctrl settings */ + ++ nand { ++ pinctrl_nand: nand-0 { ++ atmel,pins = ++ <2 13 0x0 0x1 /* PC13 gpio RDY pin pull_up */ ++ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */ ++ }; ++ }; ++ + pioA: gpio@fffff400 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; +@@ -247,6 +255,8 @@ + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioC 13 0 + &pioC 14 0 + 0 +diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi +index d7f416d..5aa07e4 100644 +--- a/arch/arm/boot/dts/at91sam9263.dtsi ++++ b/arch/arm/boot/dts/at91sam9263.dtsi +@@ -106,6 +106,14 @@ + + /* shared pinctrl settings */ + ++ nand { ++ pinctrl_nand: nand-0 { ++ atmel,pins = ++ <0 22 0x0 0x1 /* PA22 gpio RDY pin pull_up*/ ++ 3 15 0x0 0x1>; /* PD15 gpio enable pin pull_up */ ++ }; ++ }; ++ + pioA: gpio@fffff200 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff200 0x200>; +@@ -242,6 +250,8 @@ + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioA 22 0 + &pioD 15 0 + 0 +diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi +index e2fa457..f08b8c2 100644 +--- a/arch/arm/boot/dts/at91sam9g45.dtsi ++++ b/arch/arm/boot/dts/at91sam9g45.dtsi +@@ -126,6 +126,14 @@ + + /* shared pinctrl settings */ + ++ nand { ++ pinctrl_nand: nand-0 { ++ atmel,pins = ++ <2 8 0x0 0x1 /* PC8 gpio RDY pin pull_up*/ ++ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */ ++ }; ++ }; ++ + pioA: gpio@fffff200 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff200 0x200>; +@@ -297,6 +305,8 @@ + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioC 8 0 + &pioC 14 0 + 0 +diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi +index fc451f9..ec9b573 100644 +--- a/arch/arm/boot/dts/at91sam9n12.dtsi ++++ b/arch/arm/boot/dts/at91sam9n12.dtsi +@@ -128,6 +128,14 @@ + + /* shared pinctrl settings */ + ++ nand { ++ pinctrl_nand: nand-0 { ++ atmel,pins = ++ <3 5 0x0 0x1 /* PD5 gpio RDY pin pull_up*/ ++ 3 4 0x0 0x1>; /* PD4 gpio enable pin pull_up */ ++ }; ++ }; ++ + pioA: gpio@fffff400 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; +@@ -265,6 +273,8 @@ + >; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioD 5 0 + &pioD 4 0 + 0 +diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi +index 84baa90..28e053a 100644 +--- a/arch/arm/boot/dts/at91sam9x5.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5.dtsi +@@ -129,6 +129,14 @@ + + /* shared pinctrl settings */ + ++ nand { ++ pinctrl_nand: nand-0 { ++ atmel,pins = ++ <3 4 0x0 0x1 /* PD5 gpio RDY pin pull_up */ ++ 3 5 0x0 0x1>; /* PD4 gpio enable pin pull_up */ ++ }; ++ }; ++ + pioA: gpio@fffff400 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; +@@ -305,6 +313,8 @@ + atmel,pmecc-lookup-table-offset = <0x8000 0x10000>; + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_nand>; + gpios = <&pioD 5 0 + &pioD 4 0 + 0 +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch b/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch new file mode 100644 index 00000000000000..92e48d491d4aed --- /dev/null +++ b/patches.at91/0220-MTD-atmel_nand-add-pinctrl-consumer-support.patch @@ -0,0 +1,50 @@ +From 38bb2e5fb1310a6e4f4a6750037dc5a824c3cfdc 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 + +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> +Acked-by: Linus Walleij <linus.walleij@linaro.org> +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/mtd/nand/atmel_nand.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 3978336..625898e 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -41,6 +41,7 @@ + #include <linux/gpio.h> + #include <linux/io.h> + #include <linux/platform_data/atmel.h> ++#include <linux/pinctrl/consumer.h> + + #include <mach/cpu.h> + +@@ -1367,6 +1368,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + struct resource *mem; + struct mtd_part_parser_data ppdata = {}; + int res; ++ struct pinctrl *pinctrl; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { +@@ -1411,6 +1413,13 @@ 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; + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(host->dev, "Failed to request pinctrl\n"); ++ res = PTR_ERR(pinctrl); ++ goto err_ecc_ioremap; ++ } ++ + if (gpio_is_valid(host->board.rdy_pin)) { + res = devm_gpio_request(&pdev->dev, + host->board.rdy_pin, "nand_rdy"); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch b/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch new file mode 100644 index 00000000000000..d21da117a93e60 --- /dev/null +++ b/patches.at91/0221-pinctrl-at91-add-deglitch-debounce-pull-down-and-sch.patch @@ -0,0 +1,194 @@ +From 07549383aa7e1b5c99ca47f9bd75600ba1b159fc 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 + mux option support + +add : + set_deglitch: enable/disable deglitch + set_debounce: enable/disable debounce + set_pulldown: enable/disable pulldown + disable_schmitt_trig: disable schmitt trigger + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/pinctrl/pinctrl-at91.c | 110 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 110 insertions(+) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index 9c0fe11..73f7245 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -60,6 +60,12 @@ static int gpio_banks; + + #define PULL_UP (0 << 1) + #define MULTI_DRIVE (1 << 1) ++#define DEGLITCH (1 << 2) ++#define PULL_DOWN (1 << 3) ++#define DIS_SCHMIT (1 << 4) ++#define DEBOUNCE (1 << 16) ++#define DEBOUNCE_VAL_SHIFT 17 ++#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) + + /** + * struct at91_pmx_func - describes AT91 pinmux functions +@@ -123,6 +129,14 @@ struct at91_pin_group { + * @mux_B_periph: mux as periph B + * @mux_C_periph: mux as periph C + * @mux_D_periph: mux as periph D ++ * @get_deglitch: get deglitch status ++ * @set_deglitch: enable/disable deglitch ++ * @get_debounce: get debounce status ++ * @set_debounce: enable/disable debounce ++ * @get_pulldown: get pulldown status ++ * @set_pulldown: enable/disable pulldown ++ * @get_schmitt_trig: get schmitt trigger status ++ * @disable_schmitt_trig: disable schmitt trigger + * @irq_type: return irq type + */ + struct at91_pinctrl_mux_ops { +@@ -131,6 +145,14 @@ struct at91_pinctrl_mux_ops { + 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); ++ bool (*get_deglitch)(void __iomem *pio, unsigned pin); ++ void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on); ++ bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); ++ void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div); ++ bool (*get_pulldown)(void __iomem *pio, unsigned pin); ++ void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on); ++ bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); ++ void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask); + /* irq */ + int (*irq_type)(struct irq_data *d, unsigned type); + }; +@@ -390,10 +412,70 @@ static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask) + return select + 1; + } + ++static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin) ++{ ++ return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1; ++} ++ ++static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) ++{ ++ __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); ++} ++ ++static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) ++{ ++ if (is_on) ++ __raw_writel(mask, pio + PIO_IFSCDR); ++ at91_mux_set_deglitch(pio, mask, is_on); ++} ++ ++static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div) ++{ ++ *div = __raw_readl(pio + PIO_SCDR); ++ ++ return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1; ++} ++ ++static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, ++ bool is_on, u32 div) ++{ ++ if (is_on) { ++ __raw_writel(mask, pio + PIO_IFSCER); ++ __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); ++ __raw_writel(mask, pio + PIO_IFER); ++ } else { ++ __raw_writel(mask, pio + PIO_IFDR); ++ } ++} ++ ++static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) ++{ ++ return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1; ++} ++ ++static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on) ++{ ++ /* Disable pull-up anyway */ ++ __raw_writel(mask, pio + PIO_PUDR); ++ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); ++} ++ ++static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask) ++{ ++ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); ++} ++ ++static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin) ++{ ++ return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1; ++} ++ + 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, ++ .get_deglitch = at91_mux_get_deglitch, ++ .set_deglitch = at91_mux_set_deglitch, + .irq_type = gpio_irq_type, + }; + +@@ -403,6 +485,14 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = { + .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, ++ .get_deglitch = at91_mux_get_deglitch, ++ .set_deglitch = at91_mux_pio3_set_deglitch, ++ .get_debounce = at91_mux_pio3_get_debounce, ++ .set_debounce = at91_mux_pio3_set_debounce, ++ .get_pulldown = at91_mux_pio3_get_pulldown, ++ .set_pulldown = at91_mux_pio3_set_pulldown, ++ .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, ++ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .irq_type = alt_gpio_irq_type, + }; + +@@ -628,6 +718,7 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + void __iomem *pio; + unsigned pin; ++ int div; + + 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)); +@@ -639,6 +730,15 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, + if (at91_mux_get_pullup(pio, pin)) + *config |= PULL_UP; + ++ if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin)) ++ *config |= DEGLITCH; ++ if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div)) ++ *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT); ++ if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin)) ++ *config |= PULL_DOWN; ++ if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin)) ++ *config |= DIS_SCHMIT; ++ + return 0; + } + +@@ -655,6 +755,16 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, + + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); ++ if (info->ops->set_deglitch) ++ info->ops->set_deglitch(pio, mask, config & DEGLITCH); ++ if (info->ops->set_debounce) ++ info->ops->set_debounce(pio, mask, DEBOUNCE, ++ (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); ++ if (info->ops->set_pulldown) ++ info->ops->set_pulldown(pio, mask, config & PULL_DOWN); ++ if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) ++ info->ops->disable_schmitt_trig(pio, mask); ++ + return 0; + } + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch b/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch new file mode 100644 index 00000000000000..25ec8466be9ff9 --- /dev/null +++ b/patches.at91/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch @@ -0,0 +1,50 @@ +From 9924801dfee9489e8df05d857df0d872a4f02193 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 + "err_ecc_ioremap" + +Add err_ecc_ioremap label to fix following errors: +---8<--- + CC drivers/mtd/nand/atmel_nand.o +drivers/mtd/nand/atmel_nand.c: In function 'atmel_nand_probe': +drivers/mtd/nand/atmel_nand.c:1423: error: label 'err_ecc_ioremap' used but not defined +make[3]: *** [drivers/mtd/nand/atmel_nand.o] Error 1 +make[2]: *** [drivers/mtd/nand] Error 2 +make[1]: *** [drivers/mtd] Error 2 +make: *** [drivers] Error 2 +--->8--- + +This error was introduced in b654a9a46fc2100b318050483f8c5b5d0f187303 (mtd: atmel nand: fix gpio missing request) + +Signed-off-by: Josh Wu <josh.wu@atmel.com> +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/mtd/nand/atmel_nand.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c +index 625898e..fadec27 100644 +--- a/drivers/mtd/nand/atmel_nand.c ++++ b/drivers/mtd/nand/atmel_nand.c +@@ -1398,7 +1398,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) + if (pdev->dev.of_node) { + res = atmel_of_init_port(host, pdev->dev.of_node); + if (res) +- goto err_nand_ioremap; ++ goto err_ecc_ioremap; + } else { + memcpy(&host->board, pdev->dev.platform_data, + sizeof(struct atmel_nand_data)); +@@ -1554,6 +1554,8 @@ err_scan_tail: + pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); + pmecc_data_free(host); + } ++ ++err_ecc_ioremap: + if (host->ecc) + iounmap(host->ecc); + if (host->pmerrloc_base) +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch b/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch new file mode 100644 index 00000000000000..883f4c0c75c91f --- /dev/null +++ b/patches.at91/0223-pinctrl-at91-fix-compatible-order.patch @@ -0,0 +1,39 @@ +From 31a329d0cb5502f8076601608f2591adccbda8b7 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 + +sam9x5 is newer than rm9200 + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +--- + drivers/pinctrl/pinctrl-at91.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index 73f7245..a26dcb3 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -930,8 +930,8 @@ static int __devinit at91_pinctrl_parse_functions(struct device_node *np, + } + + static struct of_device_id at91_pinctrl_of_match[] __devinitdata = { +- { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, + { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops }, ++ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, + { /* sentinel */ } + }; + +@@ -1441,8 +1441,8 @@ static void __devinit at91_gpio_probe_fixup(void) + } + + static struct of_device_id at91_gpio_of_match[] __devinitdata = { ++ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops }, + { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, +- { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, + { /* sentinel */ } + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch b/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch new file mode 100644 index 00000000000000..a24fc578442441 --- /dev/null +++ b/patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch @@ -0,0 +1,46 @@ +From 54090e0c3b619793d8058ceb1d717ea453f65893 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 + +we can not use readl/writel_relaxed for interrupts + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/pinctrl/pinctrl-at91.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index a26dcb3..605fffd 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -1213,7 +1213,7 @@ static void gpio_irq_mask(struct irq_data *d) + unsigned mask = 1 << d->hwirq; + + if (pio) +- writel_relaxed(mask, pio + PIO_IDR); ++ __raw_writel(mask, pio + PIO_IDR); + } + + static void gpio_irq_unmask(struct irq_data *d) +@@ -1223,7 +1223,7 @@ static void gpio_irq_unmask(struct irq_data *d) + unsigned mask = 1 << d->hwirq; + + if (pio) +- writel_relaxed(mask, pio + PIO_IER); ++ __raw_writel(mask, pio + PIO_IER); + } + + static int gpio_irq_type(struct irq_data *d, unsigned type) +@@ -1321,7 +1321,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) + * 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); ++ isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR); + if (!isr) { + if (!at91_gpio->next) + break; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0225-i2c-at91-add-pinctrl.patch b/patches.at91/0225-i2c-at91-add-pinctrl.patch new file mode 100644 index 00000000000000..3651777c3bab3c --- /dev/null +++ b/patches.at91/0225-i2c-at91-add-pinctrl.patch @@ -0,0 +1,46 @@ +From 15398d1b5861b197b75d85e9cfd4c2560ecc49de 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 + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +--- + drivers/i2c/busses/i2c-at91.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c +index c004b34..f471747 100644 +--- a/drivers/i2c/busses/i2c-at91.c ++++ b/drivers/i2c/busses/i2c-at91.c +@@ -30,6 +30,7 @@ + #include <linux/of_device.h> + #include <linux/of_i2c.h> + #include <linux/platform_device.h> ++#include <linux/pinctrl/consumer.h> + #include <linux/slab.h> + + #include <mach/at_hdmac.h> +@@ -767,6 +768,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) + struct resource *mem; + int rc; + u32 phy_addr; ++ struct pinctrl *pinctrl; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) +@@ -779,6 +781,12 @@ static int __devinit at91_twi_probe(struct platform_device *pdev) + return -ENODEV; + phy_addr = mem->start; + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(&pdev->dev, "Failed to request pinctrl\n"); ++ return PTR_ERR(pinctrl); ++ } ++ + dev->pdata = at91_twi_get_driver_data(pdev); + if (!dev->pdata) + return -ENODEV; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0226-media-atmel_isi-add-pinctrl.patch b/patches.at91/0226-media-atmel_isi-add-pinctrl.patch new file mode 100644 index 00000000000000..8c020fba78f9dc --- /dev/null +++ b/patches.at91/0226-media-atmel_isi-add-pinctrl.patch @@ -0,0 +1,46 @@ +From d7ab9be8967e1884bba0228ea65f2893b10b019e 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 + +Signed-off-by: Ludovic Desroches <ludovic.desroches@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 7a44df4..ef80695 100644 +--- a/drivers/media/video/atmel-isi.c ++++ b/drivers/media/video/atmel-isi.c +@@ -20,6 +20,7 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/platform_device.h> ++#include <linux/pinctrl/consumer.h> + #include <linux/slab.h> + + #include <media/atmel-isi.h> +@@ -949,6 +950,7 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct soc_camera_host *soc_host; + struct isi_platform_data *pdata; ++ struct pinctrl *pinctrl; + + pdata = dev->platform_data; + if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) { +@@ -961,6 +963,12 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) + if (!regs) + return -ENXIO; + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(&pdev->dev, "Failed to request pinctrl\n"); ++ return PTR_ERR(pinctrl); ++ } ++ + pclk = clk_get(&pdev->dev, "isi_clk"); + if (IS_ERR(pclk)) + return PTR_ERR(pclk); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0227-mmc-at91-add-pinctrl.patch b/patches.at91/0227-mmc-at91-add-pinctrl.patch new file mode 100644 index 00000000000000..d041d96767a116 --- /dev/null +++ b/patches.at91/0227-mmc-at91-add-pinctrl.patch @@ -0,0 +1,91 @@ +From 6d2ed0a1963bcf555e5cdc12035ae105a94da9cf 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 + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +--- + drivers/mmc/host/atmel-mci.c | 36 ++++++++++++++++++++++++++++++------ + 1 file changed, 30 insertions(+), 6 deletions(-) + +diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c +index 3d9c7b8..9739604 100644 +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -28,6 +28,7 @@ + #include <linux/slab.h> + #include <linux/stat.h> + #include <linux/types.h> ++#include <linux/pinctrl/consumer.h> + + #include <linux/mmc/host.h> + #include <linux/mmc/sdio.h> +@@ -2154,12 +2155,20 @@ static int __init atmci_init_slot(struct atmel_mci *host, + /* Assume card is present initially */ + set_bit(ATMCI_CARD_PRESENT, &slot->flags); + if (gpio_is_valid(slot->detect_pin)) { +- if (gpio_request(slot->detect_pin, "mmc_detect")) { +- dev_dbg(&mmc->class_dev, "no detect pin available\n"); ++ if (devm_gpio_request(&mmc->class_dev, slot->detect_pin, ++ "mmc_detect")) { ++ dev_dbg(&mmc->class_dev, "can't request detect pin\n"); + slot->detect_pin = -EBUSY; +- } else if (gpio_get_value(slot->detect_pin) ^ +- slot->detect_is_active_high) { +- clear_bit(ATMCI_CARD_PRESENT, &slot->flags); ++ } else { ++ if (gpio_direction_input(slot->detect_pin)) { ++ dev_err(&mmc->class_dev, ++ "can't set detect pin direction\n"); ++ devm_gpio_free(&mmc->class_dev, slot->detect_pin); ++ slot->detect_pin = -EBUSY; ++ } else if (gpio_get_value(slot->detect_pin) ^ ++ slot->detect_is_active_high) { ++ clear_bit(ATMCI_CARD_PRESENT, &slot->flags); ++ } + } + } + +@@ -2167,9 +2176,17 @@ static int __init atmci_init_slot(struct atmel_mci *host, + mmc->caps |= MMC_CAP_NEEDS_POLL; + + if (gpio_is_valid(slot->wp_pin)) { +- if (gpio_request(slot->wp_pin, "mmc_wp")) { ++ if (devm_gpio_request(&mmc->class_dev, slot->wp_pin, ++ "mmc_wp")) { + dev_dbg(&mmc->class_dev, "no WP pin available\n"); + slot->wp_pin = -EBUSY; ++ } else { ++ if (gpio_direction_output(slot->wp_pin, 0)) { ++ dev_err(&mmc->class_dev, ++ "can't set WP pin direction\n"); ++ devm_gpio_free(&mmc->class_dev, slot->wp_pin); ++ slot->wp_pin = -EBUSY; ++ } + } + } + +@@ -2339,6 +2356,7 @@ static int __init atmci_probe(struct platform_device *pdev) + unsigned int nr_slots; + int irq; + int ret; ++ struct pinctrl *pinctrl; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) +@@ -2352,6 +2370,12 @@ static int __init atmci_probe(struct platform_device *pdev) + } + } + ++ pinctrl = devm_pinctrl_get_select_default(&pdev->dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(&pdev->dev, "Failed to request pinctrl\n"); ++ return PTR_ERR(pinctrl); ++ } ++ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch b/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch new file mode 100644 index 00000000000000..86ec57f83223e4 --- /dev/null +++ b/patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch @@ -0,0 +1,47 @@ +From 5bc80812222fefb18a5ea8b9fcf8bb93eec37942 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 + +Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> +--- + drivers/video/atmel_lcdfb_core.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index 133d4ad..b71a80c 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -11,6 +11,7 @@ + #include <linux/kernel.h> + #include <linux/module.h> + #include <linux/platform_device.h> ++#include <linux/pinctrl/consumer.h> + #include <linux/dma-mapping.h> + #include <linux/interrupt.h> + #include <linux/clk.h> +@@ -556,6 +557,7 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + struct resource *regs = NULL, *clut = NULL; + struct resource *map = NULL; + int ret; ++ struct pinctrl *pinctrl; + + dev_dbg(dev, "%s BEGIN\n", __func__); + +@@ -635,6 +637,13 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + goto stop_clk; + } + ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "Failed to request pinctrl\n"); ++ ret = PTR_ERR(pinctrl); ++ goto stop_clk; ++ } ++ + /* No error checking, some devices can do without IRQ */ + sinfo->irq_base = platform_get_irq(pdev, 0); + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch b/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch new file mode 100644 index 00000000000000..3e78d0b838f411 --- /dev/null +++ b/patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch @@ -0,0 +1,132 @@ +From 56c99e16b3c2bc6e5820266d81118915508d5b08 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9g45.dtsi | 73 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi +index f08b8c2..e379b89 100644 +--- a/arch/arm/boot/dts/at91sam9g45.dtsi ++++ b/arch/arm/boot/dts/at91sam9g45.dtsi +@@ -125,6 +125,69 @@ + >; + + /* shared pinctrl settings */ ++ dbgu { ++ pinctrl_dbgu: dbgu-0 { ++ atmel,pins = ++ <1 12 0x1 0x0 /* PB12 periph A */ ++ 1 13 0x1 0x0>; /* PB13 periph A */ ++ }; ++ }; ++ ++ uart0 { ++ pinctrl_uart0: uart0-0 { ++ atmel,pins = ++ <1 19 0x1 0x1 /* PB19 periph A with pullup */ ++ 1 18 0x1 0x0>; /* PB18 periph A */ ++ }; ++ ++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 { ++ atmel,pins = ++ <1 17 0x2 0x0 /* PB17 periph B */ ++ 1 15 0x2 0x0>; /* PB15 periph B */ ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1: uart1-0 { ++ atmel,pins = ++ <1 4 0x1 0x1 /* PB4 periph A with pullup */ ++ 1 5 0x1 0x0>; /* PB5 periph A */ ++ }; ++ ++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 { ++ atmel,pins = ++ <3 16 0x1 0x0 /* PD16 periph A */ ++ 3 17 0x1 0x0>; /* PD17 periph A */ ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2: uart2-0 { ++ atmel,pins = ++ <1 6 0x1 0x1 /* PB6 periph A with pullup */ ++ 1 7 0x1 0x0>; /* PB7 periph A */ ++ }; ++ ++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 { ++ atmel,pins = ++ <2 9 0x2 0x0 /* PC9 periph B */ ++ 2 11 0x2 0x0>; /* PC11 periph B */ ++ }; ++ }; ++ ++ uart3 { ++ pinctrl_uart3: uart3-0 { ++ atmel,pins = ++ <1 8 0x1 0x1 /* PB9 periph A with pullup */ ++ 1 9 0x1 0x0>; /* PB8 periph A */ ++ }; ++ ++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 { ++ atmel,pins = ++ <0 23 0x2 0x0 /* PA23 periph B */ ++ 0 24 0x2 0x0>; /* PA24 periph B */ ++ }; ++ }; + + nand { + pinctrl_nand: nand-0 { +@@ -189,6 +252,8 @@ + compatible = "atmel,at91sam9260-usart"; + reg = <0xffffee00 0x200>; + interrupts = <1 4 7>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; + }; + +@@ -198,6 +263,8 @@ + interrupts = <7 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart0>; + status = "disabled"; + }; + +@@ -207,6 +274,8 @@ + interrupts = <8 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; + }; + +@@ -216,6 +285,8 @@ + interrupts = <9 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; + status = "disabled"; + }; + +@@ -225,6 +296,8 @@ + interrupts = <10 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch b/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch new file mode 100644 index 00000000000000..e8ae1df3a9c1ab --- /dev/null +++ b/patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch @@ -0,0 +1,109 @@ +From 9f223333d037f72115defc10f27afaf6fc900721 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9263.dtsi | 57 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi +index 5aa07e4..690e036 100644 +--- a/arch/arm/boot/dts/at91sam9263.dtsi ++++ b/arch/arm/boot/dts/at91sam9263.dtsi +@@ -105,6 +105,55 @@ + >; + + /* shared pinctrl settings */ ++ dbgu { ++ pinctrl_dbgu: dbgu-0 { ++ atmel,pins = ++ <2 30 0x1 0x0 /* PC30 periph A */ ++ 2 31 0x1 0x1>; /* PC31 periph with pullup */ ++ }; ++ }; ++ ++ uart0 { ++ pinctrl_uart0: uart0-0 { ++ atmel,pins = ++ <0 26 0x1 0x1 /* PA26 periph A with pullup */ ++ 0 27 0x1 0x0>; /* PA27 periph A */ ++ }; ++ ++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 { ++ atmel,pins = ++ <0 28 0x1 0x0 /* PA28 periph A */ ++ 0 29 0x1 0x0>; /* PA29 periph A */ ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1: uart1-0 { ++ atmel,pins = ++ <3 0 0x1 0x1 /* PD0 periph A with pullup */ ++ 3 1 0x1 0x0>; /* PD1 periph A */ ++ }; ++ ++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 { ++ atmel,pins = ++ <3 7 0x2 0x0 /* PD7 periph B */ ++ 3 8 0x2 0x0>; /* PD8 periph B */ ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2: uart2-0 { ++ atmel,pins = ++ <3 2 0x1 0x1 /* PD2 periph A with pullup */ ++ 3 3 0x1 0x0>; /* PD3 periph A */ ++ }; ++ ++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 { ++ atmel,pins = ++ <3 5 0x2 0x0 /* PD5 periph B */ ++ 4 6 0x2 0x0>; /* PD6 periph B */ ++ }; ++ }; + + nand { + pinctrl_nand: nand-0 { +@@ -169,6 +218,8 @@ + compatible = "atmel,at91sam9260-usart"; + reg = <0xffffee00 0x200>; + interrupts = <1 4 7>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; + }; + +@@ -178,6 +229,8 @@ + interrupts = <7 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart0>; + status = "disabled"; + }; + +@@ -187,6 +240,8 @@ + interrupts = <8 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; + }; + +@@ -196,6 +251,8 @@ + interrupts = <9 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; + status = "disabled"; + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch b/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch new file mode 100644 index 00000000000000..3da53f3de710a2 --- /dev/null +++ b/patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch @@ -0,0 +1,182 @@ +From b6ce595a610de9ed6ef5b27f824f43909de0db57 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9260.dtsi | 109 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 109 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi +index 2dd4e0b..7c9d91a 100644 +--- a/arch/arm/boot/dts/at91sam9260.dtsi ++++ b/arch/arm/boot/dts/at91sam9260.dtsi +@@ -112,6 +112,101 @@ + >; + + /* 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 */ ++ }; ++ }; ++ ++ uart0 { ++ pinctrl_uart0: uart0-0 { ++ atmel,pins = ++ <1 4 0x1 0x0 /* PB4 periph A */ ++ 1 5 0x1 0x0>; /* PB5 periph A */ ++ }; ++ ++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 { ++ atmel,pins = ++ <1 26 0x1 0x0 /* PB26 periph A */ ++ 1 27 0x1 0x0>; /* PB27 periph A */ ++ }; ++ ++ pinctrl_uart0_dtr_dsr: uart0_dtr_dsr-0 { ++ atmel,pins = ++ <1 24 0x1 0x0 /* PB24 periph A */ ++ 1 22 0x1 0x0>; /* PB22 periph A */ ++ }; ++ ++ pinctrl_uart0_dcd: uart0_dcd-0 { ++ atmel,pins = ++ <1 23 0x1 0x0>; /* PB23 periph A */ ++ }; ++ ++ pinctrl_uart0_ri: uart0_ri-0 { ++ atmel,pins = ++ <1 25 0x1 0x0>; /* PB25 periph A */ ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1: uart1-0 { ++ atmel,pins = ++ <2 6 0x1 0x1 /* PB6 periph A with pullup */ ++ 2 7 0x1 0x0>; /* PB7 periph A */ ++ }; ++ ++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 { ++ atmel,pins = ++ <1 28 0x1 0x0 /* PB28 periph A */ ++ 1 29 0x1 0x0>; /* PB29 periph A */ ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2: uart2-0 { ++ atmel,pins = ++ <1 8 0x1 0x1 /* PB8 periph A with pullup */ ++ 1 9 0x1 0x0>; /* PB9 periph A */ ++ }; ++ ++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 { ++ atmel,pins = ++ <0 4 0x1 0x0 /* PA4 periph A */ ++ 0 5 0x1 0x0>; /* PA5 periph A */ ++ }; ++ }; ++ ++ uart3 { ++ pinctrl_uart3: uart3-0 { ++ atmel,pins = ++ <2 10 0x1 0x1 /* PB10 periph A with pullup */ ++ 2 11 0x1 0x0>; /* PB11 periph A */ ++ }; ++ ++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 { ++ atmel,pins = ++ <3 8 0x2 0x0 /* PB8 periph B */ ++ 3 10 0x2 0x0>; /* PB10 periph B */ ++ }; ++ }; ++ ++ uart4 { ++ pinctrl_uart4: uart4-0 { ++ atmel,pins = ++ <0 31 0x2 0x1 /* PA31 periph B with pullup */ ++ 0 30 0x2 0x0>; /* PA30 periph B */ ++ }; ++ }; ++ ++ uart5 { ++ pinctrl_uart5: uart5-0 { ++ atmel,pins = ++ <2 12 0x1 0x1 /* PB12 periph A with pullup */ ++ 2 13 0x1 0x0>; /* PB13 periph A */ ++ }; ++ }; + + nand { + pinctrl_nand: nand-0 { +@@ -156,6 +251,8 @@ + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4 7>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; + }; + +@@ -165,6 +262,8 @@ + interrupts = <6 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart0>; + status = "disabled"; + }; + +@@ -174,6 +273,8 @@ + interrupts = <7 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; + }; + +@@ -183,6 +284,8 @@ + interrupts = <8 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; + status = "disabled"; + }; + +@@ -192,6 +295,8 @@ + interrupts = <23 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; + }; + +@@ -201,6 +306,8 @@ + interrupts = <24 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; + status = "disabled"; + }; + +@@ -210,6 +317,8 @@ + interrupts = <25 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; + status = "disabled"; + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch b/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch new file mode 100644 index 00000000000000..6e529e5f38b6e7 --- /dev/null +++ b/patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch @@ -0,0 +1,620 @@ +From b07d6cfcdf6ec210b35e05e8d6ae9dc22feffcf1 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 + +where we have one dtsi per soc and one dts per board +we have also a common dtsi name at91sam9x5ek.dtsi for the based board + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9g15.dtsi | 28 +++++++ + arch/arm/boot/dts/at91sam9g15ek.dts | 16 ++++ + arch/arm/boot/dts/at91sam9g25.dtsi | 28 +++++++ + arch/arm/boot/dts/at91sam9g25ek.dts | 42 +--------- + arch/arm/boot/dts/at91sam9g35.dtsi | 28 +++++++ + arch/arm/boot/dts/at91sam9g35ek.dts | 21 +---- + arch/arm/boot/dts/at91sam9x25.dtsi | 28 +++++++ + arch/arm/boot/dts/at91sam9x25ek.dts | 24 +----- + arch/arm/boot/dts/at91sam9x35.dtsi | 28 +++++++ + arch/arm/boot/dts/at91sam9x35ek.dts | 16 ++++ + arch/arm/boot/dts/at91sam9x5.dtsi | 97 ++++++++++++++++++++-- + .../{at91sam9x5_common.dtsi => at91sam9x5ek.dtsi} | 32 ++++++- + arch/arm/mach-at91/Makefile.boot | 2 + + 13 files changed, 298 insertions(+), 92 deletions(-) + create mode 100644 arch/arm/boot/dts/at91sam9g15.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9g15ek.dts + create mode 100644 arch/arm/boot/dts/at91sam9g25.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9g35.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9x25.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9x35.dtsi + create mode 100644 arch/arm/boot/dts/at91sam9x35ek.dts + rename arch/arm/boot/dts/{at91sam9x5_common.dtsi => at91sam9x5ek.dtsi} (54%) + +diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi +new file mode 100644 +index 0000000..fbe7a70 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g15.dtsi +@@ -0,0 +1,28 @@ ++/* ++ * at91sam9g15.dtsi - Device Tree Include file for AT91SAM9G15 SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/include/ "at91sam9x5.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9G15 SoC"; ++ compatible = "atmel, at91sam9g15, atmel,at91sam9x5"; ++ ++ ahb { ++ apb { ++ pinctrl@fffff400 { ++ atmel,mux-mask = < ++ /* A B C */ ++ 0xffffffff 0xffe0399f 0x00000000 /* pioA */ ++ 0x00040000 0x00047e3f 0x00000000 /* pioB */ ++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */ ++ 0x003fffff 0x003f8000 0x00000000 /* pioD */ ++ >; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts +new file mode 100644 +index 0000000..86dd3f6 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g15ek.dts +@@ -0,0 +1,16 @@ ++/* ++ * at91sam9g15ek.dts - Device Tree file for AT91SAM9G15-EK board ++ * ++ * Copyright (C) 2012 Atmel, ++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++/dts-v1/; ++/include/ "at91sam9g15.dtsi" ++/include/ "at91sam9x5ek.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9G25-EK"; ++ compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi +new file mode 100644 +index 0000000..05a718f +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g25.dtsi +@@ -0,0 +1,28 @@ ++/* ++ * at91sam9g25.dtsi - Device Tree Include file for AT91SAM9G25 SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/include/ "at91sam9x5.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9G25 SoC"; ++ compatible = "atmel, at91sam9g25, atmel,at91sam9x5"; ++ ++ ahb { ++ apb { ++ pinctrl@fffff400 { ++ atmel,mux-mask = < ++ /* A B C */ ++ 0xffffffff 0xffe0399f 0xc000001c /* pioA */ ++ 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */ ++ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */ ++ 0x003fffff 0x003f8000 0x00000000 /* pioD */ ++ >; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts +index 91c0f02..4abc978 100644 +--- a/arch/arm/boot/dts/at91sam9g25ek.dts ++++ b/arch/arm/boot/dts/at91sam9g25ek.dts +@@ -7,55 +7,17 @@ + * Licensed under GPLv2 or later. + */ + /dts-v1/; +-/include/ "at91sam9x5_common.dtsi" ++/include/ "at91sam9g25.dtsi" ++/include/ "at91sam9x5ek.dtsi" + + / { + model = "Atmel AT91SAM9G25-EK"; + compatible = "atmel,at91sam9g25ek", "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 { +- usart0: serial@f801c000 { +- status = "okay"; +- }; +- +- macb0: ethernet@f802c000 { +- 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>; +- }; +- }; +- +- i2c0: i2c@f8010000 { +- status = "okay"; +- }; +- +- i2c1: i2c@f8014000 { +- status = "okay"; +- }; +- +- i2c2: i2c@f8018000 { +- status = "okay"; + }; + }; + }; +diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi +new file mode 100644 +index 0000000..f9d14a7 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9g35.dtsi +@@ -0,0 +1,28 @@ ++/* ++ * at91sam9g35.dtsi - Device Tree Include file for AT91SAM9G35 SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/include/ "at91sam9x5.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9G35 SoC"; ++ compatible = "atmel, at91sam9g35, atmel,at91sam9x5"; ++ ++ ahb { ++ apb { ++ pinctrl@fffff400 { ++ atmel,mux-mask = < ++ /* A B C */ ++ 0xffffffff 0xffe0399f 0xc000000c /* pioA */ ++ 0x000406ff 0x00047e3f 0x00000000 /* pioB */ ++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */ ++ 0x003fffff 0x003f8000 0x00000000 /* pioD */ ++ >; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts +index 0cb762e..2781a30 100644 +--- a/arch/arm/boot/dts/at91sam9g35ek.dts ++++ b/arch/arm/boot/dts/at91sam9g35ek.dts +@@ -7,34 +7,17 @@ + * Licensed under GPLv2 or later. + */ + /dts-v1/; +-/include/ "at91sam9x5_common.dtsi" ++/include/ "at91sam9g35.dtsi" ++/include/ "at91sam9x5ek.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 { +diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi +new file mode 100644 +index 0000000..956c65f +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9x25.dtsi +@@ -0,0 +1,28 @@ ++/* ++ * at91sam9x25.dtsi - Device Tree Include file for AT91SAM9X25 SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/include/ "at91sam9x5.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9X25 SoC"; ++ compatible = "atmel, at91sam9x25, atmel,at91sam9x5"; ++ ++ ahb { ++ apb { ++ pinctrl@fffff400 { ++ atmel,mux-mask = < ++ /* A B C */ ++ 0xffffffff 0xffe03fff 0xc000001c /* pioA */ ++ 0x0007ffff 0x00047e3f 0x00000000 /* pioB */ ++ 0x80000000 0xfffd0000 0xb83fffff /* pioC */ ++ 0x003fffff 0x003f8000 0x00000000 /* pioD */ ++ >; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts +index cf903f5..7e38951 100644 +--- a/arch/arm/boot/dts/at91sam9x25ek.dts ++++ b/arch/arm/boot/dts/at91sam9x25ek.dts +@@ -7,38 +7,20 @@ + * Licensed under GPLv2 or later. + */ + /dts-v1/; +-/include/ "at91sam9x5_common.dtsi" ++/include/ "at91sam9x25.dtsi" ++/include/ "at91sam9x5ek.dtsi" + + / { +- model = "Atmel AT91SAM9X25-EK"; ++ model = "Atmel AT91SAM9G25-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/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi +new file mode 100644 +index 0000000..fb102d6 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9x35.dtsi +@@ -0,0 +1,28 @@ ++/* ++ * at91sam9x35.dtsi - Device Tree Include file for AT91SAM9X35 SoC ++ * ++ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> ++ * ++ * Licensed under GPLv2. ++ */ ++ ++/include/ "at91sam9x5.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9X35 SoC"; ++ compatible = "atmel, at91sam9x35, atmel,at91sam9x5"; ++ ++ ahb { ++ apb { ++ pinctrl@fffff400 { ++ atmel,mux-mask = < ++ /* A B C */ ++ 0xffffffff 0xffe03fff 0xc000000c /* pioA */ ++ 0x000406ff 0x00047e3f 0x00000000 /* pioB */ ++ 0xfdffffff 0x00000000 0xb83fffff /* pioC */ ++ 0x003fffff 0x003f8000 0x00000000 /* pioD */ ++ >; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts +new file mode 100644 +index 0000000..5ccb607 +--- /dev/null ++++ b/arch/arm/boot/dts/at91sam9x35ek.dts +@@ -0,0 +1,16 @@ ++/* ++ * at91sam9x35ek.dts - Device Tree file for AT91SAM9X35-EK board ++ * ++ * Copyright (C) 2012 Atmel, ++ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com> ++ * ++ * Licensed under GPLv2 or later. ++ */ ++/dts-v1/; ++/include/ "at91sam9x35.dtsi" ++/include/ "at91sam9x5ek.dtsi" ++ ++/ { ++ model = "Atmel AT91SAM9X35-EK"; ++ compatible = "atmel,at91sam9x35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; ++}; +diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi +index 28e053a..7cefc2c 100644 +--- a/arch/arm/boot/dts/at91sam9x5.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5.dtsi +@@ -113,21 +113,92 @@ + #dma-cells = <1>; + }; + +- pinctrl@fffff200 { ++ pinctrl@fffff400 { + #address-cells = <1>; + #size-cells = <1>; + 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 */ ++ dbgu { ++ pinctrl_dbgu: dbgu-0 { ++ atmel,pins = ++ <0 9 0x1 0x0 /* PA9 periph A */ ++ 0 10 0x1 0x1>; /* PA10 periph A with pullup */ ++ }; ++ }; ++ ++ uart0 { ++ pinctrl_uart0: uart0-0 { ++ atmel,pins = ++ <0 0 0x1 0x1 /* PA0 periph A with pullup */ ++ 0 1 0x1 0x0>; /* PA1 periph A */ ++ }; ++ ++ pinctrl_uart0_rts_cts: uart0_rts_cts-0 { ++ atmel,pins = ++ <0 2 0x1 0x0 /* PA2 periph A */ ++ 0 3 0x1 0x0>; /* PA3 periph A */ ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1: uart1-0 { ++ atmel,pins = ++ <0 5 0x1 0x1 /* PA5 periph A with pullup */ ++ 0 6 0x1 0x0>; /* PA6 periph A */ ++ }; ++ ++ pinctrl_uart1_rts_cts: uart1_rts_cts-0 { ++ atmel,pins = ++ <3 27 0x3 0x0 /* PC27 periph C */ ++ 3 28 0x3 0x0>; /* PC28 periph C */ ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2: uart2-0 { ++ atmel,pins = ++ <0 7 0x1 0x1 /* PA7 periph A with pullup */ ++ 0 8 0x1 0x0>; /* PA8 periph A */ ++ }; ++ ++ pinctrl_uart2_rts_cts: uart2_rts_cts-0 { ++ atmel,pins = ++ <0 0 0x2 0x0 /* PB0 periph B */ ++ 0 1 0x2 0x0>; /* PB1 periph B */ ++ }; ++ }; ++ ++ uart3 { ++ pinctrl_uart3: uart3-0 { ++ atmel,pins = ++ <3 23 0x2 0x1 /* PC22 periph B with pullup */ ++ 3 23 0x2 0x0>; /* PC23 periph B */ ++ }; ++ ++ pinctrl_uart3_rts_cts: uart3_rts_cts-0 { ++ atmel,pins = ++ <3 24 0x2 0x0 /* PC24 periph B */ ++ 3 25 0x2 0x0>; /* PC25 periph B */ ++ }; ++ }; ++ ++ usart0 { ++ pinctrl_usart0: usart0-0 { ++ atmel,pins = ++ <3 8 0x3 0x0 /* PC8 periph C */ ++ 3 9 0x3 0x1>; /* PC9 periph C with pullup */ ++ }; ++ }; ++ ++ usart1 { ++ pinctrl_usart1: usart1-0 { ++ atmel,pins = ++ <3 16 0x3 0x0 /* PC16 periph C */ ++ 3 17 0x3 0x1>; /* PC17 periph C with pullup */ ++ }; ++ }; + + nand { + pinctrl_nand: nand-0 { +@@ -184,6 +255,8 @@ + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4 7>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_dbgu>; + status = "disabled"; + }; + +@@ -193,6 +266,8 @@ + interrupts = <5 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart0>; + status = "disabled"; + }; + +@@ -202,6 +277,8 @@ + interrupts = <6 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "disabled"; + }; + +@@ -211,6 +288,8 @@ + interrupts = <7 4 5>; + atmel,use-dma-rx; + atmel,use-dma-tx; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; + status = "disabled"; + }; + +diff --git a/arch/arm/boot/dts/at91sam9x5_common.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi +similarity index 54% +rename from arch/arm/boot/dts/at91sam9x5_common.dtsi +rename to arch/arm/boot/dts/at91sam9x5ek.dtsi +index b805425..8854794 100644 +--- a/arch/arm/boot/dts/at91sam9x5_common.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi +@@ -1,22 +1,31 @@ + /* +- * at91sam9x5_common.dtsi - Device Tree Include file for AT91SAM9x5 Evaluation Kit: +- * common peripherals. ++ * at91sam9x5ek.dtsi - Device Tree file for AT91SAM9x5CM Base board + * + * Copyright (C) 2012 Atmel, + * 2012 Nicolas Ferre <nicolas.ferre@atmel.com> + * + * Licensed under GPLv2 or later. + */ +-/include/ "at91sam9x5.dtsi" + /include/ "at91sam9x5cm.dtsi" + + / { ++ model = "Atmel AT91SAM9X5-EK"; ++ compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; ++ ++ chosen { ++ bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs"; ++ }; ++ + ahb { + apb { + dbgu: serial@fffff200 { + status = "okay"; + }; + ++ usart0: serial@f801c000 { ++ status = "okay"; ++ }; ++ + mmc0: mmc@f0008000 { + status = "okay"; + slot@0 { +@@ -26,6 +35,23 @@ + }; + }; + ++ mmc1: mmc@f000c000 { ++ slot@0 { ++ reg = <0>; ++ bus-width = <4>; ++ cd-gpios = <&pioD 14 0>; ++ }; ++ }; ++ ++ macb0: ethernet@f802c000 { ++ phy-mode = "rmii"; ++ status = "okay"; ++ }; ++ ++ macb1: ethernet@f8030000 { ++ phy-mode = "rmii"; ++ }; ++ + i2c0: i2c@f8010000 { + status = "okay"; + }; +diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot +index 410485a..f63b8bf 100644 +--- a/arch/arm/mach-at91/Makefile.boot ++++ b/arch/arm/mach-at91/Makefile.boot +@@ -33,6 +33,8 @@ dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb + # sam9n12 + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb + # sam9x5 ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g15ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g35ek.dtb + dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x25ek.dtb ++dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9x35ek.dtb +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch b/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch new file mode 100644 index 00000000000000..954f5f1bc57745 --- /dev/null +++ b/patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch @@ -0,0 +1,336 @@ +From f3a49662b5055a2e766d0a9f327c51781f463283 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9x5.dtsi | 132 +++++++++++++++++++++++++++++++----- + arch/arm/boot/dts/at91sam9x5ek.dtsi | 24 ++++--- + arch/arm/mach-at91/board-dt.c | 27 -------- + 3 files changed, 130 insertions(+), 53 deletions(-) + +diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi +index 7cefc2c..726bb82 100644 +--- a/arch/arm/boot/dts/at91sam9x5.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5.dtsi +@@ -151,8 +151,8 @@ + + pinctrl_uart1_rts_cts: uart1_rts_cts-0 { + atmel,pins = +- <3 27 0x3 0x0 /* PC27 periph C */ +- 3 28 0x3 0x0>; /* PC28 periph C */ ++ <2 27 0x3 0x0 /* PC27 periph C */ ++ 2 28 0x3 0x0>; /* PC28 periph C */ + }; + }; + +@@ -165,46 +165,134 @@ + + pinctrl_uart2_rts_cts: uart2_rts_cts-0 { + atmel,pins = +- <0 0 0x2 0x0 /* PB0 periph B */ +- 0 1 0x2 0x0>; /* PB1 periph B */ ++ <1 0 0x2 0x0 /* PB0 periph B */ ++ 1 1 0x2 0x0>; /* PB1 periph B */ + }; + }; + + uart3 { + pinctrl_uart3: uart3-0 { + atmel,pins = +- <3 23 0x2 0x1 /* PC22 periph B with pullup */ +- 3 23 0x2 0x0>; /* PC23 periph B */ ++ <2 22 0x2 0x1 /* PC22 periph B with pullup */ ++ 2 23 0x2 0x0>; /* PC23 periph B */ + }; + + pinctrl_uart3_rts_cts: uart3_rts_cts-0 { + atmel,pins = +- <3 24 0x2 0x0 /* PC24 periph B */ +- 3 25 0x2 0x0>; /* PC25 periph B */ ++ <2 24 0x2 0x0 /* PC24 periph B */ ++ 2 25 0x2 0x0>; /* PC25 periph B */ + }; + }; + + usart0 { + pinctrl_usart0: usart0-0 { + atmel,pins = +- <3 8 0x3 0x0 /* PC8 periph C */ +- 3 9 0x3 0x1>; /* PC9 periph C with pullup */ ++ <2 8 0x3 0x0 /* PC8 periph C */ ++ 2 9 0x3 0x1>; /* PC9 periph C with pullup */ + }; + }; + + usart1 { + pinctrl_usart1: usart1-0 { + atmel,pins = +- <3 16 0x3 0x0 /* PC16 periph C */ +- 3 17 0x3 0x1>; /* PC17 periph C with pullup */ ++ <2 16 0x3 0x0 /* PC16 periph C */ ++ 2 17 0x3 0x1>; /* PC17 periph C with pullup */ + }; + }; + + nand { +- pinctrl_nand: nand-0 { ++ pinctrl_nand_rdy_enable: nand_rdy_enable-0 { + atmel,pins = +- <3 4 0x0 0x1 /* PD5 gpio RDY pin pull_up */ +- 3 5 0x0 0x1>; /* PD4 gpio enable pin pull_up */ ++ <3 5 0x0 0x1 /* PD5 gpio RDY pin pull_up */ ++ 3 4 0x0 0x1>; /* PD4 gpio enable pin pull_up */ ++ }; ++ ++ pinctrl_nand_oe_we_ale_cle: nand_oe_we_ale_cle-0 { ++ atmel,pins = ++ <3 0 0x1 0x1 /* PD0 periph A with pullup */ ++ 3 1 0x1 0x1 /* PD1 periph A with pullup */ ++ 3 2 0x1 0x1 /* PD2 periph A with pullup */ ++ 3 3 0x1 0x1>; /* PD3 periph A with pullup */ ++ }; ++ ++ pinctrl_nand_bus_on_d16_8bit: nand_bus_on_d16_8bit-0 { ++ atmel,pins = ++ <3 6 0x1 0x1 /* PD6 periph A with pullup */ ++ 3 7 0x1 0x1 /* PD7 periph A with pullup */ ++ 3 8 0x1 0x1 /* PD8 periph A with pullup */ ++ 3 9 0x1 0x1 /* PD9 periph A with pullup */ ++ 3 10 0x1 0x1 /* PD10 periph A with pullup */ ++ 3 11 0x1 0x1 /* PD11 periph A with pullup */ ++ 3 12 0x1 0x1 /* PD12 periph A with pullup */ ++ 3 13 0x1 0x1>; /* PD13 periph A with pullup */ ++ }; ++ ++ pinctrl_nand_bus_on_d16_16bit: nand_bus_on_d16_16bit-0 { ++ atmel,pins = ++ <3 14 0x1 0x1 /* PD14 periph A with pullup */ ++ 3 15 0x1 0x1 /* PD15 periph A with pullup */ ++ 3 16 0x1 0x1 /* PD16 periph A with pullup */ ++ 3 17 0x1 0x1 /* PD17 periph A with pullup */ ++ 3 18 0x1 0x1 /* PD18 periph A with pullup */ ++ 3 19 0x1 0x1 /* PD19 periph A with pullup */ ++ 3 20 0x1 0x1 /* PD20 periph A with pullup */ ++ 3 21 0x1 0x1>; /* PD21 periph A with pullup */ ++ }; ++ }; ++ ++ i2c0 { ++ pinctrl_i2c0: i2c0-0 { ++ atmel,pins = ++ <0 30 0x1 0x2 /* PA30 periph A Multidrive */ ++ 0 31 0x1 0x3>; /* PA31 periph A Multidrive with pullup */ ++ }; ++ }; ++ ++ i2c1 { ++ pinctrl_i2c1: i2c1-0 { ++ atmel,pins = ++ <2 0 0x3 0x2 /* PC0 periph C Multidrive */ ++ 2 1 0x3 0x3>; /* PC1 periph C Multidrive with pullup */ ++ }; ++ }; ++ ++ i2c2 { ++ pinctrl_i2c2: i2c2-0 { ++ atmel,pins = ++ <1 4 0x2 0x2 /* PB4 periph B Multidrive */ ++ 1 5 0x2 0x3>; /* PB5 periph B Multidrive with pullup */ ++ }; ++ }; ++ ++ mmc0 { ++ pinctrl_mmc0_clk_cmd_dat0: mm0_clk_cmd_dat0 { ++ atmel,pins = ++ <0 17 0x1 0x0 /* PA17 periph A */ ++ 0 16 0x1 0x1 /* PA16 periph A with pullpup */ ++ 0 15 0x1 0x1>; /* PA15 periph A with pullpup */ ++ }; ++ ++ pinctrl_mmc0_dat1_3: mm0_dat1_3 { ++ atmel,pins = ++ <0 18 0x1 0x1 /* PA18 periph A with pullpup */ ++ 0 19 0x1 0x1 /* PA19 periph A with pullpup */ ++ 0 20 0x1 0x1>; /* PA20 periph A with pullpup */ ++ }; ++ }; ++ ++ mmc1 { ++ pinctrl_mmc1_clk_cmd_dat0: mm1_clk_cmd_dat0 { ++ atmel,pins = ++ <0 13 0x2 0x0 /* PA13 periph B */ ++ 0 12 0x2 0x1 /* PA12 periph B with pullpup */ ++ 0 11 0x2 0x1>; /* PA11 periph B with pullpup */ ++ }; ++ ++ pinctrl_mmc1_dat1_3: mm1_dat1_3 { ++ atmel,pins = ++ <0 2 0x2 0x1 /* PA2 periph B with pullpup */ ++ 0 3 0x2 0x1 /* PA3 periph B with pullpup */ ++ 0 4 0x2 0x1>; /* PA4 periph B with pullpup */ + }; + }; + +@@ -311,20 +399,22 @@ + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4 0>; +- status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + dma = <&dma0 0x10002200>; ++ pinctrl-names = "default"; ++ status = "disabled"; + }; + + mmc1: mmc@f000c000 { + compatible = "atmel,hsmci"; + reg = <0xf000c000 0x600>; + interrupts = <26 4 0>; +- status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + dma = <&dma1 0x10002200>; ++ pinctrl-names = "default"; ++ status = "disabled"; + }; + + i2c0: i2c@f8010000 { +@@ -334,6 +424,8 @@ + dma = <&dma0 0x10002278>; + #address-cells = <1>; + #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c0>; + status = "disabled"; + }; + +@@ -344,6 +436,8 @@ + dma = <&dma1 0x10002256>; + #address-cells = <1>; + #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; + status = "disabled"; + }; + +@@ -354,6 +448,8 @@ + dma = <&dma0 0x1000229A>; + #address-cells = <1>; + #size-cells = <0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; + status = "disabled"; + }; + +@@ -393,7 +489,7 @@ + atmel,nand-addr-offset = <21>; + atmel,nand-cmd-offset = <22>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_nand>; ++ pinctrl-0 = <&pinctrl_nand_rdy_enable &pinctrl_nand_oe_we_ale_cle>; + gpios = <&pioD 5 0 + &pioD 4 0 + 0 +diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi +index 8854794..0406e0d 100644 +--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi +@@ -18,6 +18,20 @@ + + ahb { + apb { ++ pinctrl@fffff400 { ++ board { ++ pinctrl_mmc0_cd: mmc0_cd { ++ atmel,pins = ++ <3 15 0x0 0x5>; /* PD15 gpio with pullup deglitch */ ++ }; ++ ++ pinctrl_mmc1_cd: mmc1_cd { ++ atmel,pins = ++ <3 14 0x0 0x5>; /* PD14 gpio with pullup deglitch */ ++ }; ++ }; ++ }; ++ + dbgu: serial@fffff200 { + status = "okay"; + }; +@@ -27,6 +41,7 @@ + }; + + mmc0: mmc@f0008000 { ++ pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_cd>; + status = "okay"; + slot@0 { + reg = <0>; +@@ -36,6 +51,7 @@ + }; + + mmc1: mmc@f000c000 { ++ pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + slot@0 { + reg = <0>; + bus-width = <4>; +@@ -55,14 +71,6 @@ + i2c0: i2c@f8010000 { + status = "okay"; + }; +- +- i2c1: i2c@f8014000 { +- status = "okay"; +- }; +- +- i2c2: i2c@f8018000 { +- status = "okay"; +- }; + }; + + usb0: ohci@00600000 { +diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c +index b1a5d3c..95798f5 100644 +--- a/arch/arm/mach-at91/board-dt.c ++++ b/arch/arm/mach-at91/board-dt.c +@@ -139,36 +139,9 @@ static void __init at91_dt_device_init(void) + { + /* 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"); + +- 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"); +- + at91sam9x5_pinmux_lcd(); + } + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch b/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch new file mode 100644 index 00000000000000..300b6fbb65bb9a --- /dev/null +++ b/patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch @@ -0,0 +1,69 @@ +From 0328d56fcf25103afd966706a035735d2bf77d9c 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9x5.dtsi | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi +index 726bb82..c1b0334 100644 +--- a/arch/arm/boot/dts/at91sam9x5.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5.dtsi +@@ -296,6 +296,42 @@ + }; + }; + ++ lcd { ++ pinctrl_lcd: lcd-0 { ++ atmel,pins = ++ <2 26 0x1 0x1 /* PC26 periph A */ ++ 2 27 0x1 0x1 /* PC27 periph A */ ++ 2 28 0x1 0x1 /* PC28 periph A */ ++ 2 24 0x1 0x1 /* PC24 periph A */ ++ 2 29 0x1 0x1 /* PC29 periph A */ ++ 2 30 0x1 0x1 /* PC30 periph A */ ++ 2 0 0x1 0x1 /* PC0 periph A */ ++ 2 1 0x1 0x1 /* PC1 periph A */ ++ 2 2 0x1 0x1 /* PC2 periph A */ ++ 2 3 0x1 0x1 /* PC3 periph A */ ++ 2 4 0x1 0x1 /* PC4 periph A */ ++ 2 5 0x1 0x1 /* PC5 periph A */ ++ 2 6 0x1 0x1 /* PC6 periph A */ ++ 2 7 0x1 0x1 /* PC7 periph A */ ++ 2 8 0x1 0x1 /* PC8 periph A */ ++ 2 9 0x1 0x1 /* PC9 periph A */ ++ 2 10 0x1 0x1 /* PC10 periph A */ ++ 2 11 0x1 0x1 /* PC11 periph A */ ++ 2 12 0x1 0x1 /* PC12 periph A */ ++ 2 13 0x1 0x1 /* PC13 periph A */ ++ 2 14 0x1 0x1 /* PC14 periph A */ ++ 2 15 0x1 0x1 /* PC15 periph A */ ++ 2 16 0x1 0x1 /* PC16 periph A */ ++ 2 17 0x1 0x1 /* PC17 periph A */ ++ 2 18 0x1 0x1 /* PC18 periph A */ ++ 2 19 0x1 0x1 /* PC19 periph A */ ++ 2 20 0x1 0x1 /* PC20 periph A */ ++ 2 21 0x1 0x1 /* PC21 periph A */ ++ 2 22 0x1 0x1 /* PC22 periph A */ ++ 2 23 0x1 0x1>; /* PC23 periph A */ ++ }; ++ }; ++ + pioA: gpio@fffff400 { + compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; +@@ -458,6 +494,8 @@ + reg = <0xf8038000 0xff + 0xf8038400 0x3ff>; + interrupts = <25 4 3>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcd>; + status = "disabled"; + }; + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch b/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch new file mode 100644 index 00000000000000..4843de1365456d --- /dev/null +++ b/patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch @@ -0,0 +1,72 @@ +From d97e722de56d81f2d86606ff2537c14bd7ec270f 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/mach-at91/board-dt.c | 41 ----------------------------------------- + 1 file changed, 41 deletions(-) + +diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c +index 95798f5..16b6b3c 100644 +--- a/arch/arm/mach-at91/board-dt.c ++++ b/arch/arm/mach-at91/board-dt.c +@@ -79,45 +79,6 @@ static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .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), +@@ -141,8 +102,6 @@ static void __init at91_dt_device_init(void) + if (of_machine_is_compatible("atmel,at91sam9x5")) { + at91_set_gpio_input(AT91_PIN_PA7, 1); + printk("AT91: qt1070 pin mux done\n"); +- +- at91sam9x5_pinmux_lcd(); + } + + of_platform_populate(NULL, of_default_bus_match_table, at91_auxdata_lookup, NULL); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch b/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch new file mode 100644 index 00000000000000..93684a0f290235 --- /dev/null +++ b/patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch @@ -0,0 +1,190 @@ +From e932c44de6861621566b9a74a1498c72b14dae49 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 + +Introduce simple bus to represent the LCDC itself so we can attached the +pinctrl to it + +signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + +Conflicts: + arch/arm/boot/dts/at91sam9x5.dtsi +--- + arch/arm/boot/dts/at91sam9g35ek.dts | 17 ++++++++----- + arch/arm/boot/dts/at91sam9x5.dtsi | 42 +++++++++++++++++------------- + drivers/video/atmel_lcdfb_core.c | 51 +++++++++++++++++++++++++++++++------ + 3 files changed, 78 insertions(+), 32 deletions(-) + +diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts +index 2781a30..9f91dbc 100644 +--- a/arch/arm/boot/dts/at91sam9g35ek.dts ++++ b/arch/arm/boot/dts/at91sam9g35ek.dts +@@ -20,16 +20,19 @@ + status = "okay"; + }; + +- lcd@f8038000 { ++ lcd_bus@f8038000 { + status = "okay"; +- }; ++ lcd@f8038000 { ++ status = "okay"; ++ }; + +- lcdovl1@f8038100 { +- status = "okay"; +- }; ++ lcdovl1@f8038100 { ++ status = "okay"; ++ }; + +- lcdheo1@f8038280 { +- status = "okay"; ++ lcdheo1@f8038280 { ++ status = "okay"; ++ }; + }; + }; + }; +diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi +index c1b0334..1fcbbe8 100644 +--- a/arch/arm/boot/dts/at91sam9x5.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5.dtsi +@@ -489,28 +489,36 @@ + status = "disabled"; + }; + +- lcd@f8038000 { +- compatible = "atmel,at91sam9x5-lcd"; +- reg = <0xf8038000 0xff +- 0xf8038400 0x3ff>; +- interrupts = <25 4 3>; ++ lcd_bus@f8038000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "atmel,at91sam9x5-lcd-bus", "simple-bus"; ++ ranges = <0xf8038000 0xf8038000 0x4000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd>; + status = "disabled"; +- }; + +- lcdovl1@f8038100 { +- compatible = "atmel,at91sam9x5-lcd"; +- reg = <0xf8038100 0xff +- 0xf8038800 0x3ff>; +- status = "disabled"; +- }; ++ lcd@f8038000 { ++ compatible = "atmel,at91sam9x5-lcd"; ++ reg = <0xf8038000 0xff ++ 0xf8038400 0x3ff>; ++ interrupts = <25 4 3>; ++ status = "disabled"; ++ }; + +- lcdheo1@f8038280 { +- compatible = "atmel,at91sam9x5-heo"; +- reg = <0xf8038280 0xbf>; +- interrupts = <25 4 3>; +- status = "disabled"; ++ lcdovl1@f8038100 { ++ compatible = "atmel,at91sam9x5-lcd"; ++ reg = <0xf8038100 0xff ++ 0xf8038800 0x3ff>; ++ status = "disabled"; ++ }; ++ ++ lcdheo1@f8038280 { ++ compatible = "atmel,at91sam9x5-heo"; ++ reg = <0xf8038280 0xbf>; ++ interrupts = <25 4 3>; ++ status = "disabled"; ++ }; + }; + }; + +diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c +index b71a80c..4d272ee 100644 +--- a/drivers/video/atmel_lcdfb_core.c ++++ b/drivers/video/atmel_lcdfb_core.c +@@ -19,6 +19,8 @@ + #include <linux/init.h> + #include <linux/delay.h> + #include <linux/gfp.h> ++#include <linux/of.h> ++#include <linux/of_device.h> + + #include <mach/board.h> + #include <mach/cpu.h> +@@ -557,7 +559,6 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + struct resource *regs = NULL, *clut = NULL; + struct resource *map = NULL; + int ret; +- struct pinctrl *pinctrl; + + dev_dbg(dev, "%s BEGIN\n", __func__); + +@@ -637,13 +638,6 @@ int __atmel_lcdfb_probe(struct platform_device *pdev, + goto stop_clk; + } + +- pinctrl = devm_pinctrl_get_select_default(dev); +- if (IS_ERR(pinctrl)) { +- dev_err(dev, "Failed to request pinctrl\n"); +- ret = PTR_ERR(pinctrl); +- goto stop_clk; +- } +- + /* No error checking, some devices can do without IRQ */ + sinfo->irq_base = platform_get_irq(pdev, 0); + +@@ -840,3 +834,44 @@ int __atmel_lcdfb_remove(struct platform_device *pdev) + return 0; + } + EXPORT_SYMBOL_GPL(__atmel_lcdfb_remove); ++ ++static const struct of_device_id atmel_lcdfb_bus_dt_ids[] = { ++ { .compatible = "atmel,at91sam9x5-lcd-bus" }, ++ { /* sentinel */ } ++}; ++ ++static int atmel_lcdfb_bus_probe(struct platform_device *pdev) ++{ ++ struct pinctrl *pinctrl; ++ struct device *dev = &pdev->dev; ++ ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "Failed to request pinctrl\n"); ++ return PTR_ERR(pinctrl); ++ } ++ ++ return 0; ++} ++ ++static struct platform_driver atmel_lcdfb_bus = { ++ .probe = atmel_lcdfb_bus_probe, ++ .driver = { ++ .name = "atmel_lcdfb_bus", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(atmel_lcdfb_bus_dt_ids), ++ }, ++}; ++ ++static int __init atmel_lcdfb_bus_init(void) ++{ ++ return platform_driver_register(&atmel_lcdfb_bus); ++} ++ ++static void __exit atmel_lcdfb_bus_exit(void) ++{ ++ platform_driver_unregister(&atmel_lcdfb_bus); ++} ++ ++module_init(atmel_lcdfb_bus_init); ++module_exit(atmel_lcdfb_bus_exit); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch b/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch new file mode 100644 index 00000000000000..fdc35a625392f1 --- /dev/null +++ b/patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch @@ -0,0 +1,91 @@ +From 11e369f0f20f451f958d7ef2e37a813a9a83dcf4 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/at91-3.4-trunk-contents.txt | 71 ++++++++++++++++++++++++++ + 1 file changed, 71 insertions(+) + create mode 100644 arch/arm/mach-at91/at91-3.4-trunk-contents.txt + +diff --git a/arch/arm/mach-at91/at91-3.4-trunk-contents.txt b/arch/arm/mach-at91/at91-3.4-trunk-contents.txt +new file mode 100644 +index 0000000..bfc5a47 +--- /dev/null ++++ b/arch/arm/mach-at91/at91-3.4-trunk-contents.txt +@@ -0,0 +1,71 @@ ++This file lists all branches that are pulled into the at91-3.4-trunk_merge ++branch of git://rfolxts01.rfo.atmel.com/linux and their external dependencies. ++ ++The at91-3.4-trunk/v3.4.x_* branches are kept in the order in which they ++get applied. ++ ++external dependencies: ++NONE ++ ++at91-3.4-trunk_merge: ++at91-3.4-trunk/v3.4.x_base git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_base ++ ++at91-3.4-trunk/v3.4.x_cleanup+fixes git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_cleanup+fixes ++ depends on at91-3.4-trunk/v3.4.x_base ++ ++at91-3.4-trunk/v3.4.x_aic5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_aic5 ++ depends on at91-3.4-trunk/v3.4.x_base ++ ++at91-3.4-trunk/v3.4.x_dma git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_dma ++at91-3.4-trunk/v3.4.x_ethernet git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_ethernet ++at91-3.4-trunk/v3.4.x_ac97 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_ac97 ++at91-3.4-trunk/v3.4.x_pmecc git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc ++at91-3.4-trunk/v3.4.x_touch git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_touch ++at91-3.4-trunk/v3.4.x_gmac git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_gmac ++at91-3.4-trunk/v3.4.x_phy git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_phy ++at91-3.4-trunk/v3.4.x_usb git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_usb ++at91-3.4-trunk/v3.4.x_isi git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_isi ++ ++at91-3.4-trunk/v3.4.x_lcd git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_lcd ++at91-3.4-trunk/v3.4.x_soc_lcd git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_soc_lcd ++ depends on at91-3.4-trunk/v3.4.x_base ++ depends on at91-3.4-trunk/v3.4.x_lcd ++ ++at91-3.4-trunk/v3.4.x_mci git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_mci ++ depends on at91-3.4-trunk/v3.4.x_base ++ ++at91-3.4-trunk/v3.4.x_i2c git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_i2c ++ depends on at91-3.4-trunk/v3.4.x_base ++at91-3.4-trunk/v3.4.x_slaveDMA_i2c git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_slaveDMA_i2c ++ depends on at91-3.4-trunk/v3.4.x_i2c ++ ++at91-3.4-trunk/v3.4.x_slaveDMA_mci git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_slaveDMA ++ depends on at91-3.4-trunk/v3.4.x_mci ++ depends on at91-3.4-trunk/v3.4.x_slaveDMA_i2c ++ ++at91-3.4-trunk/v3.4.x_pinmux_sam9x5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinmux_sam9x5 ++ depends on at91-3.4-trunk/v3.4.x_base ++ ++at91-3.4-trunk/v3.4.x_pmecc_4k_support git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc_4k_support ++ depends on at91-3.4-trunk/v3.4.x_pmecc ++ ++at91-3.4-trunk/v3.4.x_pmecc_dt_9x5 git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pmecc_dt_9x5 ++ depends on at91-3.4-trunk/v3.4.x_pmecc ++ ++at91-3.4-trunk/v3.4.x_sam9x5_dt git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_sam9x5_dt ++ depends on at91-3.4-trunk/v3.4.x_pmecc_dt_9x5 ++ depends on at91-3.4-trunk/v3.4.x_lcd ++ depends on at91-3.4-trunk/v3.4.x_pinmux_sam9x5 ++ ++at91-3.4-trunk/v3.4.x_crypto git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_crypto ++ depends on at91-3.4-trunk/v3.4.x_aic5 ++ ++at91-3.4-trunk/v3.4.x_pinctrl git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinctrl ++ depends on at91-3.4-trunk/v3.4.x_base ++ depends on at91-3.4-trunk/v3.4.x_cleanup+fixes ++ depends on at91-3.4-trunk/v3.4.x_aic5 ++ depends on at91-3.4-trunk/v3.4.x_pmecc ++ depends on at91-3.4-trunk/v3.4.x_pmecc_4k_support ++ ++at91-3.4-trunk/v3.4.x_pinctrl_drivers git://rfolxts01.rfo.atmel.com/linux at91-3.4-trunk/v3.4.x_pinctrl_drivers ++ depends on **ALL** +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch b/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch new file mode 100644 index 00000000000000..cac117dfe897b9 --- /dev/null +++ b/patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch @@ -0,0 +1,258 @@ +From 82c87f0c1d7b1077da380336e59180e3ed4c9407 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 + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/configs/at91sam9x5_defconfig | 238 ++++++++++++++++++++++++++++++++++ + 1 file changed, 238 insertions(+) + create mode 100644 arch/arm/configs/at91sam9x5_defconfig + +diff --git a/arch/arm/configs/at91sam9x5_defconfig b/arch/arm/configs/at91sam9x5_defconfig +new file mode 100644 +index 0000000..0dbbf71 +--- /dev/null ++++ b/arch/arm/configs/at91sam9x5_defconfig +@@ -0,0 +1,238 @@ ++CONFIG_EXPERIMENTAL=y ++# CONFIG_LOCALVERSION_AUTO is not set ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_IRQ_DOMAIN_DEBUG=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_EMBEDDED=y ++CONFIG_SLAB=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_LBDAF is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++CONFIG_ARCH_AT91=y ++CONFIG_SOC_AT91SAM9X5=y ++CONFIG_MACH_AT91SAM_DT=y ++CONFIG_AT91_PROGRAMMABLE_CLOCKS=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_LEDS=y ++CONFIG_LEDS_CPU=y ++CONFIG_UACCESS_WITH_MEMCPY=y ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_ARM_APPENDED_DTB=y ++CONFIG_ARM_ATAG_DTB_COMPAT=y ++CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" ++CONFIG_AUTO_ZRELADDR=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_PNP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_DIAG is not set ++CONFIG_IPV6=y ++# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET6_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET6_XFRM_MODE_BEET is not set ++CONFIG_IPV6_SIT_6RD=y ++CONFIG_CFG80211=y ++# CONFIG_CFG80211_DEFAULT_PS is not set ++CONFIG_CFG80211_DEBUGFS=y ++CONFIG_WIRELESS_EXT_SYSFS=y ++CONFIG_MAC80211=y ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_ATMEL=y ++CONFIG_MTD_UBI=y ++CONFIG_PROC_DEVICETREE=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=4 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_ATMEL_TCLIB=y ++CONFIG_EEPROM_AT24=y ++CONFIG_SCSI=y ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_NETDEVICES=y ++CONFIG_MII=y ++CONFIG_MACB=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CHELSIO is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++# CONFIG_NET_VENDOR_SMSC is not set ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_DAVICOM_PHY=y ++CONFIG_MICREL_PHY=y ++CONFIG_LIBERTAS_THINFIRM=m ++CONFIG_LIBERTAS_THINFIRM_USB=m ++CONFIG_AT76C50X_USB=m ++CONFIG_USB_ZD1201=m ++CONFIG_RTL8187=m ++CONFIG_ATH_COMMON=m ++CONFIG_ATH9K=m ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_SDIO=m ++CONFIG_ATH6KL_USB=m ++CONFIG_B43=m ++CONFIG_B43_SDIO=y ++CONFIG_B43_DEBUG=y ++CONFIG_B43LEGACY=m ++CONFIG_BRCMFMAC=m ++CONFIG_BRCMFMAC_USB=y ++CONFIG_IWM=m ++CONFIG_LIBERTAS=m ++CONFIG_LIBERTAS_USB=m ++CONFIG_LIBERTAS_SDIO=m ++CONFIG_P54_COMMON=m ++CONFIG_RT2X00=m ++CONFIG_RT2500USB=m ++CONFIG_RT73USB=m ++CONFIG_RT2800USB=m ++CONFIG_RT2800USB_RT53XX=y ++CONFIG_RT2800USB_UNKNOWN=y ++CONFIG_RTL8192CU=m ++CONFIG_WL1251=m ++CONFIG_WL1251_SDIO=m ++CONFIG_WL12XX_MENU=m ++CONFIG_WL12XX=m ++CONFIG_WL12XX_SDIO=m ++CONFIG_ZD1211RW=m ++CONFIG_MWIFIEX=m ++CONFIG_MWIFIEX_SDIO=m ++CONFIG_INPUT_POLLDEV=m ++# CONFIG_INPUT_MOUSEDEV is not set ++CONFIG_INPUT_JOYDEV=y ++CONFIG_INPUT_EVDEV=y ++# CONFIG_KEYBOARD_ATKBD is not set ++CONFIG_KEYBOARD_QT1070=y ++CONFIG_KEYBOARD_GPIO=y ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_ATMEL_MXT=m ++CONFIG_TOUCHSCREEN_ATMEL_TSADCC=y ++# CONFIG_SERIO is not set ++CONFIG_LEGACY_PTY_COUNT=4 ++CONFIG_SERIAL_ATMEL=y ++CONFIG_SERIAL_ATMEL_CONSOLE=y ++# CONFIG_HW_RANDOM is not set ++CONFIG_I2C=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_AT91=y ++CONFIG_GPIO_SYSFS=y ++# CONFIG_HWMON is not set ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++# CONFIG_RC_CORE is not set ++# CONFIG_MEDIA_TUNER_SIMPLE is not set ++# CONFIG_MEDIA_TUNER_TDA8290 is not set ++# CONFIG_MEDIA_TUNER_TDA827X is not set ++# CONFIG_MEDIA_TUNER_TDA18271 is not set ++# CONFIG_MEDIA_TUNER_TDA9887 is not set ++# CONFIG_MEDIA_TUNER_TEA5761 is not set ++# CONFIG_MEDIA_TUNER_TEA5767 is not set ++# CONFIG_MEDIA_TUNER_MT20XX is not set ++# CONFIG_MEDIA_TUNER_MT2060 is not set ++# CONFIG_MEDIA_TUNER_MT2063 is not set ++# CONFIG_MEDIA_TUNER_MT2266 is not set ++# CONFIG_MEDIA_TUNER_MT2131 is not set ++# CONFIG_MEDIA_TUNER_QT1010 is not set ++# CONFIG_MEDIA_TUNER_XC2028 is not set ++# CONFIG_MEDIA_TUNER_XC5000 is not set ++# CONFIG_MEDIA_TUNER_XC4000 is not set ++# CONFIG_MEDIA_TUNER_MXL5005S is not set ++# CONFIG_MEDIA_TUNER_MXL5007T is not set ++# CONFIG_MEDIA_TUNER_MC44S803 is not set ++# CONFIG_MEDIA_TUNER_MAX2165 is not set ++# CONFIG_MEDIA_TUNER_TDA18218 is not set ++# CONFIG_MEDIA_TUNER_TDA18212 is not set ++CONFIG_VIDEO_FIXED_MINOR_RANGES=y ++# CONFIG_V4L_USB_DRIVERS is not set ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_SOC_CAMERA=y ++CONFIG_SOC_CAMERA_OV2640=y ++CONFIG_VIDEO_ATMEL_ISI=y ++CONFIG_VIDEO_AT91SAM9X5=y ++# CONFIG_RADIO_ADAPTERS is not set ++CONFIG_FB=y ++CONFIG_FB_MODE_HELPERS=y ++CONFIG_FB_ATMEL_HLCD=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++# CONFIG_LCD_CLASS_DEVICE is not set ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++# CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_USB=y ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_OHCI_HCD=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_SERIAL=y ++CONFIG_MMC=y ++# CONFIG_MMC_BLOCK_BOUNCE is not set ++CONFIG_SDIO_UART=m ++CONFIG_MMC_ATMELMCI=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_DRV_AT91RM9200=y ++CONFIG_DMADEVICES=y ++CONFIG_AT_HDMAC=y ++CONFIG_DMATEST=m ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_EXT2_FS=y ++CONFIG_FANOTIFY=y ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_SUMMARY=y ++CONFIG_UBIFS_FS=y ++CONFIG_UBIFS_FS_XATTR=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_CODEPAGE_850=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_STRIP_ASM_SYMS=y ++CONFIG_DEBUG_FS=y ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_FTRACE is not set ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_LL=y ++CONFIG_EARLY_PRINTK=y ++CONFIG_CRYPTO_ECB=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_USER_API_HASH=m ++CONFIG_CRYPTO_USER_API_SKCIPHER=m ++# CONFIG_CRYPTO_HW is not set +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch b/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch new file mode 100644 index 00000000000000..53a6009c49a8a5 --- /dev/null +++ b/patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch @@ -0,0 +1,140 @@ +From ce5e15a7b1efddfd022dd72b9510b5ff85da6325 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 + +Configuration option is now handled by the "dma" device tree property +that links to the corresponding DMA controller. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/mmc/host/atmel-mci.c | 82 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 75 insertions(+), 7 deletions(-) + +diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c +index 9739604..17dc598 100644 +--- a/drivers/mmc/host/atmel-mci.c ++++ b/drivers/mmc/host/atmel-mci.c +@@ -512,12 +512,65 @@ static const struct of_device_id atmci_dt_ids[] = { + + MODULE_DEVICE_TABLE(of, atmci_dt_ids); + ++static int atmci_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 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; ++ struct at_dma_slave *atslave; + u32 slot_id; + + if (!np) { +@@ -531,6 +584,24 @@ atmci_of_init(struct platform_device *pdev) + 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->sdata; ++ ++ /* retrive DMA configuration first */ ++ if (atmci_dma_of_init(np, atslave)) { ++ dev_err(&pdev->dev, "could not find DMA parameters\n"); ++ devm_kfree(&pdev->dev, pdata->dma_slave); ++ devm_kfree(&pdev->dev, pdata); ++ return ERR_PTR(-EINVAL); ++ } ++ + 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", +@@ -2253,16 +2324,13 @@ static bool atmci_filter(struct dma_chan *chan, void *slave) + } + } + +-static bool atmci_configure_dma(struct atmel_mci *host) ++static bool atmci_configure_dma(struct atmel_mci *host, ++ struct mci_platform_data *pdata) + { +- struct mci_platform_data *pdata; +- + if (host == NULL) + return false; + +- pdata = host->pdev->dev.platform_data; +- +- if (pdata && find_slave_dev(pdata->dma_slave)) { ++ if (pdata && pdata->dma_slave && find_slave_dev(pdata->dma_slave)) { + dma_cap_mask_t mask; + + /* Try to grab a DMA channel */ +@@ -2414,7 +2482,7 @@ static int __init atmci_probe(struct platform_device *pdev) + + /* Get MCI capabilities and set operations according to it */ + atmci_get_cap(host); +- if (host->caps.has_dma && atmci_configure_dma(host)) { ++ if (host->caps.has_dma && atmci_configure_dma(host, pdata)) { + host->prepare_data = &atmci_prepare_data_dma; + host->submit_data = &atmci_submit_data_dma; + host->stop_transfer = &atmci_stop_transfer_dma; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch b/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch new file mode 100644 index 00000000000000..58380fba5f962a --- /dev/null +++ b/patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch @@ -0,0 +1,26 @@ +From 0179610747d87250bfba95479c9410511c8158de 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/pinctrl/pinctrl-at91.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index 605fffd..1a2404b 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -58,7 +58,7 @@ static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS]; + + static int gpio_banks; + +-#define PULL_UP (0 << 1) ++#define PULL_UP (1 << 0) + #define MULTI_DRIVE (1 << 1) + #define DEGLITCH (1 << 2) + #define PULL_DOWN (1 << 3) +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch b/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch new file mode 100644 index 00000000000000..ce7077f91ab0cc --- /dev/null +++ b/patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch @@ -0,0 +1,40 @@ +From 5adaa6978db065d84ab39eb02b1035efca7ae7c6 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 + +Drop pullup disable in set_pulldown +if the pullup is not needed the pull will be disable by set_pullup +otherwise we will end up by always disabling the pullup + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/pinctrl/pinctrl-at91.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index 1a2404b..b836567 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -455,8 +455,6 @@ static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) + + static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on) + { +- /* Disable pull-up anyway */ +- __raw_writel(mask, pio + PIO_PUDR); + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); + } + +@@ -753,6 +751,9 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, + pio = pin_to_controller(info, pin_to_bank(pin_id)); + mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + ++ if (config & PULL_UP && config & PULL_DOWN) ++ return -EINVAL; ++ + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + if (info->ops->set_deglitch) +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch b/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch new file mode 100644 index 00000000000000..28cde507aa70ae --- /dev/null +++ b/patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch @@ -0,0 +1,27 @@ +From 4d69b49852403ccd7ac2103908b455a65138aa95 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 + +the nand is on d16 and 8bit + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/boot/dts/at91sam9x5cm.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi +index 4027ac7..ca049fb 100644 +--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi ++++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi +@@ -31,6 +31,7 @@ + atmel,pmecc-cap = <2>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; ++ pinctrl-0 = <&pinctrl_nand_rdy_enable &pinctrl_nand_oe_we_ale_cle &pinctrl_nand_bus_on_d16_8bit>; + status = "okay"; + + at91bootstrap@0 { +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch b/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch new file mode 100644 index 00000000000000..f1b3dffeb7bcd9 --- /dev/null +++ b/patches.at91/0243-pinctrl-at91-fix-debounce-support.patch @@ -0,0 +1,28 @@ +From b325d161ba97b1a84b3dc3fc2edcb60cd4254902 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 + +add missing mask check + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + drivers/pinctrl/pinctrl-at91.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c +index b836567..f2e4ef5 100644 +--- a/drivers/pinctrl/pinctrl-at91.c ++++ b/drivers/pinctrl/pinctrl-at91.c +@@ -759,7 +759,7 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, + if (info->ops->set_deglitch) + info->ops->set_deglitch(pio, mask, config & DEGLITCH); + if (info->ops->set_debounce) +- info->ops->set_debounce(pio, mask, DEBOUNCE, ++ info->ops->set_debounce(pio, mask, config & DEBOUNCE, + (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); + if (info->ops->set_pulldown) + info->ops->set_pulldown(pio, mask, config & PULL_DOWN); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch b/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch new file mode 100644 index 00000000000000..7e19cbdb8810cd --- /dev/null +++ b/patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch @@ -0,0 +1,36 @@ +From b3b0a725ce779a5ff6fa9b05edced0ee2f9dd836 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. + +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> +--- + arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +index 6820417..e24116d 100644 +--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi ++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +@@ -141,14 +141,14 @@ + #size-cells = <0>; + + btn3 { +- label = "Buttin 3"; ++ label = "Button 3"; + gpios = <&pioA 30 1>; + linux,code = <0x103>; + gpio-key,wakeup; + }; + + btn4 { +- label = "Buttin 4"; ++ label = "Button 4"; + gpios = <&pioA 31 1>; + linux,code = <0x104>; + gpio-key,wakeup; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch b/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch new file mode 100644 index 00000000000000..56da209e40f6ad --- /dev/null +++ b/patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch @@ -0,0 +1,61 @@ +From 2bc3ffd68ba8a607974259eac81a93889a576c8d 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 + +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. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com> +Cc: stable <stable@vger.kernel.org> [v3.6] +--- + arch/arm/mach-at91/board-neocore926.c | 2 +- + arch/arm/mach-at91/board-sam9261ek.c | 2 +- + arch/arm/mach-at91/board-sam9263ek.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c +index 7fb2a8f..05e2566 100644 +--- a/arch/arm/mach-at91/board-neocore926.c ++++ b/arch/arm/mach-at91/board-neocore926.c +@@ -131,7 +131,7 @@ static struct spi_board_info neocore926_spi_devices[] = { + .max_speed_hz = 125000 * 16, + .bus_num = 0, + .platform_data = &ads_info, +- .irq = AT91SAM9263_ID_IRQ1, ++ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1, + }, + #endif + }; +diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c +index b8900d5..a043192 100644 +--- a/arch/arm/mach-at91/board-sam9261ek.c ++++ b/arch/arm/mach-at91/board-sam9261ek.c +@@ -311,7 +311,7 @@ static struct spi_board_info ek_spi_devices[] = { + .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ + .bus_num = 0, + .platform_data = &ads_info, +- .irq = AT91SAM9261_ID_IRQ0, ++ .irq = NR_IRQS_LEGACY + AT91SAM9261_ID_IRQ0, + .controller_data = (void *) AT91_PIN_PA28, /* CS pin */ + }, + #endif +diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c +index d4dd017..e0cef65 100644 +--- a/arch/arm/mach-at91/board-sam9263ek.c ++++ b/arch/arm/mach-at91/board-sam9263ek.c +@@ -134,7 +134,7 @@ static struct spi_board_info ek_spi_devices[] = { + .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */ + .bus_num = 0, + .platform_data = &ads_info, +- .irq = AT91SAM9263_ID_IRQ1, ++ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1, + }, + #endif + }; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch b/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch new file mode 100644 index 00000000000000..12f7c8740efd22 --- /dev/null +++ b/patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch @@ -0,0 +1,43 @@ +From 075b74ccf13912a227ca33f103e29f3b645fb4da 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 + +Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + arch/arm/mach-at91/Kconfig | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig +index 79d08ed..b2ce9c4 100644 +--- a/arch/arm/mach-at91/Kconfig ++++ b/arch/arm/mach-at91/Kconfig +@@ -19,21 +19,15 @@ config AT91_SAM9G45_RESET + + config SOC_AT91SAM9 + bool +- select GENERIC_CLOCKEVENTS + select CPU_ARM926T ++ select GENERIC_CLOCKEVENTS ++ select MULTI_IRQ_HANDLER ++ select SPARSE_IRQ + + menu "Atmel AT91 System-on-Chip" + + comment "Atmel AT91 Processor" + +-config SOC_AT91SAM9 +- bool +- select CPU_ARM926T +- select MULTI_IRQ_HANDLER +- select SPARSE_IRQ +- select AT91_SAM9_TIME +- select AT91_SAM9_SMC +- + config SOC_AT91RM9200 + bool "AT91RM9200" + select CPU_ARM920T +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0249-ARM-at91-fix-at91x40-build.patch b/patches.at91/0249-ARM-at91-fix-at91x40-build.patch new file mode 100644 index 00000000000000..a4d8b6f8bf8ff0 --- /dev/null +++ b/patches.at91/0249-ARM-at91-fix-at91x40-build.patch @@ -0,0 +1,33 @@ +From e5e253baa31df4db3db0db218019e425bd4df9cd 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 + +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. + +This changes at91x40 in the same way that the other platforms +were changed. + +Signed-off-by: Arnd Bergmann <arnd@arndb.de> +Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +--- + arch/arm/mach-at91/at91x40.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c +index 46090e6..efbb93f 100644 +--- a/arch/arm/mach-at91/at91x40.c ++++ b/arch/arm/mach-at91/at91x40.c +@@ -88,6 +88,6 @@ void __init at91x40_init_interrupts(unsigned int priority[NR_AIC_IRQS]) + if (!priority) + priority = at91x40_default_irq_priority; + +- at91_aic_init(priority); ++ at91_aic_init(priority, at91_extern_irq); + } + +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch b/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch new file mode 100644 index 00000000000000..1949b65ee7b39e --- /dev/null +++ b/patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch @@ -0,0 +1,76 @@ +From a2dcc54f95495c63504c6ee51ff1082343e5f4be 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 + +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 +specific code to the at91_aic_init() function. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com> +Cc: stable <stable@vger.kernel.org> [v3.6] +--- + arch/arm/mach-at91/generic.h | 3 ++- + arch/arm/mach-at91/irq.c | 9 +++++++-- + arch/arm/mach-at91/setup.c | 2 +- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h +index f496506..b62f560e 100644 +--- a/arch/arm/mach-at91/generic.h ++++ b/arch/arm/mach-at91/generic.h +@@ -26,7 +26,8 @@ extern void __init at91_dt_initialize(void); + extern void __init at91_init_irq_default(void); + extern void __init at91_init_interrupts(unsigned int priority[]); + extern void __init at91x40_init_interrupts(unsigned int priority[]); +-extern void __init at91_aic_init(unsigned int priority[]); ++extern void __init at91_aic_init(unsigned int priority[], ++ unsigned int ext_irq_mask); + 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, +diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c +index 1e02c0e..febc2ee 100644 +--- a/arch/arm/mach-at91/irq.c ++++ b/arch/arm/mach-at91/irq.c +@@ -502,14 +502,19 @@ int __init at91_aic5_of_init(struct device_node *node, + /* + * Initialize the AIC interrupt controller. + */ +-void __init at91_aic_init(unsigned int *priority) ++void __init at91_aic_init(unsigned int *priority, unsigned int ext_irq_mask) + { + unsigned int i; + int irq_base; + +- if (at91_aic_pm_init()) ++ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs) ++ * sizeof(*at91_extern_irq), GFP_KERNEL); ++ ++ if (at91_aic_pm_init() || at91_extern_irq == NULL) + panic("Unable to allocate bit maps\n"); + ++ *at91_extern_irq = ext_irq_mask; ++ + at91_aic_base = ioremap(AT91_AIC, 512); + if (!at91_aic_base) + panic("Unable to ioremap AIC registers\n"); +diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c +index a37bebc..7cf3fef 100644 +--- a/arch/arm/mach-at91/setup.c ++++ b/arch/arm/mach-at91/setup.c +@@ -48,7 +48,7 @@ void __init at91_init_irq_default(void) + void __init at91_init_interrupts(unsigned int *priority) + { + /* Initialize the AIC interrupt controller */ +- at91_aic_init(priority); ++ at91_aic_init(priority, at91_extern_irq); + + /* Enable GPIO interrupts */ + at91_gpio_irq_setup(); +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch b/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch new file mode 100644 index 00000000000000..033f4624ebe894 --- /dev/null +++ b/patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.patch @@ -0,0 +1,154 @@ +From c4e770c2e3cb8a3c8372f2f7a7cddcc8aa5e1160 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 + +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, +and call i2c_register_board_info(int busnum, ...) to register device +if using -1, we do not know the value of busnum + +In order to solve this issue, set the platform device ID as a fix number +Here using 0 to match the busnum used in i2c_regsiter_board_info() + +Signed-off-by: Bo Shen <voice.shen@atmel.com> +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> +Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com> +--- + arch/arm/mach-at91/at91rm9200.c | 2 +- + arch/arm/mach-at91/at91rm9200_devices.c | 2 +- + arch/arm/mach-at91/at91sam9260.c | 4 ++-- + arch/arm/mach-at91/at91sam9260_devices.c | 2 +- + arch/arm/mach-at91/at91sam9261.c | 4 ++-- + arch/arm/mach-at91/at91sam9261_devices.c | 2 +- + arch/arm/mach-at91/at91sam9263.c | 2 +- + arch/arm/mach-at91/at91sam9263_devices.c | 2 +- + arch/arm/mach-at91/at91sam9rl_devices.c | 2 +- + 9 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c +index a454734..a3e4710 100644 +--- a/arch/arm/mach-at91/at91rm9200.c ++++ b/arch/arm/mach-at91/at91rm9200.c +@@ -187,7 +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, "i2c-at91rm9200", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &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/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c +index 7cd8053..1e122bc 100644 +--- a/arch/arm/mach-at91/at91rm9200_devices.c ++++ b/arch/arm/mach-at91/at91rm9200_devices.c +@@ -512,7 +512,7 @@ static struct resource twi_resources[] = { + + static struct platform_device at91rm9200_twi_device = { + .name = "i2c-at91rm9200", +- .id = -1, ++ .id = 0, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), + }; +diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c +index 23a8cfb..50b27d0 100644 +--- a/arch/arm/mach-at91/at91sam9260.c ++++ b/arch/arm/mach-at91/at91sam9260.c +@@ -203,8 +203,8 @@ 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, "i2c-at91sam9260", &twi_clk), +- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &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/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c +index b169d64..e2a3e14 100644 +--- a/arch/arm/mach-at91/at91sam9260_devices.c ++++ b/arch/arm/mach-at91/at91sam9260_devices.c +@@ -418,7 +418,7 @@ static struct resource twi_resources[] = { + }; + + static struct platform_device at91sam9260_twi_device = { +- .id = -1, ++ .id = 0, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), + }; +diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c +index 93a24e9..4d262f3 100644 +--- a/arch/arm/mach-at91/at91sam9261.c ++++ b/arch/arm/mach-at91/at91sam9261.c +@@ -178,8 +178,8 @@ 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, "i2c-at91sam9261", &twi_clk), +- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &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/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c +index ac212e9..cf444a6 100644 +--- a/arch/arm/mach-at91/at91sam9261_devices.c ++++ b/arch/arm/mach-at91/at91sam9261_devices.c +@@ -319,7 +319,7 @@ static struct resource twi_resources[] = { + }; + + static struct platform_device at91sam9261_twi_device = { +- .id = -1, ++ .id = 0, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), + }; +diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c +index 7639f6b..ed390f6 100644 +--- a/arch/arm/mach-at91/at91sam9263.c ++++ b/arch/arm/mach-at91/at91sam9263.c +@@ -193,7 +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, "i2c-at91sam9260", &twi_clk), ++ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &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/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c +index ac61544..095ecc9e 100644 +--- a/arch/arm/mach-at91/at91sam9263_devices.c ++++ b/arch/arm/mach-at91/at91sam9263_devices.c +@@ -602,7 +602,7 @@ static struct resource twi_resources[] = { + + static struct platform_device at91sam9263_twi_device = { + .name = "i2c-at91sam9260", +- .id = -1, ++ .id = 0, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), + }; +diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c +index a3e9b08..5374e24 100644 +--- a/arch/arm/mach-at91/at91sam9rl_devices.c ++++ b/arch/arm/mach-at91/at91sam9rl_devices.c +@@ -349,7 +349,7 @@ static struct resource twi_resources[] = { + + static struct platform_device at91sam9rl_twi_device = { + .name = "i2c-at91sam9g20", +- .id = -1, ++ .id = 0, + .resource = twi_resources, + .num_resources = ARRAY_SIZE(twi_resources), + }; +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch b/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch new file mode 100644 index 00000000000000..0d588cfdb363a5 --- /dev/null +++ b/patches.at91/0252-net-macb-align-ring-buffer-function-with-mainline.patch @@ -0,0 +1,43 @@ +From 550797fd7773e9ebe542e55e770381273fe1a2f7 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 + +Available number of descriptors in ring buffer function by David Laight. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/net/ethernet/cadence/macb.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c +index e3168bf..1f7b3a3 100644 +--- a/drivers/net/ethernet/cadence/macb.c ++++ b/drivers/net/ethernet/cadence/macb.c +@@ -31,12 +31,12 @@ + #include "macb.h" + + #define RX_BUFFER_SIZE 128 +-#define RX_RING_SIZE 512 ++#define RX_RING_SIZE 512 /* must be power of 2 */ + #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_SIZE 128 /* must be power of 2 */ + #define TX_RING_BYTES (sizeof(struct macb_dma_desc) * TX_RING_SIZE) + + /* minimum number of free TX descriptors before waking up TX process */ +@@ -63,7 +63,7 @@ static unsigned int macb_tx_ring_wrap(unsigned int index) + + static unsigned int macb_tx_ring_avail(struct macb *bp) + { +- return TX_RING_SIZE - (bp->tx_head - bp->tx_tail); ++ return (bp->tx_tail - bp->tx_head) & (TX_RING_SIZE - 1); + } + + static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index) +-- +1.8.0.197.g5a90748 + diff --git a/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch b/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch new file mode 100644 index 00000000000000..74d82eb3c53740 --- /dev/null +++ b/patches.at91/0253-net-macb-move-to-circ_buf-macros-and-fix-initial-con.patch @@ -0,0 +1,90 @@ +From 10c4df2b1b3697e748032c8729d26b262eca651d 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 + +Move to circular buffers management macro and correct an error +with circular buffer initial condition. + +Without this patch, the macb_tx_ring_avail() function was +not reporting the proper ring availability at startup: +macb macb: eth0: BUG! Tx Ring full when queue awake! +macb macb: eth0: tx_head = 0, tx_tail = 0 +And hanginig forever... + +I remove the macb_tx_ring_avail() function and use the +proven macros from circ_buf.h. CIRC_CNT() is used in the +"consumer" part of the driver: macb_tx_interrupt() to match +advice from Documentation/circular-buffers.txt. + +Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com> +--- + drivers/net/ethernet/cadence/macb.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c +index 1f7b3a3..9647d37 100644 +--- a/drivers/net/ethernet/cadence/macb.c ++++ b/drivers/net/ethernet/cadence/macb.c +@@ -15,6 +15,7 @@ + #include <linux/moduleparam.h> + #include <linux/kernel.h> + #include <linux/types.h> ++#include <linux/circ_buf.h> + #include <linux/slab.h> + #include <linux/init.h> + #include <linux/interrupt.h> +@@ -39,8 +40,8 @@ + #define TX_RING_SIZE 128 /* must be power of 2 */ + #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) ++/* level of occupied TX descriptors under which we wake up TX process */ ++#define MACB_TX_WAKEUP_THRESH (3 * TX_RING_SIZE / 4) + + #define MACB_RX_INT_FLAGS (MACB_BIT(RCOMP) | MACB_BIT(RXUBR) \ + | MACB_BIT(ISR_ROVR)) +@@ -61,11 +62,6 @@ 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 (bp->tx_tail - bp->tx_head) & (TX_RING_SIZE - 1); +-} +- + static struct macb_dma_desc *macb_tx_desc(struct macb *bp, unsigned int index) + { + return &bp->tx_ring[macb_tx_ring_wrap(index)]; +@@ -495,7 +491,8 @@ static void macb_tx_interrupt(struct macb *bp) + + bp->tx_tail = tail; + if (netif_queue_stopped(bp->dev) +- && macb_tx_ring_avail(bp) > MACB_TX_WAKEUP_THRESH) ++ && CIRC_CNT(bp->tx_head, bp->tx_tail, ++ TX_RING_SIZE) <= MACB_TX_WAKEUP_THRESH) + netif_wake_queue(bp->dev); + } + +@@ -808,7 +805,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 (macb_tx_ring_avail(bp) < 1) { ++ if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1) { + netif_stop_queue(dev); + spin_unlock_irqrestore(&bp->lock, flags); + netdev_err(bp->dev, "BUG! Tx Ring full when queue awake!\n"); +@@ -845,7 +842,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) + + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART)); + +- if (macb_tx_ring_avail(bp) < 1) ++ if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1) + netif_stop_queue(dev); + + spin_unlock_irqrestore(&bp->lock, flags); +-- +1.8.0.197.g5a90748 + @@ -289,3 +289,253 @@ patches.armadillo800/0104-ARM-mach-shmobile-armadillo800eva-Fix-GPIO-buttons-d.p patches.armadillo800/0105-ARM-mach-shmobile-armadillo800eva-Enable-power-butto.patch patches.armadillo800/0106-ARM-shmobile-armadillo800eva-fixup-sound-card-detect.patch patches.armadillo800/0107-ARM-shmobile-armadillo800eva-enable-rw-rootfs-mount.patch + + +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/0004-MAINTAINERS-add-entry-for-Atmel-timer-counter-TC.patch +patches.at91/0005-MAINTAINERS-remove-non-responding-web-link-for-atmel.patch +patches.at91/0006-ARM-at91-change-AT91-Kconfig-entry-comment.patch +patches.at91/0007-ARM-at91-Kconfig-change-at91sam9g45-entry.patch +patches.at91/0008-ARM-at91-Kconfig-add-comment-to-at91sam9x5-family-en.patch +patches.at91/0009-ARM-at91-Kconfig-add-clarifications-to-AT91SAM9M10G4.patch +patches.at91/0010-ARM-at91-Kconfig-add-AT91SAM9x5-family-to-AT91_EARLY.patch +patches.at91/0011-ARM-at91-Kconfig-website-link-for-AT91SAM9G20-EK.patch +patches.at91/0012-rtc-Kconfig-remove-dependency-for-AT91-rtc-driver.patch +patches.at91/0013-Input-Kconfig-remove-dependency-for-atmel_tsadcc-dri.patch +patches.at91/0014-hwrng-Kconfig-remove-dependency-for-atmel-rng-driver.patch +patches.at91/0015-ARM-at91-uncompress-Store-UART-address-in-a-variable.patch +patches.at91/0016-ARM-at91-uncompress-autodetect-the-uart-to-use.patch +patches.at91/0017-ARM-at91-drop-at91_set_serial_console.patch +patches.at91/0018-ARM-at91-do-not-pin-mux-the-UARTs-in-init_early.patch +patches.at91/0019-ARM-at91-move-at91_init_leds-to-board-init.patch +patches.at91/0020-ARM-at91-pm-select-memory-controler-at-runtime.patch +patches.at91/0021-ARM-at91-add-SOC_AT91SAM9-kconfig-option-to-factoris.patch +patches.at91/0022-ARN-at91-introduce-SOC_AT91xxx-define-to-allow-to-co.patch +patches.at91/0023-ARM-at91-dt-do-not-specify-the-board-any-more.patch +patches.at91/0024-ARM-at91-add-defconfig-for-device-tree.patch +patches.at91/0025-ARM-at91-add-at91sam9260-DT-support.patch +patches.at91/0026-arm-at91-add-Calao-TNY-A9260-and-TNY-A9G20-board-sup.patch +patches.at91/0027-ARM-at91-add-at91sam9g20ek-boards-dt-support.patch +patches.at91/0028-ARM-at91-USB-A926x-update-nand-partition.patch +patches.at91/0029-ARM-at91-Calao-USB-A926x-factorize-common-binding-in.patch +patches.at91/0030-ARM-at91-DT-add-Calao-USB-A9260-DT-support.patch +patches.at91/0031-ARM-at91-standard-device-init-only-if-DT-is-not-popu.patch +patches.at91/0032-ARM-at91-add-at91sam9263-DT-support.patch +patches.at91/0033-ARM-at91-add-at91sam9263ek-DT-support.patch +patches.at91/0034-ARM-at91-DT-add-Calao-USB-A9263-board-support.patch +patches.at91/0035-ARM-at91-DT-add-Calao-TNY-A9263-board-support.patch +patches.at91/0036-ARM-at91-add-kizbox-board-dt-support.patch +patches.at91/0037-Ethernut-5-board-support.patch +patches.at91/0038-ARM-at91-Add-machine-header-file-for-AT91SAM9N12-SoC.patch +patches.at91/0039-ARM-at91-Add-machine-files-for-AT91SAM9N12-SoC.patch +patches.at91/0040-ARM-at91-Add-DT-description-files-for-AT91SAM9N12-EK.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/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/0222-mtd-atmel_nand-fix-the-compile-error-which-miss-labe.patch +patches.at91/0223-pinctrl-at91-fix-compatible-order.patch +patches.at91/0224-pinctrl-at91-fix-gpio-irq-support.patch +patches.at91/0225-i2c-at91-add-pinctrl.patch +patches.at91/0226-media-atmel_isi-add-pinctrl.patch +patches.at91/0227-mmc-at91-add-pinctrl.patch +patches.at91/0228-video-atmel_lcdfb-add-pinctrl.patch +patches.at91/0229-arm-at91sam9g45-add-missing-uart-pinctrl-node.patch +patches.at91/0230-arm-at91sam9263-add-missing-uart-pinctrl-node.patch +patches.at91/0231-arm-at91sam9260-add-missing-uart-pinctrl-node.patch +patches.at91/0232-arm-at91sam9x5-sync-with-the-mainline.patch +patches.at91/0233-ARM-at91-DT-add-i2c-mmc-nand-pinctrl-in-device-tree-.patch +patches.at91/0234-at91sam9x5-add-lcd-pinctrl-support.patch +patches.at91/0235-arm-at91sam9x5ek-drop-temporary-pinmux.patch +patches.at91/0236-video-atmel-lcd-only-request-the-pinctrl-once.patch +patches.at91/0237-ARM-at91-add-at91-3.4-trunk-contents.txt-file.patch +patches.at91/0238-ARM-at91-add-defconfig-for-sam9x5-family.patch +patches.at91/0239-MMC-atmel-mci-add-device-tree-property-for-configura.patch +patches.at91/0240-pinctrl-at19-fix-typo-on-PULL_UP.patch +patches.at91/0241-pinctrl-at91-fix-pull-down-support.patch +patches.at91/0242-arm-at91sam9xcm-add-specific-nand-pinctrl.patch +patches.at91/0243-pinctrl-at91-fix-debounce-support.patch +patches.at91/0245-ARM-at91-dts-at91sam9g20ek_common-Fix-typos-in-butto.patch +patches.at91/0246-ARM-at91-fix-external-interrupt-specification-in-boa.patch +patches.at91/0248-ARM-at91-drop-duplicated-config-SOC_AT91SAM9-entry.patch +patches.at91/0249-ARM-at91-fix-at91x40-build.patch +patches.at91/0250-ARM-at91-fix-external-interrupts-in-non-DT-case.patch +patches.at91/0251-ARM-at91-i2c-change-id-to-let-i2c-at91-work.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 + + |