mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
emmc: add emmc driver support on m8b
PD#141217: initial add emmc dirver support on m8b 1) add emmc driver support HS200 mode 85M 2) add sd driver support HS mode 38M test on m8b_m200. Change-Id: I1575c45af2e1246019d54a8092ee29e1da0a1a70 Signed-off-by: Nan Li <nan.li@amlogic.com>
This commit is contained in:
11
MAINTAINERS
11
MAINTAINERS
@@ -13781,6 +13781,17 @@ F: drivers/amlogic/media/video_processor/Kconfig
|
||||
F: drivers/amlogic/media/video_processor/Makefile
|
||||
F: drivers/amlogic/media/video_processor/ionvideo/*
|
||||
|
||||
AMLOGIC EMMC S805 DRIVER SUPPORT
|
||||
M: Nan Li <nan.li@amlogic.com>
|
||||
F: arch/arm/boot/dts/amlogic/meson8b.dtsi
|
||||
F: arch/arm/boot/dts/amlogic/meson8b_m200.dts
|
||||
F: drivers/amlogic/emmc/aml_sdhc_m8.c
|
||||
F: drivers/amlogic/emmc/aml_sdio.c
|
||||
F: drivers/amlogic/emmc/Kconfig
|
||||
F: drivers/amlogic/emmc/Makefile
|
||||
F: include/linux/amlogic/sd.h
|
||||
F: include/linux/amlogic/cpu_version.h
|
||||
|
||||
AMLOGIC PINCTRL SUPPORT FOR M8B
|
||||
M: Xingyu Chen <xingyu.chen@amlogic.com>
|
||||
F: drivers/amlogic/pinctrl/pinctrl-meson8b.c
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <dt-bindings/clock/meson8b-clkc.h>
|
||||
#include <dt-bindings/gpio/meson8b-gpio.h>
|
||||
#include <dt-bindings/reset/amlogic,meson8b-reset.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include "skeleton.dtsi"
|
||||
|
||||
/ {
|
||||
@@ -209,6 +210,158 @@
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
emmc_clk_cmd_pins:emmc_clk_cmd_pins {
|
||||
mux {
|
||||
groups = "sd_cmd_c",
|
||||
"sd_clk_c";
|
||||
function = "sd_c";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
emmc_all_pins:emmc_all_pins {
|
||||
mux {
|
||||
groups = "sd_d0_c",
|
||||
"sd_d1_c",
|
||||
"sd_d2_c",
|
||||
"sd_d3_c",
|
||||
"sd_cmd_c",
|
||||
"sd_clk_c";
|
||||
function = "sd_c";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sd_clk_cmd_pins:sd_clk_cmd_pins{
|
||||
mux {
|
||||
groups = "sd_cmd_b",
|
||||
"sd_clk_b";
|
||||
function = "sd_b";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sd_1bit_pins:sd_1bit_pins{
|
||||
mux {
|
||||
groups = "sd_d1_b",
|
||||
"sd_d2_b",
|
||||
"sd_d3_b",
|
||||
"sd_cmd_b",
|
||||
"sd_clk_b";
|
||||
function = "sd_b";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sd_all_pins:sd_all_pins{
|
||||
mux {
|
||||
groups = "sd_d0_b",
|
||||
"sd_d1_b",
|
||||
"sd_d2_b",
|
||||
"sd_d3_b",
|
||||
"sd_cmd_b",
|
||||
"sd_clk_b";
|
||||
function = "sd_b";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdio_clk_cmd_pins:sdio_clk_cmd_pins {
|
||||
mux {
|
||||
groups = "sd_clk_a",
|
||||
"sd_cmd_a";
|
||||
function = "sd_a";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdio_all_pins:sdio_all_pins {
|
||||
mux {
|
||||
groups = "sd_d0_a",
|
||||
"sd_d1_a",
|
||||
"sd_d2_a",
|
||||
"sd_d3_a",
|
||||
"sd_clk_a",
|
||||
"sd_cmd_a";
|
||||
function = "sd_a";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_emmc_clk_cmd_pins:sdhc_emmc_clk_cmd_pins {
|
||||
mux {
|
||||
groups = "sdxc_clk_c",
|
||||
"sdxc_cmd_c";
|
||||
function = "sdxc_c";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_emmc_all_pins:sdhc_emmc_all_pins {
|
||||
mux {
|
||||
groups = "sdxc_d0_c",
|
||||
"sdxc_d13_c",
|
||||
"sdxc_d47_c",
|
||||
"sdxc_clk_c",
|
||||
"sdxc_cmd_c";
|
||||
function = "sdxc_c";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_sd_clk_cmd_pins:sdhc_sd_clk_cmd_pins {
|
||||
mux {
|
||||
groups = "sdxc_clk_b",
|
||||
"sdxc_cmd_b";
|
||||
function = "sdxc_b";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_sd_all_pins:sdhc_sd_all_pins {
|
||||
mux {
|
||||
groups = "sdxc_d0_b",
|
||||
"sdxc_d13_b",
|
||||
"sdxc_clk_b",
|
||||
"sdxc_cmd_b";
|
||||
function = "sdxc_b";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_sdio_clk_cmd_pins:sdhc_sdio_clk_cmd_pins {
|
||||
mux {
|
||||
groups = "sdxc_clk_a",
|
||||
"sdxc_cmd_a";
|
||||
function = "sdxc_a";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
sdhc_sdio_all_pins:sdhc_sdio_all_pins {
|
||||
mux {
|
||||
groups = "sdxc_d0_1_a",
|
||||
"sdxc_d13_1_a",
|
||||
"sdxc_clk_a",
|
||||
"sdxc_cmd_a";
|
||||
function = "sdxc_a";
|
||||
input-enable;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pinctrl_aobus: pinctrl@c8100084 {
|
||||
|
||||
@@ -30,6 +30,159 @@
|
||||
reg = <0x00000000 0x40000000>;
|
||||
linux,usable-memory = <0x00200000 0x3fe00000>;
|
||||
};
|
||||
|
||||
sdio {
|
||||
compatible = "amlogic, aml_sdio";
|
||||
dev_name = "aml_sdio.0";
|
||||
status = "okay";
|
||||
interrupts = <0 28 1>;
|
||||
reg = <0xc1108c20 0x20>;
|
||||
pinctrl-names = "sd_clk_cmd_pins",
|
||||
"sd_all_pins",
|
||||
"emmc_clk_cmd_pins",
|
||||
"emmc_all_pins",
|
||||
"sdio_clk_cmd_pins",
|
||||
"sdio_all_pins",
|
||||
"sd_1bit_pins";
|
||||
pinctrl-0 = <&sd_clk_cmd_pins>;
|
||||
pinctrl-1 = <&sd_all_pins>;
|
||||
pinctrl-2 = <&emmc_clk_cmd_pins>;
|
||||
pinctrl-3 = <&emmc_all_pins>;
|
||||
pinctrl-4 = <&sdio_clk_cmd_pins>;
|
||||
pinctrl-5 = <&sdio_all_pins>;
|
||||
pinctrl-6 = <&sd_1bit_pins>;
|
||||
clocks = <&clkc CLKID_SDIO>;
|
||||
clock-names = "core";
|
||||
|
||||
sd {
|
||||
status = "okay";
|
||||
port = <1>;
|
||||
/* 0:sdio_a,
|
||||
* 1:sdio_b,
|
||||
* 2:sdio_c,
|
||||
* 3:sdhc_a,
|
||||
* 4:sdhc_b,
|
||||
* 5:sdhc_c
|
||||
*/
|
||||
pinname = "sd";
|
||||
ocr_avail = <0x200000>; /**VDD voltage 3.3 ~ 3.4 */
|
||||
caps = "MMC_CAP_4_BIT_DATA",
|
||||
"MMC_CAP_MMC_HIGHSPEED",
|
||||
"MMC_CAP_SD_HIGHSPEED";
|
||||
f_min = <300000>;
|
||||
f_max = <50000000>;
|
||||
f_max_w = <50000000>;
|
||||
max_req_size = <0x20000>; /*128KB*/
|
||||
gpio_dat3 = <&gpio CARD_4 GPIO_ACTIVE_HIGH>;
|
||||
jtag_pin = <&gpio CARD_0 GPIO_ACTIVE_HIGH>;
|
||||
gpio_cd = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
|
||||
gpio_ro = <&gpio GPIODV_25 GPIO_ACTIVE_HIGH>;
|
||||
card_type = <5>;
|
||||
/* 0:unknown,
|
||||
* 1:mmc card(include eMMC),
|
||||
* 2:sd card(include tSD),
|
||||
* 3:sdio device(ie:sdio-wifi),
|
||||
* 4:SD combo (IO+mem) card,
|
||||
* 5:NON sdio device(means sd/mmc card),
|
||||
* other:reserved
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
sdhc {
|
||||
compatible = "amlogic, aml_sdhc";
|
||||
dev_name = "aml_sdhc.0";
|
||||
status = "okay";
|
||||
interrupts = <0 78 1>;
|
||||
reg = <0xc1108e00 0x3c>;
|
||||
pinctrl-names = "sdhc_sd_clk_cmd_pins",
|
||||
"sdhc_sd_all_pins",
|
||||
"sdhc_emmc_clk_cmd_pins",
|
||||
"sdhc_emmc_all_pins",
|
||||
"sdhc_sdio_clk_cmd_pins",
|
||||
"sdhc_sdio_all_pins";
|
||||
pinctrl-0 = <&sdhc_sd_clk_cmd_pins>;
|
||||
pinctrl-1 = <&sdhc_sd_all_pins>;
|
||||
pinctrl-2 = <&sdhc_emmc_clk_cmd_pins>;
|
||||
pinctrl-3 = <&sdhc_emmc_all_pins>;
|
||||
pinctrl-4 = <&sdhc_sdio_clk_cmd_pins>;
|
||||
pinctrl-5 = <&sdhc_sdio_all_pins>;
|
||||
clocks = <&clkc CLKID_SDHC>,
|
||||
<&clkc CLKID_FCLK_DIV3>;
|
||||
clock-names = "core", "div3";
|
||||
|
||||
emmc {
|
||||
status = "okay";
|
||||
port = <5>;
|
||||
/* 0:sdio_a,
|
||||
* 1:sdio_b,
|
||||
* 2:sdio_c,
|
||||
* 3:sdhc_a,
|
||||
* 4:sdhc_b,
|
||||
* 5:sdhc_c
|
||||
*/
|
||||
pinname = "emmc";
|
||||
ocr_avail = <0x00200080>;
|
||||
/* 3.3:0x200000, 1.8+3.3:0x00200080 */
|
||||
caps = "MMC_CAP_8_BIT_DATA",
|
||||
"MMC_CAP_MMC_HIGHSPEED",
|
||||
"MMC_CAP_SD_HIGHSPEED",
|
||||
"MMC_CAP_NONREMOVABLE",
|
||||
"MMC_CAP_ERASE",
|
||||
"MMC_CAP_HW_RESET";
|
||||
caps2 = "MMC_CAP2_HS200_1_8V_SDR";
|
||||
f_min = <300000>;
|
||||
f_max = <100000000>;
|
||||
max_req_size = <0x20000>; /* 128KB */
|
||||
gpio_dat3 = <&gpio BOOT_3 GPIO_ACTIVE_HIGH>;
|
||||
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
|
||||
card_type = <1>;
|
||||
/* 0:unknown,
|
||||
* 1:mmc card(include eMMC),
|
||||
* 2:sd card(include tSD),
|
||||
* 3:sdio device(ie:sdio-wifi),
|
||||
* 4:SD combo (IO+mem) card,
|
||||
* 5:NON sdio device(means sd/mmc card),
|
||||
* other:reserved
|
||||
*/
|
||||
};
|
||||
|
||||
sdio {
|
||||
status = "okay";
|
||||
port = <3>;
|
||||
/* 0:sdio_a,
|
||||
* 1:sdio_b,
|
||||
* 2:sdio_c,
|
||||
* 3:sdhc_a,
|
||||
* 4:sdhc_b,
|
||||
* 5:sdhc_c
|
||||
*/
|
||||
pinname = "sdio";
|
||||
ocr_avail = <0x00200080>;
|
||||
/* 3.3:0x200000, 1.8+3.3:0x00200080 */
|
||||
caps = "MMC_CAP_4_BIT_DATA",
|
||||
"MMC_CAP_MMC_HIGHSPEED",
|
||||
"MMC_CAP_SD_HIGHSPEED",
|
||||
"MMC_CAP_NONREMOVABLE",
|
||||
"MMC_CAP_UHS_SDR12",
|
||||
"MMC_CAP_UHS_SDR25",
|
||||
"MMC_CAP_UHS_SDR50",
|
||||
"MMC_CAP_UHS_SDR104",
|
||||
"MMC_PM_KEEP_POWER";
|
||||
f_min = <300000>;
|
||||
f_max = <100000000>;
|
||||
max_req_size = <0x20000>; /* 128KB */
|
||||
card_type = <3>;
|
||||
/* 0:unknown,
|
||||
* 1:mmc card(include eMMC),
|
||||
* 2:sd card(include tSD),
|
||||
* 3:sdio device(ie:sdio-wifi),
|
||||
* 4:SD combo (IO+mem) card,
|
||||
* 5:NON sdio device(means sd/mmc card),
|
||||
* other:reserved
|
||||
*/
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart_AO {
|
||||
|
||||
@@ -54,6 +54,8 @@ CONFIG_AMLOGIC_CLK=y
|
||||
CONFIG_AMLOGIC_M8B_CLK=y
|
||||
CONFIG_AMLOGIC_CRYPTO=y
|
||||
CONFIG_AMLOGIC_CRYPTO_BLKMV=y
|
||||
CONFIG_AMLOGIC_MMC=y
|
||||
CONFIG_AMLOGIC_M8B_MMC=y
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_DMA_CMA=y
|
||||
@@ -106,6 +108,8 @@ CONFIG_USB_CONFIGFS_F_MTP=y
|
||||
CONFIG_USB_CONFIGFS_F_PTP=y
|
||||
CONFIG_USB_CONFIGFS_F_ACC=y
|
||||
CONFIG_USB_CONFIGFS_UEVENT=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_BLOCK_MINORS=16
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_CHROME_PLATFORMS=y
|
||||
CONFIG_ARM_TIMER_SP804=y
|
||||
|
||||
@@ -16,4 +16,15 @@ config AMLOGIC_MMC
|
||||
MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
|
||||
If you have a controller with this interface, say Y here.
|
||||
|
||||
config AMLOGIC_M8B_MMC
|
||||
bool "Amlogic M8B Multimedia Card support"
|
||||
depends on AMLOGIC_MMC
|
||||
default n
|
||||
help
|
||||
This selects support for the Amlogic SD/MMC Host Controller
|
||||
found on the S805/M8B family of SoCs. This controller is
|
||||
MMC 5.1 compliant and supports SD, eMMC and SDIO interfaces.
|
||||
If you have a controller with this interface, say Y here.
|
||||
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -3,3 +3,5 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_MMC) += amlsd.o amlsd_of.o emmc_partitions.o aml_sd_emmc.o emmc_key.o
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_M8B_MMC) += aml_sdhc_m8.o aml_sdio.o
|
||||
|
||||
@@ -2779,7 +2779,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
||||
goto free_host;
|
||||
}
|
||||
|
||||
if (amlsd_get_platform_data(pdata, mmc, 0))
|
||||
if (amlsd_get_platform_data(pdev, pdata, mmc, 0))
|
||||
mmc_free_host(mmc);
|
||||
|
||||
if (aml_card_type_mmc(pdata))
|
||||
|
||||
2477
drivers/amlogic/mmc/aml_sdhc_m8.c
Normal file
2477
drivers/amlogic/mmc/aml_sdhc_m8.c
Normal file
File diff suppressed because it is too large
Load Diff
1367
drivers/amlogic/mmc/aml_sdio.c
Normal file
1367
drivers/amlogic/mmc/aml_sdio.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -37,8 +37,10 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
/* #include <linux/amlogic/aml_gpio_consumer.h> */
|
||||
#include <linux/amlogic/amlsd.h>
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
#include <linux/amlogic/gpio-amlogic.h>
|
||||
#endif
|
||||
|
||||
const u8 tuning_blk_pattern_4bit[64] = {
|
||||
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
|
||||
@@ -109,9 +111,19 @@ static int aml_is_card_insert(struct amlsd_platform *pdata)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
int aml_sd_uart_detect(struct amlsd_platform *pdata)
|
||||
#else
|
||||
int aml_sd_uart_detect(struct amlsd_host *host)
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct mmc_host *mmc = pdata->mmc;
|
||||
#else
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
#endif
|
||||
|
||||
if (aml_is_card_insert(pdata)) {
|
||||
if (pdata->is_in)
|
||||
@@ -119,7 +131,7 @@ int aml_sd_uart_detect(struct amlsd_host *host)
|
||||
pdata->is_in = true;
|
||||
pr_info("normal card in\n");
|
||||
if (pdata->caps & MMC_CAP_4_BIT_DATA)
|
||||
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
} else {
|
||||
if (!pdata->is_in)
|
||||
return 1;
|
||||
@@ -127,14 +139,14 @@ int aml_sd_uart_detect(struct amlsd_host *host)
|
||||
pr_info("card out\n");
|
||||
|
||||
pdata->is_tuned = false;
|
||||
if (host->mmc && host->mmc->card)
|
||||
mmc_card_set_removed(host->mmc->card);
|
||||
if (mmc && mmc->card)
|
||||
mmc_card_set_removed(mmc->card);
|
||||
/* switch to 3.3V */
|
||||
aml_sd_voltage_switch(host->mmc,
|
||||
aml_sd_voltage_switch(mmc,
|
||||
MMC_SIGNAL_VOLTAGE_330);
|
||||
|
||||
if (pdata->caps & MMC_CAP_4_BIT_DATA)
|
||||
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -142,8 +154,15 @@ int aml_sd_uart_detect(struct amlsd_host *host)
|
||||
static int card_dealed;
|
||||
irqreturn_t aml_irq_cd_thread(int irq, void *data)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = (struct amlsd_platform *)data;
|
||||
struct mmc_host *mmc = pdata->mmc;
|
||||
struct amlsd_host *host = pdata->host;
|
||||
#else
|
||||
struct amlsd_host *host = (struct amlsd_host *)data;
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&pdata->in_out_lock);
|
||||
@@ -152,7 +171,11 @@ irqreturn_t aml_irq_cd_thread(int irq, void *data)
|
||||
mutex_unlock(&pdata->in_out_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
ret = aml_sd_uart_detect(pdata);
|
||||
#else
|
||||
ret = aml_sd_uart_detect(host);
|
||||
#endif
|
||||
if (ret == 1) {/* the same as the last*/
|
||||
mutex_unlock(&pdata->in_out_lock);
|
||||
return IRQ_HANDLED;
|
||||
@@ -164,9 +187,9 @@ irqreturn_t aml_irq_cd_thread(int irq, void *data)
|
||||
|
||||
/* mdelay(500); */
|
||||
if (pdata->is_in)
|
||||
mmc_detect_change(host->mmc, msecs_to_jiffies(100));
|
||||
mmc_detect_change(mmc, msecs_to_jiffies(100));
|
||||
else
|
||||
mmc_detect_change(host->mmc, msecs_to_jiffies(0));
|
||||
mmc_detect_change(mmc, msecs_to_jiffies(0));
|
||||
|
||||
card_dealed = 0;
|
||||
return IRQ_HANDLED;
|
||||
@@ -180,7 +203,12 @@ irqreturn_t aml_sd_irq_cd(int irq, void *dev_id)
|
||||
|
||||
static int aml_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
struct amlsd_host *host = pdata->host;
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
#endif
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->mrq_lock, flags);
|
||||
@@ -193,7 +221,12 @@ static int aml_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
|
||||
static int aml_rpmb_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
struct amlsd_host *host = pdata->host;
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
#endif
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->mrq_lock, flags);
|
||||
@@ -208,8 +241,12 @@ static int aml_rpmb_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
|
||||
int aml_check_unsupport_cmd(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
#endif
|
||||
u32 opcode, arg;
|
||||
|
||||
opcode = mrq->cmd->opcode;
|
||||
@@ -276,6 +313,7 @@ int aml_check_unsupport_cmd(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
|
||||
int aml_sd_voltage_switch(struct mmc_host *mmc, char signal_voltage)
|
||||
{
|
||||
#ifndef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
int ret = 0;
|
||||
@@ -311,12 +349,41 @@ int aml_sd_voltage_switch(struct mmc_host *mmc, char signal_voltage)
|
||||
return -EINVAL;
|
||||
|
||||
host->sd_sdio_switch_volat_done = 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* boot9 here */
|
||||
void aml_emmc_hw_reset(struct mmc_host *mmc)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
void __iomem *hw_ctrl;
|
||||
|
||||
if (!aml_card_type_mmc(pdata))
|
||||
return;
|
||||
hw_ctrl = ioremap(P_PREG_PAD_GPIO3_EN_N, 0x200);
|
||||
|
||||
//boot_9 used as eMMC hw_rst pin here.
|
||||
|
||||
//clr nand ce1 pinmux
|
||||
aml_clr_reg32_mask((hw_ctrl + (0x19 << 2)), (1<<24));
|
||||
|
||||
//set out
|
||||
aml_clr_reg32_mask(hw_ctrl, (1<<9));
|
||||
|
||||
//high
|
||||
aml_set_reg32_mask((hw_ctrl + (0x1 << 2)), (1<<9));
|
||||
mdelay(1);
|
||||
|
||||
//low
|
||||
aml_clr_reg32_mask((hw_ctrl + (0x1 << 2)), (1<<9));
|
||||
mdelay(2);
|
||||
|
||||
//high
|
||||
aml_set_reg32_mask((hw_ctrl + (0x1 << 2)), (1<<9));
|
||||
mdelay(1);
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
u32 ret;
|
||||
@@ -350,6 +417,7 @@ void aml_emmc_hw_reset(struct mmc_host *mmc)
|
||||
return;
|
||||
}
|
||||
mdelay(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void sdio_rescan(struct mmc_host *mmc)
|
||||
@@ -397,12 +465,37 @@ int of_amlsd_init(struct amlsd_platform *pdata)
|
||||
if (pdata->gpio_cd) {
|
||||
pr_info("gpio_cd = %x\n", pdata->gpio_cd);
|
||||
ret = gpio_request_one(pdata->gpio_cd,
|
||||
GPIOF_IN, MODULE_NAME);
|
||||
GPIOF_IN, MODULE_NAME);
|
||||
CHECK_RET(ret);
|
||||
}
|
||||
#if 0
|
||||
if (pdata->gpio_ro) {
|
||||
ret = amlogic_gpio_request_one(pdata->gpio_ro,
|
||||
GPIOF_IN, MODULE_NAME);
|
||||
if (!ret) { // ok
|
||||
/* 0:pull down, 1:pull up */
|
||||
ret = amlogic_set_pull_up_down(pdata->gpio_ro,
|
||||
1, MODULE_NAME);
|
||||
CHECK_RET(ret);
|
||||
} else {
|
||||
sdio_err("request gpio_ro pin fail!\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pdata->gpio_power) {
|
||||
if (pdata->power_level) {
|
||||
ret = gpio_request_one(pdata->gpio_power,
|
||||
GPIOF_OUT_INIT_LOW, MODULE_NAME);
|
||||
CHECK_RET(ret);
|
||||
} else {
|
||||
ret = gpio_request_one(pdata->gpio_power,
|
||||
GPIOF_OUT_INIT_HIGH, MODULE_NAME);
|
||||
CHECK_RET(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* if(pdata->port == MESON_SDIO_PORT_A) */
|
||||
/* wifi_setup_dt(); */
|
||||
/* wifi_setup_dt(); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -452,14 +545,24 @@ static struct pinctrl * __must_check aml_devm_pinctrl_get_select(
|
||||
|
||||
void of_amlsd_xfer_pre(struct mmc_host *mmc)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
struct amlsd_host *host = pdata->host;
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
#endif
|
||||
char pinctrl[30];
|
||||
char *p = pinctrl;
|
||||
int i, size = 0;
|
||||
struct pinctrl *ppin;
|
||||
|
||||
size = sizeof(pinctrl);
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
if (pdata->port > PORT_SDIO_C) // so it should be PORT_SDHC_X
|
||||
aml_snprint(&p, &size, "sdhc_");
|
||||
#endif
|
||||
|
||||
if (mmc->ios.chip_select == MMC_CS_DONTCARE) {
|
||||
if ((mmc->caps & MMC_CAP_4_BIT_DATA)
|
||||
|| (strcmp(pdata->pinname, "sd"))
|
||||
@@ -542,8 +645,13 @@ void aml_snprint (char **pp, int *left_size, const char *fmt, ...)
|
||||
void aml_cs_high(struct mmc_host *mmc) /* chip select high */
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
struct amlsd_host *host = pdata->host;
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
#endif
|
||||
|
||||
if ((mmc->ios.chip_select == MMC_CS_HIGH)
|
||||
&& (pdata->gpio_dat3 != 0)) {
|
||||
@@ -560,8 +668,12 @@ void aml_cs_high(struct mmc_host *mmc) /* chip select high */
|
||||
|
||||
void aml_cs_dont_care(struct mmc_host *mmc)
|
||||
{
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct amlsd_platform *pdata = mmc_priv(mmc);
|
||||
#else
|
||||
struct amlsd_host *host = mmc_priv(mmc);
|
||||
struct amlsd_platform *pdata = host->pdata;
|
||||
#endif
|
||||
|
||||
if ((mmc->ios.chip_select == MMC_CS_DONTCARE)
|
||||
&& (pdata->gpio_dat3 != 0)
|
||||
@@ -585,3 +697,157 @@ void of_amlsd_pwr_off(struct amlsd_platform *pdata)
|
||||
gpio_set_value(pdata->gpio_power, !pdata->power_level);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
/*-----------sg copy buffer------------*/
|
||||
/**
|
||||
* aml_sg_miter_stop - stop mapping iteration for amlogic,
|
||||
* We don't disable irq in this function
|
||||
*/
|
||||
static void aml_sg_miter_stop(struct sg_mapping_iter *miter)
|
||||
{
|
||||
WARN_ON(miter->consumed > miter->length);
|
||||
|
||||
/* drop resources from the last iteration */
|
||||
if (miter->addr) {
|
||||
miter->__offset += miter->consumed;
|
||||
miter->__remaining -= miter->consumed;
|
||||
|
||||
if (miter->__flags & SG_MITER_TO_SG)
|
||||
flush_kernel_dcache_page(miter->page);
|
||||
|
||||
if (miter->__flags & SG_MITER_ATOMIC) {
|
||||
WARN_ON_ONCE(preemptible());
|
||||
kunmap_atomic(miter->addr);
|
||||
} else
|
||||
kunmap(miter->page);
|
||||
|
||||
miter->page = NULL;
|
||||
miter->addr = NULL;
|
||||
miter->length = 0;
|
||||
miter->consumed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* aml_sg_miter_next - proceed mapping iterator to the next mapping for amlogic,
|
||||
* We don't disable irq in this function
|
||||
*/
|
||||
static bool aml_sg_miter_next(struct sg_mapping_iter *miter)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
sg_miter_stop(miter);
|
||||
|
||||
/*
|
||||
* Get to the next page if necessary.
|
||||
* __remaining, __offset is adjusted by sg_miter_stop
|
||||
*/
|
||||
if (!miter->__remaining) {
|
||||
struct scatterlist *sg;
|
||||
unsigned long pgoffset;
|
||||
|
||||
if (!__sg_page_iter_next(&miter->piter))
|
||||
return false;
|
||||
|
||||
sg = miter->piter.sg;
|
||||
pgoffset = miter->piter.sg_pgoffset;
|
||||
|
||||
miter->__offset = pgoffset ? 0 : sg->offset;
|
||||
miter->__remaining = sg->offset + sg->length -
|
||||
(pgoffset << PAGE_SHIFT) - miter->__offset;
|
||||
miter->__remaining = min_t(unsigned long, miter->__remaining,
|
||||
PAGE_SIZE - miter->__offset);
|
||||
}
|
||||
miter->page = sg_page_iter_page(&miter->piter);
|
||||
miter->consumed = miter->length = miter->__remaining;
|
||||
|
||||
if (miter->__flags & SG_MITER_ATOMIC) {
|
||||
/*pr_info(KERN_DEBUG "AML_SDHC miter_next highmem\n"); */
|
||||
local_irq_save(flags);
|
||||
miter->addr = kmap_atomic(miter->page) + miter->__offset;
|
||||
local_irq_restore(flags);
|
||||
} else
|
||||
miter->addr = kmap(miter->page) + miter->__offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* aml_sg_copy_buffer - Copy data between a linear buffer
|
||||
* and an SG list for amlogic,
|
||||
* We don't disable irq in this function
|
||||
*/
|
||||
EXPORT_SYMBOL(aml_sg_copy_buffer);
|
||||
size_t aml_sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
|
||||
void *buf, size_t buflen, int to_buffer)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
struct sg_mapping_iter miter;
|
||||
unsigned int sg_flags = SG_MITER_ATOMIC;
|
||||
unsigned long flags;
|
||||
|
||||
if (to_buffer)
|
||||
sg_flags |= SG_MITER_FROM_SG;
|
||||
else
|
||||
sg_flags |= SG_MITER_TO_SG;
|
||||
|
||||
sg_miter_start(&miter, sgl, nents, sg_flags);
|
||||
local_irq_save(flags);
|
||||
|
||||
while (aml_sg_miter_next(&miter) && offset < buflen) {
|
||||
unsigned int len;
|
||||
|
||||
len = min(miter.length, buflen - offset);
|
||||
|
||||
if (to_buffer)
|
||||
memcpy(buf + offset, miter.addr, len);
|
||||
else
|
||||
memcpy(miter.addr, buf + offset, len);
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
aml_sg_miter_stop(&miter);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/*-------------------eMMC/tSD-------------------*/
|
||||
int storage_flag;
|
||||
|
||||
bool is_emmc_exist(struct amlsd_host *host) // is eMMC/tSD exist
|
||||
{
|
||||
print_tmp("host->storage_flag=%d, POR_BOOT_VALUE=%d\n",
|
||||
host->storage_flag, POR_BOOT_VALUE);
|
||||
if ((host->storage_flag == EMMC_BOOT_FLAG)
|
||||
|| (host->storage_flag == SPI_EMMC_FLAG)
|
||||
|| (((host->storage_flag == 0)
|
||||
|| (host->storage_flag == -1))
|
||||
&& (POR_EMMC_BOOT() || POR_SPI_BOOT())))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-------------------debug---------------------*/
|
||||
|
||||
unsigned long sdhc_debug; // 0xffffffff;
|
||||
static int __init sdhc_debug_setup(char *str)
|
||||
{
|
||||
ssize_t status = 0;
|
||||
|
||||
status = kstrtol(str, 0, &sdhc_debug);
|
||||
return 1;
|
||||
}
|
||||
__setup("sdhc_debug=", sdhc_debug_setup);
|
||||
|
||||
unsigned long sdio_debug; // 0xffffff;
|
||||
static int __init sdio_debug_setup(char *str)
|
||||
{
|
||||
ssize_t status = 0;
|
||||
|
||||
status = kstrtol(str, 0, &sdio_debug);
|
||||
return 1;
|
||||
}
|
||||
__setup("sdio_debug=", sdio_debug_setup);
|
||||
#endif
|
||||
|
||||
@@ -25,11 +25,10 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/amlogic/sd.h>
|
||||
/*#include <linux/of_address.h>*/
|
||||
/*#include <linux/amlogic/aml_gpio_consumer.h>*/
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/amlogic/amlsd.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
|
||||
unsigned int sd_emmc_debug;
|
||||
|
||||
static const struct sd_caps host_caps[] = {
|
||||
@@ -119,7 +118,8 @@ static int amlsd_get_host_caps2(struct device_node *of_node,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
int amlsd_get_platform_data(struct platform_device *pdev,
|
||||
struct amlsd_platform *pdata,
|
||||
struct mmc_host *mmc, u32 index)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
@@ -127,10 +127,13 @@ int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
u32 i, prop;
|
||||
const char *str = "none";
|
||||
|
||||
if (!mmc->parent || !mmc->parent->of_node)
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
of_node = pdev->dev.of_node;
|
||||
#else
|
||||
if (!mmc->parent)
|
||||
return 0;
|
||||
|
||||
of_node = mmc->parent->of_node;
|
||||
#endif
|
||||
if (of_node) {
|
||||
child = of_node->child;
|
||||
WARN_ON(!child);
|
||||
@@ -151,8 +154,8 @@ int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
prop, pdata->f_min);
|
||||
SD_PARSE_U32_PROP_DEC(child, "f_max",
|
||||
prop, pdata->f_max);
|
||||
SD_PARSE_U32_PROP_HEX(child, "max_req_size", prop,
|
||||
pdata->max_req_size);
|
||||
SD_PARSE_U32_PROP_HEX(child, "max_req_size",
|
||||
prop, pdata->max_req_size);
|
||||
SD_PARSE_GPIO_NUM_PROP(child, "gpio_cd",
|
||||
str, pdata->gpio_cd);
|
||||
SD_PARSE_GPIO_NUM_PROP(child, "gpio_ro",
|
||||
@@ -177,20 +180,22 @@ int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
prop, pdata->vol_switch_delay);
|
||||
SD_PARSE_U32_PROP_DEC(child, "card_type",
|
||||
prop, pdata->card_type);
|
||||
if (aml_card_type_mmc(pdata)) {
|
||||
/*tx_phase set default value first*/
|
||||
if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB)
|
||||
pdata->tx_phase = 1;
|
||||
if (get_cpu_type() == MESON_CPU_MAJOR_ID_TXL)
|
||||
pdata->tx_delay = 3;
|
||||
SD_PARSE_U32_PROP_DEC(child, "tx_phase",
|
||||
prop, pdata->tx_phase);
|
||||
}
|
||||
if (aml_card_type_non_sdio(pdata)) {
|
||||
/*card in default value*/
|
||||
pdata->card_in_delay = 0;
|
||||
SD_PARSE_U32_PROP_DEC(child, "card_in_delay",
|
||||
prop, pdata->card_in_delay);
|
||||
if (get_cpu_type() > MESON_CPU_MAJOR_ID_M8B) {
|
||||
if (aml_card_type_mmc(pdata)) {
|
||||
/*tx_phase set default value first*/
|
||||
if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB)
|
||||
pdata->tx_phase = 1;
|
||||
if (get_cpu_type() == MESON_CPU_MAJOR_ID_TXL)
|
||||
pdata->tx_delay = 3;
|
||||
SD_PARSE_U32_PROP_DEC(child, "tx_phase",
|
||||
prop, pdata->tx_phase);
|
||||
}
|
||||
if (aml_card_type_non_sdio(pdata)) {
|
||||
/*card in default value*/
|
||||
pdata->card_in_delay = 0;
|
||||
SD_PARSE_U32_PROP_DEC(child, "card_in_delay",
|
||||
prop, pdata->card_in_delay);
|
||||
}
|
||||
}
|
||||
SD_PARSE_GPIO_NUM_PROP(child, "hw_reset",
|
||||
str, pdata->hw_reset);
|
||||
@@ -209,4 +214,3 @@ int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#define AML_MMC_VER_MESSAGE \
|
||||
"2015-01-21: fix a bug in tuning which caused eMMC data CRC error"
|
||||
|
||||
extern unsigned int sdhc_debug;
|
||||
extern unsigned int sdio_debug;
|
||||
extern unsigned long sdhc_debug;
|
||||
extern unsigned long sdio_debug;
|
||||
extern unsigned int sd_emmc_debug;
|
||||
extern const u8 tuning_blk_pattern_4bit[64];
|
||||
extern const u8 tuning_blk_pattern_8bit[128];
|
||||
@@ -49,8 +49,8 @@ extern const u8 tuning_blk_pattern_8bit[128];
|
||||
#define LDO4DAC_REG_1_8_V 0x24
|
||||
#define LDO4DAC_REG_2_8_V 0x4c
|
||||
#define LDO4DAC_REG_3_3_V 0x60
|
||||
|
||||
#endif
|
||||
|
||||
#define AMLSD_DBG_COMMON (1<<0)
|
||||
#define AMLSD_DBG_REQ (1<<1)
|
||||
#define AMLSD_DBG_RESP (1<<2)
|
||||
@@ -73,6 +73,12 @@ extern const u8 tuning_blk_pattern_8bit[128];
|
||||
#define EMMC_DAT3_PINMUX_CLR 0
|
||||
#define EMMC_DAT3_PINMUX_SET 1
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
#define P_PERIPHS_PIN_MUX_2 (0xc1100000 + (0x202e << 2))
|
||||
#define P_PREG_PAD_GPIO3_EN_N (0xc1100000 + (0x2015 << 2))
|
||||
#define P_PREG_PAD_GPIO3_O (0xc1100000 + (0x2016 << 2))
|
||||
#endif
|
||||
|
||||
#define CHECK_RET(ret) { \
|
||||
if (ret) \
|
||||
pr_info("[%s] gpio op failed(%d) at line %d\n",\
|
||||
@@ -171,10 +177,13 @@ extern void aml_sd_emmc_print_reg(struct amlsd_host *host);
|
||||
|
||||
extern int add_part_table(struct mtd_partition *part, unsigned int nr_part);
|
||||
extern int add_emmc_partition(struct gendisk *disk);
|
||||
#endif
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
extern size_t aml_sg_copy_buffer(struct scatterlist *sgl, unsigned int nents,
|
||||
void *buf, size_t buflen, int to_buffer);
|
||||
#endif
|
||||
int amlsd_get_platform_data(struct amlsd_platform *pdata,
|
||||
int amlsd_get_platform_data(struct platform_device *pdev,
|
||||
struct amlsd_platform *pdata,
|
||||
struct mmc_host *mmc, u32 index);
|
||||
|
||||
void of_amlsd_irq_init(struct amlsd_platform *pdata);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef __PLAT_MESON_CPU_H
|
||||
#define __PLAT_MESON_CPU_H
|
||||
|
||||
#define MESON_CPU_MAJOR_ID_M8B 0x1B
|
||||
#define MESON_CPU_MAJOR_ID_GXBB 0x1F
|
||||
#define MESON_CPU_MAJOR_ID_GXTVBB 0x20
|
||||
#define MESON_CPU_MAJOR_ID_GXL 0x21
|
||||
|
||||
@@ -159,6 +159,10 @@ struct amlsd_platform {
|
||||
#define PORT_SDHC_B 4
|
||||
#define PORT_SDHC_C 5
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
unsigned int width;
|
||||
unsigned int tune_phase; /* store tuning result */
|
||||
#endif
|
||||
unsigned int caps;
|
||||
unsigned int caps2;
|
||||
unsigned int card_capacity;
|
||||
@@ -291,6 +295,9 @@ struct amlsd_host {
|
||||
unsigned long mux_parent_rate[MUX_CLK_NUM_PARENTS];
|
||||
struct clk_divider cfg_div;
|
||||
struct clk *cfg_div_clk;
|
||||
#ifdef CONFIG_AMLOGIC_M8B_MMC
|
||||
struct clk *div3_clk;
|
||||
#endif
|
||||
|
||||
struct resource *mem;
|
||||
struct sd_emmc_regs *sd_emmc_regs;
|
||||
|
||||
Reference in New Issue
Block a user