1 /* 2 * Copyright 2013 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 #include "nv50.h" 25 26 #include <subdev/bios.h> 27 #include <subdev/bios/dcb.h> 28 #include <subdev/bios/disp.h> 29 #include <subdev/bios/init.h> 30 #include <subdev/bios/pll.h> 31 #include <subdev/clk/pll.h> 32 #include <subdev/vga.h> 33 34 int 35 nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) 36 { 37 struct nvkm_subdev *subdev = &init->subdev; 38 struct nvkm_device *device = subdev->device; 39 struct nvkm_bios *bios = device->bios; 40 struct nvbios_pll info; 41 int N1, M1, N2, M2, P; 42 int ret; 43 44 ret = nvbios_pll_parse(bios, type, &info); 45 if (ret) { 46 nvkm_error(subdev, "failed to retrieve pll data, %d\n", ret); 47 return ret; 48 } 49 50 ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); 51 if (!ret) { 52 nvkm_error(subdev, "failed pll calculation\n"); 53 return -EINVAL; 54 } 55 56 switch (info.type) { 57 case PLL_VPLL0: 58 case PLL_VPLL1: 59 nvkm_wr32(device, info.reg + 0, 0x10000611); 60 nvkm_mask(device, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); 61 nvkm_mask(device, info.reg + 8, 0x7fff00ff, (P << 28) | 62 (M2 << 16) | N2); 63 break; 64 case PLL_MEMORY: 65 nvkm_mask(device, info.reg + 0, 0x01ff0000, 66 (P << 22) | 67 (info.bias_p << 19) | 68 (P << 16)); 69 nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); 70 break; 71 default: 72 nvkm_mask(device, info.reg + 0, 0x00070000, (P << 16)); 73 nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); 74 break; 75 } 76 77 return 0; 78 } 79 80 static void 81 nv50_devinit_disable(struct nvkm_devinit *init) 82 { 83 struct nvkm_device *device = init->subdev.device; 84 u32 r001540 = nvkm_rd32(device, 0x001540); 85 86 if (!(r001540 & 0x40000000)) 87 nvkm_subdev_disable(device, NVKM_ENGINE_MPEG, 0); 88 } 89 90 void 91 nv50_devinit_preinit(struct nvkm_devinit *base) 92 { 93 struct nvkm_subdev *subdev = &base->subdev; 94 struct nvkm_device *device = subdev->device; 95 96 /* our heuristics can't detect whether the board has had its 97 * devinit scripts executed or not if the display engine is 98 * missing, assume it's a secondary gpu which requires post 99 */ 100 if (!base->post) { 101 nvkm_devinit_disable(base); 102 if (!device->disp) 103 base->post = true; 104 } 105 106 /* magic to detect whether or not x86 vbios code has executed 107 * the devinit scripts to initialise the board 108 */ 109 if (!base->post) { 110 if (!nvkm_rdvgac(device, 0, 0x00) && 111 !nvkm_rdvgac(device, 0, 0x1a)) { 112 nvkm_debug(subdev, "adaptor not initialised\n"); 113 base->post = true; 114 } 115 } 116 } 117 118 void 119 nv50_devinit_init(struct nvkm_devinit *base) 120 { 121 struct nv50_devinit *init = nv50_devinit(base); 122 struct nvkm_subdev *subdev = &init->base.subdev; 123 struct nvkm_device *device = subdev->device; 124 struct nvkm_bios *bios = device->bios; 125 struct nvbios_outp info; 126 struct dcb_output outp; 127 u8 ver = 0xff, hdr, cnt, len; 128 int i = 0; 129 130 /* if we ran the init tables, we have to execute the first script 131 * pointer of each dcb entry's display encoder table in order 132 * to properly initialise each encoder. 133 */ 134 while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { 135 if (nvbios_outp_match(bios, outp.hasht, outp.hashm, 136 &ver, &hdr, &cnt, &len, &info)) { 137 nvbios_init(subdev, info.script[0], 138 init.outp = &outp; 139 init.or = ffs(outp.or) - 1; 140 init.link = outp.sorconf.link == 2; 141 ); 142 } 143 i++; 144 } 145 } 146 147 int 148 nv50_devinit_new_(const struct nvkm_devinit_func *func, struct nvkm_device *device, 149 enum nvkm_subdev_type type, int inst, struct nvkm_devinit **pinit) 150 { 151 struct nv50_devinit *init; 152 153 if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) 154 return -ENOMEM; 155 *pinit = &init->base; 156 157 nvkm_devinit_ctor(func, device, type, inst, &init->base); 158 return 0; 159 } 160 161 static const struct nvkm_devinit_func 162 nv50_devinit = { 163 .preinit = nv50_devinit_preinit, 164 .init = nv50_devinit_init, 165 .post = nv04_devinit_post, 166 .pll_set = nv50_devinit_pll_set, 167 .disable = nv50_devinit_disable, 168 }; 169 170 int 171 nv50_devinit_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, 172 struct nvkm_devinit **pinit) 173 { 174 return nv50_devinit_new_(&nv50_devinit, device, type, inst, pinit); 175 } 176