Расширенный моддинг MMC

Способ подключения
Способ подключения

Схема подключения успешно опробована на шине питания GPIO = 2.6V

Существует два способа модификации с использованием разных GPIO для CS1, а также два варианта установки необходимого ПО для непосредственного использования карточки памяти подключенной к устройству.
Примечание: Эта модификация, как и модификация mmc_over_gpio - не поддерживает SDHC карточки памяти на уровне драйвера.

Более подробно мод расписан в соседней английской версии.

<p style="border:2px dashed red;">Первый способ.</p>

Вариант GPIO как CS1

В качестве CS для MMC/SD карты памяти, предпочтительнее использовать любой свободный GPIO пин.

Использование GPIO 7 - как CS1 для общей шины:
Index: target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
===================================================================
--- target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c	(revision 34914)
+++ target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c	(working copy)
@@ -50,7 +50,7 @@
 void __init ath79_register_m25p80(struct flash_platform_data *pdata)
 {
 	ath79_spi_data.bus_num = 0;
-	ath79_spi_data.num_chipselect = 1;
+	ath79_spi_data.num_chipselect = 2;
 	ath79_spi0_cdata.is_flash = true;
 	ath79_spi_info[0].platform_data = pdata;
 	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
Index: target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
===================================================================
--- target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c	(revision 34914)
+++ target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c	(working copy)
@@ -9,6 +9,9 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
 
 #include <asm/mach-ath79/ath79.h>
 
@@ -16,12 +19,14 @@
 #include "dev-ap9x-pci.h"
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
+#include "dev-spi.h"
 #include "dev-m25p80.h"
 #include "dev-usb.h"
 #include "machtypes.h"
 
 #define TL_MR3X20_GPIO_LED_QSS		0
 #define TL_MR3X20_GPIO_LED_SYSTEM	1
+#define TL_MR3X20_GPIO_CS1_MMC		7
 #define TL_MR3X20_GPIO_LED_3G		8
 
 #define TL_MR3X20_GPIO_BTN_RESET	11
@@ -32,6 +37,26 @@
 #define TL_MR3X20_KEYS_POLL_INTERVAL	20	/* msecs */
 #define TL_MR3X20_KEYS_DEBOUNCE_INTERVAL (3 * TL_MR3X20_KEYS_POLL_INTERVAL)
 
+static struct mmc_spi_platform_data ath79_mmc_data = {
+       .get_ro = NULL,
+       .get_cd = NULL,
+       .detect_delay = 100, /* msecs */ 
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct ath79_spi_controller_data ath79_spi1_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_GPIO,
+	.cs_line = TL_MR3X20_GPIO_CS1_MMC,
+};
+
+static struct spi_board_info ath79_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mmc_spi",
+		.platform_data	= &ath79_mmc_data,
+		.controller_data = &ath79_spi1_cdata,
+	}
+};
+
 static const char *tl_mr3x20_part_probes[] = {
 	"tp-link",
 	NULL,
@@ -97,6 +122,9 @@
 	ath79_register_eth(0);
 
 	ap91_pci_init(ee, mac);
+
+	spi_register_board_info(ath79_spi_info,
+				ARRAY_SIZE(ath79_spi_info));
 }
 
 static void __init tl_mr3x20_usb_setup(void)
<p style="border:2px dashed red;">Второй способ.</p>

Вариант Internal CS1

Internal CS AR724X AR933X
CS1 QSS LED (GPIO0) UART In (GPIO9)
CS2 SYS LED (GPIO1) UART Out (GPIO10)

На устройствах AR724X: Для того, чтобы использовать внутренний CS1 - необходимо отключить QSS LED.

На устройствах AR933X: Для того, чтобы использовать внутренний CS1 - необходимо отключить UART.

Index: target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
===================================================================
--- target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c	(revision 34914)
+++ target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c	(working copy)
@@ -50,7 +50,7 @@
 void __init ath79_register_m25p80(struct flash_platform_data *pdata)
 {
 	ath79_spi_data.bus_num = 0;
-	ath79_spi_data.num_chipselect = 1;
+	ath79_spi_data.num_chipselect = 2;
 	ath79_spi0_cdata.is_flash = true;
 	ath79_spi_info[0].platform_data = pdata;
 	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
Index: target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
===================================================================
--- target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c	(revision 34914)
+++ target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c	(working copy)
@@ -9,13 +9,19 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
 
 #include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
 
+#include "common.h"
 #include "dev-eth.h"
 #include "dev-ap9x-pci.h"
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
+#include "dev-spi.h"
 #include "dev-m25p80.h"
 #include "dev-usb.h"
 #include "machtypes.h"
@@ -32,6 +38,26 @@
 #define TL_MR3X20_KEYS_POLL_INTERVAL	20	/* msecs */
 #define TL_MR3X20_KEYS_DEBOUNCE_INTERVAL (3 * TL_MR3X20_KEYS_POLL_INTERVAL)
 
+static struct mmc_spi_platform_data ath79_mmc_data = {
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct ath79_spi_controller_data ath79_spi1_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_INTERNAL,
+	.cs_line = 1,
+}; 
+
+static struct spi_board_info ath79_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mmc_spi",
+		.platform_data	= &ath79_mmc_data,
+		.controller_data = &ath79_spi1_cdata,
+	}
+};
+
 static const char *tl_mr3x20_part_probes[] = {
 	"tp-link",
 	NULL,
@@ -80,6 +106,9 @@
 	u8 *mac = (u8 *) KSEG1ADDR(0x1f01fc00);
 	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
 
+	/* Enabling internal CS1, disable GPIO 0 */
+	ath79_gpio_function_enable(AR724X_GPIO_FUNC_SPI_CS_EN1);
+
 	ath79_register_m25p80(&tl_mr3x20_flash_data);
 
 	ath79_register_gpio_keys_polled(-1, TL_MR3X20_KEYS_POLL_INTERVAL,
@@ -97,6 +126,9 @@
 	ath79_register_eth(0);
 
 	ap91_pci_init(ee, mac);
+
+	spi_register_board_info(ath79_spi_info,
+				ARRAY_SIZE(ath79_spi_info));
 }
 
 static void __init tl_mr3x20_usb_setup(void) 
Переключение GPIO0 (QSS LED) в CS1 на AR724X:
	/* Enabling internal CS1, disable GPIO 0 */
	ath79_gpio_function_enable(AR724X_GPIO_FUNC_SPI_CS_EN1);

(Уже используется в верхнем примере.)

Отключение UART и переключение GPIO 9(Rx) в CS1 на AR933X:
	/* Disable UART, enabling GPIO 9 and GPIO 10 */
	ath79_gpio_function_disable(AR933X_GPIO_FUNC_UART_EN);
	/* Enabling internal CS1, disable GPIO 9 */
	ath79_gpio_function_enable(AR933X_GPIO_FUNC_SPI_CS_EN1);


Реализация подключение/извлечение SD-карточки памяти

Способ подключения (схема)

Используется SD Socket/SD card holder/SD Memory Card Connector с дополнительными соответствующими контактами/кнопками CD (Card Detect) и WP (Write Protect)

Всего используем два свободных GPIO7→CS1, GPIO18→CD. Создаем дополнительную кнопку по примеру:

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
index 9323b31..2c51142 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
@@ -50,7 +50,7 @@ static struct ath79_spi_platform_data ath79_spi_data;
 void __init ath79_register_m25p80(struct flash_platform_data *pdata)
 {
 	ath79_spi_data.bus_num = 0;
-	ath79_spi_data.num_chipselect = 1;
+	ath79_spi_data.num_chipselect = 2;
 	ath79_spi0_cdata.is_flash = true;
 	ath79_spi_info[0].platform_data = pdata;
 	ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
index 5924ac5..892d66f 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-tl-mr3x20.c
@@ -9,6 +9,9 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
 
 #include <asm/mach-ath79/ath79.h>
 
@@ -17,21 +20,45 @@
 #include "dev-gpio-buttons.h"
 #include "dev-leds-gpio.h"
 #include "dev-m25p80.h"
+#include "dev-spi.h"
 #include "dev-usb.h"
 #include "machtypes.h"
 
 #define TL_MR3X20_GPIO_LED_QSS		0
 #define TL_MR3X20_GPIO_LED_SYSTEM	1
+#define TL_MR3X20_GPIO_CS1_MMC		7
 #define TL_MR3X20_GPIO_LED_3G		8
 
 #define TL_MR3X20_GPIO_BTN_RESET	11
 #define TL_MR3X20_GPIO_BTN_QSS		12
+#define TL_MR3X20_GPIO_BTN_MMC		18
 
 #define TL_MR3X20_GPIO_USB_POWER	6
 
 #define TL_MR3X20_KEYS_POLL_INTERVAL	20	/* msecs */
 #define TL_MR3X20_KEYS_DEBOUNCE_INTERVAL (3 * TL_MR3X20_KEYS_POLL_INTERVAL)
 
+static struct mmc_spi_platform_data ath79_mmc_pdata = {
+	.detect_delay	= 250,				/* card detection delay in msec */
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct ath79_spi_controller_data ath79_spi1_cdata = {
+	.cs_type = ATH79_SPI_CS_TYPE_GPIO,
+	.cs_line = TL_MR3X20_GPIO_CS1_MMC,
+}; 
+
+static struct spi_board_info ath79_spi_info[] __initdata = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 1,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mmc_spi",
+		.platform_data	= &ath79_mmc_pdata,
+		.controller_data = &ath79_spi1_cdata,
+	}
+};
+
 static const char *tl_mr3x20_part_probes[] = {
 	"tp-link",
 	NULL,
@@ -72,6 +99,13 @@ static struct gpio_keys_button tl_mr3x20_gpio_keys[] __initdata = {
 		.debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL,
 		.gpio		= TL_MR3X20_GPIO_BTN_QSS,
 		.active_low	= 1,
+	}, {
+		.desc		= "mmc",
+		.type		= EV_KEY,
+		.code		= KEY_MMC_BUTTON,
+		.debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= TL_MR3X20_GPIO_BTN_MMC,
+		.active_low	= 1,
 	}
 };
 
@@ -97,6 +131,9 @@ static void __init tl_ap99_setup(void)
 	ath79_register_eth(0);
 
 	ap91_pci_init(ee, mac);
+
+	spi_register_board_info(ath79_spi_info,
+				ARRAY_SIZE(ath79_spi_info));
 }
 
 static void __init tl_mr3x20_usb_setup(void)

После компиляции, создана дополнительная кнопка GPIO18→mmc. Далее, необходимо создать конфигурацию для кнопки:

uci add system button
uci set system.@button[-1].button=mmc
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='echo "spi0.1" > /sys/bus/spi/drivers/mmc_spi/bind'
uci add system button
uci set system.@button[-1].button=mmc
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='echo "spi0.1" > /sys/bus/spi/drivers/mmc_spi/unbind'
uci commit system

Примечание: До извлечения SD-карты памяти, рекомендуется использовать команды sync и unmount <раздел> - для правильного размонтирования разделов SD-карты памяти, т.к. при извлечении карты памяти (после записи на нее), некоторые данные могут остаться в буфере.

Подключение/извлечение SD карты памяти:
<pre class="code">
...
[ 1968.380000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff
[ 1968.550000] mmc0: SD Status: Invalid Allocation Unit size.
[ 1968.560000] mmc0: host does not support reading read-only switch. assuming write-enable.
[ 1968.570000] mmc0: new SD card on SPI
[ 1968.570000] mmcblk0: mmc0:0000 00000 1.90 GiB 
[ 1968.580000]  mmcblk0: p1
<b><font size=4>[ 1980.340000] mmc0: SPI card removed</font></b>
[ 2008.900000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff
[ 2009.070000] mmc0: SD Status: Invalid Allocation Unit size.
[ 2009.080000] mmc0: host does not support reading read-only switch. assuming write-enable.
[ 2009.090000] mmc0: new SD card on SPI
[ 2009.090000] mmcblk0: mmc0:0000 00000 1.90 GiB
[ 2009.100000]  mmcblk0: p1
...
</pre>


Модули

<p style="border:2px dashed red;">Первый вариант.</p>

Важно!Использование внешних модулей kmod-mmc и kmod-mmc-spi - пока не позволяет корректно смонтировать /overlay или / разделы через extroot_configuration, данная ошибка описана в https://dev.openwrt.org/ticket/7768. Это даже с учетом того, что использование этих модулей, позволяет полноценно использовать карточку памяти и монтировать ее в другие точки монтирования (кроме extroot_configuration).

Обновление: Проблема сохранилась по состоянию ревизии прошивки r37142.
Для extroot_configuration, используйте Второй вариант.

<p style="border:2px dashed red;">Второй вариант.</p>
На уровне ядра (kernel):
Index: target/linux/ar71xx/config-3.7
===================================================================
--- target/linux/ar71xx/config-3.7	(revision 35363)
+++ target/linux/ar71xx/config-3.7	(working copy)
@@ -240,6 +240,10 @@
 # CONFIG_SPI_RB4XX is not set
 # CONFIG_SPI_RB4XX_CPLD is not set
 # CONFIG_SPI_VSC7385 is not set
+CONFIG_EXT4_FS=y
+CONFIG_MMC=y
+CONFIG_MMC_SPI=y
+CONFIG_MMC_BLOCK=y
 CONFIG_SWCONFIG=y
 CONFIG_SWCONFIG_LEDS=y
 CONFIG_SYS_HAS_CPU_MIPS32_R2=y

Помимо MMC модулей, здесь дополнительно включена возможность использовать EXT4 файловую систему на уровне ядра.
Также следует учесть, что Linux-ядро регулярно обновляется, а этот конфигурационный файл в названии носит версию ядра.
В конечном счете, если ядро Trank'а обновилось, необходимо найти этот же конфиг. файл (но уже новый, например: config-3.8) и изменить его в соответствии с представленными здесь изменениями.

Интеграция необходимых модулей в ядро, позволяет использовать обнаруженную карточку памяти на ровне с флеш-памятью.
При этом, можно использовать карточку памяти в качестве расширенной файловой системы - extroot_configuration.

Тест скоростей spi0.1:

Скорость чтения/записи утилитой dd:

root@OpenWrt:~# /usr/bin/dd count=14 bs=1M if=/dev/mmcblk0p1 of=/dev/null
14+0 records in
14+0 records out
14680064 bytes (15 MB) copied, 20.9663 s, 700 kB/s
root@OpenWrt:~# /usr/bin/dd count=14 bs=1M if=/dev/zero of=/dev/mmcblk0p1
14+0 records in
14+0 records out
14680064 bytes (15 MB) copied, 25.2994 s, 580 kB/s
root@OpenWrt:~#

Результат утилиты hdparm:

root@OpenWrt:~# hdparm -Tt /dev/mmcblk0p1

/dev/mmcblk0p1:
 Timing cached reads:     2 MB in  2.96 seconds = 691.37 kB/sec
 Timing buffered disk reads:   2 MB in  3.05 seconds = 670.43 kB/sec
root@OpenWrt:~#
Нагрузка на CPU во время чтения/записи:
<pre class="code">
root@OpenWrt:~# top
Mem: 28224K used, 1120K free, 0K shrd, 5784K buff, 5592K cached
CPU:   0% usr  <font color="red">99% sys</font>   0% nic   0% idle   0% io   0% irq   0% sirq
Load average: 1.21 0.88 0.60 2/60 28540
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
 2230     2 root     RW       0   0%  55% [kworker/u:2]
 2180     2 root     SW       0   0%  36% [kworker/u:0]
  559     2 root     RW       0   0%   6% [mmcqd/0]
...
</pre>

Итог: Скорость чтения/записи по шине SPI, прямо зависит от частоты процессора, т.к. используется Bit-banging.

Тест одновременного использования spi0.0 и spi0.1:

Здесь стоит уточнить способ выполнения теста.
Посылается две параллельные команды чтение\запись с разделительным command оператором “&” (запуск команды в фоне).

Результат следующий: при одновременном чтении или записи spi0.0 и spi0.1 (процесс не имеет значения), предпочтение дается шине spi0.1, т.е. пока не закончится операция чтении/записи блока на шине spi0.1 - на шине spi0.0 не начнется запрашиваемая операция, выполнение происходит в приоритетном порядке и не является ошибкой.

Питание:
Режим Значение
Спящий режим (простой) ~1mA
Чтение данных ~18mA
Запись данных ~23mA
Лог загрузки и инициализации карточки:
<pre class="code">
...
<b><font size=4>[    0.730000] ath79-spi ath79-spi: master is unqueued, this is deprecated</font></b>
[    0.740000] m25p80 spi0.0: found en25f32, expected m25p80
[    0.750000] m25p80 spi0.0: en25f32 (4096 Kbytes)
[    0.750000] 5 tp-link partitions found on MTD device spi0.0
[    0.760000] Creating 5 MTD partitions on "spi0.0":
[    0.760000] 0x000000000000-0x000000020000 : "u-boot"
[    0.770000] 0x000000020000-0x00000013de00 : "kernel"
[    0.770000] mtd: partition "kernel" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only
[    0.790000] 0x00000013de00-0x0000003f0000 : "rootfs"
[    0.790000] mtd: partition "rootfs" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only
[    0.810000] mtd: partition "rootfs" set to be root filesystem
[    0.810000] mtd: partition "rootfs_data" created automatically, ofs=370000, len=80000
[    0.820000] 0x000000370000-0x0000003f0000 : "rootfs_data"
[    0.830000] 0x0000003f0000-0x000000400000 : "art"
[    0.840000] 0x000000020000-0x0000003f0000 : "firmware"
[    0.860000] libphy: ag71xx_mdio: probed
[    0.860000] eth0: Atheros AG71xx at 0xba000000, irq 5, mode:GMII
[    1.420000] eth0: Found an AR7240/AR9330 built-in switch
[    2.450000] eth1: Atheros AG71xx at 0xb9000000, irq 4, mode:MII
[    3.000000] ag71xx ag71xx.0 eth1: connected to PHY at ag71xx-mdio.1:04 [uid=004dd041, driver=Generic PHY]
<b><font size=4>[    3.050000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff</font></b>
[    3.060000] TCP: cubic registered
[    3.060000] NET: Registered protocol family 17
[    3.070000] 8021q: 802.1Q VLAN Support v1.8
[    3.080000] VFS: Mounted root (squashfs filesystem) readonly on device 31:2.
[    3.090000] Freeing unused kernel memory: 268k freed
<b><font size=4>[    3.310000] mmc0: host does not support reading read-only switch. assuming write-enable.
[    3.320000] mmc0: new SD card on SPI
[    3.480000] mmcblk0: mmc0:0000 00000 1.90 GiB
[    3.490000]  mmcblk0: p1</font></b>
...
</pre>
Вид ошибки в случае НЕ обнаружения карточки памяти на уровне ядра:
...
[    6.070000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff
...
[    8.710000] mmc0: error -145 whilst initialising SD card
...
[   10.710000] mmc0: error -145 whilst initialising MMC card
...
Обнаруженные разделы:
<pre class="code">
root@OpenWrt:~# ls /dev/mmc*
<font color="magenta">/dev/mmcblk0    /dev/mmcblk0p1</font>
root@OpenWrt:~#
</pre>
Debug информация:
root@OpenWrt:~# cat /sys/kernel/debug/mmc0/ios
clock:          25000000 Hz
vdd:            20 (3.2 ~ 3.3 V)
bus mode:       2 (push-pull)
chip select:    1 (active high)
power mode:     2 (on)
bus width:      0 (1 bits)
timing spec:    0 (legacy)
signal voltage: 1 (3.30 V)
root@OpenWrt:~#
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2018/03/03 20:22
  • by 176.59.23.135