Skip to content

Commit e1bfad6

Browse files
ahunter6storulf
authored andcommitted
mmc: sdhci-pci: Add support for drive strength selection for SPT
Implement the select_drive_strength callback to provide drive strength selection for Intel SPT. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent cb84964 commit e1bfad6

File tree

4 files changed

+92
-0
lines changed

4 files changed

+92
-0
lines changed

drivers/mmc/host/sdhci-pci-data.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33

44
struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
55
EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
6+
7+
int sdhci_pci_spt_drive_strength;
8+
EXPORT_SYMBOL_GPL(sdhci_pci_spt_drive_strength);

drivers/mmc/host/sdhci-pci.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/slab.h>
2121
#include <linux/device.h>
2222
#include <linux/mmc/host.h>
23+
#include <linux/mmc/mmc.h>
2324
#include <linux/scatterlist.h>
2425
#include <linux/io.h>
2526
#include <linux/gpio.h>
@@ -266,6 +267,69 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
266267
usleep_range(300, 1000);
267268
}
268269

270+
static int spt_select_drive_strength(struct sdhci_host *host,
271+
struct mmc_card *card,
272+
unsigned int max_dtr,
273+
int host_drv, int card_drv, int *drv_type)
274+
{
275+
int drive_strength;
276+
277+
if (sdhci_pci_spt_drive_strength > 0)
278+
drive_strength = sdhci_pci_spt_drive_strength & 0xf;
279+
else
280+
drive_strength = 1; /* 33-ohm */
281+
282+
if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0)
283+
drive_strength = 0; /* Default 50-ohm */
284+
285+
return drive_strength;
286+
}
287+
288+
/* Try to read the drive strength from the card */
289+
static void spt_read_drive_strength(struct sdhci_host *host)
290+
{
291+
u32 val, i, t;
292+
u16 m;
293+
294+
if (sdhci_pci_spt_drive_strength)
295+
return;
296+
297+
sdhci_pci_spt_drive_strength = -1;
298+
299+
m = sdhci_readw(host, SDHCI_HOST_CONTROL2) & 0x7;
300+
if (m != 3 && m != 5)
301+
return;
302+
val = sdhci_readl(host, SDHCI_PRESENT_STATE);
303+
if (val & 0x3)
304+
return;
305+
sdhci_writel(host, 0x007f0023, SDHCI_INT_ENABLE);
306+
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
307+
sdhci_writew(host, 0x10, SDHCI_TRANSFER_MODE);
308+
sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL);
309+
sdhci_writew(host, 512, SDHCI_BLOCK_SIZE);
310+
sdhci_writew(host, 1, SDHCI_BLOCK_COUNT);
311+
sdhci_writel(host, 0, SDHCI_ARGUMENT);
312+
sdhci_writew(host, 0x83b, SDHCI_COMMAND);
313+
for (i = 0; i < 1000; i++) {
314+
val = sdhci_readl(host, SDHCI_INT_STATUS);
315+
if (val & 0xffff8000)
316+
return;
317+
if (val & 0x20)
318+
break;
319+
udelay(1);
320+
}
321+
val = sdhci_readl(host, SDHCI_PRESENT_STATE);
322+
if (!(val & 0x800))
323+
return;
324+
for (i = 0; i < 47; i++)
325+
val = sdhci_readl(host, SDHCI_BUFFER);
326+
t = val & 0xf00;
327+
if (t != 0x200 && t != 0x300)
328+
return;
329+
330+
sdhci_pci_spt_drive_strength = 0x10 | ((val >> 12) & 0xf);
331+
}
332+
269333
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
270334
{
271335
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
@@ -276,6 +340,10 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
276340
slot->hw_reset = sdhci_pci_int_hw_reset;
277341
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
278342
slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
343+
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_SPT_EMMC) {
344+
spt_read_drive_strength(slot->host);
345+
slot->select_drive_strength = spt_select_drive_strength;
346+
}
279347
return 0;
280348
}
281349

@@ -1203,13 +1271,28 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
12031271
slot->hw_reset(host);
12041272
}
12051273

1274+
static int sdhci_pci_select_drive_strength(struct sdhci_host *host,
1275+
struct mmc_card *card,
1276+
unsigned int max_dtr, int host_drv,
1277+
int card_drv, int *drv_type)
1278+
{
1279+
struct sdhci_pci_slot *slot = sdhci_priv(host);
1280+
1281+
if (!slot->select_drive_strength)
1282+
return 0;
1283+
1284+
return slot->select_drive_strength(host, card, max_dtr, host_drv,
1285+
card_drv, drv_type);
1286+
}
1287+
12061288
static const struct sdhci_ops sdhci_pci_ops = {
12071289
.set_clock = sdhci_set_clock,
12081290
.enable_dma = sdhci_pci_enable_dma,
12091291
.set_bus_width = sdhci_pci_set_bus_width,
12101292
.reset = sdhci_reset,
12111293
.set_uhs_signaling = sdhci_set_uhs_signaling,
12121294
.hw_reset = sdhci_pci_hw_reset,
1295+
.select_drive_strength = sdhci_pci_select_drive_strength,
12131296
};
12141297

12151298
/*****************************************************************************\

drivers/mmc/host/sdhci-pci.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ struct sdhci_pci_slot {
7272
bool cd_override_level;
7373

7474
void (*hw_reset)(struct sdhci_host *host);
75+
int (*select_drive_strength)(struct sdhci_host *host,
76+
struct mmc_card *card,
77+
unsigned int max_dtr, int host_drv,
78+
int card_drv, int *drv_type);
7579
};
7680

7781
struct sdhci_pci_chip {

include/linux/mmc/sdhci-pci-data.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ struct sdhci_pci_data {
1515
extern struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev,
1616
int slotno);
1717

18+
extern int sdhci_pci_spt_drive_strength;
19+
1820
#endif

0 commit comments

Comments
 (0)