diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/device/nv50.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/software/nv50.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/clock.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c | 445 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv04/overlay.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_hwmon.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 2 |
13 files changed, 505 insertions, 18 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index edcf801613e6..b3fa1ba191b7 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -59,6 +59,7 @@ nouveau-y += core/subdev/clock/nv40.o | |||
59 | nouveau-y += core/subdev/clock/nv50.o | 59 | nouveau-y += core/subdev/clock/nv50.o |
60 | nouveau-y += core/subdev/clock/nv84.o | 60 | nouveau-y += core/subdev/clock/nv84.o |
61 | nouveau-y += core/subdev/clock/nva3.o | 61 | nouveau-y += core/subdev/clock/nva3.o |
62 | nouveau-y += core/subdev/clock/nvaa.o | ||
62 | nouveau-y += core/subdev/clock/nvc0.o | 63 | nouveau-y += core/subdev/clock/nvc0.o |
63 | nouveau-y += core/subdev/clock/nve0.o | 64 | nouveau-y += core/subdev/clock/nve0.o |
64 | nouveau-y += core/subdev/clock/pllnv04.o | 65 | nouveau-y += core/subdev/clock/pllnv04.o |
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c index db139827047c..db3fc7be856a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c | |||
@@ -283,7 +283,7 @@ nv50_identify(struct nouveau_device *device) | |||
283 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 283 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
284 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 284 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
285 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; | 285 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
286 | device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; | 286 | device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; |
287 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; | 287 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; |
288 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 288 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
289 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 289 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
@@ -311,7 +311,7 @@ nv50_identify(struct nouveau_device *device) | |||
311 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; | 311 | device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; |
312 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; | 312 | device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass; |
313 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; | 313 | device->oclass[NVDEV_SUBDEV_I2C ] = &nv94_i2c_oclass; |
314 | device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass; | 314 | device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass; |
315 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; | 315 | device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass; |
316 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; | 316 | device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; |
317 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; | 317 | device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c index 5f555788121c..e6352bd5b4ff 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <engine/dmaobj.h> | 33 | #include <engine/dmaobj.h> |
34 | #include <engine/fifo.h> | 34 | #include <engine/fifo.h> |
35 | 35 | ||
36 | #include "nv04.h" | ||
36 | #include "nv50.h" | 37 | #include "nv50.h" |
37 | 38 | ||
38 | /******************************************************************************* | 39 | /******************************************************************************* |
@@ -460,6 +461,8 @@ nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
460 | nv_subdev(priv)->intr = nv04_fifo_intr; | 461 | nv_subdev(priv)->intr = nv04_fifo_intr; |
461 | nv_engine(priv)->cclass = &nv50_fifo_cclass; | 462 | nv_engine(priv)->cclass = &nv50_fifo_cclass; |
462 | nv_engine(priv)->sclass = nv50_fifo_sclass; | 463 | nv_engine(priv)->sclass = nv50_fifo_sclass; |
464 | priv->base.pause = nv04_fifo_pause; | ||
465 | priv->base.start = nv04_fifo_start; | ||
463 | return 0; | 466 | return 0; |
464 | } | 467 | } |
465 | 468 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c index 0908dc834c84..fe0f41e65d9b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <engine/dmaobj.h> | 35 | #include <engine/dmaobj.h> |
36 | #include <engine/fifo.h> | 36 | #include <engine/fifo.h> |
37 | 37 | ||
38 | #include "nv04.h" | ||
38 | #include "nv50.h" | 39 | #include "nv50.h" |
39 | 40 | ||
40 | /******************************************************************************* | 41 | /******************************************************************************* |
@@ -432,6 +433,8 @@ nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
432 | nv_subdev(priv)->intr = nv04_fifo_intr; | 433 | nv_subdev(priv)->intr = nv04_fifo_intr; |
433 | nv_engine(priv)->cclass = &nv84_fifo_cclass; | 434 | nv_engine(priv)->cclass = &nv84_fifo_cclass; |
434 | nv_engine(priv)->sclass = nv84_fifo_sclass; | 435 | nv_engine(priv)->sclass = nv84_fifo_sclass; |
436 | priv->base.pause = nv04_fifo_pause; | ||
437 | priv->base.start = nv04_fifo_start; | ||
435 | return 0; | 438 | return 0; |
436 | } | 439 | } |
437 | 440 | ||
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c index b574dd4bb828..5ce686ee729e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c | |||
@@ -176,7 +176,7 @@ nv50_software_context_ctor(struct nouveau_object *parent, | |||
176 | if (ret) | 176 | if (ret) |
177 | return ret; | 177 | return ret; |
178 | 178 | ||
179 | chan->vblank.nr_event = pdisp->vblank->index_nr; | 179 | chan->vblank.nr_event = pdisp ? pdisp->vblank->index_nr : 0; |
180 | chan->vblank.event = kzalloc(chan->vblank.nr_event * | 180 | chan->vblank.event = kzalloc(chan->vblank.nr_event * |
181 | sizeof(*chan->vblank.event), GFP_KERNEL); | 181 | sizeof(*chan->vblank.event), GFP_KERNEL); |
182 | if (!chan->vblank.event) | 182 | if (!chan->vblank.event) |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index e2675bc0edba..8f4ced75444a 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h | |||
@@ -14,6 +14,9 @@ enum nv_clk_src { | |||
14 | nv_clk_src_hclk, | 14 | nv_clk_src_hclk, |
15 | nv_clk_src_hclkm3, | 15 | nv_clk_src_hclkm3, |
16 | nv_clk_src_hclkm3d2, | 16 | nv_clk_src_hclkm3d2, |
17 | nv_clk_src_hclkm2d3, /* NVAA */ | ||
18 | nv_clk_src_hclkm4, /* NVAA */ | ||
19 | nv_clk_src_cclk, /* NVAA */ | ||
17 | 20 | ||
18 | nv_clk_src_host, | 21 | nv_clk_src_host, |
19 | 22 | ||
@@ -127,6 +130,7 @@ extern struct nouveau_oclass nv04_clock_oclass; | |||
127 | extern struct nouveau_oclass nv40_clock_oclass; | 130 | extern struct nouveau_oclass nv40_clock_oclass; |
128 | extern struct nouveau_oclass *nv50_clock_oclass; | 131 | extern struct nouveau_oclass *nv50_clock_oclass; |
129 | extern struct nouveau_oclass *nv84_clock_oclass; | 132 | extern struct nouveau_oclass *nv84_clock_oclass; |
133 | extern struct nouveau_oclass *nvaa_clock_oclass; | ||
130 | extern struct nouveau_oclass nva3_clock_oclass; | 134 | extern struct nouveau_oclass nva3_clock_oclass; |
131 | extern struct nouveau_oclass nvc0_clock_oclass; | 135 | extern struct nouveau_oclass nvc0_clock_oclass; |
132 | extern struct nouveau_oclass nve0_clock_oclass; | 136 | extern struct nouveau_oclass nve0_clock_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c index da50c1b12928..30c1f3a4158e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c | |||
@@ -69,6 +69,11 @@ nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1, | |||
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | static struct nouveau_clocks | ||
73 | nv04_domain[] = { | ||
74 | { nv_clk_src_max } | ||
75 | }; | ||
76 | |||
72 | static int | 77 | static int |
73 | nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | 78 | nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
74 | struct nouveau_oclass *oclass, void *data, u32 size, | 79 | struct nouveau_oclass *oclass, void *data, u32 size, |
@@ -77,7 +82,7 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
77 | struct nv04_clock_priv *priv; | 82 | struct nv04_clock_priv *priv; |
78 | int ret; | 83 | int ret; |
79 | 84 | ||
80 | ret = nouveau_clock_create(parent, engine, oclass, NULL, &priv); | 85 | ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, &priv); |
81 | *pobject = nv_object(priv); | 86 | *pobject = nv_object(priv); |
82 | if (ret) | 87 | if (ret) |
83 | return ret; | 88 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c new file mode 100644 index 000000000000..7a723b4f564d --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c | |||
@@ -0,0 +1,445 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include <engine/fifo.h> | ||
26 | #include <subdev/bios.h> | ||
27 | #include <subdev/bios/pll.h> | ||
28 | #include <subdev/timer.h> | ||
29 | #include <subdev/clock.h> | ||
30 | |||
31 | #include "pll.h" | ||
32 | |||
33 | struct nvaa_clock_priv { | ||
34 | struct nouveau_clock base; | ||
35 | enum nv_clk_src csrc, ssrc, vsrc; | ||
36 | u32 cctrl, sctrl; | ||
37 | u32 ccoef, scoef; | ||
38 | u32 cpost, spost; | ||
39 | u32 vdiv; | ||
40 | }; | ||
41 | |||
42 | static u32 | ||
43 | read_div(struct nouveau_clock *clk) | ||
44 | { | ||
45 | return nv_rd32(clk, 0x004600); | ||
46 | } | ||
47 | |||
48 | static u32 | ||
49 | read_pll(struct nouveau_clock *clk, u32 base) | ||
50 | { | ||
51 | u32 ctrl = nv_rd32(clk, base + 0); | ||
52 | u32 coef = nv_rd32(clk, base + 4); | ||
53 | u32 ref = clk->read(clk, nv_clk_src_href); | ||
54 | u32 post_div = 0; | ||
55 | u32 clock = 0; | ||
56 | int N1, M1; | ||
57 | |||
58 | switch (base){ | ||
59 | case 0x4020: | ||
60 | post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); | ||
61 | break; | ||
62 | case 0x4028: | ||
63 | post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; | ||
64 | break; | ||
65 | default: | ||
66 | break; | ||
67 | } | ||
68 | |||
69 | N1 = (coef & 0x0000ff00) >> 8; | ||
70 | M1 = (coef & 0x000000ff); | ||
71 | if ((ctrl & 0x80000000) && M1) { | ||
72 | clock = ref * N1 / M1; | ||
73 | clock = clock / post_div; | ||
74 | } | ||
75 | |||
76 | return clock; | ||
77 | } | ||
78 | |||
79 | static int | ||
80 | nvaa_clock_read(struct nouveau_clock *clk, enum nv_clk_src src) | ||
81 | { | ||
82 | struct nvaa_clock_priv *priv = (void *)clk; | ||
83 | u32 mast = nv_rd32(clk, 0x00c054); | ||
84 | u32 P = 0; | ||
85 | |||
86 | switch (src) { | ||
87 | case nv_clk_src_crystal: | ||
88 | return nv_device(priv)->crystal; | ||
89 | case nv_clk_src_href: | ||
90 | return 100000; /* PCIE reference clock */ | ||
91 | case nv_clk_src_hclkm4: | ||
92 | return clk->read(clk, nv_clk_src_href) * 4; | ||
93 | case nv_clk_src_hclkm2d3: | ||
94 | return clk->read(clk, nv_clk_src_href) * 2 / 3; | ||
95 | case nv_clk_src_host: | ||
96 | switch (mast & 0x000c0000) { | ||
97 | case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); | ||
98 | case 0x00040000: break; | ||
99 | case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); | ||
100 | case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); | ||
101 | } | ||
102 | break; | ||
103 | case nv_clk_src_core: | ||
104 | P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; | ||
105 | |||
106 | switch (mast & 0x00000003) { | ||
107 | case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; | ||
108 | case 0x00000001: return 0; | ||
109 | case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; | ||
110 | case 0x00000003: return read_pll(clk, 0x004028) >> P; | ||
111 | } | ||
112 | break; | ||
113 | case nv_clk_src_cclk: | ||
114 | if ((mast & 0x03000000) != 0x03000000) | ||
115 | return clk->read(clk, nv_clk_src_core); | ||
116 | |||
117 | if ((mast & 0x00000200) == 0x00000000) | ||
118 | return clk->read(clk, nv_clk_src_core); | ||
119 | |||
120 | switch (mast & 0x00000c00) { | ||
121 | case 0x00000000: return clk->read(clk, nv_clk_src_href); | ||
122 | case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); | ||
123 | case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); | ||
124 | default: return 0; | ||
125 | } | ||
126 | case nv_clk_src_shader: | ||
127 | P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; | ||
128 | switch (mast & 0x00000030) { | ||
129 | case 0x00000000: | ||
130 | if (mast & 0x00000040) | ||
131 | return clk->read(clk, nv_clk_src_href) >> P; | ||
132 | return clk->read(clk, nv_clk_src_crystal) >> P; | ||
133 | case 0x00000010: break; | ||
134 | case 0x00000020: return read_pll(clk, 0x004028) >> P; | ||
135 | case 0x00000030: return read_pll(clk, 0x004020) >> P; | ||
136 | } | ||
137 | break; | ||
138 | case nv_clk_src_mem: | ||
139 | return 0; | ||
140 | break; | ||
141 | case nv_clk_src_vdec: | ||
142 | P = (read_div(clk) & 0x00000700) >> 8; | ||
143 | |||
144 | switch (mast & 0x00400000) { | ||
145 | case 0x00400000: | ||
146 | return clk->read(clk, nv_clk_src_core) >> P; | ||
147 | break; | ||
148 | default: | ||
149 | return 500000 >> P; | ||
150 | break; | ||
151 | } | ||
152 | break; | ||
153 | default: | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static u32 | ||
162 | calc_pll(struct nvaa_clock_priv *priv, u32 reg, | ||
163 | u32 clock, int *N, int *M, int *P) | ||
164 | { | ||
165 | struct nouveau_bios *bios = nouveau_bios(priv); | ||
166 | struct nvbios_pll pll; | ||
167 | struct nouveau_clock *clk = &priv->base; | ||
168 | int ret; | ||
169 | |||
170 | ret = nvbios_pll_parse(bios, reg, &pll); | ||
171 | if (ret) | ||
172 | return 0; | ||
173 | |||
174 | pll.vco2.max_freq = 0; | ||
175 | pll.refclk = clk->read(clk, nv_clk_src_href); | ||
176 | if (!pll.refclk) | ||
177 | return 0; | ||
178 | |||
179 | return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); | ||
180 | } | ||
181 | |||
182 | static inline u32 | ||
183 | calc_P(u32 src, u32 target, int *div) | ||
184 | { | ||
185 | u32 clk0 = src, clk1 = src; | ||
186 | for (*div = 0; *div <= 7; (*div)++) { | ||
187 | if (clk0 <= target) { | ||
188 | clk1 = clk0 << (*div ? 1 : 0); | ||
189 | break; | ||
190 | } | ||
191 | clk0 >>= 1; | ||
192 | } | ||
193 | |||
194 | if (target - clk0 <= clk1 - target) | ||
195 | return clk0; | ||
196 | (*div)--; | ||
197 | return clk1; | ||
198 | } | ||
199 | |||
200 | static int | ||
201 | nvaa_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate) | ||
202 | { | ||
203 | struct nvaa_clock_priv *priv = (void *)clk; | ||
204 | const int shader = cstate->domain[nv_clk_src_shader]; | ||
205 | const int core = cstate->domain[nv_clk_src_core]; | ||
206 | const int vdec = cstate->domain[nv_clk_src_vdec]; | ||
207 | u32 out = 0, clock = 0; | ||
208 | int N, M, P1, P2 = 0; | ||
209 | int divs = 0; | ||
210 | |||
211 | /* cclk: find suitable source, disable PLL if we can */ | ||
212 | if (core < clk->read(clk, nv_clk_src_hclkm4)) | ||
213 | out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); | ||
214 | |||
215 | /* Calculate clock * 2, so shader clock can use it too */ | ||
216 | clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); | ||
217 | |||
218 | if (abs(core - out) <= | ||
219 | abs(core - (clock >> 1))) { | ||
220 | priv->csrc = nv_clk_src_hclkm4; | ||
221 | priv->cctrl = divs << 16; | ||
222 | } else { | ||
223 | /* NVCTRL is actually used _after_ NVPOST, and after what we | ||
224 | * call NVPLL. To make matters worse, NVPOST is an integer | ||
225 | * divider instead of a right-shift number. */ | ||
226 | if(P1 > 2) { | ||
227 | P2 = P1 - 2; | ||
228 | P1 = 2; | ||
229 | } | ||
230 | |||
231 | priv->csrc = nv_clk_src_core; | ||
232 | priv->ccoef = (N << 8) | M; | ||
233 | |||
234 | priv->cctrl = (P2 + 1) << 16; | ||
235 | priv->cpost = (1 << P1) << 16; | ||
236 | } | ||
237 | |||
238 | /* sclk: nvpll + divisor, href or spll */ | ||
239 | out = 0; | ||
240 | if (shader == clk->read(clk, nv_clk_src_href)) { | ||
241 | priv->ssrc = nv_clk_src_href; | ||
242 | } else { | ||
243 | clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); | ||
244 | if (priv->csrc == nv_clk_src_core) { | ||
245 | out = calc_P((core << 1), shader, &divs); | ||
246 | } | ||
247 | |||
248 | if (abs(shader - out) <= | ||
249 | abs(shader - clock) && | ||
250 | (divs + P2) <= 7) { | ||
251 | priv->ssrc = nv_clk_src_core; | ||
252 | priv->sctrl = (divs + P2) << 16; | ||
253 | } else { | ||
254 | priv->ssrc = nv_clk_src_shader; | ||
255 | priv->scoef = (N << 8) | M; | ||
256 | priv->sctrl = P1 << 16; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /* vclk */ | ||
261 | out = calc_P(core, vdec, &divs); | ||
262 | clock = calc_P(500000, vdec, &P1); | ||
263 | if(abs(vdec - out) <= | ||
264 | abs(vdec - clock)) { | ||
265 | priv->vsrc = nv_clk_src_cclk; | ||
266 | priv->vdiv = divs << 16; | ||
267 | } else { | ||
268 | priv->vsrc = nv_clk_src_vdec; | ||
269 | priv->vdiv = P1 << 16; | ||
270 | } | ||
271 | |||
272 | /* Print strategy! */ | ||
273 | nv_debug(priv, "nvpll: %08x %08x %08x\n", | ||
274 | priv->ccoef, priv->cpost, priv->cctrl); | ||
275 | nv_debug(priv, " spll: %08x %08x %08x\n", | ||
276 | priv->scoef, priv->spost, priv->sctrl); | ||
277 | nv_debug(priv, " vdiv: %08x\n", priv->vdiv); | ||
278 | if (priv->csrc == nv_clk_src_hclkm4) | ||
279 | nv_debug(priv, "core: hrefm4\n"); | ||
280 | else | ||
281 | nv_debug(priv, "core: nvpll\n"); | ||
282 | |||
283 | if (priv->ssrc == nv_clk_src_hclkm4) | ||
284 | nv_debug(priv, "shader: hrefm4\n"); | ||
285 | else if (priv->ssrc == nv_clk_src_core) | ||
286 | nv_debug(priv, "shader: nvpll\n"); | ||
287 | else | ||
288 | nv_debug(priv, "shader: spll\n"); | ||
289 | |||
290 | if (priv->vsrc == nv_clk_src_hclkm4) | ||
291 | nv_debug(priv, "vdec: 500MHz\n"); | ||
292 | else | ||
293 | nv_debug(priv, "vdec: core\n"); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int | ||
299 | nvaa_clock_prog(struct nouveau_clock *clk) | ||
300 | { | ||
301 | struct nvaa_clock_priv *priv = (void *)clk; | ||
302 | struct nouveau_fifo *pfifo = nouveau_fifo(clk); | ||
303 | unsigned long flags; | ||
304 | u32 pllmask = 0, mast, ptherm_gate; | ||
305 | int ret = -EBUSY; | ||
306 | |||
307 | /* halt and idle execution engines */ | ||
308 | ptherm_gate = nv_mask(clk, 0x020060, 0x00070000, 0x00000000); | ||
309 | nv_mask(clk, 0x002504, 0x00000001, 0x00000001); | ||
310 | /* Wait until the interrupt handler is finished */ | ||
311 | if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) | ||
312 | goto resume; | ||
313 | |||
314 | if (pfifo) | ||
315 | pfifo->pause(pfifo, &flags); | ||
316 | |||
317 | if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) | ||
318 | goto resume; | ||
319 | if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) | ||
320 | goto resume; | ||
321 | |||
322 | /* First switch to safe clocks: href */ | ||
323 | mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); | ||
324 | mast &= ~0x00400e73; | ||
325 | mast |= 0x03000000; | ||
326 | |||
327 | switch (priv->csrc) { | ||
328 | case nv_clk_src_hclkm4: | ||
329 | nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); | ||
330 | mast |= 0x00000002; | ||
331 | break; | ||
332 | case nv_clk_src_core: | ||
333 | nv_wr32(clk, 0x402c, priv->ccoef); | ||
334 | nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); | ||
335 | nv_wr32(clk, 0x4040, priv->cpost); | ||
336 | pllmask |= (0x3 << 8); | ||
337 | mast |= 0x00000003; | ||
338 | break; | ||
339 | default: | ||
340 | nv_warn(priv,"Reclocking failed: unknown core clock\n"); | ||
341 | goto resume; | ||
342 | } | ||
343 | |||
344 | switch (priv->ssrc) { | ||
345 | case nv_clk_src_href: | ||
346 | nv_mask(clk, 0x4020, 0x00070000, 0x00000000); | ||
347 | /* mast |= 0x00000000; */ | ||
348 | break; | ||
349 | case nv_clk_src_core: | ||
350 | nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); | ||
351 | mast |= 0x00000020; | ||
352 | break; | ||
353 | case nv_clk_src_shader: | ||
354 | nv_wr32(clk, 0x4024, priv->scoef); | ||
355 | nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); | ||
356 | nv_wr32(clk, 0x4070, priv->spost); | ||
357 | pllmask |= (0x3 << 12); | ||
358 | mast |= 0x00000030; | ||
359 | break; | ||
360 | default: | ||
361 | nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); | ||
362 | goto resume; | ||
363 | } | ||
364 | |||
365 | if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { | ||
366 | nv_warn(priv,"Reclocking failed: unstable PLLs\n"); | ||
367 | goto resume; | ||
368 | } | ||
369 | |||
370 | switch (priv->vsrc) { | ||
371 | case nv_clk_src_cclk: | ||
372 | mast |= 0x00400000; | ||
373 | default: | ||
374 | nv_wr32(clk, 0x4600, priv->vdiv); | ||
375 | } | ||
376 | |||
377 | nv_wr32(clk, 0xc054, mast); | ||
378 | ret = 0; | ||
379 | |||
380 | resume: | ||
381 | if (pfifo) | ||
382 | pfifo->start(pfifo, &flags); | ||
383 | |||
384 | nv_mask(clk, 0x002504, 0x00000001, 0x00000000); | ||
385 | nv_wr32(clk, 0x020060, ptherm_gate); | ||
386 | |||
387 | /* Disable some PLLs and dividers when unused */ | ||
388 | if (priv->csrc != nv_clk_src_core) { | ||
389 | nv_wr32(clk, 0x4040, 0x00000000); | ||
390 | nv_mask(clk, 0x4028, 0x80000000, 0x00000000); | ||
391 | } | ||
392 | |||
393 | if (priv->ssrc != nv_clk_src_shader) { | ||
394 | nv_wr32(clk, 0x4070, 0x00000000); | ||
395 | nv_mask(clk, 0x4020, 0x80000000, 0x00000000); | ||
396 | } | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static void | ||
402 | nvaa_clock_tidy(struct nouveau_clock *clk) | ||
403 | { | ||
404 | } | ||
405 | |||
406 | static struct nouveau_clocks | ||
407 | nvaa_domains[] = { | ||
408 | { nv_clk_src_crystal, 0xff }, | ||
409 | { nv_clk_src_href , 0xff }, | ||
410 | { nv_clk_src_core , 0xff, 0, "core", 1000 }, | ||
411 | { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, | ||
412 | { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, | ||
413 | { nv_clk_src_max } | ||
414 | }; | ||
415 | |||
416 | static int | ||
417 | nvaa_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
418 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
419 | struct nouveau_object **pobject) | ||
420 | { | ||
421 | struct nvaa_clock_priv *priv; | ||
422 | int ret; | ||
423 | |||
424 | ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, &priv); | ||
425 | *pobject = nv_object(priv); | ||
426 | if (ret) | ||
427 | return ret; | ||
428 | |||
429 | priv->base.read = nvaa_clock_read; | ||
430 | priv->base.calc = nvaa_clock_calc; | ||
431 | priv->base.prog = nvaa_clock_prog; | ||
432 | priv->base.tidy = nvaa_clock_tidy; | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | struct nouveau_oclass * | ||
437 | nvaa_clock_oclass = &(struct nouveau_oclass) { | ||
438 | .handle = NV_SUBDEV(CLOCK, 0xaa), | ||
439 | .ofuncs = &(struct nouveau_ofuncs) { | ||
440 | .ctor = nvaa_clock_ctor, | ||
441 | .dtor = _nouveau_clock_dtor, | ||
442 | .init = _nouveau_clock_init, | ||
443 | .fini = _nouveau_clock_fini, | ||
444 | }, | ||
445 | }; | ||
diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 3618ac6b6316..32e7064b819b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c | |||
@@ -58,8 +58,8 @@ struct nouveau_plane { | |||
58 | }; | 58 | }; |
59 | 59 | ||
60 | static uint32_t formats[] = { | 60 | static uint32_t formats[] = { |
61 | DRM_FORMAT_NV12, | ||
62 | DRM_FORMAT_UYVY, | 61 | DRM_FORMAT_UYVY, |
62 | DRM_FORMAT_NV12, | ||
63 | }; | 63 | }; |
64 | 64 | ||
65 | /* Sine can be approximated with | 65 | /* Sine can be approximated with |
@@ -99,13 +99,28 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | |||
99 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 99 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
100 | struct nouveau_bo *cur = nv_plane->cur; | 100 | struct nouveau_bo *cur = nv_plane->cur; |
101 | bool flip = nv_plane->flip; | 101 | bool flip = nv_plane->flip; |
102 | int format = ALIGN(src_w * 4, 0x100); | ||
103 | int soff = NV_PCRTC0_SIZE * nv_crtc->index; | 102 | int soff = NV_PCRTC0_SIZE * nv_crtc->index; |
104 | int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; | 103 | int soff2 = NV_PCRTC0_SIZE * !nv_crtc->index; |
105 | int ret; | 104 | int format, ret; |
105 | |||
106 | /* Source parameters given in 16.16 fixed point, ignore fractional. */ | ||
107 | src_x >>= 16; | ||
108 | src_y >>= 16; | ||
109 | src_w >>= 16; | ||
110 | src_h >>= 16; | ||
111 | |||
112 | format = ALIGN(src_w * 4, 0x100); | ||
106 | 113 | ||
107 | if (format > 0xffff) | 114 | if (format > 0xffff) |
108 | return -EINVAL; | 115 | return -ERANGE; |
116 | |||
117 | if (dev->chipset >= 0x30) { | ||
118 | if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) | ||
119 | return -ERANGE; | ||
120 | } else { | ||
121 | if (crtc_w < (src_w >> 3) || crtc_h < (src_h >> 3)) | ||
122 | return -ERANGE; | ||
123 | } | ||
109 | 124 | ||
110 | ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); | 125 | ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM); |
111 | if (ret) | 126 | if (ret) |
@@ -113,12 +128,6 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, | |||
113 | 128 | ||
114 | nv_plane->cur = nv_fb->nvbo; | 129 | nv_plane->cur = nv_fb->nvbo; |
115 | 130 | ||
116 | /* Source parameters given in 16.16 fixed point, ignore fractional. */ | ||
117 | src_x = src_x >> 16; | ||
118 | src_y = src_y >> 16; | ||
119 | src_w = src_w >> 16; | ||
120 | src_h = src_h >> 16; | ||
121 | |||
122 | nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); | 131 | nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff, NV_CRTC_FSEL_OVERLAY, NV_CRTC_FSEL_OVERLAY); |
123 | nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); | 132 | nv_mask(dev, NV_PCRTC_ENGINE_CTRL + soff2, NV_CRTC_FSEL_OVERLAY, 0); |
124 | 133 | ||
@@ -245,14 +254,25 @@ nv10_overlay_init(struct drm_device *device) | |||
245 | { | 254 | { |
246 | struct nouveau_device *dev = nouveau_dev(device); | 255 | struct nouveau_device *dev = nouveau_dev(device); |
247 | struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); | 256 | struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL); |
257 | int num_formats = ARRAY_SIZE(formats); | ||
248 | int ret; | 258 | int ret; |
249 | 259 | ||
250 | if (!plane) | 260 | if (!plane) |
251 | return; | 261 | return; |
252 | 262 | ||
263 | switch (dev->chipset) { | ||
264 | case 0x10: | ||
265 | case 0x11: | ||
266 | case 0x15: | ||
267 | case 0x1a: | ||
268 | case 0x20: | ||
269 | num_formats = 1; | ||
270 | break; | ||
271 | } | ||
272 | |||
253 | ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, | 273 | ret = drm_plane_init(device, &plane->base, 3 /* both crtc's */, |
254 | &nv10_plane_funcs, | 274 | &nv10_plane_funcs, |
255 | formats, ARRAY_SIZE(formats), false); | 275 | formats, num_formats, false); |
256 | if (ret) | 276 | if (ret) |
257 | goto err; | 277 | goto err; |
258 | 278 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 7809d92183c4..29c3efdfc7dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -608,6 +608,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
608 | fence = nouveau_fence_ref(new_bo->bo.sync_obj); | 608 | fence = nouveau_fence_ref(new_bo->bo.sync_obj); |
609 | spin_unlock(&new_bo->bo.bdev->fence_lock); | 609 | spin_unlock(&new_bo->bo.bdev->fence_lock); |
610 | ret = nouveau_fence_sync(fence, chan); | 610 | ret = nouveau_fence_sync(fence, chan); |
611 | nouveau_fence_unref(&fence); | ||
611 | if (ret) | 612 | if (ret) |
612 | return ret; | 613 | return ret; |
613 | 614 | ||
@@ -701,7 +702,7 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, | |||
701 | 702 | ||
702 | s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); | 703 | s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head); |
703 | if (s->event) | 704 | if (s->event) |
704 | drm_send_vblank_event(dev, -1, s->event); | 705 | drm_send_vblank_event(dev, s->crtc, s->event); |
705 | 706 | ||
706 | list_del(&s->head); | 707 | list_del(&s->head); |
707 | if (ps) | 708 | if (ps) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 7a3759f1c41a..98a22e6e27a1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -858,6 +858,12 @@ static int nouveau_pmops_runtime_suspend(struct device *dev) | |||
858 | if (nouveau_runtime_pm == 0) | 858 | if (nouveau_runtime_pm == 0) |
859 | return -EINVAL; | 859 | return -EINVAL; |
860 | 860 | ||
861 | /* are we optimus enabled? */ | ||
862 | if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) { | ||
863 | DRM_DEBUG_DRIVER("failing to power off - not optimus\n"); | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
861 | nv_debug_level(SILENT); | 867 | nv_debug_level(SILENT); |
862 | drm_kms_helper_poll_disable(drm_dev); | 868 | drm_kms_helper_poll_disable(drm_dev); |
863 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); | 869 | vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 38a4db5bfe21..4aff04fa483c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c | |||
@@ -630,7 +630,6 @@ error: | |||
630 | hwmon->hwmon = NULL; | 630 | hwmon->hwmon = NULL; |
631 | return ret; | 631 | return ret; |
632 | #else | 632 | #else |
633 | hwmon->hwmon = NULL; | ||
634 | return 0; | 633 | return 0; |
635 | #endif | 634 | #endif |
636 | } | 635 | } |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index f8e66c08b11a..4e384a2f99c3 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -1265,7 +1265,7 @@ nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, | |||
1265 | uint32_t start, uint32_t size) | 1265 | uint32_t start, uint32_t size) |
1266 | { | 1266 | { |
1267 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 1267 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
1268 | u32 end = max(start + size, (u32)256); | 1268 | u32 end = min_t(u32, start + size, 256); |
1269 | u32 i; | 1269 | u32 i; |
1270 | 1270 | ||
1271 | for (i = start; i < end; i++) { | 1271 | for (i = start; i < end; i++) { |