From fe0efc8956a0fceaa9eda4300c1db7d6083539f8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 5 Mar 2010 15:08:51 +1000 Subject: [PATCH] nouveau: attempt to get bios rom in switcheroo --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 53 +++++++++++++++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_bios.c | 19 +++++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 5 +++ 3 files changed, 76 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 0e0730a..66262be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -34,6 +34,7 @@ static struct nouveau_dsm_priv { bool dsm_detected; acpi_handle dhandle; acpi_handle dsm_handle; + acpi_handle rom_handle; } nouveau_dsm_priv; static const char nouveau_dsm_muid[] = { @@ -142,7 +143,7 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = { static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) { - acpi_handle dhandle, nvidia_handle; + acpi_handle dhandle, nvidia_handle, rom_handle; acpi_status status; int ret; uint32_t result; @@ -155,6 +156,10 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) return false; } + status = acpi_get_handle(dhandle, "_ROM", &rom_handle); + if (ACPI_FAILURE(status)) + return false; + ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); if (ret < 0) @@ -162,6 +167,7 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) nouveau_dsm_priv.dhandle = dhandle; nouveau_dsm_priv.dsm_handle = nvidia_handle; + nouveau_dsm_priv.rom_handle = rom_handle; return true; } @@ -203,3 +209,48 @@ void nouveau_unregister_dsm_handler(void) { vga_switcheroo_unregister_handler(); } + +/* retrieve the ROM in 4k blocks */ +static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, + int offset, int len) +{ + acpi_status status; + union acpi_object rom_arg_elements[2], *obj; + struct acpi_object_list rom_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + + rom_arg.count = 2; + rom_arg.pointer = &rom_arg_elements[0]; + + rom_arg_elements[0].type = ACPI_TYPE_INTEGER; + rom_arg_elements[0].integer.value = offset; + + rom_arg_elements[1].type = ACPI_TYPE_INTEGER; + rom_arg_elements[1].integer.value = len; + + status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); + if (ACPI_FAILURE(status)) { + printk("failed to evaluate ROM got %s\n", acpi_format_exception(status)); + return -ENODEV; + } + obj = (union acpi_object *)buffer.pointer; + memcpy(bios+offset, obj->buffer.pointer, len); + kfree(buffer.pointer); + return len; +} + +bool nouveau_acpi_rom_supported(struct pci_dev *pdev) +{ + if (!nouveau_dsm_priv.dsm_detected) + return false; + + if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev)) + return false; + + return true; +} + +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) +{ + return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 71247da..0618ef3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -177,6 +177,24 @@ out: pci_disable_rom(dev->pdev); } +static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) +{ + int i; + int ret; + int size = 64 * 1024; + if (!nouveau_acpi_rom_supported(dev->pdev)) + return; + + for (i = 0; i < size / ROM_BIOS_PAGE; i++) { + ret = nouveau_acpi_get_bios_chunk(data, + (i * ROM_BIOS_PAGE), + ROM_BIOS_PAGE); + if (ret <= 0) + break; + } + return; +} + struct methods { const char desc[8]; void (*loadbios)(struct drm_device *, uint8_t *); @@ -190,6 +208,7 @@ static struct methods nv04_methods[] = { }; static struct methods nv50_methods[] = { + { "ACPI", load_vbios_acpi, true }, { "PRAMIN", load_vbios_pramin, true }, { "PROM", load_vbios_prom, false }, { "PCIROM", load_vbios_pci, true }, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5f8d987..363e886 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -852,12 +852,17 @@ extern int nouveau_dma_init(struct nouveau_channel *); extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); /* nouveau_acpi.c */ +#define ROM_BIOS_PAGE 4096 #if defined(CONFIG_ACPI) void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); +int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); +bool nouveau_acpi_rom_supported(struct pci_dev *pdev); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } +static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } #endif /* nouveau_backlight.c */ -- 1.6.5.2