diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /drivers/mmc/host/sdhci.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 139 | 
1 files changed, 76 insertions, 63 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index bc1445238fb3..64b7fdbd1a9c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *);  static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);  static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);  static int sdhci_pre_dma_transfer(struct sdhci_host *host, -					struct mmc_data *data, -					struct sdhci_host_next *next); +					struct mmc_data *data);  static int sdhci_do_get_cd(struct sdhci_host *host);  #ifdef CONFIG_PM @@ -207,8 +206,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset);  static void sdhci_do_reset(struct sdhci_host *host, u8 mask)  {  	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { -		if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & -			SDHCI_CARD_PRESENT)) +		if (!sdhci_do_get_cd(host))  			return;  	} @@ -496,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,  		goto fail;  	BUG_ON(host->align_addr & host->align_mask); -	host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); +	host->sg_count = sdhci_pre_dma_transfer(host, data);  	if (host->sg_count < 0)  		goto unmap_align; @@ -635,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host,  		}  	} -	if (!data->host_cookie) +	if (data->host_cookie == COOKIE_MAPPED) {  		dma_unmap_sg(mmc_dev(host->mmc), data->sg,  			data->sg_len, direction); +		data->host_cookie = COOKIE_UNMAPPED; +	}  }  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -833,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)  		} else {  			int sg_cnt; -			sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); +			sg_cnt = sdhci_pre_dma_transfer(host, data);  			if (sg_cnt <= 0) {  				/*  				 * This only happens when someone fed @@ -949,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host)  		if (host->flags & SDHCI_USE_ADMA)  			sdhci_adma_table_post(host, data);  		else { -			if (!data->host_cookie) +			if (data->host_cookie == COOKIE_MAPPED) {  				dma_unmap_sg(mmc_dev(host->mmc),  					data->sg, data->sg_len,  					(data->flags & MMC_DATA_READ) ?  					DMA_FROM_DEVICE : DMA_TO_DEVICE); +				data->host_cookie = COOKIE_UNMAPPED; +			}  		}  	} @@ -1132,6 +1134,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)  		preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);  		break;  	case MMC_TIMING_UHS_DDR50: +	case MMC_TIMING_MMC_DDR52:  		preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);  		break;  	case MMC_TIMING_MMC_HS400: @@ -1152,6 +1155,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  	int real_div = div, clk_mul = 1;  	u16 clk = 0;  	unsigned long timeout; +	bool switch_base_clk = false;  	host->mmc->actual_clock = 0; @@ -1189,15 +1193,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  					<= clock)  					break;  			} -			/* -			 * Set Programmable Clock Mode in the Clock -			 * Control register. -			 */ -			clk = SDHCI_PROG_CLOCK_MODE; -			real_div = div; -			clk_mul = host->clk_mul; -			div--; -		} else { +			if ((host->max_clk * host->clk_mul / div) <= clock) { +				/* +				 * Set Programmable Clock Mode in the Clock +				 * Control register. +				 */ +				clk = SDHCI_PROG_CLOCK_MODE; +				real_div = div; +				clk_mul = host->clk_mul; +				div--; +			} else { +				/* +				 * Divisor can be too small to reach clock +				 * speed requirement. Then use the base clock. +				 */ +				switch_base_clk = true; +			} +		} + +		if (!host->clk_mul || switch_base_clk) {  			/* Version 3.00 divisors must be a multiple of 2. */  			if (host->max_clk <= clock)  				div = 1; @@ -1210,6 +1224,9 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  			}  			real_div = div;  			div >>= 1; +			if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN) +				&& !div && host->max_clk <= 25000000) +				div = 1;  		}  	} else {  		/* Version 2.00 divisors must be a power of 2. */ @@ -1559,7 +1576,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)  				 (ios->timing == MMC_TIMING_UHS_SDR25) ||  				 (ios->timing == MMC_TIMING_UHS_SDR50) ||  				 (ios->timing == MMC_TIMING_UHS_SDR104) || -				 (ios->timing == MMC_TIMING_UHS_DDR50))) { +				 (ios->timing == MMC_TIMING_UHS_DDR50) || +				 (ios->timing == MMC_TIMING_MMC_DDR52))) {  			u16 preset;  			sdhci_enable_preset_value(host, true); @@ -1601,15 +1619,21 @@ static int sdhci_do_get_cd(struct sdhci_host *host)  	if (host->flags & SDHCI_DEVICE_DEAD)  		return 0; -	/* If polling/nonremovable, assume that the card is always present. */ -	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || -	    (host->mmc->caps & MMC_CAP_NONREMOVABLE)) +	/* If nonremovable, assume that the card is always present. */ +	if (host->mmc->caps & MMC_CAP_NONREMOVABLE)  		return 1; -	/* Try slot gpio detect */ +	/* +	 * Try slot gpio detect, if defined it take precedence +	 * over build in controller functionality +	 */  	if (!IS_ERR_VALUE(gpio_cd))  		return !!gpio_cd; +	/* If polling, assume that the card is always present. */ +	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) +		return 1; +  	/* Host native card detect */  	return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);  } @@ -2097,49 +2121,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,  	struct mmc_data *data = mrq->data;  	if (host->flags & SDHCI_REQ_USE_DMA) { -		if (data->host_cookie) +		if (data->host_cookie == COOKIE_GIVEN || +				data->host_cookie == COOKIE_MAPPED)  			dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,  					 data->flags & MMC_DATA_WRITE ?  					 DMA_TO_DEVICE : DMA_FROM_DEVICE); -		mrq->data->host_cookie = 0; +		data->host_cookie = COOKIE_UNMAPPED;  	}  }  static int sdhci_pre_dma_transfer(struct sdhci_host *host, -				       struct mmc_data *data, -				       struct sdhci_host_next *next) +				       struct mmc_data *data)  {  	int sg_count; -	if (!next && data->host_cookie && -	    data->host_cookie != host->next_data.cookie) { -		pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", -			__func__, data->host_cookie, host->next_data.cookie); -		data->host_cookie = 0; +	if (data->host_cookie == COOKIE_MAPPED) { +		data->host_cookie = COOKIE_GIVEN; +		return data->sg_count;  	} -	/* Check if next job is already prepared */ -	if (next || -	    (!next && data->host_cookie != host->next_data.cookie)) { -		sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, -				     data->sg_len, -				     data->flags & MMC_DATA_WRITE ? -				     DMA_TO_DEVICE : DMA_FROM_DEVICE); - -	} else { -		sg_count = host->next_data.sg_count; -		host->next_data.sg_count = 0; -	} +	WARN_ON(data->host_cookie == COOKIE_GIVEN); +	sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, +				data->flags & MMC_DATA_WRITE ? +				DMA_TO_DEVICE : DMA_FROM_DEVICE);  	if (sg_count == 0) -		return -EINVAL; +		return -ENOSPC; -	if (next) { -		next->sg_count = sg_count; -		data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; -	} else -		host->sg_count = sg_count; +	data->sg_count = sg_count; +	data->host_cookie = COOKIE_MAPPED;  	return sg_count;  } @@ -2149,16 +2160,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,  {  	struct sdhci_host *host = mmc_priv(mmc); -	if (mrq->data->host_cookie) { -		mrq->data->host_cookie = 0; -		return; -	} +	mrq->data->host_cookie = COOKIE_UNMAPPED;  	if (host->flags & SDHCI_REQ_USE_DMA) -		if (sdhci_pre_dma_transfer(host, -					mrq->data, -					&host->next_data) < 0) -			mrq->data->host_cookie = 0; +		sdhci_pre_dma_transfer(host, mrq->data);  }  static void sdhci_card_event(struct mmc_host *mmc) @@ -2866,6 +2871,7 @@ int sdhci_add_host(struct sdhci_host *host)  	u32 max_current_caps;  	unsigned int ocr_avail;  	unsigned int override_timeout_clk; +	u32 max_clk;  	int ret;  	WARN_ON(host == NULL); @@ -2978,8 +2984,11 @@ int sdhci_add_host(struct sdhci_host *host)  						      GFP_KERNEL);  		host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);  		if (!host->adma_table || !host->align_buffer) { -			dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, -					  host->adma_table, host->adma_addr); +			if (host->adma_table) +				dma_free_coherent(mmc_dev(mmc), +						  host->adma_table_sz, +						  host->adma_table, +						  host->adma_addr);  			kfree(host->align_buffer);  			pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",  				mmc_hostname(mmc)); @@ -3026,7 +3035,6 @@ int sdhci_add_host(struct sdhci_host *host)  		host->max_clk = host->ops->get_max_clock(host);  	} -	host->next_data.cookie = 1;  	/*  	 * In case of Host Controller v3.00, find out whether clock  	 * multiplier is supported. @@ -3047,18 +3055,22 @@ int sdhci_add_host(struct sdhci_host *host)  	 * Set host parameters.  	 */  	mmc->ops = &sdhci_ops; -	mmc->f_max = host->max_clk; +	max_clk = host->max_clk; +  	if (host->ops->get_min_clock)  		mmc->f_min = host->ops->get_min_clock(host);  	else if (host->version >= SDHCI_SPEC_300) {  		if (host->clk_mul) {  			mmc->f_min = (host->max_clk * host->clk_mul) / 1024; -			mmc->f_max = host->max_clk * host->clk_mul; +			max_clk = host->max_clk * host->clk_mul;  		} else  			mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;  	} else  		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; +	if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk))) +		mmc->f_max = max_clk; +  	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {  		host->timeout_clk = (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >>  					SDHCI_TIMEOUT_CLK_SHIFT; @@ -3118,7 +3130,8 @@ int sdhci_add_host(struct sdhci_host *host)  		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;  	if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && -	    !(mmc->caps & MMC_CAP_NONREMOVABLE)) +	    !(mmc->caps & MMC_CAP_NONREMOVABLE) && +	    IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc)))  		mmc->caps |= MMC_CAP_NEEDS_POLL;  	/* If there are external regulators, get them */  |