[U-Boot] [PATCH v3] AT91: Add SD/MMC controller support

Albin Tonnerre albin.tonnerre at free-electrons.com
Tue Sep 8 22:39:34 CEST 2009


This patch allows to use the atmel_mci SD/MMC driver on the at91 architecture.
It contains:
 - initialization code for the MCI controller for all the supported AT91. It
   allows the use of only one controller even if a SoC has two controllers
   (anyway there's no support for it in atmel_mci as of now)
 - the necessary get_mci_clk_rate function
 - definition of MMCI_BASE for use in atmel_mci
 - the cpu_mmc_init function. As of now this is not used, but will be required
   when atmel_mci is ported to the new generic mmc API.

Signed-off-by: Albin Tonnerre <albin.tonnerre at free-electrons.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
Changes since v1
 - Fix the MCI controller ID in the init code for CAP9, SAM9263 and SAM9G45
 - Move AT91_BASE_MCI* define to soc header
 - define AT91_BASE_MCI{0,1} instead of AT91_BASE_MCI for boards which have 2
   controllers
 - rework the way MMCI_BASE is defined accordingly

Changes since v2
 - allow using 8-bit bus width on CPUs that support it
 - change the arguments of atmel_mciX_hw_init to (slot, bus) so that it's more
   meaningful than (bitmask)

 cpu/arm926ejs/at91/at91cap9_devices.c       |   40 +++++++++++++++
 cpu/arm926ejs/at91/at91sam9260_devices.c    |   37 ++++++++++++++
 cpu/arm926ejs/at91/at91sam9261_devices.c    |   21 ++++++++
 cpu/arm926ejs/at91/at91sam9263_devices.c    |   72 +++++++++++++++++++++++++++
 cpu/arm926ejs/at91/at91sam9m10g45_devices.c |   56 +++++++++++++++++++++
 cpu/arm926ejs/at91/at91sam9rl_devices.c     |   25 +++++++++
 include/asm-arm/arch-at91/at91_common.h     |    2 +
 include/asm-arm/arch-at91/at91cap9.h        |    2 +
 include/asm-arm/arch-at91/at91sam9260.h     |    1 +
 include/asm-arm/arch-at91/at91sam9261.h     |    1 +
 include/asm-arm/arch-at91/at91sam9263.h     |    2 +
 include/asm-arm/arch-at91/at91sam9g45.h     |    2 +
 include/asm-arm/arch-at91/at91sam9rl.h      |    1 +
 include/asm-arm/arch-at91/clk.h             |    5 ++
 include/asm-arm/arch-at91/memory-map.h      |    6 ++
 15 files changed, 273 insertions(+), 0 deletions(-)

diff --git a/cpu/arm926ejs/at91/at91cap9_devices.c b/cpu/arm926ejs/at91/at91cap9_devices.c
index 39e405f..de7048b 100644
--- a/cpu/arm926ejs/at91/at91cap9_devices.c
+++ b/cpu/arm926ejs/at91/at91cap9_devices.c
@@ -79,6 +79,46 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91CAP9_ID_MCI0);
+
+	/* 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 (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);
+	}
+}
+
+void at91_mci1_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91CAP9_ID_MCI0);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA16, 0);
+
+	/* CMD */
+	at91_set_A_periph(AT91_PIN_PA17, 1);
+
+	/* DAT0, maybe DAT1..DAT3 */
+	at91_set_A_periph(AT91_PIN_PA18, 1);
+	if (bus_width == 4) {
+		at91_set_A_periph(AT91_PIN_PA19, 1);
+		at91_set_A_periph(AT91_PIN_PA20, 1);
+		at91_set_A_periph(AT91_PIN_PA21, 1);
+	}
+}
+#endif
+
 #ifdef CONFIG_HAS_DATAFLASH
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/cpu/arm926ejs/at91/at91sam9260_devices.c b/cpu/arm926ejs/at91/at91sam9260_devices.c
index f86cb99..f724f58 100644
--- a/cpu/arm926ejs/at91/at91sam9260_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9260_devices.c
@@ -75,6 +75,43 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_MCI);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA8, 0);
+
+	switch (slot) {
+		case 0:
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA7, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA6, 1);
+			if (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);
+			}
+			break;
+		case 1:
+			/* CMD */
+			at91_set_B_periph(AT91_PIN_PA1, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_B_periph(AT91_PIN_PA0, 1);
+			if (bus_width == 4) {
+				at91_set_B_periph(AT91_PIN_PA3, 1);
+				at91_set_B_periph(AT91_PIN_PA4, 1);
+				at91_set_B_periph(AT91_PIN_PA5, 1);
+			}
+			break;
+	}
+}
+#endif /* ATMEL_MCI */
+
 #if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI)
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/cpu/arm926ejs/at91/at91sam9261_devices.c b/cpu/arm926ejs/at91/at91sam9261_devices.c
index 16d411f..be76acf 100644
--- a/cpu/arm926ejs/at91/at91sam9261_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9261_devices.c
@@ -75,6 +75,27 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9261_ID_MCI);
+
+	/* 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 (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);
+	}
+}
+#endif /* ATMEL_MCI */
+
 #ifdef CONFIG_HAS_DATAFLASH
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/cpu/arm926ejs/at91/at91sam9263_devices.c b/cpu/arm926ejs/at91/at91sam9263_devices.c
index f72efdf..c06a541 100644
--- a/cpu/arm926ejs/at91/at91sam9263_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9263_devices.c
@@ -79,6 +79,78 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_MCI0);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA12, 0);
+
+	switch (slot) {
+		case 0:
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA1, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA0, 1);
+			if (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);
+			}
+			break;
+		case 1:
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA16, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA17, 1);
+			if (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);
+			}
+			break;
+	}
+}
+
+void at91_mci1_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_MCI1);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA6, 0);
+
+	switch (slot) {
+		case 0:
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA7, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA8, 1);
+			if (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);
+			}
+			break;
+		case 1:
+			/* CMD */
+			at91_set_B_periph(AT91_PIN_PA21, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_B_periph(AT91_PIN_PA22, 1);
+			if (bus_width == 4) {
+				at91_set_B_periph(AT91_PIN_PA23, 1);
+				at91_set_B_periph(AT91_PIN_PA24, 1);
+				at91_set_B_periph(AT91_PIN_PA25, 1);
+			}
+			break;
+	}
+}
+#endif
+
 #ifdef CONFIG_HAS_DATAFLASH
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/cpu/arm926ejs/at91/at91sam9m10g45_devices.c b/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
index 98d90f2..91a0546 100644
--- a/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9m10g45_devices.c
@@ -75,6 +75,62 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9G45_ID_MCI0);
+
+	at91_set_A_periph(AT91_PIN_PA12, 0);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA0, 1);
+
+	/* CMD */
+	at91_set_A_periph(AT91_PIN_PA1, 1);
+
+	/* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+	at91_set_A_periph(AT91_PIN_PA2, 1);
+	switch (bus_width) {
+	case 8:
+		at91_set_A_periph(AT91_PIN_PA6, 1);
+		at91_set_A_periph(AT91_PIN_PA7, 1);
+		at91_set_A_periph(AT91_PIN_PA8, 1);
+		at91_set_A_periph(AT91_PIN_PA9, 1);
+	case 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);
+		break;
+	}
+}
+
+void at91_mci1_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9G45_ID_MCI1);
+
+	/* CLK */
+	at91_set_A_periph(AT91_PIN_PA31, 0);
+
+	/* CMD */
+	at91_set_A_periph(AT91_PIN_PA22, 1);
+
+	/* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
+	at91_set_A_periph(AT91_PIN_PA23, 1);
+	switch (bus_width) {
+	case 8:
+		at91_set_A_periph(AT91_PIN_PA27, 1);
+		at91_set_A_periph(AT91_PIN_PA28, 1);
+		at91_set_A_periph(AT91_PIN_PA29, 1);
+		at91_set_A_periph(AT91_PIN_PA30, 1);
+	case 4:
+		at91_set_A_periph(AT91_PIN_PA24, 1);
+		at91_set_A_periph(AT91_PIN_PA25, 1);
+		at91_set_A_periph(AT91_PIN_PA26, 1);
+		break;
+	}
+}
+#endif
+
 #ifdef CONFIG_ATMEL_SPI
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/cpu/arm926ejs/at91/at91sam9rl_devices.c b/cpu/arm926ejs/at91/at91sam9rl_devices.c
index ebed193..3945e13 100644
--- a/cpu/arm926ejs/at91/at91sam9rl_devices.c
+++ b/cpu/arm926ejs/at91/at91sam9rl_devices.c
@@ -75,6 +75,31 @@ void at91_serial_hw_init(void)
 #endif
 }
 
+/* 
+ * The AT91SAM9RL64 is said to have 2 slots, but the datasheet doesn't
+ * seem to mention to what pins the second slot is assigned
+ */
+#ifdef CONFIG_ATMEL_MCI
+void at91_mci0_hw_init(int slot, int bus_width)
+{
+	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9RL_ID_MCI);
+
+	/* 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 (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);
+	}
+}
+#endif /* ATMEL_MCI */
+
 #ifdef CONFIG_HAS_DATAFLASH
 void at91_spi0_hw_init(unsigned long cs_mask)
 {
diff --git a/include/asm-arm/arch-at91/at91_common.h b/include/asm-arm/arch-at91/at91_common.h
index 01840ee..1c96b40 100644
--- a/include/asm-arm/arch-at91/at91_common.h
+++ b/include/asm-arm/arch-at91/at91_common.h
@@ -32,6 +32,8 @@ void at91_serial0_hw_init(void);
 void at91_serial1_hw_init(void);
 void at91_serial2_hw_init(void);
 void at91_serial3_hw_init(void);
+void at91_mci0_hw_init(int slot, int bus_width);
+void at91_mci1_hw_init(int slot, int bus_width);
 void at91_spi0_hw_init(unsigned long cs_mask);
 void at91_spi1_hw_init(unsigned long cs_mask);
 void at91_uhp_hw_init(void);
diff --git a/include/asm-arm/arch-at91/at91cap9.h b/include/asm-arm/arch-at91/at91cap9.h
index 98bfcc7..de731ac 100644
--- a/include/asm-arm/arch-at91/at91cap9.h
+++ b/include/asm-arm/arch-at91/at91cap9.h
@@ -112,6 +112,8 @@
 #define AT91_BASE_SPI	AT91CAP9_BASE_SPI0
 #define AT91_ID_UHP	AT91CAP9_ID_UHP
 #define AT91_PMC_UHP	AT91CAP9_PMC_UHP
+#define AT91_BASE_MCI0	AT91CAP9_BASE_MCI0
+#define AT91_BASE_MCI1	AT91CAP9_BASE_MCI1
 
 /*
  * SCKCR flags
diff --git a/include/asm-arm/arch-at91/at91sam9260.h b/include/asm-arm/arch-at91/at91sam9260.h
index f2aef8a..6b26140 100644
--- a/include/asm-arm/arch-at91/at91sam9260.h
+++ b/include/asm-arm/arch-at91/at91sam9260.h
@@ -108,6 +108,7 @@
 #define AT91_BASE_SPI	AT91SAM9260_BASE_SPI0
 #define AT91_ID_UHP	AT91SAM9260_ID_UHP
 #define AT91_PMC_UHP	AT91SAM926x_PMC_UHP
+#define AT91_BASE_MCI0	AT91SAM9260_BASE_MCI
 
 /*
  * Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9261.h b/include/asm-arm/arch-at91/at91sam9261.h
index 55bd49a..48fb8f4 100644
--- a/include/asm-arm/arch-at91/at91sam9261.h
+++ b/include/asm-arm/arch-at91/at91sam9261.h
@@ -91,6 +91,7 @@
 #define AT91_BASE_SPI	AT91SAM9261_BASE_SPI0
 #define AT91_ID_UHP	AT91SAM9261_ID_UHP
 #define AT91_PMC_UHP	AT91SAM926x_PMC_UHP
+#define AT91_BASE_MCI0	AT91SAM9261_BASE_MCI
 
 /*
  * Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9263.h b/include/asm-arm/arch-at91/at91sam9263.h
index d862129..4f29e65 100644
--- a/include/asm-arm/arch-at91/at91sam9263.h
+++ b/include/asm-arm/arch-at91/at91sam9263.h
@@ -111,6 +111,8 @@
 #define AT91_BASE_SPI	AT91SAM9263_BASE_SPI0
 #define AT91_ID_UHP	AT91SAM9263_ID_UHP
 #define AT91_PMC_UHP	AT91SAM926x_PMC_UHP
+#define AT91_BASE_MCI0	AT91SAM9263_BASE_MCI0
+#define AT91_BASE_MCI1	AT91SAM9263_BASE_MCI1
 
 /*
  * Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9g45.h b/include/asm-arm/arch-at91/at91sam9g45.h
index d02b157..f232600 100644
--- a/include/asm-arm/arch-at91/at91sam9g45.h
+++ b/include/asm-arm/arch-at91/at91sam9g45.h
@@ -118,6 +118,8 @@
 #define AT91_BASE_SPI	AT91SAM9G45_BASE_SPI0
 #define AT91_ID_UHP	AT91SAM9G45_ID_UHPHS
 #define AT91_PMC_UHP	AT91SAM926x_PMC_UHP
+#define AT91_BASE_MCI0	AT91SAM9G45_BASE_MCI0
+#define AT91_BASE_MCI1	AT91SAM9G45_BASE_MCI1
 
 /*
  * Internal Memory.
diff --git a/include/asm-arm/arch-at91/at91sam9rl.h b/include/asm-arm/arch-at91/at91sam9rl.h
index 3638f92..d26a607 100644
--- a/include/asm-arm/arch-at91/at91sam9rl.h
+++ b/include/asm-arm/arch-at91/at91sam9rl.h
@@ -101,6 +101,7 @@
 
 #define AT91_BASE_SPI	AT91SAM9RL_BASE_SPI
 #define AT91_ID_UHP	AT91SAM9RL_ID_UHP
+#define AT91_BASE_MCI0	AT91SAM9RL_BASE_MCI
 
 
 /*
diff --git a/include/asm-arm/arch-at91/clk.h b/include/asm-arm/arch-at91/clk.h
index f642dd9..457e6c9 100644
--- a/include/asm-arm/arch-at91/clk.h
+++ b/include/asm-arm/arch-at91/clk.h
@@ -59,5 +59,10 @@ static inline unsigned long get_twi_clk_rate(unsigned int dev_id)
 	return get_mck_clk_rate();
 }
 
+static inline unsigned long get_mci_clk_rate(void)
+{
+	return get_mck_clk_rate();
+}
+
 int at91_clock_init(unsigned long main_clock);
 #endif /* __ASM_ARM_ARCH_CLK_H__ */
diff --git a/include/asm-arm/arch-at91/memory-map.h b/include/asm-arm/arch-at91/memory-map.h
index f605f37..de0aba7 100644
--- a/include/asm-arm/arch-at91/memory-map.h
+++ b/include/asm-arm/arch-at91/memory-map.h
@@ -32,4 +32,10 @@
 #define USART3_BASE (AT91_BASE_SYS + AT91_DBGU)
 #define SPI0_BASE	AT91_BASE_SPI
 
+#ifndef CONFIG_AT91_MCI1
+#define MMCI_BASE AT91_BASE_MCI0
+#else
+#define MMCI_BASE AT91_BASE_MCI1
+#endif
+
 #endif /* __ASM_ARM_ARCH_MEMORYMAP_H__ */
-- 
1.6.3.3



More information about the U-Boot mailing list