aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-04-06 23:55:09 -0400
committerDave Airlie <airlied@redhat.com>2010-05-31 20:24:21 -0400
commitafeb3e11147adb357603b071d6d7d1f30ea7f19d (patch)
treeb8460e2bcba524fbeab090328c8f276419f552e6
parentcf22f20ade30f8c03955324aaf27b1049e182600 (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.c59
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c20
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h5
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
40static const char nouveau_dsm_muid[] = { 41static 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 */
212static 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
240bool 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
260int 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
181static 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
181struct methods { 200struct 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
193static struct methods nv50_methods[] = { 212static 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 *);
851extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); 851extern 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)
855void nouveau_register_dsm_handler(void); 856void nouveau_register_dsm_handler(void);
856void nouveau_unregister_dsm_handler(void); 857void nouveau_unregister_dsm_handler(void);
858int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
859bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
857#else 860#else
858static inline void nouveau_register_dsm_handler(void) {} 861static inline void nouveau_register_dsm_handler(void) {}
859static inline void nouveau_unregister_dsm_handler(void) {} 862static inline void nouveau_unregister_dsm_handler(void) {}
863static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
864static 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 */