Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
Next revisionBoth sides next revision
toh:tp-link:tl-mr3420:deep.mmc.hack [2014/10/18 16:28] – created dioptimizertoh:tp-link:tl-mr3420:deep.mmc.hack [2018/07/02 07:56] – minor addings/changes deoptim
Line 1: Line 1:
 +====== Deep MMC Mod ======
 +{{page>meta:infobox:cleanup&noheader&nofooter&noeditbtn}}
  
 +<WRAP center important 70%>
 +This mod does not work on the older **//LEDE//** and **//Chaos Calmer 15.05//** (since the revision [[https://dev.openwrt.org/changeset/47045|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:
 +<code>
 +git rm target/linux/generic/patches-3.18/092-01-spi-Check-to-see-if-the-device-is-processing-a-messa.patch
 +git rm target/linux/generic/patches-3.18/092-02-spi-Pump-transfers-inside-calling-context-for-spi_sy.patch
 +git rm target/linux/generic/patches-3.18/092-03-spi-Only-idle-the-message-pump-in-the-worker-kthread.patch
 +</code>
 +**Note:** Instead of path **patches-3.18**, new versions already use **pending-3.18** path.
 +You can also do remove those patches in same way for other branches...
 +----
 +Or you can use old **Barrier Breaker 14.07** branch or **Chaos Calmer 15.05** branch (up to revision r47042).\\
 +\\
 +For example, to reset **trunk** branch to old revision r47042, use this command:
 +<code>git reset --hard d8d8d594442086ce07b0401d472468b0c6a3c4ce</code>
 +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'')).//
 +</WRAP>
 +
 +===== How to connect SD-card to SPI bus =====
 +^  <color red>Scheme for First way</color>  ^
 +|  {{media:tplink:tl-mr3420:tl-mr3420-v1_common_CS_line.png?nolink|First connection scheme}} \\ //This connection scheme was successfully tested on TP-LINK MR3220 v1 device \\ (**NO** GPIO needed for this scheme)//  |
 +^  <color red>Two schems below for Second or Third way</color>  ^
 +|  {{media:tplink:tl-mr3420:tl-mr3420-v1_sd-card.png?nolink|Second connection scheme}} \\ //This connection scheme was successfully tested on TP-LINK MR3220 v1 device \\ (with GPIO power bus = 2.6V)//  |
 +|  {{media:tplink:tl-wr841:tl-wr841n-v7_sd-card.png?nolink|Third connection scheme}} \\ //This connection scheme was successfully tested on TP-LINK WR841N v7.1 device \\ (with GPIO power bus = FIXME)//  |
 +
 +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 [[docs:guide-user:hardware:mmc_over_gpio|mmc_over_gpio]], the only difference in the [[wp>Serial_Peripheral_Interface_Bus#Independent_slave_SPI_configuration|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: [[:docs:guide-developer:build-system:start]].\\
 +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: | <code>patch -u -p0 < patchfile.patch</code> |
 +| Git patch\\ file format: | <code>git apply patchfile.patch</code> OR <code>patch -u -p1 < patchfile.patch</code> |
 +
 +{{:meta:icons:tango:48px-emblem-important.svg.png?nolink&16|Important! }} 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.
 +|  {{media:doc:hardware:gpio_pullup_pulldown.png?nolink}}  |
 +\\
 +\\
 +==== First way, using common CS0 ====
 +{{:meta:icons:tango:48px-emblem-important.svg.png?nolink&16|Important! }} Using this method, you need to purchase a Single (or Schmitt-Trigger) Inverter Gate (which can operates on voltage 3.3V).
 +
 +== Main changes in the source code of kernel: ==
 +<hidden Old patch for Openwrt (before LEDE project)><code diff>
 +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..5961732 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,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);
 +
 +</code></hidden>
 +<hidden Patch for Openwrt/LEDE (4.9, ar71xx platform, mach-*.c files)><code diff>
 +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 e53d97d..269e469 100644
 +--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
 ++++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-m25p80.c
 +@@ -7,8 +7,10 @@
 +  */
 + 
 + #include <linux/init.h>
 ++#include <linux/mmc/host.h>
 + #include <linux/spi/spi.h>
 + #include <linux/spi/flash.h>
 ++#include <linux/spi/mmc_spi.h>
 + #include <linux/mtd/mtd.h>
 + #include <linux/mtd/partitions.h>
 + #include <linux/mtd/concat.h>
 +@@ -16,6 +18,11 @@
 + #include "dev-spi.h"
 + #include "dev-m25p80.h"
 + 
 ++static struct mmc_spi_platform_data ath79_mmc_data = {
 ++ .detect_delay = 100, /* msecs */
 ++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
 ++};
 ++
 + static struct spi_board_info ath79_spi_info[] = {
 +  {
 +  .bus_num = 0,
 +@@ -27,18 +34,25 @@ static struct spi_board_info ath79_spi_info[] = {
 +  .bus_num = 0,
 +  .chip_select = 1,
 +  .max_speed_hz   = 25000000,
 +- .modalias = "m25p80",
 ++ .modalias = "mmc_spi",
 ++ .platform_data = &ath79_mmc_data,
 +  }
 + };
 + 
 ++static int device_spi_cs_gpios[2] = {
 ++ -ENOENT,
 ++ 2, /* GPIO Number */
 ++};
 ++
 + 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_spi_data.cs_gpios = device_spi_cs_gpios;
 +  ath79_spi_info[0].platform_data = pdata;
 +- ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1);
 ++ ath79_register_spi(&ath79_spi_data, ath79_spi_info, 2);
 + }
 + 
 + static struct flash_platform_data *multi_pdata;
 +
 +</code></hidden>
 +<hidden Patch for Openwrt (4.14+, ath79 platform, dts files)><code diff>
 +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 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 = <3200 3400>;
 ++ };
 + };
 + 
 + &pcie {
 +
 +</code></hidden>
 +\\
 +\\
 +==== Second way, using GPIO as CS1 (Recommended) ====
 +Recommended to use any unused GPIO-pin as CS1 for MMC/SD memory card.
 +
 +== Main changes in the source code of kernel: ==
 +<hidden Old patch for Openwrt (before LEDE project)><code diff>
 +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 e5831d4..80760d5 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..4d4ac42 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,11 +20,13 @@
 + #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
 +@@ -32,6 +37,28 @@
 + #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,
 ++ .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 +109,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);
 +
 +</code></hidden>
 +<hidden Patch for Openwrt (4.14+, ath79 platform, dts files)><code diff>
 +diff --git a/target/linux/ath79/dts/ar7241_tp-link.dtsi b/target/linux/ath79/dts/ar7241_tp-link.dtsi
 +index 3846d811ac..58399eb4de 100644
 +--- a/target/linux/ath79/dts/ar7241_tp-link.dtsi
 ++++ b/target/linux/ath79/dts/ar7241_tp-link.dtsi
 +@@ -48,7 +48,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 +85,13 @@
 +  };
 +  };
 +  };
 ++
 ++ sdcard@0 {
 ++ compatible = "mmc-spi-slot";
 ++ reg = <1>;
 ++ spi-max-frequency = <25000000>;
 ++ voltage-ranges = <3200 3400>;
 ++ };
 + };
 + 
 + &pcie {
 +
 +</code></hidden>
 +\\
 +\\
 +==== Third way, using Internal CS1 ====
 +
 +^ Internal CS ^ AR71XX  ^ AR724X ^ AR933X ^ AR934X ^
 +| CS1         | usualy LED or BUTTON (GPIO0) || UART In (GPIO9)   | any unused GPIOs(11-22) \\ (Software configurable \\ [[wp>Multiplexer|multiplexer]]) |
 +| CS2         | usualy LED or BUTTON (GPIO1) || UART Out (GPIO10) | ::: |
 +
 +On platforms with AR71XX SoC: If you want to use the internal CS1 - you need to [[#switching#gpio0#to#cs1#on#ar71xx#soc|turn off GPIO0]].
 +
 +On platforms with AR724X SoC: If you want to use the internal CS1 - you need to [[#switching#gpio0#to#cs1#on#ar724x#soc|turn off GPIO0]].
 +
 +On platforms with AR933X SoC: If you want to use the internal CS1 - you need to [[#turn#off#uart#and#switching#gpio9(rx)#to#cs1#on#ar933x#soc|turn off UART]].
 +
 +On platforms with AR934X SoC: If you want to use the internal CS1 - you need to [[#configure#gpio11#to#cs1#on#ar934x#soc|configure GPIO to CS1]].
 +
 +== Main changes in the source code of kernel: ==
 +<hidden Old patch for Openwrt (before LEDE project)><code diff>
 +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 e5831d4..80760d5 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..1c6428f 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,19 +9,26 @@
 +  */
 + 
 + #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-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
 +@@ -32,6 +39,28 @@
 + #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_INTERNAL,
 ++ .cs_line = 1,
 ++ .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,
 +@@ -80,8 +109,14 @@ static void __init tl_ap99_setup(void)
 +  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);
 + 
 ++ 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);
 +
 +</code></hidden>
 +<hidden Patch for Openwrt (4.14+, ath79 platform, dts files)><code diff>
 +diff --git a/target/linux/ath79/dts/ar7241_tp-link.dtsi b/target/linux/ath79/dts/ar7241_tp-link.dtsi
 +index 3846d811ac..ea915872dc 100644
 +--- a/target/linux/ath79/dts/ar7241_tp-link.dtsi
 ++++ b/target/linux/ath79/dts/ar7241_tp-link.dtsi
 +@@ -48,7 +48,10 @@
 + 
 + &spi {
 +  status = "okay";
 +- num-cs = <1>;
 ++ pinctrl-names = "default";
 ++ pinctrl-0 = <&enable_cs1_bit>;
 ++ num-cs = <2>;
 ++ cs-gpios = <0>, <0>;
 + 
 +  flash@0 {
 +  #address-cells = <1>;
 +@@ -80,6 +83,30 @@
 +  };
 +  };
 +  };
 ++
 ++ sdcard@0 {
 ++ compatible = "mmc-spi-slot";
 ++ reg = <1>;
 ++ spi-max-frequency = <25000000>;
 ++ voltage-ranges = <3200 3400>;
 ++ };
 ++};
 ++
 ++&pinmux {
 ++ enable_cs1_bit: pinmux_enable_cs1_bit {
 ++ pinctrl-single,bits = <
 ++ /*
 ++ * Set AR724X_GPIO_FUNC_SPI_CS_EN1 BIT(13) to 1,
 ++ * i.e. enable hardware CS1 but it turn-off GPIO0;
 ++ * Formula: *addr = (*addr & ~sub-mask) |
 ++ * (value & sub-mask);
 ++ * Where: addr is 0x18000000 + 0x40000 + 0x28 is
 ++ * base address of AR724X GPIO functions;
 ++ * <addr_offset value sub-mask>
 ++ */
 ++ 0x0 0x2000 0x2000
 ++ >;
 ++ };
 + };
 + 
 + &pcie {
 +
 +</code></hidden>
 +\\
 +== Switching GPIO0 to CS1 on AR71XX SoC: ==
 +<hidden Instruction for old Openwrt (including LEDE project)>
 +<code c>
 + /* Enabling internal CS1, disable GPIO 0 */
 + ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN);
 +</code>
 +</hidden>
 +\\
 +== Switching GPIO0 to CS1 on AR724X SoC: ==
 +<hidden Instruction for old Openwrt (including LEDE project)>
 +<code c>
 + /* Enabling internal CS1, disable GPIO 0 */
 + ath79_gpio_function_enable(AR724X_GPIO_FUNC_SPI_CS_EN1);
 +</code>
 +</hidden>
 +<hidden Instruction for Openwrt (4.14+, ath79 platform, dts files)>
 +<code c>
 + ...
 + ...
 + /* Add this two lines to spi enum */
 + pinctrl-names = "default";
 + pinctrl-0 = <&enable_cs1_bit>;
 + ...
 + ...
 +&pinmux {
 + enable_cs1_bit: pinmux_enable_cs1_bit {
 + pinctrl-single,bits = <
 + /*
 + * Set AR724X_GPIO_FUNC_SPI_CS_EN1 BIT(13) to 1,
 + * i.e. enable hardware CS1 but it turn-off GPIO0;
 + * Formula: *addr = (*addr & ~sub-mask) |
 + * (value & sub-mask);
 + * Where: addr is 0x18000000 + 0x40000 + 0x28 is
 + * base address of AR724X GPIO functions;
 + * <addr_offset value sub-mask>
 + */
 + 0x0 0x2000 0x2000
 + >;
 + };
 + };
 +</code>
 +</hidden>
 +**Note:** Already used in the example above.
 +\\
 +== Turn off UART and switching GPIO9(Rx) to CS1 on AR933X SoC: ==
 +<hidden Instruction for old Openwrt (including LEDE project)>
 +<code c>
 + /* 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);
 +</code>
 +</hidden>
 +\\
 +== Configure GPIO11 to CS1 on AR934X SoC: ==
 +<hidden Instruction for old Openwrt (including LEDE project)>
 +<code c>
 + /* 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);
 +</code>
 +</hidden>
 +<hidden Instruction for Openwrt (4.14+, ath79 platform, dts files)>
 +<code c>
 + ...
 + ...
 + /* 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;
 + */
 + 0x8 0x7000000 0xff000000
 + >;
 + };
 + };
 +</code>
 +</hidden>
 +\\
 +\\
 +==== How to implement the Hotplug of SD-card ====
 +|  {{media:doc:hardware:memory_card_connectors_memory_card_billboard.gif?nolink}}  |
 +|  {{media:tplink:tl-mr3420:moz-screenshot-4.png?nolink|Connection scheme}} \\ //We use [[https://www.google.com.ua/search?q=SD+Socket+OR+SD+card+holder+OR+SD+Memory+Card+connector&tbm=isch|SD Socket/SD card holder/SD Memory Card Connector]] with special integrated buttons - \\ CD (Card Detect) and WP (Write Protect)//  |
 +
 +Total we use two unused GPIOs: **GPIO7->CS1**, **GPIO18->CD**. \\
 +Create a new additional button on this example:
 +<hidden Old patch for Openwrt (before LEDE project)><code diff>
 +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 e5831d4..80760d5 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..9990d05 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,46 @@
 + #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,
 ++ .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,
 +@@ -72,6 +100,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 = BTN_0,
 ++ .debounce_interval = TL_MR3X20_KEYS_DEBOUNCE_INTERVAL,
 ++ .gpio = TL_MR3X20_GPIO_BTN_MMC,
 ++ .active_low = 1,
 +  }
 + };
 + 
 +@@ -82,6 +117,11 @@ 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));
 ++
 ++ gpio_direction_input(TL_MR3X20_GPIO_BTN_MMC);
 ++
 +  ath79_register_gpio_keys_polled(-1, TL_MR3X20_KEYS_POLL_INTERVAL,
 +  ARRAY_SIZE(tl_mr3x20_gpio_keys),
 +  tl_mr3x20_gpio_keys);
 +
 +</code></hidden>
 +<hidden Patch for Openwrt (4.14+, ath79 platform, dts files)><code diff>
 +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 = <3200 3400>;
 ++ };
 + };
 + 
 + &pcie {
 +
 +</code></hidden>
 +// 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 FIXME   //
 +
 +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 [[docs:guide-user:hardware:hardware.button#using.atheros.00-button.uci|create a configuration(/etc/hotplug.d/button/00-button)]] for the button **''mmc''**:
 +<code bash>
 +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
 +</code>
 +
 +**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: ==
 +<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
 +[ 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
 +...
 +</code>
 +
 +==== Modules installation ====
 +=== First way, build it in kernel (Recommended) ===
 +| {{:meta:icons:tango:dialog-information.png?nolink}} | 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 [[docs:guide-user:additional-software: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:
 +<code>
 +(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 >
 +</code>
 +//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 ===
 +| {{:meta:icons:tango:48px-emblem-important.svg.png?nolink |Important!}} | If we are using external modules ''kmod-mmc'' and ''kmod-mmc-spi'' - this does not allow to correctly mount ''<color magenta>/overlay</color>'' \\ or ''<color blue>/</color>'' (root) partitions through [[docs:guide-user:additional-software:extroot_configuration]]. This problem is described in [[https://dev.openwrt.org/ticket/7768|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 [[docs:guide-user:additional-software:extroot_configuration]]). |
 +
 +** Update: ** The problem remained in **r37142** firmware revision.\\ 
 +For [[docs:guide-user:additional-software: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**:
 +<code>
 +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:~#
 +</code>
 +
 +Result **hdparm**:
 +<code>
 +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:~#
 +</code>
 +
 +== CPU load during read/write process: ==
 +<code>
 +root@OpenWrt:~# top
 +Mem: 28224K used, 1120K free, 0K shrd, 5784K buff, 5592K cached
 +CPU:   0% usr  99% sys   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%  55% [kworker/u:2]
 + 2180     2 root     SW         0%  36% [kworker/u:0]
 +  559     2 root     RW         0%   6% [mmcqd/0]
 +...
 +</code>
 +
 +**Conclusion:** operations read/write speed via [ath79-spi<->spi-bitbang<->mmc_spi], directly depends on the frequency of the processor, because is used [[wp>Bit-banging|Bit-banging]] method to read/write the word.
 +
 +== (AR933x) Speed testing spi0.1: ==
 +FIXME TODO
 +
 +== (AR934x) Speed testing spi0.1: ==
 +FIXME 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: ==
 +<code>
 +...
 +[    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
 +...
 +</code>
 +
 +== Error type in the case that system has NOT detected the SD-card: ==
 +<code>
 +...
 +[    6.070000] mmc_spi spi0.1: SD/MMC host mmc0, no DMA, no WP, no poweroff
 +...
 +[    8.710000] mmc0: error -22 whilst initialising SD card
 +...
 +[   10.710000] mmc0: error -22 whilst initialising MMC card
 +...
 +</code>
 +
 +== After detecting the SD-card we can find partitions: ==
 +<code>
 +root@OpenWrt:~# ls /dev/mmc*
 +/dev/mmcblk0    /dev/mmcblk0p1
 +root@OpenWrt:~#
 +</code>
 +
 +== Debug info: ==
 +<code>
 +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:~#
 +</code>
 +
 +===== Forum discussion =====
 +
 +[[https://forum.openwrt.org/viewtopic.php?id=54077]]
 +
 +Porting this mod on LEDE Project:\\
 +[[https://forum.lede-project.org/t/ath79-sd-card-on-spi-bus-deep-mmc-mod/7527]]
  • Last modified: 2021/10/15 09:06
  • by bobafetthotmail