Commit 81229d91 authored by Harrison Meng's avatar Harrison Meng Committed by Wu Gao
Browse files

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: default avatarHarrison Meng <quic_hmeng@quicinc.com>
parent 521fadd2
......@@ -173,6 +173,7 @@
#define REFCLK_STABILIZATION_DELAY_US_MAX (1005)
#define LINK_UP_TIMEOUT_US_MIN (5000)
#define LINK_UP_TIMEOUT_US_MAX (5100)
#define LINK_CHECK_COUNT_MAX (20)
#define LINK_UP_CHECK_MAX_COUNT (20)
#define EP_UP_TIMEOUT_US_MIN (1000)
#define EP_UP_TIMEOUT_US_MAX (1005)
......@@ -6608,6 +6609,88 @@ static int msm_pcie_set_link_width(struct msm_pcie_dev_t *pcie_dev,
return 0;
}
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_CHECK_COUNT_MAX);
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(msm_pcie_dsp_link_control);
void msm_pcie_allow_l1(struct pci_dev *pci_dev)
{
struct pci_dev *root_pci_dev;
......
......@@ -212,6 +212,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)
......@@ -269,6 +280,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 */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment