/* * Copyright 2012 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Ben Skeggs * Roy Spliet
*/ #define gt215_clk(p) container_of((p), struct gt215_clk, base) #include"gt215.h" #include"pll.h"
/* refclk for the 0xe8xx plls is a fixed frequency */ if (idx >= 0x40) { if (device->chipset == 0xaf) { /* no joke.. seriously.. sigh.. */ return nvkm_rd32(device, 0x00471c) * 1000;
}
static u32
read_pll(struct gt215_clk *clk, int idx, u32 pll)
{ struct nvkm_device *device = clk->base.subdev.device;
u32 ctrl = nvkm_rd32(device, pll + 0);
u32 sclk = 0, P = 1, N = 1, M = 1;
u32 MP;
if (!(ctrl & 0x00000008)) { if (ctrl & 0x00000001) {
u32 coef = nvkm_rd32(device, pll + 4);
M = (coef & 0x000000ff) >> 0;
N = (coef & 0x0000ff00) >> 8;
P = (coef & 0x003f0000) >> 16;
/* no post-divider on these.. * XXX: it looks more like two post-"dividers" that
* cross each other out in the default RPLL config */ if ((pll & 0x00ff00) == 0x00e800)
P = 1;
/* When imprecise, play it safe and aim for a clock lower than
* desired rather than higher */ if (diff < 0) {
sdiv++;
oclk = (sclk * 2) / sdiv;
}
/* divider can go as low as 2, limited here because NVIDIA * and the VBIOS on my NVA8 seem to prefer using the PLL * for 810MHz - is there a good reason?
* XXX: PLLs with refclk 810MHz? */ if (sdiv > 4) {
info->clk = (((sdiv - 2) << 16) | 0x00003100); return oclk;
}
break;
}
return -ERANGE;
}
int
gt215_pll_info(struct nvkm_clk *base, int idx, u32 pll, u32 khz, struct gt215_clk_info *info)
{ struct gt215_clk *clk = gt215_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll limits; int P, N, M, diff; int ret;
info->pll = 0;
/* If we can get a within [-2, 3) MHz of a divider, we'll disable the
* PLL and use the divider instead. */
ret = gt215_clk_info(&clk->base, idx, khz, info);
diff = khz - ret; if (!pll || (diff >= -2000 && diff < 3000)) { goto out;
}
/* Try with PLL */
ret = nvbios_pll_parse(subdev->device->bios, pll, &limits); if (ret) return ret;
ret = gt215_clk_info(&clk->base, idx - 0x10, limits.refclk, info); if (ret != limits.refclk) return -EINVAL;
ret = gt215_pll_calc(subdev, &limits, khz, &N, NULL, &M, &P); if (ret >= 0) {
info->pll = (P << 16) | (N << 8) | M;
}
out:
info->fb_delay = max(((khz + 7566) / 15133), (u32) 18); return ret ? ret : -ERANGE;
}
staticint
calc_clk(struct gt215_clk *clk, struct nvkm_cstate *cstate, int idx, u32 pll, int dom)
{ int ret = gt215_pll_info(&clk->base, idx, pll, cstate->domain[dom],
&clk->eng[dom]); if (ret >= 0) return 0; return ret;
}
/* XXX: Should be reading the highest bit in the VBIOS clock to decide
* whether to use a PLL or not... but using a PLL defeats the purpose */ if (core->pll) {
ret = gt215_clk_info(&clk->base, 0x10,
cstate->domain[nv_clk_src_core_intm],
&clk->eng[nv_clk_src_core_intm]); if (ret < 0) return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.