diff options
author | Dave Airlie <airlied@redhat.com> | 2010-05-31 21:32:06 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-31 21:32:06 -0400 |
commit | afa3b60c905f606e8245115474d77787035e02eb (patch) | |
tree | f9ff2222404da700c7bbe651ce63d4e1d6e9456f /drivers/gpu | |
parent | c09a35028567ae2c11d627bf69134b87a3c0efae (diff) | |
parent | fbf81762e385d3d45acad057b654d56972acf58c (diff) |
Merge branch 'drm-switcheroo-fixes' into drm-testing
* drm-switcheroo-fixes:
drm/kms: disable/enable poll around switcheroo on/off
drm/nouveau: fixup confusion over which handle the DSM is hanging off.
drm/nouveau: attempt to get bios from ACPI v3
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_acpi.c | 71 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 2 |
7 files changed, 118 insertions, 15 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 764401951041..9b2a54117c91 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c | |||
@@ -860,19 +860,24 @@ static void output_poll_execute(struct slow_work *work) | |||
860 | } | 860 | } |
861 | } | 861 | } |
862 | 862 | ||
863 | void drm_kms_helper_poll_init(struct drm_device *dev) | 863 | void drm_kms_helper_poll_disable(struct drm_device *dev) |
864 | { | ||
865 | if (!dev->mode_config.poll_enabled) | ||
866 | return; | ||
867 | delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | ||
868 | } | ||
869 | EXPORT_SYMBOL(drm_kms_helper_poll_disable); | ||
870 | |||
871 | void drm_kms_helper_poll_enable(struct drm_device *dev) | ||
864 | { | 872 | { |
865 | struct drm_connector *connector; | ||
866 | bool poll = false; | 873 | bool poll = false; |
874 | struct drm_connector *connector; | ||
867 | int ret; | 875 | int ret; |
868 | 876 | ||
869 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | 877 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
870 | if (connector->polled) | 878 | if (connector->polled) |
871 | poll = true; | 879 | poll = true; |
872 | } | 880 | } |
873 | slow_work_register_user(THIS_MODULE); | ||
874 | delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, | ||
875 | &output_poll_ops); | ||
876 | 881 | ||
877 | if (poll) { | 882 | if (poll) { |
878 | ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); | 883 | ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); |
@@ -880,11 +885,22 @@ void drm_kms_helper_poll_init(struct drm_device *dev) | |||
880 | DRM_ERROR("delayed enqueue failed %d\n", ret); | 885 | DRM_ERROR("delayed enqueue failed %d\n", ret); |
881 | } | 886 | } |
882 | } | 887 | } |
888 | EXPORT_SYMBOL(drm_kms_helper_poll_enable); | ||
889 | |||
890 | void drm_kms_helper_poll_init(struct drm_device *dev) | ||
891 | { | ||
892 | slow_work_register_user(THIS_MODULE); | ||
893 | delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, | ||
894 | &output_poll_ops); | ||
895 | dev->mode_config.poll_enabled = true; | ||
896 | |||
897 | drm_kms_helper_poll_enable(dev); | ||
898 | } | ||
883 | EXPORT_SYMBOL(drm_kms_helper_poll_init); | 899 | EXPORT_SYMBOL(drm_kms_helper_poll_init); |
884 | 900 | ||
885 | void drm_kms_helper_poll_fini(struct drm_device *dev) | 901 | void drm_kms_helper_poll_fini(struct drm_device *dev) |
886 | { | 902 | { |
887 | delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | 903 | drm_kms_helper_poll_disable(dev); |
888 | slow_work_unregister_user(THIS_MODULE); | 904 | slow_work_unregister_user(THIS_MODULE); |
889 | } | 905 | } |
890 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); | 906 | EXPORT_SYMBOL(drm_kms_helper_poll_fini); |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2a6b5de5ae5d..cc6e56a18edd 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1399,12 +1399,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ | |||
1399 | struct drm_device *dev = pci_get_drvdata(pdev); | 1399 | struct drm_device *dev = pci_get_drvdata(pdev); |
1400 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | 1400 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; |
1401 | if (state == VGA_SWITCHEROO_ON) { | 1401 | if (state == VGA_SWITCHEROO_ON) { |
1402 | printk(KERN_INFO "i915: switched off\n"); | 1402 | printk(KERN_INFO "i915: switched on\n"); |
1403 | /* i915 resume handler doesn't set to D0 */ | 1403 | /* i915 resume handler doesn't set to D0 */ |
1404 | pci_set_power_state(dev->pdev, PCI_D0); | 1404 | pci_set_power_state(dev->pdev, PCI_D0); |
1405 | i915_resume(dev); | 1405 | i915_resume(dev); |
1406 | drm_kms_helper_poll_enable(dev); | ||
1406 | } else { | 1407 | } else { |
1407 | printk(KERN_ERR "i915: switched off\n"); | 1408 | printk(KERN_ERR "i915: switched off\n"); |
1409 | drm_kms_helper_poll_disable(dev); | ||
1408 | i915_suspend(dev, pmm); | 1410 | i915_suspend(dev, pmm); |
1409 | } | 1411 | } |
1410 | } | 1412 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index e13f6af0037a..d4bcca8a5133 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c | |||
@@ -34,7 +34,7 @@ | |||
34 | static struct nouveau_dsm_priv { | 34 | 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 rom_handle; |
38 | } nouveau_dsm_priv; | 38 | } nouveau_dsm_priv; |
39 | 39 | ||
40 | static const char nouveau_dsm_muid[] = { | 40 | static const char nouveau_dsm_muid[] = { |
@@ -107,9 +107,9 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero | |||
107 | static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) | 107 | static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id) |
108 | { | 108 | { |
109 | if (id == VGA_SWITCHEROO_IGD) | 109 | if (id == VGA_SWITCHEROO_IGD) |
110 | return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA); | 110 | return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA); |
111 | else | 111 | else |
112 | return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED); | 112 | return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED); |
113 | } | 113 | } |
114 | 114 | ||
115 | static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, | 115 | static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, |
@@ -118,7 +118,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id, | |||
118 | if (id == VGA_SWITCHEROO_IGD) | 118 | if (id == VGA_SWITCHEROO_IGD) |
119 | return 0; | 119 | return 0; |
120 | 120 | ||
121 | return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state); | 121 | return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state); |
122 | } | 122 | } |
123 | 123 | ||
124 | static int nouveau_dsm_init(void) | 124 | static int nouveau_dsm_init(void) |
@@ -151,18 +151,18 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) | |||
151 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); | 151 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); |
152 | if (!dhandle) | 152 | if (!dhandle) |
153 | return false; | 153 | return false; |
154 | |||
154 | status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); | 155 | status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle); |
155 | if (ACPI_FAILURE(status)) { | 156 | if (ACPI_FAILURE(status)) { |
156 | return false; | 157 | return false; |
157 | } | 158 | } |
158 | 159 | ||
159 | ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED, | 160 | ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, |
160 | NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); | 161 | NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); |
161 | if (ret < 0) | 162 | if (ret < 0) |
162 | return false; | 163 | return false; |
163 | 164 | ||
164 | nouveau_dsm_priv.dhandle = dhandle; | 165 | nouveau_dsm_priv.dhandle = dhandle; |
165 | nouveau_dsm_priv.dsm_handle = nvidia_handle; | ||
166 | return true; | 166 | return true; |
167 | } | 167 | } |
168 | 168 | ||
@@ -173,6 +173,7 @@ static bool nouveau_dsm_detect(void) | |||
173 | struct pci_dev *pdev = NULL; | 173 | struct pci_dev *pdev = NULL; |
174 | int has_dsm = 0; | 174 | int has_dsm = 0; |
175 | int vga_count = 0; | 175 | int vga_count = 0; |
176 | |||
176 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { | 177 | while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { |
177 | vga_count++; | 178 | vga_count++; |
178 | 179 | ||
@@ -180,7 +181,7 @@ static bool nouveau_dsm_detect(void) | |||
180 | } | 181 | } |
181 | 182 | ||
182 | if (vga_count == 2 && has_dsm) { | 183 | if (vga_count == 2 && has_dsm) { |
183 | acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer); | 184 | acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); |
184 | printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", | 185 | printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", |
185 | acpi_method_name); | 186 | acpi_method_name); |
186 | nouveau_dsm_priv.dsm_detected = true; | 187 | nouveau_dsm_priv.dsm_detected = true; |
@@ -204,3 +205,57 @@ void nouveau_unregister_dsm_handler(void) | |||
204 | { | 205 | { |
205 | vga_switcheroo_unregister_handler(); | 206 | vga_switcheroo_unregister_handler(); |
206 | } | 207 | } |
208 | |||
209 | /* retrieve the ROM in 4k blocks */ | ||
210 | static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, | ||
211 | int offset, int len) | ||
212 | { | ||
213 | acpi_status status; | ||
214 | union acpi_object rom_arg_elements[2], *obj; | ||
215 | struct acpi_object_list rom_arg; | ||
216 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; | ||
217 | |||
218 | rom_arg.count = 2; | ||
219 | rom_arg.pointer = &rom_arg_elements[0]; | ||
220 | |||
221 | rom_arg_elements[0].type = ACPI_TYPE_INTEGER; | ||
222 | rom_arg_elements[0].integer.value = offset; | ||
223 | |||
224 | rom_arg_elements[1].type = ACPI_TYPE_INTEGER; | ||
225 | rom_arg_elements[1].integer.value = len; | ||
226 | |||
227 | status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer); | ||
228 | if (ACPI_FAILURE(status)) { | ||
229 | printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status)); | ||
230 | return -ENODEV; | ||
231 | } | ||
232 | obj = (union acpi_object *)buffer.pointer; | ||
233 | memcpy(bios+offset, obj->buffer.pointer, len); | ||
234 | kfree(buffer.pointer); | ||
235 | return len; | ||
236 | } | ||
237 | |||
238 | bool nouveau_acpi_rom_supported(struct pci_dev *pdev) | ||
239 | { | ||
240 | acpi_status status; | ||
241 | acpi_handle dhandle, rom_handle; | ||
242 | |||
243 | if (!nouveau_dsm_priv.dsm_detected) | ||
244 | return false; | ||
245 | |||
246 | dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); | ||
247 | if (!dhandle) | ||
248 | return false; | ||
249 | |||
250 | status = acpi_get_handle(dhandle, "_ROM", &rom_handle); | ||
251 | if (ACPI_FAILURE(status)) | ||
252 | return false; | ||
253 | |||
254 | nouveau_dsm_priv.rom_handle = rom_handle; | ||
255 | return true; | ||
256 | } | ||
257 | |||
258 | int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) | ||
259 | { | ||
260 | return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); | ||
261 | } | ||
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 */ |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index e632339c323e..5c468a4fef9a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -376,12 +376,15 @@ out_err: | |||
376 | static void nouveau_switcheroo_set_state(struct pci_dev *pdev, | 376 | static void nouveau_switcheroo_set_state(struct pci_dev *pdev, |
377 | enum vga_switcheroo_state state) | 377 | enum vga_switcheroo_state state) |
378 | { | 378 | { |
379 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
379 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; | 380 | pm_message_t pmm = { .event = PM_EVENT_SUSPEND }; |
380 | if (state == VGA_SWITCHEROO_ON) { | 381 | if (state == VGA_SWITCHEROO_ON) { |
381 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); | 382 | printk(KERN_ERR "VGA switcheroo: switched nouveau on\n"); |
382 | nouveau_pci_resume(pdev); | 383 | nouveau_pci_resume(pdev); |
384 | drm_kms_helper_poll_enable(dev); | ||
383 | } else { | 385 | } else { |
384 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); | 386 | printk(KERN_ERR "VGA switcheroo: switched nouveau off\n"); |
387 | drm_kms_helper_poll_disable(dev); | ||
385 | nouveau_pci_suspend(pdev, pmm); | 388 | nouveau_pci_suspend(pdev, pmm); |
386 | } | 389 | } |
387 | } | 390 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index fdc3fdf78acb..db338522191f 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -546,8 +546,10 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero | |||
546 | /* don't suspend or resume card normally */ | 546 | /* don't suspend or resume card normally */ |
547 | rdev->powered_down = false; | 547 | rdev->powered_down = false; |
548 | radeon_resume_kms(dev); | 548 | radeon_resume_kms(dev); |
549 | drm_kms_helper_poll_enable(dev); | ||
549 | } else { | 550 | } else { |
550 | printk(KERN_INFO "radeon: switched off\n"); | 551 | printk(KERN_INFO "radeon: switched off\n"); |
552 | drm_kms_helper_poll_disable(dev); | ||
551 | radeon_suspend_kms(dev, pmm); | 553 | radeon_suspend_kms(dev, pmm); |
552 | /* don't suspend or resume card normally */ | 554 | /* don't suspend or resume card normally */ |
553 | rdev->powered_down = true; | 555 | rdev->powered_down = true; |