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>
72 lines
1.9 KiB
C
72 lines
1.9 KiB
C
/* 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
|
|
};
|