20
20
#include <linux/slab.h>
21
21
#include <linux/device.h>
22
22
#include <linux/mmc/host.h>
23
+ #include <linux/mmc/mmc.h>
23
24
#include <linux/scatterlist.h>
24
25
#include <linux/io.h>
25
26
#include <linux/gpio.h>
@@ -266,6 +267,69 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
266
267
usleep_range (300 , 1000 );
267
268
}
268
269
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
+
269
333
static int byt_emmc_probe_slot (struct sdhci_pci_slot * slot )
270
334
{
271
335
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)
276
340
slot -> hw_reset = sdhci_pci_int_hw_reset ;
277
341
if (slot -> chip -> pdev -> device == PCI_DEVICE_ID_INTEL_BSW_EMMC )
278
342
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
+ }
279
347
return 0 ;
280
348
}
281
349
@@ -1203,13 +1271,28 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
1203
1271
slot -> hw_reset (host );
1204
1272
}
1205
1273
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
+
1206
1288
static const struct sdhci_ops sdhci_pci_ops = {
1207
1289
.set_clock = sdhci_set_clock ,
1208
1290
.enable_dma = sdhci_pci_enable_dma ,
1209
1291
.set_bus_width = sdhci_pci_set_bus_width ,
1210
1292
.reset = sdhci_reset ,
1211
1293
.set_uhs_signaling = sdhci_set_uhs_signaling ,
1212
1294
.hw_reset = sdhci_pci_hw_reset ,
1295
+ .select_drive_strength = sdhci_pci_select_drive_strength ,
1213
1296
};
1214
1297
1215
1298
/*****************************************************************************\
0 commit comments