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 26301acf691SAdam Lee int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot) 26401acf691SAdam Lee { 26501acf691SAdam Lee struct sdhci_pci_chip *chip; 26601acf691SAdam Lee struct sdhci_host *host; 26701acf691SAdam Lee u32 reg; 26857322d54Sernest.zhang int ret; 26901acf691SAdam Lee 27001acf691SAdam Lee chip = slot->chip; 27101acf691SAdam Lee host = slot->host; 27201acf691SAdam Lee switch (chip->pdev->device) { 27301acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS0: 27401acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD0: 27501acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD1: 27601acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS1: 27701acf691SAdam Lee case PCI_DEVICE_ID_O2_FUJIN2: 27801acf691SAdam Lee reg = sdhci_readl(host, O2_SD_VENDOR_SETTING); 27901acf691SAdam Lee if (reg & 0x1) 28001acf691SAdam Lee host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; 28101acf691SAdam Lee 28257322d54Sernest.zhang if (chip->pdev->device == PCI_DEVICE_ID_O2_SEABIRD0) { 28357322d54Sernest.zhang ret = pci_read_config_dword(chip->pdev, 28457322d54Sernest.zhang O2_SD_MISC_SETTING, ®); 28557322d54Sernest.zhang if (ret) 28657322d54Sernest.zhang return -EIO; 28757322d54Sernest.zhang if (reg & (1 << 4)) { 28857322d54Sernest.zhang pr_info("%s: emmc 1.8v flag is set, force 1.8v signaling voltage\n", 28957322d54Sernest.zhang mmc_hostname(host->mmc)); 29057322d54Sernest.zhang host->flags &= ~SDHCI_SIGNALING_330; 29157322d54Sernest.zhang host->flags |= SDHCI_SIGNALING_180; 29257322d54Sernest.zhang host->mmc->caps2 |= MMC_CAP2_NO_SD; 29357322d54Sernest.zhang host->mmc->caps2 |= MMC_CAP2_NO_SDIO; 29457322d54Sernest.zhang } 29557322d54Sernest.zhang } 29657322d54Sernest.zhang 2970086fc21Sernest.zhang host->mmc_host_ops.execute_tuning = sdhci_o2_execute_tuning; 2980086fc21Sernest.zhang 29901acf691SAdam Lee if (chip->pdev->device != PCI_DEVICE_ID_O2_FUJIN2) 30001acf691SAdam Lee break; 30101acf691SAdam Lee /* set dll watch dog timer */ 30201acf691SAdam Lee reg = sdhci_readl(host, O2_SD_VENDOR_SETTING2); 30301acf691SAdam Lee reg |= (1 << 12); 30401acf691SAdam Lee sdhci_writel(host, reg, O2_SD_VENDOR_SETTING2); 30501acf691SAdam Lee 30601acf691SAdam Lee break; 30701acf691SAdam Lee default: 30801acf691SAdam Lee break; 30901acf691SAdam Lee } 31001acf691SAdam Lee 31101acf691SAdam Lee return 0; 31201acf691SAdam Lee } 31301acf691SAdam Lee 31401acf691SAdam Lee int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip) 31501acf691SAdam Lee { 31601acf691SAdam Lee int ret; 31701acf691SAdam Lee u8 scratch; 31801acf691SAdam Lee u32 scratch_32; 31901acf691SAdam Lee 32001acf691SAdam Lee switch (chip->pdev->device) { 32101acf691SAdam Lee case PCI_DEVICE_ID_O2_8220: 32201acf691SAdam Lee case PCI_DEVICE_ID_O2_8221: 32301acf691SAdam Lee case PCI_DEVICE_ID_O2_8320: 32401acf691SAdam Lee case PCI_DEVICE_ID_O2_8321: 32501acf691SAdam Lee /* This extra setup is required due to broken ADMA. */ 32601acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 32701acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 32801acf691SAdam Lee if (ret) 32901acf691SAdam Lee return ret; 33001acf691SAdam Lee scratch &= 0x7f; 33101acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 33201acf691SAdam Lee 33301acf691SAdam Lee /* Set Multi 3 to VCC3V# */ 33401acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08); 33501acf691SAdam Lee 33601acf691SAdam Lee /* Disable CLK_REQ# support after media DET */ 33701acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 33801acf691SAdam Lee O2_SD_CLKREQ, &scratch); 33901acf691SAdam Lee if (ret) 34001acf691SAdam Lee return ret; 34101acf691SAdam Lee scratch |= 0x20; 34201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch); 34301acf691SAdam Lee 34401acf691SAdam Lee /* Choose capabilities, enable SDMA. We have to write 0x01 34501acf691SAdam Lee * to the capabilities register first to unlock it. 34601acf691SAdam Lee */ 34701acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch); 34801acf691SAdam Lee if (ret) 34901acf691SAdam Lee return ret; 35001acf691SAdam Lee scratch |= 0x01; 35101acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch); 35201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73); 35301acf691SAdam Lee 35401acf691SAdam Lee /* Disable ADMA1/2 */ 35501acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39); 35601acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08); 35701acf691SAdam Lee 35801acf691SAdam Lee /* Disable the infinite transfer mode */ 35901acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 36001acf691SAdam Lee O2_SD_INF_MOD, &scratch); 36101acf691SAdam Lee if (ret) 36201acf691SAdam Lee return ret; 36301acf691SAdam Lee scratch |= 0x08; 36401acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch); 36501acf691SAdam Lee 36601acf691SAdam Lee /* Lock WP */ 36701acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 36801acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 36901acf691SAdam Lee if (ret) 37001acf691SAdam Lee return ret; 37101acf691SAdam Lee scratch |= 0x80; 37201acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 37301acf691SAdam Lee break; 37401acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS0: 37501acf691SAdam Lee case PCI_DEVICE_ID_O2_SDS1: 37601acf691SAdam Lee case PCI_DEVICE_ID_O2_FUJIN2: 37701acf691SAdam Lee /* UnLock WP */ 37801acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 37901acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 38001acf691SAdam Lee if (ret) 38101acf691SAdam Lee return ret; 38201acf691SAdam Lee 38301acf691SAdam Lee scratch &= 0x7f; 38401acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 38501acf691SAdam Lee 386706adf6bSPeter Guo /* DevId=8520 subId= 0x11 or 0x12 Type Chip support */ 387706adf6bSPeter Guo if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) { 388706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 389706adf6bSPeter Guo O2_SD_FUNC_REG0, 390706adf6bSPeter Guo &scratch_32); 391706adf6bSPeter Guo scratch_32 = ((scratch_32 & 0xFF000000) >> 24); 392706adf6bSPeter Guo 393706adf6bSPeter Guo /* Check Whether subId is 0x11 or 0x12 */ 394706adf6bSPeter Guo if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) { 3953665ff03Sernest.zhang scratch_32 = 0x25100000; 396706adf6bSPeter Guo 397706adf6bSPeter Guo o2_pci_set_baseclk(chip, scratch_32); 398706adf6bSPeter Guo ret = pci_read_config_dword(chip->pdev, 399706adf6bSPeter Guo O2_SD_FUNC_REG4, 400706adf6bSPeter Guo &scratch_32); 401706adf6bSPeter Guo 402706adf6bSPeter Guo /* Enable Base Clk setting change */ 403706adf6bSPeter Guo scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET; 404706adf6bSPeter Guo pci_write_config_dword(chip->pdev, 405706adf6bSPeter Guo O2_SD_FUNC_REG4, 406706adf6bSPeter Guo scratch_32); 407706adf6bSPeter Guo 408706adf6bSPeter Guo /* Set Tuning Window to 4 */ 409706adf6bSPeter Guo pci_write_config_byte(chip->pdev, 410706adf6bSPeter Guo O2_SD_TUNING_CTRL, 0x44); 411706adf6bSPeter Guo 412706adf6bSPeter Guo break; 413706adf6bSPeter Guo } 414706adf6bSPeter Guo } 415706adf6bSPeter Guo 416706adf6bSPeter Guo /* Enable 8520 led function */ 417706adf6bSPeter Guo o2_pci_led_enable(chip); 418706adf6bSPeter Guo 41901acf691SAdam Lee /* Set timeout CLK */ 42001acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 42101acf691SAdam Lee O2_SD_CLK_SETTING, &scratch_32); 42201acf691SAdam Lee if (ret) 42301acf691SAdam Lee return ret; 42401acf691SAdam Lee 42501acf691SAdam Lee scratch_32 &= ~(0xFF00); 42601acf691SAdam Lee scratch_32 |= 0x07E0C800; 42701acf691SAdam Lee pci_write_config_dword(chip->pdev, 42801acf691SAdam Lee O2_SD_CLK_SETTING, scratch_32); 42901acf691SAdam Lee 43001acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 43101acf691SAdam Lee O2_SD_CLKREQ, &scratch_32); 43201acf691SAdam Lee if (ret) 43301acf691SAdam Lee return ret; 43401acf691SAdam Lee scratch_32 |= 0x3; 43501acf691SAdam Lee pci_write_config_dword(chip->pdev, O2_SD_CLKREQ, scratch_32); 43601acf691SAdam Lee 43701acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 43801acf691SAdam Lee O2_SD_PLL_SETTING, &scratch_32); 43901acf691SAdam Lee if (ret) 44001acf691SAdam Lee return ret; 44101acf691SAdam Lee 44201acf691SAdam Lee scratch_32 &= ~(0x1F3F070E); 44301acf691SAdam Lee scratch_32 |= 0x18270106; 44401acf691SAdam Lee pci_write_config_dword(chip->pdev, 44501acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 44601acf691SAdam Lee 44701acf691SAdam Lee /* Disable UHS1 funciton */ 44801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 44901acf691SAdam Lee O2_SD_CAP_REG2, &scratch_32); 45001acf691SAdam Lee if (ret) 45101acf691SAdam Lee return ret; 45201acf691SAdam Lee scratch_32 &= ~(0xE0); 45301acf691SAdam Lee pci_write_config_dword(chip->pdev, 45401acf691SAdam Lee O2_SD_CAP_REG2, scratch_32); 45501acf691SAdam Lee 45601acf691SAdam Lee if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) 45701acf691SAdam Lee sdhci_pci_o2_fujin2_pci_init(chip); 45801acf691SAdam Lee 45901acf691SAdam Lee /* Lock WP */ 46001acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 46101acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 46201acf691SAdam Lee if (ret) 46301acf691SAdam Lee return ret; 46401acf691SAdam Lee scratch |= 0x80; 46501acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 46601acf691SAdam Lee break; 46701acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD0: 46801acf691SAdam Lee case PCI_DEVICE_ID_O2_SEABIRD1: 46901acf691SAdam Lee /* UnLock WP */ 47001acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 47101acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 47201acf691SAdam Lee if (ret) 47301acf691SAdam Lee return ret; 47401acf691SAdam Lee 47501acf691SAdam Lee scratch &= 0x7f; 47601acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 47701acf691SAdam Lee 47801acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 479706adf6bSPeter Guo O2_SD_PLL_SETTING, &scratch_32); 48001acf691SAdam Lee 48101acf691SAdam Lee if ((scratch_32 & 0xff000000) == 0x01000000) { 48201acf691SAdam Lee scratch_32 &= 0x0000FFFF; 48301acf691SAdam Lee scratch_32 |= 0x1F340000; 48401acf691SAdam Lee 48501acf691SAdam Lee pci_write_config_dword(chip->pdev, 48601acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 48701acf691SAdam Lee } else { 48801acf691SAdam Lee scratch_32 &= 0x0000FFFF; 4893665ff03Sernest.zhang scratch_32 |= 0x25100000; 49001acf691SAdam Lee 49101acf691SAdam Lee pci_write_config_dword(chip->pdev, 49201acf691SAdam Lee O2_SD_PLL_SETTING, scratch_32); 49301acf691SAdam Lee 49401acf691SAdam Lee ret = pci_read_config_dword(chip->pdev, 49501acf691SAdam Lee O2_SD_FUNC_REG4, 49601acf691SAdam Lee &scratch_32); 49701acf691SAdam Lee scratch_32 |= (1 << 22); 49801acf691SAdam Lee pci_write_config_dword(chip->pdev, 49901acf691SAdam Lee O2_SD_FUNC_REG4, scratch_32); 50001acf691SAdam Lee } 50101acf691SAdam Lee 502706adf6bSPeter Guo /* Set Tuning Windows to 5 */ 503706adf6bSPeter Guo pci_write_config_byte(chip->pdev, 504706adf6bSPeter Guo O2_SD_TUNING_CTRL, 0x55); 50501acf691SAdam Lee /* Lock WP */ 50601acf691SAdam Lee ret = pci_read_config_byte(chip->pdev, 50701acf691SAdam Lee O2_SD_LOCK_WP, &scratch); 50801acf691SAdam Lee if (ret) 50901acf691SAdam Lee return ret; 51001acf691SAdam Lee scratch |= 0x80; 51101acf691SAdam Lee pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); 51201acf691SAdam Lee break; 51301acf691SAdam Lee } 51401acf691SAdam Lee 51501acf691SAdam Lee return 0; 51601acf691SAdam Lee } 51701acf691SAdam Lee 518b7813f0fSAdrian Hunter #ifdef CONFIG_PM_SLEEP 51901acf691SAdam Lee int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip) 52001acf691SAdam Lee { 52101acf691SAdam Lee sdhci_pci_o2_probe(chip); 52230cf2803SAdrian Hunter return sdhci_pci_resume_host(chip); 52301acf691SAdam Lee } 524b7813f0fSAdrian Hunter #endif 525