forked from mirrors/linux
		
	mmc: sdhci-pci: Use ACPI DSM to get driver strength for some Intel devices
Make use of an Intel ACPI _DSM that provides eMMC driver strength. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Ludovic Desroches <ludovic.desroches@microchip.com>
This commit is contained in:
		
							parent
							
								
									c959a6b00f
								
							
						
					
					
						commit
						51ced59cc0
					
				
					 2 changed files with 14 additions and 66 deletions
				
			
		| 
						 | 
					@ -261,11 +261,13 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	INTEL_DSM_FNS		=  0,
 | 
						INTEL_DSM_FNS		=  0,
 | 
				
			||||||
 | 
						INTEL_DSM_DRV_STRENGTH	=  9,
 | 
				
			||||||
	INTEL_DSM_D3_RETUNE	= 10,
 | 
						INTEL_DSM_D3_RETUNE	= 10,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct intel_host {
 | 
					struct intel_host {
 | 
				
			||||||
	u32	dsm_fns;
 | 
						u32	dsm_fns;
 | 
				
			||||||
 | 
						int	drv_strength;
 | 
				
			||||||
	bool	d3_retune;
 | 
						bool	d3_retune;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,6 +328,9 @@ static void intel_dsm_init(struct intel_host *intel_host, struct device *dev,
 | 
				
			||||||
	pr_debug("%s: DSM function mask %#x\n",
 | 
						pr_debug("%s: DSM function mask %#x\n",
 | 
				
			||||||
		 mmc_hostname(mmc), intel_host->dsm_fns);
 | 
							 mmc_hostname(mmc), intel_host->dsm_fns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = intel_dsm(intel_host, dev, INTEL_DSM_DRV_STRENGTH, &val);
 | 
				
			||||||
 | 
						intel_host->drv_strength = err ? 0 : val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val);
 | 
						err = intel_dsm(intel_host, dev, INTEL_DSM_D3_RETUNE, &val);
 | 
				
			||||||
	intel_host->d3_retune = err ? true : !!val;
 | 
						intel_host->d3_retune = err ? true : !!val;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -345,67 +350,15 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
 | 
				
			||||||
	usleep_range(300, 1000);
 | 
						usleep_range(300, 1000);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int spt_select_drive_strength(struct sdhci_host *host,
 | 
					static int intel_select_drive_strength(struct mmc_card *card,
 | 
				
			||||||
				     struct mmc_card *card,
 | 
									       unsigned int max_dtr, int host_drv,
 | 
				
			||||||
				     unsigned int max_dtr,
 | 
									       int card_drv, int *drv_type)
 | 
				
			||||||
				     int host_drv, int card_drv, int *drv_type)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int drive_strength;
 | 
						struct sdhci_host *host = mmc_priv(card->host);
 | 
				
			||||||
 | 
						struct sdhci_pci_slot *slot = sdhci_priv(host);
 | 
				
			||||||
 | 
						struct intel_host *intel_host = sdhci_pci_priv(slot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sdhci_pci_spt_drive_strength > 0)
 | 
						return intel_host->drv_strength;
 | 
				
			||||||
		drive_strength = sdhci_pci_spt_drive_strength & 0xf;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		drive_strength = 0; /* Default 50-ohm */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0)
 | 
					 | 
				
			||||||
		drive_strength = 0; /* Default 50-ohm */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return drive_strength;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Try to read the drive strength from the card */
 | 
					 | 
				
			||||||
static void spt_read_drive_strength(struct sdhci_host *host)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 val, i, t;
 | 
					 | 
				
			||||||
	u16 m;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (sdhci_pci_spt_drive_strength)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sdhci_pci_spt_drive_strength = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m = sdhci_readw(host, SDHCI_HOST_CONTROL2) & 0x7;
 | 
					 | 
				
			||||||
	if (m != 3 && m != 5)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	val = sdhci_readl(host, SDHCI_PRESENT_STATE);
 | 
					 | 
				
			||||||
	if (val & 0x3)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	sdhci_writel(host, 0x007f0023, SDHCI_INT_ENABLE);
 | 
					 | 
				
			||||||
	sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
 | 
					 | 
				
			||||||
	sdhci_writew(host, 0x10, SDHCI_TRANSFER_MODE);
 | 
					 | 
				
			||||||
	sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
 | 
					 | 
				
			||||||
	sdhci_writew(host, 512, SDHCI_BLOCK_SIZE);
 | 
					 | 
				
			||||||
	sdhci_writew(host, 1, SDHCI_BLOCK_COUNT);
 | 
					 | 
				
			||||||
	sdhci_writel(host, 0, SDHCI_ARGUMENT);
 | 
					 | 
				
			||||||
	sdhci_writew(host, 0x83b, SDHCI_COMMAND);
 | 
					 | 
				
			||||||
	for (i = 0; i < 1000; i++) {
 | 
					 | 
				
			||||||
		val = sdhci_readl(host, SDHCI_INT_STATUS);
 | 
					 | 
				
			||||||
		if (val & 0xffff8000)
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		if (val & 0x20)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		udelay(1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	val = sdhci_readl(host, SDHCI_PRESENT_STATE);
 | 
					 | 
				
			||||||
	if (!(val & 0x800))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	for (i = 0; i < 47; i++)
 | 
					 | 
				
			||||||
		val = sdhci_readl(host, SDHCI_BUFFER);
 | 
					 | 
				
			||||||
	t = val & 0xf00;
 | 
					 | 
				
			||||||
	if (t != 0x200 && t != 0x300)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sdhci_pci_spt_drive_strength = 0x10 | ((val >> 12) & 0xf);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bxt_get_cd(struct mmc_host *mmc)
 | 
					static int bxt_get_cd(struct mmc_host *mmc)
 | 
				
			||||||
| 
						 | 
					@ -451,10 +404,8 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 | 
				
			||||||
	slot->hw_reset = sdhci_pci_int_hw_reset;
 | 
						slot->hw_reset = sdhci_pci_int_hw_reset;
 | 
				
			||||||
	if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
 | 
						if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
 | 
				
			||||||
		slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
 | 
							slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
 | 
				
			||||||
	if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_SPT_EMMC) {
 | 
						slot->host->mmc_host_ops.select_drive_strength =
 | 
				
			||||||
		spt_read_drive_strength(slot->host);
 | 
											intel_select_drive_strength;
 | 
				
			||||||
		slot->select_drive_strength = spt_select_drive_strength;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,3 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
 | 
					struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
 | 
				
			||||||
EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
 | 
					EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
int sdhci_pci_spt_drive_strength;
 | 
					 | 
				
			||||||
EXPORT_SYMBOL_GPL(sdhci_pci_spt_drive_strength);
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue