Cleanup Required!
This page or section needs cleanup. You can edit this page to fix wiki markup, redundant content or outdated information.
This mod does not work on the older LEDE and Chaos Calmer 15.05 (since the revision r47045).
But it works completely on the newest kernel 4.14+(ath79) and does not need to delete anything.
If you use older version of branch then you need to discard/remove this three changes to work property with this mod:
You can also do this in same way for other branches...
(Where the long parameter is a commit of necessary revision (git log −−grep 47042)).
How to connect SD-card to SPI bus
Scheme for First way
This connection scheme was successfully tested on TP-LINK MR3220 v1 device
(NO GPIO needed for this scheme, but this circuit using Inverter Gate IC: 74LVC1G04 or 74LVC1G14)
Two schems below for Second or Third way
This connection scheme was successfully tested on TP-LINK MR3220 v1 device
(with GPIO power bus = 2.6V)
This connection scheme was successfully tested on TP-LINK WR841N v7.1 device
(with GPIO power bus = )
There are three ways to modify the device and the source code for this device by using the same(common) CS0 and share it with SD-card /or/ any unused GPIO as CS1 /or/ Internal CS1 (it used by SPI controller).
And two ways for installing the required modules for detect and use the SD memory card is connected to the SPI bus of device.
At software level, this modification is almost no different from mmc_over_gpio, the only difference in the Independent slave SPI configuration of controller - that means we are using CS0, CS1...CSn line for each slave SPI-device.
On any platform with Atheros SoC we can see serial NOR-flash chip which is connected to SPI controller and it is used as primary boot device.
How to build your own firmware is covered here: toolchain.
If you already have experience with compile own firmware, and you want to easy apply these changes as patch(es), you can just use this Linux console command:
Svn patch
file format:
patch -u -p0 < patchfile.patch
Git patch
file format:
git apply patchfile.patch
OR
patch -u -p1 < patchfile.patch
Where patchfile.patch must be placed in the trunk or other branches directory.
Connection MMC/SD memory card to the spi0.1 bus
Note: Keep in mind, very often the unused GPIOs a pulled-down to the ground or pulled-up to the power bus via resistor - this may affect on detection of SD memory cards.
First way, using common CS0
Using this method, you need to purchase a Single (or Schmitt-Trigger) Inverter Gate (which can operates on voltage 3.3V, 74LVC1G04 or 74LVC1G14 was tested and it works).
Main changes in the source code of kernel:
Old patch for Openwrt (before LEDE project)
Old patch for Openwrt (before LEDE project)
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..2c51142100644--- 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..5961732100644--- 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,6 +20,7 @@
#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"
@@ -32,6 +36,37 @@
#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,+};+++/*+ * Need to change cs_line to 2 (for AR72xx, AR933x)+ * or 5 (for AR934x, QCA95xx), this GPIO num. is equivalent of+ * internal CS0 line.+ * In its core, this is a dummy, because internal CS0 line+ * is locked by HW and SPI driver, and we can not use it at all.+ * We use this to simply switch SPI bus to another device.+ */+static struct ath79_spi_controller_data ath79_spi1_cdata = {+ .cs_type = ATH79_SPI_CS_TYPE_GPIO,+ .cs_line = 2,+ .is_flash = false,+};++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,
@@ -82,6 +117,9 @@ static void __init tl_ap99_setup(void)
ath79_register_m25p80(&tl_mr3x20_flash_data);
+ spi_register_board_info(ath79_spi_info,+ ARRAY_SIZE(ath79_spi_info));+
ath79_register_gpio_keys_polled(-1, TL_MR3X20_KEYS_POLL_INTERVAL,
ARRAY_SIZE(tl_mr3x20_gpio_keys),
tl_mr3x20_gpio_keys);
Patch for Openwrt/LEDE (4.9, ar71xx platform, mach-*.c files)
Patch for Openwrt/LEDE (4.9, ar71xx platform, mach-*.c files)
Patch for Openwrt (4.14+, ath79 platform, dts files)
Patch for Openwrt (4.14+, ath79 platform, dts files)
diff --git a/target/linux/ath79/dts/ar7241_tp-link.dtsi b/target/linux/ath79/dts/ar7241_tp-link.dtsi
index 3846d811ac..d845e06951 100644--- a/target/linux/ath79/dts/ar7241_tp-link.dtsi+++ b/target/linux/ath79/dts/ar7241_tp-link.dtsi@@ -48,7 +48,19 @@
&spi {
status = "okay";
- num-cs = <1>;+ num-cs = <2>;+ /*+ * First value is default pin for flash, second value+ * (via comma) the GPIO number for sdcard. But we used+ * gpio 2 and it's equivalent of internal CS0 line. And+ * we use it because we use common bus SPI0.0 for two+ * devices (default Low polarity chip-select, custom+ * High polarity chip-select).+ * In its core, this is a dummy, because internal CS0 line+ * is locked by HW and SPI driver, and we can not use it at all.+ * We use this to simply switch SPI bus to another device.+ */+ cs-gpios = <0>, <&gpio 2 GPIO_ACTIVE_HIGH>;
flash@0 {
#address-cells = <1>;
@@ -80,6 +92,13 @@};
};
};
++ sdcard@0 {+ compatible = "mmc-spi-slot";+ reg = <1>;+ spi-max-frequency = <25000000>;+ voltage-ranges = <32003400>;+ };};
&pcie {
Second way, using GPIO as CS1 (Recommended)
Recommended to use any unused GPIO-pin as CS1 for MMC/SD memory card.
Instruction for old Openwrt (including LEDE project)
Instruction for old Openwrt (including LEDE project)
/* We chose GPIO11 - for this example. You can use any unused GPIOs(11-22) */#define DEVICE_GPIO_CS1_MMC 11/* custom register for CS2 (AR934X SoC), TODO in future ar71xx_regs.h */#define AR934X_GPIO_OUT_SPI_CS2 8
...
/* Configure GPIO to MUX Select (CS1) */
ath79_gpio_output_select(DEVICE_GPIO_CS1_MMC, AR934X_GPIO_OUT_SPI_CS1);
Instruction for Openwrt (4.14+, ath79 platform, dts files)
Instruction for Openwrt (4.14+, ath79 platform, dts files)
...
...
/* Add this two lines to spi enum */
pinctrl-names ="default";
pinctrl-0=<&gpio11_to_cs1_bit>;
...
...
&pinmux {
gpio11_to_cs1_bit: pinmux_gpio11_to_cs1_bit {
pinctrl-single,bits =</*
* Set AR934X_GPIO_OUT_SPI_CS1 7 value to GPIO11,
* i.e. enable hardware CS1 but it turn-off GPIO11;
* Formula: *addr = (*addr & ~sub-mask) |
* (value & sub-mask);
* Where: addr is 0x18000000 + 0x40000 + 0x2C is
* base address of AR934X GPIO Output functions;
* <addr_offset value sub-mask>;
*//*
* 0x2c+0x8 addr_offset for GPIO11(Bit 31:24);
* 0x2c+0xc addr_offset for GPIO12-GPIO15;
* 0x2c+0x10 addr_offset for GPIO16-GPIO19;
* 0x7 value (with Bitwise Left Shift) for mux CS1
* use 0x8 value for mux CS2;
*/0x80x70000000xff000000>;};};
Patch for Openwrt (4.14+, ath79 platform, dts files)
Patch for Openwrt (4.14+, ath79 platform, dts files)
diff --git a/target/linux/ath79/dts/ar7241_tp-link.dtsi b/target/linux/ath79/dts/ar7241_tp-link.dtsi
index 3846d811ac..d99bafcb2b 100644--- a/target/linux/ath79/dts/ar7241_tp-link.dtsi+++ b/target/linux/ath79/dts/ar7241_tp-link.dtsi@@ -22,13 +22,18 @@
gpios = <&gpio 11 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
-
qss {
label = "qss";
linux,code = <KEY_WPS_BUTTON>;
gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
+ mmc {+ label = "mmc";+ linux,code = <BTN_0>;+ gpios = <&gpio 18 GPIO_ACTIVE_LOW>;+ debounce-interval = <60>;+ };};
gpio_leds: gpio-leds {@@ -48,7 +53,12 @@
&spi {
status = "okay";
- num-cs = <1>;+ num-cs = <2>;+ /*+ * Where first parameter <0> is default CS0 pin for flash+ * and second parameter is GPIO Number for sdcard.+ */+ cs-gpios = <0>, <&gpio 7 GPIO_ACTIVE_HIGH>;
flash@0 {
#address-cells = <1>;
@@ -80,6 +90,30 @@};
};
};
++ sdcard@0 {+ compatible = "mmc-spi-slot";+ reg = <1>;+ /*+ * If you need to use GPIO18 as Card Detect and+ * IRQ trigger (as standard implementation) - just+ * uncomment line below (but don't forget delete+ * the equivalent gpio-key). We don't use this+ * property because it doesn't detect removing of+ * SD Card.+ */+ //gpios = <&gpio 18 GPIO_ACTIVE_LOW>;+ /*+ * By default, Card Detect use "active low" state.+ * Using the "cd-inverted" property means, that the+ * CD line is active high, i.e. it is high, when a+ * card is inserted.+ * (uncomment line below to enable this option)+ */+ //cd-inverted;+ spi-max-frequency = <25000000>;+ voltage-ranges = <32003400>;+ };};
&pcie {
We could use GPIO to IRQ event as card detection (implemented in mmc_spi module) or GPIO to IRQ event as new hotplug SPI-device (implemented in standart SPI bus driver) - but in all this cases, it was found that it not support hotplug detection with removing the SD-card or SPI-device via the IRQ trigger. IRQ trigger needed if your gpio controller could be in sleep/idle state (and those CD gpio switch could be ignored by the system) - in that cause use standard implementation(not buttons).
Or
The solution was found without the use of IRQ trigger:
After build and compiling the firmware, we just added additional button with the name mmc.
Next, you need to create a configuration(/etc/hotplug.d/button/00-button) for the button mmc:
uci add system button
uci set system.@button[-1].button=BTN_0
uci set system.@button[-1].action=pressed
uci set system.@button[-1].handler='echo "spi0.1" > /sys/bus/spi/drivers/mmc_spi/unbind'
uci add system button
uci set system.@button[-1].button=BTN_0
uci set system.@button[-1].action=released
uci set system.@button[-1].handler='echo "spi0.1" > /sys/bus/spi/drivers/mmc_spi/bind'
uci commit system
Note: Action pressed/released dependent on default state of GPIO (Input), i.e., sometimes you need to swap actions. Before removing SD-card from the slot, it is recommended to use the console commands sync and unmount<partition> - for correctly unmounting of a partition. Because if we remove SD-card(after recording on it) without using unmount commands - we risk losing some not recorded data.
Log of hotplug process:
...
[ 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
[ 1980.340000] mmc0: SPI card removed
[ 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
...
Modules installation
First way, build it in kernel (Recommended)
By using this variant - NO need to install external modules kmod-mmc, kmod-mmc-spi and kmod-fs-ext4.
You can use the SD memory card as extroot_configuration (block-mount) with no problem.
Integrating modules in kernel:
When we build own firmware we use standard menu make menuconfig, after that we need to use special menu make kernel_menuconfig.
In this kernel menu, select the asterisks following items:
(Use Arrows UP and DOWN to find and select)
Device Drivers ---> (Press ENTER)
<*> MMC/SD/SDIO card support ---- (Find this item and press SPACE twice from the <M> to turn the <*> and then press ENTER)
├<*> MMC block device driver (Find this item and press SPACE twice from the <M> to turn the <*>)
└<*> MMC/SD/SDIO over SPI (Find this item and press SPACE twice from the <M> to turn the <*>)
(Press ESC twice to go to the previous menu)
File systems ---> (Press ENTER)
<*> The Extended 4 (ext4) filesystem (Find this item and press SPACE twice from the <M> to turn the <*>)
(Press ESC twice)
(Use TAB or Arrows LEFT and RIGHT to select < Exit >)
< Exit >
< Yes >
Besides MMC modules, we include the EXT4 module on the kernel level.
The integration of the required modules into the kernel, allows us to use detected SD-card on one level with NOR flash memory. For example: we can mount root-fs at kernel level by setting: CONFIG_CMDLINE=“rootfstype=squashfs,jffs2,ext3 noinitrd root=/dev/mmcblk0p1 rootwait”
Second way, using external modules
If we are using external modules kmod-mmc and kmod-mmc-spi - this does not allow to correctly mount /overlay
or / (root) partitions through extroot_configuration. This problem is described in this old ticket.
It's even considering that the use of these external modules, allow us to fully use the SD-card and mount it in the other mount points (except extroot_configuration).
Update: The problem remained in r37142 firmware revision.
For extroot_configuration, use First way.
Testing
(AR71xx) Speed testing spi0.1:
~ the same as AR724x tests
(AR724x) Speed testing spi0.1:
Read/write speed by using utility coreutils-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:~#
Result 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:~#
Conclusion: operations read/write speed via [ath79-spi↔spi-bitbang↔mmc_spi], directly depends on the frequency of the processor, because is used Bit-banging method to read/write the word.
(AR933x) Speed testing spi0.1:
TODO
(AR934x) Speed testing spi0.1:
TODO
Access to spi0.0 and spi0.1 at the one time:
Here it is necessary to specify method of performing the test.
We send two parallel commands(operations) read\write command with the division operator & (execute the console command in the background).
Result next: while reading or writing spi0.0 and spi0.1 at the same time (the process does not matter), priority given to spi0.1 bus, i.e. until the end of read/write operation on the spi0.1 bus - on the spi0.0 bus will not begin the requested operation, all operations occurs as a priority and not a bug.
Power
Operation
Probe
Idle
~1mA
Read data
~18mA
Write data
~23mA
Logs
Log with loading and initializing SD-card:
...
[ 0.730000] ath79-spi ath79-spi: master is unqueued, this is deprecated
[ 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]
[ 3.050000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff
[ 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
[ 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
...
Error type in the case that system has NOT detected the SD-card:
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