diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/device/nve0.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/volt.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/os.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c | 199 |
6 files changed, 218 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 1ec77ccc9611..6461e3565afe 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -226,6 +226,7 @@ nouveau-y += core/subdev/vm/nvc0.o | |||
226 | nouveau-y += core/subdev/volt/base.o | 226 | nouveau-y += core/subdev/volt/base.o |
227 | nouveau-y += core/subdev/volt/gpio.o | 227 | nouveau-y += core/subdev/volt/gpio.o |
228 | nouveau-y += core/subdev/volt/nv40.o | 228 | nouveau-y += core/subdev/volt/nv40.o |
229 | nouveau-y += core/subdev/volt/gk20a.o | ||
229 | 230 | ||
230 | nouveau-y += core/engine/falcon.o | 231 | nouveau-y += core/engine/falcon.o |
231 | nouveau-y += core/engine/xtensa.o | 232 | nouveau-y += core/engine/xtensa.o |
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index b1b2e484ecfa..674da1f095b2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c | |||
@@ -179,6 +179,7 @@ nve0_identify(struct nouveau_device *device) | |||
179 | device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass; | 179 | device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass; |
180 | device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; | 180 | device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; |
181 | device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; | 181 | device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass; |
182 | device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; | ||
182 | break; | 183 | break; |
183 | case 0xf0: | 184 | case 0xf0: |
184 | device->cname = "GK110"; | 185 | device->cname = "GK110"; |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h index 820b62ffd75b..67db5e58880d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h | |||
@@ -52,6 +52,7 @@ int _nouveau_volt_init(struct nouveau_object *); | |||
52 | #define _nouveau_volt_fini _nouveau_subdev_fini | 52 | #define _nouveau_volt_fini _nouveau_subdev_fini |
53 | 53 | ||
54 | extern struct nouveau_oclass nv40_volt_oclass; | 54 | extern struct nouveau_oclass nv40_volt_oclass; |
55 | extern struct nouveau_oclass gk20a_volt_oclass; | ||
55 | 56 | ||
56 | int nouveau_voltgpio_init(struct nouveau_volt *); | 57 | int nouveau_voltgpio_init(struct nouveau_volt *); |
57 | int nouveau_voltgpio_get(struct nouveau_volt *); | 58 | int nouveau_voltgpio_get(struct nouveau_volt *); |
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h index ccfa21d72ddc..bdd05ee7ec72 100644 --- a/drivers/gpu/drm/nouveau/core/os.h +++ b/drivers/gpu/drm/nouveau/core/os.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
24 | #include <linux/power_supply.h> | 24 | #include <linux/power_supply.h> |
25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | #include <linux/regulator/consumer.h> | ||
26 | 27 | ||
27 | #include <asm/unaligned.h> | 28 | #include <asm/unaligned.h> |
28 | 29 | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c index 82abbea2be12..fb4fad374bdd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c | |||
@@ -470,76 +470,91 @@ gk20a_pstates[] = { | |||
470 | { | 470 | { |
471 | .base = { | 471 | .base = { |
472 | .domain[nv_clk_src_gpc] = 72000, | 472 | .domain[nv_clk_src_gpc] = 72000, |
473 | .voltage = 0, | ||
473 | }, | 474 | }, |
474 | }, | 475 | }, |
475 | { | 476 | { |
476 | .base = { | 477 | .base = { |
477 | .domain[nv_clk_src_gpc] = 108000, | 478 | .domain[nv_clk_src_gpc] = 108000, |
479 | .voltage = 1, | ||
478 | }, | 480 | }, |
479 | }, | 481 | }, |
480 | { | 482 | { |
481 | .base = { | 483 | .base = { |
482 | .domain[nv_clk_src_gpc] = 180000, | 484 | .domain[nv_clk_src_gpc] = 180000, |
485 | .voltage = 2, | ||
483 | }, | 486 | }, |
484 | }, | 487 | }, |
485 | { | 488 | { |
486 | .base = { | 489 | .base = { |
487 | .domain[nv_clk_src_gpc] = 252000, | 490 | .domain[nv_clk_src_gpc] = 252000, |
491 | .voltage = 3, | ||
488 | }, | 492 | }, |
489 | }, | 493 | }, |
490 | { | 494 | { |
491 | .base = { | 495 | .base = { |
492 | .domain[nv_clk_src_gpc] = 324000, | 496 | .domain[nv_clk_src_gpc] = 324000, |
497 | .voltage = 4, | ||
493 | }, | 498 | }, |
494 | }, | 499 | }, |
495 | { | 500 | { |
496 | .base = { | 501 | .base = { |
497 | .domain[nv_clk_src_gpc] = 396000, | 502 | .domain[nv_clk_src_gpc] = 396000, |
503 | .voltage = 5, | ||
498 | }, | 504 | }, |
499 | }, | 505 | }, |
500 | { | 506 | { |
501 | .base = { | 507 | .base = { |
502 | .domain[nv_clk_src_gpc] = 468000, | 508 | .domain[nv_clk_src_gpc] = 468000, |
509 | .voltage = 6, | ||
503 | }, | 510 | }, |
504 | }, | 511 | }, |
505 | { | 512 | { |
506 | .base = { | 513 | .base = { |
507 | .domain[nv_clk_src_gpc] = 540000, | 514 | .domain[nv_clk_src_gpc] = 540000, |
515 | .voltage = 7, | ||
508 | }, | 516 | }, |
509 | }, | 517 | }, |
510 | { | 518 | { |
511 | .base = { | 519 | .base = { |
512 | .domain[nv_clk_src_gpc] = 612000, | 520 | .domain[nv_clk_src_gpc] = 612000, |
521 | .voltage = 8, | ||
513 | }, | 522 | }, |
514 | }, | 523 | }, |
515 | { | 524 | { |
516 | .base = { | 525 | .base = { |
517 | .domain[nv_clk_src_gpc] = 648000, | 526 | .domain[nv_clk_src_gpc] = 648000, |
527 | .voltage = 9, | ||
518 | }, | 528 | }, |
519 | }, | 529 | }, |
520 | { | 530 | { |
521 | .base = { | 531 | .base = { |
522 | .domain[nv_clk_src_gpc] = 684000, | 532 | .domain[nv_clk_src_gpc] = 684000, |
533 | .voltage = 10, | ||
523 | }, | 534 | }, |
524 | }, | 535 | }, |
525 | { | 536 | { |
526 | .base = { | 537 | .base = { |
527 | .domain[nv_clk_src_gpc] = 708000, | 538 | .domain[nv_clk_src_gpc] = 708000, |
539 | .voltage = 11, | ||
528 | }, | 540 | }, |
529 | }, | 541 | }, |
530 | { | 542 | { |
531 | .base = { | 543 | .base = { |
532 | .domain[nv_clk_src_gpc] = 756000, | 544 | .domain[nv_clk_src_gpc] = 756000, |
545 | .voltage = 12, | ||
533 | }, | 546 | }, |
534 | }, | 547 | }, |
535 | { | 548 | { |
536 | .base = { | 549 | .base = { |
537 | .domain[nv_clk_src_gpc] = 804000, | 550 | .domain[nv_clk_src_gpc] = 804000, |
551 | .voltage = 13, | ||
538 | }, | 552 | }, |
539 | }, | 553 | }, |
540 | { | 554 | { |
541 | .base = { | 555 | .base = { |
542 | .domain[nv_clk_src_gpc] = 852000, | 556 | .domain[nv_clk_src_gpc] = 852000, |
557 | .voltage = 14, | ||
543 | }, | 558 | }, |
544 | }, | 559 | }, |
545 | }; | 560 | }; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c new file mode 100644 index 000000000000..717368ef31ac --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifdef __KERNEL__ | ||
24 | #include <nouveau_platform.h> | ||
25 | #endif | ||
26 | #include <subdev/volt.h> | ||
27 | |||
28 | struct cvb_coef { | ||
29 | int c0; | ||
30 | int c1; | ||
31 | int c2; | ||
32 | int c3; | ||
33 | int c4; | ||
34 | int c5; | ||
35 | }; | ||
36 | |||
37 | struct gk20a_volt_priv { | ||
38 | struct nouveau_volt base; | ||
39 | struct regulator *vdd; | ||
40 | }; | ||
41 | |||
42 | const struct cvb_coef gk20a_cvb_coef[] = { | ||
43 | /* MHz, c0, c1, c2, c3, c4, c5 */ | ||
44 | /* 72 */ { 1209886, -36468, 515, 417, -13123, 203}, | ||
45 | /* 108 */ { 1130804, -27659, 296, 298, -10834, 221}, | ||
46 | /* 180 */ { 1162871, -27110, 247, 238, -10681, 268}, | ||
47 | /* 252 */ { 1220458, -28654, 247, 179, -10376, 298}, | ||
48 | /* 324 */ { 1280953, -30204, 247, 119, -9766, 304}, | ||
49 | /* 396 */ { 1344547, -31777, 247, 119, -8545, 292}, | ||
50 | /* 468 */ { 1420168, -34227, 269, 60, -7172, 256}, | ||
51 | /* 540 */ { 1490757, -35955, 274, 60, -5188, 197}, | ||
52 | /* 612 */ { 1599112, -42583, 398, 0, -1831, 119}, | ||
53 | /* 648 */ { 1366986, -16459, -274, 0, -3204, 72}, | ||
54 | /* 684 */ { 1391884, -17078, -274, -60, -1526, 30}, | ||
55 | /* 708 */ { 1415522, -17497, -274, -60, -458, 0}, | ||
56 | /* 756 */ { 1464061, -18331, -274, -119, 1831, -72}, | ||
57 | /* 804 */ { 1524225, -20064, -254, -119, 4272, -155}, | ||
58 | /* 852 */ { 1608418, -21643, -269, 0, 763, -48}, | ||
59 | }; | ||
60 | |||
61 | /** | ||
62 | * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) | ||
63 | */ | ||
64 | static inline int | ||
65 | gk20a_volt_get_cvb_voltage(int speedo, int s_scale, | ||
66 | const struct cvb_coef *coef) | ||
67 | { | ||
68 | int mv; | ||
69 | |||
70 | mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale); | ||
71 | mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0; | ||
72 | return mv; | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * cvb_t_mv = | ||
77 | * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) + | ||
78 | * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale) | ||
79 | */ | ||
80 | static inline int | ||
81 | gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale, | ||
82 | const struct cvb_coef *coef) | ||
83 | { | ||
84 | int cvb_mv, mv; | ||
85 | |||
86 | cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef); | ||
87 | |||
88 | mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 + | ||
89 | DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale); | ||
90 | mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv; | ||
91 | return mv; | ||
92 | } | ||
93 | |||
94 | static int | ||
95 | gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) | ||
96 | { | ||
97 | int mv; | ||
98 | |||
99 | mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef); | ||
100 | mv = DIV_ROUND_UP(mv, 1000); | ||
101 | |||
102 | return mv * 1000; | ||
103 | } | ||
104 | |||
105 | static int | ||
106 | gk20a_volt_vid_get(struct nouveau_volt *volt) | ||
107 | { | ||
108 | struct gk20a_volt_priv *priv = (void *)volt; | ||
109 | int i, uv; | ||
110 | |||
111 | uv = regulator_get_voltage(priv->vdd); | ||
112 | |||
113 | for (i = 0; i < volt->vid_nr; i++) | ||
114 | if (volt->vid[i].uv >= uv) | ||
115 | return i; | ||
116 | |||
117 | return -EINVAL; | ||
118 | } | ||
119 | |||
120 | static int | ||
121 | gk20a_volt_vid_set(struct nouveau_volt *volt, u8 vid) | ||
122 | { | ||
123 | struct gk20a_volt_priv *priv = (void *)volt; | ||
124 | |||
125 | nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv); | ||
126 | return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000); | ||
127 | } | ||
128 | |||
129 | static int | ||
130 | gk20a_volt_set_id(struct nouveau_volt *volt, u8 id, int condition) | ||
131 | { | ||
132 | struct gk20a_volt_priv *priv = (void *)volt; | ||
133 | int prev_uv = regulator_get_voltage(priv->vdd); | ||
134 | int target_uv = volt->vid[id].uv; | ||
135 | int ret; | ||
136 | |||
137 | nv_debug(volt, "prev=%d, target=%d, condition=%d\n", | ||
138 | prev_uv, target_uv, condition); | ||
139 | if (!condition || | ||
140 | (condition < 0 && target_uv < prev_uv) || | ||
141 | (condition > 0 && target_uv > prev_uv)) { | ||
142 | ret = gk20a_volt_vid_set(volt, volt->vid[id].vid); | ||
143 | } else { | ||
144 | ret = 0; | ||
145 | } | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | static int | ||
151 | gk20a_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | ||
152 | struct nouveau_oclass *oclass, void *data, u32 size, | ||
153 | struct nouveau_object **pobject) | ||
154 | { | ||
155 | struct gk20a_volt_priv *priv; | ||
156 | struct nouveau_volt *volt; | ||
157 | struct nouveau_platform_device *plat; | ||
158 | int i, ret, uv; | ||
159 | |||
160 | ret = nouveau_volt_create(parent, engine, oclass, &priv); | ||
161 | *pobject = nv_object(priv); | ||
162 | if (ret) | ||
163 | return ret; | ||
164 | |||
165 | volt = &priv->base; | ||
166 | |||
167 | plat = nv_device_to_platform(nv_device(parent)); | ||
168 | |||
169 | uv = regulator_get_voltage(plat->gpu->vdd); | ||
170 | nv_info(priv, "The default voltage is %duV\n", uv); | ||
171 | |||
172 | priv->vdd = plat->gpu->vdd; | ||
173 | priv->base.vid_get = gk20a_volt_vid_get; | ||
174 | priv->base.vid_set = gk20a_volt_vid_set; | ||
175 | priv->base.set_id = gk20a_volt_set_id; | ||
176 | |||
177 | volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef); | ||
178 | nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr); | ||
179 | for (i = 0; i < volt->vid_nr; i++) { | ||
180 | volt->vid[i].vid = i; | ||
181 | volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], | ||
182 | plat->gpu_speedo); | ||
183 | nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid, | ||
184 | volt->vid[i].uv); | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | struct nouveau_oclass | ||
191 | gk20a_volt_oclass = { | ||
192 | .handle = NV_SUBDEV(VOLT, 0xea), | ||
193 | .ofuncs = &(struct nouveau_ofuncs) { | ||
194 | .ctor = gk20a_volt_ctor, | ||
195 | .dtor = _nouveau_volt_dtor, | ||
196 | .init = _nouveau_volt_init, | ||
197 | .fini = _nouveau_volt_fini, | ||
198 | }, | ||
199 | }; | ||