drivers/gfx/nvidia: Add driver for NVIDIA GPU
Add a driver for laptops with NVIDIA Optimus (hybrid) graphics. The driver provides ACPI support for dynamically powering on and off the GPU, NVIDIA Dynamic Boost support, and a function for enabling the GPU power in romstage. References: - DG-09845-001: NVIDIA GN20/QN20 Hardware Design Guide - DG-09954-001: NVIDIA GN20/QN20 Software Design Guide Change-Id: I2dec7aa2c8db7994f78a7cc1220502676e248465 Signed-off-by: Jeremy Soller <jeremy@system76.com> Signed-off-by: Tim Crawford <tcrawford@system76.com>
This commit is contained in:
		
				
					committed by
					
						 Tim Crawford
						Tim Crawford
					
				
			
			
				
	
			
			
			
						parent
						
							39d7b7ea64
						
					
				
				
					commit
					109ff15817
				
			
							
								
								
									
										38
									
								
								src/drivers/gfx/nvidia/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/drivers/gfx/nvidia/Kconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| config DRIVERS_GFX_NVIDIA | ||||
| 	bool | ||||
| 	default n | ||||
| 	help | ||||
| 	  Support for NVIDIA Optimus graphics | ||||
|  | ||||
| config DRIVERS_GFX_NVIDIA_BRIDGE | ||||
| 	hex "PCI bridge for the GPU device" | ||||
| 	default 0x01 | ||||
| 	depends on DRIVERS_GFX_NVIDIA | ||||
|  | ||||
| config DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST | ||||
| 	depends on DRIVERS_GFX_NVIDIA | ||||
| 	bool | ||||
| 	default n | ||||
| 	help | ||||
| 	  Support for NVIDIA Dynamic Boost | ||||
|  | ||||
| config DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_TPP | ||||
| 	int "Total processor power offset from default TGP in watts" | ||||
| 	default 45 | ||||
| 	depends on DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST | ||||
| 	help | ||||
| 	  This identifies the available power for the CPU or GPU boost | ||||
|  | ||||
| config DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_MIN | ||||
| 	int "Minimum TGP offset from default TGP in watts" | ||||
| 	default 0 | ||||
| 	depends on DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST | ||||
| 	help | ||||
| 	  This is used to transfer power from the GPU to the CPU | ||||
|  | ||||
| config DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_MAX | ||||
| 	int "Maximum TGP offset from default TGP in watts" | ||||
| 	default 0 | ||||
| 	depends on DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST | ||||
| 	help | ||||
| 	  This is used to transfer power from the CPU to the GPU | ||||
							
								
								
									
										5
									
								
								src/drivers/gfx/nvidia/Makefile.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/drivers/gfx/nvidia/Makefile.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only | ||||
|  | ||||
| romstage-$(CONFIG_DRIVERS_GFX_NVIDIA) += romstage.c | ||||
|  | ||||
| ramstage-$(CONFIG_DRIVERS_GFX_NVIDIA) += nvidia.c | ||||
							
								
								
									
										96
									
								
								src/drivers/gfx/nvidia/acpi/coffeelake.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/drivers/gfx/nvidia/acpi/coffeelake.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /* NVIDIA GC6 on CFL and CML CPU PCIe ports */ | ||||
|  | ||||
| // Memory mapped PCI express config space | ||||
| OperationRegion (PCIC, SystemMemory, CONFIG_ECAM_MMCONF_BASE_ADDRESS + (CONFIG_DRIVERS_GFX_NVIDIA_BRIDGE << 15), 0x1000) | ||||
|  | ||||
| Field (PCIC, ByteAcc, NoLock, Preserve) { | ||||
| 	PVID,   16, | ||||
| 	PDID,   16, | ||||
|  | ||||
| 	Offset (0x248), | ||||
| 		,   7, | ||||
| 	L23E,   1,      /* L23_Rdy Entry Request */ | ||||
| 	L23R,   1,      /* L23_Rdy to Detect Transition */ | ||||
|  | ||||
| 	Offset (0xC20), | ||||
| 		,   4, | ||||
| 	P0AP,   2,      /* Additional power savings */ | ||||
|  | ||||
| 	Offset (0xC38), | ||||
| 		,   3, | ||||
| 	P0RM,   1,      /* Robust squelch mechanism */ | ||||
| } | ||||
|  | ||||
| // Enter L23 | ||||
| Method (DL23, 0, Serialized) { | ||||
| 	Printf("      GPU PORT DL23 START") | ||||
|  | ||||
| 	L23E = 1 | ||||
| 	Sleep (16) | ||||
| 	Local0 = 0 | ||||
| 	While (L23E) { | ||||
| 		If ((Local0 > 4)) { | ||||
| 			Break | ||||
| 		} | ||||
|  | ||||
| 		Sleep (16) | ||||
| 		Local0++ | ||||
| 	} | ||||
|  | ||||
| 	P0RM = 1 | ||||
| 	P0AP = 3 | ||||
|  | ||||
| 	Printf("      GPU PORT DL23 FINISH") | ||||
| } | ||||
|  | ||||
| // Exit L23 | ||||
| Method (L23D, 0, Serialized) { | ||||
| 	Printf("      GPU PORT L23D START") | ||||
|  | ||||
| 	L23R = 1 | ||||
| 	Sleep (16) | ||||
| 	Local0 = 0 | ||||
| 	While (L23R) { | ||||
| 		If ((Local0 > 4)) { | ||||
| 			Break | ||||
| 		} | ||||
|  | ||||
| 		Sleep (16) | ||||
| 		Local0++ | ||||
| 	} | ||||
|  | ||||
| 	P0RM = 0 | ||||
| 	P0AP = 0 | ||||
|  | ||||
| 	Printf("      GPU PORT L23D FINISH") | ||||
| } | ||||
|  | ||||
| // Main power resource | ||||
| PowerResource (PWRR, 0, 0) { | ||||
| 	Name (_STA, 1) | ||||
|  | ||||
| 	Method (_ON, 0, Serialized) { | ||||
| 		Printf("GPU PORT PWRR._ON") | ||||
|  | ||||
| 		^^DEV0._ON() | ||||
|  | ||||
| 		_STA = 1 | ||||
| 	} | ||||
|  | ||||
| 	Method (_OFF, 0, Serialized) { | ||||
| 		Printf("GPU PORT PWRR._OFF") | ||||
|  | ||||
| 		^^DEV0._OFF() | ||||
|  | ||||
| 		_STA = 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Power resources for entering D0 | ||||
| Name (_PR0, Package () { PWRR }) | ||||
|  | ||||
| // Power resources for entering D3 | ||||
| Name (_PR3, Package () { PWRR }) | ||||
|  | ||||
| #include "common/gpu.asl" | ||||
							
								
								
									
										30
									
								
								src/drivers/gfx/nvidia/acpi/common/dsm.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/drivers/gfx/nvidia/acpi/common/dsm.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #define NV_ERROR_SUCCESS 0x0 | ||||
| #define NV_ERROR_UNSPECIFIED 0x80000001 | ||||
| #define NV_ERROR_UNSUPPORTED 0x80000002 | ||||
|  | ||||
| #include "gps.asl" | ||||
| #include "nvjt.asl" | ||||
|  | ||||
| Method (_DSM, 4, Serialized) { | ||||
| 	Printf("GPU _DSM") | ||||
| 	If (Arg0 == ToUUID (JT_DSM_GUID)) { | ||||
| 		If (ToInteger(Arg1) >= JT_REVISION_ID_MIN) { | ||||
| 			Return (NVJT(Arg2, Arg3)) | ||||
| 		} Else { | ||||
| 			Printf("  Unsupported JT revision: %o", SFST(Arg1)) | ||||
| 			Return (NV_ERROR_UNSUPPORTED) | ||||
| 		} | ||||
| 	} ElseIf (Arg0 == ToUUID (GPS_DSM_GUID)) { | ||||
| 		If (ToInteger(Arg1) == GPS_REVISION_ID) { | ||||
| 			Return (GPS(Arg2, Arg3)) | ||||
| 		} Else { | ||||
| 			Printf("  Unsupported GPS revision: %o", SFST(Arg1)) | ||||
| 			Return (NV_ERROR_UNSUPPORTED) | ||||
| 		} | ||||
| 	} Else { | ||||
| 		Printf("  Unsupported GUID: %o", IDST(Arg0)) | ||||
| 		Return (NV_ERROR_UNSPECIFIED) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										66
									
								
								src/drivers/gfx/nvidia/acpi/common/gps.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/drivers/gfx/nvidia/acpi/common/gps.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #define GPS_DSM_GUID "A3132D01-8CDA-49BA-A52E-BC9D46DF6B81" | ||||
| #define GPS_REVISION_ID 0x00000200 | ||||
| #define GPS_FUNC_SUPPORT 0x00000000 | ||||
| #define GPS_FUNC_PSHARESTATUS 0x00000020 | ||||
| #define GPS_FUNC_PSHAREPARAMS 0x0000002A | ||||
|  | ||||
| Method(GPS, 2, Serialized) { | ||||
| 	Printf("  GPU GPS") | ||||
| 	Switch(ToInteger(Arg0)) { | ||||
| 		Case(GPS_FUNC_SUPPORT) { | ||||
| 			Printf("    Supported Functions") | ||||
| 			Return(ITOB( | ||||
| 				(1 << GPS_FUNC_SUPPORT) | | ||||
| 				(1 << GPS_FUNC_PSHARESTATUS) | | ||||
| 				(1 << GPS_FUNC_PSHAREPARAMS) | ||||
| 			)) | ||||
| 		} | ||||
| 		Case(GPS_FUNC_PSHARESTATUS) { | ||||
| 			Printf("    Power Share Status") | ||||
| 			Return(ITOB(0)) | ||||
| 		} | ||||
| 		Case(GPS_FUNC_PSHAREPARAMS) { | ||||
| 			Printf("    Power Share Parameters") | ||||
|  | ||||
| 			CreateField(Arg1, 0, 4, QTYP) // Query type | ||||
|  | ||||
| 			Name(GPSP, Buffer(36) { 0x00 }) | ||||
| 			CreateDWordField(GPSP, 0, RSTS) // Response status | ||||
| 			CreateDWordField(GPSP, 4, VERS) // Version | ||||
|  | ||||
| 			// Set query type of response | ||||
| 			RSTS = QTYP | ||||
| 			// Set version of response | ||||
| 			VERS = 0x00010000 | ||||
|  | ||||
| 			Switch(ToInteger(QTYP)) { | ||||
| 				Case(0) { | ||||
| 					Printf("      Request Current Information") | ||||
| 					// No required information | ||||
| 					Return(GPSP) | ||||
| 				} | ||||
| 				Case(1) { | ||||
| 					Printf("      Request Supported Fields") | ||||
| 					// Support GPU temperature field | ||||
| 					RSTS |= (1 << 8) | ||||
| 					Return(GPSP) | ||||
| 				} | ||||
| 				Case(2) { | ||||
| 					Printf("      Request Current Limits") | ||||
| 					// No required limits | ||||
| 					Return(GPSP) | ||||
| 				} | ||||
| 				Default { | ||||
| 					Printf("      Unknown Query: %o", SFST(QTYP)) | ||||
| 					Return(NV_ERROR_UNSUPPORTED) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		Default { | ||||
| 			Printf("    Unsupported function: %o", SFST(Arg0)) | ||||
| 			Return(NV_ERROR_UNSUPPORTED) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										18
									
								
								src/drivers/gfx/nvidia/acpi/common/gpu.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/drivers/gfx/nvidia/acpi/common/gpu.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| Device (DEV0) { | ||||
| 	Name(_ADR, 0x00000000) | ||||
|  | ||||
| 	#include "utility.asl" | ||||
| 	#include "dsm.asl" | ||||
| 	#include "power.asl" | ||||
| } | ||||
|  | ||||
| #if CONFIG(DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST) | ||||
| Scope (\_SB) { | ||||
| 	Device(NPCF) { | ||||
| 		#include "utility.asl" | ||||
| 		#include "nvpcf.asl" | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										152
									
								
								src/drivers/gfx/nvidia/acpi/common/nvjt.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/drivers/gfx/nvidia/acpi/common/nvjt.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #define JT_DSM_GUID "CBECA351-067B-4924-9CBD-B46B00B86F34" | ||||
| #define JT_REVISION_ID_MIN 0x00000100 | ||||
| #define JT_REVISION_ID_MAX 0x00000200 | ||||
| #define JT_FUNC_SUPPORT 0x00000000 | ||||
| #define JT_FUNC_CAPS 0x00000001 | ||||
| #define JT_FUNC_POWERCONTROL 0x00000003 | ||||
|  | ||||
| //TODO: SMI traps and EGIN/XCLM | ||||
| #define JT_GPC_GSS 0 // Get current GPU GCx sleep status | ||||
| #define JT_GPC_EGNS 1 // Enter GC6 without self-refresh | ||||
| #define JT_GPC_EGIS 2 // Enter GC6 with self-refresh | ||||
| #define JT_GPC_XGXS 3 // Exit GC6 and stop self-refresh | ||||
| #define JT_GPC_XGIS 4 // Exit GC6 for self-refresh update | ||||
|  | ||||
| #define JT_DFGC_NONE 0 // Handle request immediately | ||||
| #define JT_DFGC_DEFER 1 // Defer GPC and GPCX | ||||
| //TODO #define JT_DFGC_CLEAR 2 // Clear pending requests | ||||
|  | ||||
| // Deferred GC6 enter/exit until D3-cold (saved DFGC) | ||||
| Name(DFEN, 0) | ||||
|  | ||||
| // Deferred GC6 enter control (saved GPC) | ||||
| Name(DFCI, 0) | ||||
|  | ||||
| // Deferred GC6 exit control (saved GPCX) | ||||
| Name(DFCO, 0) | ||||
|  | ||||
| Method (NVJT, 2, Serialized) { | ||||
| 	Printf("  GPU NVJT") | ||||
| 	Switch (ToInteger(Arg0)) { | ||||
| 		Case (JT_FUNC_SUPPORT) { | ||||
| 			Printf("    Supported Functions") | ||||
| 			Return(ITOB( | ||||
| 				(1 << JT_FUNC_SUPPORT) | | ||||
| 				(1 << JT_FUNC_CAPS) | | ||||
| 				(1 << JT_FUNC_POWERCONTROL) | ||||
| 			)) | ||||
| 		} | ||||
| 		Case (JT_FUNC_CAPS) { | ||||
| 			Printf("    Capabilities") | ||||
| 			Return(ITOB( | ||||
| 				(1 << 0) | // G-SYNC NSVR power-saving features are enabled | ||||
| 				(1 << 1) | // NVSR disabled | ||||
| 				(2 << 3) | // Panel power and backlight are on the suspend rail | ||||
| 				(0 << 5) | // self-refresh controller remains powered while panel is powered | ||||
| 				(0 << 6) | // FB is not on the suspend rail but is powered on in GC6 | ||||
| 				(0 << 8) | // Combined power rail for all GPUs | ||||
| 				(0 << 10) | // External SPI ROM | ||||
| 				(1 << 11) | // No SMI handler for kernel panic exit while in GC6 | ||||
| 				(0 << 12) | // Supports notify on GC6 state done | ||||
| 				(1 << 13) | // Support deferred GC6 | ||||
| 				(1 << 14) | // Support fine-grained root port control | ||||
| 				(2 << 15) | // GC6 version is GC6-R | ||||
| 				(0 << 17) | // GC6 exit ISR is not supported | ||||
| 				(0 << 18) | // GC6 self wakeup not supported | ||||
| 				(JT_REVISION_ID_MAX << 20) // Highest revision supported | ||||
| 			)) | ||||
| 		} | ||||
| 		Case (JT_FUNC_POWERCONTROL) { | ||||
| 			Printf("    Power Control: %o", SFST(Arg1)) | ||||
|  | ||||
| 			CreateField (Arg1, 0, 3, GPC) // GPU power control | ||||
| 			CreateField (Arg1, 4, 1, PPC) // Panel power control | ||||
| 			CreateField (Arg1, 14, 2, DFGC) // Defer GC6 enter/exit until D3 cold | ||||
| 			CreateField (Arg1, 16, 3, GPCX) // Deferred GC6 exit control | ||||
|  | ||||
| 			// Save deferred GC6 request | ||||
| 			If ((ToInteger(GPC) != 0) || (ToInteger(DFGC) != 0)) { | ||||
| 				DFEN = DFGC | ||||
| 				DFCI = GPC | ||||
| 				DFCO = GPCX | ||||
| 			} | ||||
|  | ||||
| 			// Buffer to cache current state | ||||
| 			Name (JTBF, Buffer (4) { 0, 0, 0, 0 }) | ||||
| 			CreateField (JTBF, 0, 3, CGCS) // Current GC state | ||||
| 			CreateField (JTBF, 3, 1, CGPS) // Current GPU power status | ||||
| 			CreateField (JTBF, 7, 1, CPSS) // Current panel and SRC state (0 when on) | ||||
|  | ||||
| 			// If doing deferred GC6 request, return now | ||||
| 			If (ToInteger(DFGC) != 0) { | ||||
| 				CGCS = 1 | ||||
| 				CGPS = 1 | ||||
| 				Return (JTBF) | ||||
| 			} | ||||
|  | ||||
| 			// Apply requested state | ||||
| 			Switch (ToInteger(GPC)) { | ||||
| 				Case (JT_GPC_GSS) { | ||||
| 					Printf("    Get current GPU GCx sleep status") | ||||
| 					//TODO: include transitions! | ||||
| 					If (GTXS(DGPU_RST_N)) { | ||||
| 						// GPU powered on | ||||
| 						CGCS = 1 | ||||
| 						CGPS = 1 | ||||
| 					} ElseIf (GTXS(DGPU_PWR_EN)) { | ||||
| 						// GPU powered off, GC6 | ||||
| 						CGCS = 3 | ||||
| 						CGPS = 0 | ||||
| 					} Else { | ||||
| 						// GPU powered off, D3 cold | ||||
| 						CGCS = 2 | ||||
| 						CGPS = 0 | ||||
| 					} | ||||
| 				} | ||||
| 				Case (JT_GPC_EGNS) { | ||||
| 					Printf("    Enter GC6 without self-refresh") | ||||
| 					GC6I() | ||||
| 					CPSS = 1 | ||||
| 				} | ||||
| 				Case (JT_GPC_EGIS) { | ||||
| 					Printf("    Enter GC6 with self-refresh") | ||||
| 					GC6I() | ||||
| 					If (ToInteger(PPC) == 0) { | ||||
| 						CPSS = 0 | ||||
| 					} | ||||
| 				} | ||||
| 				Case (JT_GPC_XGXS) { | ||||
| 					Printf("    Exit GC6 and stop self-refresh") | ||||
| 					GC6O() | ||||
|  | ||||
| 					CGCS = 1 | ||||
| 					CGPS = 1 | ||||
| 					If (ToInteger(PPC) != 0) { | ||||
| 						CPSS = 0 | ||||
| 					} | ||||
| 				} | ||||
| 				Case (JT_GPC_XGIS) { | ||||
| 					Printf("    Exit GC6 for self-refresh update") | ||||
| 					GC6O() | ||||
|  | ||||
| 					CGCS = 1 | ||||
| 					CGPS = 1 | ||||
| 					If (ToInteger(PPC) != 0) { | ||||
| 						CPSS = 0 | ||||
| 					} | ||||
| 				} | ||||
| 				Default { | ||||
| 					Printf("    Unsupported GPU power control: %o", SFST(GPC)) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			Return (JTBF) | ||||
| 		} | ||||
| 		Default { | ||||
| 			Printf("    Unsupported function: %o", SFST(Arg0)) | ||||
| 			Return (NV_ERROR_UNSUPPORTED) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										113
									
								
								src/drivers/gfx/nvidia/acpi/common/nvpcf.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/drivers/gfx/nvidia/acpi/common/nvpcf.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #define NVPCF_DSM_GUID "36b49710-2483-11e7-9598-0800200c9a66" | ||||
| #define NVPCF_REVISION_ID 0x00000200 | ||||
| #define NVPCF_ERROR_SUCCESS 0x0 | ||||
| #define NVPCF_ERROR_GENERIC 0x80000001 | ||||
| #define NVPCF_ERROR_UNSUPPORTED 0x80000002 | ||||
| #define NVPCF_FUNC_GET_SUPPORTED 0x00000000 | ||||
| #define NVPCF_FUNC_GET_STATIC_CONFIG_TABLES 0x00000001 | ||||
| #define NVPCF_FUNC_UPDATE_DYNAMIC_PARAMS 0x00000002 | ||||
|  | ||||
| Name(_HID, "NVDA0820") | ||||
|  | ||||
| Name(_UID, "NPCF") | ||||
|  | ||||
| Method(_DSM, 4, Serialized) { | ||||
| 	Printf("NVPCF _DSM") | ||||
| 	If (Arg0 == ToUUID(NVPCF_DSM_GUID)) { | ||||
| 		If (ToInteger(Arg1) == NVPCF_REVISION_ID) { | ||||
| 			Return(NPCF(Arg2, Arg3)) | ||||
| 		} Else { | ||||
| 			Printf("  Unsupported NVPCF revision: %o", SFST(Arg1)) | ||||
| 			Return(NVPCF_ERROR_GENERIC) | ||||
| 		} | ||||
| 	} Else { | ||||
| 		Printf("  Unsupported GUID: %o", IDST(Arg0)) | ||||
| 		Return(NVPCF_ERROR_GENERIC) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| Method(NPCF, 2, Serialized) { | ||||
| 	Printf("  NVPCF NPCF") | ||||
| 	Switch(ToInteger(Arg0)) { | ||||
| 		Case(NVPCF_FUNC_GET_SUPPORTED) { | ||||
| 			Printf("    Supported Functions") | ||||
| 			Return(ITOB( | ||||
| 				(1 << NVPCF_FUNC_GET_SUPPORTED) | | ||||
| 				(1 << NVPCF_FUNC_GET_STATIC_CONFIG_TABLES) | | ||||
| 				(1 << NVPCF_FUNC_UPDATE_DYNAMIC_PARAMS) | ||||
| 			)) | ||||
| 		} | ||||
| 		Case(NVPCF_FUNC_GET_STATIC_CONFIG_TABLES) { | ||||
| 			Printf("    Get Static Config") | ||||
| 			Return(Buffer(14) { | ||||
| 				// Device table header | ||||
| 				0x20, 0x03, 0x01, | ||||
| 				// Intel + NVIDIA | ||||
| 				0x00, | ||||
| 				// Controller table header | ||||
| 				0x23, 0x04, 0x05, 0x01, | ||||
| 				// Dynamic boost controller | ||||
| 				0x01, | ||||
| 				// Supports DC | ||||
| 				0x01, | ||||
| 				// Reserved | ||||
| 				0x00, 0x00, 0x00, | ||||
| 				// Checksum | ||||
| 				0xAD | ||||
| 			}) | ||||
| 		} | ||||
| 		Case(NVPCF_FUNC_UPDATE_DYNAMIC_PARAMS) { | ||||
| 			Printf("    Update Dynamic Boost") | ||||
|  | ||||
| 			CreateField(Arg1, 0x28, 2, ICMD) // Input command | ||||
|  | ||||
| 			Name(PCFP, Buffer(49) { | ||||
| 				// Table version | ||||
| 				0x23, | ||||
| 				// Table header size | ||||
| 				0x05, | ||||
| 				// Size of common status in bytes | ||||
| 				0x10, | ||||
| 				// Size of controller entry in bytes | ||||
| 				0x1C, | ||||
| 				// Other fields filled in later | ||||
| 			}) | ||||
| 			CreateByteField(PCFP, 0x04, CCNT) // Controller count | ||||
| 			CreateWordField(PCFP, 0x19, ATPP) // AC TPP offset | ||||
| 			CreateWordField(PCFP, 0x1D, AMXP) // AC maximum TGP offset | ||||
| 			CreateWordField(PCFP, 0x21, AMNP) // AC minimum TGP offset | ||||
|  | ||||
| 			Switch(ToInteger(ICMD)) { | ||||
| 				Case(0) { | ||||
| 					Printf("      Get Controller Params") | ||||
| 					// Number of controllers | ||||
| 					CCNT = 1 | ||||
| 					// AC total processor power offset from default TGP in 1/8 watt units | ||||
| 					ATPP = (CONFIG_DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_TPP << 3) | ||||
| 					// AC maximum TGP offset from default TGP in 1/8 watt units | ||||
| 					AMXP = (CONFIG_DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_MAX << 3) | ||||
| 					// AC minimum TGP offset from default TGP in 1/8 watt units | ||||
| 					AMNP = (CONFIG_DRIVERS_GFX_NVIDIA_DYNAMIC_BOOST_MIN << 3) | ||||
| 					Printf("PCFP: %o", SFST(PCFP)) | ||||
| 					Return(PCFP) | ||||
| 				} | ||||
| 				Case(1) { | ||||
| 					Printf("      Set Controller Status") | ||||
| 					//TODO | ||||
| 					Printf("PCFP: %o", SFST(PCFP)) | ||||
| 					Return(PCFP) | ||||
| 				} | ||||
| 				Default { | ||||
| 					Printf("      Unknown Input Command: %o", SFST(ICMD)) | ||||
| 					Return(NV_ERROR_UNSUPPORTED) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		Default { | ||||
| 			Printf("    Unsupported function: %o", SFST(Arg0)) | ||||
| 			Return(NVPCF_ERROR_UNSUPPORTED) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										120
									
								
								src/drivers/gfx/nvidia/acpi/common/power.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/drivers/gfx/nvidia/acpi/common/power.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| //TODO: evaluate sleeps | ||||
|  | ||||
| OperationRegion (PCIC, PCI_Config, 0x00, 0xFF) | ||||
| Field (PCIC, DwordAcc, NoLock, Preserve) { | ||||
| 	Offset (0x40), | ||||
| 	SSID, 32, // Subsystem vendor and product ID | ||||
| } | ||||
|  | ||||
| // Enter GC6 | ||||
| Method(GC6I, 0, Serialized) { | ||||
| 	Printf("    GPU GC6I START") | ||||
|  | ||||
| 	// Enter L23 | ||||
| 	^^DL23() | ||||
| 	Sleep(5) | ||||
|  | ||||
| 	// Put GPU into reset | ||||
| 	Printf("      Put GPU into reset") | ||||
| 	CTXS(DGPU_RST_N) | ||||
| 	Sleep(5) | ||||
|  | ||||
| 	Printf("    GPU GC6I FINISH") | ||||
| } | ||||
|  | ||||
| // Exit GC6 | ||||
| Method(GC6O, 0, Serialized) { | ||||
| 	Printf("    GPU GC6O START") | ||||
|  | ||||
| 	// Bring GPU out of reset | ||||
| 	Printf("      Bring GPU out of reset") | ||||
| 	STXS(DGPU_RST_N) | ||||
| 	Sleep(5) | ||||
|  | ||||
| 	// Exit L23 | ||||
| 	^^L23D() | ||||
| 	Sleep(5) | ||||
|  | ||||
| 	Printf("    GPU GC6O FINISH") | ||||
| } | ||||
|  | ||||
| Method (_ON, 0, Serialized) { | ||||
| 	Printf("  GPU _ON START") | ||||
|  | ||||
| 	If (DFEN == JT_DFGC_DEFER) { | ||||
| 		Switch (ToInteger(DFCO)) { | ||||
| 			Case (JT_GPC_XGXS) { | ||||
| 				Printf("    Exit GC6 and stop self-refresh") | ||||
| 				GC6O() | ||||
| 			} | ||||
| 			Default { | ||||
| 				Printf("    Unsupported DFCO: %o", SFST(DFCO)) | ||||
| 			} | ||||
| 		} | ||||
| 		DFEN = JT_DFGC_NONE | ||||
| 	} Else { | ||||
| 		Printf("    Standard RTD3 power on") | ||||
| 		STXS(DGPU_PWR_EN) | ||||
| 		Sleep(5) | ||||
| 		GC6O() | ||||
| 	} | ||||
|  | ||||
| 	Printf("  GPU _ON FINISH") | ||||
| } | ||||
|  | ||||
| Method (_OFF, 0, Serialized) { | ||||
| 	Printf("  GPU _OFF START") | ||||
|  | ||||
| 	If (DFEN == JT_DFGC_DEFER) { | ||||
| 		Switch (ToInteger(DFCI)) { | ||||
| 			Case (JT_GPC_EGNS) { | ||||
| 				Printf("    Enter GC6 without self-refresh") | ||||
| 				GC6I() | ||||
| 			} | ||||
| 			Case (JT_GPC_EGIS) { | ||||
| 				Printf("    Enter GC6 with self-refresh") | ||||
| 				GC6I() | ||||
| 			} | ||||
| 			Default { | ||||
| 				Printf("    Unsupported DFCI: %o", SFST(DFCI)) | ||||
| 			} | ||||
| 		} | ||||
| 		DFEN = JT_DFGC_NONE | ||||
| 	} Else { | ||||
| 		Printf("    Standard RTD3 power off") | ||||
| 		GC6I() | ||||
| 		CTXS(DGPU_PWR_EN) | ||||
| 		Sleep(5) | ||||
| 	} | ||||
|  | ||||
| 	Printf("  GPU _OFF FINISH") | ||||
| } | ||||
|  | ||||
| // Main power resource | ||||
| PowerResource (PWRR, 0, 0) { | ||||
| 	Name (_STA, 1) | ||||
|  | ||||
| 	Method (_ON, 0, Serialized) { | ||||
| 		Printf("GPU PWRR._ON") | ||||
|  | ||||
| 		// Restore SSID | ||||
| 		^^SSID = DGPU_SSID | ||||
| 		Printf("  Restore SSID: %o", SFST(^^SSID)) | ||||
|  | ||||
| 		_STA = 1 | ||||
| 	} | ||||
|  | ||||
| 	Method (_OFF, 0, Serialized) { | ||||
| 		Printf("GPU PWRR._OFF") | ||||
|  | ||||
| 		_STA = 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Power resources for entering D0 | ||||
| Name (_PR0, Package () { PWRR }) | ||||
|  | ||||
| // Power resources for entering D3 | ||||
| Name (_PR3, Package () { PWRR }) | ||||
							
								
								
									
										63
									
								
								src/drivers/gfx/nvidia/acpi/common/utility.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/drivers/gfx/nvidia/acpi/common/utility.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| // Convert a byte to a hex string, trimming extra parts | ||||
| Method (BHEX, 1) { | ||||
| 	Local0 = ToHexString(Arg0) | ||||
| 	Return (Mid(Local0, SizeOf(Local0) - 2, 2)) | ||||
| } | ||||
|  | ||||
| // UUID to string | ||||
| Method (IDST, 1) { | ||||
| 	Local0 = "" | ||||
| 	Fprintf( | ||||
| 		Local0, | ||||
| 		"%o%o%o%o-%o%o-%o%o-%o%o-%o%o%o%o%o%o", | ||||
| 		BHEX(DerefOf(Arg0[3])), | ||||
| 		BHEX(DerefOf(Arg0[2])), | ||||
| 		BHEX(DerefOf(Arg0[1])), | ||||
| 		BHEX(DerefOf(Arg0[0])), | ||||
| 		BHEX(DerefOf(Arg0[5])), | ||||
| 		BHEX(DerefOf(Arg0[4])), | ||||
| 		BHEX(DerefOf(Arg0[7])), | ||||
| 		BHEX(DerefOf(Arg0[6])), | ||||
| 		BHEX(DerefOf(Arg0[8])), | ||||
| 		BHEX(DerefOf(Arg0[9])), | ||||
| 		BHEX(DerefOf(Arg0[10])), | ||||
| 		BHEX(DerefOf(Arg0[11])), | ||||
| 		BHEX(DerefOf(Arg0[12])), | ||||
| 		BHEX(DerefOf(Arg0[13])), | ||||
| 		BHEX(DerefOf(Arg0[14])), | ||||
| 		BHEX(DerefOf(Arg0[15])) | ||||
| 	) | ||||
| 	Return (Local0) | ||||
| } | ||||
|  | ||||
| // Safe hex conversion, checks type first | ||||
| Method (SFST, 1) { | ||||
| 	Local0 = ObjectType(Arg0) | ||||
| 	If (Local0 == 1 || Local0 == 2 || Local0 == 3) { | ||||
| 		Return (ToHexString(Arg0)) | ||||
| 	} Else { | ||||
| 		Return (Concatenate("Type: ", Arg0)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Convert from 4-byte buffer to 32-bit integer | ||||
| Method (BTOI, 1) { | ||||
| 	Return( | ||||
| 		DerefOf(Arg0[0]) | | ||||
| 		(DerefOf(Arg0[1]) << 8) | | ||||
| 		(DerefOf(Arg0[2]) << 16) | | ||||
| 		(DerefOf(Arg0[3]) << 24) | ||||
| 	) | ||||
| } | ||||
|  | ||||
| // Convert from 32-bit integer to 4-byte buffer | ||||
| Method (ITOB, 1) { | ||||
| 	Local0 = Buffer(4) { 0, 0, 0, 0 } | ||||
| 	Local0[0] = Arg0 & 0xFF | ||||
| 	Local0[1] = (Arg0 >> 8) & 0xFF | ||||
| 	Local0[2] = (Arg0 >> 16) & 0xFF | ||||
| 	Local0[3] = (Arg0 >> 24) & 0xFF | ||||
| 	Return (Local0) | ||||
| } | ||||
							
								
								
									
										140
									
								
								src/drivers/gfx/nvidia/acpi/tigerlake.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/drivers/gfx/nvidia/acpi/tigerlake.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /* NVIDIA GC6 on (TGL and ADL) (CPU and PCH) PCIe ports */ | ||||
|  | ||||
| // Port mapped PCI express config space | ||||
| OperationRegion (PCIC, PCI_Config, 0x00, 0xFF) | ||||
|  | ||||
| Field (PCIC, AnyAcc, NoLock, Preserve) { | ||||
| 	Offset(0x52),  /* LSTS - Link Status Register */ | ||||
| 	, 13, | ||||
| 	LASX, 1,       /* 0, Link Active Status */ | ||||
|  | ||||
| 	Offset(0x60),  /* RSTS - Root Status Register */ | ||||
| 	, 16, | ||||
| 	PSPX, 1,       /* 16,  PME Status */ | ||||
|  | ||||
| 	Offset(0xD8),  /* 0xD8, MPC - Miscellaneous Port Configuration Register */ | ||||
| 	, 30, | ||||
| 	HPEX, 1,       /* 30,  Hot Plug SCI Enable */ | ||||
| 	PMEX, 1,       /* 31,  Power Management SCI Enable */ | ||||
|  | ||||
| 	Offset (0xE0), /* 0xE0, SPR - Scratch Pad Register */ | ||||
| 	SCB0, 1,       /* Scratch bit 0 */ | ||||
|  | ||||
| 	Offset(0xE2),  /* 0xE2, RPPGEN - Root Port Power Gating Enable */ | ||||
| 	, 2, | ||||
| 	L23E, 1,       /* 2,   L23_Rdy Entry Request (L23ER) */ | ||||
| 	L23R, 1,       /* 3,   L23_Rdy to Detect Transition (L23R2DT) */ | ||||
| } | ||||
|  | ||||
| Field (PCIC, AnyAcc, NoLock, WriteAsZeros) { | ||||
| 	Offset(0xDC),  /* 0xDC, SMSCS - SMI/SCI Status Register */ | ||||
| 	, 30, | ||||
| 	HPSX, 1,       /* 30,  Hot Plug SCI Status */ | ||||
| 	PMSX, 1        /* 31,  Power Management SCI Status */ | ||||
| } | ||||
|  | ||||
| // Enter L23 | ||||
| Method (DL23, 0, Serialized) { | ||||
| 	Printf("      GPU PORT DL23 START") | ||||
|  | ||||
| 	L23E = 1 | ||||
| 	Sleep (16) | ||||
| 	Local0 = 0 | ||||
| 	While (L23E) { | ||||
| 		If ((Local0 > 4)) { | ||||
| 			Break | ||||
| 		} | ||||
|  | ||||
| 		Sleep (16) | ||||
| 		Local0++ | ||||
| 	} | ||||
| 	SCB0 = 1 | ||||
|  | ||||
| 	Printf("      GPU PORT DL23 FINISH") | ||||
| } | ||||
|  | ||||
| // Exit L23 | ||||
| Method (L23D, 0, Serialized) { | ||||
| 	Printf("      GPU PORT L23D START") | ||||
|  | ||||
| 	If ((SCB0 == 1)) { | ||||
| 		L23R = 1 | ||||
| 		Local0 = 0 | ||||
| 		While (L23R) { | ||||
| 			If ((Local0 > 4)) { | ||||
| 				Break | ||||
| 			} | ||||
| 			Sleep (16) | ||||
| 			Local0++ | ||||
| 		} | ||||
|  | ||||
| 		SCB0 = 0 | ||||
| 		Local0 = 0 | ||||
| 		While ((LASX == 0)) { | ||||
| 			If ((Local0 > 8)) { | ||||
| 				Break | ||||
| 			} | ||||
| 			Sleep (16) | ||||
| 			Local0++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Printf("      GPU PORT L23D FINISH") | ||||
| } | ||||
|  | ||||
| Method (HPME, 0, Serialized) { | ||||
| 	Printf("  GPU PORT HPME START") | ||||
|  | ||||
| 	If (PMSX == 1) { | ||||
| 		Printf("    Notify GPU driver of PME SCI") | ||||
| 		Notify(DEV0, 0x2) | ||||
| 		Printf("    Clear PME SCI") | ||||
| 		PMSX = 1 | ||||
| 		Printf("    Consume PME notification") | ||||
| 		PSPX = 1 | ||||
| 	} | ||||
|  | ||||
| 	Printf("  GPU PORT HPME FINISH") | ||||
| } | ||||
|  | ||||
| // Main power resource | ||||
| PowerResource (PWRR, 0, 0) { | ||||
| 	Name (_STA, 1) | ||||
|  | ||||
| 	Method (_ON, 0, Serialized) { | ||||
| 		Printf("GPU PORT PWRR._ON") | ||||
|  | ||||
| 		HPME(); | ||||
| 		If (PMEX == 1) { | ||||
| 			Printf("  Disable power management SCI") | ||||
| 			PMEX = 0 | ||||
| 		} | ||||
|  | ||||
| 		^^DEV0._ON() | ||||
|  | ||||
| 		_STA = 1 | ||||
| 	} | ||||
|  | ||||
| 	Method (_OFF, 0, Serialized) { | ||||
| 		Printf("GPU PORT PWRR._OFF") | ||||
|  | ||||
| 		^^DEV0._OFF() | ||||
|  | ||||
| 		If (PMEX == 0) { | ||||
| 			Printf("  Enable power management SCI") | ||||
| 			PMEX = 1 | ||||
| 			HPME() | ||||
| 		} | ||||
|  | ||||
| 		_STA = 0 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Power resources for entering D0 | ||||
| Name (_PR0, Package () { PWRR }) | ||||
|  | ||||
| // Power resources for entering D3 | ||||
| Name (_PR3, Package () { PWRR }) | ||||
|  | ||||
| #include "common/gpu.asl" | ||||
							
								
								
									
										10
									
								
								src/drivers/gfx/nvidia/chip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/drivers/gfx/nvidia/chip.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #ifndef _DRIVERS_GFX_NVIDIA_CHIP_H_ | ||||
| #define _DRIVERS_GFX_NVIDIA_CHIP_H_ | ||||
|  | ||||
| struct drivers_gfx_nvidia_config { | ||||
| 	/* TODO: Set GPIOs in devicetree? */ | ||||
| }; | ||||
|  | ||||
| #endif /* _DRIVERS_GFX_NVIDIA_CHIP_H_ */ | ||||
							
								
								
									
										19
									
								
								src/drivers/gfx/nvidia/gpu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/drivers/gfx/nvidia/gpu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #ifndef _DRIVERS_GFX_NVIDIA_GPU_H_ | ||||
| #define _DRIVERS_GFX_NVIDIA_GPU_H_ | ||||
|  | ||||
| #include <stdbool.h> | ||||
|  | ||||
| struct nvidia_gpu_config { | ||||
| 	/* GPIO for GPU_PWR_EN */ | ||||
| 	unsigned int power_gpio; | ||||
| 	/* GPIO for GPU_RST# */ | ||||
| 	unsigned int reset_gpio; | ||||
| 	/* Enable or disable GPU power */ | ||||
| 	bool enable; | ||||
| }; | ||||
|  | ||||
| void nvidia_set_power(const struct nvidia_gpu_config *config); | ||||
|  | ||||
| #endif /* _DRIVERS_NVIDIA_GPU_H_ */ | ||||
							
								
								
									
										71
									
								
								src/drivers/gfx/nvidia/nvidia.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/drivers/gfx/nvidia/nvidia.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #include "chip.h" | ||||
| #include <console/console.h> | ||||
| #include <device/device.h> | ||||
| #include <device/pci.h> | ||||
| #include <device/pci_ids.h> | ||||
|  | ||||
| #define NVIDIA_SUBSYSTEM_ID_OFFSET 0x40 | ||||
|  | ||||
| static void nvidia_read_resources(struct device *dev) | ||||
| { | ||||
| 	printk(BIOS_DEBUG, "%s: %s\n", __func__, dev_path(dev)); | ||||
|  | ||||
| 	pci_dev_read_resources(dev); | ||||
|  | ||||
| 	// Find all BARs on GPU, mark them above 4g if prefetchable | ||||
| 	for (int bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) { | ||||
| 		struct resource *res = probe_resource(dev, bar); | ||||
|  | ||||
| 		if (res) { | ||||
| 			if (res->flags & IORESOURCE_PREFETCH) { | ||||
| 				printk(BIOS_INFO, "  BAR at 0x%02x marked above 4g\n", bar); | ||||
| 				res->flags |= IORESOURCE_ABOVE_4G; | ||||
| 			} else { | ||||
| 				printk(BIOS_DEBUG, "  BAR at 0x%02x not prefetch\n", bar); | ||||
| 			} | ||||
| 		} else { | ||||
| 			printk(BIOS_DEBUG, "  BAR at 0x%02x not found\n", bar); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void nvidia_set_subsystem(struct device *dev, unsigned int vendor, unsigned int device) | ||||
| { | ||||
| 	pci_write_config32(dev, NVIDIA_SUBSYSTEM_ID_OFFSET, | ||||
| 		((device & 0xffff) << 16) | (vendor & 0xffff)); | ||||
| } | ||||
|  | ||||
| static struct pci_operations nvidia_device_ops_pci = { | ||||
| 	.set_subsystem = nvidia_set_subsystem, | ||||
| }; | ||||
|  | ||||
| static struct device_operations nvidia_device_ops = { | ||||
| 	.read_resources   = nvidia_read_resources, | ||||
| 	.set_resources    = pci_dev_set_resources, | ||||
| 	.enable_resources = pci_dev_enable_resources, | ||||
| #if CONFIG(HAVE_ACPI_TABLES) | ||||
| 	.write_acpi_tables = pci_rom_write_acpi_tables, | ||||
| 	.acpi_fill_ssdt    = pci_rom_ssdt, | ||||
| #endif | ||||
| 	.init             = pci_dev_init, | ||||
| 	.ops_pci          = &nvidia_device_ops_pci, | ||||
|  | ||||
| }; | ||||
|  | ||||
| static void nvidia_enable(struct device *dev) | ||||
| { | ||||
| 	if (!is_dev_enabled(dev) || dev->path.type != DEVICE_PATH_PCI) | ||||
| 		return; | ||||
|  | ||||
| 	if (pci_read_config16(dev, PCI_VENDOR_ID) != PCI_VID_NVIDIA) | ||||
| 		return; | ||||
|  | ||||
| 	dev->ops = &nvidia_device_ops; | ||||
| } | ||||
|  | ||||
| struct chip_operations drivers_gfx_nvidia_ops = { | ||||
| 	.name = "NVIDIA Optimus Graphics Device", | ||||
| 	.enable_dev = nvidia_enable | ||||
| }; | ||||
							
								
								
									
										33
									
								
								src/drivers/gfx/nvidia/romstage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/drivers/gfx/nvidia/romstage.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
|  | ||||
| #include <console/console.h> | ||||
| #include <delay.h> | ||||
| #include <device/device.h> | ||||
| #include <device/pci.h> | ||||
| #include <gpio.h> | ||||
| #include "chip.h" | ||||
| #include "gpu.h" | ||||
|  | ||||
| void nvidia_set_power(const struct nvidia_gpu_config *config) | ||||
| { | ||||
| 	if (!config->power_gpio || !config->reset_gpio) { | ||||
| 		printk(BIOS_ERR, "%s: GPU_PWR_EN and GPU_RST# must be set\n", __func__); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s: GPU_PWR_EN = %d\n", __func__, config->power_gpio); | ||||
| 	printk(BIOS_DEBUG, "%s: GPU_RST# = %d\n", __func__, config->reset_gpio); | ||||
|  | ||||
| 	gpio_set(config->reset_gpio, 0); | ||||
| 	mdelay(10); | ||||
|  | ||||
| 	if (config->enable) { | ||||
| 		gpio_set(config->power_gpio, 1); | ||||
| 		mdelay(25); | ||||
| 		gpio_set(config->reset_gpio, 1); | ||||
| 	} else { | ||||
| 		gpio_set(config->power_gpio, 0); | ||||
| 	} | ||||
|  | ||||
| 	mdelay(10); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user