19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 201acf691SAdam Lee /* 301acf691SAdam Lee * Copyright (C) 2013 BayHub Technology Ltd. 401acf691SAdam Lee * 501acf691SAdam Lee * Authors: Peter Guo <peter.guo@bayhubtech.com> 601acf691SAdam Lee * Adam Lee <adam.lee@canonical.com> 757322d54Sernest.zhang * Ernest Zhang <ernest.zhang@bayhubtech.com> 801acf691SAdam Lee */ 901acf691SAdam Lee 1001acf691SAdam Lee #include <linux/pci.h> 110086fc21Sernest.zhang #include <linux/mmc/host.h> 120086fc21Sernest.zhang #include <linux/mmc/mmc.h> 130086fc21Sernest.zhang #include <linux/delay.h> 1401acf691SAdam Lee 1501acf691SAdam Lee #include "sdhci.h" 1601acf691SAdam Lee #include "sdhci-pci.h" 17361eeda0SAdrian Hunter 18361eeda0SAdrian Hunter /* 19361eeda0SAdrian Hunter * O2Micro device registers 20361eeda0SAdrian Hunter */ 21361eeda0SAdrian Hunter 22361eeda0SAdrian Hunter #define O2_SD_MISC_REG5 0x64 23361eeda0SAdrian Hunter #define O2_SD_LD0_CTRL 0x68 24361eeda0SAdrian Hunter #define O2_SD_DEV_CTRL 0x88 25361eeda0SAdrian Hunter #define O2_SD_LOCK_WP 0xD3 26361eeda0SAdrian Hunter #define O2_SD_TEST_REG 0xD4 27361eeda0SAdrian Hunter #define O2_SD_FUNC_REG0 0xDC 28361eeda0SAdrian Hunter #define O2_SD_MULTI_VCC3V 0xEE 29361eeda0SAdrian Hunter #define O2_SD_CLKREQ 0xEC 30361eeda0SAdrian Hunter #define O2_SD_CAPS 0xE0 31361eeda0SAdrian Hunter #define O2_SD_ADMA1 0xE2 32361eeda0SAdrian Hunter #define O2_SD_ADMA2 0xE7 33361eeda0SAdrian Hunter #define O2_SD_INF_MOD 0xF1 34361eeda0SAdrian Hunter #define O2_SD_MISC_CTRL4 0xFC 35361eeda0SAdrian Hunter #define O2_SD_TUNING_CTRL 0x300 36361eeda0SAdrian Hunter #define O2_SD_PLL_SETTING 0x304 3757322d54Sernest.zhang #define O2_SD_MISC_SETTING 0x308 38361eeda0SAdrian Hunter #define O2_SD_CLK_SETTING 0x328 39361eeda0SAdrian Hunter #define O2_SD_CAP_REG2 0x330 40361eeda0SAdrian Hunter #define O2_SD_CAP_REG0 0x334 41361eeda0SAdrian Hunter #define O2_SD_UHS1_CAP_SETTING 0x33C 42361eeda0SAdrian Hunter #define O2_SD_DELAY_CTRL 0x350 43361eeda0SAdrian Hunter #define O2_SD_UHS2_L1_CTRL 0x35C 44361eeda0SAdrian Hunter #define O2_SD_FUNC_REG3 0x3E0 45361eeda0SAdrian Hunter #define O2_SD_FUNC_REG4 0x3E4 46361eeda0SAdrian Hunter #define O2_SD_LED_ENABLE BIT(6) 47361eeda0SAdrian Hunter #define O2_SD_FREG0_LEDOFF BIT(13) 48361eeda0SAdrian Hunter #define O2_SD_FREG4_ENABLE_CLK_SET BIT(22) 49361eeda0SAdrian Hunter 50361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING 0x110 51361eeda0SAdrian Hunter #define O2_SD_VENDOR_SETTING2 0x1C8 520086fc21Sernest.zhang #define O2_SD_HW_TUNING_DISABLE BIT(4) 530086fc21Sernest.zhang 54*9674bab4SShirley Her (SC) #define O2_PLL_DLL_WDT_CONTROL1 0x1CC 5569d91ed1SErnest Zhang(WH) #define O2_PLL_FORCE_ACTIVE BIT(18) 5669d91ed1SErnest Zhang(WH) #define O2_PLL_LOCK_STATUS BIT(14) 5769d91ed1SErnest Zhang(WH) #define O2_PLL_SOFT_RESET BIT(12) 5869d91ed1SErnest Zhang(WH) 5969d91ed1SErnest Zhang(WH) #define O2_SD_DETECT_SETTING 0x324 6069d91ed1SErnest Zhang(WH) 610086fc21Sernest.zhang static void sdhci_o2_set_tuning_mode(struct sdhci_host *host) 620086fc21Sernest.zhang { 630086fc21Sernest.zhang u16 reg; 640086fc21Sernest.zhang 650086fc21Sernest.zhang /* enable hardware tuning */ 660086fc21Sernest.zhang reg = sdhci_readw(host, O2_SD_VENDOR_SETTING); 670086fc21Sernest.zhang reg &= ~O2_SD_HW_TUNING_DISABLE; 680086fc21Sernest.zhang sdhci_writew(host, reg, O2_SD_VENDOR_SETTING); 690086fc21Sernest.zhang } 700086fc21Sernest.zhang 710086fc21Sernest.zhang static void __sdhci_o2_execute_tuning(struct sdhci_host *host, u32 opcode) 720086fc21Sernest.zhang { 730086fc21Sernest.zhang int i; 740086fc21Sernest.zhang 750086fc21Sernest.zhang sdhci_send_tuning(host, MMC_SEND_TUNING_BLOCK_HS200); 760086fc21Sernest.zhang 770086fc21Sernest.zhang for (i = 0; i < 150; i++) { 780086fc21Sernest.zhang u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); 790086fc21Sernest.zhang 800086fc21Sernest.zhang if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) { 810086fc21Sernest.zhang if (ctrl & SDHCI_CTRL_TUNED_CLK) { 820086fc21Sernest.zhang host->tuning_done = true; 830086fc21Sernest.zhang return; 840086fc21Sernest.zhang } 850086fc21Sernest.zhang pr_warn("%s: HW tuning failed !\n", 860086fc21Sernest.zhang mmc_hostname(host->mmc)); 870086fc21Sernest.zhang break; 880086fc21Sernest.zhang } 890086fc21Sernest.zhang 900086fc21Sernest.zhang mdelay(1); 910086fc21Sernest.zhang } 920086fc21Sernest.zhang 930086fc21Sernest.zhang pr_info("%s: Tuning failed, falling back to fixed sampling clock\n", 940086fc21Sernest.zhang mmc_hostname(host->mmc)); 950086fc21Sernest.zhang sdhci_reset_tuning(host); 960086fc21Sernest.zhang } 970086fc21Sernest.zhang 980086fc21Sernest.zhang static int sdhci_o2_execute_tuning(struct mmc_host *mmc, u32 opcode) 990086fc21Sernest.zhang { 1000086fc21Sernest.zhang struct sdhci_host *host = mmc_priv(mmc); 1010086fc21Sernest.zhang int current_bus_width = 0; 1020086fc21Sernest.zhang 1030086fc21Sernest.zhang /* 1040086fc21Sernest.zhang * This handler only implements the eMMC tuning that is specific to 1050086fc21Sernest.zhang * this controller. Fall back to the standard method for other TIMING. 1060086fc21Sernest.zhang */ 1070086fc21Sernest.zhang if (host->timing != MMC_TIMING_MMC_HS200) 1080086fc21Sernest.zhang return sdhci_execute_tuning(mmc, opcode); 1090086fc21Sernest.zhang 1100086fc21Sernest.zhang if (WARN_ON(opcode != MMC_SEND_TUNING_BLOCK_HS200)) 1110086fc21Sernest.zhang return -EINVAL; 1120086fc21Sernest.zhang 1130086fc21Sernest.zhang /* 1140086fc21Sernest.zhang * o2 sdhci host didn't support 8bit emmc tuning 1150086fc21Sernest.zhang */ 1160086fc21Sernest.zhang if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) { 1170086fc21Sernest.zhang current_bus_width = mmc->ios.bus_width; 1180f7b79a4SRaul E Rangel mmc->ios.bus_width = MMC_BUS_WIDTH_4; 1190086fc21Sernest.zhang sdhci_set_bus_width(host, MMC_BUS_WIDTH_4); 1200086fc21Sernest.zhang } 1210086fc21Sernest.zhang 1220086fc21Sernest.zhang sdhci_o2_set_tuning_mode(host); 1230086fc21Sernest.zhang 1240086fc21Sernest.zhang sdhci_start_tuning(host); 1250086fc21Sernest.zhang 1260086fc21Sernest.zhang __sdhci_o2_execute_tuning(host, opcode); 1270086fc21Sernest.zhang 1280086fc21Sernest.zhang sdhci_end_tuning(host); 1290086fc21Sernest.zhang 1300f7b79a4SRaul E Rangel if (current_bus_width == MMC_BUS_WIDTH_8) { 1310f7b79a4SRaul E Rangel mmc->ios.bus_width = MMC_BUS_WIDTH_8; 1320086fc21Sernest.zhang sdhci_set_bus_width(host, current_bus_width); 1330f7b79a4SRaul E Rangel } 1340086fc21Sernest.zhang 1350086fc21Sernest.zhang host->flags &= ~SDHCI_HS400_TUNING; 1360086fc21Sernest.zhang return 0; 1370086fc21Sernest.zhang } 13801acf691SAdam Lee 139706adf6bSPeter Guo static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value) 140706adf6bSPeter Guo { 141706adf6bSPeter Guo u32 scratch_32; 142706adf6bSPeter Guo pci_read_config_dword(chip->pdev, 143706adf6bSPeter Guo O2_SD_PLL_SETTING, &scratch_32); 144706adf6bSPeter Guo 145706adf6bSPeter Guo scratch_32 &= 0x0000FFFF; 146706adf6bSPeter Guo scratch_32 |= value; 147706adf6bSPeter Guo 148706adf6bSPeter Guo pci_write_config_dword(chip->pdev, 149706adf6bSPeter Guo O2_SD_PLL_SETTING, scratch_32); 150706adf6bSPeter Guo } 151706adf6bSPeter Guo 152706adf6bSPeter Guo static void o2_pci_led_enable(struct sdhci_pci_chip *chip) 153706adf6bSPeter Guo { 154706adf6bSPeter Guo int ret; 155706adf6bSPeter Guo u32 scratch_32; 156706adf6bSPeter Guo 157706adf6bSPeter Guo /* Set led of SD host function enable */ 158706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 159706adf6bSPeter Guo O2_SD_FUNC_REG0, &scratch_32); 160706adf6bSPeter Guo if (ret) 161706adf6bSPeter Guo return; 162706adf6bSPeter Guo 163706adf6bSPeter Guo scratch_32 &= ~O2_SD_FREG0_LEDOFF; 164706adf6bSPeter Guo pci_write_config_dword(chip->pdev, 165706adf6bSPeter Guo O2_SD_FUNC_REG0, scratch_32); 166706adf6bSPeter Guo 167706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 168706adf6bSPeter Guo O2_SD_TEST_REG, &scratch_32); 169706adf6bSPeter Guo if (ret) 170706adf6bSPeter Guo return; 171706adf6bSPeter Guo 172706adf6bSPeter Guo scratch_32 |= O2_SD_LED_ENABLE; 173706adf6bSPeter Guo pci_write_config_dword(chip->pdev, 174706adf6bSPeter Guo O2_SD_TEST_REG, scratch_32); 175706adf6bSPeter Guo 176706adf6bSPeter Guo } 177706adf6bSPeter Guo 178f0cbd780SBen Hutchings static void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) 17901acf691SAdam Lee { 18001acf691SAdam Lee u32 scratch_32; 18101acf691SAdam Lee int ret; 18201acf691SAdam Lee /* Improve write performance for SD3.0 */ 18301acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_DEV_CTRL, &scratch_32); 18401acf691SAdam Lee if (ret) 18501acf691SAdam Lee return; 18601acf691SAdam Lee scratch_32 &= ~((1 << 12) | (1 << 13) | (1 << 14)); 18701acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_DEV_CTRL, scratch_32); 18801acf691SAdam Lee 18901acf691SAdam Lee /* Enable Link abnormal reset generating Reset */ 19001acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_MISC_REG5, &scratch_32); 19101acf691SAdam Lee if (ret) 19201acf691SAdam Lee return; 19301acf691SAdam Lee scratch_32 &= ~((1 << 19) | (1 << 11)); 19401acf691SAdam Lee scratch_32 |= (1 << 10); 19501acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_MISC_REG5, scratch_32); 19601acf691SAdam Lee 19701acf691SAdam Lee /* set card power over current protection */ 19801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_TEST_REG, &scratch_32); 19901acf691SAdam Lee if (ret) 20001acf691SAdam Lee return; 20101acf691SAdam Lee scratch_32 |= (1 << 4); 20201acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_TEST_REG, scratch_32); 20301acf691SAdam Lee 20401acf691SAdam Lee /* adjust the output delay for SD mode */ 20501acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_DELAY_CTRL, 0x00002492); 20601acf691SAdam Lee 20701acf691SAdam Lee /* Set the output voltage setting of Aux 1.2v LDO */ 20801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_LD0_CTRL, &scratch_32); 20901acf691SAdam Lee if (ret) 21001acf691SAdam Lee return; 21101acf691SAdam Lee scratch_32 &= ~(3 << 12); 21201acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_LD0_CTRL, scratch_32); 21301acf691SAdam Lee 21401acf691SAdam Lee /* Set Max power supply capability of SD host */ 21501acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_CAP_REG0, &scratch_32); 21601acf691SAdam Lee if (ret) 21701acf691SAdam Lee return; 21801acf691SAdam Lee scratch_32 &= ~(0x01FE); 21901acf691SAdam Lee scratch_32 |= 0x00CC; 22001acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_CAP_REG0, scratch_32); 22101acf691SAdam Lee /* Set DLL Tuning Window */ 22201acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 22301acf691SAdam Lee O2_SD_TUNING_CTRL, &scratch_32); 22401acf691SAdam Lee if (ret) 22501acf691SAdam Lee return; 22601acf691SAdam Lee scratch_32 &= ~(0x000000FF); 22701acf691SAdam Lee scratch_32 |= 0x00000066; 22801acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_TUNING_CTRL, scratch_32); 22901acf691SAdam Lee 23001acf691SAdam Lee /* Set UHS2 T_EIDLE */ 23101acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 23201acf691SAdam Lee O2_SD_UHS2_L1_CTRL, &scratch_32); 23301acf691SAdam Lee if (ret) 23401acf691SAdam Lee return; 23501acf691SAdam Lee scratch_32 &= ~(0x000000FC); 23601acf691SAdam Lee scratch_32 |= 0x00000084; 23701acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_UHS2_L1_CTRL, scratch_32); 23801acf691SAdam Lee 23901acf691SAdam Lee /* Set UHS2 Termination */ 24001acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_FUNC_REG3, &scratch_32); 24101acf691SAdam Lee if (ret) 24201acf691SAdam Lee return; 24301acf691SAdam Lee scratch_32 &= ~((1 << 21) | (1 << 30)); 24401acf691SAdam Lee 24501acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32); 24601acf691SAdam Lee 24701acf691SAdam Lee /* Set L1 Entrance Timer */ 24801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, O2_SD_CAPS, &scratch_32); 24901acf691SAdam Lee if (ret) 25001acf691SAdam Lee return; 25101acf691SAdam Lee scratch_32 &= ~(0xf0000000); 25201acf691SAdam Lee scratch_32 |= 0x30000000; 25301acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_CAPS, scratch_32); 25401acf691SAdam Lee 25501acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 25601acf691SAdam Lee O2_SD_MISC_CTRL4, &scratch_32); 25701acf691SAdam Lee if (ret) 25801acf691SAdam Lee return; 25901acf691SAdam Lee scratch_32 &= ~(0x000f0000); 26001acf691SAdam Lee scratch_32 |= 0x00080000; 26101acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL4, scratch_32); 26201acf691SAdam Lee } 26301acf691SAdam Lee 26402a3c0bdSernest.zhang static void sdhci_pci_o2_enable_msi(struct sdhci_pci_chip *chip, 26502a3c0bdSernest.zhang struct sdhci_host *host) 26602a3c0bdSernest.zhang { 26702a3c0bdSernest.zhang int ret; 26802a3c0bdSernest.zhang 26902a3c0bdSernest.zhang ret = pci_find_capability(chip->pdev, PCI_CAP_ID_MSI); 27002a3c0bdSernest.zhang if (!ret) { 27102a3c0bdSernest.zhang pr_info("%s: unsupport msi, use INTx irq\n", 27202a3c0bdSernest.zhang mmc_hostname(host->mmc)); 27302a3c0bdSernest.zhang return; 27402a3c0bdSernest.zhang } 27502a3c0bdSernest.zhang 27602a3c0bdSernest.zhang ret = pci_alloc_irq_vectors(chip->pdev, 1, 1, 27702a3c0bdSernest.zhang PCI_IRQ_MSI | PCI_IRQ_MSIX); 27802a3c0bdSernest.zhang if (ret < 0) { 27902a3c0bdSernest.zhang pr_err("%s: enable PCI MSI failed, err=%d\n", 28002a3c0bdSernest.zhang mmc_hostname(host->mmc), ret); 28102a3c0bdSernest.zhang return; 28202a3c0bdSernest.zhang } 28302a3c0bdSernest.zhang 28402a3c0bdSernest.zhang host->irq = pci_irq_vector(chip->pdev, 0); 28502a3c0bdSernest.zhang } 28602a3c0bdSernest.zhang 28769d91ed1SErnest Zhang(WH) static void sdhci_o2_wait_card_detect_stable(struct sdhci_host *host) 28869d91ed1SErnest Zhang(WH) { 28969d91ed1SErnest Zhang(WH) ktime_t timeout; 29069d91ed1SErnest Zhang(WH) u32 scratch32; 29169d91ed1SErnest Zhang(WH) 29269d91ed1SErnest Zhang(WH) /* Wait max 50 ms */ 29369d91ed1SErnest Zhang(WH) timeout = ktime_add_ms(ktime_get(), 50); 29469d91ed1SErnest Zhang(WH) while (1) { 29569d91ed1SErnest Zhang(WH) bool timedout = ktime_after(ktime_get(), timeout); 29669d91ed1SErnest Zhang(WH) 29769d91ed1SErnest Zhang(WH) scratch32 = sdhci_readl(host, SDHCI_PRESENT_STATE); 29869d91ed1SErnest Zhang(WH) if ((scratch32 & SDHCI_CARD_PRESENT) >> SDHCI_CARD_PRES_SHIFT 29969d91ed1SErnest Zhang(WH) == (scratch32 & SDHCI_CD_LVL) >> SDHCI_CD_LVL_SHIFT) 30069d91ed1SErnest Zhang(WH) break; 30169d91ed1SErnest Zhang(WH) 30269d91ed1SErnest Zhang(WH) if (timedout) { 30369d91ed1SErnest Zhang(WH) pr_err("%s: Card Detect debounce never finished.\n", 30469d91ed1SErnest Zhang(WH) mmc_hostname(host->mmc)); 30569d91ed1SErnest Zhang(WH) sdhci_dumpregs(host); 30669d91ed1SErnest Zhang(WH) return; 30769d91ed1SErnest Zhang(WH) } 30869d91ed1SErnest Zhang(WH) udelay(10); 30969d91ed1SErnest Zhang(WH) } 31069d91ed1SErnest Zhang(WH) } 31169d91ed1SErnest Zhang(WH) 31269d91ed1SErnest Zhang(WH) static void sdhci_o2_enable_internal_clock(struct sdhci_host *host) 31369d91ed1SErnest Zhang(WH) { 31469d91ed1SErnest Zhang(WH) ktime_t timeout; 31569d91ed1SErnest Zhang(WH) u16 scratch; 31669d91ed1SErnest Zhang(WH) u32 scratch32; 31769d91ed1SErnest Zhang(WH) 31869d91ed1SErnest Zhang(WH) /* PLL software reset */ 319*9674bab4SShirley Her (SC) scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); 32069d91ed1SErnest Zhang(WH) scratch32 |= O2_PLL_SOFT_RESET; 321*9674bab4SShirley Her (SC) sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); 32269d91ed1SErnest Zhang(WH) udelay(1); 32369d91ed1SErnest Zhang(WH) scratch32 &= ~(O2_PLL_SOFT_RESET); 324*9674bab4SShirley Her (SC) sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); 32569d91ed1SErnest Zhang(WH) 32669d91ed1SErnest Zhang(WH) /* PLL force active */ 32769d91ed1SErnest Zhang(WH) scratch32 |= O2_PLL_FORCE_ACTIVE; 328*9674bab4SShirley Her (SC) sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); 32969d91ed1SErnest Zhang(WH) 33069d91ed1SErnest Zhang(WH) /* Wait max 20 ms */ 33169d91ed1SErnest Zhang(WH) timeout = ktime_add_ms(ktime_get(), 20); 33269d91ed1SErnest Zhang(WH) while (1) { 33369d91ed1SErnest Zhang(WH) bool timedout = ktime_after(ktime_get(), timeout); 33469d91ed1SErnest Zhang(WH) 335*9674bab4SShirley Her (SC) scratch = sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1); 33669d91ed1SErnest Zhang(WH) if (scratch & O2_PLL_LOCK_STATUS) 33769d91ed1SErnest Zhang(WH) break; 33869d91ed1SErnest Zhang(WH) if (timedout) { 33969d91ed1SErnest Zhang(WH) pr_err("%s: Internal clock never stabilised.\n", 34069d91ed1SErnest Zhang(WH) mmc_hostname(host->mmc)); 34169d91ed1SErnest Zhang(WH) sdhci_dumpregs(host); 34269d91ed1SErnest Zhang(WH) goto out; 34369d91ed1SErnest Zhang(WH) } 34469d91ed1SErnest Zhang(WH) udelay(10); 34569d91ed1SErnest Zhang(WH) } 34669d91ed1SErnest Zhang(WH) 34769d91ed1SErnest Zhang(WH) /* Wait for card detect finish */ 34869d91ed1SErnest Zhang(WH) udelay(1); 34969d91ed1SErnest Zhang(WH) sdhci_o2_wait_card_detect_stable(host); 35069d91ed1SErnest Zhang(WH) 35169d91ed1SErnest Zhang(WH) out: 35269d91ed1SErnest Zhang(WH) /* Cancel PLL force active */ 353*9674bab4SShirley Her (SC) scratch32 = sdhci_readl(host, O2_PLL_DLL_WDT_CONTROL1); 35469d91ed1SErnest Zhang(WH) scratch32 &= ~O2_PLL_FORCE_ACTIVE; 355*9674bab4SShirley Her (SC) sdhci_writel(host, scratch32, O2_PLL_DLL_WDT_CONTROL1); 35669d91ed1SErnest Zhang(WH) } 35769d91ed1SErnest Zhang(WH) 35869d91ed1SErnest Zhang(WH) static int sdhci_o2_get_cd(struct mmc_host *mmc) 35969d91ed1SErnest Zhang(WH) { 36069d91ed1SErnest Zhang(WH) struct sdhci_host *host = mmc_priv(mmc); 36169d91ed1SErnest Zhang(WH) 36269d91ed1SErnest Zhang(WH) sdhci_o2_enable_internal_clock(host); 36369d91ed1SErnest Zhang(WH) 36469d91ed1SErnest Zhang(WH) return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); 36569d91ed1SErnest Zhang(WH) } 36669d91ed1SErnest Zhang(WH) 36769d91ed1SErnest Zhang(WH) static void sdhci_o2_enable_clk(struct sdhci_host *host, u16 clk) 36869d91ed1SErnest Zhang(WH) { 36969d91ed1SErnest Zhang(WH) /* Enable internal clock */ 37069d91ed1SErnest Zhang(WH) clk |= SDHCI_CLOCK_INT_EN; 37169d91ed1SErnest Zhang(WH) sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 37269d91ed1SErnest Zhang(WH) 37369d91ed1SErnest Zhang(WH) if (sdhci_o2_get_cd(host->mmc)) { 37469d91ed1SErnest Zhang(WH) clk |= SDHCI_CLOCK_CARD_EN; 37569d91ed1SErnest Zhang(WH) sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); 37669d91ed1SErnest Zhang(WH) } 37769d91ed1SErnest Zhang(WH) } 37869d91ed1SErnest Zhang(WH) 37969d91ed1SErnest Zhang(WH) void sdhci_pci_o2_set_clock(struct sdhci_host *host, unsigned int clock) 38069d91ed1SErnest Zhang(WH) { 38169d91ed1SErnest Zhang(WH) u16 clk; 38269d91ed1SErnest Zhang(WH) 38369d91ed1SErnest Zhang(WH) host->mmc->actual_clock = 0; 38469d91ed1SErnest Zhang(WH) 38569d91ed1SErnest Zhang(WH) sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); 38669d91ed1SErnest Zhang(WH) 38769d91ed1SErnest Zhang(WH) if (clock == 0) 38869d91ed1SErnest Zhang(WH) return; 38969d91ed1SErnest Zhang(WH) 39069d91ed1SErnest Zhang(WH) clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); 39169d91ed1SErnest Zhang(WH) sdhci_o2_enable_clk(host, clk); 39269d91ed1SErnest Zhang(WH) } 39369d91ed1SErnest Zhang(WH) 39401acf691SAdam Lee int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) 39501acf691SAdam Lee { 39601acf691SAdam Lee struct sdhci_pci_chip *chip; 39701acf691SAdam Lee struct sdhci_host *host; 398de23f0b7SRaul E Rangel u32 reg, caps; 39957322d54Sernest.zhang int ret; 40001acf691SAdam Lee 40101acf691SAdam Lee chip = slot->chip; 40201acf691SAdam Lee host = slot->host; 403de23f0b7SRaul E Rangel 404de23f0b7SRaul E Rangel caps = sdhci_readl(host, SDHCI_CAPABILITIES); 405de23f0b7SRaul E Rangel 406de23f0b7SRaul E Rangel /* 407de23f0b7SRaul E Rangel * mmc_select_bus_width() will test the bus to determine the actual bus 408de23f0b7SRaul E Rangel * width. 409de23f0b7SRaul E Rangel */ 410de23f0b7SRaul E Rangel if (caps & SDHCI_CAN_DO_8BIT) 411de23f0b7SRaul E Rangel host->mmc->caps |= MMC_CAP_8_BIT_DATA; 412de23f0b7SRaul E Rangel 41301acf691SAdam Lee switch (chip->pdev->device) { 41401acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS0: 41501acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD0: 41601acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD1: 41701acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS1: 41801acf691SAdam Lee case PCI_DEVICE_ID_O2_FUJIN2: 41901acf691SAdam Lee reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); 42001acf691SAdam Lee if (reg & 0x1) 42101acf691SAdam Lee host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; 42201acf691SAdam Lee 42302a3c0bdSernest.zhang sdhci_pci_o2_enable_msi(chip, host); 42402a3c0bdSernest.zhang 42557322d54Sernest.zhang if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { 42657322d54Sernest.zhang ret = pci_read_config_dword(chip->pdev, 42757322d54Sernest.zhang O2_SD_MISC_SETTING, ®); 42857322d54Sernest.zhang if (ret) 42957322d54Sernest.zhang return -EIO; 43057322d54Sernest.zhang if (reg & (1 << 4)) { 43157322d54Sernest.zhang pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n", 43257322d54Sernest.zhang mmc_hostname(host->mmc)); 43357322d54Sernest.zhang host->flags &= ~SDHCI_SIGNALING_330; 43457322d54Sernest.zhang host->flags |= SDHCI_SIGNALING_180; 435414126f9SErnest Zhang(WH) host->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD; 43657322d54Sernest.zhang host->mmc->caps2 |= MMC_CAP2_NO_SD; 43757322d54Sernest.zhang host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 43869d91ed1SErnest Zhang(WH) pci_write_config_dword(chip->pdev, 43969d91ed1SErnest Zhang(WH) O2_SD_DETECT_SETTING, 3); 44057322d54Sernest.zhang } 44169d91ed1SErnest Zhang(WH) 44269d91ed1SErnest Zhang(WH) slot->host->mmc_host_ops.get_cd = sdhci_o2_get_cd; 44357322d54Sernest.zhang } 44457322d54Sernest.zhang 4450086fc21Sernest.zhang host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; 4460086fc21Sernest.zhang 44701acf691SAdam Lee if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) 44801acf691SAdam Lee break; 44901acf691SAdam Lee /* set dll watch dog timer */ 45001acf691SAdam Lee reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); 45101acf691SAdam Lee reg |= (1 << 12); 45201acf691SAdam Lee sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); 45301acf691SAdam Lee 45401acf691SAdam Lee break; 45501acf691SAdam Lee default: 45601acf691SAdam Lee break; 45701acf691SAdam Lee } 45801acf691SAdam Lee 45901acf691SAdam Lee return 0; 46001acf691SAdam Lee } 46101acf691SAdam Lee 46201acf691SAdam Lee int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) 46301acf691SAdam Lee { 46401acf691SAdam Lee int ret; 46501acf691SAdam Lee u8 scratch; 46601acf691SAdam Lee u32 scratch_32; 46701acf691SAdam Lee 46801acf691SAdam Lee switch (chip->pdev->device) { 46901acf691SAdam Lee case PCI_DEVICE_ID_O2_8220: 47001acf691SAdam Lee case PCI_DEVICE_ID_O2_8221: 47101acf691SAdam Lee case PCI_DEVICE_ID_O2_8320: 47201acf691SAdam Lee case PCI_DEVICE_ID_O2_8321: 47301acf691SAdam Lee /* This extra setup is required due to broken ADMA. */ 47401acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 47501acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 47601acf691SAdam Lee if (ret) 47701acf691SAdam Lee return ret; 47801acf691SAdam Lee scratch &= 0x7f; 47901acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 48001acf691SAdam Lee 48101acf691SAdam Lee /* Set Multi 3 to VCC3V# */ 48201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); 48301acf691SAdam Lee 48401acf691SAdam Lee /* Disable CLK_REQ# support after media DET */ 48501acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 48601acf691SAdam Lee O2_SD_CLKREQ, &scratch); 48701acf691SAdam Lee if (ret) 48801acf691SAdam Lee return ret; 48901acf691SAdam Lee scratch |= 0x20; 49001acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); 49101acf691SAdam Lee 49201acf691SAdam Lee /* Choose capabilities, enable SDMA. We have to write 0x01 49301acf691SAdam Lee * to the capabilities register first to unlock it. 49401acf691SAdam Lee */ 49501acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); 49601acf691SAdam Lee if (ret) 49701acf691SAdam Lee return ret; 49801acf691SAdam Lee scratch |= 0x01; 49901acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); 50001acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); 50101acf691SAdam Lee 50201acf691SAdam Lee /* Disable ADMA1/2 */ 50301acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); 50401acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); 50501acf691SAdam Lee 50601acf691SAdam Lee /* Disable the infinite transfer mode */ 50701acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 50801acf691SAdam Lee O2_SD_INF_MOD, &scratch); 50901acf691SAdam Lee if (ret) 51001acf691SAdam Lee return ret; 51101acf691SAdam Lee scratch |= 0x08; 51201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); 51301acf691SAdam Lee 51401acf691SAdam Lee /* Lock WP */ 51501acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 51601acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 51701acf691SAdam Lee if (ret) 51801acf691SAdam Lee return ret; 51901acf691SAdam Lee scratch |= 0x80; 52001acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 52101acf691SAdam Lee break; 52201acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS0: 52301acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS1: 52401acf691SAdam Lee case PCI_DEVICE_ID_O2_FUJIN2: 52501acf691SAdam Lee /* UnLock WP */ 52601acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 52701acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 52801acf691SAdam Lee if (ret) 52901acf691SAdam Lee return ret; 53001acf691SAdam Lee 53101acf691SAdam Lee scratch &= 0x7f; 53201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 53301acf691SAdam Lee 534706adf6bSPeter Guo /* DevId=8520 subId= 0x11 or 0x12 Type Chip support */ 535706adf6bSPeter Guo if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) { 536706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 537706adf6bSPeter Guo O2_SD_FUNC_REG0, 538706adf6bSPeter Guo &scratch_32); 539706adf6bSPeter Guo scratch_32 = ((scratch_32 & 0xFF000000) >> 24); 540706adf6bSPeter Guo 541706adf6bSPeter Guo /* Check Whether subId is 0x11 or 0x12 */ 542706adf6bSPeter Guo if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) { 5433665ff03Sernest.zhang scratch_32 = 0x25100000; 544706adf6bSPeter Guo 545706adf6bSPeter Guo o2_pci_set_baseclk(chip, scratch_32); 546706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 547706adf6bSPeter Guo O2_SD_FUNC_REG4, 548706adf6bSPeter Guo &scratch_32); 549706adf6bSPeter Guo 550706adf6bSPeter Guo /* Enable Base Clk setting change */ 551706adf6bSPeter Guo scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; 552706adf6bSPeter Guo pci_write_config_dword(chip->pdev, 553706adf6bSPeter Guo O2_SD_FUNC_REG4, 554706adf6bSPeter Guo scratch_32); 555706adf6bSPeter Guo 556706adf6bSPeter Guo /* Set Tuning Window to 4 */ 557706adf6bSPeter Guo pci_write_config_byte(chip->pdev, 558706adf6bSPeter Guo O2_SD_TUNING_CTRL, 0x44); 559706adf6bSPeter Guo 560706adf6bSPeter Guo break; 561706adf6bSPeter Guo } 562706adf6bSPeter Guo } 563706adf6bSPeter Guo 564706adf6bSPeter Guo /* Enable 8520 led function */ 565706adf6bSPeter Guo o2_pci_led_enable(chip); 566706adf6bSPeter Guo 56701acf691SAdam Lee /* Set timeout CLK */ 56801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 56901acf691SAdam Lee O2_SD_CLK_SETTING, &scratch_32); 57001acf691SAdam Lee if (ret) 57101acf691SAdam Lee return ret; 57201acf691SAdam Lee 57301acf691SAdam Lee scratch_32 &= ~(0xFF00); 57401acf691SAdam Lee scratch_32 |= 0x07E0C800; 57501acf691SAdam Lee pci_write_config_dword(chip->pdev, 57601acf691SAdam Lee O2_SD_CLK_SETTING, scratch_32); 57701acf691SAdam Lee 57801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 57901acf691SAdam Lee O2_SD_CLKREQ, &scratch_32); 58001acf691SAdam Lee if (ret) 58101acf691SAdam Lee return ret; 58201acf691SAdam Lee scratch_32 |= 0x3; 58301acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); 58401acf691SAdam Lee 58501acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 58601acf691SAdam Lee O2_SD_PLL_SETTING, &scratch_32); 58701acf691SAdam Lee if (ret) 58801acf691SAdam Lee return ret; 58901acf691SAdam Lee 59001acf691SAdam Lee scratch_32 &= ~(0x1F3F070E); 59101acf691SAdam Lee scratch_32 |= 0x18270106; 59201acf691SAdam Lee pci_write_config_dword(chip->pdev, 59301acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 59401acf691SAdam Lee 59501acf691SAdam Lee /* Disable UHS1 funciton */ 59601acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 59701acf691SAdam Lee O2_SD_CAP_REG2, &scratch_32); 59801acf691SAdam Lee if (ret) 59901acf691SAdam Lee return ret; 60001acf691SAdam Lee scratch_32 &= ~(0xE0); 60101acf691SAdam Lee pci_write_config_dword(chip->pdev, 60201acf691SAdam Lee O2_SD_CAP_REG2, scratch_32); 60301acf691SAdam Lee 60401acf691SAdam Lee if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) 60501acf691SAdam Lee sdhci_pci_o2_fujin2_pci_init(chip); 60601acf691SAdam Lee 60701acf691SAdam Lee /* Lock WP */ 60801acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 60901acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 61001acf691SAdam Lee if (ret) 61101acf691SAdam Lee return ret; 61201acf691SAdam Lee scratch |= 0x80; 61301acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 61401acf691SAdam Lee break; 61501acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD0: 61601acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD1: 61701acf691SAdam Lee /* UnLock WP */ 61801acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 61901acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 62001acf691SAdam Lee if (ret) 62101acf691SAdam Lee return ret; 62201acf691SAdam Lee 62301acf691SAdam Lee scratch &= 0x7f; 62401acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 62501acf691SAdam Lee 62601acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 627706adf6bSPeter Guo O2_SD_PLL_SETTING, &scratch_32); 62801acf691SAdam Lee 62901acf691SAdam Lee if ((scratch_32 & 0xff000000) == 0x01000000) { 63001acf691SAdam Lee scratch_32 &= 0x0000FFFF; 63101acf691SAdam Lee scratch_32 |= 0x1F340000; 63201acf691SAdam Lee 63301acf691SAdam Lee pci_write_config_dword(chip->pdev, 63401acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 63501acf691SAdam Lee } else { 63601acf691SAdam Lee scratch_32 &= 0x0000FFFF; 6373665ff03Sernest.zhang scratch_32 |= 0x25100000; 63801acf691SAdam Lee 63901acf691SAdam Lee pci_write_config_dword(chip->pdev, 64001acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 64101acf691SAdam Lee 64201acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 64301acf691SAdam Lee O2_SD_FUNC_REG4, 64401acf691SAdam Lee &scratch_32); 64501acf691SAdam Lee scratch_32 |= (1 << 22); 64601acf691SAdam Lee pci_write_config_dword(chip->pdev, 64701acf691SAdam Lee O2_SD_FUNC_REG4, scratch_32); 64801acf691SAdam Lee } 64901acf691SAdam Lee 650706adf6bSPeter Guo /* Set Tuning Windows to 5 */ 651706adf6bSPeter Guo pci_write_config_byte(chip->pdev, 652706adf6bSPeter Guo O2_SD_TUNING_CTRL, 0x55); 65301acf691SAdam Lee /* Lock WP */ 65401acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 65501acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 65601acf691SAdam Lee if (ret) 65701acf691SAdam Lee return ret; 65801acf691SAdam Lee scratch |= 0x80; 65901acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 66001acf691SAdam Lee break; 66101acf691SAdam Lee } 66201acf691SAdam Lee 66301acf691SAdam Lee return 0; 66401acf691SAdam Lee } 66501acf691SAdam Lee 666b7813f0fSAdrian Hunter #ifdef CONFIG_PM_SLEEP 66701acf691SAdam Lee int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) 66801acf691SAdam Lee { 66901acf691SAdam Lee sdhci_pci_o2_probe(chip); 67030cf2803SAdrian Hunter return sdhci_pci_resume_host(chip); 67101acf691SAdam Lee } 672b7813f0fSAdrian Hunter #endif 673328be8beSErnest Zhang(WH) 67469d91ed1SErnest Zhang(WH) static const struct sdhci_ops sdhci_pci_o2_ops = { 67569d91ed1SErnest Zhang(WH) .set_clock = sdhci_pci_o2_set_clock, 67669d91ed1SErnest Zhang(WH) .enable_dma = sdhci_pci_enable_dma, 67769d91ed1SErnest Zhang(WH) .set_bus_width = sdhci_set_bus_width, 67869d91ed1SErnest Zhang(WH) .reset = sdhci_reset, 67969d91ed1SErnest Zhang(WH) .set_uhs_signaling = sdhci_set_uhs_signaling, 68069d91ed1SErnest Zhang(WH) }; 68169d91ed1SErnest Zhang(WH) 682328be8beSErnest Zhang(WH) const struct sdhci_pci_fixes sdhci_o2 = { 683328be8beSErnest Zhang(WH) .probe = sdhci_pci_o2_probe, 684328be8beSErnest Zhang(WH) .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 685328be8beSErnest Zhang(WH) .probe_slot = sdhci_pci_o2_probe_slot, 686328be8beSErnest Zhang(WH) #ifdef CONFIG_PM_SLEEP 687328be8beSErnest Zhang(WH) .resume = sdhci_pci_o2_resume, 688328be8beSErnest Zhang(WH) #endif 68969d91ed1SErnest Zhang(WH) .ops = &sdhci_pci_o2_ops, 690328be8beSErnest Zhang(WH) }; 691