ARM: at91: introduce SAMA5 support
authorLudovic Desroches <ludovic.desroches@atmel.com>
Fri, 22 Mar 2013 13:24:12 +0000 (13:24 +0000)
committerNicolas Ferre <nicolas.ferre@atmel.com>
Tue, 26 Mar 2013 11:18:04 +0000 (12:18 +0100)
This patch introduces the SAMA5 support and a generic board file for SAMA5
devices. It also updates the PMC driver to manage clock division which is a
requirement since some peripherals can't work at the bus frequency on SAMA5.

Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/board-dt-sama5.c [new file with mode: 0644]
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/clock.h
arch/arm/mach-at91/include/mach/at91_pmc.h
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/sama5d3.h [new file with mode: 0644]
arch/arm/mach-at91/sama5d3.c [new file with mode: 0644]
arch/arm/mach-at91/setup.c
arch/arm/mach-at91/soc.h

index 8b35c7f1634fe3ca9166b2316878e7b321e22265..02802386b894e99dc074a16bd44fb15d508efd82 100644 (file)
@@ -29,6 +29,14 @@ config SOC_AT91SAM9
        select MULTI_IRQ_HANDLER
        select SPARSE_IRQ
 
+config SOC_SAMA5
+       bool
+       select AT91_SAM9_TIME
+       select CPU_V7
+       select GENERIC_CLOCKEVENTS
+       select MULTI_IRQ_HANDLER
+       select SPARSE_IRQ
+
 menu "Atmel AT91 System-on-Chip"
 
 choice
@@ -41,10 +49,27 @@ config SOC_SAM_V4_V5
          Select this if you are using one of Atmel's AT91SAM9, AT91RM9200
          or AT91X40 SoC.
 
+config SOC_SAM_V7
+       bool "Cortex A5"
+       help
+         Select this if you are using one of Atmel's SAMA5D3 SoC.
+
 endchoice
 
 comment "Atmel AT91 Processor"
 
+if SOC_SAM_V7
+config SOC_SAMA5D3
+       bool "SAMA5D3 family"
+       depends on SOC_SAM_V7
+       select SOC_SAMA5
+       select HAVE_FB_ATMEL
+       select HAVE_AT91_DBGU1
+       help
+         Select this if you are using one of Atmel's SAMA5D3 family SoC.
+         This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35.
+endif
+
 if SOC_SAM_V4_V5
 config SOC_AT91RM9200
        bool "AT91RM9200"
@@ -134,6 +159,14 @@ config MACH_AT91SAM9_DT
          Select this if you want to experiment device-tree with
          an Atmel Evaluation Kit.
 
+config MACH_SAMA5_DT
+       bool "Atmel SAMA5 Evaluation Kits with device-tree support"
+       depends on SOC_SAMA5
+       select USE_OF
+       help
+         Select this if you want to experiment device-tree with
+         an Atmel Evaluation Kit.
+
 # ----------------------------------------------------------
 
 comment "AT91 Feature Selections"
index 74e9b5b637bff8440001081163ce8c62674fe785..788562dccb435f1d8b3ec0be9a79af58cb797a13 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o
 obj-$(CONFIG_SOC_AT91SAM9N12)  += at91sam9n12.o
 obj-$(CONFIG_SOC_AT91SAM9X5)   += at91sam9x5.o
 obj-$(CONFIG_SOC_AT91SAM9RL)   += at91sam9rl.o
+obj-$(CONFIG_SOC_SAMA5D3)      += sama5d3.o
 
 obj-$(CONFIG_ARCH_AT91RM9200)  += at91rm9200_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o
@@ -91,6 +92,9 @@ obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 obj-$(CONFIG_MACH_AT91RM9200_DT) += board-dt-rm9200.o
 obj-$(CONFIG_MACH_AT91SAM9_DT) += board-dt-sam9.o
 
+# SAMA5 board with device-tree
+obj-$(CONFIG_MACH_SAMA5_DT) += board-dt-sama5.o
+
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)    += board-eb01.o
 
diff --git a/arch/arm/mach-at91/board-dt-sama5.c b/arch/arm/mach-at91/board-dt-sama5.c
new file mode 100644 (file)
index 0000000..705305e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  Setup code for SAMA5 Evaluation Kits with Device Tree support
+ *
+ *  Copyright (C) 2013 Atmel,
+ *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/micrel_phy.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "at91_aic.h"
+#include "generic.h"
+
+
+static const struct of_device_id irq_of_match[] __initconst = {
+
+       { .compatible = "atmel,sama5d3-aic", .data = at91_aic5_of_init },
+       { /*sentinel*/ }
+};
+
+static void __init at91_dt_init_irq(void)
+{
+       of_irq_init(irq_of_match);
+}
+
+static int ksz9021rn_phy_fixup(struct phy_device *phy)
+{
+       int value;
+
+#define GMII_RCCPSR    260
+#define GMII_RRDPSR    261
+#define GMII_ERCR      11
+#define GMII_ERDWR     12
+
+       /* Set delay values */
+       value = GMII_RCCPSR | 0x8000;
+       phy_write(phy, GMII_ERCR, value);
+       value = 0xF2F4;
+       phy_write(phy, GMII_ERDWR, value);
+       value = GMII_RRDPSR | 0x8000;
+       phy_write(phy, GMII_ERCR, value);
+       value = 0x2222;
+       phy_write(phy, GMII_ERDWR, value);
+
+       return 0;
+}
+
+static void __init sama5_dt_device_init(void)
+{
+       if (of_machine_is_compatible("atmel,sama5d3xcm"))
+               phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
+                       ksz9021rn_phy_fixup);
+
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *sama5_dt_board_compat[] __initdata = {
+       "atmel,sama5",
+       NULL
+};
+
+DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)")
+       /* Maintainer: Atmel */
+       .init_time      = at91sam926x_pit_init,
+       .map_io         = at91_map_io,
+       .handle_irq     = at91_aic5_handle_irq,
+       .init_early     = at91_dt_initialize,
+       .init_irq       = at91_dt_init_irq,
+       .init_machine   = sama5_dt_device_init,
+       .dt_compat      = sama5_dt_board_compat,
+MACHINE_END
index 33361505c0cd70cc3171f64ec4d5306670b2cd4b..da841885d01c724c9b399de0080137a5c7be7ef3 100644 (file)
@@ -54,7 +54,10 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
  */
 #define cpu_has_utmi()         (  cpu_is_at91sam9rl() \
                                || cpu_is_at91sam9g45() \
-                               || cpu_is_at91sam9x5())
+                               || cpu_is_at91sam9x5() \
+                               || cpu_is_sama5d3())
+
+#define cpu_has_1056M_plla()   (cpu_is_sama5d3())
 
 #define cpu_has_800M_plla()    (  cpu_is_at91sam9g20() \
                                || cpu_is_at91sam9g45() \
@@ -75,7 +78,8 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
                                || cpu_is_at91sam9n12()))
 
 #define cpu_has_upll()         (cpu_is_at91sam9g45() \
-                               || cpu_is_at91sam9x5())
+                               || cpu_is_at91sam9x5() \
+                               || cpu_is_sama5d3())
 
 /* USB host HS & FS */
 #define cpu_has_uhp()          (!cpu_is_at91sam9rl())
@@ -83,18 +87,22 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
 /* USB device FS only */
 #define cpu_has_udpfs()                (!(cpu_is_at91sam9rl() \
                                || cpu_is_at91sam9g45() \
-                               || cpu_is_at91sam9x5()))
+                               || cpu_is_at91sam9x5() \
+                               || cpu_is_sama5d3()))
 
 #define cpu_has_plladiv2()     (cpu_is_at91sam9g45() \
                                || cpu_is_at91sam9x5() \
-                               || cpu_is_at91sam9n12())
+                               || cpu_is_at91sam9n12() \
+                               || cpu_is_sama5d3())
 
 #define cpu_has_mdiv3()                (cpu_is_at91sam9g45() \
                                || cpu_is_at91sam9x5() \
-                               || cpu_is_at91sam9n12())
+                               || cpu_is_at91sam9n12() \
+                               || cpu_is_sama5d3())
 
 #define cpu_has_alt_prescaler()        (cpu_is_at91sam9x5() \
-                               || cpu_is_at91sam9n12())
+                               || cpu_is_at91sam9n12() \
+                               || cpu_is_sama5d3())
 
 static LIST_HEAD(clocks);
 static DEFINE_SPINLOCK(clk_lock);
@@ -210,10 +218,26 @@ struct clk mck = {
 
 static void pmc_periph_mode(struct clk *clk, int is_on)
 {
-       if (is_on)
-               at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask);
-       else
-               at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask);
+       u32 regval = 0;
+
+       /*
+        * With sama5d3 devices, we are managing clock division so we have to
+        * use the Peripheral Control Register introduced from at91sam9x5
+        * devices.
+        */
+       if (cpu_is_sama5d3()) {
+               regval |= AT91_PMC_PCR_CMD; /* write command */
+               regval |= clk->pid & AT91_PMC_PCR_PID; /* peripheral selection */
+               regval |= AT91_PMC_PCR_DIV(clk->div);
+               if (is_on)
+                       regval |= AT91_PMC_PCR_EN; /* enable clock */
+               at91_pmc_write(AT91_PMC_PCR, regval);
+       } else {
+               if (is_on)
+                       at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask);
+               else
+                       at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask);
+       }
 }
 
 static struct clk __init *at91_css_to_clk(unsigned long css)
@@ -443,14 +467,18 @@ static void __init init_programmable_clock(struct clk *clk)
 
 static int at91_clk_show(struct seq_file *s, void *unused)
 {
-       u32             scsr, pcsr, uckr = 0, sr;
+       u32             scsr, pcsr, pcsr1 = 0, uckr = 0, sr;
        struct clk      *clk;
 
        scsr = at91_pmc_read(AT91_PMC_SCSR);
        pcsr = at91_pmc_read(AT91_PMC_PCSR);
+       if (cpu_is_sama5d3())
+               pcsr1 = at91_pmc_read(AT91_PMC_PCSR1);
        sr = at91_pmc_read(AT91_PMC_SR);
        seq_printf(s, "SCSR = %8x\n", scsr);
        seq_printf(s, "PCSR = %8x\n", pcsr);
+       if (cpu_is_sama5d3())
+               seq_printf(s, "PCSR1 = %8x\n", pcsr1);
        seq_printf(s, "MOR  = %8x\n", at91_pmc_read(AT91_CKGR_MOR));
        seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR));
        seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR));
@@ -470,20 +498,30 @@ static int at91_clk_show(struct seq_file *s, void *unused)
        list_for_each_entry(clk, &clocks, node) {
                char    *state;
 
-               if (clk->mode == pmc_sys_mode)
+               if (clk->mode == pmc_sys_mode) {
                        state = (scsr & clk->pmc_mask) ? "on" : "off";
-               else if (clk->mode == pmc_periph_mode)
-                       state = (pcsr & clk->pmc_mask) ? "on" : "off";
-               else if (clk->mode == pmc_uckr_mode)
+               } else if (clk->mode == pmc_periph_mode) {
+                       if (cpu_is_sama5d3()) {
+                               u32 pmc_mask = 1 << (clk->pid % 32);
+
+                               if (clk->pid > 31)
+                                       state = (pcsr1 & pmc_mask) ? "on" : "off";
+                               else
+                                       state = (pcsr & pmc_mask) ? "on" : "off";
+                       } else {
+                               state = (pcsr & clk->pmc_mask) ? "on" : "off";
+                       }
+               } else if (clk->mode == pmc_uckr_mode) {
                        state = (uckr & clk->pmc_mask) ? "on" : "off";
-               else if (clk->pmc_mask)
+               } else if (clk->pmc_mask) {
                        state = (sr & clk->pmc_mask) ? "on" : "off";
-               else if (clk == &clk32k || clk == &main_clk)
+               } else if (clk == &clk32k || clk == &main_clk) {
                        state = "on";
-               else
+               } else {
                        state = "";
+               }
 
-               seq_printf(s, "%-10s users=%2d %-3s %9ld Hz %s\n",
+               seq_printf(s, "%-10s users=%2d %-3s %9lu Hz %s\n",
                        clk->name, clk->users, state, clk_get_rate(clk),
                        clk->parent ? clk->parent->name : "");
        }
@@ -530,6 +568,9 @@ int __init clk_register(struct clk *clk)
        if (clk_is_peripheral(clk)) {
                if (!clk->parent)
                        clk->parent = &mck;
+               if (cpu_is_sama5d3())
+                       clk->rate_hz = DIV_ROUND_UP(clk->parent->rate_hz,
+                                                   1 << clk->div);
                clk->mode = pmc_periph_mode;
        }
        else if (clk_is_sys(clk)) {
@@ -555,7 +596,11 @@ static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
        unsigned mul, div;
 
        div = reg & 0xff;
-       mul = (reg >> 16) & 0x7ff;
+       if (cpu_is_sama5d3())
+               mul = AT91_PMC3_MUL_GET(reg);
+       else
+               mul = AT91_PMC_MUL_GET(reg);
+
        if (div && mul) {
                freq /= div;
                freq *= mul + 1;
@@ -706,12 +751,15 @@ static int __init at91_pmc_init(unsigned long main_clock)
 
        /* report if PLLA is more than mildly overclocked */
        plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR));
-       if (cpu_has_300M_plla()) {
-               if (plla.rate_hz > 300000000)
+       if (cpu_has_1056M_plla()) {
+               if (plla.rate_hz > 1056000000)
                        pll_overclock = true;
        } else if (cpu_has_800M_plla()) {
                if (plla.rate_hz > 800000000)
                        pll_overclock = true;
+       } else if (cpu_has_300M_plla()) {
+               if (plla.rate_hz > 300000000)
+                       pll_overclock = true;
        } else if (cpu_has_240M_plla()) {
                if (plla.rate_hz > 240000000)
                        pll_overclock = true;
@@ -872,6 +920,7 @@ int __init at91_clock_init(unsigned long main_clock)
 static int __init at91_clock_reset(void)
 {
        unsigned long pcdr = 0;
+       unsigned long pcdr1 = 0;
        unsigned long scdr = 0;
        struct clk *clk;
 
@@ -879,8 +928,17 @@ static int __init at91_clock_reset(void)
                if (clk->users > 0)
                        continue;
 
-               if (clk->mode == pmc_periph_mode)
-                       pcdr |= clk->pmc_mask;
+               if (clk->mode == pmc_periph_mode) {
+                       if (cpu_is_sama5d3()) {
+                               u32 pmc_mask = 1 << (clk->pid % 32);
+
+                               if (clk->pid > 31)
+                                       pcdr1 |= pmc_mask;
+                               else
+                                       pcdr |= pmc_mask;
+                       } else
+                               pcdr |= clk->pmc_mask;
+               }
 
                if (clk->mode == pmc_sys_mode)
                        scdr |= clk->pmc_mask;
@@ -888,8 +946,9 @@ static int __init at91_clock_reset(void)
                pr_debug("Clocks: disable unused %s\n", clk->name);
        }
 
-       at91_pmc_write(AT91_PMC_PCDR, pcdr);
        at91_pmc_write(AT91_PMC_SCDR, scdr);
+       if (cpu_is_sama5d3())
+               at91_pmc_write(AT91_PMC_PCDR1, pcdr1);
 
        return 0;
 }
index c2e63e47dcbece02cf2c9ea296b52476b59ef938..a98a39bbd8839e446e6be44defd9bdb4cd615358 100644 (file)
@@ -20,7 +20,9 @@ struct clk {
        const char      *name;          /* unique clock name */
        struct clk_lookup cl;
        unsigned long   rate_hz;
+       unsigned        div;            /* parent clock divider */
        struct clk      *parent;
+       unsigned        pid;            /* peripheral ID */
        u32             pmc_mask;
        void            (*mode)(struct clk *, int);
        unsigned        id:3;           /* PCK0..4, or 32k/main/a/b */
index ea2c57a86ca6ebf389aaa406bffeb5441e65a067..31df12029c4e9a5b32695874e95fb9e4e4c75589 100644 (file)
@@ -75,6 +75,9 @@ extern void __iomem *at91_pmc_base;
 #define                AT91_PMC_PLLCOUNT       (0x3f  <<  8)           /* PLL Counter */
 #define                AT91_PMC_OUT            (3     << 14)           /* PLL Clock Frequency Range */
 #define                AT91_PMC_MUL            (0x7ff << 16)           /* PLL Multiplier */
+#define                AT91_PMC_MUL_GET(n)     ((n) >> 16 & 0x7ff)
+#define                AT91_PMC3_MUL           (0x7f  << 18)           /* PLL Multiplier [SAMA5 only] */
+#define                AT91_PMC3_MUL_GET(n)    ((n) >> 18 & 0x7f)
 #define                AT91_PMC_USBDIV         (3     << 28)           /* USB Divisor (PLLB only) */
 #define                        AT91_PMC_USBDIV_1               (0 << 28)
 #define                        AT91_PMC_USBDIV_2               (1 << 28)
@@ -167,11 +170,18 @@ extern void __iomem *at91_pmc_base;
 #define                AT91_PMC_WPVS           (0x1  <<  0)            /* Write Protect Violation Status */
 #define                AT91_PMC_WPVSRC         (0xffff  <<  8)         /* Write Protect Violation Source */
 
-#define AT91_PMC_PCR           0x10c                   /* Peripheral Control Register [some SAM9] */
+#define AT91_PMC_PCER1         0x100                   /* Peripheral Clock Enable Register 1 [SAMA5 only]*/
+#define AT91_PMC_PCDR1         0x104                   /* Peripheral Clock Enable Register 1 */
+#define AT91_PMC_PCSR1         0x108                   /* Peripheral Clock Enable Register 1 */
+
+#define AT91_PMC_PCR           0x10c                   /* Peripheral Control Register [some SAM9 and SAMA5] */
 #define                AT91_PMC_PCR_PID        (0x3f  <<  0)           /* Peripheral ID */
-#define                AT91_PMC_PCR_CMD        (0x1  <<  12)           /* Command */
-#define                AT91_PMC_PCR_DIV        (0x3  <<  16)           /* Divisor Value */
-#define                AT91_PMC_PCRDIV(n)      (((n) <<  16) & AT91_PMC_PCR_DIV)
+#define                AT91_PMC_PCR_CMD        (0x1  <<  12)           /* Command (read=0, write=1) */
+#define                AT91_PMC_PCR_DIV(n)     ((n)  <<  16)           /* Divisor Value */
+#define                        AT91_PMC_PCR_DIV0       0x0                     /* Peripheral clock is MCK */
+#define                        AT91_PMC_PCR_DIV2       0x2                     /* Peripheral clock is MCK/2 */
+#define                        AT91_PMC_PCR_DIV4       0x4                     /* Peripheral clock is MCK/4 */
+#define                        AT91_PMC_PCR_DIV8       0x8                     /* Peripheral clock is MCK/8 */
 #define                AT91_PMC_PCR_EN         (0x1  <<  28)           /* Enable */
 
 #endif
index b6504c19d55c2849d84a64a23317673b55ed926c..0f3379fe645ff7914156b6dd85cdb5efe00c588b 100644 (file)
@@ -36,6 +36,8 @@
 #define ARCH_ID_AT91M40807     0x14080745
 #define ARCH_ID_AT91R40008     0x44000840
 
+#define ARCH_ID_SAMA5D3                0x8A5C07C0
+
 #define ARCH_EXID_AT91SAM9M11  0x00000001
 #define ARCH_EXID_AT91SAM9M10  0x00000002
 #define ARCH_EXID_AT91SAM9G46  0x00000003
 #define ARCH_EXID_AT91SAM9G25  0x00000003
 #define ARCH_EXID_AT91SAM9X25  0x00000004
 
+#define ARCH_EXID_SAMA5D31     0x00444300
+#define ARCH_EXID_SAMA5D33     0x00414300
+#define ARCH_EXID_SAMA5D34     0x00414301
+#define ARCH_EXID_SAMA5D35     0x00584300
+
 #define ARCH_FAMILY_AT91X92    0x09200000
 #define ARCH_FAMILY_AT91SAM9   0x01900000
 #define ARCH_FAMILY_AT91SAM9XE 0x02900000
@@ -75,6 +82,9 @@ enum at91_soc_type {
        /* SAM9N12 */
        AT91_SOC_SAM9N12,
 
+       /* SAMA5D3 */
+       AT91_SOC_SAMA5D3,
+
        /* Unknown type */
        AT91_SOC_NONE
 };
@@ -93,6 +103,10 @@ enum at91_soc_subtype {
        AT91_SOC_SAM9G15, AT91_SOC_SAM9G35, AT91_SOC_SAM9X35,
        AT91_SOC_SAM9G25, AT91_SOC_SAM9X25,
 
+       /* SAMA5D3 */
+       AT91_SOC_SAMA5D31, AT91_SOC_SAMA5D33, AT91_SOC_SAMA5D34,
+       AT91_SOC_SAMA5D35,
+
        /* Unknown subtype */
        AT91_SOC_SUBTYPE_NONE
 };
@@ -187,6 +201,12 @@ static inline int at91_soc_is_detected(void)
 #define cpu_is_at91sam9n12()   (0)
 #endif
 
+#ifdef CONFIG_SOC_SAMA5D3
+#define cpu_is_sama5d3()       (at91_soc_initdata.type == AT91_SOC_SAMA5D3)
+#else
+#define cpu_is_sama5d3()       (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/sama5d3.h b/arch/arm/mach-at91/include/mach/sama5d3.h
new file mode 100644 (file)
index 0000000..6dc81ee
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Chip-specific header file for the SAMA5D3 family
+ *
+ *  Copyright (C) 2013 Atmel,
+ *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
+ *
+ * Common definitions.
+ * Based on SAMA5D3 datasheet.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef SAMA5D3_H
+#define SAMA5D3_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ             0      /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS             1      /* System Peripherals */
+#define SAMA5D3_ID_DBGU                 2      /* debug Unit (usually no special interrupt line) */
+#define AT91_ID_PIT             3      /* PIT */
+#define SAMA5D3_ID_WDT          4      /* Watchdog Timer Interrupt */
+#define SAMA5D3_ID_HSMC                 5      /* Static Memory Controller */
+#define SAMA5D3_ID_PIOA                 6      /* PIOA */
+#define SAMA5D3_ID_PIOB                 7      /* PIOB */
+#define SAMA5D3_ID_PIOC                 8      /* PIOC */
+#define SAMA5D3_ID_PIOD                 9      /* PIOD */
+#define SAMA5D3_ID_PIOE                10      /* PIOE */
+#define SAMA5D3_ID_SMD         11      /* SMD Soft Modem */
+#define SAMA5D3_ID_USART0      12      /* USART0 */
+#define SAMA5D3_ID_USART1      13      /* USART1 */
+#define SAMA5D3_ID_USART2      14      /* USART2 */
+#define SAMA5D3_ID_USART3      15      /* USART3 */
+#define SAMA5D3_ID_UART0       16      /* UART 0 */
+#define SAMA5D3_ID_UART1       17      /* UART 1 */
+#define SAMA5D3_ID_TWI0                18      /* Two-Wire Interface 0 */
+#define SAMA5D3_ID_TWI1                19      /* Two-Wire Interface 1 */
+#define SAMA5D3_ID_TWI2                20      /* Two-Wire Interface 2 */
+#define SAMA5D3_ID_HSMCI0      21      /* MCI */
+#define SAMA5D3_ID_HSMCI1      22      /* MCI */
+#define SAMA5D3_ID_HSMCI2      23      /* MCI */
+#define SAMA5D3_ID_SPI0                24      /* Serial Peripheral Interface 0 */
+#define SAMA5D3_ID_SPI1                25      /* Serial Peripheral Interface 1 */
+#define SAMA5D3_ID_TC0         26      /* Timer Counter 0 */
+#define SAMA5D3_ID_TC1         27      /* Timer Counter 2 */
+#define SAMA5D3_ID_PWM         28      /* Pulse Width Modulation Controller */
+#define SAMA5D3_ID_ADC         29      /* Touch Screen ADC Controller */
+#define SAMA5D3_ID_DMA0                30      /* DMA Controller 0 */
+#define SAMA5D3_ID_DMA1                31      /* DMA Controller 1 */
+#define SAMA5D3_ID_UHPHS       32      /* USB Host High Speed */
+#define SAMA5D3_ID_UDPHS       33      /* USB Device High Speed */
+#define SAMA5D3_ID_GMAC                34      /* Gigabit Ethernet MAC */
+#define SAMA5D3_ID_EMAC                35      /* Ethernet MAC */
+#define SAMA5D3_ID_LCDC                36      /* LCD Controller */
+#define SAMA5D3_ID_ISI         37      /* Image Sensor Interface */
+#define SAMA5D3_ID_SSC0                38      /* Synchronous Serial Controller 0 */
+#define SAMA5D3_ID_SSC1                39      /* Synchronous Serial Controller 1 */
+#define SAMA5D3_ID_CAN0                40      /* CAN Controller 0 */
+#define SAMA5D3_ID_CAN1                41      /* CAN Controller 1 */
+#define SAMA5D3_ID_SHA         42      /* Secure Hash Algorithm */
+#define SAMA5D3_ID_AES         43      /* Advanced Encryption Standard */
+#define SAMA5D3_ID_TDES                44      /* Triple Data Encryption Standard */
+#define SAMA5D3_ID_TRNG                45      /* True Random Generator Number */
+#define SAMA5D3_ID_IRQ0                47      /* Advanced Interrupt Controller (IRQ0) */
+
+/*
+ * Internal Memory
+ */
+#define SAMA5D3_SRAM_BASE      0x00300000      /* Internal SRAM base address */
+#define SAMA5D3_SRAM_SIZE      (128 * SZ_1K)   /* Internal SRAM size (128Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c
new file mode 100644 (file)
index 0000000..4012797
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ *  Chip-specific setup code for the SAMA5D3 family
+ *
+ *  Copyright (C) 2013 Atmel,
+ *                2013 Ludovic Desroches <ludovic.desroches@atmel.com>
+ *
+ * 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/sama5d3.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+
+static struct clk pioA_clk = {
+       .name           = "pioA_clk",
+       .pid            = SAMA5D3_ID_PIOA,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+       .name           = "pioB_clk",
+       .pid            = SAMA5D3_ID_PIOB,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+       .name           = "pioC_clk",
+       .pid            = SAMA5D3_ID_PIOC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioD_clk = {
+       .name           = "pioD_clk",
+       .pid            = SAMA5D3_ID_PIOD,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioE_clk = {
+       .name           = "pioE_clk",
+       .pid            = SAMA5D3_ID_PIOE,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+       .name           = "usart0_clk",
+       .pid            = SAMA5D3_ID_USART0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk usart1_clk = {
+       .name           = "usart1_clk",
+       .pid            = SAMA5D3_ID_USART1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk usart2_clk = {
+       .name           = "usart2_clk",
+       .pid            = SAMA5D3_ID_USART2,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk usart3_clk = {
+       .name           = "usart3_clk",
+       .pid            = SAMA5D3_ID_USART3,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk uart0_clk = {
+       .name           = "uart0_clk",
+       .pid            = SAMA5D3_ID_UART0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk uart1_clk = {
+       .name           = "uart1_clk",
+       .pid            = SAMA5D3_ID_UART1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk twi0_clk = {
+       .name           = "twi0_clk",
+       .pid            = SAMA5D3_ID_TWI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk twi1_clk = {
+       .name           = "twi1_clk",
+       .pid            = SAMA5D3_ID_TWI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk twi2_clk = {
+       .name           = "twi2_clk",
+       .pid            = SAMA5D3_ID_TWI2,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk mmc0_clk = {
+       .name           = "mci0_clk",
+       .pid            = SAMA5D3_ID_HSMCI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+       .name           = "mci1_clk",
+       .pid            = SAMA5D3_ID_HSMCI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc2_clk = {
+       .name           = "mci2_clk",
+       .pid            = SAMA5D3_ID_HSMCI2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+       .name           = "spi0_clk",
+       .pid            = SAMA5D3_ID_SPI0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+       .name           = "spi1_clk",
+       .pid            = SAMA5D3_ID_SPI1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb0_clk = {
+       .name           = "tcb0_clk",
+       .pid            = SAMA5D3_ID_TC0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk tcb1_clk = {
+       .name           = "tcb1_clk",
+       .pid            = SAMA5D3_ID_TC1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk adc_clk = {
+       .name           = "adc_clk",
+       .pid            = SAMA5D3_ID_ADC,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk adc_op_clk = {
+       .name           = "adc_op_clk",
+       .type           = CLK_TYPE_PERIPHERAL,
+       .rate_hz        = 5000000,
+};
+static struct clk dma0_clk = {
+       .name           = "dma0_clk",
+       .pid            = SAMA5D3_ID_DMA0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma1_clk = {
+       .name           = "dma1_clk",
+       .pid            = SAMA5D3_ID_DMA1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhphs_clk = {
+       .name           = "uhphs",
+       .pid            = SAMA5D3_ID_UHPHS,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+       .name           = "udphs_clk",
+       .pid            = SAMA5D3_ID_UDPHS,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* gmac only for sama5d33, sama5d34, sama5d35 */
+static struct clk macb0_clk = {
+       .name           = "macb0_clk",
+       .pid            = SAMA5D3_ID_GMAC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* emac only for sama5d31, sama5d35 */
+static struct clk macb1_clk = {
+       .name           = "macb1_clk",
+       .pid            = SAMA5D3_ID_EMAC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* lcd only for sama5d31, sama5d33, sama5d34 */
+static struct clk lcdc_clk = {
+       .name           = "lcdc_clk",
+       .pid            = SAMA5D3_ID_LCDC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+/* isi only for sama5d33, sama5d35 */
+static struct clk isi_clk = {
+       .name           = "isi_clk",
+       .pid            = SAMA5D3_ID_ISI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk can0_clk = {
+       .name           = "can0_clk",
+       .pid            = SAMA5D3_ID_CAN0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk can1_clk = {
+       .name           = "can1_clk",
+       .pid            = SAMA5D3_ID_CAN1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk ssc0_clk = {
+       .name           = "ssc0_clk",
+       .pid            = SAMA5D3_ID_SSC0,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk ssc1_clk = {
+       .name           = "ssc1_clk",
+       .pid            = SAMA5D3_ID_SSC1,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV2,
+};
+static struct clk sha_clk = {
+       .name           = "sha_clk",
+       .pid            = SAMA5D3_ID_SHA,
+       .type           = CLK_TYPE_PERIPHERAL,
+       .div            = AT91_PMC_PCR_DIV8,
+};
+static struct clk aes_clk = {
+       .name           = "aes_clk",
+       .pid            = SAMA5D3_ID_AES,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tdes_clk = {
+       .name           = "tdes_clk",
+       .pid            = SAMA5D3_ID_TDES,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+       &pioA_clk,
+       &pioB_clk,
+       &pioC_clk,
+       &pioD_clk,
+       &pioE_clk,
+       &usart0_clk,
+       &usart1_clk,
+       &usart2_clk,
+       &usart3_clk,
+       &uart0_clk,
+       &uart1_clk,
+       &twi0_clk,
+       &twi1_clk,
+       &twi2_clk,
+       &mmc0_clk,
+       &mmc1_clk,
+       &mmc2_clk,
+       &spi0_clk,
+       &spi1_clk,
+       &tcb0_clk,
+       &tcb1_clk,
+       &adc_clk,
+       &adc_op_clk,
+       &dma0_clk,
+       &dma1_clk,
+       &uhphs_clk,
+       &udphs_clk,
+       &macb0_clk,
+       &macb1_clk,
+       &lcdc_clk,
+       &isi_clk,
+       &can0_clk,
+       &can1_clk,
+       &ssc0_clk,
+       &ssc1_clk,
+       &sha_clk,
+       &aes_clk,
+       &tdes_clk,
+};
+
+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 struct clk pck2 = {
+       .name           = "pck2",
+       .pmc_mask       = AT91_PMC_PCK2,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 2,
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+       /* lookup table for DT entries */
+       CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
+       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", &pioD_clk),
+       CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioE_clk),
+       CLKDEV_CON_DEV_ID("usart", "f001c000.serial", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "f0020000.serial", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart3_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f0014000.i2c", &twi0_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f0018000.i2c", &twi1_clk),
+       CLKDEV_CON_DEV_ID(NULL, "f801c000.i2c", &twi2_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "f0000000.mmc", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "f8000000.mmc", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "f8004000.mmc", &mmc2_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "f8008000.spi", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "f0010000.timer", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "f8014000.timer", &tcb1_clk),
+       CLKDEV_CON_DEV_ID("tsc_clk", "f8018000.tsadcc", &adc_clk),
+       CLKDEV_CON_DEV_ID("dma_clk", "ffffe600.dma-controller", &dma0_clk),
+       CLKDEV_CON_DEV_ID("dma_clk", "ffffe800.dma-controller", &dma1_clk),
+       CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk),
+       CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk),
+       CLKDEV_CON_DEV_ID("hclk", "f0028000.ethernet", &macb0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "f0028000.ethernet", &macb0_clk),
+       CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "f802c000.ethernet", &macb1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "f0008000.ssc", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "f000c000.ssc", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("can_clk", "f000c000.can", &can0_clk),
+       CLKDEV_CON_DEV_ID("can_clk", "f8010000.can", &can1_clk),
+       CLKDEV_CON_DEV_ID("sha_clk", "f8034000.sha", &sha_clk),
+       CLKDEV_CON_DEV_ID("aes_clk", "f8038000.aes", &aes_clk),
+       CLKDEV_CON_DEV_ID("tdes_clk", "f803c000.tdes", &tdes_clk),
+};
+
+static void __init sama5d3_register_clocks(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+               clk_register(periph_clocks[i]);
+
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+
+       clk_register(&pck0);
+       clk_register(&pck1);
+       clk_register(&pck2);
+}
+
+/* --------------------------------------------------------------------
+ *  AT91SAM9x5 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init sama5d3_map_io(void)
+{
+       at91_init_sram(0, SAMA5D3_SRAM_BASE, SAMA5D3_SRAM_SIZE);
+}
+
+AT91_SOC_START(sama5d3)
+       .map_io = sama5d3_map_io,
+       .register_clocks = sama5d3_register_clocks,
+AT91_SOC_END
index 4b678478cf95d9f60d6a4484b4a490ee46228d45..2ecd1693c804f68ccca3c09ec4dda6dffcf23d00 100644 (file)
@@ -151,6 +151,11 @@ static void __init soc_detect(u32 dbgu_base)
                at91_soc_initdata.type = AT91_SOC_SAM9N12;
                at91_boot_soc = at91sam9n12_soc;
                break;
+
+       case ARCH_ID_SAMA5D3:
+               at91_soc_initdata.type = AT91_SOC_SAMA5D3;
+               at91_boot_soc = sama5d3_soc;
+               break;
        }
 
        /* at91sam9g10 */
@@ -206,6 +211,23 @@ static void __init soc_detect(u32 dbgu_base)
                        break;
                }
        }
+
+       if (at91_soc_initdata.type == AT91_SOC_SAMA5D3) {
+               switch (at91_soc_initdata.exid) {
+               case ARCH_EXID_SAMA5D31:
+                       at91_soc_initdata.subtype = AT91_SOC_SAMA5D31;
+                       break;
+               case ARCH_EXID_SAMA5D33:
+                       at91_soc_initdata.subtype = AT91_SOC_SAMA5D33;
+                       break;
+               case ARCH_EXID_SAMA5D34:
+                       at91_soc_initdata.subtype = AT91_SOC_SAMA5D34;
+                       break;
+               case ARCH_EXID_SAMA5D35:
+                       at91_soc_initdata.subtype = AT91_SOC_SAMA5D35;
+                       break;
+               }
+       }
 }
 
 static const char *soc_name[] = {
@@ -219,6 +241,7 @@ static const char *soc_name[] = {
        [AT91_SOC_SAM9RL]       = "at91sam9rl",
        [AT91_SOC_SAM9X5]       = "at91sam9x5",
        [AT91_SOC_SAM9N12]      = "at91sam9n12",
+       [AT91_SOC_SAMA5D3]      = "sama5d3",
        [AT91_SOC_NONE]         = "Unknown"
 };
 
@@ -241,6 +264,10 @@ static const char *soc_subtype_name[] = {
        [AT91_SOC_SAM9X35]      = "at91sam9x35",
        [AT91_SOC_SAM9G25]      = "at91sam9g25",
        [AT91_SOC_SAM9X25]      = "at91sam9x25",
+       [AT91_SOC_SAMA5D31]     = "sama5d31",
+       [AT91_SOC_SAMA5D33]     = "sama5d33",
+       [AT91_SOC_SAMA5D34]     = "sama5d34",
+       [AT91_SOC_SAMA5D35]     = "sama5d35",
        [AT91_SOC_SUBTYPE_NONE] = "Unknown"
 };
 
index f3d350278565f480cf04660a04b16bcb4ccba83f..43a225f9e71334757a3a4a1817ca60f804404fd1 100644 (file)
@@ -22,6 +22,7 @@ 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;
+extern struct at91_init_soc sama5d3_soc;
 
 #define AT91_SOC_START(_name)                          \
 struct at91_init_soc __initdata _name##_soc            \
@@ -68,3 +69,7 @@ static inline int at91_soc_is_enabled(void)
 #if !defined(CONFIG_SOC_AT91SAM9N12)
 #define at91sam9n12_soc        at91_boot_soc
 #endif
+
+#if !defined(CONFIG_SOC_SAMA5D3)
+#define sama5d3_soc    at91_boot_soc
+#endif