aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c89
-rw-r--r--drivers/gpu/drm/nouveau/nv04_pm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c2
6 files changed, 104 insertions, 4 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index ef44070321e..07171dd3c16 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -4832,8 +4832,11 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
4832 */ 4832 */
4833 if (limit_match > PLL_MAX) 4833 if (limit_match > PLL_MAX)
4834 pll_lim->reg = limit_match; 4834 pll_lim->reg = limit_match;
4835 else 4835 else {
4836 pll_lim->reg = get_pll_register(dev, limit_match); 4836 pll_lim->reg = get_pll_register(dev, limit_match);
4837 if (!pll_lim->reg)
4838 return -ENOENT;
4839 }
4837 4840
4838 if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) { 4841 if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) {
4839 uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex]; 4842 uint8_t *pll_rec = &bios->data[bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex];
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 14a4960a989..b03bb6d5b98 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -102,6 +102,14 @@ MODULE_PARM_DESC(reg_debug, "Register access debug bitmask:\n"
102int nouveau_reg_debug; 102int nouveau_reg_debug;
103module_param_named(reg_debug, nouveau_reg_debug, int, 0600); 103module_param_named(reg_debug, nouveau_reg_debug, int, 0600);
104 104
105MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n");
106char *nouveau_perflvl;
107module_param_named(perflvl, nouveau_perflvl, charp, 0400);
108
109MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n");
110int nouveau_perflvl_wr;
111module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
112
105int nouveau_fbpercrtc; 113int nouveau_fbpercrtc;
106#if 0 114#if 0
107module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); 115module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index bda4d1e7c63..8d36ed6907d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -716,6 +716,8 @@ extern int nouveau_ignorelid;
716extern int nouveau_nofbaccel; 716extern int nouveau_nofbaccel;
717extern int nouveau_noaccel; 717extern int nouveau_noaccel;
718extern int nouveau_override_conntype; 718extern int nouveau_override_conntype;
719extern char *nouveau_perflvl;
720extern int nouveau_perflvl_wr;
719 721
720extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); 722extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
721extern int nouveau_pci_resume(struct pci_dev *pdev); 723extern int nouveau_pci_resume(struct pci_dev *pdev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 9cf5fd665b8..9e8e14eb6df 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -28,6 +28,78 @@
28#include "nouveau_pm.h" 28#include "nouveau_pm.h"
29 29
30static int 30static int
31nouveau_pm_clock_set(struct drm_device *dev, u8 id, u32 khz)
32{
33 struct drm_nouveau_private *dev_priv = dev->dev_private;
34 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
35 void *pre_state;
36
37 if (khz == 0)
38 return 0;
39
40 pre_state = pm->clock_pre(dev, id, khz);
41 if (IS_ERR(pre_state))
42 return PTR_ERR(pre_state);
43
44 if (pre_state)
45 pm->clock_set(dev, pre_state);
46 return 0;
47}
48
49static int
50nouveau_pm_profile_set(struct drm_device *dev, const char *profile)
51{
52 struct drm_nouveau_private *dev_priv = dev->dev_private;
53 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
54 struct nouveau_pm_level *perflvl = NULL;
55 int ret;
56
57 /* safety precaution, for now */
58 if (nouveau_perflvl_wr != 7777)
59 return -EPERM;
60
61 if (!pm->clock_set)
62 return -EINVAL;
63
64 if (!strncmp(profile, "boot", 4))
65 perflvl = &pm->boot;
66 else {
67 int pl = simple_strtol(profile, NULL, 10);
68 int i;
69
70 for (i = 0; i < pm->nr_perflvl; i++) {
71 if (pm->perflvl[i].id == pl) {
72 perflvl = &pm->perflvl[i];
73 break;
74 }
75 }
76
77 if (!perflvl)
78 return -EINVAL;
79 }
80
81 if (perflvl == pm->cur)
82 return 0;
83
84 NV_INFO(dev, "setting performance level: %s\n", profile);
85 if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) {
86 ret = pm->voltage_set(dev, perflvl->voltage);
87 if (ret) {
88 NV_ERROR(dev, "voltage_set %d failed: %d\n",
89 perflvl->voltage, ret);
90 }
91 }
92
93 nouveau_pm_clock_set(dev, PLL_CORE, perflvl->core);
94 nouveau_pm_clock_set(dev, PLL_SHADER, perflvl->shader);
95 nouveau_pm_clock_set(dev, PLL_MEMORY, perflvl->memory);
96 nouveau_pm_clock_set(dev, PLL_UNK05, perflvl->unk05);
97
98 pm->cur = perflvl;
99 return 0;
100}
101
102static int
31nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) 103nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
32{ 104{
33 struct drm_nouveau_private *dev_priv = dev->dev_private; 105 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -130,7 +202,13 @@ static ssize_t
130nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 202nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
131 const char *buf, size_t count) 203 const char *buf, size_t count)
132{ 204{
133 return -EPERM; 205 struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
206 int ret;
207
208 ret = nouveau_pm_profile_set(dev, buf);
209 if (ret)
210 return ret;
211 return strlen(buf);
134} 212}
135 213
136DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 214DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
@@ -163,6 +241,15 @@ nouveau_pm_init(struct drm_device *dev)
163 NV_INFO(dev, "c: %s", info); 241 NV_INFO(dev, "c: %s", info);
164 } 242 }
165 243
244 /* switch performance levels now if requested */
245 if (nouveau_perflvl != NULL) {
246 ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
247 if (ret) {
248 NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
249 nouveau_perflvl, ret);
250 }
251 }
252
166 /* initialise sysfs */ 253 /* initialise sysfs */
167 ret = device_create_file(d, &dev_attr_performance_level); 254 ret = device_create_file(d, &dev_attr_performance_level);
168 if (ret) 255 if (ret)
diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c
index 35c200eb476..15e4b9029df 100644
--- a/drivers/gpu/drm/nouveau/nv04_pm.c
+++ b/drivers/gpu/drm/nouveau/nv04_pm.c
@@ -50,7 +50,7 @@ nv04_pm_clock_pre(struct drm_device *dev, u32 id, int khz)
50 ret = get_pll_limits(dev, id, &state->pll); 50 ret = get_pll_limits(dev, id, &state->pll);
51 if (ret) { 51 if (ret) {
52 kfree(state); 52 kfree(state);
53 return ERR_PTR(ret); 53 return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
54 } 54 }
55 55
56 ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc); 56 ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index a616e424034..64bc29c39c3 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -80,7 +80,7 @@ nv50_pm_clock_pre(struct drm_device *dev, u32 id, int khz)
80 ret = get_pll_limits(dev, id, &state->pll); 80 ret = get_pll_limits(dev, id, &state->pll);
81 if (ret < 0) { 81 if (ret < 0) {
82 kfree(state); 82 kfree(state);
83 return ERR_PTR(ret); 83 return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
84 } 84 }
85 85
86 ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M, 86 ret = nv50_calc_pll(dev, &state->pll, khz, &state->N, &state->M,