Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0019  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0020  * DEALINGS IN THE SOFTWARE.
0021  */
0022 #define gk20a_volt(p) container_of((p), struct gk20a_volt, base)
0023 #include "priv.h"
0024 
0025 #include <core/tegra.h>
0026 
0027 #include "gk20a.h"
0028 
0029 static const struct cvb_coef gk20a_cvb_coef[] = {
0030     /* MHz,        c0,     c1,   c2,    c3,     c4,   c5 */
0031     /*  72 */ { 1209886, -36468,  515,   417, -13123,  203},
0032     /* 108 */ { 1130804, -27659,  296,   298, -10834,  221},
0033     /* 180 */ { 1162871, -27110,  247,   238, -10681,  268},
0034     /* 252 */ { 1220458, -28654,  247,   179, -10376,  298},
0035     /* 324 */ { 1280953, -30204,  247,   119,  -9766,  304},
0036     /* 396 */ { 1344547, -31777,  247,   119,  -8545,  292},
0037     /* 468 */ { 1420168, -34227,  269,    60,  -7172,  256},
0038     /* 540 */ { 1490757, -35955,  274,    60,  -5188,  197},
0039     /* 612 */ { 1599112, -42583,  398,     0,  -1831,  119},
0040     /* 648 */ { 1366986, -16459, -274,     0,  -3204,   72},
0041     /* 684 */ { 1391884, -17078, -274,   -60,  -1526,   30},
0042     /* 708 */ { 1415522, -17497, -274,   -60,   -458,    0},
0043     /* 756 */ { 1464061, -18331, -274,  -119,   1831,  -72},
0044     /* 804 */ { 1524225, -20064, -254,  -119,   4272, -155},
0045     /* 852 */ { 1608418, -21643, -269,     0,    763,  -48},
0046 };
0047 
0048 /**
0049  * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
0050  */
0051 static inline int
0052 gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef)
0053 {
0054     int mv;
0055 
0056     mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
0057     mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
0058     return mv;
0059 }
0060 
0061 /**
0062  * cvb_t_mv =
0063  * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
0064  * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
0065  */
0066 static inline int
0067 gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
0068                  const struct cvb_coef *coef)
0069 {
0070     int cvb_mv, mv;
0071 
0072     cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
0073 
0074     mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
0075         DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
0076     mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
0077     return mv;
0078 }
0079 
0080 static int
0081 gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
0082 {
0083     static const int v_scale = 1000;
0084     int mv;
0085 
0086     mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
0087     mv = DIV_ROUND_UP(mv, v_scale);
0088 
0089     return mv * 1000;
0090 }
0091 
0092 static int
0093 gk20a_volt_vid_get(struct nvkm_volt *base)
0094 {
0095     struct gk20a_volt *volt = gk20a_volt(base);
0096     int i, uv;
0097 
0098     uv = regulator_get_voltage(volt->vdd);
0099 
0100     for (i = 0; i < volt->base.vid_nr; i++)
0101         if (volt->base.vid[i].uv >= uv)
0102             return i;
0103 
0104     return -EINVAL;
0105 }
0106 
0107 static int
0108 gk20a_volt_vid_set(struct nvkm_volt *base, u8 vid)
0109 {
0110     struct gk20a_volt *volt = gk20a_volt(base);
0111     struct nvkm_subdev *subdev = &volt->base.subdev;
0112 
0113     nvkm_debug(subdev, "set voltage as %duv\n", volt->base.vid[vid].uv);
0114     return regulator_set_voltage(volt->vdd, volt->base.vid[vid].uv, 1200000);
0115 }
0116 
0117 static int
0118 gk20a_volt_set_id(struct nvkm_volt *base, u8 id, int condition)
0119 {
0120     struct gk20a_volt *volt = gk20a_volt(base);
0121     struct nvkm_subdev *subdev = &volt->base.subdev;
0122     int prev_uv = regulator_get_voltage(volt->vdd);
0123     int target_uv = volt->base.vid[id].uv;
0124     int ret;
0125 
0126     nvkm_debug(subdev, "prev=%d, target=%d, condition=%d\n",
0127            prev_uv, target_uv, condition);
0128     if (!condition ||
0129         (condition < 0 && target_uv < prev_uv) ||
0130         (condition > 0 && target_uv > prev_uv)) {
0131         ret = gk20a_volt_vid_set(&volt->base, volt->base.vid[id].vid);
0132     } else {
0133         ret = 0;
0134     }
0135 
0136     return ret;
0137 }
0138 
0139 static const struct nvkm_volt_func
0140 gk20a_volt = {
0141     .vid_get = gk20a_volt_vid_get,
0142     .vid_set = gk20a_volt_vid_set,
0143     .set_id = gk20a_volt_set_id,
0144 };
0145 
0146 int
0147 gk20a_volt_ctor(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
0148         const struct cvb_coef *coefs, int nb_coefs,
0149         int vmin, struct gk20a_volt *volt)
0150 {
0151     struct nvkm_device_tegra *tdev = device->func->tegra(device);
0152     int i, uv;
0153 
0154     nvkm_volt_ctor(&gk20a_volt, device, type, inst, &volt->base);
0155 
0156     uv = regulator_get_voltage(tdev->vdd);
0157     nvkm_debug(&volt->base.subdev, "the default voltage is %duV\n", uv);
0158 
0159     volt->vdd = tdev->vdd;
0160 
0161     volt->base.vid_nr = nb_coefs;
0162     for (i = 0; i < volt->base.vid_nr; i++) {
0163         volt->base.vid[i].vid = i;
0164         volt->base.vid[i].uv = max(
0165             gk20a_volt_calc_voltage(&coefs[i], tdev->gpu_speedo),
0166             vmin);
0167         nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i,
0168                volt->base.vid[i].vid, volt->base.vid[i].uv);
0169     }
0170 
0171     return 0;
0172 }
0173 
0174 int
0175 gk20a_volt_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_volt **pvolt)
0176 {
0177     struct gk20a_volt *volt;
0178 
0179     volt = kzalloc(sizeof(*volt), GFP_KERNEL);
0180     if (!volt)
0181         return -ENOMEM;
0182     *pvolt = &volt->base;
0183 
0184     return gk20a_volt_ctor(device, type, inst, gk20a_cvb_coef,
0185                    ARRAY_SIZE(gk20a_cvb_coef), 0, volt);
0186 }