mirror of https://gitee.com/openkylin/linux.git
mfd: rts5249: Add support for RTS5250S power saving
Enable power saving for RTS5250S as following steps: 1.Set 0xFE58 to enable clock power management. 2.Check cfg space whether support L1SS or not. 3.If support L1SS, set 0xFF03 to free clkreq. 4.When entering idle status, enable aspm and set parameters for L1SS and LTR. 5.Wnen entering run status, disable aspm and set parameters for L1SS and LTR. If entering L1SS mode successfully, electric current will be below 2mA. Signed-off-by: Rui Feng <rui_feng@realsil.com.cn> Signed-off-by: Lee Jones <lee.jones@linaro.org>
This commit is contained in:
parent
3137497232
commit
8275b77a15
|
@ -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;
|
||||||
|
|
|
@ -79,6 +79,96 @@ static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr)
|
||||||
0xFC, 0);
|
0xFC, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
|
||||||
|
{
|
||||||
|
rtsx_pci_write_register(pcr, MSGTXDATA0,
|
||||||
|
MASK_8_BIT_DEF, (u8) (latency & 0xFF));
|
||||||
|
rtsx_pci_write_register(pcr, MSGTXDATA1,
|
||||||
|
MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF));
|
||||||
|
rtsx_pci_write_register(pcr, MSGTXDATA2,
|
||||||
|
MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF));
|
||||||
|
rtsx_pci_write_register(pcr, MSGTXDATA3,
|
||||||
|
MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF));
|
||||||
|
rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK |
|
||||||
|
LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
|
||||||
|
{
|
||||||
|
if (pcr->ops->set_ltr_latency)
|
||||||
|
return pcr->ops->set_ltr_latency(pcr, latency);
|
||||||
|
else
|
||||||
|
return rtsx_comm_set_ltr_latency(pcr, latency);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||||
|
{
|
||||||
|
struct rtsx_cr_option *option = &pcr->option;
|
||||||
|
|
||||||
|
if (pcr->aspm_enabled == enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
|
||||||
|
if (enable)
|
||||||
|
rtsx_pci_enable_aspm(pcr);
|
||||||
|
else
|
||||||
|
rtsx_pci_disable_aspm(pcr);
|
||||||
|
} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
|
||||||
|
u8 mask = FORCE_ASPM_VAL_MASK;
|
||||||
|
u8 val = 0;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
val = pcr->aspm_en;
|
||||||
|
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pcr->aspm_enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtsx_disable_aspm(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
if (pcr->ops->set_aspm)
|
||||||
|
pcr->ops->set_aspm(pcr, false);
|
||||||
|
else
|
||||||
|
rtsx_comm_set_aspm(pcr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val)
|
||||||
|
{
|
||||||
|
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active)
|
||||||
|
{
|
||||||
|
if (pcr->ops->set_l1off_cfg_sub_d0)
|
||||||
|
pcr->ops->set_l1off_cfg_sub_d0(pcr, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
struct rtsx_cr_option *option = &pcr->option;
|
||||||
|
|
||||||
|
rtsx_disable_aspm(pcr);
|
||||||
|
|
||||||
|
if (option->ltr_enabled)
|
||||||
|
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
|
||||||
|
|
||||||
|
if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
|
||||||
|
rtsx_set_l1off_sub_cfg_d0(pcr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtsx_pm_full_on(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
if (pcr->ops->full_on)
|
||||||
|
pcr->ops->full_on(pcr);
|
||||||
|
else
|
||||||
|
rtsx_comm_pm_full_on(pcr);
|
||||||
|
}
|
||||||
|
|
||||||
void rtsx_pci_start_run(struct rtsx_pcr *pcr)
|
void rtsx_pci_start_run(struct rtsx_pcr *pcr)
|
||||||
{
|
{
|
||||||
/* If pci device removed, don't queue idle work any more */
|
/* If pci device removed, don't queue idle work any more */
|
||||||
|
@ -89,9 +179,7 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
|
||||||
pcr->state = PDEV_STAT_RUN;
|
pcr->state = PDEV_STAT_RUN;
|
||||||
if (pcr->ops->enable_auto_blink)
|
if (pcr->ops->enable_auto_blink)
|
||||||
pcr->ops->enable_auto_blink(pcr);
|
pcr->ops->enable_auto_blink(pcr);
|
||||||
|
rtsx_pm_full_on(pcr);
|
||||||
if (pcr->aspm_en)
|
|
||||||
rtsx_pci_disable_aspm(pcr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
|
mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
|
||||||
|
@ -958,6 +1046,41 @@ static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
if (pcr->ops->set_aspm)
|
||||||
|
pcr->ops->set_aspm(pcr, true);
|
||||||
|
else
|
||||||
|
rtsx_comm_set_aspm(pcr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
struct rtsx_cr_option *option = &pcr->option;
|
||||||
|
|
||||||
|
if (option->ltr_enabled) {
|
||||||
|
u32 latency = option->ltr_l1off_latency;
|
||||||
|
|
||||||
|
if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
|
||||||
|
mdelay(option->l1_snooze_delay);
|
||||||
|
|
||||||
|
rtsx_set_ltr_latency(pcr, latency);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
|
||||||
|
rtsx_set_l1off_sub_cfg_d0(pcr, 0);
|
||||||
|
|
||||||
|
rtsx_enable_aspm(pcr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
|
||||||
|
{
|
||||||
|
if (pcr->ops->power_saving)
|
||||||
|
pcr->ops->power_saving(pcr);
|
||||||
|
else
|
||||||
|
rtsx_comm_pm_power_saving(pcr);
|
||||||
|
}
|
||||||
|
|
||||||
static void rtsx_pci_idle_work(struct work_struct *work)
|
static void rtsx_pci_idle_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct delayed_work *dwork = to_delayed_work(work);
|
struct delayed_work *dwork = to_delayed_work(work);
|
||||||
|
@ -974,8 +1097,7 @@ static void rtsx_pci_idle_work(struct work_struct *work)
|
||||||
if (pcr->ops->turn_off_led)
|
if (pcr->ops->turn_off_led)
|
||||||
pcr->ops->turn_off_led(pcr);
|
pcr->ops->turn_off_led(pcr);
|
||||||
|
|
||||||
if (pcr->aspm_en)
|
rtsx_pm_power_saving(pcr);
|
||||||
rtsx_pci_enable_aspm(pcr);
|
|
||||||
|
|
||||||
mutex_unlock(&pcr->pcr_mutex);
|
mutex_unlock(&pcr->pcr_mutex);
|
||||||
}
|
}
|
||||||
|
@ -1063,6 +1185,16 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
switch (PCI_PID(pcr)) {
|
||||||
|
case PID_5250:
|
||||||
|
case PID_524A:
|
||||||
|
case PID_525A:
|
||||||
|
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable clk_request_n to enable clock power management */
|
/* Enable clk_request_n to enable clock power management */
|
||||||
rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
|
rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
|
||||||
/* Enter L1 when host tx idle */
|
/* Enter L1 when host tx idle */
|
||||||
|
|
|
@ -32,6 +32,18 @@
|
||||||
#define RTS524A_PME_FORCE_CTL 0xFF78
|
#define RTS524A_PME_FORCE_CTL 0xFF78
|
||||||
#define RTS524A_PM_CTRL3 0xFF7E
|
#define RTS524A_PM_CTRL3 0xFF7E
|
||||||
|
|
||||||
|
#define LTR_ACTIVE_LATENCY_DEF 0x883C
|
||||||
|
#define LTR_IDLE_LATENCY_DEF 0x892C
|
||||||
|
#define LTR_L1OFF_LATENCY_DEF 0x9003
|
||||||
|
#define L1_SNOOZE_DELAY_DEF 1
|
||||||
|
#define LTR_L1OFF_SSPWRGATE_5249_DEF 0xAF
|
||||||
|
#define LTR_L1OFF_SSPWRGATE_5250_DEF 0xFF
|
||||||
|
#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF 0xAC
|
||||||
|
#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF 0xF8
|
||||||
|
#define CMD_TIMEOUT_DEF 100
|
||||||
|
#define ASPM_MASK_NEG 0xFC
|
||||||
|
#define MASK_8_BIT_DEF 0xFF
|
||||||
|
|
||||||
int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
|
int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
|
||||||
int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
|
int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
|
||||||
|
|
||||||
|
@ -85,5 +97,7 @@ do { \
|
||||||
|
|
||||||
/* generic operations */
|
/* generic operations */
|
||||||
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
|
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
|
||||||
|
int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency);
|
||||||
|
int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -573,6 +573,12 @@
|
||||||
#define MSGTXDATA3 0xFE47
|
#define MSGTXDATA3 0xFE47
|
||||||
#define MSGTXCTL 0xFE48
|
#define MSGTXCTL 0xFE48
|
||||||
#define LTR_CTL 0xFE4A
|
#define LTR_CTL 0xFE4A
|
||||||
|
#define LTR_TX_EN_MASK BIT(7)
|
||||||
|
#define LTR_TX_EN_1 BIT(7)
|
||||||
|
#define LTR_TX_EN_0 0
|
||||||
|
#define LTR_LATENCY_MODE_MASK BIT(6)
|
||||||
|
#define LTR_LATENCY_MODE_HW 0
|
||||||
|
#define LTR_LATENCY_MODE_SW BIT(6)
|
||||||
#define OBFF_CFG 0xFE4C
|
#define OBFF_CFG 0xFE4C
|
||||||
|
|
||||||
#define CDRESUMECTL 0xFE52
|
#define CDRESUMECTL 0xFE52
|
||||||
|
@ -616,11 +622,15 @@
|
||||||
#define L1SUB_CONFIG2 0xFE8E
|
#define L1SUB_CONFIG2 0xFE8E
|
||||||
#define L1SUB_AUTO_CFG 0x02
|
#define L1SUB_AUTO_CFG 0x02
|
||||||
#define L1SUB_CONFIG3 0xFE8F
|
#define L1SUB_CONFIG3 0xFE8F
|
||||||
|
#define L1OFF_MBIAS2_EN_5250 BIT(7)
|
||||||
|
|
||||||
#define DUMMY_REG_RESET_0 0xFE90
|
#define DUMMY_REG_RESET_0 0xFE90
|
||||||
|
|
||||||
#define AUTOLOAD_CFG_BASE 0xFF00
|
#define AUTOLOAD_CFG_BASE 0xFF00
|
||||||
#define PETXCFG 0xFF03
|
#define PETXCFG 0xFF03
|
||||||
|
#define FORCE_CLKREQ_DELINK_MASK BIT(7)
|
||||||
|
#define FORCE_CLKREQ_LOW 0x80
|
||||||
|
#define FORCE_CLKREQ_HIGH 0x00
|
||||||
|
|
||||||
#define PM_CTRL1 0xFF44
|
#define PM_CTRL1 0xFF44
|
||||||
#define CD_RESUME_EN_MASK 0xF0
|
#define CD_RESUME_EN_MASK 0xF0
|
||||||
|
@ -844,6 +854,9 @@
|
||||||
#define PHY_DIG1E_RX_EN_KEEP 0x0001
|
#define PHY_DIG1E_RX_EN_KEEP 0x0001
|
||||||
#define PHY_DUM_REG 0x1F
|
#define PHY_DUM_REG 0x1F
|
||||||
|
|
||||||
|
#define PCR_ASPM_SETTING_REG1 0x160
|
||||||
|
#define PCR_ASPM_SETTING_REG2 0x168
|
||||||
|
|
||||||
#define PCR_SETTING_REG1 0x724
|
#define PCR_SETTING_REG1 0x724
|
||||||
#define PCR_SETTING_REG2 0x814
|
#define PCR_SETTING_REG2 0x814
|
||||||
#define PCR_SETTING_REG3 0x747
|
#define PCR_SETTING_REG3 0x747
|
||||||
|
@ -876,14 +889,79 @@ struct pcr_ops {
|
||||||
int (*conv_clk_and_div_n)(int clk, int dir);
|
int (*conv_clk_and_div_n)(int clk, int dir);
|
||||||
void (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
|
void (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
|
||||||
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
|
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
|
||||||
|
|
||||||
|
void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
|
||||||
|
int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
|
||||||
|
int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val);
|
||||||
|
void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active);
|
||||||
|
void (*full_on)(struct rtsx_pcr *pcr);
|
||||||
|
void (*power_saving)(struct rtsx_pcr *pcr);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN};
|
enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN};
|
||||||
|
|
||||||
|
#define ASPM_L1_1_EN_MASK BIT(3)
|
||||||
|
#define ASPM_L1_2_EN_MASK BIT(2)
|
||||||
|
#define PM_L1_1_EN_MASK BIT(1)
|
||||||
|
#define PM_L1_2_EN_MASK BIT(0)
|
||||||
|
|
||||||
|
#define ASPM_L1_1_EN BIT(0)
|
||||||
|
#define ASPM_L1_2_EN BIT(1)
|
||||||
|
#define PM_L1_1_EN BIT(2)
|
||||||
|
#define PM_L1_2_EN BIT(3)
|
||||||
|
#define LTR_L1SS_PWR_GATE_EN BIT(4)
|
||||||
|
#define L1_SNOOZE_TEST_EN BIT(5)
|
||||||
|
#define LTR_L1SS_PWR_GATE_CHECK_CARD_EN BIT(6)
|
||||||
|
|
||||||
|
enum dev_aspm_mode {
|
||||||
|
DEV_ASPM_DISABLE = 0,
|
||||||
|
DEV_ASPM_DYNAMIC,
|
||||||
|
DEV_ASPM_BACKDOOR,
|
||||||
|
DEV_ASPM_STATIC,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* struct rtsx_cr_option - card reader option
|
||||||
|
* @dev_flags: device flags
|
||||||
|
* @force_clkreq_0: force clock request
|
||||||
|
* @ltr_en: enable ltr mode flag
|
||||||
|
* @ltr_enabled: ltr mode in configure space flag
|
||||||
|
* @ltr_active: ltr mode status
|
||||||
|
* @ltr_active_latency: ltr mode active latency
|
||||||
|
* @ltr_idle_latency: ltr mode idle latency
|
||||||
|
* @ltr_l1off_latency: ltr mode l1off latency
|
||||||
|
* @dev_aspm_mode: device aspm mode
|
||||||
|
* @l1_snooze_delay: l1 snooze delay
|
||||||
|
* @ltr_l1off_sspwrgate: ltr l1off sspwrgate
|
||||||
|
* @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
|
||||||
|
*/
|
||||||
|
struct rtsx_cr_option {
|
||||||
|
u32 dev_flags;
|
||||||
|
bool force_clkreq_0;
|
||||||
|
bool ltr_en;
|
||||||
|
bool ltr_enabled;
|
||||||
|
bool ltr_active;
|
||||||
|
u32 ltr_active_latency;
|
||||||
|
u32 ltr_idle_latency;
|
||||||
|
u32 ltr_l1off_latency;
|
||||||
|
enum dev_aspm_mode dev_aspm_mode;
|
||||||
|
u32 l1_snooze_delay;
|
||||||
|
u8 ltr_l1off_sspwrgate;
|
||||||
|
u8 ltr_l1off_snooze_sspwrgate;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define rtsx_set_dev_flag(cr, flag) \
|
||||||
|
((cr)->option.dev_flags |= (flag))
|
||||||
|
#define rtsx_clear_dev_flag(cr, flag) \
|
||||||
|
((cr)->option.dev_flags &= ~(flag))
|
||||||
|
#define rtsx_check_dev_flag(cr, flag) \
|
||||||
|
((cr)->option.dev_flags & (flag))
|
||||||
|
|
||||||
struct rtsx_pcr {
|
struct rtsx_pcr {
|
||||||
struct pci_dev *pci;
|
struct pci_dev *pci;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
int pcie_cap;
|
int pcie_cap;
|
||||||
|
struct rtsx_cr_option option;
|
||||||
|
|
||||||
/* pci resources */
|
/* pci resources */
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
|
@ -940,6 +1018,7 @@ struct rtsx_pcr {
|
||||||
u8 card_drive_sel;
|
u8 card_drive_sel;
|
||||||
#define ASPM_L1_EN 0x02
|
#define ASPM_L1_EN 0x02
|
||||||
u8 aspm_en;
|
u8 aspm_en;
|
||||||
|
bool aspm_enabled;
|
||||||
|
|
||||||
#define PCR_MS_PMOS (1 << 0)
|
#define PCR_MS_PMOS (1 << 0)
|
||||||
#define PCR_REVERSE_SOCKET (1 << 1)
|
#define PCR_REVERSE_SOCKET (1 << 1)
|
||||||
|
@ -964,6 +1043,11 @@ struct rtsx_pcr {
|
||||||
u8 dma_error_count;
|
u8 dma_error_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PID_524A 0x524A
|
||||||
|
#define PID_5249 0x5249
|
||||||
|
#define PID_5250 0x5250
|
||||||
|
#define PID_525A 0x525A
|
||||||
|
|
||||||
#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid))
|
#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid))
|
||||||
#define PCI_VID(pcr) ((pcr)->pci->vendor)
|
#define PCI_VID(pcr) ((pcr)->pci->vendor)
|
||||||
#define PCI_PID(pcr) ((pcr)->pci->device)
|
#define PCI_PID(pcr) ((pcr)->pci->device)
|
||||||
|
|
Loading…
Reference in New Issue