2023-09-27 14:35:40

by liuchang_125125

[permalink] [raw]
Subject: [PATCH V1 1/1] mmc: sdhci-pci-o2micro: Fix Bayhub SD host hardware tuning compatibility issue for BanQ card

From: Charl Liu <[email protected]>

1.Driver get the card's MID and OID by init_card callback
function to judge whether the card is BanQ card
2.Update tuning setting to make sure tuning done can be set
3.Stop transfer for CMD19 after tuning done is set to avoid data
line inhibit and then set input phase manually for BanQ card

Signed-off-by: Charl Liu <[email protected]>
---
Change in V1:
Update the tuning process to be compatibility with BanQ card.
---
drivers/mmc/host/sdhci-pci-o2micro.c | 204 ++++++++++++++++++++++++---
1 file changed, 182 insertions(+), 22 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index 7bfee28116af..ab898c583323 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -36,6 +36,7 @@
#define O2_SD_MISC_CTRL2 0xF0
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
+#define O2_SD_DLL_CTRL 0x1B0
#define O2_SD_MISC_CTRL 0x1C0
#define O2_SD_EXP_INT_REG 0x1E0
#define O2_SD_PWR_FORCE_L0 0x0002
@@ -78,7 +79,8 @@ static const u32 dmdn_table[] = {0x2B1C0000,
#define DMDN_SZ ARRAY_SIZE(dmdn_table)

struct o2_host {
- u8 dll_adjust_count;
+ u8 dll_adjust_count: 4;
+ u8 banq_card_setting: 4;
};

static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host)
@@ -311,14 +313,104 @@ static int sdhci_o2_dll_recovery(struct sdhci_host *host)
return ret;
}

+static void sdhci_o2_send_stop_transmission(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct mmc_command cmd = {};
+ struct mmc_request mrq = {};
+
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.busy_timeout = 150;
+
+ mrq.cmd = &cmd;
+
+ mmc_wait_for_req(mmc, &mrq);
+
+ /*
+ * Command CRC error may occur due to compatibility issue.
+ * It is normal and ignore it here.
+ */
+ if ((cmd.error != 0) && (cmd.error != -EILSEQ))
+ pr_err("%s: CMD12 error: %d\n", mmc_hostname(mmc), cmd.error);
+}
+
+static void sdhci_o2_tuning_setting(struct mmc_host *mmc, bool isbanq, u8 phase_num)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ struct sdhci_pci_chip *chip = slot->chip;
+ struct o2_host *o2_host = sdhci_pci_priv(slot);
+ u32 reg_val;
+
+ if (isbanq) {
+ /* update tuning command times for BanQ card */
+ pci_read_config_dword(chip->pdev, O2_SD_TUNING_CTRL, &reg_val);
+ reg_val &= 0x00FFFFFF;
+ reg_val |= 0x02000000;
+ pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, reg_val);
+ } else {
+ reg_val = sdhci_readl(host, O2_SD_DLL_CTRL);
+ reg_val &= ~BIT(28);
+ sdhci_writel(host, reg_val, O2_SD_DLL_CTRL);
+
+ /* Update tuning command times for normal card */
+ pci_read_config_dword(chip->pdev, O2_SD_TUNING_CTRL, &reg_val);
+ reg_val &= 0x00FFFFFF;
+ reg_val |= (phase_num * 3) << 24;
+ pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, reg_val);
+ }
+}
+
+static void sdhci_o2_configure_banq_best_input_phase(struct sdhci_host *host)
+{
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ struct sdhci_pci_chip *chip = slot->chip;
+
+ u32 response = 0;
+ u16 dll_phase_configure = 0;
+ u16 best_input_phase = 0;
+
+ switch (chip->pdev->device) {
+ case PCI_DEVICE_ID_O2_FUJIN2:
+ best_input_phase = 0x0;
+ break;
+
+ case PCI_DEVICE_ID_O2_SEABIRD0:
+ case PCI_DEVICE_ID_O2_SEABIRD1:
+ best_input_phase = 0x0;
+ break;
+
+ case PCI_DEVICE_ID_O2_GG8_9860:
+ case PCI_DEVICE_ID_O2_GG8_9861:
+ case PCI_DEVICE_ID_O2_GG8_9862:
+ case PCI_DEVICE_ID_O2_GG8_9863:
+ best_input_phase = 0xB;
+ break;
+
+ default:
+ break;
+ }
+
+ /* configure the best input phase (0xB) for BanQ card */
+ dll_phase_configure = sdhci_readw(host, 0x1B2);
+ dll_phase_configure = (dll_phase_configure & (u16)0xF0FF) |
+ (best_input_phase << 8) | BIT(12);
+ sdhci_writew(host, dll_phase_configure, 0x1B2);
+}
+
static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct sdhci_pci_chip *chip = slot->chip;
+ struct mmc_card *card = mmc->card;
+ struct o2_host *o2_host = sdhci_pci_priv(slot);
int current_bus_width = 0;
u32 scratch32 = 0;
+ u16 data_timeout_counter_value = 0;
u16 scratch = 0;
+ u8 phase_num = 0;
u8 scratch_8 = 0;
u32 reg_val;

@@ -334,6 +426,31 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (WARN_ON(!mmc_op_tuning(opcode)))
return -EINVAL;

+ if ((chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9860) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9861) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9862) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9863)) {
+ phase_num = 14;
+ } else {
+ phase_num = 11;
+ }
+
+ /* UnLock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
+ scratch_8 &= 0x7f;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
+
+ sdhci_o2_tuning_setting(mmc, (bool)o2_host->banq_card_setting, phase_num);
+
+ if (o2_host->banq_card_setting) {
+ /*
+ * set data timeout counter value to 0 to ensure that
+ * the tuning process can be completed
+ */
+ data_timeout_counter_value = sdhci_readw(host, SDHCI_TIMEOUT_CONTROL);
+ sdhci_writew(host, data_timeout_counter_value & (u16)0xFFF0, SDHCI_TIMEOUT_CONTROL);
+ }
+
/* Force power mode enter L0 */
scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
scratch |= O2_SD_PWR_FORCE_L0;
@@ -351,23 +468,13 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
reg_val &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);

- if (host->timing == MMC_TIMING_MMC_HS200 ||
- host->timing == MMC_TIMING_UHS_SDR104) {
- /* UnLock WP */
- pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
- scratch_8 &= 0x7f;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
-
+ if ((host->timing == MMC_TIMING_MMC_HS200) ||
+ (host->timing == MMC_TIMING_UHS_SDR104)) {
/* Set pcr 0x354[16] to choose dll clock, and set the default phase */
pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &reg_val);
reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE);
pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val);
-
- /* Lock WP */
- pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
- scratch_8 |= 0x80;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
}

/* Start clk */
@@ -375,10 +482,19 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
reg_val |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
break;
+ case PCI_DEVICE_ID_O2_GG8_9860:
+ case PCI_DEVICE_ID_O2_GG8_9861:
+ case PCI_DEVICE_ID_O2_GG8_9862:
+ case PCI_DEVICE_ID_O2_GG8_9863:
default:
break;
}

+ /* Lock WP */
+ pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
+ scratch_8 |= 0x80;
+ pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
+
/* wait DLL lock, timeout value 5ms */
if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000))
@@ -416,6 +532,20 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_set_bus_width(host, current_bus_width);
}

+ /* update input phase for BanQ card */
+ if (o2_host->banq_card_setting) {
+ /* recover the data timeout counter value */
+ sdhci_writew(host, data_timeout_counter_value, SDHCI_TIMEOUT_CONTROL);
+
+ /*
+ * Stop transfer for CMD19 after tuning done is set to
+ * avoid data line inhibit
+ */
+ sdhci_o2_send_stop_transmission(host);
+
+ sdhci_o2_configure_banq_best_input_phase(host);
+ }
+
/* Cancel force power mode enter L0 */
scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
scratch &= ~(O2_SD_PWR_FORCE_L0);
@@ -428,6 +558,24 @@ static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
return 0;
}

+static void sdhci_o2_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pci_slot *slot = sdhci_priv(host);
+ struct o2_host *o2_host = sdhci_pci_priv(slot);
+ unsigned int manfid;
+ unsigned short oemid;
+
+ manfid = card->raw_cid[0] >> 24;
+ oemid = (card->raw_cid[0] >> 8) & 0xFFFF;
+
+ /* judge whether the card is BanQ card */
+ if (manfid == 0x89 && oemid == 0x303)
+ o2_host->banq_card_setting = 1;
+ else
+ o2_host->banq_card_setting = 0;
+}
+
static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
{
int ret;
@@ -596,15 +744,20 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
scratch &= 0x7f;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);

- if (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9860 ||
- chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9861 ||
- chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9862 ||
- chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9863) {
+ if ((chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9860) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9861) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9862) ||
+ (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9863)) {
dmdn_208m = 0x2c500000;
dmdn_200m = 0x25200000;
} else {
dmdn_208m = 0x2c280000;
dmdn_200m = 0x25100000;
+
+ /* open-clock for old project */
+ pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
+ scratch_32 &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
+ pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32);
}

if ((host->timing == MMC_TIMING_UHS_SDR104) && (clock == 200000000)) {
@@ -619,10 +772,6 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
o2_pci_set_baseclk(chip, dmdn_200m);
}

- pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
- scratch_32 &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
- pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32);
-
/* Lock WP */
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
scratch |= 0x80;
@@ -632,6 +781,11 @@ static void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_o2_enable_clk(host, clk);
}

+static void sdhci_o2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ sdhci_writeb(host, 0x0E, SDHCI_TIMEOUT_CONTROL);
+}
+
static int sdhci_pci_o2_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
@@ -705,6 +859,7 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
host = slot->host;

o2_host->dll_adjust_count = 0;
+ o2_host->banq_card_setting = 0;
caps = sdhci_readl(host, SDHCI_CAPABILITIES);

/*
@@ -718,7 +873,9 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)

sdhci_pci_o2_enable_msi(chip, host);

+ host->mmc_host_ops.init_card = sdhci_o2_init_card;
host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
+
switch (chip->pdev->device) {
case PCI_DEVICE_ID_O2_SDS0:
case PCI_DEVICE_ID_O2_SEABIRD0:
@@ -770,6 +927,8 @@ static int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd;
host->mmc_host_ops.init_sd_express = sdhci_pci_o2_init_sd_express;
+
+ sdhci_writel(host, 0xFFFFFFFF, SDHCI_INT_STATUS);
break;
default:
break;
@@ -1022,7 +1181,7 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
/* Set output delay*/
pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &scratch_32);
scratch_32 &= 0xFF0FFF00;
- scratch_32 |= 0x00B0003B;
+ scratch_32 |= 0x00B000CB;
pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, scratch_32);

/* Lock WP */
@@ -1051,6 +1210,7 @@ static const struct sdhci_ops sdhci_pci_o2_ops = {
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_timeout = sdhci_o2_set_timeout,
};

const struct sdhci_pci_fixes sdhci_o2 = {

base-commit: 0e945134b680040b8613e962f586d91b6d40292d
--
2.34.1


2023-09-28 06:56:46

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH V1 1/1] mmc: sdhci-pci-o2micro: Fix Bayhub SD host hardware tuning compatibility issue for BanQ card

Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 0e945134b680040b8613e962f586d91b6d40292d]

url: https://github.com/intel-lab-lkp/linux/commits/liuchang_125125-163-com/mmc-sdhci-pci-o2micro-Fix-Bayhub-SD-host-hardware-tuning-compatibility-issue-for-BanQ-card/20230927-203005
base: 0e945134b680040b8613e962f586d91b6d40292d
patch link: https://lore.kernel.org/r/20230927122652.4969-1-liuchang_125125%40163.com
patch subject: [PATCH V1 1/1] mmc: sdhci-pci-o2micro: Fix Bayhub SD host hardware tuning compatibility issue for BanQ card
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20230928/[email protected]/config)
compiler: alpha-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230928/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

drivers/mmc/host/sdhci-pci-o2micro.c: In function 'sdhci_o2_tuning_setting':
>> drivers/mmc/host/sdhci-pci-o2micro.c:343:25: warning: unused variable 'o2_host' [-Wunused-variable]
343 | struct o2_host *o2_host = sdhci_pci_priv(slot);
| ^~~~~~~
drivers/mmc/host/sdhci-pci-o2micro.c: In function 'sdhci_o2_configure_banq_best_input_phase':
>> drivers/mmc/host/sdhci-pci-o2micro.c:370:13: warning: unused variable 'response' [-Wunused-variable]
370 | u32 response = 0;
| ^~~~~~~~
drivers/mmc/host/sdhci-pci-o2micro.c: In function 'sdhci_o2_execute_tuning':
>> drivers/mmc/host/sdhci-pci-o2micro.c:407:26: warning: unused variable 'card' [-Wunused-variable]
407 | struct mmc_card *card = mmc->card;
| ^~~~


vim +/o2_host +343 drivers/mmc/host/sdhci-pci-o2micro.c

337
338 static void sdhci_o2_tuning_setting(struct mmc_host *mmc, bool isbanq, u8 phase_num)
339 {
340 struct sdhci_host *host = mmc_priv(mmc);
341 struct sdhci_pci_slot *slot = sdhci_priv(host);
342 struct sdhci_pci_chip *chip = slot->chip;
> 343 struct o2_host *o2_host = sdhci_pci_priv(slot);
344 u32 reg_val;
345
346 if (isbanq) {
347 /* update tuning command times for BanQ card */
348 pci_read_config_dword(chip->pdev, O2_SD_TUNING_CTRL, &reg_val);
349 reg_val &= 0x00FFFFFF;
350 reg_val |= 0x02000000;
351 pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, reg_val);
352 } else {
353 reg_val = sdhci_readl(host, O2_SD_DLL_CTRL);
354 reg_val &= ~BIT(28);
355 sdhci_writel(host, reg_val, O2_SD_DLL_CTRL);
356
357 /* Update tuning command times for normal card */
358 pci_read_config_dword(chip->pdev, O2_SD_TUNING_CTRL, &reg_val);
359 reg_val &= 0x00FFFFFF;
360 reg_val |= (phase_num * 3) << 24;
361 pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, reg_val);
362 }
363 }
364
365 static void sdhci_o2_configure_banq_best_input_phase(struct sdhci_host *host)
366 {
367 struct sdhci_pci_slot *slot = sdhci_priv(host);
368 struct sdhci_pci_chip *chip = slot->chip;
369
> 370 u32 response = 0;
371 u16 dll_phase_configure = 0;
372 u16 best_input_phase = 0;
373
374 switch (chip->pdev->device) {
375 case PCI_DEVICE_ID_O2_FUJIN2:
376 best_input_phase = 0x0;
377 break;
378
379 case PCI_DEVICE_ID_O2_SEABIRD0:
380 case PCI_DEVICE_ID_O2_SEABIRD1:
381 best_input_phase = 0x0;
382 break;
383
384 case PCI_DEVICE_ID_O2_GG8_9860:
385 case PCI_DEVICE_ID_O2_GG8_9861:
386 case PCI_DEVICE_ID_O2_GG8_9862:
387 case PCI_DEVICE_ID_O2_GG8_9863:
388 best_input_phase = 0xB;
389 break;
390
391 default:
392 break;
393 }
394
395 /* configure the best input phase (0xB) for BanQ card */
396 dll_phase_configure = sdhci_readw(host, 0x1B2);
397 dll_phase_configure = (dll_phase_configure & (u16)0xF0FF) |
398 (best_input_phase << 8) | BIT(12);
399 sdhci_writew(host, dll_phase_configure, 0x1B2);
400 }
401
402 static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
403 {
404 struct sdhci_host *host = mmc_priv(mmc);
405 struct sdhci_pci_slot *slot = sdhci_priv(host);
406 struct sdhci_pci_chip *chip = slot->chip;
> 407 struct mmc_card *card = mmc->card;
408 struct o2_host *o2_host = sdhci_pci_priv(slot);
409 int current_bus_width = 0;
410 u32 scratch32 = 0;
411 u16 data_timeout_counter_value = 0;
412 u16 scratch = 0;
413 u8 phase_num = 0;
414 u8 scratch_8 = 0;
415 u32 reg_val;
416
417 /*
418 * This handler implements the hardware tuning that is specific to
419 * this controller. Fall back to the standard method for other TIMING.
420 */
421 if ((host->timing != MMC_TIMING_MMC_HS200) &&
422 (host->timing != MMC_TIMING_UHS_SDR104) &&
423 (host->timing != MMC_TIMING_UHS_SDR50))
424 return sdhci_execute_tuning(mmc, opcode);
425
426 if (WARN_ON(!mmc_op_tuning(opcode)))
427 return -EINVAL;
428
429 if ((chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9860) ||
430 (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9861) ||
431 (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9862) ||
432 (chip->pdev->device == PCI_DEVICE_ID_O2_GG8_9863)) {
433 phase_num = 14;
434 } else {
435 phase_num = 11;
436 }
437
438 /* UnLock WP */
439 pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
440 scratch_8 &= 0x7f;
441 pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
442
443 sdhci_o2_tuning_setting(mmc, (bool)o2_host->banq_card_setting, phase_num);
444
445 if (o2_host->banq_card_setting) {
446 /*
447 * set data timeout counter value to 0 to ensure that
448 * the tuning process can be completed
449 */
450 data_timeout_counter_value = sdhci_readw(host, SDHCI_TIMEOUT_CONTROL);
451 sdhci_writew(host, data_timeout_counter_value & (u16)0xFFF0, SDHCI_TIMEOUT_CONTROL);
452 }
453
454 /* Force power mode enter L0 */
455 scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
456 scratch |= O2_SD_PWR_FORCE_L0;
457 sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
458
459 /* Update output phase */
460 switch (chip->pdev->device) {
461 case PCI_DEVICE_ID_O2_SDS0:
462 case PCI_DEVICE_ID_O2_SEABIRD0:
463 case PCI_DEVICE_ID_O2_SEABIRD1:
464 case PCI_DEVICE_ID_O2_SDS1:
465 case PCI_DEVICE_ID_O2_FUJIN2:
466 /* Stop clk */
467 reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
468 reg_val &= ~SDHCI_CLOCK_CARD_EN;
469 sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
470
471 if ((host->timing == MMC_TIMING_MMC_HS200) ||
472 (host->timing == MMC_TIMING_UHS_SDR104)) {
473 /* Set pcr 0x354[16] to choose dll clock, and set the default phase */
474 pci_read_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, &reg_val);
475 reg_val &= ~(O2_SD_SEL_DLL | O2_SD_PHASE_MASK);
476 reg_val |= (O2_SD_SEL_DLL | O2_SD_FIX_PHASE);
477 pci_write_config_dword(chip->pdev, O2_SD_OUTPUT_CLK_SOURCE_SWITCH, reg_val);
478 }
479
480 /* Start clk */
481 reg_val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
482 reg_val |= SDHCI_CLOCK_CARD_EN;
483 sdhci_writew(host, reg_val, SDHCI_CLOCK_CONTROL);
484 break;
485 case PCI_DEVICE_ID_O2_GG8_9860:
486 case PCI_DEVICE_ID_O2_GG8_9861:
487 case PCI_DEVICE_ID_O2_GG8_9862:
488 case PCI_DEVICE_ID_O2_GG8_9863:
489 default:
490 break;
491 }
492
493 /* Lock WP */
494 pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch_8);
495 scratch_8 |= 0x80;
496 pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch_8);
497
498 /* wait DLL lock, timeout value 5ms */
499 if (readx_poll_timeout(sdhci_o2_pll_dll_wdt_control, host,
500 scratch32, (scratch32 & O2_DLL_LOCK_STATUS), 1, 5000))
501 pr_warn("%s: DLL can't lock in 5ms after force L0 during tuning.\n",
502 mmc_hostname(host->mmc));
503 /*
504 * Judge the tuning reason, whether caused by dll shift
505 * If cause by dll shift, should call sdhci_o2_dll_recovery
506 */
507 if (!sdhci_o2_wait_dll_detect_lock(host))
508 if (!sdhci_o2_dll_recovery(host)) {
509 pr_err("%s: o2 dll recovery failed\n",
510 mmc_hostname(host->mmc));
511 return -EINVAL;
512 }
513 /*
514 * o2 sdhci host didn't support 8bit emmc tuning
515 */
516 if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
517 current_bus_width = mmc->ios.bus_width;
518 mmc->ios.bus_width = MMC_BUS_WIDTH_4;
519 sdhci_set_bus_width(host, MMC_BUS_WIDTH_4);
520 }
521
522 sdhci_o2_set_tuning_mode(host);
523
524 sdhci_start_tuning(host);
525
526 __sdhci_o2_execute_tuning(host, opcode);
527
528 sdhci_end_tuning(host);
529
530 if (current_bus_width == MMC_BUS_WIDTH_8) {
531 mmc->ios.bus_width = MMC_BUS_WIDTH_8;
532 sdhci_set_bus_width(host, current_bus_width);
533 }
534
535 /* update input phase for BanQ card */
536 if (o2_host->banq_card_setting) {
537 /* recover the data timeout counter value */
538 sdhci_writew(host, data_timeout_counter_value, SDHCI_TIMEOUT_CONTROL);
539
540 /*
541 * Stop transfer for CMD19 after tuning done is set to
542 * avoid data line inhibit
543 */
544 sdhci_o2_send_stop_transmission(host);
545
546 sdhci_o2_configure_banq_best_input_phase(host);
547 }
548
549 /* Cancel force power mode enter L0 */
550 scratch = sdhci_readw(host, O2_SD_MISC_CTRL);
551 scratch &= ~(O2_SD_PWR_FORCE_L0);
552 sdhci_writew(host, scratch, O2_SD_MISC_CTRL);
553
554 sdhci_reset(host, SDHCI_RESET_CMD);
555 sdhci_reset(host, SDHCI_RESET_DATA);
556
557 host->flags &= ~SDHCI_HS400_TUNING;
558 return 0;
559 }
560

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki