blob: 5c5a335c19563e2f472ec25dd3cbf2c1553a41b0 [file] [log] [blame]
zbao7d94cf92012-07-02 14:19:14 +08001/* $NoKeywords:$ */
2/**
3 * @file
4 *
5 * Various PCI service routines.
6 *
7 *
8 *
9 * @xrefitem bom "File Content Label" "Release Content"
10 * @e project: AGESA
11 * @e sub-project: GNB
12 * @e \$Revision: 63425 $ @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
13 *
14 */
15/*
16*****************************************************************************
17*
Siyuan Wang641f00c2013-06-08 11:50:55 +080018 * Copyright (c) 2008 - 2012, Advanced Micro Devices, Inc.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions are met:
23 * * Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * * Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
29 * its contributors may be used to endorse or promote products derived
30 * from this software without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zbao7d94cf92012-07-02 14:19:14 +080042* ***************************************************************************
43*
44*/
45
46
47#include "AGESA.h"
48#include "amdlib.h"
49#include "Gnb.h"
50#include "GnbLibPciAcc.h"
51#include "GnbLibPci.h"
52#include "GnbLib.h"
53#include "Filecode.h"
54#define FILECODE PROC_GNB_MODULES_GNBCOMMONLIB_GNBLIBPCI_FILECODE
55
56/*----------------------------------------------------------------------------------------*/
57/*
58 * Check if device present
59 *
60 *
61 *
62 * @param[in] Address PCI address (as described in PCI_ADDR)
63 * @param[in] StdHeader Standard configuration header
64 * @retval TRUE Device is present
65 * @retval FALSE Device is not present
66 */
67
68BOOLEAN
69GnbLibPciIsDevicePresent (
70 IN UINT32 Address,
71 IN AMD_CONFIG_PARAMS *StdHeader
72 )
73{
74 UINT32 DeviceId;
75 GnbLibPciRead (Address, AccessWidth32, &DeviceId, StdHeader);
76 if (DeviceId == 0xffffffff) {
77 return FALSE;
78 } else {
79 return TRUE;
80 }
81}
82
83
84/*----------------------------------------------------------------------------------------*/
85/*
86 * Check if device is bridge
87 *
88 *
89 *
90 * @param[in] Address PCI address (as described in PCI_ADDR)
91 * @param[in] StdHeader Standard configuration header
92 * @retval TRUE Device is a bridge
93 * @retval FALSE Device is not a bridge
94 */
95
96BOOLEAN
97GnbLibPciIsBridgeDevice (
98 IN UINT32 Address,
99 IN AMD_CONFIG_PARAMS *StdHeader
100 )
101{
102 UINT8 Header;
103 GnbLibPciRead (Address | 0xe, AccessWidth8, &Header, StdHeader);
104 if ((Header & 0x7f) == 1) {
105 return TRUE;
106 } else {
107 return FALSE;
108 }
109}
110
111/*----------------------------------------------------------------------------------------*/
112/*
113 * Check if device is multifunction
114 *
115 *
116 *
117 * @param[in] Address PCI address (as described in PCI_ADDR)
118 * @param[in] StdHeader Standard configuration header
119 * @retval TRUE Device is a multifunction device.
120 * @retval FALSE Device is a single function device.
121 *
122 */
123BOOLEAN
124GnbLibPciIsMultiFunctionDevice (
125 IN UINT32 Address,
126 IN AMD_CONFIG_PARAMS *StdHeader
127 )
128{
129 UINT8 Header;
130 GnbLibPciRead (Address | 0xe, AccessWidth8, &Header, StdHeader);
131 if ((Header & 0x80) != 0) {
132 return TRUE;
133 } else {
134 return FALSE;
135 }
136}
137
138/*----------------------------------------------------------------------------------------*/
139/*
140 * Check if device is PCIe device
141 *
142 *
143 *
144 * @param[in] Address PCI address (as described in PCI_ADDR)
145 * @param[in] StdHeader Standard configuration header
146 * @retval TRUE Device is a PCIe device
147 * @retval FALSE Device is not a PCIe device
148 *
149 */
150
151BOOLEAN
152GnbLibPciIsPcieDevice (
153 IN UINT32 Address,
154 IN AMD_CONFIG_PARAMS *StdHeader
155 )
156{
157 if (GnbLibFindPciCapability (Address, PCIE_CAP_ID, StdHeader) != 0 ) {
158 return TRUE;
159 } else {
160 return FALSE;
161 }
162}
163
164
165/*----------------------------------------------------------------------------------------*/
166/*
167 * Find PCI capability pointer
168 *
169 *
170 *
171 * @param[in] Address PCI address (as described in PCI_ADDR)
172 * @param[in] CapabilityId PCI capability ID
173 * @param[in] StdHeader Standard configuration header
174 * @retval Register address of capability pointer
175 *
176 */
177
178UINT8
179GnbLibFindPciCapability (
180 IN UINT32 Address,
181 IN UINT8 CapabilityId,
182 IN AMD_CONFIG_PARAMS *StdHeader
183 )
184{
185 UINT8 CapabilityPtr;
186 UINT8 CurrentCapabilityId;
187 CapabilityPtr = 0x34;
188 if (!GnbLibPciIsDevicePresent (Address, StdHeader)) {
189 return 0;
190 }
191 while (CapabilityPtr != 0) {
192 GnbLibPciRead (Address | CapabilityPtr, AccessWidth8 , &CapabilityPtr, StdHeader);
193 if (CapabilityPtr != 0) {
194 GnbLibPciRead (Address | CapabilityPtr , AccessWidth8 , &CurrentCapabilityId, StdHeader);
195 if (CurrentCapabilityId == CapabilityId) {
196 break;
197 }
198 CapabilityPtr++;
199 }
200 }
201 return CapabilityPtr;
202}
zbao7d94cf92012-07-02 14:19:14 +0800203
zbao7d94cf92012-07-02 14:19:14 +0800204/*----------------------------------------------------------------------------------------*/
205/*
206 * Scan range of device on PCI bus.
207 *
208 *
209 *
210 * @param[in] Start Start address to start scan from
211 * @param[in] End End address of scan
212 * @param[in] ScanData Supporting data
213 *
214 */
215/*----------------------------------------------------------------------------------------*/
216VOID
217GnbLibPciScan (
218 IN PCI_ADDR Start,
219 IN PCI_ADDR End,
220 IN GNB_PCI_SCAN_DATA *ScanData
221 )
222{
223 UINTN Bus;
224 UINTN Device;
225 UINTN LastDevice;
226 UINTN Function;
227 UINTN LastFunction;
228 PCI_ADDR PciDevice;
229 SCAN_STATUS Status;
230
231 for (Bus = Start.Address.Bus; Bus <= End.Address.Bus; Bus++) {
232 Device = (Bus == Start.Address.Bus) ? Start.Address.Device : 0x00;
233 LastDevice = (Bus == End.Address.Bus) ? End.Address.Device : 0x1F;
234 for ( ; Device <= LastDevice; Device++) {
235 if ((Bus == Start.Address.Bus) && (Device == Start.Address.Device)) {
236 Function = Start.Address.Function;
237 } else {
238 Function = 0x0;
239 }
240 PciDevice.AddressValue = MAKE_SBDFO (0, Bus, Device, Function, 0);
241 if (!GnbLibPciIsDevicePresent (PciDevice.AddressValue, ScanData->StdHeader)) {
242 continue;
243 }
244 if (GnbLibPciIsMultiFunctionDevice (PciDevice.AddressValue, ScanData->StdHeader)) {
245 if ((Bus == End.Address.Bus) && (Device == End.Address.Device)) {
246 LastFunction = Start.Address.Function;
247 } else {
248 LastFunction = 0x7;
249 }
250 } else {
251 LastFunction = 0x0;
252 }
253 for ( ; Function <= LastFunction; Function++) {
254 PciDevice.AddressValue = MAKE_SBDFO (0, Bus, Device, Function, 0);
255 if (GnbLibPciIsDevicePresent (PciDevice.AddressValue, ScanData->StdHeader)) {
256 Status = ScanData->GnbScanCallback (PciDevice, ScanData);
257 if ((Status & SCAN_SKIP_FUNCTIONS) != 0) {
258 Function = LastFunction + 1;
259 }
260 if ((Status & SCAN_SKIP_DEVICES) != 0) {
261 Device = LastDevice + 1;
262 }
263 if ((Status & SCAN_SKIP_BUSES) != 0) {
264 Bus = End.Address.Bus + 1;
265 }
266 }
267 }
268 }
269 }
270}
271
272/*----------------------------------------------------------------------------------------*/
273/**
274 * Scan all subordinate buses
275 *
276 *
277 * @param[in] Bridge PCI bridge address
278 * @param[in,out] ScanData Scan configuration data
279 *
280 */
281VOID
282GnbLibPciScanSecondaryBus (
283 IN PCI_ADDR Bridge,
284 IN OUT GNB_PCI_SCAN_DATA *ScanData
285 )
286{
287 PCI_ADDR StartRange;
288 PCI_ADDR EndRange;
289 UINT8 SecondaryBus;
290 GnbLibPciRead (Bridge.AddressValue | 0x19, AccessWidth8, &SecondaryBus, ScanData->StdHeader);
291 if (SecondaryBus != 0) {
292 StartRange.AddressValue = MAKE_SBDFO (0, SecondaryBus, 0, 0, 0);
293 EndRange.AddressValue = MAKE_SBDFO (0, SecondaryBus, 0x1f, 0x7, 0);
294 GnbLibPciScan (StartRange, EndRange, ScanData);
295 }
296}
297
298/*----------------------------------------------------------------------------------------*/
299/**
300 * Get PCIe device type
301 *
302 *
303 *
304 * @param[in] Device PCI address of device.
305 * @param[in] StdHeader Northbridge configuration structure pointer.
306 *
307 * @retval PCIE_DEVICE_TYPE
308 */
309 /*----------------------------------------------------------------------------------------*/
310
311PCIE_DEVICE_TYPE
312GnbLibGetPcieDeviceType (
313 IN PCI_ADDR Device,
314 IN AMD_CONFIG_PARAMS *StdHeader
315 )
316{
317 UINT8 PcieCapPtr;
318 UINT8 Value;
319
320 PcieCapPtr = GnbLibFindPciCapability (Device.AddressValue, PCIE_CAP_ID, StdHeader);
321 if (PcieCapPtr != 0) {
322 GnbLibPciRead (Device.AddressValue | (PcieCapPtr + 0x2) , AccessWidth8, &Value, StdHeader);
323 return Value >> 4;
324 }
325 return PcieNotPcieDevice;
326}
327
328/*----------------------------------------------------------------------------------------*/
329/**
330 * Save config space area
331 *
332 *
333 *
334 * @param[in] Address PCI address of device.
335 * @param[in] StartRegisterAddress Start register address.
336 * @param[in] EndRegisterAddress End register address.
337 * @param[in] Width Acess width.
338 * @param[in] StdHeader Standard header.
339 *
340 */
341 /*----------------------------------------------------------------------------------------*/
342
343VOID
344GnbLibS3SaveConfigSpace (
345 IN UINT32 Address,
346 IN UINT16 StartRegisterAddress,
347 IN UINT16 EndRegisterAddress,
348 IN ACCESS_WIDTH Width,
349 IN AMD_CONFIG_PARAMS *StdHeader
350 )
351{
352 UINT16 Index;
353 UINT16 Delta;
354 UINT16 Length;
355 Length = (StartRegisterAddress < EndRegisterAddress) ? (EndRegisterAddress - StartRegisterAddress) : (StartRegisterAddress - EndRegisterAddress);
356 Delta = LibAmdAccessWidth (Width);
357 for (Index = 0; Index <= Length; Index = Index + Delta) {
358 GnbLibPciRMW (
359 Address | ((StartRegisterAddress < EndRegisterAddress) ? (StartRegisterAddress + Index) : (StartRegisterAddress - Index)),
360 Width,
361 0xffffffff,
362 0x0,
363 StdHeader
364 );
365 }
366}