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 | }; | ||
