diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bios.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.c | 89 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_pm.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_pm.c | 2 |
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" | |||
102 | int nouveau_reg_debug; | 102 | int nouveau_reg_debug; |
103 | module_param_named(reg_debug, nouveau_reg_debug, int, 0600); | 103 | module_param_named(reg_debug, nouveau_reg_debug, int, 0600); |
104 | 104 | ||
105 | MODULE_PARM_DESC(perflvl, "Performance level (default: boot)\n"); | ||
106 | char *nouveau_perflvl; | ||
107 | module_param_named(perflvl, nouveau_perflvl, charp, 0400); | ||
108 | |||
109 | MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)\n"); | ||
110 | int nouveau_perflvl_wr; | ||
111 | module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); | ||
112 | |||
105 | int nouveau_fbpercrtc; | 113 | int nouveau_fbpercrtc; |
106 | #if 0 | 114 | #if 0 |
107 | module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); | 115 | module_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; | |||
716 | extern int nouveau_nofbaccel; | 716 | extern int nouveau_nofbaccel; |
717 | extern int nouveau_noaccel; | 717 | extern int nouveau_noaccel; |
718 | extern int nouveau_override_conntype; | 718 | extern int nouveau_override_conntype; |
719 | extern char *nouveau_perflvl; | ||
720 | extern int nouveau_perflvl_wr; | ||
719 | 721 | ||
720 | extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); | 722 | extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); |
721 | extern int nouveau_pci_resume(struct pci_dev *pdev); | 723 | extern 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 | ||
30 | static int | 30 | static int |
31 | nouveau_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 | |||
49 | static int | ||
50 | nouveau_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 | |||
102 | static int | ||
31 | nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) | 103 | nouveau_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 | |||
130 | nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, | 202 | nouveau_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 | ||
136 | DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, | 214 | DEVICE_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, |