[ARM] 5319/1: AT91: support AT91CAP9 revC CPUs
authorStelian Pop <stelian@popies.net>
Wed, 22 Oct 2008 12:52:08 +0000 (13:52 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Mon, 1 Dec 2008 17:22:07 +0000 (17:22 +0000)
The AT91CAP9 revC CPU has a few differences over the previous,
revB CPU which was distributed in small quantities only (revA was
an internal Atmel product only).

This patch adds the detection routines to recognize the different
AT91CAP9 revisions (based on the PMC subsystem version number), and
uses them to:
- activate a workaround for the external interrupts levels
  (on revB CPUs)
- set the UDPHS_BYPASS bit (on revB CPUs)
- set AT91_GPBR register address to the correct offset
  (0xfffffd50 on revB, 0xfffffd60 on revC)

For debugging usage, the CPU revision can be found in /proc/cpuinfo
on the 'Revision' line.

This patch is extracted from Andrew Victor's -at91 patch (2.6.27-at91.patch)
where it has been tested for the last 6 months.

Signed-off-by: Stelian Pop <stelian@popies.net>
Signed-off-by: Andrew Victor <linux@maxim.org.za>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/cpu.h
drivers/rtc/rtc-at91sam9.c

index 0fc0ada..0a38c69 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+
+#include <mach/cpu.h>
 #include <mach/at91cap9.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_rstc.h>
@@ -317,6 +319,12 @@ void __init at91cap9_initialize(unsigned long main_clock)
 
        /* Register GPIO subsystem */
        at91_gpio_init(at91cap9_gpio, 4);
+
+       /* Remember the silicon revision */
+       if (cpu_is_at91cap9_revB())
+               system_rev = 0xB;
+       else if (cpu_is_at91cap9_revC())
+               system_rev = 0xC;
 }
 
 /* --------------------------------------------------------------------
index 3a36182..9eca220 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/irq.h>
 
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -21,6 +22,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <mach/board.h>
+#include <mach/cpu.h>
 #include <mach/gpio.h>
 #include <mach/at91cap9.h>
 #include <mach/at91cap9_matrix.h>
@@ -69,6 +71,9 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
        if (!data)
                return;
 
+       if (cpu_is_at91cap9_revB())
+               set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
+
        /* Enable VBus control for UHP ports */
        for (i = 0; i < data->ports; i++) {
                if (data->vbus_pin[i])
@@ -151,8 +156,13 @@ static struct platform_device at91_usba_udc_device = {
 
 void __init at91_add_device_usba(struct usba_platform_data *data)
 {
-       at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
-                                         AT91_MATRIX_UDPHS_BYPASS_LOCK);
+       if (cpu_is_at91cap9_revB()) {
+               set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
+               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS |
+                                                 AT91_MATRIX_UDPHS_BYPASS_LOCK);
+       }
+       else
+               at91_sys_write(AT91_MATRIX_UDPHS, AT91_MATRIX_SELECT_UDPHS);
 
        /*
         * Invalid pins are 0 on AT91, but the usba driver is shared
@@ -850,6 +860,9 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
        if (!data)
                return;
 
+       if (cpu_is_at91cap9_revB())
+               set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
+
        at91_set_A_periph(AT91_PIN_PC1, 0);     /* LCDHSYNC */
        at91_set_A_periph(AT91_PIN_PC2, 0);     /* LCDDOTCK */
        at91_set_A_periph(AT91_PIN_PC3, 0);     /* LCDDEN */
index 43b37bc..83a1a0f 100644 (file)
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/irq.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
 
 #include <mach/board.h>
 #include <mach/gpio.h>
@@ -376,10 +374,8 @@ static void __init cap9adk_board_init(void)
        /* Serial */
        at91_add_device_serial();
        /* USB Host */
-       set_irq_type(AT91CAP9_ID_UHP, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_usbh(&cap9adk_usbh_data);
        /* USB HS */
-       set_irq_type(AT91CAP9_ID_UDPHS, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_usba(&cap9adk_usba_udc_data);
        /* SPI */
        at91_add_device_spi(cap9adk_spi_devices, ARRAY_SIZE(cap9adk_spi_devices));
@@ -396,7 +392,6 @@ static void __init cap9adk_board_init(void)
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* LCD Controller */
-       set_irq_type(AT91CAP9_ID_LCDC, IRQ_TYPE_LEVEL_HIGH);
        at91_add_device_lcdc(&cap9adk_lcdc_data);
        /* AC97 */
        at91_add_device_ac97(&cap9adk_ac97_data);
index 2e3f289..9561e33 100644 (file)
@@ -23,6 +23,7 @@
 #define                AT91_PMC_PCK            (1 <<  0)               /* Processor Clock */
 #define                AT91RM9200_PMC_UDP      (1 <<  1)               /* USB Devcice Port Clock [AT91RM9200 only] */
 #define                AT91RM9200_PMC_MCKUDP   (1 <<  2)               /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
+#define                AT91CAP9_PMC_DDR        (1 <<  2)               /* DDR Clock [AT91CAP9 revC only] */
 #define                AT91RM9200_PMC_UHP      (1 <<  4)               /* USB Host Port Clock [AT91RM9200 only] */
 #define                AT91SAM926x_PMC_UHP     (1 <<  6)               /* USB Host Port Clock [AT91SAM926x only] */
 #define                AT91CAP9_PMC_UHP        (1 <<  6)               /* USB Host Port Clock [AT91CAP9 only] */
 #define                AT91_PMC_LOCKB          (1 <<  2)               /* PLLB Lock */
 #define                AT91_PMC_MCKRDY         (1 <<  3)               /* Master Clock */
 #define                AT91_PMC_LOCKU          (1 <<  6)               /* UPLL Lock [AT91CAP9 only] */
+#define                AT91_PMC_OSCSEL         (1 <<  7)               /* Slow Clock Oscillator [AT91CAP9 revC only] */
 #define                AT91_PMC_PCK0RDY        (1 <<  8)               /* Programmable Clock 0 */
 #define                AT91_PMC_PCK1RDY        (1 <<  9)               /* Programmable Clock 1 */
 #define                AT91_PMC_PCK2RDY        (1 << 10)               /* Programmable Clock 2 */
 #define                AT91_PMC_PCK3RDY        (1 << 11)               /* Programmable Clock 3 */
 #define        AT91_PMC_IMR            (AT91_PMC + 0x6c)       /* Interrupt Mask Register */
 
+#define AT91_PMC_PROT          (AT91_PMC + 0xe4)       /* Protect Register [AT91CAP9 revC only] */
+#define                AT91_PMC_PROTKEY        0x504d4301      /* Activation Code */
+
+#define AT91_PMC_VER           (AT91_PMC + 0xfc)       /* PMC Module Version [AT91CAP9 only] */
+
 #endif
index 4a4b641..d8c1ede 100644 (file)
 #define AT91_RTT       (0xfffffd20 - AT91_BASE_SYS)
 #define AT91_PIT       (0xfffffd30 - AT91_BASE_SYS)
 #define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
-#define AT91_GPBR      (0xfffffd50 - AT91_BASE_SYS)
+#define AT91_GPBR      (cpu_is_at91cap9_revB() ?       \
+                       (0xfffffd50 - AT91_BASE_SYS) :  \
+                       (0xfffffd60 - AT91_BASE_SYS))
 
 #define AT91_USART0    AT91CAP9_BASE_US0
 #define AT91_USART1    AT91CAP9_BASE_US1
index dbfd9f7..c554c3e 100644 (file)
@@ -49,6 +49,17 @@ static inline unsigned long at91_arch_identify(void)
        return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
 }
 
+#ifdef CONFIG_ARCH_AT91CAP9
+#include <mach/at91_pmc.h>
+
+#define ARCH_REVISION_CAP9_B   0x399
+#define ARCH_REVISION_CAP9_C   0x601
+
+static inline unsigned long at91cap9_rev_identify(void)
+{
+       return (at91_sys_read(AT91_PMC_VER));
+}
+#endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
 #define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
@@ -90,8 +101,12 @@ static inline unsigned long at91_arch_identify(void)
 
 #ifdef CONFIG_ARCH_AT91CAP9
 #define cpu_is_at91cap9()      (at91_cpu_identify() == ARCH_ID_AT91CAP9)
+#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
+#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C)
 #else
 #define cpu_is_at91cap9()      (0)
+#define cpu_is_at91cap9_revB() (0)
+#define cpu_is_at91cap9_revC() (0)
 #endif
 
 /*
index 2133f37..d5e4e63 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <mach/board.h>
 #include <mach/at91_rtt.h>
+#include <mach/cpu.h>
 
 
 /*