1/* $NetBSD: nouveau_nvkm_subdev_pci_gk104.c,v 1.2 2021/12/18 23:45:41 riastradh Exp $ */ 2 3/* 4 * Copyright 2015 Karol Herbst <nouveau@karolherbst.de> 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: Karol Herbst <nouveau@karolherbst.de> 25 */ 26#include <sys/cdefs.h> 27__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_pci_gk104.c,v 1.2 2021/12/18 23:45:41 riastradh Exp $"); 28 29#include "priv.h" 30 31static int 32gk104_pcie_version_supported(struct nvkm_pci *pci) 33{ 34 return (nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x4) == 0x4 ? 2 : 1; 35} 36 37static void 38gk104_pcie_set_cap_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) 39{ 40 struct nvkm_device *device = pci->subdev.device; 41 42 switch (speed) { 43 case NVKM_PCIE_SPEED_2_5: 44 gf100_pcie_set_cap_speed(pci, false); 45 nvkm_mask(device, 0x8c1c0, 0x30000, 0x10000); 46 break; 47 case NVKM_PCIE_SPEED_5_0: 48 gf100_pcie_set_cap_speed(pci, true); 49 nvkm_mask(device, 0x8c1c0, 0x30000, 0x20000); 50 break; 51 case NVKM_PCIE_SPEED_8_0: 52 gf100_pcie_set_cap_speed(pci, true); 53 nvkm_mask(device, 0x8c1c0, 0x30000, 0x30000); 54 break; 55 } 56} 57 58static enum nvkm_pcie_speed 59gk104_pcie_cap_speed(struct nvkm_pci *pci) 60{ 61 int speed = gf100_pcie_cap_speed(pci); 62 63 if (speed == 0) 64 return NVKM_PCIE_SPEED_2_5; 65 66 if (speed >= 1) { 67 int speed2 = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x30000; 68 switch (speed2) { 69 case 0x00000: 70 case 0x10000: 71 return NVKM_PCIE_SPEED_2_5; 72 case 0x20000: 73 return NVKM_PCIE_SPEED_5_0; 74 case 0x30000: 75 return NVKM_PCIE_SPEED_8_0; 76 } 77 } 78 79 return -EINVAL; 80} 81 82static void 83gk104_pcie_set_lnkctl_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) 84{ 85 u8 reg_v = 0; 86 switch (speed) { 87 case NVKM_PCIE_SPEED_2_5: 88 reg_v = 1; 89 break; 90 case NVKM_PCIE_SPEED_5_0: 91 reg_v = 2; 92 break; 93 case NVKM_PCIE_SPEED_8_0: 94 reg_v = 3; 95 break; 96 } 97 nvkm_pci_mask(pci, 0xa8, 0x3, reg_v); 98} 99 100static enum nvkm_pcie_speed 101gk104_pcie_lnkctl_speed(struct nvkm_pci *pci) 102{ 103 u8 reg_v = nvkm_pci_rd32(pci, 0xa8) & 0x3; 104 switch (reg_v) { 105 case 0: 106 case 1: 107 return NVKM_PCIE_SPEED_2_5; 108 case 2: 109 return NVKM_PCIE_SPEED_5_0; 110 case 3: 111 return NVKM_PCIE_SPEED_8_0; 112 } 113 return -1; 114} 115 116static enum nvkm_pcie_speed 117gk104_pcie_max_speed(struct nvkm_pci *pci) 118{ 119 u32 max_speed = nvkm_rd32(pci->subdev.device, 0x8c1c0) & 0x300000; 120 switch (max_speed) { 121 case 0x000000: 122 return NVKM_PCIE_SPEED_8_0; 123 case 0x100000: 124 return NVKM_PCIE_SPEED_5_0; 125 case 0x200000: 126 return NVKM_PCIE_SPEED_2_5; 127 } 128 return NVKM_PCIE_SPEED_2_5; 129} 130 131static void 132gk104_pcie_set_link_speed(struct nvkm_pci *pci, enum nvkm_pcie_speed speed) 133{ 134 struct nvkm_device *device = pci->subdev.device; 135 u32 mask_value; 136 137 switch (speed) { 138 case NVKM_PCIE_SPEED_8_0: 139 mask_value = 0x00000; 140 break; 141 case NVKM_PCIE_SPEED_5_0: 142 mask_value = 0x40000; 143 break; 144 case NVKM_PCIE_SPEED_2_5: 145 default: 146 mask_value = 0x80000; 147 break; 148 } 149 150 nvkm_mask(device, 0x8c040, 0xc0000, mask_value); 151 nvkm_mask(device, 0x8c040, 0x1, 0x1); 152} 153 154static int 155gk104_pcie_init(struct nvkm_pci * pci) 156{ 157 enum nvkm_pcie_speed lnkctl_speed, max_speed, cap_speed; 158 struct nvkm_subdev *subdev = &pci->subdev; 159 160 if (gf100_pcie_version(pci) < 2) 161 return 0; 162 163 lnkctl_speed = gk104_pcie_lnkctl_speed(pci); 164 max_speed = gk104_pcie_max_speed(pci); 165 cap_speed = gk104_pcie_cap_speed(pci); 166 167 if (cap_speed != max_speed) { 168 nvkm_trace(subdev, "adjusting cap to max speed\n"); 169 gk104_pcie_set_cap_speed(pci, max_speed); 170 cap_speed = gk104_pcie_cap_speed(pci); 171 if (cap_speed != max_speed) 172 nvkm_warn(subdev, "failed to adjust cap speed\n"); 173 } 174 175 if (lnkctl_speed != max_speed) { 176 nvkm_debug(subdev, "adjusting lnkctl to max speed\n"); 177 gk104_pcie_set_lnkctl_speed(pci, max_speed); 178 lnkctl_speed = gk104_pcie_lnkctl_speed(pci); 179 if (lnkctl_speed != max_speed) 180 nvkm_error(subdev, "failed to adjust lnkctl speed\n"); 181 } 182 183 return 0; 184} 185 186static int 187gk104_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width) 188{ 189 struct nvkm_subdev *subdev = &pci->subdev; 190 enum nvkm_pcie_speed lnk_ctl_speed = gk104_pcie_lnkctl_speed(pci); 191 enum nvkm_pcie_speed lnk_cap_speed = gk104_pcie_cap_speed(pci); 192 193 if (speed > lnk_cap_speed) { 194 speed = lnk_cap_speed; 195 nvkm_warn(subdev, "dropping requested speed due too low cap" 196 " speed\n"); 197 } 198 199 if (speed > lnk_ctl_speed) { 200 speed = lnk_ctl_speed; 201 nvkm_warn(subdev, "dropping requested speed due too low" 202 " lnkctl speed\n"); 203 } 204 205 gk104_pcie_set_link_speed(pci, speed); 206 return 0; 207} 208 209 210static const struct nvkm_pci_func 211gk104_pci_func = { 212 .init = g84_pci_init, 213 .rd32 = nv40_pci_rd32, 214 .wr08 = nv40_pci_wr08, 215 .wr32 = nv40_pci_wr32, 216 .msi_rearm = nv40_pci_msi_rearm, 217 218 .pcie.init = gk104_pcie_init, 219 .pcie.set_link = gk104_pcie_set_link, 220 221 .pcie.max_speed = gk104_pcie_max_speed, 222 .pcie.cur_speed = g84_pcie_cur_speed, 223 224 .pcie.set_version = gf100_pcie_set_version, 225 .pcie.version = gf100_pcie_version, 226 .pcie.version_supported = gk104_pcie_version_supported, 227}; 228 229int 230gk104_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) 231{ 232 return nvkm_pci_new_(&gk104_pci_func, device, index, ppci); 233} 234