101acf691SAdam Lee /*
201acf691SAdam Lee  * Copyright (C) 2013 BayHub Technology Ltd.
301acf691SAdam Lee  *
401acf691SAdam Lee  * Authors: Peter Guo <peter.guo@bayhubtech.com>
501acf691SAdam Lee  *          Adam Lee <adam.lee@canonical.com>
657322d54Sernest.zhang  *          Ernest Zhang <ernest.zhang@bayhubtech.com>
701acf691SAdam Lee  *
801acf691SAdam Lee  * This software is licensed under the terms of the GNU General Public
901acf691SAdam Lee  * License version 2, as published by the Free Software Foundation, and
1001acf691SAdam Lee  * may be copied, distributed, and modified under those terms.
1101acf691SAdam Lee  *
1201acf691SAdam Lee  * This program is distributed in the hope that it will be useful,
1301acf691SAdam Lee  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1401acf691SAdam Lee  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1501acf691SAdam Lee  * GNU General Public License for more details.
1601acf691SAdam Lee  *
1701acf691SAdam Lee  */
1801acf691SAdam Lee 
1901acf691SAdam Lee #include <linux/pci.h>
200086fc21Sernest.zhang #include <linux/mmc/host.h>
210086fc21Sernest.zhang #include <linux/mmc/mmc.h>
220086fc21Sernest.zhang #include <linux/delay.h>
2301acf691SAdam Lee 
2401acf691SAdam Lee #include "sdhci.h"
2501acf691SAdam Lee #include "sdhci-pci.h"
26361eeda0SAdrian Hunter 
27361eeda0SAdrian Hunter /*
28361eeda0SAdrian Hunter  * O2Micro device registers
29361eeda0SAdrian Hunter  */
30361eeda0SAdrian Hunter 
31361eeda0SAdrian Hunter #define O2_SD_MISC_REG5		0x64
32361eeda0SAdrian Hunter #define O2_SD_LD0_CTRL		0x68
33361eeda0SAdrian Hunter #define O2_SD_DEV_CTRL		0x88
34361eeda0SAdrian Hunter #define O2_SD_LOCK_WP		0xD3
35361eeda0SAdrian Hunter #define O2_SD_TEST_REG		0xD4
36361eeda0SAdrian Hunter #define O2_SD_FUNC_REG0		0xDC
37361eeda0SAdrian Hunter #define O2_SD_MULTI_VCC3V	0xEE
38361eeda0SAdrian Hunter #define O2_SD_CLKREQ		0xEC
39361eeda0SAdrian Hunter #define O2_SD_CAPS		0xE0
40361eeda0SAdrian Hunter #define O2_SD_ADMA1		0xE2
41361eeda0SAdrian Hunter #define O2_SD_ADMA2		0xE7
42361eeda0SAdrian Hunter #define O2_SD_INF_MOD		0xF1
43361eeda0SAdrian Hunter #define O2_SD_MISC_CTRL4	0xFC
44361eeda0SAdrian Hunter #define O2_SD_TUNING_CTRL	0x300
45361eeda0SAdrian Hunter #define O2_SD_PLL_SETTING	0x304
4657322d54Sernest.zhang #define O2_SD_MISC_SETTING	0x308
47361eeda0SAdrian Hunter #define O2_SD_CLK_SETTING	0x328
48361eeda0SAdrian Hunter #define O2_SD_CAP_REG2		0x330
49361eeda0SAdrian Hunter #define O2_SD_CAP_REG0		0x334
50361eeda0SAdrian Hunter #define O2_SD_UHS1_CAP_SETTING	0x33C
51361eeda0SAdrian Hunter #define O2_SD_DELAY_CTRL	0x350
52361eeda0SAdrian Hunter #define O2_SD_UHS2_L1_CTRL	0x35C
53361eeda0SAdrian Hunter #define O2_SD_FUNC_REG3		0x3E0
54361eeda0SAdrian Hunter #define O2_SD_FUNC_REG4		0x3E4
55361eeda0SAdrian Hunter #define O2_SD_LED_ENABLE	BIT(6)
56361eeda0SAdrian Hunter #define O2_SD_FREG0_LEDOFF	BIT(13)
57361eeda0SAdrian Hunter #define O2_SD_FREG4_ENABLE_CLK_SET	BIT(22)
58361eeda0SAdrian Hunter 
59361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING	0x110
60361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING2	0x1C8
610086fc21Sernest.zhang #define O2_SD_HW_TUNING_DISABLE	BIT(4)
620086fc21Sernest.zhang 
630086fc21Sernest.zhang static void sdhci_o2_set_tuning_mode(struct sdhci_host *host)
640086fc21Sernest.zhang {
650086fc21Sernest.zhang 	u16 reg;
660086fc21Sernest.zhang 
670086fc21Sernest.zhang 	/* enable hardware tuning */
680086fc21Sernest.zhang 	reg = sdhci_readw(host, O2_SD_VENDOR_SETTING);
690086fc21Sernest.zhang 	reg &= ~O2_SD_HW_TUNING_DISABLE;
700086fc21Sernest.zhang 	sdhci_writew(host, reg, O2_SD_VENDOR_SETTING);
710086fc21Sernest.zhang }
720086fc21Sernest.zhang 
730086fc21Sernest.zhang static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode)
740086fc21Sernest.zhang {
750086fc21Sernest.zhang 	int i;
760086fc21Sernest.zhang 
770086fc21Sernest.zhang 	sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200);
780086fc21Sernest.zhang 
790086fc21Sernest.zhang 	for (i = 0; i < 150; i++) {
800086fc21Sernest.zhang 		u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
810086fc21Sernest.zhang 
820086fc21Sernest.zhang 		if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
830086fc21Sernest.zhang 			if (ctrl & SDHCI_CTRL_TUNED_CLK) {
840086fc21Sernest.zhang 				host->tuning_done = true;
850086fc21Sernest.zhang 				return;
860086fc21Sernest.zhang 			}
870086fc21Sernest.zhang 			pr_warn("%s: HW tuning failed !\n",
880086fc21Sernest.zhang 				mmc_hostname(host->mmc));
890086fc21Sernest.zhang 			break;
900086fc21Sernest.zhang 		}
910086fc21Sernest.zhang 
920086fc21Sernest.zhang 		mdelay(1);
930086fc21Sernest.zhang 	}
940086fc21Sernest.zhang 
950086fc21Sernest.zhang 	pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
960086fc21Sernest.zhang 		mmc_hostname(host->mmc));
970086fc21Sernest.zhang 	sdhci_reset_tuning(host);
980086fc21Sernest.zhang }
990086fc21Sernest.zhang 
1000086fc21Sernest.zhang static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode)
1010086fc21Sernest.zhang {
1020086fc21Sernest.zhang 	struct sdhci_host *host = mmc_priv(mmc);
1030086fc21Sernest.zhang 	int current_bus_width = 0;
1040086fc21Sernest.zhang 
1050086fc21Sernest.zhang 	/*
1060086fc21Sernest.zhang 	 * This handler only implements the eMMC tuning that is specific to
1070086fc21Sernest.zhang 	 * this controller.  Fall back to the standard method for other TIMING.
1080086fc21Sernest.zhang 	 */
1090086fc21Sernest.zhang 	if (host->timing != MMC_TIMING_MMC_HS200)
1100086fc21Sernest.zhang 		return sdhci_execute_tuning(mmc, opcode);
1110086fc21Sernest.zhang 
1120086fc21Sernest.zhang 	if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200))
1130086fc21Sernest.zhang 		return -EINVAL;
1140086fc21Sernest.zhang 
1150086fc21Sernest.zhang 	/*
1160086fc21Sernest.zhang 	 * o2 sdhci host didn't support 8bit emmc tuning
1170086fc21Sernest.zhang 	 */
1180086fc21Sernest.zhang 	if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
1190086fc21Sernest.zhang 		current_bus_width = mmc->ios.bus_width;
1200086fc21Sernest.zhang 		sdhci_set_bus_width(host, MMC_BUS_WIDTH_4);
1210086fc21Sernest.zhang 	}
1220086fc21Sernest.zhang 
1230086fc21Sernest.zhang 	sdhci_o2_set_tuning_mode(host);
1240086fc21Sernest.zhang 
1250086fc21Sernest.zhang 	sdhci_start_tuning(host);
1260086fc21Sernest.zhang 
1270086fc21Sernest.zhang 	__sdhci_o2_execute_tuning(host, opcode);
1280086fc21Sernest.zhang 
1290086fc21Sernest.zhang 	sdhci_end_tuning(host);
1300086fc21Sernest.zhang 
1310086fc21Sernest.zhang 	if (current_bus_width == MMC_BUS_WIDTH_8)
1320086fc21Sernest.zhang 		sdhci_set_bus_width(host, current_bus_width);
1330086fc21Sernest.zhang 
1340086fc21Sernest.zhang 	host->flags &= ~SDHCI_HS400_TUNING;
1350086fc21Sernest.zhang 	return 0;
1360086fc21Sernest.zhang }
13701acf691SAdam Lee 
138706adf6bSPeter Guo static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value)
139706adf6bSPeter Guo {
140706adf6bSPeter Guo 	u32 scratch_32;
141706adf6bSPeter Guo 	pci_read_config_dword(chip->pdev,
142706adf6bSPeter Guo 			      O2_SD_PLL_SETTING, &scratch_32);
143706adf6bSPeter Guo 
144706adf6bSPeter Guo 	scratch_32 &= 0x0000FFFF;
145706adf6bSPeter Guo 	scratch_32 |= value;
146706adf6bSPeter Guo 
147706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
148706adf6bSPeter Guo 			       O2_SD_PLL_SETTING, scratch_32);
149706adf6bSPeter Guo }
150706adf6bSPeter Guo 
151706adf6bSPeter Guo static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
152706adf6bSPeter Guo {
153706adf6bSPeter Guo 	int ret;
154706adf6bSPeter Guo 	u32 scratch_32;
155706adf6bSPeter Guo 
156706adf6bSPeter Guo 	/* Set led of SD host function enable */
157706adf6bSPeter Guo 	ret = pci_read_config_dword(chip->pdev,
158706adf6bSPeter Guo 				    O2_SD_FUNC_REG0, &scratch_32);
159706adf6bSPeter Guo 	if (ret)
160706adf6bSPeter Guo 		return;
161706adf6bSPeter Guo 
162706adf6bSPeter Guo 	scratch_32 &= ~O2_SD_FREG0_LEDOFF;
163706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
164706adf6bSPeter Guo 			       O2_SD_FUNC_REG0, scratch_32);
165706adf6bSPeter Guo 
166706adf6bSPeter Guo 	ret = pci_read_config_dword(chip->pdev,
167706adf6bSPeter Guo 				    O2_SD_TEST_REG, &scratch_32);
168706adf6bSPeter Guo 	if (ret)
169706adf6bSPeter Guo 		return;
170706adf6bSPeter Guo 
171706adf6bSPeter Guo 	scratch_32 |= O2_SD_LED_ENABLE;
172706adf6bSPeter Guo 	pci_write_config_dword(chip->pdev,
173706adf6bSPeter Guo 			       O2_SD_TEST_REG, scratch_32);
174706adf6bSPeter Guo 
175706adf6bSPeter Guo }
176706adf6bSPeter Guo 
177f0cbd780SBen Hutchings static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
17801acf691SAdam Lee {
17901acf691SAdam Lee 	u32 scratch_32;
18001acf691SAdam Lee 	int ret;
18101acf691SAdam Lee 	/* Improve write performance for SD3.0 */
18201acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32);
18301acf691SAdam Lee 	if (ret)
18401acf691SAdam Lee 		return;
18501acf691SAdam Lee 	scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14));
18601acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32);
18701acf691SAdam Lee 
18801acf691SAdam Lee 	/* Enable Link abnormal reset generating Reset */
18901acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32);
19001acf691SAdam Lee 	if (ret)
19101acf691SAdam Lee 		return;
19201acf691SAdam Lee 	scratch_32 &= ~((1 << 19) | (1 << 11));
19301acf691SAdam Lee 	scratch_32 |= (1 << 10);
19401acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32);
19501acf691SAdam Lee 
19601acf691SAdam Lee 	/* set card power over current protection */
19701acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32);
19801acf691SAdam Lee 	if (ret)
19901acf691SAdam Lee 		return;
20001acf691SAdam Lee 	scratch_32 |= (1 << 4);
20101acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32);
20201acf691SAdam Lee 
20301acf691SAdam Lee 	/* adjust the output delay for SD mode */
20401acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492);
20501acf691SAdam Lee 
20601acf691SAdam Lee 	/* Set the output voltage setting of Aux 1.2v LDO */
20701acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32);
20801acf691SAdam Lee 	if (ret)
20901acf691SAdam Lee 		return;
21001acf691SAdam Lee 	scratch_32 &= ~(3 << 12);
21101acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32);
21201acf691SAdam Lee 
21301acf691SAdam Lee 	/* Set Max power supply capability of SD host */
21401acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32);
21501acf691SAdam Lee 	if (ret)
21601acf691SAdam Lee 		return;
21701acf691SAdam Lee 	scratch_32 &= ~(0x01FE);
21801acf691SAdam Lee 	scratch_32 |= 0x00CC;
21901acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32);
22001acf691SAdam Lee 	/* Set DLL Tuning Window */
22101acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
22201acf691SAdam Lee 				    O2_SD_TUNING_CTRL, &scratch_32);
22301acf691SAdam Lee 	if (ret)
22401acf691SAdam Lee 		return;
22501acf691SAdam Lee 	scratch_32 &= ~(0x000000FF);
22601acf691SAdam Lee 	scratch_32 |= 0x00000066;
22701acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32);
22801acf691SAdam Lee 
22901acf691SAdam Lee 	/* Set UHS2 T_EIDLE */
23001acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
23101acf691SAdam Lee 				    O2_SD_UHS2_L1_CTRL, &scratch_32);
23201acf691SAdam Lee 	if (ret)
23301acf691SAdam Lee 		return;
23401acf691SAdam Lee 	scratch_32 &= ~(0x000000FC);
23501acf691SAdam Lee 	scratch_32 |= 0x00000084;
23601acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32);
23701acf691SAdam Lee 
23801acf691SAdam Lee 	/* Set UHS2 Termination */
23901acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32);
24001acf691SAdam Lee 	if (ret)
24101acf691SAdam Lee 		return;
24201acf691SAdam Lee 	scratch_32 &= ~((1 << 21) | (1 << 30));
24301acf691SAdam Lee 
24401acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32);
24501acf691SAdam Lee 
24601acf691SAdam Lee 	/* Set L1 Entrance Timer */
24701acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32);
24801acf691SAdam Lee 	if (ret)
24901acf691SAdam Lee 		return;
25001acf691SAdam Lee 	scratch_32 &= ~(0xf0000000);
25101acf691SAdam Lee 	scratch_32 |= 0x30000000;
25201acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32);
25301acf691SAdam Lee 
25401acf691SAdam Lee 	ret = pci_read_config_dword(chip->pdev,
25501acf691SAdam Lee 				    O2_SD_MISC_CTRL4, &scratch_32);
25601acf691SAdam Lee 	if (ret)
25701acf691SAdam Lee 		return;
25801acf691SAdam Lee 	scratch_32 &= ~(0x000f0000);
25901acf691SAdam Lee 	scratch_32 |= 0x00080000;
26001acf691SAdam Lee 	pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32);
26101acf691SAdam Lee }
26201acf691SAdam Lee 
26302a3c0bdSernest.zhang static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip,
26402a3c0bdSernest.zhang 				    struct sdhci_host *host)
26502a3c0bdSernest.zhang {
26602a3c0bdSernest.zhang 	int ret;
26702a3c0bdSernest.zhang 
26802a3c0bdSernest.zhang 	ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI);
26902a3c0bdSernest.zhang 	if (!ret) {
27002a3c0bdSernest.zhang 		pr_info("%s: unsupport msi, use INTx irq\n",
27102a3c0bdSernest.zhang 			mmc_hostname(host->mmc));
27202a3c0bdSernest.zhang 		return;
27302a3c0bdSernest.zhang 	}
27402a3c0bdSernest.zhang 
27502a3c0bdSernest.zhang 	ret = pci_alloc_irq_vectors(chip->pdev, 1, 1,
27602a3c0bdSernest.zhang 				    PCI_IRQ_MSI | PCI_IRQ_MSIX);
27702a3c0bdSernest.zhang 	if (ret < 0) {
27802a3c0bdSernest.zhang 		pr_err("%s: enable PCI MSI failed, err=%d\n",
27902a3c0bdSernest.zhang 		       mmc_hostname(host->mmc), ret);
28002a3c0bdSernest.zhang 		return;
28102a3c0bdSernest.zhang 	}
28202a3c0bdSernest.zhang 
28302a3c0bdSernest.zhang 	host->irq = pci_irq_vector(chip->pdev, 0);
28402a3c0bdSernest.zhang }
28502a3c0bdSernest.zhang 
28601acf691SAdam Lee int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
28701acf691SAdam Lee {
28801acf691SAdam Lee 	struct sdhci_pci_chip *chip;
28901acf691SAdam Lee 	struct sdhci_host *host;
29001acf691SAdam Lee 	u32 reg;
29157322d54Sernest.zhang 	int ret;
29201acf691SAdam Lee 
29301acf691SAdam Lee 	chip = slot->chip;
29401acf691SAdam Lee 	host = slot->host;
29501acf691SAdam Lee 	switch (chip->pdev->device) {
29601acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS0:
29701acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD0:
29801acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD1:
29901acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS1:
30001acf691SAdam Lee 	case PCI_DEVICE_ID_O2_FUJIN2:
30101acf691SAdam Lee 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING);
30201acf691SAdam Lee 		if (reg & 0x1)
30301acf691SAdam Lee 			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
30401acf691SAdam Lee 
30502a3c0bdSernest.zhang 		sdhci_pci_o2_enable_msi(chip, host);
30602a3c0bdSernest.zhang 
30757322d54Sernest.zhang 		if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) {
30857322d54Sernest.zhang 			ret = pci_read_config_dword(chip->pdev,
30957322d54Sernest.zhang 						    O2_SD_MISC_SETTING, &reg);
31057322d54Sernest.zhang 			if (ret)
31157322d54Sernest.zhang 				return -EIO;
31257322d54Sernest.zhang 			if (reg & (1 << 4)) {
31357322d54Sernest.zhang 				pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n",
31457322d54Sernest.zhang 					mmc_hostname(host->mmc));
31557322d54Sernest.zhang 				host->flags &= ~SDHCI_SIGNALING_330;
31657322d54Sernest.zhang 				host->flags |= SDHCI_SIGNALING_180;
31757322d54Sernest.zhang 				host->mmc->caps2 |= MMC_CAP2_NO_SD;
31857322d54Sernest.zhang 				host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
31957322d54Sernest.zhang 			}
32057322d54Sernest.zhang 		}
32157322d54Sernest.zhang 
3220086fc21Sernest.zhang 		host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning;
3230086fc21Sernest.zhang 
32401acf691SAdam Lee 		if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2)
32501acf691SAdam Lee 			break;
32601acf691SAdam Lee 		/* set dll watch dog timer */
32701acf691SAdam Lee 		reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2);
32801acf691SAdam Lee 		reg |= (1 << 12);
32901acf691SAdam Lee 		sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2);
33001acf691SAdam Lee 
33101acf691SAdam Lee 		break;
33201acf691SAdam Lee 	default:
33301acf691SAdam Lee 		break;
33401acf691SAdam Lee 	}
33501acf691SAdam Lee 
33601acf691SAdam Lee 	return 0;
33701acf691SAdam Lee }
33801acf691SAdam Lee 
33901acf691SAdam Lee int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
34001acf691SAdam Lee {
34101acf691SAdam Lee 	int ret;
34201acf691SAdam Lee 	u8 scratch;
34301acf691SAdam Lee 	u32 scratch_32;
34401acf691SAdam Lee 
34501acf691SAdam Lee 	switch (chip->pdev->device) {
34601acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8220:
34701acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8221:
34801acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8320:
34901acf691SAdam Lee 	case PCI_DEVICE_ID_O2_8321:
35001acf691SAdam Lee 		/* This extra setup is required due to broken ADMA. */
35101acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
35201acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
35301acf691SAdam Lee 		if (ret)
35401acf691SAdam Lee 			return ret;
35501acf691SAdam Lee 		scratch &= 0x7f;
35601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
35701acf691SAdam Lee 
35801acf691SAdam Lee 		/* Set Multi 3 to VCC3V# */
35901acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
36001acf691SAdam Lee 
36101acf691SAdam Lee 		/* Disable CLK_REQ# support after media DET */
36201acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
36301acf691SAdam Lee 				O2_SD_CLKREQ, &scratch);
36401acf691SAdam Lee 		if (ret)
36501acf691SAdam Lee 			return ret;
36601acf691SAdam Lee 		scratch |= 0x20;
36701acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
36801acf691SAdam Lee 
36901acf691SAdam Lee 		/* Choose capabilities, enable SDMA.  We have to write 0x01
37001acf691SAdam Lee 		 * to the capabilities register first to unlock it.
37101acf691SAdam Lee 		 */
37201acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
37301acf691SAdam Lee 		if (ret)
37401acf691SAdam Lee 			return ret;
37501acf691SAdam Lee 		scratch |= 0x01;
37601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
37701acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
37801acf691SAdam Lee 
37901acf691SAdam Lee 		/* Disable ADMA1/2 */
38001acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
38101acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
38201acf691SAdam Lee 
38301acf691SAdam Lee 		/* Disable the infinite transfer mode */
38401acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
38501acf691SAdam Lee 				O2_SD_INF_MOD, &scratch);
38601acf691SAdam Lee 		if (ret)
38701acf691SAdam Lee 			return ret;
38801acf691SAdam Lee 		scratch |= 0x08;
38901acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
39001acf691SAdam Lee 
39101acf691SAdam Lee 		/* Lock WP */
39201acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
39301acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
39401acf691SAdam Lee 		if (ret)
39501acf691SAdam Lee 			return ret;
39601acf691SAdam Lee 		scratch |= 0x80;
39701acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
39801acf691SAdam Lee 		break;
39901acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS0:
40001acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SDS1:
40101acf691SAdam Lee 	case PCI_DEVICE_ID_O2_FUJIN2:
40201acf691SAdam Lee 		/* UnLock WP */
40301acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
40401acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
40501acf691SAdam Lee 		if (ret)
40601acf691SAdam Lee 			return ret;
40701acf691SAdam Lee 
40801acf691SAdam Lee 		scratch &= 0x7f;
40901acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
41001acf691SAdam Lee 
411706adf6bSPeter Guo 		/* DevId=8520 subId= 0x11 or 0x12  Type Chip support */
412706adf6bSPeter Guo 		if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) {
413706adf6bSPeter Guo 			ret = pci_read_config_dword(chip->pdev,
414706adf6bSPeter Guo 						    O2_SD_FUNC_REG0,
415706adf6bSPeter Guo 						    &scratch_32);
416706adf6bSPeter Guo 			scratch_32 = ((scratch_32 & 0xFF000000) >> 24);
417706adf6bSPeter Guo 
418706adf6bSPeter Guo 			/* Check Whether subId is 0x11 or 0x12 */
419706adf6bSPeter Guo 			if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) {
4203665ff03Sernest.zhang 				scratch_32 = 0x25100000;
421706adf6bSPeter Guo 
422706adf6bSPeter Guo 				o2_pci_set_baseclk(chip, scratch_32);
423706adf6bSPeter Guo 				ret = pci_read_config_dword(chip->pdev,
424706adf6bSPeter Guo 							    O2_SD_FUNC_REG4,
425706adf6bSPeter Guo 							    &scratch_32);
426706adf6bSPeter Guo 
427706adf6bSPeter Guo 				/* Enable Base Clk setting change */
428706adf6bSPeter Guo 				scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET;
429706adf6bSPeter Guo 				pci_write_config_dword(chip->pdev,
430706adf6bSPeter Guo 						       O2_SD_FUNC_REG4,
431706adf6bSPeter Guo 						       scratch_32);
432706adf6bSPeter Guo 
433706adf6bSPeter Guo 				/* Set Tuning Window to 4 */
434706adf6bSPeter Guo 				pci_write_config_byte(chip->pdev,
435706adf6bSPeter Guo 						      O2_SD_TUNING_CTRL, 0x44);
436706adf6bSPeter Guo 
437706adf6bSPeter Guo 				break;
438706adf6bSPeter Guo 			}
439706adf6bSPeter Guo 		}
440706adf6bSPeter Guo 
441706adf6bSPeter Guo 		/* Enable 8520 led function */
442706adf6bSPeter Guo 		o2_pci_led_enable(chip);
443706adf6bSPeter Guo 
44401acf691SAdam Lee 		/* Set timeout CLK */
44501acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
44601acf691SAdam Lee 					    O2_SD_CLK_SETTING, &scratch_32);
44701acf691SAdam Lee 		if (ret)
44801acf691SAdam Lee 			return ret;
44901acf691SAdam Lee 
45001acf691SAdam Lee 		scratch_32 &= ~(0xFF00);
45101acf691SAdam Lee 		scratch_32 |= 0x07E0C800;
45201acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
45301acf691SAdam Lee 				       O2_SD_CLK_SETTING, scratch_32);
45401acf691SAdam Lee 
45501acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
45601acf691SAdam Lee 					    O2_SD_CLKREQ, &scratch_32);
45701acf691SAdam Lee 		if (ret)
45801acf691SAdam Lee 			return ret;
45901acf691SAdam Lee 		scratch_32 |= 0x3;
46001acf691SAdam Lee 		pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32);
46101acf691SAdam Lee 
46201acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
46301acf691SAdam Lee 					    O2_SD_PLL_SETTING, &scratch_32);
46401acf691SAdam Lee 		if (ret)
46501acf691SAdam Lee 			return ret;
46601acf691SAdam Lee 
46701acf691SAdam Lee 		scratch_32 &= ~(0x1F3F070E);
46801acf691SAdam Lee 		scratch_32 |= 0x18270106;
46901acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
47001acf691SAdam Lee 				       O2_SD_PLL_SETTING, scratch_32);
47101acf691SAdam Lee 
47201acf691SAdam Lee 		/* Disable UHS1 funciton */
47301acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
47401acf691SAdam Lee 					    O2_SD_CAP_REG2, &scratch_32);
47501acf691SAdam Lee 		if (ret)
47601acf691SAdam Lee 			return ret;
47701acf691SAdam Lee 		scratch_32 &= ~(0xE0);
47801acf691SAdam Lee 		pci_write_config_dword(chip->pdev,
47901acf691SAdam Lee 				       O2_SD_CAP_REG2, scratch_32);
48001acf691SAdam Lee 
48101acf691SAdam Lee 		if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2)
48201acf691SAdam Lee 			sdhci_pci_o2_fujin2_pci_init(chip);
48301acf691SAdam Lee 
48401acf691SAdam Lee 		/* Lock WP */
48501acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
48601acf691SAdam Lee 					   O2_SD_LOCK_WP, &scratch);
48701acf691SAdam Lee 		if (ret)
48801acf691SAdam Lee 			return ret;
48901acf691SAdam Lee 		scratch |= 0x80;
49001acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
49101acf691SAdam Lee 		break;
49201acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD0:
49301acf691SAdam Lee 	case PCI_DEVICE_ID_O2_SEABIRD1:
49401acf691SAdam Lee 		/* UnLock WP */
49501acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
49601acf691SAdam Lee 				O2_SD_LOCK_WP, &scratch);
49701acf691SAdam Lee 		if (ret)
49801acf691SAdam Lee 			return ret;
49901acf691SAdam Lee 
50001acf691SAdam Lee 		scratch &= 0x7f;
50101acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
50201acf691SAdam Lee 
50301acf691SAdam Lee 		ret = pci_read_config_dword(chip->pdev,
504706adf6bSPeter Guo 					    O2_SD_PLL_SETTING, &scratch_32);
50501acf691SAdam Lee 
50601acf691SAdam Lee 		if ((scratch_32 & 0xff000000) == 0x01000000) {
50701acf691SAdam Lee 			scratch_32 &= 0x0000FFFF;
50801acf691SAdam Lee 			scratch_32 |= 0x1F340000;
50901acf691SAdam Lee 
51001acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
51101acf691SAdam Lee 					       O2_SD_PLL_SETTING, scratch_32);
51201acf691SAdam Lee 		} else {
51301acf691SAdam Lee 			scratch_32 &= 0x0000FFFF;
5143665ff03Sernest.zhang 			scratch_32 |= 0x25100000;
51501acf691SAdam Lee 
51601acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
51701acf691SAdam Lee 					       O2_SD_PLL_SETTING, scratch_32);
51801acf691SAdam Lee 
51901acf691SAdam Lee 			ret = pci_read_config_dword(chip->pdev,
52001acf691SAdam Lee 						    O2_SD_FUNC_REG4,
52101acf691SAdam Lee 						    &scratch_32);
52201acf691SAdam Lee 			scratch_32 |= (1 << 22);
52301acf691SAdam Lee 			pci_write_config_dword(chip->pdev,
52401acf691SAdam Lee 					       O2_SD_FUNC_REG4, scratch_32);
52501acf691SAdam Lee 		}
52601acf691SAdam Lee 
527706adf6bSPeter Guo 		/* Set Tuning Windows to 5 */
528706adf6bSPeter Guo 		pci_write_config_byte(chip->pdev,
529706adf6bSPeter Guo 				O2_SD_TUNING_CTRL, 0x55);
53001acf691SAdam Lee 		/* Lock WP */
53101acf691SAdam Lee 		ret = pci_read_config_byte(chip->pdev,
53201acf691SAdam Lee 					   O2_SD_LOCK_WP, &scratch);
53301acf691SAdam Lee 		if (ret)
53401acf691SAdam Lee 			return ret;
53501acf691SAdam Lee 		scratch |= 0x80;
53601acf691SAdam Lee 		pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
53701acf691SAdam Lee 		break;
53801acf691SAdam Lee 	}
53901acf691SAdam Lee 
54001acf691SAdam Lee 	return 0;
54101acf691SAdam Lee }
54201acf691SAdam Lee 
543b7813f0fSAdrian Hunter #ifdef CONFIG_PM_SLEEP
54401acf691SAdam Lee int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip)
54501acf691SAdam Lee {
54601acf691SAdam Lee 	sdhci_pci_o2_probe(chip);
54730cf2803SAdrian Hunter 	return sdhci_pci_resume_host(chip);
54801acf691SAdam Lee }
549b7813f0fSAdrian Hunter #endif
550