From c951eac0271032cc1f793f6a61fcf8f285ffe075 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Mon, 14 Apr 2008 15:22:49 -0700 Subject: [PATCH] ANDROID: mmc: sdio: Add concept of an 'embedded' SDIO device. This is required to support chips which use SDIO for signaling/ communication but do not implement the various card enumeration registers as required for full SD / SDIO cards. mmc: sdio: Fix bug where we're freeing the CIS tables we never allocated when using EMBEDDED_SDIO mmc: Add max_blksize to embedded SDIO data Change-Id: Ibff2e3e991e5522f55ec8c6edc25ed09f2553736 Signed-off-by: San Mehat [AmitP: Rebased the original commit to align with the upstream commit 5fc3d80ef496 ("mmc: sdio: don't use rocr to check if the card could support UHS mode") Also folded following android-4.9 commit changes into this patch d775b65ecaf6 ("ANDROID: mmc: core: Remove stray CONFIG_EXPERIMENTAL dependencies")] Signed-off-by: Amit Pundir --- drivers/mmc/core/Kconfig | 9 +++- drivers/mmc/core/core.c | 16 +++++++ drivers/mmc/core/sdio.c | 88 ++++++++++++++++++++++++++--------- drivers/mmc/core/sdio_bus.c | 13 +++++- include/linux/amba/mmci.h | 10 ++++ include/linux/mmc/host.h | 17 +++++++ include/linux/mmc/sdio_func.h | 8 ++++ 7 files changed, 136 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 0b004586c803..b3faf1062d4e 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -80,8 +80,15 @@ config MMC_TEST This driver is only of interest to those developing or testing a host driver. Most people should say N here. +config MMC_EMBEDDED_SDIO + boolean "MMC embedded SDIO device support" + help + If you say Y here, support will be added for embedded SDIO + devices which do not contain the necessary enumeration + support in hardware to be properly detected. + config MMC_PARANOID_SD_INIT - bool "Enable paranoid SD card initialization (EXPERIMENTAL)" + bool "Enable paranoid SD card initialization" help If you say Y here, the MMC layer will be extra paranoid about re-trying SD init requests. This can be a useful diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 66c9cf49ad2f..41ac82921922 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2802,6 +2802,22 @@ void mmc_init_context_info(struct mmc_host *host) init_waitqueue_head(&host->context_info.wait); } +#ifdef CONFIG_MMC_EMBEDDED_SDIO +void mmc_set_embedded_sdio_data(struct mmc_host *host, + struct sdio_cis *cis, + struct sdio_cccr *cccr, + struct sdio_embedded_func *funcs, + int num_funcs) +{ + host->embedded_sdio_data.cis = cis; + host->embedded_sdio_data.cccr = cccr; + host->embedded_sdio_data.funcs = funcs; + host->embedded_sdio_data.num_funcs = num_funcs; +} + +EXPORT_SYMBOL(mmc_set_embedded_sdio_data); +#endif + static int __init mmc_init(void) { int ret; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index cc43687ca241..c42e3cd537f2 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -31,6 +31,10 @@ #include "sdio_ops.h" #include "sdio_cis.h" +#ifdef CONFIG_MMC_EMBEDDED_SDIO +#include +#endif + static int sdio_read_fbr(struct sdio_func *func) { int ret; @@ -706,28 +710,44 @@ try_again: goto finish; } - /* - * Read the common registers. Note that we should try to - * validate whether UHS would work or not. - */ - err = sdio_read_cccr(card, ocr); - if (err) { - mmc_sdio_resend_if_cond(host, card); - if (ocr & R4_18V_PRESENT) { - /* Retry init sequence, but without R4_18V_PRESENT. */ - retries = 0; - goto try_again; - } else { - goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.cccr) + memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr)); + else { +#endif + /* + * Read the common registers. Note that we should try to + * validate whether UHS would work or not. + */ + err = sdio_read_cccr(card, ocr); + if (err) { + mmc_sdio_resend_if_cond(host, card); + if (ocr & R4_18V_PRESENT) { + /* Retry init sequence, but without R4_18V_PRESENT. */ + retries = 0; + goto try_again; + } else { + goto remove; + } } +#ifdef CONFIG_MMC_EMBEDDED_SDIO } +#endif - /* - * Read the common CIS tuples. - */ - err = sdio_read_common_cis(card); - if (err) - goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.cis) + memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis)); + else { +#endif + /* + * Read the common CIS tuples. + */ + err = sdio_read_common_cis(card); + if (err) + goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + } +#endif if (oldcard) { int same = (card->cis.vendor == oldcard->cis.vendor && @@ -1129,14 +1149,36 @@ int mmc_attach_sdio(struct mmc_host *host) funcs = (ocr & 0x70000000) >> 28; card->sdio_funcs = 0; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.funcs) + card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs; +#endif + /* * Initialize (but don't add) all present functions. */ for (i = 0; i < funcs; i++, card->sdio_funcs++) { - err = sdio_init_func(host->card, i + 1); - if (err) - goto remove; - +#ifdef CONFIG_MMC_EMBEDDED_SDIO + if (host->embedded_sdio_data.funcs) { + struct sdio_func *tmp; + + tmp = sdio_alloc_func(host->card); + if (IS_ERR(tmp)) + goto remove; + tmp->num = (i + 1); + card->sdio_func[i] = tmp; + tmp->class = host->embedded_sdio_data.funcs[i].f_class; + tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize; + tmp->vendor = card->cis.vendor; + tmp->device = card->cis.device; + } else { +#endif + err = sdio_init_func(host->card, i + 1); + if (err) + goto remove; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + } +#endif /* * Enable Runtime PM for this func (if supported) */ diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 2b32b88949ba..997d556fccf1 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -29,6 +29,10 @@ #include "sdio_cis.h" #include "sdio_bus.h" +#ifdef CONFIG_MMC_EMBEDDED_SDIO +#include +#endif + #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) /* show configuration fields */ @@ -264,7 +268,14 @@ static void sdio_release_func(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - sdio_free_func_cis(func); +#ifdef CONFIG_MMC_EMBEDDED_SDIO + /* + * If this device is embedded then we never allocated + * cis tables for this func + */ + if (!func->card->host->embedded_sdio_data.funcs) +#endif + sdio_free_func_cis(func); kfree(func->info); kfree(func->tmpbuf); diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index da8357ba11bc..02dc2f3a76f7 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -6,6 +6,15 @@ #define AMBA_MMCI_H #include +#include +#include + +struct embedded_sdio_data { + struct sdio_cis cis; + struct sdio_cccr cccr; + struct sdio_embedded_func *funcs; + int num_funcs; +}; /** * struct mmci_platform_data - platform configuration for the MMCI @@ -32,6 +41,7 @@ struct mmci_platform_data { int gpio_wp; int gpio_cd; bool cd_invert; + struct embedded_sdio_data *embedded_sdio; }; #endif diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 9a43763a68ad..227961c5011b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -439,6 +439,15 @@ struct mmc_host { bool cqe_enabled; bool cqe_on; +#ifdef CONFIG_MMC_EMBEDDED_SDIO + struct { + struct sdio_cis *cis; + struct sdio_cccr *cccr; + struct sdio_embedded_func *funcs; + int num_funcs; + } embedded_sdio_data; +#endif + unsigned long private[0] ____cacheline_aligned; }; @@ -451,6 +460,14 @@ void mmc_free_host(struct mmc_host *); int mmc_of_parse(struct mmc_host *host); int mmc_of_parse_voltage(struct device_node *np, u32 *mask); +#ifdef CONFIG_MMC_EMBEDDED_SDIO +extern void mmc_set_embedded_sdio_data(struct mmc_host *host, + struct sdio_cis *cis, + struct sdio_cccr *cccr, + struct sdio_embedded_func *funcs, + int num_funcs); +#endif + static inline void *mmc_priv(struct mmc_host *host) { return (void *)host->private; diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 97ca105347a6..f466f381ad25 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -22,6 +22,14 @@ struct sdio_func; typedef void (sdio_irq_handler_t)(struct sdio_func *); +/* + * Structure used to hold embedded SDIO device data from platform layer + */ +struct sdio_embedded_func { + uint8_t f_class; + uint32_t f_maxblksize; +}; + /* * SDIO function CIS tuple (unknown to the core) */ -- 2.20.1