From: zhangguijiang zhangguijiang@huawei.com
ascend inclusion category: feature feature: Ascend emmc adaption bugzilla: https://gitee.com/openeuler/kernel/issues/I4F4LL CVE: NA
--------------------
To identify Ascend HiSilicon emmc chip, we add a customized property to dts. In this patch we add an interface to read this property. At the same time, we provided a switch, which is CONFIG_ASCEND_HISI_MMC, for you to get rid of our modifications.
Signed-off-by: zhangguijiang zhangguijiang@huawei.com Reviewed-by: Ding Tianhong dingtianhong@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/mmc/Kconfig | 10 ++++ drivers/mmc/core/host.c | 43 ++++++++++++--- include/linux/mmc/host.h | 115 +++++++++++++++++++++++++++++++++++++++ include/linux/mmc/pm.h | 1 + 4 files changed, 162 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ec21388311db2..8b29ecadd1862 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -12,6 +12,16 @@ menuconfig MMC If you want MMC/SD/SDIO support, you should say Y here and also to your specific host controller driver.
+config ASCEND_HISI_MMC + bool "Ascend HiSilicon MMC card support" + depends on MMC + default n + help + This selects for Hisilicon SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. + You should select this option if you want mmc support on + Ascend platform. + if MMC
source "drivers/mmc/core/Kconfig" diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index dd1c14d8f6863..b29ee31e7865e 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -348,6 +348,11 @@ int mmc_of_parse(struct mmc_host *host)
EXPORT_SYMBOL(mmc_of_parse);
+static inline int mmc_is_ascend_hi_mci_1(struct device *dev) +{ + return !strncmp(dev_name(dev), "hi_mci.1", strlen("hi_mci.1")); +} + /** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure @@ -374,7 +379,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) }
host->index = err; - + if (mmc_is_ascend_customized(dev)) { + if (mmc_is_ascend_hi_mci_1(dev)) + host->index = 1; + } dev_set_name(&host->class_dev, "mmc%d", host->index);
host->parent = dev; @@ -383,10 +391,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) device_initialize(&host->class_dev); device_enable_async_suspend(&host->class_dev);
- if (mmc_gpio_alloc(host)) { - put_device(&host->class_dev); - return NULL; - } + if (!mmc_is_ascend_customized(host->parent)) + if (mmc_gpio_alloc(host)) { + put_device(&host->class_dev); + return NULL; + }
spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); @@ -439,7 +448,9 @@ int mmc_add_host(struct mmc_host *host) #endif
mmc_start_host(host); - mmc_register_pm_notifier(host); + if (!mmc_is_ascend_customized(host->parent) || + !(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + mmc_register_pm_notifier(host);
return 0; } @@ -456,7 +467,9 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { - mmc_unregister_pm_notifier(host); + if (!mmc_is_ascend_customized(host->parent) || + !(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY)) + mmc_unregister_pm_notifier(host); mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS @@ -483,3 +496,19 @@ void mmc_free_host(struct mmc_host *host) }
EXPORT_SYMBOL(mmc_free_host); + + +int mmc_is_ascend_customized(struct device *dev) +{ +#ifdef CONFIG_ASCEND_HISI_MMC + static int is_ascend_customized = -1; + + if (is_ascend_customized == -1) + is_ascend_customized = ((dev == NULL) ? 0 : + of_find_property(dev->of_node, "customized", NULL) != NULL); + return is_ascend_customized; +#else + return 0; +#endif +} +EXPORT_SYMBOL(mmc_is_ascend_customized); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 7e8e5b20e82b0..2cd5a73ab12a2 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -19,6 +19,9 @@ #include <linux/mmc/pm.h> #include <linux/dma-direction.h>
+#include <linux/jiffies.h> +#include <linux/version.h> + struct mmc_ios { unsigned int clock; /* clock rate */ unsigned short vdd; @@ -63,6 +66,7 @@ struct mmc_ios { #define MMC_TIMING_MMC_DDR52 8 #define MMC_TIMING_MMC_HS200 9 #define MMC_TIMING_MMC_HS400 10 +#define MMC_TIMING_NEW_SD MMC_TIMING_UHS_SDR12
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
@@ -78,7 +82,25 @@ struct mmc_ios { #define MMC_SET_DRIVER_TYPE_D 3
bool enhanced_strobe; /* hs400es selection */ +#ifdef CONFIG_ASCEND_HISI_MMC + unsigned int clock_store; /*store the clock before power off*/ +#endif +}; + +#ifdef CONFIG_ASCEND_HISI_MMC +struct mmc_cmdq_host_ops { + int (*enable)(struct mmc_host *mmc); + int (*disable)(struct mmc_host *mmc, bool soft); + int (*restore_irqs)(struct mmc_host *mmc); + int (*request)(struct mmc_host *mmc, struct mmc_request *mrq); + int (*halt)(struct mmc_host *mmc, bool halt); + void (*post_req)(struct mmc_host *mmc, struct mmc_request *mrq, + int err); + void (*disable_immediately)(struct mmc_host *mmc); + int (*clear_and_halt)(struct mmc_host *mmc); }; +#endif +
struct mmc_host;
@@ -168,6 +190,12 @@ struct mmc_host_ops { */ int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); +#ifdef CONFIG_ASCEND_HISI_MMC + /* Slow down clk for ascend chip SD cards */ + void (*slowdown_clk)(struct mmc_host *host, int timing); + int (*enable_enhanced_strobe)(struct mmc_host *host); + int (*send_cmd_direct)(struct mmc_host *host, struct mmc_request *mrq); +#endif };
struct mmc_cqe_ops { @@ -255,6 +283,30 @@ struct mmc_context_info { wait_queue_head_t wait; };
+#ifdef CONFIG_ASCEND_HISI_MMC +/** + * mmc_cmdq_context_info - describes the contexts of cmdq + * @active_reqs requests being processed + * @active_dcmd dcmd in progress, don't issue any + * more dcmd requests + * @rpmb_in_wait do not pull any more reqs till rpmb is handled + * @cmdq_state state of cmdq engine + * @req_starved completion should invoke the request_fn since + * no tags were available + * @cmdq_ctx_lock acquire this before accessing this structure + */ +struct mmc_cmdq_context_info { + unsigned long active_reqs; /* in-flight requests */ + bool active_dcmd; + bool rpmb_in_wait; + unsigned long curr_state; + + /* no free tag available */ + unsigned long req_starved; + spinlock_t cmdq_ctx_lock; +}; +#endif + struct regulator; struct mmc_pwrseq;
@@ -328,6 +380,9 @@ struct mmc_host { #define MMC_CAP_UHS_SDR50 (1 << 18) /* Host supports UHS SDR50 mode */ #define MMC_CAP_UHS_SDR104 (1 << 19) /* Host supports UHS SDR104 mode */ #define MMC_CAP_UHS_DDR50 (1 << 20) /* Host supports UHS DDR50 mode */ +#ifdef CONFIG_ASCEND_HISI_MMC +#define MMC_CAP_RUNTIME_RESUME (1 << 20) /* Resume at runtime_resume. */ +#endif #define MMC_CAP_UHS (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | \ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \ MMC_CAP_UHS_DDR50) @@ -368,6 +423,34 @@ struct mmc_host { #define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */ #define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */ #define MMC_CAP2_AVOID_3_3V (1 << 25) /* Host must negotiate down from 3.3V */ +#ifdef CONFIG_ASCEND_HISI_MMC +#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ +#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock read don't work */ +#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */ +#define MMC_CAP2_BROKEN_VOLTAGE (1 << 7) /* Use the broken voltage */ +#define MMC_CAP2_DETECT_ON_ERR (1 << 8) /* I/O err check card removal */ +#define MMC_CAP2_HC_ERASE_SZ (1 << 9) /* High-capacity erase size */ +#define MMC_CAP2_PACKED_RD (1 << 12) /* Allow packed read */ +#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */ +#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ + MMC_CAP2_PACKED_WR) +#define MMC_CAP2_CMD_QUEUE (1 << 18) /* support eMMC command queue */ +#define MMC_CAP2_ENHANCED_STROBE (1 << 19) +#define MMC_CAP2_CACHE_FLUSH_BARRIER (1 << 20) +/* Allow background operations auto enable control */ +#define MMC_CAP2_BKOPS_AUTO_CTRL (1 << 21) +/* Allow background operations manual enable control */ +#define MMC_CAP2_BKOPS_MANUAL_CTRL (1 << 22) + +/* host is connected by via modem through sdio */ +#define MMC_CAP2_SUPPORT_VIA_MODEM (1 << 26) +/* host is connected by wifi through sdio */ +#define MMC_CAP2_SUPPORT_WIFI (1 << 27) +/* host is connected to 1102 wifi */ +#define MMC_CAP2_SUPPORT_WIFI_CMD11 (1 << 28) +/* host do not support low power for wifi*/ +#define MMC_CAP2_WIFI_NO_LOWPWR (1 << 29) +#endif
int fixed_drv_type; /* fixed driver type for non-removable media */
@@ -461,6 +544,12 @@ struct mmc_host { bool cqe_on;
unsigned long private[0] ____cacheline_aligned; +#ifdef CONFIG_ASCEND_HISI_MMC + const struct mmc_cmdq_host_ops *cmdq_ops; + int sdio_present; + unsigned int cmdq_slots; + struct mmc_cmdq_context_info cmdq_ctx; +#endif };
struct device_node; @@ -588,4 +677,30 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_abort_tuning(struct mmc_host *host, u32 opcode);
+#ifdef CONFIG_ASCEND_HISI_MMC +int mmc_cache_ctrl(struct mmc_host *host, u8 enable); +int mmc_card_awake(struct mmc_host *host); +int mmc_card_sleep(struct mmc_host *host); +int mmc_card_can_sleep(struct mmc_host *host); +#else +static inline int mmc_cache_ctrl(struct mmc_host *host, u8 enable) +{ + return 0; +} +static inline int mmc_card_awake(struct mmc_host *host) +{ + return 0; +} +static inline int mmc_card_sleep(struct mmc_host *host) +{ + return 0; +} +static inline int mmc_card_can_sleep(struct mmc_host *host) +{ + return 0; +} +#endif + +int mmc_is_ascend_customized(struct device *dev); + #endif /* LINUX_MMC_HOST_H */ diff --git a/include/linux/mmc/pm.h b/include/linux/mmc/pm.h index 4a139204c20c0..6e2d6a135c7e0 100644 --- a/include/linux/mmc/pm.h +++ b/include/linux/mmc/pm.h @@ -26,5 +26,6 @@ typedef unsigned int mmc_pm_flag_t;
#define MMC_PM_KEEP_POWER (1 << 0) /* preserve card power during suspend */ #define MMC_PM_WAKE_SDIO_IRQ (1 << 1) /* wake up host system on SDIO IRQ assertion */ +#define MMC_PM_IGNORE_PM_NOTIFY (1 << 2) /* ignore mmc pm notify */
#endif /* LINUX_MMC_PM_H */