diff options
author | Dave Airlie <airlied@redhat.com> | 2010-04-06 23:55:09 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-31 20:24:21 -0400 |
commit | afeb3e11147adb357603b071d6d7d1f30ea7f19d (patch) | |
tree | b8460e2bcba524fbeab090328c8f276419f552e6 | |
parent | cf22f20ade30f8c03955324aaf27b1049e182600 (diff) |
drm/nouveau: attempt to get bios from ACPI v3
Some of the laptops with the switchable graphics, seem to not post the secondary GPU at all, and we can't find a copy of the BIOS anywhere except in the ACPI rom retrieval.
This adds support for ACPI ROM retrieval to nouveau.
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 5 |
3 files changed, 83 insertions, 1 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index e13f6af0037a..b3f146a811ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
@@ -35,6 +35,7 @@ static struct nouveau_dsm_priv { | |||
35 | bool dsm_detected; | 35 | bool dsm_detected; |
36 | acpi_handle dhandle; | 36 | acpi_handle dhandle; |
37 | acpi_handle dsm_handle; | 37 | acpi_handle dsm_handle; |
38 | acpi_handle rom_handle; | ||
38 | } nouveau_dsm_priv; | 39 | } nouveau_dsm_priv; |
39 | 40 | ||
40 | static const char nouveau_dsm_muid[] = { | 41 | static const char nouveau_dsm_muid[] = { |
@@ -151,12 +152,13 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
151 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); | 152 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); |
152 | if (!dhandle) | 153 | if (!dhandle) |
153 | return false; | 154 | return false; |
155 | |||
154 | status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); | 156 | status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); |
155 | if (ACPI_FAILURE(status)) { | 157 | if (ACPI_FAILURE(status)) { |
156 | return false; | 158 | return false; |
157 | } | 159 | } |
158 | 160 | ||
159 | ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, | 161 | ret = nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, |
160 | NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); | 162 | NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); |
161 | if (ret < 0) | 163 | if (ret < 0) |
162 | return false; | 164 | return false; |
@@ -173,6 +175,7 @@ static bool nouveau_dsm_detect(void) | |||
173 | struct pci_dev *pdev = NULL; | 175 | struct pci_dev *pdev = NULL; |
174 | int has_dsm = 0; | 176 | int has_dsm = 0; |
175 | int vga_count = 0; | 177 | int vga_count = 0; |
178 | |||
176 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { | 179 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { |
177 | vga_count++; | 180 | vga_count++; |
178 | 181 | ||
@@ -204,3 +207,57 @@ void nouveau_unregister_dsm_handler(void) | |||
204 | { | 207 | { |
205 | vga_switcheroo_unregister_handler(); | 208 | vga_switcheroo_unregister_handler(); |
206 | } | 209 | } |
210 | |||
211 | /* retrieve the ROM in 4k blocks */ | ||
212 | static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, | ||
213 | int offset, int len) | ||
214 | { | ||
215 | acpi_status status; | ||
216 | union acpi_object rom_arg_elements[2], *obj; | ||
217 | struct acpi_object_list rom_arg; | ||
218 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; | ||
219 | |||
220 | rom_arg.count = 2; | ||
221 | rom_arg.pointer = &rom_arg_elements[0]; | ||
222 | |||
223 | rom_arg_elements[0].type = ACPI_TYPE_INTEGER; | ||
224 | rom_arg_elements[0].integer.value = offset; | ||
225 | |||
226 | rom_arg_elements[1].type = ACPI_TYPE_INTEGER; | ||
227 | rom_arg_elements[1].integer.value = len; | ||
228 | |||
229 | status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); | ||
230 | if (ACPI_FAILURE(status)) { | ||
231 | printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status)); | ||
232 | return -ENODEV; | ||
233 | } | ||
234 | obj = (union acpi_object *)buffer.pointer; | ||
235 | memcpy(bios+offset, obj->buffer.pointer, len); | ||
236 | kfree(buffer.pointer); | ||
237 | return len; | ||
238 | } | ||
239 | |||
240 | bool nouveau_acpi_rom_supported(struct pci_dev *pdev) | ||
241 | { | ||
242 | acpi_status status; | ||
243 | acpi_handle dhandle, rom_handle; | ||
244 | |||
245 | if (!nouveau_dsm_priv.dsm_detected) | ||
246 | return false; | ||
247 | |||
248 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); | ||
249 | if (!dhandle) | ||
250 | return false; | ||
251 | |||
252 | status = acpi_get_handle(dhandle, "_ROM", &rom_handle); | ||
253 | if (ACPI_FAILURE(status)) | ||
254 | return false; | ||
255 | |||
256 | nouveau_dsm_priv.rom_handle = rom_handle; | ||
257 | return true; | ||
258 | } | ||
259 | |||
260 | int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) | ||
261 | { | ||
262 | return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); | ||
263 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e7e69ccce5c9..745ff3788e9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c | |||
@@ -178,6 +178,25 @@ out: | |||
178 | pci_disable_rom(dev->pdev); | 178 | pci_disable_rom(dev->pdev); |
179 | } | 179 | } |
180 | 180 | ||
181 | static void load_vbios_acpi(struct drm_device *dev, uint8_t *data) | ||
182 | { | ||
183 | int i; | ||
184 | int ret; | ||
185 | int size = 64 * 1024; | ||
186 | |||
187 | if (!nouveau_acpi_rom_supported(dev->pdev)) | ||
188 | return; | ||
189 | |||
190 | for (i = 0; i < (size / ROM_BIOS_PAGE); i++) { | ||
191 | ret = nouveau_acpi_get_bios_chunk(data, | ||
192 | (i * ROM_BIOS_PAGE), | ||
193 | ROM_BIOS_PAGE); | ||
194 | if (ret <= 0) | ||
195 | break; | ||
196 | } | ||
197 | return; | ||
198 | } | ||
199 | |||
181 | struct methods { | 200 | struct methods { |
182 | const char desc[8]; | 201 | const char desc[8]; |
183 | void (*loadbios)(struct drm_device *, uint8_t *); | 202 | void (*loadbios)(struct drm_device *, uint8_t *); |
@@ -191,6 +210,7 @@ static struct methods nv04_methods[] = { | |||
191 | }; | 210 | }; |
192 | 211 | ||
193 | static struct methods nv50_methods[] = { | 212 | static struct methods nv50_methods[] = { |
213 | { "ACPI", load_vbios_acpi, true }, | ||
194 | { "PRAMIN", load_vbios_pramin, true }, | 214 | { "PRAMIN", load_vbios_pramin, true }, |
195 | { "PROM", load_vbios_prom, false }, | 215 | { "PROM", load_vbios_prom, false }, |
196 | { "PCIROM", load_vbios_pci, true }, | 216 | { "PCIROM", load_vbios_pci, true }, |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 5b134438effe..c69719106489 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -851,12 +851,17 @@ extern int nouveau_dma_init(struct nouveau_channel *); | |||
851 | extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); | 851 | extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); |
852 | 852 | ||
853 | /* nouveau_acpi.c */ | 853 | /* nouveau_acpi.c */ |
854 | #define ROM_BIOS_PAGE 4096 | ||
854 | #if defined(CONFIG_ACPI) | 855 | #if defined(CONFIG_ACPI) |
855 | void nouveau_register_dsm_handler(void); | 856 | void nouveau_register_dsm_handler(void); |
856 | void nouveau_unregister_dsm_handler(void); | 857 | void nouveau_unregister_dsm_handler(void); |
858 | int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); | ||
859 | bool nouveau_acpi_rom_supported(struct pci_dev *pdev); | ||
857 | #else | 860 | #else |
858 | static inline void nouveau_register_dsm_handler(void) {} | 861 | static inline void nouveau_register_dsm_handler(void) {} |
859 | static inline void nouveau_unregister_dsm_handler(void) {} | 862 | static inline void nouveau_unregister_dsm_handler(void) {} |
863 | static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } | ||
864 | static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } | ||
860 | #endif | 865 | #endif |
861 | 866 | ||
862 | /* nouveau_backlight.c */ | 867 | /* nouveau_backlight.c */ |