pci: msm: Add API to control pcie link state of NTN3 downstream port

On CPE platform, there is ntn3 pcie switch locates between RC and
Wlan, so the wlan pcie link is separated two parts, RC<->USP and
DSP<->WLAN, when pcie link suspend/resume, the link status of these
two buses is different, when link suspend the RC<->USP is not powered
off due to the existence of Ethernet device under same pcie switch.
For the case of cnss driver to power on/off wlan soc when pcie link
is still turned on, to avoid AER issue, before power on wlan soc cnss
driver needs to disable DSP<->WLAN link and then enable the link and
wait for link training completion Before powering off wlan soc cnss
driver also needs to disable DSP<->WLAN link at first. Function
msm_pcie_ntn3_dsp_link_control() is called by cnss driver to
enable(with link train)/disable DSP<->WLAN link when RC<->USP is on.

Change-Id: I8236b0786a14d6fb6c11805f24407edaa24e9836
Signed-off-by: Harrison Meng <quic_hmeng@quicinc.com>
Signed-off-by: Yogesh Jadav <quic_yjadav@quicinc.com>
Signed-off-by: Joco Zhang <quic_pingshen@quicinc.com>
This commit is contained in:
Harrison Meng 2022-04-19 22:49:48 -07:00 committed by Joco Zhang
parent caf2e99f0c
commit 3fcfd9ecc2
2 changed files with 99 additions and 0 deletions

View File

@ -8979,6 +8979,88 @@ static int msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev,
return -EINVAL;
}
int msm_pcie_dsp_link_control(struct pci_dev *pci_dev,
bool link_enable)
{
int ret = 0;
struct pci_dev *dsp_dev = NULL;
u16 link_control = 0;
u16 link_status = 0;
u32 link_capability = 0;
int link_check_count = 0;
bool link_trained = false;
struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(pci_dev->bus);
if (!pcie_dev->power_on)
return 0;
dsp_dev = pci_dev->bus->self;
if (pci_pcie_type(dsp_dev) != PCI_EXP_TYPE_DOWNSTREAM) {
PCIE_DBG(pcie_dev,
"PCIe: RC%d: no DSP<->EP link under this RC\n",
pcie_dev->rc_idx);
return 0;
}
pci_read_config_dword(dsp_dev, dsp_dev->pcie_cap + PCI_EXP_LNKCAP,
&link_capability);
pci_read_config_word(dsp_dev, dsp_dev->pcie_cap + PCI_EXP_LNKCTL,
&link_control);
if (link_enable) {
link_control &= ~PCI_EXP_LNKCTL_LD;
pci_write_config_word(dsp_dev,
dsp_dev->pcie_cap + PCI_EXP_LNKCTL,
link_control);
PCIE_DBG(pcie_dev,
"PCIe: RC%d: DSP<->EP Link is enabled\n",
pcie_dev->rc_idx);
/* Wait for up to 100ms for the link to come up */
do {
usleep_range(LINK_UP_TIMEOUT_US_MIN,
LINK_UP_TIMEOUT_US_MAX);
pci_read_config_word(dsp_dev,
dsp_dev->pcie_cap + PCI_EXP_LNKSTA,
&link_status);
if (link_capability & PCI_EXP_LNKCAP_DLLLARC)
link_trained = (!(link_status &
PCI_EXP_LNKSTA_LT)) &&
(link_status &
PCI_EXP_LNKSTA_DLLLA);
else
link_trained = !(link_status &
PCI_EXP_LNKSTA_LT);
if (link_trained)
break;
} while (link_check_count++ < LINK_UP_CHECK_MAX_COUNT);
if (link_trained) {
PCIE_DBG(pcie_dev,
"PCIe: RC%d: DSP<->EP link status: 0x%04x\n",
pcie_dev->rc_idx, link_status);
PCIE_DBG(pcie_dev,
"PCIe: RC%d: DSP<->EP Link is up after %d checkings\n",
pcie_dev->rc_idx, link_check_count);
} else {
PCIE_DBG(pcie_dev, "DSP<->EP link initialization failed\n");
ret = MSM_PCIE_ERROR;
}
} else {
link_control |= PCI_EXP_LNKCTL_LD;
pci_write_config_word(dsp_dev,
dsp_dev->pcie_cap + PCI_EXP_LNKCTL,
link_control);
PCIE_DBG(pcie_dev,
"PCIe: RC%d: DSP<->EP Link is disabled\n",
pcie_dev->rc_idx);
}
return ret;
}
EXPORT_SYMBOL_GPL(msm_pcie_dsp_link_control);
void msm_pcie_allow_l1(struct pci_dev *pci_dev)
{
struct pci_dev *root_pci_dev;

View File

@ -225,6 +225,17 @@ int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base,
*/
int msm_pcie_reg_dump(struct pci_dev *pci_dev, u8 *buff, u32 len);
/*
* msm_pcie_dsp_link_control - enable/disable DSP link
* @pci_dev: pci device structure, endpoint of this DSP
* @link_enable true to enable, false to disable
*
* This function enable(include training)/disable link between PCIe
* switch DSP and endpoint attached.
* Return: 0 on success, negative value on error
*/
int msm_pcie_dsp_link_control(struct pci_dev *pci_dev,
bool link_enable);
#else /* !CONFIG_PCI_MSM */
static inline int msm_pcie_pm_control(enum msm_pcie_pm_opt pm_opt, u32 busnr,
void *user, void *data, u32 options)
@ -287,6 +298,12 @@ static inline int msm_pcie_reg_dump(struct pci_dev *pci_dev, u8 *buff, u32 len)
{
return -ENODEV;
}
static inline int msm_pcie_dsp_link_control(struct pci_dev *pci_dev,
bool link_enable)
{
return -ENODEV;
}
#endif /* CONFIG_PCI_MSM */
#endif /* __MSM_PCIE_H */