1 /* $NetBSD: nouveau_nvkm_subdev_devinit_nv50.c,v 1.3 2021/12/18 23:45:39 riastradh Exp $ */ 2 3 /* 4 * Copyright 2013 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Ben Skeggs 25 */ 26 #include <sys/cdefs.h> 27 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_devinit_nv50.c,v 1.3 2021/12/18 23:45:39 riastradh Exp $"); 28 29 #include "nv50.h" 30 31 #include <subdev/bios.h> 32 #include <subdev/bios/dcb.h> 33 #include <subdev/bios/disp.h> 34 #include <subdev/bios/init.h> 35 #include <subdev/bios/pll.h> 36 #include <subdev/clk/pll.h> 37 #include <subdev/vga.h> 38 39 int 40 nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) 41 { 42 struct nvkm_subdev *subdev = &init->subdev; 43 struct nvkm_device *device = subdev->device; 44 struct nvkm_bios *bios = device->bios; 45 struct nvbios_pll info; 46 int N1, M1, N2, M2, P; 47 int ret; 48 49 ret = nvbios_pll_parse(bios, type, &info); 50 if (ret) { 51 nvkm_error(subdev, "failed to retrieve pll data, %d\n", ret); 52 return ret; 53 } 54 55 ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); 56 if (!ret) { 57 nvkm_error(subdev, "failed pll calculation\n"); 58 return -EINVAL; 59 } 60 61 switch (info.type) { 62 case PLL_VPLL0: 63 case PLL_VPLL1: 64 nvkm_wr32(device, info.reg + 0, 0x10000611); 65 nvkm_mask(device, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); 66 nvkm_mask(device, info.reg + 8, 0x7fff00ff, (P << 28) | 67 (M2 << 16) | N2); 68 break; 69 case PLL_MEMORY: 70 nvkm_mask(device, info.reg + 0, 0x01ff0000, 71 (P << 22) | 72 (info.bias_p << 19) | 73 (P << 16)); 74 nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); 75 break; 76 default: 77 nvkm_mask(device, info.reg + 0, 0x00070000, (P << 16)); 78 nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); 79 break; 80 } 81 82 return 0; 83 } 84 85 static u64 86 nv50_devinit_disable(struct nvkm_devinit *init) 87 { 88 struct nvkm_device *device = init->subdev.device; 89 u32 r001540 = nvkm_rd32(device, 0x001540); 90 u64 disable = 0ULL; 91 92 if (!(r001540 & 0x40000000)) 93 disable |= (1ULL << NVKM_ENGINE_MPEG); 94 95 return disable; 96 } 97 98 void 99 nv50_devinit_preinit(struct nvkm_devinit *base) 100 { 101 struct nvkm_subdev *subdev = &base->subdev; 102 struct nvkm_device *device = subdev->device; 103 104 /* our heuristics can't detect whether the board has had its 105 * devinit scripts executed or not if the display engine is 106 * missing, assume it's a secondary gpu which requires post 107 */ 108 if (!base->post) { 109 u64 disable = nvkm_devinit_disable(base); 110 if (disable & (1ULL << NVKM_ENGINE_DISP)) 111 base->post = true; 112 } 113 114 /* magic to detect whether or not x86 vbios code has executed 115 * the devinit scripts to initialise the board 116 */ 117 if (!base->post) { 118 if (!nvkm_rdvgac(device, 0, 0x00) && 119 !nvkm_rdvgac(device, 0, 0x1a)) { 120 nvkm_debug(subdev, "adaptor not initialised\n"); 121 base->post = true; 122 } 123 } 124 } 125 126 void 127 nv50_devinit_init(struct nvkm_devinit *base) 128 { 129 struct nv50_devinit *init = nv50_devinit(base); 130 struct nvkm_subdev *subdev = &init->base.subdev; 131 struct nvkm_device *device = subdev->device; 132 struct nvkm_bios *bios = device->bios; 133 struct nvbios_outp info; 134 struct dcb_output outp; 135 u8 ver = 0xff, hdr, cnt, len; 136 int i = 0; 137 138 /* if we ran the init tables, we have to execute the first script 139 * pointer of each dcb entry's display encoder table in order 140 * to properly initialise each encoder. 141 */ 142 while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { 143 if (nvbios_outp_match(bios, outp.hasht, outp.hashm, 144 &ver, &hdr, &cnt, &len, &info)) { 145 nvbios_init(subdev, info.script[0], 146 init.outp = &outp; 147 init.or = ffs(outp.or) - 1; 148 init.link = outp.sorconf.link == 2; 149 ); 150 } 151 i++; 152 } 153 } 154 155 int 156 nv50_devinit_new_(const struct nvkm_devinit_func *func, 157 struct nvkm_device *device, int index, 158 struct nvkm_devinit **pinit) 159 { 160 struct nv50_devinit *init; 161 162 if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) 163 return -ENOMEM; 164 *pinit = &init->base; 165 166 nvkm_devinit_ctor(func, device, index, &init->base); 167 return 0; 168 } 169 170 static const struct nvkm_devinit_func 171 nv50_devinit = { 172 .preinit = nv50_devinit_preinit, 173 .init = nv50_devinit_init, 174 .post = nv04_devinit_post, 175 .pll_set = nv50_devinit_pll_set, 176 .disable = nv50_devinit_disable, 177 }; 178 179 int 180 nv50_devinit_new(struct nvkm_device *device, int index, 181 struct nvkm_devinit **pinit) 182 { 183 return nv50_devinit_new_(&nv50_devinit, device, index, pinit); 184 } 185