| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* Driver for Realtek PCI-Express card reader |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 7 | | - * Free Software Foundation; either version 2, or (at your option) any |
|---|
| 8 | | - * later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, but |
|---|
| 11 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | | - * General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License along |
|---|
| 16 | | - * with this program; if not, see <http://www.gnu.org/licenses/>. |
|---|
| 17 | 5 | * |
|---|
| 18 | 6 | * Author: |
|---|
| 19 | 7 | * Wei WANG <wei_wang@realsil.com.cn> |
|---|
| .. | .. |
|---|
| 68 | 56 | |
|---|
| 69 | 57 | static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) |
|---|
| 70 | 58 | { |
|---|
| 59 | + struct pci_dev *pdev = pcr->pci; |
|---|
| 71 | 60 | u32 reg; |
|---|
| 72 | 61 | |
|---|
| 73 | | - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); |
|---|
| 62 | + pci_read_config_dword(pdev, PCR_SETTING_REG1, ®); |
|---|
| 74 | 63 | pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); |
|---|
| 75 | 64 | |
|---|
| 76 | 65 | if (!rtsx_vendor_setting_valid(reg)) |
|---|
| .. | .. |
|---|
| 81 | 70 | pcr->card_drive_sel &= 0x3F; |
|---|
| 82 | 71 | pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); |
|---|
| 83 | 72 | |
|---|
| 84 | | - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); |
|---|
| 73 | + pci_read_config_dword(pdev, PCR_SETTING_REG2, ®); |
|---|
| 85 | 74 | pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); |
|---|
| 75 | + if (rtsx_check_mmc_support(reg)) |
|---|
| 76 | + pcr->extra_caps |= EXTRA_CAPS_NO_MMC; |
|---|
| 86 | 77 | pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); |
|---|
| 87 | 78 | if (rtsx_reg_check_reverse_socket(reg)) |
|---|
| 88 | 79 | pcr->flags |= PCR_REVERSE_SOCKET; |
|---|
| 89 | 80 | } |
|---|
| 90 | 81 | |
|---|
| 91 | | -static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) |
|---|
| 82 | +static void rts5227_init_from_cfg(struct rtsx_pcr *pcr) |
|---|
| 92 | 83 | { |
|---|
| 93 | | - /* Set relink_time to 0 */ |
|---|
| 94 | | - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); |
|---|
| 95 | | - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); |
|---|
| 96 | | - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); |
|---|
| 84 | + struct pci_dev *pdev = pcr->pci; |
|---|
| 85 | + int l1ss; |
|---|
| 86 | + u32 lval; |
|---|
| 87 | + struct rtsx_cr_option *option = &pcr->option; |
|---|
| 97 | 88 | |
|---|
| 98 | | - if (pm_state == HOST_ENTER_S3) |
|---|
| 99 | | - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x10); |
|---|
| 89 | + l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); |
|---|
| 90 | + if (!l1ss) |
|---|
| 91 | + return; |
|---|
| 100 | 92 | |
|---|
| 101 | | - rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); |
|---|
| 93 | + pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); |
|---|
| 94 | + |
|---|
| 95 | + if (CHK_PCI_PID(pcr, 0x522A)) { |
|---|
| 96 | + if (0 == (lval & 0x0F)) |
|---|
| 97 | + rtsx_pci_enable_oobs_polling(pcr); |
|---|
| 98 | + else |
|---|
| 99 | + rtsx_pci_disable_oobs_polling(pcr); |
|---|
| 100 | + } |
|---|
| 101 | + |
|---|
| 102 | + if (lval & PCI_L1SS_CTL1_ASPM_L1_1) |
|---|
| 103 | + rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); |
|---|
| 104 | + else |
|---|
| 105 | + rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN); |
|---|
| 106 | + |
|---|
| 107 | + if (lval & PCI_L1SS_CTL1_ASPM_L1_2) |
|---|
| 108 | + rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); |
|---|
| 109 | + else |
|---|
| 110 | + rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN); |
|---|
| 111 | + |
|---|
| 112 | + if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) |
|---|
| 113 | + rtsx_set_dev_flag(pcr, PM_L1_1_EN); |
|---|
| 114 | + else |
|---|
| 115 | + rtsx_clear_dev_flag(pcr, PM_L1_1_EN); |
|---|
| 116 | + |
|---|
| 117 | + if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) |
|---|
| 118 | + rtsx_set_dev_flag(pcr, PM_L1_2_EN); |
|---|
| 119 | + else |
|---|
| 120 | + rtsx_clear_dev_flag(pcr, PM_L1_2_EN); |
|---|
| 121 | + |
|---|
| 122 | + if (option->ltr_en) { |
|---|
| 123 | + u16 val; |
|---|
| 124 | + |
|---|
| 125 | + pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val); |
|---|
| 126 | + if (val & PCI_EXP_DEVCTL2_LTR_EN) { |
|---|
| 127 | + option->ltr_enabled = true; |
|---|
| 128 | + option->ltr_active = true; |
|---|
| 129 | + rtsx_set_ltr_latency(pcr, option->ltr_active_latency); |
|---|
| 130 | + } else { |
|---|
| 131 | + option->ltr_enabled = false; |
|---|
| 132 | + } |
|---|
| 133 | + } |
|---|
| 134 | + |
|---|
| 135 | + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN |
|---|
| 136 | + | PM_L1_1_EN | PM_L1_2_EN)) |
|---|
| 137 | + option->force_clkreq_0 = false; |
|---|
| 138 | + else |
|---|
| 139 | + option->force_clkreq_0 = true; |
|---|
| 140 | + |
|---|
| 102 | 141 | } |
|---|
| 103 | 142 | |
|---|
| 104 | 143 | static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) |
|---|
| 105 | 144 | { |
|---|
| 106 | 145 | u16 cap; |
|---|
| 146 | + struct rtsx_cr_option *option = &pcr->option; |
|---|
| 107 | 147 | |
|---|
| 148 | + rts5227_init_from_cfg(pcr); |
|---|
| 108 | 149 | rtsx_pci_init_cmd(pcr); |
|---|
| 109 | 150 | |
|---|
| 110 | 151 | /* Configure GPIO as output */ |
|---|
| .. | .. |
|---|
| 126 | 167 | rts5227_fill_driving(pcr, OUTPUT_3V3); |
|---|
| 127 | 168 | /* Configure force_clock_req */ |
|---|
| 128 | 169 | if (pcr->flags & PCR_REVERSE_SOCKET) |
|---|
| 129 | | - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0xB8); |
|---|
| 170 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x30); |
|---|
| 130 | 171 | else |
|---|
| 131 | | - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0x88); |
|---|
| 172 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x00); |
|---|
| 173 | + |
|---|
| 174 | + if (option->force_clkreq_0) |
|---|
| 175 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, |
|---|
| 176 | + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); |
|---|
| 177 | + else |
|---|
| 178 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, |
|---|
| 179 | + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); |
|---|
| 180 | + |
|---|
| 132 | 181 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, pcr->reg_pm_ctrl3, 0x10, 0x00); |
|---|
| 133 | 182 | |
|---|
| 134 | 183 | return rtsx_pci_send_cmd(pcr, 100); |
|---|
| .. | .. |
|---|
| 170 | 219 | { |
|---|
| 171 | 220 | int err; |
|---|
| 172 | 221 | |
|---|
| 222 | + if (pcr->option.ocp_en) |
|---|
| 223 | + rtsx_pci_enable_ocp(pcr); |
|---|
| 224 | + |
|---|
| 173 | 225 | rtsx_pci_init_cmd(pcr); |
|---|
| 174 | 226 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, |
|---|
| 175 | 227 | SD_POWER_MASK, SD_PARTIAL_POWER_ON); |
|---|
| 228 | + |
|---|
| 176 | 229 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, |
|---|
| 177 | 230 | LDO3318_PWR_MASK, 0x02); |
|---|
| 231 | + |
|---|
| 178 | 232 | err = rtsx_pci_send_cmd(pcr, 100); |
|---|
| 179 | 233 | if (err < 0) |
|---|
| 180 | 234 | return err; |
|---|
| 181 | 235 | |
|---|
| 182 | 236 | /* To avoid too large in-rush current */ |
|---|
| 183 | | - udelay(150); |
|---|
| 184 | | - |
|---|
| 237 | + msleep(20); |
|---|
| 185 | 238 | rtsx_pci_init_cmd(pcr); |
|---|
| 186 | 239 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, |
|---|
| 187 | 240 | SD_POWER_MASK, SD_POWER_ON); |
|---|
| 241 | + |
|---|
| 188 | 242 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, |
|---|
| 189 | 243 | LDO3318_PWR_MASK, 0x06); |
|---|
| 244 | + |
|---|
| 245 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, |
|---|
| 246 | + SD_OUTPUT_EN, SD_OUTPUT_EN); |
|---|
| 247 | + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, |
|---|
| 248 | + MS_OUTPUT_EN, MS_OUTPUT_EN); |
|---|
| 190 | 249 | return rtsx_pci_send_cmd(pcr, 100); |
|---|
| 191 | 250 | } |
|---|
| 192 | 251 | |
|---|
| 193 | 252 | static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card) |
|---|
| 194 | 253 | { |
|---|
| 195 | | - rtsx_pci_init_cmd(pcr); |
|---|
| 196 | | - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, |
|---|
| 197 | | - SD_POWER_MASK | PMOS_STRG_MASK, |
|---|
| 198 | | - SD_POWER_OFF | PMOS_STRG_400mA); |
|---|
| 199 | | - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, |
|---|
| 200 | | - LDO3318_PWR_MASK, 0X00); |
|---|
| 201 | | - return rtsx_pci_send_cmd(pcr, 100); |
|---|
| 254 | + if (pcr->option.ocp_en) |
|---|
| 255 | + rtsx_pci_disable_ocp(pcr); |
|---|
| 256 | + |
|---|
| 257 | + rtsx_pci_write_register(pcr, CARD_PWR_CTL, SD_POWER_MASK | |
|---|
| 258 | + PMOS_STRG_MASK, SD_POWER_OFF | PMOS_STRG_400mA); |
|---|
| 259 | + rtsx_pci_write_register(pcr, PWR_GATE_CTRL, LDO3318_PWR_MASK, 0X00); |
|---|
| 260 | + |
|---|
| 261 | + return 0; |
|---|
| 202 | 262 | } |
|---|
| 203 | 263 | |
|---|
| 204 | 264 | static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) |
|---|
| .. | .. |
|---|
| 239 | 299 | .switch_output_voltage = rts5227_switch_output_voltage, |
|---|
| 240 | 300 | .cd_deglitch = NULL, |
|---|
| 241 | 301 | .conv_clk_and_div_n = NULL, |
|---|
| 242 | | - .force_power_down = rts5227_force_power_down, |
|---|
| 243 | 302 | }; |
|---|
| 244 | 303 | |
|---|
| 245 | 304 | /* SD Pull Control Enable: |
|---|
| .. | .. |
|---|
| 353 | 412 | return 0; |
|---|
| 354 | 413 | } |
|---|
| 355 | 414 | |
|---|
| 415 | +static int rts522a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) |
|---|
| 416 | +{ |
|---|
| 417 | + int err; |
|---|
| 418 | + |
|---|
| 419 | + if (voltage == OUTPUT_3V3) { |
|---|
| 420 | + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x57E4); |
|---|
| 421 | + if (err < 0) |
|---|
| 422 | + return err; |
|---|
| 423 | + } else if (voltage == OUTPUT_1V8) { |
|---|
| 424 | + err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02); |
|---|
| 425 | + if (err < 0) |
|---|
| 426 | + return err; |
|---|
| 427 | + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x54A4); |
|---|
| 428 | + if (err < 0) |
|---|
| 429 | + return err; |
|---|
| 430 | + } else { |
|---|
| 431 | + return -EINVAL; |
|---|
| 432 | + } |
|---|
| 433 | + |
|---|
| 434 | + /* set pad drive */ |
|---|
| 435 | + rtsx_pci_init_cmd(pcr); |
|---|
| 436 | + rts5227_fill_driving(pcr, voltage); |
|---|
| 437 | + return rtsx_pci_send_cmd(pcr, 100); |
|---|
| 438 | +} |
|---|
| 439 | + |
|---|
| 440 | +static void rts522a_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active) |
|---|
| 441 | +{ |
|---|
| 442 | + struct rtsx_cr_option *option = &pcr->option; |
|---|
| 443 | + int aspm_L1_1, aspm_L1_2; |
|---|
| 444 | + u8 val = 0; |
|---|
| 445 | + |
|---|
| 446 | + aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN); |
|---|
| 447 | + aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN); |
|---|
| 448 | + |
|---|
| 449 | + if (active) { |
|---|
| 450 | + /* run, latency: 60us */ |
|---|
| 451 | + if (aspm_L1_1) |
|---|
| 452 | + val = option->ltr_l1off_snooze_sspwrgate; |
|---|
| 453 | + } else { |
|---|
| 454 | + /* l1off, latency: 300us */ |
|---|
| 455 | + if (aspm_L1_2) |
|---|
| 456 | + val = option->ltr_l1off_sspwrgate; |
|---|
| 457 | + } |
|---|
| 458 | + |
|---|
| 459 | + rtsx_set_l1off_sub(pcr, val); |
|---|
| 460 | +} |
|---|
| 461 | + |
|---|
| 356 | 462 | /* rts522a operations mainly derived from rts5227, except phy/hw init setting. |
|---|
| 357 | 463 | */ |
|---|
| 358 | 464 | static const struct pcr_ops rts522a_pcr_ops = { |
|---|
| .. | .. |
|---|
| 365 | 471 | .disable_auto_blink = rts5227_disable_auto_blink, |
|---|
| 366 | 472 | .card_power_on = rts5227_card_power_on, |
|---|
| 367 | 473 | .card_power_off = rts5227_card_power_off, |
|---|
| 368 | | - .switch_output_voltage = rts5227_switch_output_voltage, |
|---|
| 474 | + .switch_output_voltage = rts522a_switch_output_voltage, |
|---|
| 369 | 475 | .cd_deglitch = NULL, |
|---|
| 370 | 476 | .conv_clk_and_div_n = NULL, |
|---|
| 371 | | - .force_power_down = rts5227_force_power_down, |
|---|
| 477 | + .set_l1off_cfg_sub_d0 = rts522a_set_l1off_cfg_sub_d0, |
|---|
| 372 | 478 | }; |
|---|
| 373 | 479 | |
|---|
| 374 | 480 | void rts522a_init_params(struct rtsx_pcr *pcr) |
|---|
| 375 | 481 | { |
|---|
| 482 | + struct rtsx_cr_option *option = &pcr->option; |
|---|
| 483 | + |
|---|
| 376 | 484 | rts5227_init_params(pcr); |
|---|
| 377 | 485 | pcr->ops = &rts522a_pcr_ops; |
|---|
| 378 | 486 | pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11); |
|---|
| 379 | 487 | pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3; |
|---|
| 488 | + |
|---|
| 489 | + option->dev_flags = LTR_L1SS_PWR_GATE_EN; |
|---|
| 490 | + option->ltr_en = true; |
|---|
| 491 | + |
|---|
| 492 | + /* init latency of active, idle, L1OFF to 60us, 300us, 3ms */ |
|---|
| 493 | + option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF; |
|---|
| 494 | + option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF; |
|---|
| 495 | + option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF; |
|---|
| 496 | + option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF; |
|---|
| 497 | + option->ltr_l1off_sspwrgate = 0x7F; |
|---|
| 498 | + option->ltr_l1off_snooze_sspwrgate = 0x78; |
|---|
| 499 | + |
|---|
| 500 | + pcr->option.ocp_en = 1; |
|---|
| 501 | + if (pcr->option.ocp_en) |
|---|
| 502 | + pcr->hw_param.interrupt_en |= SD_OC_INT_EN; |
|---|
| 503 | + pcr->hw_param.ocp_glitch = SD_OCP_GLITCH_10M; |
|---|
| 504 | + pcr->option.sd_800mA_ocp_thd = RTS522A_OCP_THD_800; |
|---|
| 505 | + |
|---|
| 380 | 506 | } |
|---|