emmc: add sd emmc driver

PD#138714: add sd/emmc driver support
1 add emmc hs200/hs400 mode
2 add sd highspeed mode
3 add sd hotplug detect
4 add emmc clock tree supported
5 add sdio get_wifi_inf & sdio_reinit
6 add partitions on dts
7 add sd/emmc pinmux set

Change-Id: I449e61517844cb4cb9ad3aaa2f79c911e8658356
Signed-off-by: Nan Li <nan.li@amlogic.com>
This commit is contained in:
Nan Li
2017-02-09 11:28:31 +08:00
committed by Victor Wan
parent 260c6d8c9b
commit a0de710366
25 changed files with 7641 additions and 56 deletions

View File

@@ -13578,3 +13578,26 @@ F: include/uapi/linux/rc_common.h
F: arch/arm64/boot/dts/amlogic/mesongxl.dtsi
F: arch/arm64/boot/dts/amlogic/mesongxm.dtsi
AMLOGIC SD/MMC DIRVER SUPPORT
M: Nan Li <nan.li@amlogic.com>
F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts
F: arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts
F: arch/arm64/boot/dts/amlogic/mesongxl.dtsi
F: arch/arm64/configs/meson64_defconfig
F: drivers/amlogic/Kconfig
F: drivers/amlogic/Makefile
F: drivers/amlogic/mmc/Kconfig
F: drivers/amlogic/mmc/Makefile
F: drivers/amlogic/mmc/aml_sd_emmc.c
F: drivers/amlogic/mmc/emmc_partitions.c
F: drivers/amlogic/mmc/amlsd_of.c
F: drivers/amlogic/mmc/amlsd.c
F: drivers/mmc/card/block.c
F: drivers/mmc/core/bus.c
F: drivers/mmc/core/core.c
F: drivers/mmc/core/mmc.c
F: include/linux/amlogic/amlsd.h
F: include/linux/amlogic/sd.h
F: include/linux/mmc/emmc_partitions.h
F: include/linux/mmc/host.h

View File

@@ -107,11 +107,156 @@
};
};
sd_emmc_c: emmc@d0074000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0074000 0x0 0x2000>;
interrupts = <0 218 1>;
pinctrl-names = "emmc_clk_cmd_pins", "emmc_all_pins";
pinctrl-0 = <&emmc_clk_cmd_pins>;
pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&clkc CLKID_SD_EMMC_C_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <8>;
cap-sd-highspeed;
cap-mmc-highspeed;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
max-frequency = <200000000>;
non-removable;
disable-wp;
emmc {
status = "disabled";
pinname = "emmc";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_8_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED",
"MMC_CAP_NONREMOVABLE",
"MMC_CAP_1_8V_DDR",
"MMC_CAP_HW_RESET",
"MMC_CAP_ERASE",
"MMC_CAP_CMD23";
caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
f_min = <300000>;
f_max = <100000000>;
max_req_size = <0x20000>; /**128KB*/
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
card_type = <1>;
/* 1:mmc card(include eMMC),
* 2:sd card(include tSD)
*/
};
};
sd_emmc_b:sd@d0072000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0072000 0x0 0x2000>;
interrupts = <0 217 1>;
pinctrl-names = "sd_all_pins",
"sd_clk_cmd_pins",
"sd_clk_cmd_uart_pins",
"sd_to_ao_uart_pins",
"ao_to_sd_uart_pins";
pinctrl-0 = <&sd_all_pins>;
pinctrl-1 = <&sd_clk_cmd_pins>;
pinctrl-2 = <&sd_clk_cmd_pins &ao_to_sd_uart_pins>;
pinctrl-3 = <&sd_to_ao_uart_pins>;
pinctrl-4 = <&ao_to_sd_uart_pins>;
clocks = <&clkc CLKID_SD_EMMC_B>,
<&clkc CLKID_SD_EMMC_B_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
max-frequency = <100000000>;
disable-wp;
sd {
status = "disabled";
pinname = "sd";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_4_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED";
/* "MMC_CAP_UHS_SDR12",
* "MMC_CAP_UHS_SDR25",
* "MMC_CAP_UHS_SDR50",
* "MMC_CAP_UHS_SDR104";
*/
f_min = <400000>;
f_max = <100000000>;
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>;
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
*/
};
};
sd_emmc_a:sdio@d0070000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0070000 0x0 0x2000>;
interrupts = <0 216 4>;
pinctrl-names = "sdio_clk_cmd_pins", "sdio_all_pins";
pinctrl-0 = <&sdio_clk_cmd_pins>;
pinctrl-1 = <&sdio_all_pins>;
clocks = <&clkc CLKID_SD_EMMC_A>,
<&clkc CLKID_SD_EMMC_A_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
cap-mmc-highspeed;
max-frequency = <100000000>;
non-removable;
disable-wp;
sdio {
status = "disabled";
pinname = "sdio";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
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",
"MMC_CAP_SDIO_IRQ";
f_min = <400000>;
f_max = <200000000>;
max_req_size = <0x20000>; /**128KB*/
card_type = <3>;
/* 3:sdio device(ie:sdio-wifi),
* 4:SD combo (IO+mem) card
*/
};
};
uart_AO: serial@c81004c0 {
compatible = "amlogic, meson-uart";
reg = <0x0 0xc81004c0 0x0 0x18>;
interrupts = <0 193 1>;
status = "okay";
clocks = <&xtal>;
clock-names = "clk_uart";
xtal_tick_en = <1>;
fifosize = < 64 >;
pinctrl-names = "default";
@@ -364,6 +509,81 @@
interrupts = <0 89 1>;
interrupt-names = "rdma";
};
partitions: partitions{
parts = <11>;
part-0 = <&logo>;
part-1 = <&recovery>;
part-2 = <&rsv>;
part-3 = <&tee>;
part-4 = <&crypt>;
part-5 = <&misc>;
part-6 = <&instaboot>;
part-7 = <&boot>;
part-8 = <&system>;
part-9 = <&cache>;
part-10 = <&data>;
logo:logo{
pname = "logo";
size = <0x0 0x2000000>;
mask = <1>;
};
recovery:recovery{
pname = "recovery";
size = <0x0 0x2000000>;
mask = <1>;
};
rsv:rsv{
pname = "rsv";
size = <0x0 0x800000>;
mask = <1>;
};
tee:tee{
pname = "tee";
size = <0x0 0x800000>;
mask = <1>;
};
crypt:crypt{
pname = "crypt";
size = <0x0 0x2000000>;
mask = <1>;
};
misc:misc{
pname = "misc";
size = <0x0 0x2000000>;
mask = <1>;
};
instaboot:instaboot{
pname = "instaboot";
size = <0x0 0x400000>;
mask = <1>;
};
boot:boot
{
pname = "boot";
size = <0x0 0x2000000>;
mask = <1>;
};
system:system
{
pname = "system";
size = <0x0 0x80000000>;
mask = <1>;
};
cache:cache
{
pname = "cache";
size = <0x0 0x20000000>;
mask = <2>;
};
data:data
{
pname = "data";
size = <0xffffffff 0xffffffff>;
mask = <4>;
};
};
};
&efuse {
status = "ok";

View File

@@ -108,6 +108,149 @@
};
};
sd_emmc_c: emmc@d0074000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0074000 0x0 0x2000>;
interrupts = <0 218 1>;
pinctrl-names = "emmc_clk_cmd_pins", "emmc_all_pins";
pinctrl-0 = <&emmc_clk_cmd_pins>;
pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&clkc CLKID_SD_EMMC_C_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <8>;
cap-sd-highspeed;
cap-mmc-highspeed;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
max-frequency = <200000000>;
non-removable;
disable-wp;
emmc {
status = "disabled";
pinname = "emmc";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_8_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED",
"MMC_CAP_NONREMOVABLE",
"MMC_CAP_1_8V_DDR",
"MMC_CAP_HW_RESET",
"MMC_CAP_ERASE",
"MMC_CAP_CMD23";
caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
f_min = <300000>;
f_max = <100000000>;
max_req_size = <0x20000>; /**128KB*/
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
card_type = <1>;
/* 1:mmc card(include eMMC),
* 2:sd card(include tSD)
*/
};
};
sd_emmc_b:sd@d0072000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0072000 0x0 0x2000>;
interrupts = <0 217 1>;
pinctrl-names = "sd_all_pins",
"sd_clk_cmd_pins",
"sd_clk_cmd_uart_pins",
"sd_to_ao_uart_pins",
"ao_to_sd_uart_pins";
pinctrl-0 = <&sd_all_pins>;
pinctrl-1 = <&sd_clk_cmd_pins>;
pinctrl-2 = <&sd_clk_cmd_pins &ao_to_sd_uart_pins>;
pinctrl-3 = <&sd_to_ao_uart_pins>;
pinctrl-4 = <&ao_to_sd_uart_pins>;
clocks = <&clkc CLKID_SD_EMMC_B>,
<&clkc CLKID_SD_EMMC_B_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
max-frequency = <100000000>;
disable-wp;
sd {
status = "disabled";
pinname = "sd";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_4_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED";
/* "MMC_CAP_UHS_SDR12",
* "MMC_CAP_UHS_SDR25",
* "MMC_CAP_UHS_SDR50",
* "MMC_CAP_UHS_SDR104";
*/
f_min = <400000>;
f_max = <100000000>;
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>;
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
*/
};
};
sd_emmc_a:sdio@d0070000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0070000 0x0 0x2000>;
interrupts = <0 216 4>;
pinctrl-names = "sdio_clk_cmd_pins", "sdio_all_pins";
pinctrl-0 = <&sdio_clk_cmd_pins>;
pinctrl-1 = <&sdio_all_pins>;
clocks = <&clkc CLKID_SD_EMMC_A>,
<&clkc CLKID_SD_EMMC_A_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
cap-mmc-highspeed;
max-frequency = <100000000>;
non-removable;
disable-wp;
sdio {
status = "disabled";
pinname = "sdio";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
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",
"MMC_CAP_SDIO_IRQ";
f_min = <400000>;
f_max = <200000000>;
max_req_size = <0x20000>; /**128KB*/
card_type = <3>;
/* 3:sdio device(ie:sdio-wifi),
* 4:SD combo (IO+mem) card
*/
};
};
uart_AO: serial@c81004c0 {
compatible = "amlogic, meson-uart";
reg = <0x0 0xc81004c0 0x0 0x18>;
@@ -364,6 +507,81 @@
interrupts = <0 89 1>;
interrupt-names = "rdma";
};
partitions: partitions{
parts = <11>;
part-0 = <&logo>;
part-1 = <&recovery>;
part-2 = <&rsv>;
part-3 = <&tee>;
part-4 = <&crypt>;
part-5 = <&misc>;
part-6 = <&instaboot>;
part-7 = <&boot>;
part-8 = <&system>;
part-9 = <&cache>;
part-10 = <&data>;
logo:logo{
pname = "logo";
size = <0x0 0x2000000>;
mask = <1>;
};
recovery:recovery{
pname = "recovery";
size = <0x0 0x2000000>;
mask = <1>;
};
rsv:rsv{
pname = "rsv";
size = <0x0 0x800000>;
mask = <1>;
};
tee:tee{
pname = "tee";
size = <0x0 0x800000>;
mask = <1>;
};
crypt:crypt{
pname = "crypt";
size = <0x0 0x2000000>;
mask = <1>;
};
misc:misc{
pname = "misc";
size = <0x0 0x2000000>;
mask = <1>;
};
instaboot:instaboot{
pname = "instaboot";
size = <0x0 0x400000>;
mask = <1>;
};
boot:boot
{
pname = "boot";
size = <0x0 0x2000000>;
mask = <1>;
};
system:system
{
pname = "system";
size = <0x0 0x80000000>;
mask = <1>;
};
cache:cache
{
pname = "cache";
size = <0x0 0x20000000>;
mask = <2>;
};
data:data
{
pname = "data";
size = <0xffffffff 0xffffffff>;
mask = <4>;
};
};
};
&efuse {
status = "ok";

View File

@@ -107,11 +107,156 @@
};
};
sd_emmc_c: emmc@d0074000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0074000 0x0 0x2000>;
interrupts = <0 218 1>;
pinctrl-names = "emmc_clk_cmd_pins", "emmc_all_pins";
pinctrl-0 = <&emmc_clk_cmd_pins>;
pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&clkc CLKID_SD_EMMC_C_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <8>;
cap-sd-highspeed;
cap-mmc-highspeed;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
max-frequency = <200000000>;
non-removable;
disable-wp;
emmc {
status = "disabled";
pinname = "emmc";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_8_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED",
"MMC_CAP_NONREMOVABLE",
"MMC_CAP_1_8V_DDR",
"MMC_CAP_HW_RESET",
"MMC_CAP_ERASE",
"MMC_CAP_CMD23";
caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
f_min = <300000>;
f_max = <100000000>;
max_req_size = <0x20000>; /**128KB*/
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
card_type = <1>;
/* 1:mmc card(include eMMC),
* 2:sd card(include tSD)
*/
};
};
sd_emmc_b:sd@d0072000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0072000 0x0 0x2000>;
interrupts = <0 217 1>;
pinctrl-names = "sd_all_pins",
"sd_clk_cmd_pins",
"sd_clk_cmd_uart_pins",
"sd_to_ao_uart_pins",
"ao_to_sd_uart_pins";
pinctrl-0 = <&sd_all_pins>;
pinctrl-1 = <&sd_clk_cmd_pins>;
pinctrl-2 = <&sd_clk_cmd_pins &ao_to_sd_uart_pins>;
pinctrl-3 = <&sd_to_ao_uart_pins>;
pinctrl-4 = <&ao_to_sd_uart_pins>;
clocks = <&clkc CLKID_SD_EMMC_B>,
<&clkc CLKID_SD_EMMC_B_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
max-frequency = <100000000>;
disable-wp;
sd {
status = "disabled";
pinname = "sd";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_4_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED";
/* "MMC_CAP_UHS_SDR12",
* "MMC_CAP_UHS_SDR25",
* "MMC_CAP_UHS_SDR50",
* "MMC_CAP_UHS_SDR104";
*/
f_min = <400000>;
f_max = <100000000>;
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>;
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
*/
};
};
sd_emmc_a:sdio@d0070000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0070000 0x0 0x2000>;
interrupts = <0 216 4>;
pinctrl-names = "sdio_clk_cmd_pins", "sdio_all_pins";
pinctrl-0 = <&sdio_clk_cmd_pins>;
pinctrl-1 = <&sdio_all_pins>;
clocks = <&clkc CLKID_SD_EMMC_A>,
<&clkc CLKID_SD_EMMC_A_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
cap-mmc-highspeed;
max-frequency = <100000000>;
non-removable;
disable-wp;
sdio {
status = "disabled";
pinname = "sdio";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
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",
"MMC_CAP_SDIO_IRQ";
f_min = <400000>;
f_max = <200000000>;
max_req_size = <0x20000>; /**128KB*/
card_type = <3>;
/* 3:sdio device(ie:sdio-wifi),
* 4:SD combo (IO+mem) card
*/
};
};
uart_AO: serial@c81004c0 {
compatible = "amlogic, meson-uart";
reg = <0x0 0xc81004c0 0x0 0x18>;
interrupts = <0 193 1>;
status = "okay";
clocks = <&xtal>;
clock-names = "clk_uart";
xtal_tick_en = <1>;
fifosize = < 64 >;
pinctrl-names = "default";
@@ -363,6 +508,81 @@
interrupts = <0 89 1>;
interrupt-names = "rdma";
};
partitions: partitions{
parts = <11>;
part-0 = <&logo>;
part-1 = <&recovery>;
part-2 = <&rsv>;
part-3 = <&tee>;
part-4 = <&crypt>;
part-5 = <&misc>;
part-6 = <&instaboot>;
part-7 = <&boot>;
part-8 = <&system>;
part-9 = <&cache>;
part-10 = <&data>;
logo:logo{
pname = "logo";
size = <0x0 0x2000000>;
mask = <1>;
};
recovery:recovery{
pname = "recovery";
size = <0x0 0x2000000>;
mask = <1>;
};
rsv:rsv{
pname = "rsv";
size = <0x0 0x800000>;
mask = <1>;
};
tee:tee{
pname = "tee";
size = <0x0 0x800000>;
mask = <1>;
};
crypt:crypt{
pname = "crypt";
size = <0x0 0x2000000>;
mask = <1>;
};
misc:misc{
pname = "misc";
size = <0x0 0x2000000>;
mask = <1>;
};
instaboot:instaboot{
pname = "instaboot";
size = <0x0 0x400000>;
mask = <1>;
};
boot:boot
{
pname = "boot";
size = <0x0 0x2000000>;
mask = <1>;
};
system:system
{
pname = "system";
size = <0x0 0x80000000>;
mask = <1>;
};
cache:cache
{
pname = "cache";
size = <0x0 0x20000000>;
mask = <2>;
};
data:data
{
pname = "data";
size = <0xffffffff 0xffffffff>;
mask = <4>;
};
};
};
&efuse {
status = "ok";

View File

@@ -108,6 +108,149 @@
};
};
sd_emmc_c: emmc@d0074000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0074000 0x0 0x2000>;
interrupts = <0 218 1>;
pinctrl-names = "emmc_clk_cmd_pins", "emmc_all_pins";
pinctrl-0 = <&emmc_clk_cmd_pins>;
pinctrl-1 = <&emmc_conf_pull_up &emmc_conf_pull_done>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&clkc CLKID_SD_EMMC_C_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <8>;
cap-sd-highspeed;
cap-mmc-highspeed;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
max-frequency = <200000000>;
non-removable;
disable-wp;
emmc {
status = "disabled";
pinname = "emmc";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_8_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED",
"MMC_CAP_NONREMOVABLE",
"MMC_CAP_1_8V_DDR",
"MMC_CAP_HW_RESET",
"MMC_CAP_ERASE",
"MMC_CAP_CMD23";
caps2 = "MMC_CAP2_HS200", "MMC_CAP2_HS400";
f_min = <300000>;
f_max = <100000000>;
max_req_size = <0x20000>; /**128KB*/
hw_reset = <&gpio BOOT_9 GPIO_ACTIVE_HIGH>;
card_type = <1>;
/* 1:mmc card(include eMMC),
* 2:sd card(include tSD)
*/
};
};
sd_emmc_b:sd@d0072000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0072000 0x0 0x2000>;
interrupts = <0 217 1>;
pinctrl-names = "sd_all_pins",
"sd_clk_cmd_pins",
"sd_clk_cmd_uart_pins",
"sd_to_ao_uart_pins",
"ao_to_sd_uart_pins";
pinctrl-0 = <&sd_all_pins>;
pinctrl-1 = <&sd_clk_cmd_pins>;
pinctrl-2 = <&sd_clk_cmd_pins &ao_to_sd_uart_pins>;
pinctrl-3 = <&sd_to_ao_uart_pins>;
pinctrl-4 = <&ao_to_sd_uart_pins>;
clocks = <&clkc CLKID_SD_EMMC_B>,
<&clkc CLKID_SD_EMMC_B_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
max-frequency = <100000000>;
disable-wp;
sd {
status = "disabled";
pinname = "sd";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
caps = "MMC_CAP_4_BIT_DATA",
"MMC_CAP_MMC_HIGHSPEED",
"MMC_CAP_SD_HIGHSPEED";
/* "MMC_CAP_UHS_SDR12",
* "MMC_CAP_UHS_SDR25",
* "MMC_CAP_UHS_SDR50",
* "MMC_CAP_UHS_SDR104";
*/
f_min = <400000>;
f_max = <100000000>;
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>;
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
*/
};
};
sd_emmc_a:sdio@d0070000 {
status = "okay";
compatible = "amlogic, meson-aml-mmc";
reg = <0x0 0xd0070000 0x0 0x2000>;
interrupts = <0 216 4>;
pinctrl-names = "sdio_clk_cmd_pins", "sdio_all_pins";
pinctrl-0 = <&sdio_clk_cmd_pins>;
pinctrl-1 = <&sdio_all_pins>;
clocks = <&clkc CLKID_SD_EMMC_A>,
<&clkc CLKID_SD_EMMC_A_P0_COMP>,
<&clkc CLKID_FCLK_DIV2>;
clock-names = "core", "clkin0", "clkin1";
bus-width = <4>;
cap-sd-highspeed;
cap-mmc-highspeed;
max-frequency = <100000000>;
non-removable;
disable-wp;
sdio {
status = "disabled";
pinname = "sdio";
ocr_avail = <0x200080>; /**VDD voltage 3.3 ~ 3.4 */
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",
"MMC_CAP_SDIO_IRQ";
f_min = <400000>;
f_max = <200000000>;
max_req_size = <0x20000>; /**128KB*/
card_type = <3>;
/* 3:sdio device(ie:sdio-wifi),
* 4:SD combo (IO+mem) card
*/
};
};
uart_AO: serial@c81004c0 {
compatible = "amlogic, meson-uart";
reg = <0x0 0xc81004c0 0x0 0x18>;
@@ -115,6 +258,8 @@
status = "okay";
xtal_tick_en = <1>;
fifosize = < 64 >;
pinctrl-names = "default";
pinctrl-0 = <&ao_uart_pins>;
support-sysrq = <0>; /* 0 not support , 1 support */
};
@@ -208,6 +353,25 @@
status = "okay";
};
amhdmitx: amhdmitx{
compatible = "amlogic, amhdmitx";
dev_name = "amhdmitx";
status = "okay";
vend-data = <&vend_data>;
pinctrl-names="hdmitx_hpd", "hdmitx_ddc";
pinctrl-0=<&hdmitx_hpd>;
pinctrl-1=<&hdmitx_ddc>;
/* HPD, 57 + 32 = 89; CEC, 151 + 32 = 183*/
interrupts = <0 57 1>;
interrupt-names = "hdmitx_hpd";
vend_data: vend_data{ /* Should modified by Customer */
vendor_name = "Amlogic"; /* Max Chars: 8 */
/* standards.ieee.org/develop/regauth/oui/oui.txt */
vendor_id = <0x000000>;
product_desc = "MBox Meson Ref"; /* Max Chars: 16 */
};
};
meson-fb {
compatible = "amlogic, meson-fb";
/* memory-region = <&fb_reserved>; */
@@ -245,27 +409,82 @@
interrupts = <0 89 1>;
interrupt-names = "rdma";
};
amhdmitx: amhdmitx{
compatible = "amlogic, amhdmitx";
dev_name = "amhdmitx";
status = "okay";
vend-data = <&vend_data>;
pinctrl-names="hdmitx_hpd", "hdmitx_ddc";
pinctrl-0=<&hdmitx_hpd>;
pinctrl-1=<&hdmitx_ddc>;
/* HPD, 57 + 32 = 89; CEC, 151 + 32 = 183*/
interrupts = <0 57 1>;
interrupt-names = "hdmitx_hpd";
ranges;
vend_data: vend_data{ /* Should modified by Customer */
vendor_name = "Amlogic"; /* Max Chars: 8 */
/* standards.ieee.org/develop/regauth/oui/oui.txt */
vendor_id = <0x000000>;
product_desc = "MBox Meson Ref"; /* Max Chars: 16 */
partitions: partitions{
parts = <11>;
part-0 = <&logo>;
part-1 = <&recovery>;
part-2 = <&rsv>;
part-3 = <&tee>;
part-4 = <&crypt>;
part-5 = <&misc>;
part-6 = <&instaboot>;
part-7 = <&boot>;
part-8 = <&system>;
part-9 = <&cache>;
part-10 = <&data>;
logo:logo{
pname = "logo";
size = <0x0 0x2000000>;
mask = <1>;
};
recovery:recovery{
pname = "recovery";
size = <0x0 0x2000000>;
mask = <1>;
};
rsv:rsv{
pname = "rsv";
size = <0x0 0x800000>;
mask = <1>;
};
tee:tee{
pname = "tee";
size = <0x0 0x800000>;
mask = <1>;
};
crypt:crypt{
pname = "crypt";
size = <0x0 0x2000000>;
mask = <1>;
};
misc:misc{
pname = "misc";
size = <0x0 0x2000000>;
mask = <1>;
};
instaboot:instaboot{
pname = "instaboot";
size = <0x0 0x400000>;
mask = <1>;
};
boot:boot
{
pname = "boot";
size = <0x0 0x2000000>;
mask = <1>;
};
system:system
{
pname = "system";
size = <0x0 0x80000000>;
mask = <1>;
};
cache:cache
{
pname = "cache";
size = <0x0 0x20000000>;
mask = <2>;
};
data:data
{
pname = "data";
size = <0xffffffff 0xffffffff>;
mask = <4>;
};
};
};
&efuse {
status = "ok";
};

View File

@@ -19,6 +19,7 @@
#include <dt-bindings/reset/amlogic,gxl-reset.h>
#include <dt-bindings/clock/amlogic,gxl-clkc.h>
#include <dt-bindings/gpio/gxl.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pwm/meson.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/input/meson_rc.h>
@@ -396,6 +397,15 @@
function = "remote";
};
};
sd_to_ao_uart_pins:sd_to_ao_uart_pins {
mux {
groups = "uart_tx_ao_a_0",
"uart_rx_ao_a_0";
function = "uart_ao";
bias-pull-up;
input-enable;
};
};
ao_uart_pins:ao_uart {
mux {
@@ -552,32 +562,29 @@
* };
* sd_1bit_uart_pins:sd_1bit_uart_pins {
* };
* sd_to_ao_uart_pins:sd_to_ao_uart_pins {
* };
* ao_to_sd_uart_pins:ao_to_sd_uart_pins {
* };
* sd_to_ao_jtag_pins:sd_to_ao_jtag_pins{
* };
*/
ao_to_sd_uart_pins:ao_to_sd_uart_pins {
mux {
groups = "uart_tx_ao_a_1",
"uart_rx_ao_a_1";
function = "uart_ao_a_1";
bias-pull-up;
input-enable;
};
};
emmc_clk_cmd_pins:emmc_clk_cmd_pins {
mux {
groups = "emmc_cmd",
"emmc_clk";
function = "emmc";
bias-pull-up;
input-enable;
bias-pull-up;
};
};
emmc_pins: emmc {
mux {
groups = "emmc_nand_d07",
"emmc_cmd",
"emmc_clk";
function = "emmc";
};
};
emmc_conf_pull_up:emmc_conf_pull_up {
mux {
@@ -585,6 +592,7 @@
"emmc_clk",
"emmc_cmd";
function = "emmc";
input-enable;
bias-pull-up;
};
};
@@ -593,17 +601,32 @@
mux {
groups = "emmc_ds";
function = "emmc";
input-enable;
bias-pull-down;
};
};
emmc_all_pins:emmc_all_pins {
sd_clk_cmd_pins:sd_clk_cmd_pins{
mux {
groups = "emmc_nand_d07",
"emmc_clk",
"emmc_cmd";
function = "emmc";
groups = "sdcard_cmd",
"sdcard_clk";
function = "sdcard";
input-enable;
bias-pull-up;
};
};
sd_all_pins:sd_all_pins{
mux {
groups = "sdcard_d0",
"sdcard_d1",
"sdcard_d2",
"sdcard_d3",
"sdcard_cmd",
"sdcard_clk";
function = "sdcard";
input-enable;
bias-pull-up;
};
};

View File

@@ -19,6 +19,7 @@
#include <dt-bindings/reset/amlogic,gxl-reset.h>
#include <dt-bindings/clock/amlogic,gxl-clkc.h>
#include <dt-bindings/gpio/gxl.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pwm/meson.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/input/meson_rc.h>
@@ -448,6 +449,15 @@
function = "remote";
};
};
sd_to_ao_uart_pins:sd_to_ao_uart_pins {
mux {
groups = "uart_tx_ao_a_0",
"uart_rx_ao_a_0";
function = "uart_ao";
bias-pull-up;
input-enable;
};
};
ao_uart_pins:ao_uart {
mux {
@@ -604,32 +614,29 @@
* };
* sd_1bit_uart_pins:sd_1bit_uart_pins {
* };
* sd_to_ao_uart_pins:sd_to_ao_uart_pins {
* };
* ao_to_sd_uart_pins:ao_to_sd_uart_pins {
* };
* sd_to_ao_jtag_pins:sd_to_ao_jtag_pins{
* };
*/
ao_to_sd_uart_pins:ao_to_sd_uart_pins {
mux {
groups = "uart_tx_ao_a_1",
"uart_rx_ao_a_1";
function = "uart_ao_a_1";
bias-pull-up;
input-enable;
};
};
emmc_clk_cmd_pins:emmc_clk_cmd_pins {
mux {
groups = "emmc_cmd",
"emmc_clk";
function = "emmc";
bias-pull-up;
input-enable;
bias-pull-up;
};
};
emmc_pins: emmc {
mux {
groups = "emmc_nand_d07",
"emmc_cmd",
"emmc_clk";
function = "emmc";
};
};
emmc_conf_pull_up:emmc_conf_pull_up {
mux {
@@ -637,6 +644,7 @@
"emmc_clk",
"emmc_cmd";
function = "emmc";
input-enable;
bias-pull-up;
};
};
@@ -645,17 +653,32 @@
mux {
groups = "emmc_ds";
function = "emmc";
input-enable;
bias-pull-down;
};
};
emmc_all_pins:emmc_all_pins {
sd_clk_cmd_pins:sd_clk_cmd_pins{
mux {
groups = "emmc_nand_d07",
"emmc_clk",
"emmc_cmd";
function = "emmc";
groups = "sdcard_cmd",
"sdcard_clk";
function = "sdcard";
input-enable;
bias-pull-up;
};
};
sd_all_pins:sd_all_pins{
mux {
groups = "sdcard_d0",
"sdcard_d1",
"sdcard_d2",
"sdcard_d3",
"sdcard_cmd",
"sdcard_clk";
function = "sdcard";
input-enable;
bias-pull-up;
};
};

View File

@@ -209,6 +209,7 @@ CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA=y
CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE=y
CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR=y
CONFIG_AMLOGIC_HDMITX=y
CONFIG_AMLOGIC_MMC=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -287,6 +288,9 @@ CONFIG_USB_ISP1301=y
CONFIG_USB_GADGET=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y

View File

@@ -51,5 +51,7 @@ source "drivers/amlogic/pwm/Kconfig"
source "drivers/amlogic/media/Kconfig"
source "drivers/amlogic/mmc/Kconfig"
endmenu
endif

View File

@@ -47,3 +47,6 @@ obj-$(CONFIG_AMLOGIC_PWM) += pwm/
obj-$(CONFIG_AMLOGIC_MEDIA_ENABLE) += media/
obj-$(CONFIG_AMLOGIC_MMC) += mmc/

View File

@@ -0,0 +1,19 @@
# Amlogic MMC driver
comment "MMC/SD/SDIO Host Controller Drivers"
menu "Multimedia Card support"
config AMLOGIC_MMC
bool "Amlogic Multimedia Card support"
depends on MMC
depends on MMC_BLOCK
depends on MMC_BLOCK_BOUNCE
default n
help
This selects support for the Amlogic SD/MMC Host Controller
found on the S912/GXM 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

View File

@@ -0,0 +1,5 @@
#
# Amlogic MMC specific Makefile
#
obj-$(CONFIG_AMLOGIC_MMC) += amlsd.o amlsd_of.o emmc_partitions.o aml_sd_emmc.o

File diff suppressed because it is too large Load Diff

542
drivers/amlogic/mmc/amlsd.c Normal file
View File

@@ -0,0 +1,542 @@
/*
* drivers/amlogic/mmc/amlsd.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sd.h>
#include <linux/mmc/card.h>
#include <linux/slab.h>
#include <linux/amlogic/sd.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/cpu_version.h>
#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>
const u8 tuning_blk_pattern_4bit[64] = {
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
};
const u8 tuning_blk_pattern_8bit[128] = {
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};
void aml_mmc_ver_msg_show(void)
{
static bool one_time_flag;
if (!one_time_flag) {
pr_info("mmc driver version: %d.%02d, %s\n",
AML_MMC_MAJOR_VERSION, AML_MMC_MINOR_VERSION,
AML_MMC_VER_MESSAGE);
one_time_flag = true;
}
}
static int aml_is_card_insert(struct amlsd_platform *pdata)
{
int ret = 0, in_count = 0, out_count = 0, i;
if (pdata->gpio_cd) {
mdelay(pdata->card_in_delay);
for (i = 0; i < 200; i++) {
ret = gpio_get_value(pdata->gpio_cd);
if (ret)
out_count++;
in_count++;
if ((out_count > 100) || (in_count > 100))
break;
}
if (out_count > 100)
ret = 1;
else if (in_count > 100)
ret = 0;
}
sdio_err("card %s\n", ret?"OUT":"IN");
if (!pdata->gpio_cd_level)
ret = !ret; /* reverse, so ---- 0: no inserted 1: inserted */
return ret;
}
int aml_sd_uart_detect(struct amlsd_host *host)
{
struct amlsd_platform *pdata = host->pdata;
if (aml_is_card_insert(pdata)) {
if (pdata->is_in)
return 1;
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;
} else {
if (!pdata->is_in)
return 1;
pdata->is_in = false;
pr_info("card out\n");
pdata->is_tuned = false;
if (host->mmc && host->mmc->card)
mmc_card_set_removed(host->mmc->card);
/* switch to 3.3V */
aml_sd_voltage_switch(host->mmc,
MMC_SIGNAL_VOLTAGE_330);
if (pdata->caps & MMC_CAP_4_BIT_DATA)
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
}
return 0;
}
static int card_dealed;
irqreturn_t aml_irq_cd_thread(int irq, void *data)
{
struct amlsd_host *host = (struct amlsd_host *)data;
struct amlsd_platform *pdata = host->pdata;
int ret = 0;
mutex_lock(&pdata->in_out_lock);
if (card_dealed == 1) {
card_dealed = 0;
mutex_unlock(&pdata->in_out_lock);
return IRQ_HANDLED;
}
ret = aml_sd_uart_detect(host);
if (ret == 1) {/* the same as the last*/
mutex_unlock(&pdata->in_out_lock);
return IRQ_HANDLED;
}
card_dealed = 1;
if ((pdata->is_in == 0) && aml_card_type_non_sdio(pdata))
host->init_flag = 0;
mutex_unlock(&pdata->in_out_lock);
/* mdelay(500); */
if (pdata->is_in)
mmc_detect_change(host->mmc, msecs_to_jiffies(100));
else
mmc_detect_change(host->mmc, msecs_to_jiffies(0));
card_dealed = 0;
return IRQ_HANDLED;
}
irqreturn_t aml_sd_irq_cd(int irq, void *dev_id)
{
/* pr_info("cd dev_id %x\n", (unsigned)dev_id); */
return IRQ_WAKE_THREAD;
}
static int aml_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct amlsd_host *host = mmc_priv(mmc);
unsigned long flags;
spin_lock_irqsave(&host->mrq_lock, flags);
mrq->cmd->error = -EINVAL;
spin_unlock_irqrestore(&host->mrq_lock, flags);
mmc_request_done(mmc, mrq);
return -EINVAL;
}
static int aml_rpmb_cmd_invalid(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct amlsd_host *host = mmc_priv(mmc);
unsigned long flags;
spin_lock_irqsave(&host->mrq_lock, flags);
host->xfer_step = XFER_FINISHED;
host->mrq = NULL;
host->status = HOST_INVALID;
spin_unlock_irqrestore(&host->mrq_lock, flags);
mrq->data->bytes_xfered = mrq->data->blksz*mrq->data->blocks;
mmc_request_done(mmc, mrq);
return -EINVAL;
}
int aml_check_unsupport_cmd(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct amlsd_host *host = mmc_priv(mmc);
struct amlsd_platform *pdata = host->pdata;
u32 opcode, arg;
opcode = mrq->cmd->opcode;
arg = mrq->cmd->arg;
/* CMD3 means the first time initialized flow is running */
if (opcode == 3)
mmc->first_init_flag = false;
if (aml_card_type_mmc(pdata)) {
if (opcode == 6) {
if (arg == 0x3B30301)
pdata->rmpb_cmd_flag = 1;
else
pdata->rmpb_cmd_flag = 0;
}
if (pdata->rmpb_cmd_flag && (!pdata->rpmb_valid_command)) {
if ((opcode == 18)
|| (opcode == 25))
return aml_rpmb_cmd_invalid(mmc, mrq);
}
if (pdata->rmpb_cmd_flag && (opcode == 23))
pdata->rpmb_valid_command = 1;
else
pdata->rpmb_valid_command = 0;
}
if (mmc->caps & MMC_CAP_NONREMOVABLE) { /* nonremovable device */
if (mmc->first_init_flag) { /* init for the first time */
/* for 8189ETV needs ssdio reset when starts */
if (aml_card_type_sdio(pdata)) {
/* if (opcode == SD_IO_RW_DIRECT
* || opcode == SD_IO_RW_EXTENDED
* || opcode == SD_SEND_IF_COND)
* return aml_cmd_invalid(mmc, mrq);
*/
return 0;
} else if (aml_card_type_mmc(pdata)) {
if (opcode == SD_IO_SEND_OP_COND
|| opcode == SD_IO_RW_DIRECT
|| opcode == SD_IO_RW_EXTENDED
|| opcode == SD_SEND_IF_COND
|| opcode == MMC_APP_CMD)
return aml_cmd_invalid(mmc, mrq);
} else if (aml_card_type_sd(pdata)
|| aml_card_type_non_sdio(pdata)) {
if (opcode == SD_IO_SEND_OP_COND
|| opcode == SD_IO_RW_DIRECT
|| opcode == SD_IO_RW_EXTENDED)
return aml_cmd_invalid(mmc, mrq);
}
}
} else { /* removable device */
/* filter cmd 5/52/53 for a non-sdio device */
if (!aml_card_type_sdio(pdata)
&& !aml_card_type_unknown(pdata)) {
if (opcode == SD_IO_SEND_OP_COND
|| opcode == SD_IO_RW_DIRECT
|| opcode == SD_IO_RW_EXTENDED)
return aml_cmd_invalid(mmc, mrq);
}
}
return 0;
}
int aml_sd_voltage_switch(struct mmc_host *mmc, char signal_voltage)
{
struct amlsd_host *host = mmc_priv(mmc);
struct amlsd_platform *pdata = host->pdata;
int ret = 0;
/* voltage is the same, return directly */
if (!aml_card_type_non_sdio(pdata)
|| (pdata->signal_voltage == signal_voltage)) {
if (aml_card_type_sdio(pdata))
host->sd_sdio_switch_volat_done = 1;
return 0;
}
if (pdata->vol_switch) {
if (pdata->signal_voltage == 0xff) {
gpio_free(pdata->vol_switch);
ret = gpio_request_one(pdata->vol_switch,
GPIOF_OUT_INIT_HIGH, MODULE_NAME);
if (ret) {
pr_err("%s [%d] request error\n",
__func__, __LINE__);
return -EINVAL;
}
}
if (signal_voltage == MMC_SIGNAL_VOLTAGE_180)
ret = gpio_direction_output(pdata->vol_switch,
pdata->vol_switch_18);
else
ret = gpio_direction_output(pdata->vol_switch,
(!pdata->vol_switch_18));
CHECK_RET(ret);
if (!ret)
pdata->signal_voltage = signal_voltage;
} else
return -EINVAL;
host->sd_sdio_switch_volat_done = 1;
return 0;
}
/* boot9 here */
void aml_emmc_hw_reset(struct mmc_host *mmc)
{
struct amlsd_host *host = mmc_priv(mmc);
struct amlsd_platform *pdata = host->pdata;
u32 ret;
if (!aml_card_type_mmc(pdata) || !pdata->hw_reset)
return;
/* boot_9 used as eMMC hw_rst pin here. */
gpio_free(pdata->hw_reset);
ret = gpio_request_one(pdata->hw_reset,
GPIOF_OUT_INIT_HIGH, MODULE_NAME);
CHECK_RET(ret);
if (ret) {
pr_err("%s [%d] request error\n",
__func__, __LINE__);
return;
}
ret = gpio_direction_output(pdata->hw_reset, 0);
CHECK_RET(ret);
if (ret) {
pr_err("%s [%d] output high error\n",
__func__, __LINE__);
return;
}
mdelay(2);
ret = gpio_direction_output(pdata->hw_reset, 1);
CHECK_RET(ret);
if (ret) {
pr_err("%s [%d] output high error\n",
__func__, __LINE__);
return;
}
mdelay(2);
}
static void sdio_rescan(struct mmc_host *mmc)
{
int ret;
mmc->rescan_entered = 0;
/* mmc->host_rescan_disable = false;*/
mmc_detect_change(mmc, 0);
/* start the delayed_work */
ret = flush_work(&(mmc->detect.work));
/* wait for the delayed_work to finish */
if (!ret)
pr_info("Error: delayed_work mmc_rescan() already idle!\n");
}
void sdio_reinit(void)
{
if (sdio_host) {
if (sdio_host->card)
sdio_reset_comm(sdio_host->card);
else
sdio_rescan(sdio_host);
} else {
pr_info("Error: sdio_host is NULL\n");
}
pr_info("[%s] finish\n", __func__);
}
EXPORT_SYMBOL(sdio_reinit);
void of_amlsd_irq_init(struct amlsd_platform *pdata)
{
if (aml_card_type_non_sdio(pdata))
pdata->irq_cd = gpio_to_irq(pdata->gpio_cd);
pr_info("sd irq num = %d\n", pdata->irq_cd);
}
int of_amlsd_init(struct amlsd_platform *pdata)
{
int ret;
WARN_ON(!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);
CHECK_RET(ret);
}
/* if(pdata->port == MESON_SDIO_PORT_A) */
/* wifi_setup_dt(); */
return 0;
}
void aml_devm_pinctrl_put(struct amlsd_host *host)
{
if (host->pinctrl) {
devm_pinctrl_put(host->pinctrl);
host->pinctrl = NULL;
host->pinctrl_name[0] = '\0';
/* sdio_err("Put Pinctrl\n"); */
}
}
static struct pinctrl * __must_check aml_devm_pinctrl_get_select(
struct amlsd_host *host, const char *name)
{
struct pinctrl *p = host->pinctrl;
struct pinctrl_state *s;
int ret;
if (!p) {
p = devm_pinctrl_get(&host->pdev->dev);
if (IS_ERR(p))
return p;
host->pinctrl = p;
/* sdio_err("switch %s\n", name); */
}
s = pinctrl_lookup_state(p, name);
if (IS_ERR(s)) {
sdio_err("lookup %s fail\n", name);
devm_pinctrl_put(p);
return ERR_CAST(s);
}
ret = pinctrl_select_state(p, s);
if (ret < 0) {
sdio_err("select %s fail\n", name);
devm_pinctrl_put(p);
return ERR_PTR(ret);
}
return p;
}
void of_amlsd_xfer_pre(struct mmc_host *mmc)
{
struct amlsd_host *host = mmc_priv(mmc);
struct amlsd_platform *pdata = host->pdata;
char pinctrl[30];
char *p = pinctrl;
int i, size = 0;
struct pinctrl *ppin;
size = sizeof(pinctrl);
if (mmc->ios.chip_select == MMC_CS_DONTCARE) {
if ((mmc->caps & MMC_CAP_4_BIT_DATA)
|| (strcmp(pdata->pinname, "sd"))
|| (mmc->caps & MMC_CAP_8_BIT_DATA))
aml_snprint(&p, &size, "%s_all_pins", pdata->pinname);
} else { /* MMC_CS_HIGH */
if (pdata->is_sduart && (!strcmp(pdata->pinname, "sd"))) {
aml_snprint(&p, &size,
"%s_clk_cmd_uart_pins", pdata->pinname);
} else {
aml_snprint(&p, &size,
"%s_clk_cmd_pins", pdata->pinname);
}
}
/* if pinmux setting is changed (pinctrl_name is different) */
if (strncmp(host->pinctrl_name, pinctrl,
sizeof(host->pinctrl_name))) {
if (strlcpy(host->pinctrl_name, pinctrl,
sizeof(host->pinctrl_name))
>= sizeof(host->pinctrl_name)) {
sdio_err("Pinctrl name is too long!\n");
return;
}
for (i = 0; i < 100; i++) {
mutex_lock(&host->pinmux_lock);
ppin = aml_devm_pinctrl_get_select(host, pinctrl);
mutex_unlock(&host->pinmux_lock);
if (!IS_ERR(ppin)) {
/* pdata->host->pinctrl = ppin; */
break;
}
/* else -> aml_irq_cdin_thread()
*should be using one of the GPIO of card,
* then we should wait here until the GPIO is free,
* otherwise something must be wrong.
*/
mdelay(1);
}
if (i == 100)
sdhc_err("CMD%d: get pinctrl %s fail.\n",
host->opcode, pinctrl);
}
}
void of_amlsd_xfer_post(struct mmc_host *mmc)
{
}
int of_amlsd_ro(struct amlsd_platform *pdata)
{
int ret = 0; /* 0--read&write, 1--read only */
if (pdata->gpio_ro)
ret = gpio_get_value(pdata->gpio_ro);
/* sdio_err("read-only?--%s\n", ret?"YES":"NO"); */
return ret;
}
void aml_snprint (char **pp, int *left_size, const char *fmt, ...)
{
va_list args;
char *p = *pp;
int size;
if (*left_size <= 1) {
sdhc_err("buf is full\n");
return;
}
va_start(args, fmt);
size = vsnprintf(p, *left_size, fmt, args);
va_end(args);
*pp += size;
*left_size -= size;
}

View File

@@ -0,0 +1,210 @@
/*
* drivers/amlogic/mmc/amlsd_of.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
#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[] = {
SD_CAPS(MMC_CAP_4_BIT_DATA, "MMC_CAP_4_BIT_DATA"),
SD_CAPS(MMC_CAP_MMC_HIGHSPEED, "MMC_CAP_MMC_HIGHSPEED"),
SD_CAPS(MMC_CAP_SD_HIGHSPEED, "MMC_CAP_SD_HIGHSPEED"),
SD_CAPS(MMC_CAP_SDIO_IRQ, "MMC_CAP_SDIO_IRQ"),
SD_CAPS(MMC_CAP_SPI, "MMC_CAP_SPI"),
SD_CAPS(MMC_CAP_NEEDS_POLL, "MMC_CAP_NEEDS_POLL"),
SD_CAPS(MMC_CAP_8_BIT_DATA, "MMC_CAP_8_BIT_DATA"),
SD_CAPS(MMC_CAP_NONREMOVABLE, "MMC_CAP_NONREMOVABLE"),
SD_CAPS(MMC_CAP_WAIT_WHILE_BUSY, "MMC_CAP_WAIT_WHILE_BUSY"),
SD_CAPS(MMC_CAP_ERASE, "MMC_CAP_ERASE"),
SD_CAPS(MMC_CAP_1_8V_DDR, "MMC_CAP_1_8V_DDR"),
SD_CAPS(MMC_CAP_1_2V_DDR, "MMC_CAP_1_2V_DDR"),
SD_CAPS(MMC_CAP_POWER_OFF_CARD, "MMC_CAP_POWER_OFF_CARD"),
SD_CAPS(MMC_CAP_BUS_WIDTH_TEST, "MMC_CAP_BUS_WIDTH_TEST"),
SD_CAPS(MMC_CAP_UHS_SDR12, "MMC_CAP_UHS_SDR12"),
SD_CAPS(MMC_CAP_UHS_SDR25, "MMC_CAP_UHS_SDR25"),
SD_CAPS(MMC_CAP_UHS_SDR50, "MMC_CAP_UHS_SDR50"),
SD_CAPS(MMC_CAP_UHS_SDR104, "MMC_CAP_UHS_SDR104"),
SD_CAPS(MMC_CAP_UHS_DDR50, "MMC_CAP_UHS_DDR50"),
SD_CAPS(MMC_CAP_DRIVER_TYPE_A, "MMC_CAP_DRIVER_TYPE_A"),
SD_CAPS(MMC_CAP_DRIVER_TYPE_C, "MMC_CAP_DRIVER_TYPE_C"),
SD_CAPS(MMC_CAP_DRIVER_TYPE_D, "MMC_CAP_DRIVER_TYPE_D"),
SD_CAPS(MMC_CAP_CMD23, "MMC_CAP_CMD23"),
SD_CAPS(MMC_CAP_HW_RESET, "MMC_CAP_HW_RESET"),
SD_CAPS(MMC_CAP_AGGRESSIVE_PM, "MMC_CAP_AGGRESSIVE_PM"),
SD_CAPS(MMC_PM_KEEP_POWER, "MMC_PM_KEEP_POWER"),
};
static int amlsd_get_host_caps(struct device_node *of_node,
struct amlsd_platform *pdata)
{
const char *str_caps;
struct property *prop;
u32 i, caps = 0;
of_property_for_each_string(of_node, "caps", prop, str_caps) {
for (i = 0; i < ARRAY_SIZE(host_caps); i++) {
if (!strcasecmp(host_caps[i].name, str_caps))
caps |= host_caps[i].caps;
}
};
if (caps & MMC_CAP_8_BIT_DATA)
caps |= MMC_CAP_4_BIT_DATA;
pdata->caps = caps;
pr_info("%s:pdata->caps = %x\n", pdata->pinname, pdata->caps);
return 0;
}
static const struct sd_caps host_caps2[] = {
SD_CAPS(MMC_CAP2_BOOTPART_NOACC, "MMC_CAP2_BOOTPART_NOACC"),
/*SD_CAPS(MMC_CAP2_CACHE_CTRL, "MMC_CAP2_CACHE_CTRL"),*/
/* SD_CAPS(MMC_CAP2_POWEROFF_NOTIFY, "MMC_CAP2_POWEROFF_NOTIFY"), */
SD_CAPS(MMC_CAP2_NO_MULTI_READ, "MMC_CAP2_NO_MULTI_READ"),
/*SD_CAPS(MMC_CAP2_NO_SLEEP_CMD, "MMC_CAP2_NO_SLEEP_CMD"),*/
SD_CAPS(MMC_CAP2_HS200_1_8V_SDR, "MMC_CAP2_HS200_1_8V_SDR"),
SD_CAPS(MMC_CAP2_HS200_1_2V_SDR, "MMC_CAP2_HS200_1_2V_SDR"),
SD_CAPS(MMC_CAP2_HS200, "MMC_CAP2_HS200"),
SD_CAPS(MMC_CAP2_HS400_1_8V, "MMC_CAP2_HS400_1_8V"),
SD_CAPS(MMC_CAP2_HS400_1_2V, "MMC_CAP2_HS400_1_2V"),
SD_CAPS(MMC_CAP2_HS400, "MMC_CAP2_HS400"),
/*SD_CAPS(MMC_CAP2_BROKEN_VOLTAGE, "MMC_CAP2_BROKEN_VOLTAGE"),*/
/* SD_CAPS(MMC_CAP2_DETECT_ON_ERR, "MMC_CAP2_DETECT_ON_ERR"), */
SD_CAPS(MMC_CAP2_HC_ERASE_SZ, "MMC_CAP2_HC_ERASE_SZ"),
SD_CAPS(MMC_CAP2_CD_ACTIVE_HIGH, "MMC_CAP2_CD_ACTIVE_HIGH"),
SD_CAPS(MMC_CAP2_RO_ACTIVE_HIGH, "MMC_CAP2_RO_ACTIVE_HIGH"),
};
static int amlsd_get_host_caps2(struct device_node *of_node,
struct amlsd_platform *pdata)
{
const char *str_caps;
struct property *prop;
u32 i, caps = 0;
of_property_for_each_string(of_node, "caps2", prop, str_caps) {
for (i = 0; i < ARRAY_SIZE(host_caps2); i++) {
if (!strcasecmp(host_caps2[i].name, str_caps))
caps |= host_caps2[i].caps;
}
};
pdata->caps2 = caps;
pr_info("%s:pdata->caps2 = %x\n", pdata->pinname, pdata->caps2);
return 0;
}
int amlsd_get_platform_data(struct amlsd_platform *pdata,
struct mmc_host *mmc, u32 index)
{
struct device_node *of_node;
struct device_node *child;
u32 i, prop;
const char *str = "none";
if (!mmc->parent || !mmc->parent->of_node)
return 0;
of_node = mmc->parent->of_node;
if (of_node) {
child = of_node->child;
WARN_ON(!child);
WARN_ON(index >= MMC_MAX_DEVICE);
for (i = 0; i < index; i++)
child = child->sibling;
if (!child)
return -EINVAL;
/* amlsd_init_pins_input(child, pdata);*/
SD_PARSE_U32_PROP_HEX(child, "port",
prop, pdata->port);
SD_PARSE_U32_PROP_HEX(child, "ocr_avail",
prop, pdata->ocr_avail);
WARN_ON(!pdata->ocr_avail);
SD_PARSE_U32_PROP_DEC(child, "f_min",
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_GPIO_NUM_PROP(child, "gpio_cd",
str, pdata->gpio_cd);
SD_PARSE_GPIO_NUM_PROP(child, "gpio_ro",
str, pdata->gpio_ro);
SD_PARSE_GPIO_NUM_PROP(child, "vol_switch",
str, pdata->vol_switch);
SD_PARSE_U32_PROP_HEX(child, "power_level",
prop, pdata->power_level);
SD_PARSE_U32_PROP_DEC(child, "gpio_cd_level",
prop, pdata->gpio_cd_level);
SD_PARSE_STRING_PROP(child, "pinname",
str, pdata->pinname);
SD_PARSE_U32_PROP_DEC(child, "auto_clk_close",
prop, pdata->auto_clk_close);
SD_PARSE_U32_PROP_DEC(child, "vol_switch_18",
prop, pdata->vol_switch_18);
SD_PARSE_U32_PROP_DEC(child, "vol_switch_delay",
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);
}
SD_PARSE_GPIO_NUM_PROP(child, "hw_reset",
str, pdata->hw_reset);
SD_PARSE_GPIO_NUM_PROP(child, "gpio_dat3",
str, pdata->gpio_dat3);
pdata->xfer_pre = of_amlsd_xfer_pre;
pdata->xfer_post = of_amlsd_xfer_post;
amlsd_get_host_caps(child, pdata);
amlsd_get_host_caps2(child, pdata);
pdata->port_init = of_amlsd_init;
pdata->irq_init = of_amlsd_irq_init;
pdata->ro = of_amlsd_ro;
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,9 @@
#include "queue.h"
#include "block.h"
#ifdef CONFIG_AMLOGIC_MMC
#include <linux/mmc/emmc_partitions.h>
#endif
MODULE_ALIAS("mmc:block");
#ifdef MODULE_PARAM_PREFIX
@@ -2607,6 +2610,11 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(md))
goto out;
#ifdef CONFIG_AMLOGIC_MMC
/* amlogic add emmc partitions ops */
aml_emmc_partition_ops(card, md->disk);
#endif
list_for_each_entry(part_md, &md->part, part) {
if (mmc_add_disk(part_md))
goto out;

View File

@@ -284,6 +284,10 @@ int mmc_add_card(struct mmc_card *card)
int ret;
const char *type;
const char *uhs_bus_speed_mode = "";
#ifdef CONFIG_AMLOGIC_MMC
int width;
struct mmc_host *mmc = card->host;
#endif
static const char *const uhs_speeds[] = {
[UHS_SDR12_BUS_SPEED] = "SDR12 ",
[UHS_SDR25_BUS_SPEED] = "SDR25 ",
@@ -332,6 +336,23 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_ddr52(card) ? "DDR " : "",
type);
} else {
#ifdef CONFIG_AMLOGIC_MMC
switch (mmc->ios.bus_width) {
case MMC_BUS_WIDTH_1:
width = 1;
break;
case MMC_BUS_WIDTH_4:
width = 4;
break;
case MMC_BUS_WIDTH_8:
width = 8;
break;
default:
width = -1;
break;
}
#endif
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_uhs(card) ? "ultra high speed " :
@@ -341,6 +362,12 @@ int mmc_add_card(struct mmc_card *card)
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
mmc_card_ddr52(card) ? "DDR " : "",
uhs_bus_speed_mode, type, card->rca);
#ifdef CONFIG_AMLOGIC_MMC
pr_info("%s: clock %d, %u-bit-bus-width\n ",
mmc_hostname(card->host),
mmc->actual_clock, width);
#endif
}
#ifdef CONFIG_DEBUG_FS

View File

@@ -2635,6 +2635,9 @@ EXPORT_SYMBOL(mmc_hw_reset);
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
#ifdef CONFIG_AMLOGIC_MMC
host->first_init_flag = 1;
#endif
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",

View File

@@ -1159,8 +1159,29 @@ static int mmc_select_hs400(struct mmc_card *card)
}
/* Switch card to HS400 */
#ifdef CONFIG_AMLOGIC_MMC
if (card->ext_csd.raw_driver_strength & (1 << 1)) {
val =
(0x1 << EXT_CSD_DRV_STR_SHIFT)
| EXT_CSD_TIMING_HS400;
pr_info("%s: support driver strength type 1\n",
mmc_hostname(host));
} else if (card->ext_csd.raw_driver_strength & (1 << 4)) {
val =
(0x4 << EXT_CSD_DRV_STR_SHIFT)
| EXT_CSD_TIMING_HS400;
pr_info("%s: support driver strength type 4\n",
mmc_hostname(host));
} else {
val = EXT_CSD_TIMING_HS400;
pr_info("%s: no support driver strength type 1 and 4\n",
mmc_hostname(host));
}
#else
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
#endif
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
@@ -1560,6 +1581,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
}
#ifdef CONFIG_AMLOGIC_MMC
host->first_init_flag = 0;
#endif
if (!oldcard) {
/*
* Fetch CSD from card.

View File

@@ -21,6 +21,7 @@
#include "core.h"
#include "bus.h"
#include "host.h"
#include "sd.h"
#include "sdio_bus.h"
#include "mmc_ops.h"
@@ -1172,4 +1173,43 @@ err:
return err;
}
#ifdef CONFIG_AMLOGIC_MMC
int sdio_reset_comm(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u32 ocr;
u32 rocr;
int err;
pr_info("%s():\n", __func__);
mmc_claim_host(host);
mmc_retune_disable(host);
mmc_go_idle(host);
mmc_set_clock(host, host->f_min);
err = mmc_send_io_op_cond(host, 0, &ocr);
if (err)
goto err;
rocr = mmc_select_voltage(host, ocr);
if (!rocr) {
err = -EINVAL;
goto err;
}
err = mmc_sdio_init_card(host, rocr, card, 0);
if (err)
goto err;
mmc_release_host(host);
return 0;
err:
pr_err("%s: Error resetting SDIO communications (%d)\n",
mmc_hostname(host), err);
mmc_release_host(host);
return err;
}
EXPORT_SYMBOL(sdio_reset_comm);
#endif

View File

@@ -0,0 +1,229 @@
/*
* include/linux/amlogic/amlsd.h
*
* Copyright (C) 2016 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef AMLSD_H
#define AMLSD_H
#include <linux/of_gpio.h>
#define AML_MMC_MAJOR_VERSION 1
#define AML_MMC_MINOR_VERSION 07
#define AML_MMC_VERSION \
((AML_MMC_MAJOR_VERSION << 8) | AML_MMC_MINOR_VERSION)
#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 int sd_emmc_debug;
extern const u8 tuning_blk_pattern_4bit[64];
extern const u8 tuning_blk_pattern_8bit[128];
#define DEBUG_SD_OF 1
/* #define DEBUG_SD_OF 0 */
#define MODULE_NAME "amlsd"
#if 0
#define A0_GP_CFG0 (0xc8100240)
#define A0_GP_CFG2 (0xc8100248)
#define STORAGE_DEV_NOSET (0)
#define STORAGE_DEV_EMMC (1)
#define STORAGE_DEV_NAND (2)
#define STORAGE_DEV_SPI (3)
#define STORAGE_DEV_SDCARD (4)
#define STORAGE_DEV_USB (5)
#define LDO4DAC_REG_ADDR 0x4f
#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)
#define AMLSD_DBG_REG (1<<3)
#define AMLSD_DBG_RD_TIME (1<<4)
#define AMLSD_DBG_WR_TIME (1<<5)
#define AMLSD_DBG_BUSY_TIME (1<<6)
#define AMLSD_DBG_RD_DATA (1<<7)
#define AMLSD_DBG_WR_DATA (1<<8)
#define AMLSD_DBG_IOS (1<<9)
#define AMLSD_DBG_IRQ (1<<10)
#define AMLSD_DBG_CLKC (1<<11)
#define AMLSD_DBG_TUNING (1<<12)
#define DETECT_CARD_IN 1
#define DETECT_CARD_OUT 2
#define DETECT_CARD_JTAG_IN 3
#define DETECT_CARD_JTAG_OUT 4
#define EMMC_DAT3_PINMUX_CLR 0
#define EMMC_DAT3_PINMUX_SET 1
#define CHECK_RET(ret) { \
if (ret) \
pr_info("[%s] gpio op failed(%d) at line %d\n",\
__func__, ret, __LINE__); \
}
#define sdhc_dbg(dbg_level, fmt, args...) do {\
if (dbg_level & sdhc_debug) \
pr_info("[%s]" fmt, __func__, ##args); \
} while (0)
#define sdhc_err(fmt, args...) \
pr_info("[%s] " fmt, __func__, ##args)
#define sdio_dbg(dbg_level, fmt, args...) do {\
if (dbg_level & sdio_debug) \
pr_info("[%s]" fmt, __func__, ##args); \
} while (0)
#define sdio_err(fmt, args...) \
pr_info("[%s] " fmt, __func__, ##args)
#define sd_emmc_dbg(dbg_level, fmt, args...) do {\
if (dbg_level & sd_emmc_debug) \
pr_info("[%s]" fmt, __func__, ##args); \
} while (0)
#define sd_emmc_err(fmt, args...) \
pr_warn("[%s] " fmt, __func__, ##args)
#define SD_PARSE_U32_PROP_HEX(node, prop_name, prop, value) do { \
if (!of_property_read_u32(node, prop_name, &prop)) {\
value = prop;\
prop = 0;\
if (DEBUG_SD_OF) { \
pr_info("get property:%25s, value:0x%08x\n", \
prop_name, (unsigned int)value); \
} \
} \
} while (0)
#define SD_PARSE_U32_PROP_DEC(node, prop_name, prop, value) do { \
if (!of_property_read_u32(node, prop_name, &prop)) {\
value = prop;\
prop = 0;\
if (DEBUG_SD_OF) { \
pr_info("get property:%25s, value:%d\n", \
prop_name, (unsigned int)value); \
} \
} \
} while (0)
#define SD_PARSE_GPIO_NUM_PROP(node, prop_name, str, gpio_pin) {\
if (!of_property_read_string(node, prop_name, &str)) {\
gpio_pin = \
of_get_named_gpio(node, \
prop_name, 0);\
if (DEBUG_SD_OF) { \
pr_info("get property:%25s, str:%s\n",\
prop_name, str);\
} \
} \
}
#define SD_PARSE_STRING_PROP(node, prop_name, str, prop) {\
if (!of_property_read_string(node, prop_name, &str)) {\
strcpy(prop, str);\
if (DEBUG_SD_OF) {\
pr_info("get property:%25s, str:%s\n",\
prop_name, prop); \
} \
} \
}
#define SD_CAPS(a, b) { .caps = a, .name = b }
struct sd_caps {
unsigned int caps;
const char *name;
};
void aml_mmc_ver_msg_show(void);
extern int sdio_reset_comm(struct mmc_card *card);
#if 0
extern int storage_flag;
extern void aml_debug_print_buf(char *buf, int size);
extern int aml_buf_verify(int *buf, int blocks, int lba);
extern void aml_sdhc_init_debugfs(struct mmc_host *mmc);
void aml_sdhc_print_reg_(u32 *buf);
extern void aml_sdhc_print_reg(struct amlsd_host *host);
extern void aml_sdio_init_debugfs(struct mmc_host *mmc);
extern void aml_sd_emmc_init_debugfs(struct mmc_host *mmc);
extern void aml_sdio_print_reg(struct amlsd_host *host);
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);
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,
struct mmc_host *mmc, u32 index);
void of_amlsd_irq_init(struct amlsd_platform *pdata);
int of_amlsd_init(struct amlsd_platform *pdata);
#if 0
int amlsd_get_reg_base(struct platform_device *pdev,
struct amlsd_host *host);
/* int of_amlsd_detect(struct amlsd_platform* pdata); */
void of_amlsd_pwr_prepare(struct amlsd_platform *pdata);
void of_amlsd_pwr_on(struct amlsd_platform *pdata);
void of_amlsd_pwr_off(struct amlsd_platform *pdata);
int aml_sd_uart_detect(struct amlsd_platform *pdata);
void aml_sd_uart_detect_clr(struct amlsd_platform *pdata);
#endif
void of_amlsd_xfer_pre(struct mmc_host *mmc);
void of_amlsd_xfer_post(struct mmc_host *mmc);
irqreturn_t aml_sd_irq_cd(int irq, void *dev_id);
irqreturn_t aml_irq_cd_thread(int irq, void *data);
#if 0
void aml_sduart_pre(struct amlsd_platform *pdata);
/* chip select high */
void aml_cs_high(struct amlsd_platform *pdata);
/* chip select don't care */
void aml_cs_dont_care(struct amlsd_platform *pdata);
/* is eMMC/tSD exist */
bool is_emmc_exist(struct amlsd_host *host);
void aml_devm_pinctrl_put(struct amlsd_host *host);
/* void of_init_pins (struct amlsd_platform* pdata); */
void aml_dbg_print_pinmux(void);
#ifdef CONFIG_MMC_AML_DEBUG
void aml_dbg_verify_pull_up(struct amlsd_platform *pdata);
int aml_dbg_verify_pinmux(struct amlsd_platform *pdata);
#endif
#endif
void aml_snprint (char **pp, int *left_size, const char *fmt, ...);
int of_amlsd_ro(struct amlsd_platform *pdata);
int aml_sd_voltage_switch(struct mmc_host *mmc, char signal_voltage);
int aml_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios);
int aml_check_unsupport_cmd(struct mmc_host *mmc, struct mmc_request *mrq);
extern void aml_emmc_hw_reset(struct mmc_host *mmc);
#endif

1507
include/linux/amlogic/sd.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
#ifndef _EMMC_PARTITIONS_H
#define _EMMC_PARTITIONS_H
#include<linux/genhd.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/core.h>
/* #include <mach/register.h> */
/* #include <mach/am_regs.h> */
#define CONFIG_DTB_SIZE (256*1024U)
#define STORE_CODE 1
#define STORE_CACHE (1<<1)
#define STORE_DATA (1<<2)
#define MAX_PART_NAME_LEN 16
#define MAX_MMC_PART_NUM 32
/* MMC Partition Table */
#define MMC_PARTITIONS_MAGIC "MPT"
#define MMC_RESERVED_NAME "reserved"
#define SZ_1M 0x00100000
/* the size of bootloader partition */
#define MMC_BOOT_PARTITION_SIZE (4*SZ_1M)
/* the size of reserve space behind bootloader partition */
#define MMC_BOOT_PARTITION_RESERVED (32*SZ_1M)
#define RESULT_OK 0
#define RESULT_FAIL 1
#define RESULT_UNSUP_HOST 2
#define RESULT_UNSUP_CARD 3
struct partitions {
/* identifier string */
char name[MAX_PART_NAME_LEN];
/* partition size, byte unit */
uint64_t size;
/* offset within the master space, byte unit */
uint64_t offset;
/* master flags to mask out for this partition */
unsigned mask_flags;
};
struct mmc_partitions_fmt {
char magic[4];
unsigned char version[12];
int part_num;
int checksum;
struct partitions partitions[MAX_MMC_PART_NUM];
};
/*#ifdef CONFIG_MMC_AML*/
int aml_emmc_partition_ops(struct mmc_card *card, struct gendisk *disk);
/*
*#else
*static inline int aml_emmc_partition_ops(struct mmc_card *card,
* struct gendisk *disk)
*{
* return -1;
*}
*#endif
*/
unsigned int mmc_capacity(struct mmc_card *card);
int mmc_read_internal(struct mmc_card *card,
unsigned dev_addr, unsigned blocks, void *buf);
int mmc_write_internal(struct mmc_card *card,
unsigned dev_addr, unsigned blocks, void *buf);
int get_reserve_partition_off_from_tbl(void);
int get_reserve_partition_off(struct mmc_card *card);/* byte unit */
#endif
extern struct mmc_partitions_fmt *pt_fmt;

View File

@@ -225,6 +225,9 @@ struct mmc_host {
unsigned int f_min;
unsigned int f_max;
unsigned int f_init;
#ifdef CONFIG_AMLOGIC_MMC
u8 first_init_flag;
#endif
u32 ocr_avail;
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd; /* SD-specific OCR */
@@ -287,8 +290,11 @@ struct mmc_host {
u32 caps2; /* More host capabilities */
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
#define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
#define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */
#ifdef CONFIG_AMLOGIC_MMC
#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
#endif
#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \