2009-06-17 00:55:38

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 1/6] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

Unification of the atmel-mci driver to support the AT91 processors MCI interface. The atmel-mci driver currently supports the AVR32 and this patch adds AT91 support.

To use this new driver on a at91 the platform driver for your board needs to updated. See the following patch for an example of how to do that.

Signed-off-by: Rob Emanuele <[email protected]>
---
drivers/mmc/host/Kconfig | 16 ++++++++++++----
drivers/mmc/host/atmel-mci.c | 37 +++++++++++++++++++++++++++++++++----
2 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 40111a6..a0eaf69 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -135,6 +135,12 @@ config MMC_AU1X

If unsure, say N.

+choice
+ prompt "Atmel MMC Driver"
+ default MMC_ATMELMCI if AVR32
+ help
+ Choose which driver to use for the Atmel MCI Silicon
+
config MMC_AT91
tristate "AT91 SD/MMC Card Interface support"
depends on ARCH_AT91
@@ -145,17 +151,19 @@ config MMC_AT91

config MMC_ATMELMCI
tristate "Atmel Multimedia Card Interface support"
- depends on AVR32
+ depends on AVR32 || ARCH_AT91
help
This selects the Atmel Multimedia Card Interface driver. If
- you have an AT32 (AVR32) platform with a Multimedia Card
- slot, say Y or M here.
+ you have an AT32 (AVR32) or AT91 platform with a Multimedia
+ Card slot, say Y or M here.

If unsure, say N.

+endchoice
+
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support (EXPERIMENTAL)"
- depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+ depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
help
Say Y here to have the Atmel MCI driver use a DMA engine to
do data transfers and thus increase the throughput and
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 7b603e4..98b25de 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -30,11 +30,14 @@
#include <asm/io.h>
#include <asm/unaligned.h>

+#include <mach/cpu.h>
#include <mach/board.h>

#include "atmel-mci-regs.h"

-#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DATA_ERROR_FLAGS (MCI_RINDE | MCI_RDIRE | MCI_RCRCE \
+ | MCI_RENDE | MCI_RTOE | MCI_DCRCE \
+ | MCI_DTOE | MCI_OVRE | MCI_UNRE)
#define ATMCI_DMA_THRESHOLD 16

enum {
@@ -210,6 +213,18 @@ struct atmel_mci_slot {
set_bit(event, &host->pending_events)

/*
+ * Enable or disable features/registers based on
+ * whether the processor supports them
+ */
+static bool mci_has_rwproof(void)
+{
+ if (cpu_is_at91sam9261() || cpu_is_at91rm9200())
+ return false;
+ else
+ return true;
+}
+
+/*
* The debugfs stuff below is mostly optimized away when
* CONFIG_DEBUG_FS is not set.
*/
@@ -276,8 +291,13 @@ static void atmci_show_status_reg(struct seq_file *s,
[3] = "BLKE",
[4] = "DTIP",
[5] = "NOTBUSY",
+ [6] = "ENDRX",
+ [7] = "ENDTX",
[8] = "SDIOIRQA",
[9] = "SDIOIRQB",
+ [12] = "SDIOWAIT",
+ [14] = "RXBUFF",
+ [15] = "TXBUFE",
[16] = "RINDE",
[17] = "RDIRE",
[18] = "RCRCE",
@@ -285,6 +305,11 @@ static void atmci_show_status_reg(struct seq_file *s,
[20] = "RTOE",
[21] = "DCRCE",
[22] = "DTOE",
+ [23] = "CSTOE",
+ [24] = "BLKOVRE",
+ [25] = "DMADONE",
+ [26] = "FIFOEMPTY",
+ [27] = "XFRDONE",
[30] = "OVRE",
[31] = "UNRE",
};
@@ -849,13 +874,15 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clkdiv = 255;
}

+ host->mode_reg = MCI_MR_CLKDIV(clkdiv);
+
/*
* WRPROOF and RDPROOF prevent overruns/underruns by
* stopping the clock when the FIFO is full/empty.
* This state is not expected to last for long.
*/
- host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
- | MCI_MR_RDPROOF;
+ if (mci_has_rwproof())
+ host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);

if (list_empty(&host->queue))
mci_writel(host, MR, host->mode_reg);
@@ -1648,8 +1675,10 @@ static int __init atmci_probe(struct platform_device *pdev)
nr_slots++;
}

- if (!nr_slots)
+ if (!nr_slots) {
+ printk(KERN_ERR "Atmel MCI controller init failed. atmci_init_slot error or no slots with bus_width > 0.\n");
goto err_init_slot;
+ }

dev_info(&pdev->dev,
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
--
1.6.0.4


2009-06-17 00:55:51

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 2/6] atmel-mci: Platform configuration to the the atmel-mci driver

Created a modified version of the at91sam9g20 evaluation kit platform (board-sam9g20ek-2slot-mmc.c) and device support to make use of the updated atmel-mci driver.

This patch shows how an AT91 developer could add support for both SD slots for their project.

This requires getting the most updated arch/arm/tools/mach-types from http://www.arm.linux.org.uk/developer/machines/download.php to have the machine type for the modified at91sam9g20ek.

Signed-off-by: Rob Emanuele <[email protected]>
---
arch/arm/mach-at91/Kconfig | 7 +
arch/arm/mach-at91/Makefile | 1 +
arch/arm/mach-at91/at91sam9260_devices.c | 95 ++++++++
arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 277 ++++++++++++++++++++++++
arch/arm/mach-at91/include/mach/board.h | 5 +
5 files changed, 385 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 323b47f..5c8d770 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -276,6 +276,13 @@ config MACH_AT91SAM9G20EK
help
Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit.

+config MACH_AT91SAM9G20EK_2MMC
+ bool "Atmel AT91SAM9G20-EK Evaluation Kit modified for 2 MMC Slots"
+ depends on ARCH_AT91SAM9G20
+ help
+ Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
+ Rev A or B modified for 2 MMC Slots.
+
endif

# ----------------------------------------------------------
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c69ff23..cdddba8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o

# AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
+obj-$(CONFIG_MACH_AT91SAM9G20EK_2MMC) += board-sam9g20ek-2slot-mmc.o

# AT91CAP9 board-specific support
obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index d74c9ac..c372f4f 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -278,6 +278,101 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
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)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_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 = AT91SAM9260_ID_MCI,
+ .end = AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9260_mmc_device = {
+ .name = "atmel_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_mci(short mmc_id, struct mci_platform_data *data)
+{
+ unsigned int i;
+ unsigned int slot_count = 0;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (data->slot[i].bus_width) {
+ /* input/irq */
+ if (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 (data->slot[i].wp_pin)
+ at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+ switch(i) {
+ case 0:
+ /* CMD */
+ at91_set_A_periph(AT91_PIN_PA7, 1);
+ /* DAT0, maybe DAT1..DAT3 */
+ at91_set_A_periph(AT91_PIN_PA6, 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);
+ }
+ 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 (data->slot[i].bus_width == 4) {
+ at91_set_B_periph(AT91_PIN_PA5, 1);
+ at91_set_B_periph(AT91_PIN_PA4, 1);
+ at91_set_B_periph(AT91_PIN_PA3, 1);
+ }
+ break;
+ default:
+ printk("Configuration Error, No MMC Port %d\n",i);
+ break;
+ };
+ slot_count++;
+ }
+ }
+
+ if (slot_count) {
+ /* CLK */
+ at91_set_A_periph(AT91_PIN_PA8, 0);
+
+ mmc_data = *data;
+ platform_device_register(&at91sam9260_mmc_device);
+ }
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+
+

/* --------------------------------------------------------------------
* NAND / SmartMedia
diff --git a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
new file mode 100644
index 0000000..a28e53f
--- /dev/null
+++ b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ * Copyright (C) 2009 Rob Emanuele
+ *
+ * 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
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
+#include <linux/clk.h>
+
+#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>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init ek_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91sam9260_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);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init ek_init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata ek_usbh_data = {
+ .ports = 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata ek_udc_data = {
+ .vbus_pin = AT91_PIN_PC5,
+ .pullup_pin = 0, /* pull-up driven by UDC */
+};
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info ek_spi_devices[] = {
+#if !defined(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+ { /* DataFlash card */
+ .modalias = "mtd_dataflash",
+ .chip_select = 0,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+#endif
+#endif
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata ek_macb_data = {
+ .phy_irq_pin = AT91_PIN_PC12,
+ .is_rmii = 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata ek_nand_partition[] = {
+ {
+ .name = "Bootstrap",
+ .offset = 0,
+ .size = 4 * SZ_1M,
+ },
+ {
+ .name = "Partition 1",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = 60 * SZ_1M,
+ },
+ {
+ .name = "Partition 2",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+ *num_partitions = ARRAY_SIZE(ek_nand_partition);
+ return ek_nand_partition;
+}
+
+/* det_pin is not connected */
+static struct atmel_nand_data __initdata ek_nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .rdy_pin = AT91_PIN_PC13,
+ .enable_pin = AT91_PIN_PC14,
+ .partition_info = nand_partitions,
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
+ .bus_width_16 = 1,
+#else
+ .bus_width_16 = 0,
+#endif
+};
+
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 2,
+ .ncs_write_setup = 0,
+ .nwe_setup = 2,
+
+ .ncs_read_pulse = 4,
+ .nrd_pulse = 4,
+ .ncs_write_pulse = 4,
+ .nwe_pulse = 4,
+
+ .read_cycle = 7,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+ .tdf_cycles = 3,
+};
+
+static void __init ek_add_device_nand(void)
+{
+ /* setup bus-width (8 or 16) */
+ if (ek_nand_data.bus_width_16)
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+ else
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+ /* configure chip-select 3 (NAND) */
+ sam9_smc_configure(3, &ek_nand_smc_config);
+
+ at91_add_device_nand(&ek_nand_data);
+}
+
+
+/*
+ * MCI (SD/MMC)
+ * det_pin and wp_pin are not connected
+ */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata ek_mmc_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+ .slot[1] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+
+};
+#else
+static struct amci_platform_data __initdata ek_mmc_data = {
+};
+#endif
+
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+ { /* "bottom" led, green, userled1 to be defined */
+ .name = "ds5",
+ .gpio = AT91_PIN_PB12,
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+ { /* "power" led, yellow */
+ .name = "ds1",
+ .gpio = AT91_PIN_PB13,
+ .default_trigger = "heartbeat",
+ }
+};
+
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("24c512", 0x50),
+ },
+};
+
+
+static void __init ek_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+ /* USB Device */
+ at91_add_device_udc(&ek_udc_data);
+ /* SPI */
+ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* NAND */
+ ek_add_device_nand();
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+ at91_add_device_mci(0, &ek_mmc_data);
+ /* I2C */
+ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+ /* LEDs */
+ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ /* PCK0 provides MCLK to the WM8731 */
+ at91_set_B_periph(AT91_PIN_PC1, 0);
+ /* SSC (for WM8731) */
+ at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
+}
+
+MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+ /* Maintainer: Rob Emanuele */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = ek_map_io,
+ .init_irq = ek_init_irq,
+ .init_machine = ek_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index e6afff8..a635dad 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -37,6 +37,7 @@
#include <linux/leds.h>
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
+#include <linux/atmel-mci.h>

/* USB Device */
struct at91_udc_data {
@@ -63,6 +64,7 @@ struct at91_cf_data {
extern void __init at91_add_device_cf(struct at91_cf_data *data);

/* MMC / SD */
+ /* at91_mci platform config */
struct at91_mmc_data {
u8 det_pin; /* card detect IRQ */
unsigned slot_b:1; /* uses Slot B */
@@ -72,6 +74,9 @@ struct at91_mmc_data {
};
extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);

+ /* atmel-mci platform config */
+extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
+
/* Ethernet (EMAC & MACB) */
struct at91_eth_data {
u32 phy_mask;
--
1.6.0.4

2009-06-17 00:56:05

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 3/6] atmel-mci: Optional controller reset before every command

This patch adds the compile time configuration option for the atmel-mci driver to reset the Atmel MCI controller before every command.

This is sometimes needed for the Atmel controller / board to function properly.

Signed-off-by: Rob Emanuele <[email protected]>
---
drivers/mmc/host/Kconfig | 10 ++++++++++
drivers/mmc/host/atmel-mci.c | 11 ++++++++++-
2 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index a0eaf69..5875125 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -161,6 +161,16 @@ config MMC_ATMELMCI

endchoice

+config MMC_ATMELMCI_ALWAYS_RESET
+ bool "Reset before every request. Sometimes needed for buggy chips."
+ depends on MMC_ATMELMCI
+ help
+ There are reports that some buggy controllers work better
+ with a reset before every command. This may improve your
+ controller's reliability.
+
+ If unsure, say N.
+
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support (EXPERIMENTAL)"
depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 98b25de..e5894f6 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -63,6 +63,15 @@ struct atmel_mci_dma {
#endif
};

+/*
+ * Configuration options from the kernel config
+ */
+#ifdef CONFIG_MMC_ATMELMCI_ALWAYS_RESET
+#define MMC_ALWAYS_RESET 1
+#else
+#define MMC_ALWAYS_RESET 0
+#endif
+
/**
* struct atmel_mci - MMC controller state shared between all slots
* @lock: Spinlock protecting the queue and associated data.
@@ -720,7 +729,7 @@ static void atmci_start_request(struct atmel_mci *host,
host->completed_events = 0;
host->data_status = 0;

- if (host->need_reset) {
+ if (host->need_reset || MMC_ALWAYS_RESET) {
mci_writel(host, CR, MCI_CR_SWRST);
mci_writel(host, CR, MCI_CR_MCIEN);
mci_writel(host, MR, host->mode_reg);
--
1.6.0.4

2009-06-17 00:56:24

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 4/6] atmel-mci: CLKDIV cap to restrict the MCI controller speed

This patch adds the compile time configuration option for the atmel-mci driver to cap the MCI CLKDIV register value to a minimum value.

This is useful for debugging and for boards that have a long mci clock line.

Signed-off-by: Rob Emanuele <[email protected]>
---
drivers/mmc/host/Kconfig | 14 ++++++++++++++
drivers/mmc/host/atmel-mci.c | 10 ++++++++++
2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5875125..b628037 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -161,6 +161,20 @@ config MMC_ATMELMCI

endchoice

+config MMC_ATMELMCI_CLKDIV_CAP
+ int "Cap the CLKDIV to keep the controller from going too fast."
+ depends on MMC_ATMELMCI
+ default 0
+ range 0 255
+ help
+ This is the lowest value the clock divisor for the MMC
+ controller can be. Value is between 0 and 255.
+ MCI_CK = MCK/(2*(CLKDIV+1))
+ Raising this value may improve your controller's reliability
+ at the cost of speed.
+
+ If unsure, leave at 0.
+
config MMC_ATMELMCI_ALWAYS_RESET
bool "Reset before every request. Sometimes needed for buggy chips."
depends on MMC_ATMELMCI
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index e5894f6..601dae7 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -72,6 +72,10 @@ struct atmel_mci_dma {
#define MMC_ALWAYS_RESET 0
#endif

+#ifndef CONFIG_MMC_ATMELMCI_CLKDIV_CAP
+#define CONFIG_MMC_ATMELMCI_CLKDIV_CAP 0
+#endif
+
/**
* struct atmel_mci - MMC controller state shared between all slots
* @lock: Spinlock protecting the queue and associated data.
@@ -882,6 +886,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clock_min, host->bus_hz / (2 * 256));
clkdiv = 255;
}
+ if (clkdiv < CONFIG_MMC_ATMELMCI_CLKDIV_CAP) {
+ dev_warn(&mmc->class_dev,
+ "clkdiv %u too fast; capped using %u\n",
+ clkdiv, CONFIG_MMC_ATMELMCI_CLKDIV_CAP);
+ clkdiv = CONFIG_MMC_ATMELMCI_CLKDIV_CAP;
+ }

host->mode_reg = MCI_MR_CLKDIV(clkdiv);

--
1.6.0.4

2009-06-17 00:56:39

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 5/6] atmel-mci: Power control option for each MMC Slot

Add support to the atmel-mci driver for a VCC pin in order to conserve power by removing power from an MMC Slot.

Signed-off-by: Rob Emanuele <[email protected]>
---
drivers/mmc/host/atmel-mci.c | 33 ++++++++++++++++++++-------------
include/linux/atmel-mci.h | 2 ++
2 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 601dae7..63cd5c7 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -214,6 +214,8 @@ struct atmel_mci_slot {
int detect_pin;
int wp_pin;
bool detect_is_active_high;
+ int vcc_pin;
+ bool vcc_active_low;

struct timer_list detect_timer;
};
@@ -932,23 +934,19 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}

switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ if (gpio_is_valid(slot->vcc_pin))
+ gpio_set_value(slot->vcc_pin, slot->vcc_active_low);
+ break;
case MMC_POWER_UP:
+ if (gpio_is_valid(slot->vcc_pin))
+ gpio_set_value(slot->vcc_pin, !slot->vcc_active_low);
set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
break;
- default:
- /*
- * TODO: None of the currently available AVR32-based
- * boards allow MMC power to be turned off. Implement
- * power control when this can be tested properly.
- *
- * We also need to hook this into the clock management
- * somehow so that newly inserted cards aren't
- * subjected to a fast clock before we have a chance
- * to figure out what the maximum rate is. Currently,
- * there's no way to avoid this, and there never will
- * be for boards that don't support power control.
- */
+ case MMC_POWER_ON:
break;
+ default:
+ WARN_ON(1);
}
}

@@ -1507,6 +1505,8 @@ static int __init atmci_init_slot(struct atmel_mci *host,
slot->detect_pin = slot_data->detect_pin;
slot->wp_pin = slot_data->wp_pin;
slot->detect_is_active_high = slot_data->detect_is_active_high;
+ slot->vcc_pin = slot_data->vcc_pin;
+ slot->vcc_active_low = slot_data->vcc_active_low;
slot->sdc_reg = sdc_reg;

mmc->ops = &atmci_ops;
@@ -1544,6 +1544,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
}
}

+ if (gpio_is_valid(slot->vcc_pin)) {
+ if (gpio_request(slot->vcc_pin, "mmc_pow")) {
+ dev_dbg(&mmc->class_dev, "no power pin available\n");
+ slot->vcc_pin = -EBUSY;
+ }
+ }
+
host->slot[id] = slot;
mmc_add_host(mmc);

diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h
index 57b1846..7c15a7c 100644
--- a/include/linux/atmel-mci.h
+++ b/include/linux/atmel-mci.h
@@ -26,6 +26,8 @@ struct mci_slot_pdata {
int detect_pin;
int wp_pin;
bool detect_is_active_high;
+ int vcc_pin;
+ unsigned vcc_active_low:1;
};

/**
--
1.6.0.4

2009-06-17 00:56:53

by Robert Emanuele

[permalink] [raw]
Subject: [PATCH 6/6] atmel-mci: Platform driver MMC slot power control

Add support to the at91sam9g20ek_2mmc platform (board-sam9g20ek-2slot-mmc.c) and support files for a VCC pin using the atmel-mci driver.

Signed-off-by: Rob Emanuele <[email protected]>
---
arch/arm/mach-at91/at91sam9260_devices.c | 2 ++
arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 3 +++
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index c372f4f..7634632 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -328,6 +328,8 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
}
if (data->slot[i].wp_pin)
at91_set_gpio_input(data->slot[i].wp_pin, 1);
+ if (data->slot[i].vcc_pin)
+ at91_set_gpio_output(data->slot[i].vcc_pin, 0);

switch(i) {
case 0:
diff --git a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
index a28e53f..20c6738 100644
--- a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
+++ b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
@@ -202,11 +202,14 @@ static struct mci_platform_data __initdata ek_mmc_data = {
.bus_width = 4,
.detect_pin = -ENODEV,
.wp_pin = -ENODEV,
+ .vcc_pin = AT91_PIN_PA30,
+ .vcc_active_low = 1,
},
.slot[1] = {
.bus_width = 4,
.detect_pin = -ENODEV,
.wp_pin = -ENODEV,
+ .vcc_pin = -ENODEV,
},

};
--
1.6.0.4

2009-06-17 01:21:50

by Ryan Mallon

[permalink] [raw]
Subject: Re: [PATCH 6/6] atmel-mci: Platform driver MMC slot power control

Rob Emanuele wrote:
> Add support to the at91sam9g20ek_2mmc platform (board-sam9g20ek-2slot-mmc.c) and support files for a VCC pin using the atmel-mci driver.
>
> Signed-off-by: Rob Emanuele <[email protected]>
> ---
> arch/arm/mach-at91/at91sam9260_devices.c | 2 ++
> arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 3 +++
> 2 files changed, 5 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
> index c372f4f..7634632 100644
> --- a/arch/arm/mach-at91/at91sam9260_devices.c
> +++ b/arch/arm/mach-at91/at91sam9260_devices.c
> @@ -328,6 +328,8 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
> }
> if (data->slot[i].wp_pin)
> at91_set_gpio_input(data->slot[i].wp_pin, 1);
> + if (data->slot[i].vcc_pin)
> + at91_set_gpio_output(data->slot[i].vcc_pin, 0);
>

Can use gpio_direction_output on these.

~Ryan

--
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon Unit 5, Amuri Park
Phone: +64 3 3779127 404 Barbadoes St
Fax: +64 3 3779135 PO Box 13 889
Email: [email protected] Christchurch, 8013
Web: http://www.bluewatersys.com New Zealand
Freecall Australia 1800 148 751 USA 1800 261 2934

2009-06-17 08:29:02

by Marc Pignat

[permalink] [raw]
Subject: Re: [PATCH 5/6] atmel-mci: Power control option for each MMC Slot

Hi!

On Wednesday 17 June 2009 02:54:38 Rob Emanuele wrote:
> Add support to the atmel-mci driver for a VCC pin in order to conserve power by removing power from an MMC Slot.
...

> @@ -1544,6 +1544,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
> }
> }
>
> + if (gpio_is_valid(slot->vcc_pin)) {
> + if (gpio_request(slot->vcc_pin, "mmc_pow")) {

gpio_request will check for "gpio_is_valid" so this is not necessary.

> + dev_dbg(&mmc->class_dev, "no power pin available\n");
> + slot->vcc_pin = -EBUSY;
> + }
> + }
> +
...

Best regards

Marc

2009-06-17 08:32:44

by Marc Pignat

[permalink] [raw]
Subject: Re: [PATCH 3/6] atmel-mci: Optional controller reset before every command

Hi!

On Wednesday 17 June 2009 02:54:36 Rob Emanuele wrote:
> This patch adds the compile time configuration option for the atmel-mci driver to reset the Atmel MCI controller before every command.
>
> This is sometimes needed for the Atmel controller / board to function properly.
>
> Signed-off-by: Rob Emanuele <[email protected]>
> ---
> drivers/mmc/host/Kconfig | 10 ++++++++++
> drivers/mmc/host/atmel-mci.c | 11 ++++++++++-
> 2 files changed, 20 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index a0eaf69..5875125 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -161,6 +161,16 @@ config MMC_ATMELMCI
>
> endchoice
>
> +config MMC_ATMELMCI_ALWAYS_RESET
> + bool "Reset before every request. Sometimes needed for buggy chips."
> + depends on MMC_ATMELMCI
> + help
> + There are reports that some buggy controllers work better
> + with a reset before every command. This may improve your
> + controller's reliability.
> +
> + If unsure, say N.
> +
> config MMC_ATMELMCI_DMA
> bool "Atmel MCI DMA support (EXPERIMENTAL)"
> depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
> diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
> index 98b25de..e5894f6 100644
> --- a/drivers/mmc/host/atmel-mci.c
> +++ b/drivers/mmc/host/atmel-mci.c
> @@ -63,6 +63,15 @@ struct atmel_mci_dma {
> #endif
> };
>
> +/*
> + * Configuration options from the kernel config
> + */
> +#ifdef CONFIG_MMC_ATMELMCI_ALWAYS_RESET
> +#define MMC_ALWAYS_RESET 1
> +#else
> +#define MMC_ALWAYS_RESET 0
> +#endif

Some chips are known to hang after (some) transfer. There is no need for this
configuration option, I think we should just do :

#define MMC_ALWAYS_RESET (cpu_is_at91rm9200() || add_your_cpu_name_here())

> +
> /**
> * struct atmel_mci - MMC controller state shared between all slots
> * @lock: Spinlock protecting the queue and associated data.
> @@ -720,7 +729,7 @@ static void atmci_start_request(struct atmel_mci *host,
> host->completed_events = 0;
> host->data_status = 0;
>
> - if (host->need_reset) {
> + if (host->need_reset || MMC_ALWAYS_RESET) {
> mci_writel(host, CR, MCI_CR_SWRST);
> mci_writel(host, CR, MCI_CR_MCIEN);
> mci_writel(host, MR, host->mode_reg);

Another option is to always reset the controller.

The reset operation won't hurt, it is simple and fast, and the code will be
simpler and better tested.

Best regards

Marc

2009-06-17 09:56:52

by Nicolas Ferre

[permalink] [raw]
Subject: Re: [PATCH 1/6] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

Rob, Haavard,

Rob Emanuele :
> Unification of the atmel-mci driver to support the AT91 processors MCI interface. The atmel-mci driver currently supports the AVR32 and this patch adds AT91 support.
>
> To use this new driver on a at91 the platform driver for your board needs to updated. See the following patch for an example of how to do that.

I format those lines remove last sentence and add :
"Add read/write proof selection switch dependent on chip availability
of this feature."


> Signed-off-by: Rob Emanuele <[email protected]>
> ---
> drivers/mmc/host/Kconfig | 16 ++++++++++++----
> drivers/mmc/host/atmel-mci.c | 37 +++++++++++++++++++++++++++++++++----
> 2 files changed, 45 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 40111a6..a0eaf69 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -135,6 +135,12 @@ config MMC_AU1X
>
> If unsure, say N.
>
> +choice
> + prompt "Atmel MMC Driver"

I add SD/MMC

> + default MMC_ATMELMCI if AVR32
> + help
> + Choose which driver to use for the Atmel MCI Silicon
> +
> config MMC_AT91
> tristate "AT91 SD/MMC Card Interface support"
> depends on ARCH_AT91
> @@ -145,17 +151,19 @@ config MMC_AT91
>
> config MMC_ATMELMCI
> tristate "Atmel Multimedia Card Interface support"
> - depends on AVR32
> + depends on AVR32 || ARCH_AT91
> help
> This selects the Atmel Multimedia Card Interface driver. If
> - you have an AT32 (AVR32) platform with a Multimedia Card
> - slot, say Y or M here.
> + you have an AT32 (AVR32) or AT91 platform with a Multimedia
> + Card slot, say Y or M here.
>
> If unsure, say N.
>
> +endchoice
> +
> config MMC_ATMELMCI_DMA
> bool "Atmel MCI DMA support (EXPERIMENTAL)"
> - depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
> + depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
> help
> Say Y here to have the Atmel MCI driver use a DMA engine to
> do data transfers and thus increase the throughput and
> diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
> index 7b603e4..98b25de 100644
> --- a/drivers/mmc/host/atmel-mci.c
> +++ b/drivers/mmc/host/atmel-mci.c
> @@ -30,11 +30,14 @@
> #include <asm/io.h>
> #include <asm/unaligned.h>
>
> +#include <mach/cpu.h>
> #include <mach/board.h>
>
> #include "atmel-mci-regs.h"
>
> -#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
> +#define ATMCI_DATA_ERROR_FLAGS (MCI_RINDE | MCI_RDIRE | MCI_RCRCE \
> + | MCI_RENDE | MCI_RTOE | MCI_DCRCE \
> + | MCI_DTOE | MCI_OVRE | MCI_UNRE)

Haavard, is it ok to add those flags on an AVR32 platform for now ?

> #define ATMCI_DMA_THRESHOLD 16
>
> enum {
> @@ -210,6 +213,18 @@ struct atmel_mci_slot {
> set_bit(event, &host->pending_events)
>
> /*
> + * Enable or disable features/registers based on
> + * whether the processor supports them
> + */
> +static bool mci_has_rwproof(void)
> +{
> + if (cpu_is_at91sam9261() || cpu_is_at91rm9200())
> + return false;
> + else
> + return true;
> +}
> +
> +/*
> * The debugfs stuff below is mostly optimized away when
> * CONFIG_DEBUG_FS is not set.
> */
> @@ -276,8 +291,13 @@ static void atmci_show_status_reg(struct seq_file *s,
> [3] = "BLKE",
> [4] = "DTIP",
> [5] = "NOTBUSY",
> + [6] = "ENDRX",
> + [7] = "ENDTX",
> [8] = "SDIOIRQA",
> [9] = "SDIOIRQB",
> + [12] = "SDIOWAIT",
> + [14] = "RXBUFF",
> + [15] = "TXBUFE",
> [16] = "RINDE",
> [17] = "RDIRE",
> [18] = "RCRCE",
> @@ -285,6 +305,11 @@ static void atmci_show_status_reg(struct seq_file *s,
> [20] = "RTOE",
> [21] = "DCRCE",
> [22] = "DTOE",
> + [23] = "CSTOE",
> + [24] = "BLKOVRE",
> + [25] = "DMADONE",
> + [26] = "FIFOEMPTY",
> + [27] = "XFRDONE",

Little indentation modifications.

> [30] = "OVRE",
> [31] = "UNRE",
> };
> @@ -849,13 +874,15 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> clkdiv = 255;
> }
>
> + host->mode_reg = MCI_MR_CLKDIV(clkdiv);
> +
> /*
> * WRPROOF and RDPROOF prevent overruns/underruns by
> * stopping the clock when the FIFO is full/empty.
> * This state is not expected to last for long.
> */
> - host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
> - | MCI_MR_RDPROOF;
> + if (mci_has_rwproof())
> + host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);
>
> if (list_empty(&host->queue))
> mci_writel(host, MR, host->mode_reg);
> @@ -1648,8 +1675,10 @@ static int __init atmci_probe(struct platform_device *pdev)
> nr_slots++;
> }
>
> - if (!nr_slots)
> + if (!nr_slots) {
> + printk(KERN_ERR "Atmel MCI controller init failed. atmci_init_slot error or no slots with bus_width > 0.\n");

I change this to :
dev_err(&pdev->dev, "init failed: no slot defined\n");

> goto err_init_slot;
> + }
>
> dev_info(&pdev->dev,
> "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",

If Haavard is ok, I post the patch to Pierre Ossman with the tiny
modifications above (your SOB & From: preserved of course).

Thanks, Bye,
--
Nicolas Ferre

2009-06-17 10:09:05

by Haavard Skinnemoen

[permalink] [raw]
Subject: Re: [PATCH 1/6] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

Nicolas Ferre wrote:
> > -#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
> > +#define ATMCI_DATA_ERROR_FLAGS (MCI_RINDE | MCI_RDIRE | MCI_RCRCE \
> > + | MCI_RENDE | MCI_RTOE | MCI_DCRCE \
> > + | MCI_DTOE | MCI_OVRE | MCI_UNRE)
>
> Haavard, is it ok to add those flags on an AVR32 platform for now ?

It probably doesn't hurt on AVR32. But I'm not a great fan since it
seems like the wrong thing to do, and it may simply mask the real
problem.

Haavard

2009-06-17 10:28:01

by Nicolas Ferre

[permalink] [raw]
Subject: Re: [PATCH 2/6] atmel-mci: Platform configuration to the the atmel-mci driver

Rob Emanuele :
> Created a modified version of the at91sam9g20 evaluation kit platform (board-sam9g20ek-2slot-mmc.c) and device support to make use of the updated atmel-mci driver.
>
> This patch shows how an AT91 developer could add support for both SD slots for their project.

Comment formated.

> This requires getting the most updated arch/arm/tools/mach-types from http://www.arm.linux.org.uk/developer/machines/download.php to have the machine type for the modified at91sam9g20ek.

Ok moved below "---"

> Signed-off-by: Rob Emanuele <[email protected]>
> ---
> arch/arm/mach-at91/Kconfig | 7 +
> arch/arm/mach-at91/Makefile | 1 +
> arch/arm/mach-at91/at91sam9260_devices.c | 95 ++++++++
> arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 277 ++++++++++++++++++++++++
> arch/arm/mach-at91/include/mach/board.h | 5 +
> 5 files changed, 385 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 323b47f..5c8d770 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -276,6 +276,13 @@ config MACH_AT91SAM9G20EK
> help
> Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit.
>
> +config MACH_AT91SAM9G20EK_2MMC
> + bool "Atmel AT91SAM9G20-EK Evaluation Kit modified for 2 MMC Slots"
> + depends on ARCH_AT91SAM9G20
> + help
> + Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
> + Rev A or B modified for 2 MMC Slots.
> +
> endif
>
> # ----------------------------------------------------------
> diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
> index c69ff23..cdddba8 100644
> --- a/arch/arm/mach-at91/Makefile
> +++ b/arch/arm/mach-at91/Makefile
> @@ -54,6 +54,7 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o
>
> # AT91SAM9G20 board-specific support
> obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
> +obj-$(CONFIG_MACH_AT91SAM9G20EK_2MMC) += board-sam9g20ek-2slot-mmc.o
>
> # AT91CAP9 board-specific support
> obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
> diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
> index d74c9ac..c372f4f 100644
> --- a/arch/arm/mach-at91/at91sam9260_devices.c
> +++ b/arch/arm/mach-at91/at91sam9260_devices.c
> @@ -278,6 +278,101 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
> 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)
> +static u64 mmc_dmamask = DMA_BIT_MASK(32);
> +static struct mci_platform_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 = AT91SAM9260_ID_MCI,
> + .end = AT91SAM9260_ID_MCI,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
> +static struct platform_device at91sam9260_mmc_device = {
> + .name = "atmel_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_mci(short mmc_id, struct mci_platform_data *data)
> +{
> + unsigned int i;
> + unsigned int slot_count = 0;
> +
> + if (!data)
> + return;
> +
> + for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
> + if (data->slot[i].bus_width) {

Indentation.

> + /* input/irq */
> + if (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 (data->slot[i].wp_pin)
> + at91_set_gpio_input(data->slot[i].wp_pin, 1);
> +
> + switch(i) {
> + case 0:
> + /* CMD */
> + at91_set_A_periph(AT91_PIN_PA7, 1);
> + /* DAT0, maybe DAT1..DAT3 */
> + at91_set_A_periph(AT91_PIN_PA6, 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);
> + }

I put slot_count here...
+ slot_count++;

> + 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 (data->slot[i].bus_width == 4) {
> + at91_set_B_periph(AT91_PIN_PA5, 1);
> + at91_set_B_periph(AT91_PIN_PA4, 1);
> + at91_set_B_periph(AT91_PIN_PA3, 1);
> + }

and here...
+ slot_count++;

> + break;
> + default:
> + printk("Configuration Error, No MMC Port %d\n",i);

Replaced with:
printk(KERN_ERR
"AT91: SD/MMC slot %d not available\n", i);


> + break;
> + };

removed here.

> + slot_count++;
> + }
> + }
> +
> + if (slot_count) {
> + /* CLK */
> + at91_set_A_periph(AT91_PIN_PA8, 0);
> +
> + mmc_data = *data;
> + platform_device_register(&at91sam9260_mmc_device);
> + }
> +}
> +#else
> +void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
> +#endif
> +
> +
>
> /* --------------------------------------------------------------------
> * NAND / SmartMedia
> diff --git a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
> new file mode 100644
> index 0000000..a28e53f
> --- /dev/null
> +++ b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c

Ok. True that it duplicates code but it is simpler.
It also can be a testbed for future -EK revision D and following.

[..]


> diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
> index e6afff8..a635dad 100644
> --- a/arch/arm/mach-at91/include/mach/board.h
> +++ b/arch/arm/mach-at91/include/mach/board.h
> @@ -37,6 +37,7 @@
> #include <linux/leds.h>
> #include <linux/spi/spi.h>
> #include <linux/usb/atmel_usba_udc.h>
> +#include <linux/atmel-mci.h>
>
> /* USB Device */
> struct at91_udc_data {
> @@ -63,6 +64,7 @@ struct at91_cf_data {
> extern void __init at91_add_device_cf(struct at91_cf_data *data);
>
> /* MMC / SD */
> + /* at91_mci platform config */
> struct at91_mmc_data {
> u8 det_pin; /* card detect IRQ */
> unsigned slot_b:1; /* uses Slot B */
> @@ -72,6 +74,9 @@ struct at91_mmc_data {
> };
> extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
>
> + /* atmel-mci platform config */
> +extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
> +
> /* Ethernet (EMAC & MACB) */
> struct at91_eth_data {
> u32 phy_mask;

Ok.


I post the patch to Andrew Victor with the tiny
modifications above (your SOB & From: preserved of course).

Thanks, Bye,

--
Nicolas Ferre

2009-06-17 18:28:08

by Robert Emanuele

[permalink] [raw]
Subject: Re: [PATCH 3/6] atmel-mci: Optional controller reset before every command

Marc,

(This may be a resend, gmail and its fancy text hates me.)

There has been debate over whether always reseting the MCI controller
is the correct thing to do. I think for some platforms it is required
but there is no consensus to what those platforms are. I think the
config option is the best of both worlds as a user of this
kernel/driver can choose to enable this or not without having to
modify their source. It may even be a decent idea to enable this
option if they are using certain chips that we know reseting improves
their behavior.

Thank you,
Rob

2009-06-18 19:58:44

by Andrew Victor

[permalink] [raw]
Subject: Re: [PATCH 2/6] atmel-mci: Platform configuration to the the atmel-mci driver

hi,

> + if (data->slot[i].bus_width) {
> + /* input/irq */
> + if (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 (data->slot[i].wp_pin)
> + at91_set_gpio_input(data->slot[i].wp_pin, 1);

The current at91_mci also allows the driver to control the "vcc_pin".
Can that functionality be merged into atmel_mci driver?


Regards.
Andre Victor

2009-06-18 20:00:36

by Andrew Victor

[permalink] [raw]
Subject: Re: [PATCH 2/6] atmel-mci: Platform configuration to the the atmel-mci driver

> The current at91_mci also allows the driver to control the "vcc_pin".
> Can that functionality be merged into atmel_mci driver?

Ignore that comment, I see it's in Patch 5.

2009-06-23 16:29:22

by Nicolas Ferre

[permalink] [raw]
Subject: Re: [PATCH 1/6] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

Haavard Skinnemoen :
> Nicolas Ferre wrote:
>>> -#define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
>>> +#define ATMCI_DATA_ERROR_FLAGS (MCI_RINDE | MCI_RDIRE | MCI_RCRCE \
>>> + | MCI_RENDE | MCI_RTOE | MCI_DCRCE \
>>> + | MCI_DTOE | MCI_OVRE | MCI_UNRE)
>> Haavard, is it ok to add those flags on an AVR32 platform for now ?
>
> It probably doesn't hurt on AVR32. But I'm not a great fan since it
> seems like the wrong thing to do, and it may simply mask the real
> problem.

Agreed.

To move forward, I will submit a first patch series without those flags
added.

Best regards,
--
Nicolas Ferre

2009-06-23 16:36:44

by Nicolas Ferre

[permalink] [raw]
Subject: [PATCH 2/2] AT91: atmel-mci: Platform configuration to the the atmel-mci driver

From: Rob Emanuele <[email protected]>

Created a modified version of the at91sam9g20 evaluation kit platform
(board-sam9g20ek-2slot-mmc.c) and device support to make use of the updated
atmel-mci driver.
As the use of two slots modify GPIO pin allocation, we create another board
file.

Signed-off-by: Rob Emanuele <[email protected]>
[[email protected]: printk, slot_count modification in at91sam9260_devices.c file]
Signed-off-by: Nicolas Ferre <[email protected]>
---
This requires getting the most updated arch/arm/tools/mach-types from
http://www.arm.linux.org.uk/developer/machines/download.php to have the machine
type for the at91sam9g20ek-2slot-mmc board.

arch/arm/mach-at91/Kconfig | 7 +
arch/arm/mach-at91/Makefile | 1 +
arch/arm/mach-at91/at91sam9260_devices.c | 96 ++++++++
arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 277 ++++++++++++++++++++++++
arch/arm/mach-at91/include/mach/board.h | 5 +
5 files changed, 386 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 323b47f..5c8d770 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -276,6 +276,13 @@ config MACH_AT91SAM9G20EK
help
Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit.

+config MACH_AT91SAM9G20EK_2MMC
+ bool "Atmel AT91SAM9G20-EK Evaluation Kit modified for 2 MMC Slots"
+ depends on ARCH_AT91SAM9G20
+ help
+ Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
+ Rev A or B modified for 2 MMC Slots.
+
endif

# ----------------------------------------------------------
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c69ff23..cdddba8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o

# AT91SAM9G20 board-specific support
obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
+obj-$(CONFIG_MACH_AT91SAM9G20EK_2MMC) += board-sam9g20ek-2slot-mmc.o

# AT91CAP9 board-specific support
obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index d74c9ac..86a29bf 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -278,6 +278,102 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
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)
+static u64 mmc_dmamask = DMA_BIT_MASK(32);
+static struct mci_platform_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 = AT91SAM9260_ID_MCI,
+ .end = AT91SAM9260_ID_MCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9260_mmc_device = {
+ .name = "atmel_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_mci(short mmc_id, struct mci_platform_data *data)
+{
+ unsigned int i;
+ unsigned int slot_count = 0;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+ if (data->slot[i].bus_width) {
+ /* input/irq */
+ if (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 (data->slot[i].wp_pin)
+ at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+ switch(i) {
+ case 0:
+ /* CMD */
+ at91_set_A_periph(AT91_PIN_PA7, 1);
+ /* DAT0, maybe DAT1..DAT3 */
+ at91_set_A_periph(AT91_PIN_PA6, 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:
+ /* CMD */
+ at91_set_B_periph(AT91_PIN_PA1, 1);
+ /* DAT0, maybe DAT1..DAT3 */
+ at91_set_B_periph(AT91_PIN_PA0, 1);
+ if (data->slot[i].bus_width == 4) {
+ at91_set_B_periph(AT91_PIN_PA5, 1);
+ at91_set_B_periph(AT91_PIN_PA4, 1);
+ at91_set_B_periph(AT91_PIN_PA3, 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_PA8, 0);
+
+ mmc_data = *data;
+ platform_device_register(&at91sam9260_mmc_device);
+ }
+}
+#else
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
+#endif
+

/* --------------------------------------------------------------------
* NAND / SmartMedia
diff --git a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
new file mode 100644
index 0000000..a28e53f
--- /dev/null
+++ b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2008 Atmel
+ * Copyright (C) 2009 Rob Emanuele
+ *
+ * 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
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
+#include <linux/clk.h>
+
+#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>
+#include <mach/at91sam9_smc.h>
+
+#include "sam9_smc.h"
+#include "generic.h"
+
+
+static void __init ek_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91sam9260_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);
+
+ /* set serial console to ttyS0 (ie, DBGU) */
+ at91_set_serial_console(0);
+}
+
+static void __init ek_init_irq(void)
+{
+ at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata ek_usbh_data = {
+ .ports = 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata ek_udc_data = {
+ .vbus_pin = AT91_PIN_PC5,
+ .pullup_pin = 0, /* pull-up driven by UDC */
+};
+
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info ek_spi_devices[] = {
+#if !defined(CONFIG_MMC_ATMELMCI)
+ { /* DataFlash chip */
+ .modalias = "mtd_dataflash",
+ .chip_select = 1,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+ { /* DataFlash card */
+ .modalias = "mtd_dataflash",
+ .chip_select = 0,
+ .max_speed_hz = 15 * 1000 * 1000,
+ .bus_num = 0,
+ },
+#endif
+#endif
+};
+
+
+/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata ek_macb_data = {
+ .phy_irq_pin = AT91_PIN_PC12,
+ .is_rmii = 1,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata ek_nand_partition[] = {
+ {
+ .name = "Bootstrap",
+ .offset = 0,
+ .size = 4 * SZ_1M,
+ },
+ {
+ .name = "Partition 1",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = 60 * SZ_1M,
+ },
+ {
+ .name = "Partition 2",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
+{
+ *num_partitions = ARRAY_SIZE(ek_nand_partition);
+ return ek_nand_partition;
+}
+
+/* det_pin is not connected */
+static struct atmel_nand_data __initdata ek_nand_data = {
+ .ale = 21,
+ .cle = 22,
+ .rdy_pin = AT91_PIN_PC13,
+ .enable_pin = AT91_PIN_PC14,
+ .partition_info = nand_partitions,
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
+ .bus_width_16 = 1,
+#else
+ .bus_width_16 = 0,
+#endif
+};
+
+static struct sam9_smc_config __initdata ek_nand_smc_config = {
+ .ncs_read_setup = 0,
+ .nrd_setup = 2,
+ .ncs_write_setup = 0,
+ .nwe_setup = 2,
+
+ .ncs_read_pulse = 4,
+ .nrd_pulse = 4,
+ .ncs_write_pulse = 4,
+ .nwe_pulse = 4,
+
+ .read_cycle = 7,
+ .write_cycle = 7,
+
+ .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
+ .tdf_cycles = 3,
+};
+
+static void __init ek_add_device_nand(void)
+{
+ /* setup bus-width (8 or 16) */
+ if (ek_nand_data.bus_width_16)
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
+ else
+ ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
+
+ /* configure chip-select 3 (NAND) */
+ sam9_smc_configure(3, &ek_nand_smc_config);
+
+ at91_add_device_nand(&ek_nand_data);
+}
+
+
+/*
+ * MCI (SD/MMC)
+ * det_pin and wp_pin are not connected
+ */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata ek_mmc_data = {
+ .slot[0] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+ .slot[1] = {
+ .bus_width = 4,
+ .detect_pin = -ENODEV,
+ .wp_pin = -ENODEV,
+ },
+
+};
+#else
+static struct amci_platform_data __initdata ek_mmc_data = {
+};
+#endif
+
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+ { /* "bottom" led, green, userled1 to be defined */
+ .name = "ds5",
+ .gpio = AT91_PIN_PB12,
+ .active_low = 1,
+ .default_trigger = "none",
+ },
+ { /* "power" led, yellow */
+ .name = "ds1",
+ .gpio = AT91_PIN_PB13,
+ .default_trigger = "heartbeat",
+ }
+};
+
+static struct i2c_board_info __initdata ek_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("24c512", 0x50),
+ },
+};
+
+
+static void __init ek_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* USB Host */
+ at91_add_device_usbh(&ek_usbh_data);
+ /* USB Device */
+ at91_add_device_udc(&ek_udc_data);
+ /* SPI */
+ at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* NAND */
+ ek_add_device_nand();
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
+ /* MMC */
+ at91_add_device_mci(0, &ek_mmc_data);
+ /* I2C */
+ at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
+ /* LEDs */
+ at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+ /* PCK0 provides MCLK to the WM8731 */
+ at91_set_B_periph(AT91_PIN_PC1, 0);
+ /* SSC (for WM8731) */
+ at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
+}
+
+MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+ /* Maintainer: Rob Emanuele */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91sam926x_timer,
+ .map_io = ek_map_io,
+ .init_irq = ek_init_irq,
+ .init_machine = ek_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index e6afff8..a635dad 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -37,6 +37,7 @@
#include <linux/leds.h>
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
+#include <linux/atmel-mci.h>

/* USB Device */
struct at91_udc_data {
@@ -63,6 +64,7 @@ struct at91_cf_data {
extern void __init at91_add_device_cf(struct at91_cf_data *data);

/* MMC / SD */
+ /* at91_mci platform config */
struct at91_mmc_data {
u8 det_pin; /* card detect IRQ */
unsigned slot_b:1; /* uses Slot B */
@@ -72,6 +74,9 @@ struct at91_mmc_data {
};
extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);

+ /* atmel-mci platform config */
+extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
+
/* Ethernet (EMAC & MACB) */
struct at91_eth_data {
u32 phy_mask;
--
1.5.3.7

2009-06-23 16:36:56

by Nicolas Ferre

[permalink] [raw]
Subject: [PATCH 1/2] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

From: Rob Emanuele <[email protected]>

Unification of the atmel-mci driver to support the AT91 processors MCI
interface. The atmel-mci driver currently supports the AVR32 and this patch
adds AT91 support.
Add read/write proof selection switch dependent on chip availability of this
feature.

To use this new driver on a at91 the platform driver for your board needs to
updated.

Signed-off-by: Rob Emanuele <[email protected]>
[[email protected] indent, Kconfig comment and one printk modification]
Signed-off-by: Nicolas Ferre <[email protected]>
---
drivers/mmc/host/Kconfig | 16 ++++++++++++----
drivers/mmc/host/atmel-mci.c | 33 ++++++++++++++++++++++++++++++---
2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index b4cf691..e779049 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -124,6 +124,12 @@ config MMC_AU1X

If unsure, say N.

+choice
+ prompt "Atmel SD/MMC Driver"
+ default MMC_ATMELMCI if AVR32
+ help
+ Choose which driver to use for the Atmel MCI Silicon
+
config MMC_AT91
tristate "AT91 SD/MMC Card Interface support"
depends on ARCH_AT91
@@ -134,17 +140,19 @@ config MMC_AT91

config MMC_ATMELMCI
tristate "Atmel Multimedia Card Interface support"
- depends on AVR32
+ depends on AVR32 || ARCH_AT91
help
This selects the Atmel Multimedia Card Interface driver. If
- you have an AT32 (AVR32) platform with a Multimedia Card
- slot, say Y or M here.
+ you have an AT32 (AVR32) or AT91 platform with a Multimedia
+ Card slot, say Y or M here.

If unsure, say N.

+endchoice
+
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support (EXPERIMENTAL)"
- depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+ depends on MMC_ATMELMCI && AVR32 && DMA_ENGINE && EXPERIMENTAL
help
Say Y here to have the Atmel MCI driver use a DMA engine to
do data transfers and thus increase the throughput and
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 7b603e4..065fa81 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -30,6 +30,7 @@
#include <asm/io.h>
#include <asm/unaligned.h>

+#include <mach/cpu.h>
#include <mach/board.h>

#include "atmel-mci-regs.h"
@@ -210,6 +211,18 @@ struct atmel_mci_slot {
set_bit(event, &host->pending_events)

/*
+ * Enable or disable features/registers based on
+ * whether the processor supports them
+ */
+static bool mci_has_rwproof(void)
+{
+ if (cpu_is_at91sam9261() || cpu_is_at91rm9200())
+ return false;
+ else
+ return true;
+}
+
+/*
* The debugfs stuff below is mostly optimized away when
* CONFIG_DEBUG_FS is not set.
*/
@@ -276,8 +289,13 @@ static void atmci_show_status_reg(struct seq_file *s,
[3] = "BLKE",
[4] = "DTIP",
[5] = "NOTBUSY",
+ [6] = "ENDRX",
+ [7] = "ENDTX",
[8] = "SDIOIRQA",
[9] = "SDIOIRQB",
+ [12] = "SDIOWAIT",
+ [14] = "RXBUFF",
+ [15] = "TXBUFE",
[16] = "RINDE",
[17] = "RDIRE",
[18] = "RCRCE",
@@ -285,6 +303,11 @@ static void atmci_show_status_reg(struct seq_file *s,
[20] = "RTOE",
[21] = "DCRCE",
[22] = "DTOE",
+ [23] = "CSTOE",
+ [24] = "BLKOVRE",
+ [25] = "DMADONE",
+ [26] = "FIFOEMPTY",
+ [27] = "XFRDONE",
[30] = "OVRE",
[31] = "UNRE",
};
@@ -849,13 +872,15 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clkdiv = 255;
}

+ host->mode_reg = MCI_MR_CLKDIV(clkdiv);
+
/*
* WRPROOF and RDPROOF prevent overruns/underruns by
* stopping the clock when the FIFO is full/empty.
* This state is not expected to last for long.
*/
- host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
- | MCI_MR_RDPROOF;
+ if (mci_has_rwproof())
+ host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);

if (list_empty(&host->queue))
mci_writel(host, MR, host->mode_reg);
@@ -1648,8 +1673,10 @@ static int __init atmci_probe(struct platform_device *pdev)
nr_slots++;
}

- if (!nr_slots)
+ if (!nr_slots) {
+ dev_err(&pdev->dev, "init failed: no slot defined\n");
goto err_init_slot;
+ }

dev_info(&pdev->dev,
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
--
1.5.3.7

Subject: Re: [PATCH 2/2] AT91: atmel-mci: Platform configuration to the the atmel-mci driver

On 19:39 Tue 23 Jun , Nicolas Ferre wrote:
> From: Rob Emanuele <[email protected]>
>
> Created a modified version of the at91sam9g20 evaluation kit platform
> (board-sam9g20ek-2slot-mmc.c) and device support to make use of the updated
> atmel-mci driver.
> As the use of two slots modify GPIO pin allocation, we create another board
> file.
>
> Signed-off-by: Rob Emanuele <[email protected]>
> [[email protected]: printk, slot_count modification in at91sam9260_devices.c file]
> Signed-off-by: Nicolas Ferre <[email protected]>
> ---
> This requires getting the most updated arch/arm/tools/mach-types from
> http://www.arm.linux.org.uk/developer/machines/download.php to have the machine
> type for the at91sam9g20ek-2slot-mmc board.
>
> arch/arm/mach-at91/Kconfig | 7 +
> arch/arm/mach-at91/Makefile | 1 +
> arch/arm/mach-at91/at91sam9260_devices.c | 96 ++++++++
> arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c | 277 ++++++++++++++++++++++++
> arch/arm/mach-at91/include/mach/board.h | 5 +
> 5 files changed, 386 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
>
> diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
> index 323b47f..5c8d770 100644
> --- a/arch/arm/mach-at91/Kconfig
> +++ b/arch/arm/mach-at91/Kconfig
> @@ -276,6 +276,13 @@ config MACH_AT91SAM9G20EK
> help
> Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit.
>
> +config MACH_AT91SAM9G20EK_2MMC
> + bool "Atmel AT91SAM9G20-EK Evaluation Kit modified for 2 MMC Slots"
> + depends on ARCH_AT91SAM9G20
> + help
> + Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
> + Rev A or B modified for 2 MMC Slots.
create a new machine id for just such update :(
is this not possible to detect it and use the same machine?

Best Regards,
J.

2009-06-26 19:26:26

by Robert Emanuele

[permalink] [raw]
Subject: Re: [PATCH 2/2] AT91: atmel-mci: Platform configuration to the the atmel-mci driver

After talking with Nicholas Ferre, we decided there were enough
changes made to the at91sam9g20-ek (eval kit) that it warranted its
own machine and related board-xxx.c file. In addition, Atmel has
released schematics for its newest revision of the at91sam9g20-ek
(rev. D) which will go into production once their supply of rev. C
boards is sufficiently small. The rev. D board is much different than
the previous revisions. The new machine with its board file is an
excellent base to build on once the rev. D board is released.

Thank you,

Rob Emanuele

2009-09-02 07:31:32

by Haavard Skinnemoen

[permalink] [raw]
Subject: Re: [PATCH 1/2] atmel-mci: Unified Atmel MCI drivers (AVR32 & AT91)

Nicolas Ferre <[email protected]> wrote:
> From: Rob Emanuele <[email protected]>
>
> Unification of the atmel-mci driver to support the AT91 processors MCI
> interface. The atmel-mci driver currently supports the AVR32 and this patch
> adds AT91 support.
> Add read/write proof selection switch dependent on chip availability of this
> feature.
>
> To use this new driver on a at91 the platform driver for your board needs to
> updated.
>
> Signed-off-by: Rob Emanuele <[email protected]>
> [[email protected] indent, Kconfig comment and one printk modification]
> Signed-off-by: Nicolas Ferre <[email protected]>

Acked-by: Haavard Skinnemoen <[email protected]>