aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c105
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fbcon.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c4
6 files changed, 76 insertions, 45 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index db76b94e6e26..f2ad17aa33f0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -45,6 +45,8 @@
45static struct nouveau_dsm_priv { 45static struct nouveau_dsm_priv {
46 bool dsm_detected; 46 bool dsm_detected;
47 bool optimus_detected; 47 bool optimus_detected;
48 bool optimus_flags_detected;
49 bool optimus_skip_dsm;
48 acpi_handle dhandle; 50 acpi_handle dhandle;
49 acpi_handle rom_handle; 51 acpi_handle rom_handle;
50} nouveau_dsm_priv; 52} nouveau_dsm_priv;
@@ -57,9 +59,6 @@ bool nouveau_is_v1_dsm(void) {
57 return nouveau_dsm_priv.dsm_detected; 59 return nouveau_dsm_priv.dsm_detected;
58} 60}
59 61
60#define NOUVEAU_DSM_HAS_MUX 0x1
61#define NOUVEAU_DSM_HAS_OPT 0x2
62
63#ifdef CONFIG_VGA_SWITCHEROO 62#ifdef CONFIG_VGA_SWITCHEROO
64static const char nouveau_dsm_muid[] = { 63static const char nouveau_dsm_muid[] = {
65 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 64 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
@@ -110,7 +109,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
110 * requirements on the fourth parameter, so a private implementation 109 * requirements on the fourth parameter, so a private implementation
111 * instead of using acpi_check_dsm(). 110 * instead of using acpi_check_dsm().
112 */ 111 */
113static int nouveau_check_optimus_dsm(acpi_handle handle) 112static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
114{ 113{
115 int result; 114 int result;
116 115
@@ -125,7 +124,9 @@ static int nouveau_check_optimus_dsm(acpi_handle handle)
125 * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. 124 * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
126 * If the n-th bit is enabled, function n is supported 125 * If the n-th bit is enabled, function n is supported
127 */ 126 */
128 return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS); 127 if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
128 return result;
129 return 0;
129} 130}
130 131
131static int nouveau_dsm(acpi_handle handle, int func, int arg) 132static int nouveau_dsm(acpi_handle handle, int func, int arg)
@@ -212,26 +213,55 @@ static const struct vga_switcheroo_handler nouveau_dsm_handler = {
212 .get_client_id = nouveau_dsm_get_client_id, 213 .get_client_id = nouveau_dsm_get_client_id,
213}; 214};
214 215
215static int nouveau_dsm_pci_probe(struct pci_dev *pdev) 216/*
217 * Firmware supporting Windows 8 or later do not use _DSM to put the device into
218 * D3cold, they instead rely on disabling power resources on the parent.
219 */
220static bool nouveau_pr3_present(struct pci_dev *pdev)
221{
222 struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
223 struct acpi_device *parent_adev;
224
225 if (!parent_pdev)
226 return false;
227
228 parent_adev = ACPI_COMPANION(&parent_pdev->dev);
229 if (!parent_adev)
230 return false;
231
232 return acpi_has_method(parent_adev->handle, "_PR3");
233}
234
235static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
236 bool *has_mux, bool *has_opt,
237 bool *has_opt_flags, bool *has_pr3)
216{ 238{
217 acpi_handle dhandle; 239 acpi_handle dhandle;
218 int retval = 0; 240 bool supports_mux;
241 int optimus_funcs;
219 242
220 dhandle = ACPI_HANDLE(&pdev->dev); 243 dhandle = ACPI_HANDLE(&pdev->dev);
221 if (!dhandle) 244 if (!dhandle)
222 return false; 245 return;
223 246
224 if (!acpi_has_method(dhandle, "_DSM")) 247 if (!acpi_has_method(dhandle, "_DSM"))
225 return false; 248 return;
249
250 supports_mux = acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
251 1 << NOUVEAU_DSM_POWER);
252 optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
226 253
227 if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102, 254 /* Does not look like a Nvidia device. */
228 1 << NOUVEAU_DSM_POWER)) 255 if (!supports_mux && !optimus_funcs)
229 retval |= NOUVEAU_DSM_HAS_MUX; 256 return;
230 257
231 if (nouveau_check_optimus_dsm(dhandle)) 258 *dhandle_out = dhandle;
232 retval |= NOUVEAU_DSM_HAS_OPT; 259 *has_mux = supports_mux;
260 *has_opt = !!optimus_funcs;
261 *has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
262 *has_pr3 = false;
233 263
234 if (retval & NOUVEAU_DSM_HAS_OPT) { 264 if (optimus_funcs) {
235 uint32_t result; 265 uint32_t result;
236 nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0, 266 nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
237 &result); 267 &result);
@@ -239,11 +269,9 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
239 (result & OPTIMUS_ENABLED) ? "enabled" : "disabled", 269 (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
240 (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "", 270 (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
241 (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : ""); 271 (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
242 }
243 if (retval)
244 nouveau_dsm_priv.dhandle = dhandle;
245 272
246 return retval; 273 *has_pr3 = nouveau_pr3_present(pdev);
274 }
247} 275}
248 276
249static bool nouveau_dsm_detect(void) 277static bool nouveau_dsm_detect(void)
@@ -251,11 +279,13 @@ static bool nouveau_dsm_detect(void)
251 char acpi_method_name[255] = { 0 }; 279 char acpi_method_name[255] = { 0 };
252 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 280 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
253 struct pci_dev *pdev = NULL; 281 struct pci_dev *pdev = NULL;
254 int has_dsm = 0; 282 acpi_handle dhandle = NULL;
255 int has_optimus = 0; 283 bool has_mux = false;
284 bool has_optimus = false;
285 bool has_optimus_flags = false;
286 bool has_power_resources = false;
256 int vga_count = 0; 287 int vga_count = 0;
257 bool guid_valid; 288 bool guid_valid;
258 int retval;
259 bool ret = false; 289 bool ret = false;
260 290
261 /* lookup the MXM GUID */ 291 /* lookup the MXM GUID */
@@ -268,32 +298,32 @@ static bool nouveau_dsm_detect(void)
268 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 298 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
269 vga_count++; 299 vga_count++;
270 300
271 retval = nouveau_dsm_pci_probe(pdev); 301 nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
272 if (retval & NOUVEAU_DSM_HAS_MUX) 302 &has_optimus_flags, &has_power_resources);
273 has_dsm |= 1;
274 if (retval & NOUVEAU_DSM_HAS_OPT)
275 has_optimus = 1;
276 } 303 }
277 304
278 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) { 305 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
279 vga_count++; 306 vga_count++;
280 307
281 retval = nouveau_dsm_pci_probe(pdev); 308 nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
282 if (retval & NOUVEAU_DSM_HAS_MUX) 309 &has_optimus_flags, &has_power_resources);
283 has_dsm |= 1;
284 if (retval & NOUVEAU_DSM_HAS_OPT)
285 has_optimus = 1;
286 } 310 }
287 311
288 /* find the optimus DSM or the old v1 DSM */ 312 /* find the optimus DSM or the old v1 DSM */
289 if (has_optimus == 1) { 313 if (has_optimus) {
314 nouveau_dsm_priv.dhandle = dhandle;
290 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, 315 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
291 &buffer); 316 &buffer);
292 printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n", 317 printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
293 acpi_method_name); 318 acpi_method_name);
319 if (has_power_resources)
320 pr_info("nouveau: detected PR support, will not use DSM\n");
294 nouveau_dsm_priv.optimus_detected = true; 321 nouveau_dsm_priv.optimus_detected = true;
322 nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
323 nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
295 ret = true; 324 ret = true;
296 } else if (vga_count == 2 && has_dsm && guid_valid) { 325 } else if (vga_count == 2 && has_mux && guid_valid) {
326 nouveau_dsm_priv.dhandle = dhandle;
297 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, 327 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
298 &buffer); 328 &buffer);
299 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", 329 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
@@ -321,11 +351,12 @@ void nouveau_register_dsm_handler(void)
321void nouveau_switcheroo_optimus_dsm(void) 351void nouveau_switcheroo_optimus_dsm(void)
322{ 352{
323 u32 result = 0; 353 u32 result = 0;
324 if (!nouveau_dsm_priv.optimus_detected) 354 if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
325 return; 355 return;
326 356
327 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS, 357 if (nouveau_dsm_priv.optimus_flags_detected)
328 0x3, &result); 358 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
359 0x3, &result);
329 360
330 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 361 nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_CAPS,
331 NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result); 362 NOUVEAU_DSM_OPTIMUS_SET_POWERDOWN, &result);
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 7d9248b8c664..da8fd5ff9d0f 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -107,11 +107,11 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
107 ((image->dx + image->width) & 0xffff)); 107 ((image->dx + image->width) & 0xffff));
108 OUT_RING(chan, bg); 108 OUT_RING(chan, bg);
109 OUT_RING(chan, fg); 109 OUT_RING(chan, fg);
110 OUT_RING(chan, (image->height << 16) | image->width); 110 OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
111 OUT_RING(chan, (image->height << 16) | image->width); 111 OUT_RING(chan, (image->height << 16) | image->width);
112 OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff)); 112 OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
113 113
114 dsize = ALIGN(image->width * image->height, 32) >> 5; 114 dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
115 while (dsize) { 115 while (dsize) {
116 int iter_len = dsize > 128 ? 128 : dsize; 116 int iter_len = dsize > 128 ? 128 : dsize;
117 117
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index 1aeb698e9707..af3d3c49411a 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -125,7 +125,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
125 OUT_RING(chan, 0); 125 OUT_RING(chan, 0);
126 OUT_RING(chan, image->dy); 126 OUT_RING(chan, image->dy);
127 127
128 dwords = ALIGN(image->width * image->height, 32) >> 5; 128 dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
129 while (dwords) { 129 while (dwords) {
130 int push = dwords > 2047 ? 2047 : dwords; 130 int push = dwords > 2047 ? 2047 : dwords;
131 131
diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
index 839f4c8c1805..054b6a056d99 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
@@ -125,7 +125,7 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
125 OUT_RING (chan, 0); 125 OUT_RING (chan, 0);
126 OUT_RING (chan, image->dy); 126 OUT_RING (chan, image->dy);
127 127
128 dwords = ALIGN(image->width * image->height, 32) >> 5; 128 dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
129 while (dwords) { 129 while (dwords) {
130 int push = dwords > 2047 ? 2047 : dwords; 130 int push = dwords > 2047 ? 2047 : dwords;
131 131
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
index 69de8c6259fe..f1e15a4d4f64 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -76,8 +76,8 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
76 nvkm_wo32(chan->inst, i, 0x00040004); 76 nvkm_wo32(chan->inst, i, 0x00040004);
77 for (i = 0x1f18; i <= 0x3088 ; i += 16) { 77 for (i = 0x1f18; i <= 0x3088 ; i += 16) {
78 nvkm_wo32(chan->inst, i + 0, 0x10700ff9); 78 nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
79 nvkm_wo32(chan->inst, i + 1, 0x0436086c); 79 nvkm_wo32(chan->inst, i + 4, 0x0436086c);
80 nvkm_wo32(chan->inst, i + 2, 0x000c001b); 80 nvkm_wo32(chan->inst, i + 8, 0x000c001b);
81 } 81 }
82 for (i = 0x30b8; i < 0x30c8; i += 4) 82 for (i = 0x30b8; i < 0x30c8; i += 4)
83 nvkm_wo32(chan->inst, i, 0x0000ffff); 83 nvkm_wo32(chan->inst, i, 0x0000ffff);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
index 2207dac23981..300f5ed5de0b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -75,8 +75,8 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
75 nvkm_wo32(chan->inst, i, 0x00040004); 75 nvkm_wo32(chan->inst, i, 0x00040004);
76 for (i = 0x15ac; i <= 0x271c ; i += 16) { 76 for (i = 0x15ac; i <= 0x271c ; i += 16) {
77 nvkm_wo32(chan->inst, i + 0, 0x10700ff9); 77 nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
78 nvkm_wo32(chan->inst, i + 1, 0x0436086c); 78 nvkm_wo32(chan->inst, i + 4, 0x0436086c);
79 nvkm_wo32(chan->inst, i + 2, 0x000c001b); 79 nvkm_wo32(chan->inst, i + 8, 0x000c001b);
80 } 80 }
81 for (i = 0x274c; i < 0x275c; i += 4) 81 for (i = 0x274c; i < 0x275c; i += 4)
82 nvkm_wo32(chan->inst, i, 0x0000ffff); 82 nvkm_wo32(chan->inst, i, 0x0000ffff);