drm/nvc0/gr: calculate some more of our magic numbers
[linux-2.6-block.git] / drivers / gpu / drm / nouveau / nva3_pm.c
CommitLineData
fade7ad5
BS
1/*
2 * Copyright 2010 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 "drmP.h"
26#include "nouveau_drv.h"
27#include "nouveau_bios.h"
28#include "nouveau_pm.h"
29
215f902e
BS
30/* This is actually a lot more complex than it appears here, but hopefully
31 * this should be able to deal with what the VBIOS leaves for us..
32 *
33 * If not, well, I'll jump off that bridge when I come to it.
fade7ad5
BS
34 */
35
36struct nva3_pm_state {
37 struct pll_lims pll;
38 int N, M, P;
39};
40
215f902e
BS
41static int
42nva3_pm_pll_offset(u32 id)
43{
44 static const u32 pll_map[] = {
45 0x00, PLL_CORE,
46 0x01, PLL_SHADER,
47 0x02, PLL_MEMORY,
48 0x00, 0x00
49 };
50 const u32 *map = pll_map;
51
52 while (map[1]) {
53 if (id == map[1])
54 return map[0];
55 map += 2;
56 }
57
58 return -ENOENT;
59}
60
fade7ad5
BS
61int
62nva3_pm_clock_get(struct drm_device *dev, u32 id)
63{
215f902e 64 u32 src0, src1, ctrl, coef;
fade7ad5 65 struct pll_lims pll;
215f902e
BS
66 int ret, off;
67 int P, N, M;
fade7ad5
BS
68
69 ret = get_pll_limits(dev, id, &pll);
70 if (ret)
71 return ret;
72
215f902e
BS
73 off = nva3_pm_pll_offset(id);
74 if (off < 0)
75 return off;
76
77 src0 = nv_rd32(dev, 0x4120 + (off * 4));
78 src1 = nv_rd32(dev, 0x4160 + (off * 4));
79 ctrl = nv_rd32(dev, pll.reg + 0);
80 coef = nv_rd32(dev, pll.reg + 4);
81 NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
82 id, src0, src1, ctrl, coef);
83
84 if (ctrl & 0x00000008) {
85 u32 div = ((src1 & 0x003c0000) >> 18) + 1;
86 return (pll.refclk * 2) / div;
87 }
88
89 P = (coef & 0x003f0000) >> 16;
90 N = (coef & 0x0000ff00) >> 8;
91 M = (coef & 0x000000ff);
fade7ad5
BS
92 return pll.refclk * N / M / P;
93}
94
95void *
96nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
97 u32 id, int khz)
98{
99 struct nva3_pm_state *state;
100 int dummy, ret;
101
102 state = kzalloc(sizeof(*state), GFP_KERNEL);
103 if (!state)
104 return ERR_PTR(-ENOMEM);
105
106 ret = get_pll_limits(dev, id, &state->pll);
107 if (ret < 0) {
108 kfree(state);
109 return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
110 }
111
112 ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
113 &state->M, &state->P);
114 if (ret < 0) {
115 kfree(state);
116 return ERR_PTR(ret);
117 }
118
119 return state;
120}
121
122void
123nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
124{
125 struct nva3_pm_state *state = pre_state;
126 u32 reg = state->pll.reg;
127
128 nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
129 kfree(state);
130}
131