Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 #define nv40_clk(p) container_of((p), struct nv40_clk, base)
0025 #include "priv.h"
0026 #include "pll.h"
0027 
0028 #include <subdev/bios.h>
0029 #include <subdev/bios/pll.h>
0030 
0031 struct nv40_clk {
0032     struct nvkm_clk base;
0033     u32 ctrl;
0034     u32 npll_ctrl;
0035     u32 npll_coef;
0036     u32 spll;
0037 };
0038 
0039 static u32
0040 read_pll_1(struct nv40_clk *clk, u32 reg)
0041 {
0042     struct nvkm_device *device = clk->base.subdev.device;
0043     u32 ctrl = nvkm_rd32(device, reg + 0x00);
0044     int P = (ctrl & 0x00070000) >> 16;
0045     int N = (ctrl & 0x0000ff00) >> 8;
0046     int M = (ctrl & 0x000000ff) >> 0;
0047     u32 ref = 27000, khz = 0;
0048 
0049     if (ctrl & 0x80000000)
0050         khz = ref * N / M;
0051 
0052     return khz >> P;
0053 }
0054 
0055 static u32
0056 read_pll_2(struct nv40_clk *clk, u32 reg)
0057 {
0058     struct nvkm_device *device = clk->base.subdev.device;
0059     u32 ctrl = nvkm_rd32(device, reg + 0x00);
0060     u32 coef = nvkm_rd32(device, reg + 0x04);
0061     int N2 = (coef & 0xff000000) >> 24;
0062     int M2 = (coef & 0x00ff0000) >> 16;
0063     int N1 = (coef & 0x0000ff00) >> 8;
0064     int M1 = (coef & 0x000000ff) >> 0;
0065     int P = (ctrl & 0x00070000) >> 16;
0066     u32 ref = 27000, khz = 0;
0067 
0068     if ((ctrl & 0x80000000) && M1) {
0069         khz = ref * N1 / M1;
0070         if ((ctrl & 0x40000100) == 0x40000000) {
0071             if (M2)
0072                 khz = khz * N2 / M2;
0073             else
0074                 khz = 0;
0075         }
0076     }
0077 
0078     return khz >> P;
0079 }
0080 
0081 static u32
0082 read_clk(struct nv40_clk *clk, u32 src)
0083 {
0084     switch (src) {
0085     case 3:
0086         return read_pll_2(clk, 0x004000);
0087     case 2:
0088         return read_pll_1(clk, 0x004008);
0089     default:
0090         break;
0091     }
0092 
0093     return 0;
0094 }
0095 
0096 static int
0097 nv40_clk_read(struct nvkm_clk *base, enum nv_clk_src src)
0098 {
0099     struct nv40_clk *clk = nv40_clk(base);
0100     struct nvkm_subdev *subdev = &clk->base.subdev;
0101     struct nvkm_device *device = subdev->device;
0102     u32 mast = nvkm_rd32(device, 0x00c040);
0103 
0104     switch (src) {
0105     case nv_clk_src_crystal:
0106         return device->crystal;
0107     case nv_clk_src_href:
0108         return 100000; /*XXX: PCIE/AGP differ*/
0109     case nv_clk_src_core:
0110         return read_clk(clk, (mast & 0x00000003) >> 0);
0111     case nv_clk_src_shader:
0112         return read_clk(clk, (mast & 0x00000030) >> 4);
0113     case nv_clk_src_mem:
0114         return read_pll_2(clk, 0x4020);
0115     default:
0116         break;
0117     }
0118 
0119     nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast);
0120     return -EINVAL;
0121 }
0122 
0123 static int
0124 nv40_clk_calc_pll(struct nv40_clk *clk, u32 reg, u32 khz,
0125           int *N1, int *M1, int *N2, int *M2, int *log2P)
0126 {
0127     struct nvkm_subdev *subdev = &clk->base.subdev;
0128     struct nvbios_pll pll;
0129     int ret;
0130 
0131     ret = nvbios_pll_parse(subdev->device->bios, reg, &pll);
0132     if (ret)
0133         return ret;
0134 
0135     if (khz < pll.vco1.max_freq)
0136         pll.vco2.max_freq = 0;
0137 
0138     ret = nv04_pll_calc(subdev, &pll, khz, N1, M1, N2, M2, log2P);
0139     if (ret == 0)
0140         return -ERANGE;
0141 
0142     return ret;
0143 }
0144 
0145 static int
0146 nv40_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate)
0147 {
0148     struct nv40_clk *clk = nv40_clk(base);
0149     int gclk = cstate->domain[nv_clk_src_core];
0150     int sclk = cstate->domain[nv_clk_src_shader];
0151     int N1, M1, N2, M2, log2P;
0152     int ret;
0153 
0154     /* core/geometric clock */
0155     ret = nv40_clk_calc_pll(clk, 0x004000, gclk,
0156                 &N1, &M1, &N2, &M2, &log2P);
0157     if (ret < 0)
0158         return ret;
0159 
0160     if (N2 == M2) {
0161         clk->npll_ctrl = 0x80000100 | (log2P << 16);
0162         clk->npll_coef = (N1 << 8) | M1;
0163     } else {
0164         clk->npll_ctrl = 0xc0000000 | (log2P << 16);
0165         clk->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
0166     }
0167 
0168     /* use the second pll for shader/rop clock, if it differs from core */
0169     if (sclk && sclk != gclk) {
0170         ret = nv40_clk_calc_pll(clk, 0x004008, sclk,
0171                     &N1, &M1, NULL, NULL, &log2P);
0172         if (ret < 0)
0173             return ret;
0174 
0175         clk->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
0176         clk->ctrl = 0x00000223;
0177     } else {
0178         clk->spll = 0x00000000;
0179         clk->ctrl = 0x00000333;
0180     }
0181 
0182     return 0;
0183 }
0184 
0185 static int
0186 nv40_clk_prog(struct nvkm_clk *base)
0187 {
0188     struct nv40_clk *clk = nv40_clk(base);
0189     struct nvkm_device *device = clk->base.subdev.device;
0190     nvkm_mask(device, 0x00c040, 0x00000333, 0x00000000);
0191     nvkm_wr32(device, 0x004004, clk->npll_coef);
0192     nvkm_mask(device, 0x004000, 0xc0070100, clk->npll_ctrl);
0193     nvkm_mask(device, 0x004008, 0xc007ffff, clk->spll);
0194     mdelay(5);
0195     nvkm_mask(device, 0x00c040, 0x00000333, clk->ctrl);
0196     return 0;
0197 }
0198 
0199 static void
0200 nv40_clk_tidy(struct nvkm_clk *obj)
0201 {
0202 }
0203 
0204 static const struct nvkm_clk_func
0205 nv40_clk = {
0206     .read = nv40_clk_read,
0207     .calc = nv40_clk_calc,
0208     .prog = nv40_clk_prog,
0209     .tidy = nv40_clk_tidy,
0210     .domains = {
0211         { nv_clk_src_crystal, 0xff },
0212         { nv_clk_src_href   , 0xff },
0213         { nv_clk_src_core   , 0xff, 0, "core", 1000 },
0214         { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
0215         { nv_clk_src_mem    , 0xff, 0, "memory", 1000 },
0216         { nv_clk_src_max }
0217     }
0218 };
0219 
0220 int
0221 nv40_clk_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
0222          struct nvkm_clk **pclk)
0223 {
0224     struct nv40_clk *clk;
0225 
0226     if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL)))
0227         return -ENOMEM;
0228     clk->base.pll_calc = nv04_clk_pll_calc;
0229     clk->base.pll_prog = nv04_clk_pll_prog;
0230     *pclk = &clk->base;
0231 
0232     return nvkm_clk_ctor(&nv40_clk, device, type, inst, true, &clk->base);
0233 }