xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/pcie_core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file pcie_core.c
2  *
3  * Contains PCIe related functions that are shared between different driver models (e.g. firmware
4  * builds, DHD builds, BMAC builds), in order to avoid code duplication.
5  *
6  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
7  *
8  * Copyright (C) 1999-2017, Broadcom Corporation
9  *
10  *      Unless you and Broadcom execute a separate written software license
11  * agreement governing use of this software, this software is licensed to you
12  * under the terms of the GNU General Public License version 2 (the "GPL"),
13  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
14  * following added to such license:
15  *
16  *      As a special exception, the copyright holders of this software give you
17  * permission to link this software with independent modules, and to copy and
18  * distribute the resulting executable under terms of your choice, provided that
19  * you also meet, for each linked independent module, the terms and conditions of
20  * the license of that module.  An independent module is a module which is not
21  * derived from this software.  The special exception does not apply to any
22  * modifications of the software.
23  *
24  *      Notwithstanding the above, under no circumstances may you combine this
25  * software in any way with any other Broadcom software provided under a license
26  * other than the GPL, without Broadcom's express prior written consent.
27  *
28  *
29  * <<Broadcom-WL-IPTag/Open:>>
30  *
31  * $Id: pcie_core.c 701962 2017-05-30 06:13:15Z $
32  */
33 
34 #include <bcm_cfg.h>
35 #include <typedefs.h>
36 #include <bcmutils.h>
37 #include <bcmdefs.h>
38 #include <osl.h>
39 #include <siutils.h>
40 #include <hndsoc.h>
41 #include <sbchipc.h>
42 #include <pcicfg.h>
43 #include <bcmdevs.h>
44 #include <siutils_priv.h>
45 #include "pcie_core.h"
46 
47 extern int dhdpcie_dongle_host_pre_wd_reset_sequence(si_t *sih, osl_t *osh);
48 extern int dhdpcie_dongle_host_post_wd_reset_sequence(si_t *sih, osl_t *osh);
49 
50 /* local prototypes */
51 
52 /* local variables */
53 
54 /* function definitions */
55 
56 #ifdef BCMDRIVER
57 
58 /* wd_mask/wd_val is only for chipc_corerev >= 65 */
pcie_watchdog_reset(osl_t * osh,si_t * sih,uint32 wd_mask,uint32 wd_val)59 void pcie_watchdog_reset(osl_t *osh, si_t *sih, uint32 wd_mask, uint32 wd_val)
60 {
61 	uint32 val, i, lsc;
62 	uint16 cfg_offset[] = {PCIECFGREG_STATUS_CMD, PCIECFGREG_PM_CSR,
63 		PCIECFGREG_MSI_CAP, PCIECFGREG_MSI_ADDR_L,
64 		PCIECFGREG_MSI_ADDR_H, PCIECFGREG_MSI_DATA,
65 		PCIECFGREG_LINK_STATUS_CTRL2, PCIECFGREG_RBAR_CTRL,
66 		PCIECFGREG_PML1_SUB_CTRL1, PCIECFGREG_REG_BAR2_CONFIG,
67 		PCIECFGREG_REG_BAR3_CONFIG};
68 	sbpcieregs_t *pcieregs = NULL;
69 	uint32 origidx = si_coreidx(sih);
70 	int32 bcmerror = BCME_ERROR;
71 
72 #ifdef BCMQT
73 	/* To avoid hang on FPGA, donot reset watchdog */
74 	if (CCREV(sih->ccrev) < 65) {
75 		si_setcoreidx(sih, origidx);
76 		return;
77 	}
78 #endif // endif
79 #ifdef BCMFPGA_HW
80 		if (CCREV(sih->ccrev) < 67) {
81 			/* To avoid hang on FPGA, donot reset watchdog */
82 			si_setcoreidx(sih, origidx);
83 			return;
84 		}
85 #endif // endif
86 
87 	/* Switch to PCIE2 core */
88 	pcieregs = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0);
89 	BCM_REFERENCE(pcieregs);
90 	ASSERT(pcieregs != NULL);
91 
92 	/* Disable/restore ASPM Control to protect the watchdog reset */
93 	W_REG(osh, &pcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL);
94 	lsc = R_REG(osh, &pcieregs->configdata);
95 	val = lsc & (~PCIE_ASPM_ENAB);
96 	W_REG(osh, &pcieregs->configdata, val);
97 
98 	/*
99 	 * CYW55560 - As part of watchdog reset, ARM gets reset and bootloader starts from fresh,
100 	 * So, pre wd reset sequcnce defined to make sure that pre init for bootloader can be done
101 	 */
102 	if (sih->chip == CYW55560_CHIP_ID) {
103 		if ((bcmerror = dhdpcie_dongle_host_pre_wd_reset_sequence(sih, osh))) {
104 			SI_ERROR(("%s: error %d pre wd reset seq\n",  __FUNCTION__, bcmerror));
105 			return;
106 		}
107 	}
108 
109 	si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4);
110 
111 #ifdef BCMQT
112 	OSL_DELAY(10000000);
113 #else
114 	OSL_DELAY(100000);
115 #endif // endif
116 
117 	/*
118 	 * CYW55560 - Once watchdog reset initiated, bootloader takes much time to be ready,
119 	 * [BL_READY bit set], to make sure that host should not access backplane till bootloader
120 	 * is not ready, post wd reset sequence is performed.
121 	 */
122 	if (sih->chip == CYW55560_CHIP_ID) {
123 		if ((bcmerror = dhdpcie_dongle_host_post_wd_reset_sequence(sih, osh))) {
124 			SI_ERROR(("%s: error %d post wd reset seq.\n", __FUNCTION__, bcmerror));
125 			return;
126 		}
127 	}
128 
129 	W_REG(osh, &pcieregs->configaddr, PCIECFGREG_LINK_STATUS_CTRL);
130 	W_REG(osh, &pcieregs->configdata, lsc);
131 
132 	if (sih->buscorerev <= 13) {
133 		/* Write configuration registers back to the shadow registers
134 		 * cause shadow registers are cleared out after watchdog reset.
135 		 */
136 		for (i = 0; i < ARRAYSIZE(cfg_offset); i++) {
137 			W_REG(osh, &pcieregs->configaddr, cfg_offset[i]);
138 			val = R_REG(osh, &pcieregs->configdata);
139 			W_REG(osh, &pcieregs->configdata, val);
140 		}
141 	}
142 	si_setcoreidx(sih, origidx);
143 }
144 
145 /* CRWLPCIEGEN2-117 pcie_pipe_Iddq should be controlled
146  * by the L12 state from MAC to save power by putting the
147  * SerDes analog in IDDQ mode
148  */
pcie_serdes_iddqdisable(osl_t * osh,si_t * sih,sbpcieregs_t * sbpcieregs)149 void  pcie_serdes_iddqdisable(osl_t *osh, si_t *sih, sbpcieregs_t *sbpcieregs)
150 {
151 	sbpcieregs_t *pcie = NULL;
152 	uint crwlpciegen2_117_disable = 0;
153 	uint32 origidx = si_coreidx(sih);
154 
155 	crwlpciegen2_117_disable = PCIE_PipeIddqDisable0 | PCIE_PipeIddqDisable1;
156 	/* Switch to PCIE2 core */
157 	pcie = (sbpcieregs_t *)si_setcore(sih, PCIE2_CORE_ID, 0);
158 	BCM_REFERENCE(pcie);
159 	ASSERT(pcie != NULL);
160 
161 	OR_REG(osh, &sbpcieregs->control,
162 		crwlpciegen2_117_disable);
163 
164 	si_setcoreidx(sih, origidx);
165 }
166 
167 #define PCIE_PMCR_REFUP_MASK 0x3f0001e0
168 #define PCIE_PMCR_REFEXT_MASK 0x400000
169 #define PCIE_PMCR_REFUP_100US 0x38000080
170 #define PCIE_PMCR_REFEXT_100US 0x400000
171 
172 /* Set PCIE TRefUp time to 100us */
pcie_set_trefup_time_100us(si_t * sih)173 void pcie_set_trefup_time_100us(si_t *sih)
174 {
175 	si_corereg(sih, sih->buscoreidx,
176 		OFFSETOF(sbpcieregs_t, configaddr), ~0, PCI_PMCR_REFUP);
177 	si_corereg(sih, sih->buscoreidx,
178 		OFFSETOF(sbpcieregs_t, configdata), PCIE_PMCR_REFUP_MASK, PCIE_PMCR_REFUP_100US);
179 
180 	si_corereg(sih, sih->buscoreidx,
181 		OFFSETOF(sbpcieregs_t, configaddr), ~0, PCI_PMCR_REFUP_EXT);
182 	si_corereg(sih, sih->buscoreidx,
183 		OFFSETOF(sbpcieregs_t, configdata), PCIE_PMCR_REFEXT_MASK, PCIE_PMCR_REFEXT_100US);
184 }
185 
186 #endif /* BCMDRIVER */
187