|
@@ -103,8 +103,64 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
|
|
rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
|
|
rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
|
|
|
|
+{
|
|
|
|
+ struct rtsx_cr_option *option = &(pcr->option);
|
|
|
|
+ u32 lval;
|
|
|
|
+
|
|
|
|
+ if (CHK_PCI_PID(pcr, PID_524A))
|
|
|
|
+ rtsx_pci_read_config_dword(pcr,
|
|
|
|
+ PCR_ASPM_SETTING_REG1, &lval);
|
|
|
|
+ else
|
|
|
|
+ rtsx_pci_read_config_dword(pcr,
|
|
|
|
+ PCR_ASPM_SETTING_REG2, &lval);
|
|
|
|
+
|
|
|
|
+ if (lval & ASPM_L1_1_EN_MASK)
|
|
|
|
+ rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
|
|
|
+
|
|
|
|
+ if (lval & ASPM_L1_2_EN_MASK)
|
|
|
|
+ rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
|
|
|
+
|
|
|
|
+ if (lval & PM_L1_1_EN_MASK)
|
|
|
|
+ rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
|
|
|
+
|
|
|
|
+ if (lval & PM_L1_2_EN_MASK)
|
|
|
|
+ rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
|
|
|
+
|
|
|
|
+ if (option->ltr_en) {
|
|
|
|
+ u16 val;
|
|
|
|
+
|
|
|
|
+ pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
|
|
|
+ if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
|
|
|
+ option->ltr_enabled = true;
|
|
|
|
+ option->ltr_active = true;
|
|
|
|
+ rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
|
|
|
|
+ } else {
|
|
|
|
+ option->ltr_enabled = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
|
|
|
|
+{
|
|
|
|
+ struct rtsx_cr_option *option = &(pcr->option);
|
|
|
|
+
|
|
|
|
+ if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
|
|
|
|
+ | PM_L1_1_EN | PM_L1_2_EN))
|
|
|
|
+ option->force_clkreq_0 = false;
|
|
|
|
+ else
|
|
|
|
+ option->force_clkreq_0 = true;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
|
|
static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
|
|
{
|
|
{
|
|
|
|
+ struct rtsx_cr_option *option = &(pcr->option);
|
|
|
|
+
|
|
|
|
+ rts5249_init_from_cfg(pcr);
|
|
|
|
+ rts5249_init_from_hw(pcr);
|
|
|
|
+
|
|
rtsx_pci_init_cmd(pcr);
|
|
rtsx_pci_init_cmd(pcr);
|
|
|
|
|
|
/* Rest L1SUB Config */
|
|
/* Rest L1SUB Config */
|
|
@@ -125,7 +181,18 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
|
|
else
|
|
else
|
|
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
|
|
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
|
|
|
|
|
|
- return rtsx_pci_send_cmd(pcr, 100);
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
|
|
|
|
+ * to drive low, and we forcibly request clock.
|
|
|
|
+ */
|
|
|
|
+ if (option->force_clkreq_0)
|
|
|
|
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
|
|
|
|
+ FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
|
|
|
|
+ else
|
|
|
|
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
|
|
|
|
+ FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
|
|
|
|
+
|
|
|
|
+ return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
|
|
}
|
|
}
|
|
|
|
|
|
static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
|
|
static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
|
|
@@ -285,6 +352,31 @@ static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
|
return rtsx_pci_send_cmd(pcr, 100);
|
|
return rtsx_pci_send_cmd(pcr, 100);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable)
|
|
|
|
+{
|
|
|
|
+ struct rtsx_cr_option *option = &pcr->option;
|
|
|
|
+ u8 val = 0;
|
|
|
|
+
|
|
|
|
+ if (pcr->aspm_enabled == enable)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
|
|
|
|
+ if (enable)
|
|
|
|
+ val = pcr->aspm_en;
|
|
|
|
+ rtsx_pci_update_cfg_byte(pcr,
|
|
|
|
+ pcr->pcie_cap + PCI_EXP_LNKCTL,
|
|
|
|
+ ASPM_MASK_NEG, val);
|
|
|
|
+ } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
|
|
|
|
+ u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0;
|
|
|
|
+
|
|
|
|
+ if (!enable)
|
|
|
|
+ val = FORCE_ASPM_CTL0;
|
|
|
|
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pcr->aspm_enabled = enable;
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct pcr_ops rts5249_pcr_ops = {
|
|
static const struct pcr_ops rts5249_pcr_ops = {
|
|
.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
|
|
.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
|
|
.extra_init_hw = rts5249_extra_init_hw,
|
|
.extra_init_hw = rts5249_extra_init_hw,
|
|
@@ -297,6 +389,7 @@ static const struct pcr_ops rts5249_pcr_ops = {
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.switch_output_voltage = rtsx_base_switch_output_voltage,
|
|
.switch_output_voltage = rtsx_base_switch_output_voltage,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
|
|
+ .set_aspm = rts5249_set_aspm,
|
|
};
|
|
};
|
|
|
|
|
|
/* SD Pull Control Enable:
|
|
/* SD Pull Control Enable:
|
|
@@ -353,6 +446,8 @@ static const u32 rts5249_ms_pull_ctl_disable_tbl[] = {
|
|
|
|
|
|
void rts5249_init_params(struct rtsx_pcr *pcr)
|
|
void rts5249_init_params(struct rtsx_pcr *pcr)
|
|
{
|
|
{
|
|
|
|
+ struct rtsx_cr_option *option = &(pcr->option);
|
|
|
|
+
|
|
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
|
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
|
pcr->num_slots = 2;
|
|
pcr->num_slots = 2;
|
|
pcr->ops = &rts5249_pcr_ops;
|
|
pcr->ops = &rts5249_pcr_ops;
|
|
@@ -372,6 +467,20 @@ void rts5249_init_params(struct rtsx_pcr *pcr)
|
|
pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
|
|
pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
|
|
|
|
|
|
pcr->reg_pm_ctrl3 = PM_CTRL3;
|
|
pcr->reg_pm_ctrl3 = PM_CTRL3;
|
|
|
|
+
|
|
|
|
+ option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
|
|
|
|
+ | LTR_L1SS_PWR_GATE_EN);
|
|
|
|
+ option->ltr_en = true;
|
|
|
|
+
|
|
|
|
+ /* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */
|
|
|
|
+ option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
|
|
|
|
+ option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
|
|
|
|
+ option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
|
|
|
|
+ option->dev_aspm_mode = DEV_ASPM_DYNAMIC;
|
|
|
|
+ option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
|
|
|
|
+ option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF;
|
|
|
|
+ option->ltr_l1off_snooze_sspwrgate =
|
|
|
|
+ LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF;
|
|
}
|
|
}
|
|
|
|
|
|
static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val)
|
|
static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val)
|
|
@@ -459,6 +568,40 @@ static int rts524a_extra_init_hw(struct rtsx_pcr *pcr)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
|
|
|
|
+{
|
|
|
|
+ struct rtsx_cr_option *option = &(pcr->option);
|
|
|
|
+
|
|
|
|
+ u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
|
|
|
|
+ int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST);
|
|
|
|
+ int aspm_L1_1, aspm_L1_2;
|
|
|
|
+ u8 val = 0;
|
|
|
|
+
|
|
|
|
+ aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
|
|
|
|
+ aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
|
|
|
|
+
|
|
|
|
+ if (active) {
|
|
|
|
+ /* Run, latency: 60us */
|
|
|
|
+ if (aspm_L1_1)
|
|
|
|
+ val = option->ltr_l1off_snooze_sspwrgate;
|
|
|
|
+ } else {
|
|
|
|
+ /* L1off, latency: 300us */
|
|
|
|
+ if (aspm_L1_2)
|
|
|
|
+ val = option->ltr_l1off_sspwrgate;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (aspm_L1_1 || aspm_L1_2) {
|
|
|
|
+ if (rtsx_check_dev_flag(pcr,
|
|
|
|
+ LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
|
|
|
|
+ if (card_exist)
|
|
|
|
+ val &= ~L1OFF_MBIAS2_EN_5250;
|
|
|
|
+ else
|
|
|
|
+ val |= L1OFF_MBIAS2_EN_5250;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ rtsx_set_l1off_sub(pcr, val);
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct pcr_ops rts524a_pcr_ops = {
|
|
static const struct pcr_ops rts524a_pcr_ops = {
|
|
.write_phy = rts524a_write_phy,
|
|
.write_phy = rts524a_write_phy,
|
|
.read_phy = rts524a_read_phy,
|
|
.read_phy = rts524a_read_phy,
|
|
@@ -473,11 +616,16 @@ static const struct pcr_ops rts524a_pcr_ops = {
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.switch_output_voltage = rtsx_base_switch_output_voltage,
|
|
.switch_output_voltage = rtsx_base_switch_output_voltage,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
|
|
+ .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
|
|
|
|
+ .set_aspm = rts5249_set_aspm,
|
|
};
|
|
};
|
|
|
|
|
|
void rts524a_init_params(struct rtsx_pcr *pcr)
|
|
void rts524a_init_params(struct rtsx_pcr *pcr)
|
|
{
|
|
{
|
|
rts5249_init_params(pcr);
|
|
rts5249_init_params(pcr);
|
|
|
|
+ pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
|
|
|
|
+ pcr->option.ltr_l1off_snooze_sspwrgate =
|
|
|
|
+ LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
|
|
|
|
|
|
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
|
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
|
pcr->ops = &rts524a_pcr_ops;
|
|
pcr->ops = &rts524a_pcr_ops;
|
|
@@ -576,11 +724,16 @@ static const struct pcr_ops rts525a_pcr_ops = {
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.card_power_off = rtsx_base_card_power_off,
|
|
.switch_output_voltage = rts525a_switch_output_voltage,
|
|
.switch_output_voltage = rts525a_switch_output_voltage,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
.force_power_down = rtsx_base_force_power_down,
|
|
|
|
+ .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
|
|
|
|
+ .set_aspm = rts5249_set_aspm,
|
|
};
|
|
};
|
|
|
|
|
|
void rts525a_init_params(struct rtsx_pcr *pcr)
|
|
void rts525a_init_params(struct rtsx_pcr *pcr)
|
|
{
|
|
{
|
|
rts5249_init_params(pcr);
|
|
rts5249_init_params(pcr);
|
|
|
|
+ pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
|
|
|
|
+ pcr->option.ltr_l1off_snooze_sspwrgate =
|
|
|
|
+ LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
|
|
|
|
|
|
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
|
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
|
|
pcr->ops = &rts525a_pcr_ops;
|
|
pcr->ops = &rts525a_pcr_ops;
|