1 1.3 riastrad /* $NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2011 Advanced Micro Devices, Inc. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice shall be included in 14 1.1 riastrad * all copies or substantial portions of the Software. 15 1.1 riastrad * 16 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 1.1 riastrad * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 1.1 riastrad * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 1.1 riastrad * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 1.1 riastrad * OTHER DEALINGS IN THE SOFTWARE. 23 1.1 riastrad * 24 1.1 riastrad * Authors: Alex Deucher 25 1.1 riastrad */ 26 1.1 riastrad 27 1.1 riastrad #include <sys/cdefs.h> 28 1.3 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_rv770_smc.c,v 1.3 2021/12/18 23:45:43 riastradh Exp $"); 29 1.1 riastrad 30 1.1 riastrad #include <linux/firmware.h> 31 1.3 riastrad 32 1.1 riastrad #include "radeon.h" 33 1.1 riastrad #include "rv770d.h" 34 1.1 riastrad #include "rv770_dpm.h" 35 1.1 riastrad #include "rv770_smc.h" 36 1.1 riastrad #include "atom.h" 37 1.1 riastrad #include "radeon_ucode.h" 38 1.1 riastrad 39 1.1 riastrad #define FIRST_SMC_INT_VECT_REG 0xFFD8 40 1.1 riastrad #define FIRST_INT_VECT_S19 0xFFC0 41 1.1 riastrad 42 1.1 riastrad static const u8 rv770_smc_int_vectors[] = 43 1.1 riastrad { 44 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 45 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 46 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 47 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 48 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 49 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 50 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 51 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 52 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 53 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 54 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 55 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 56 1.1 riastrad 0x08, 0x10, 0x0C, 0xD7, 57 1.1 riastrad 0x08, 0x2B, 0x08, 0x10, 58 1.1 riastrad 0x03, 0x51, 0x03, 0x51, 59 1.1 riastrad 0x03, 0x51, 0x03, 0x51 60 1.1 riastrad }; 61 1.1 riastrad 62 1.1 riastrad static const u8 rv730_smc_int_vectors[] = 63 1.1 riastrad { 64 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 65 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 66 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 67 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 68 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 69 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 70 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 71 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 72 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 73 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 74 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 75 1.1 riastrad 0x08, 0x15, 0x08, 0x15, 76 1.1 riastrad 0x08, 0x15, 0x0C, 0xBB, 77 1.1 riastrad 0x08, 0x30, 0x08, 0x15, 78 1.1 riastrad 0x03, 0x56, 0x03, 0x56, 79 1.1 riastrad 0x03, 0x56, 0x03, 0x56 80 1.1 riastrad }; 81 1.1 riastrad 82 1.1 riastrad static const u8 rv710_smc_int_vectors[] = 83 1.1 riastrad { 84 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 85 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 86 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 87 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 88 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 89 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 90 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 91 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 92 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 93 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 94 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 95 1.1 riastrad 0x08, 0x04, 0x08, 0x04, 96 1.1 riastrad 0x08, 0x04, 0x0C, 0xCB, 97 1.1 riastrad 0x08, 0x1F, 0x08, 0x04, 98 1.1 riastrad 0x03, 0x51, 0x03, 0x51, 99 1.1 riastrad 0x03, 0x51, 0x03, 0x51 100 1.1 riastrad }; 101 1.1 riastrad 102 1.1 riastrad static const u8 rv740_smc_int_vectors[] = 103 1.1 riastrad { 104 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 105 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 106 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 107 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 108 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 109 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 110 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 111 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 112 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 113 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 114 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 115 1.1 riastrad 0x08, 0x10, 0x08, 0x10, 116 1.1 riastrad 0x08, 0x10, 0x0C, 0xD7, 117 1.1 riastrad 0x08, 0x2B, 0x08, 0x10, 118 1.1 riastrad 0x03, 0x51, 0x03, 0x51, 119 1.1 riastrad 0x03, 0x51, 0x03, 0x51 120 1.1 riastrad }; 121 1.1 riastrad 122 1.1 riastrad static const u8 cedar_smc_int_vectors[] = 123 1.1 riastrad { 124 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 125 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 126 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 127 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 128 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 129 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 130 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 131 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 132 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 133 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 134 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 135 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 136 1.1 riastrad 0x0B, 0x05, 0x11, 0x8B, 137 1.1 riastrad 0x0B, 0x20, 0x0B, 0x05, 138 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6, 139 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6 140 1.1 riastrad }; 141 1.1 riastrad 142 1.1 riastrad static const u8 redwood_smc_int_vectors[] = 143 1.1 riastrad { 144 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 145 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 146 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 147 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 148 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 149 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 150 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 151 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 152 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 153 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 154 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 155 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 156 1.1 riastrad 0x0B, 0x05, 0x11, 0x8B, 157 1.1 riastrad 0x0B, 0x20, 0x0B, 0x05, 158 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6, 159 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6 160 1.1 riastrad }; 161 1.1 riastrad 162 1.1 riastrad static const u8 juniper_smc_int_vectors[] = 163 1.1 riastrad { 164 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 165 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 166 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 167 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 168 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 169 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 170 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 171 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 172 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 173 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 174 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 175 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 176 1.1 riastrad 0x0B, 0x05, 0x11, 0x8B, 177 1.1 riastrad 0x0B, 0x20, 0x0B, 0x05, 178 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6, 179 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6 180 1.1 riastrad }; 181 1.1 riastrad 182 1.1 riastrad static const u8 cypress_smc_int_vectors[] = 183 1.1 riastrad { 184 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 185 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 186 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 187 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 188 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 189 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 190 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 191 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 192 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 193 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 194 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 195 1.1 riastrad 0x0B, 0x05, 0x0B, 0x05, 196 1.1 riastrad 0x0B, 0x05, 0x11, 0x8B, 197 1.1 riastrad 0x0B, 0x20, 0x0B, 0x05, 198 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6, 199 1.1 riastrad 0x04, 0xF6, 0x04, 0xF6 200 1.1 riastrad }; 201 1.1 riastrad 202 1.1 riastrad static const u8 barts_smc_int_vectors[] = 203 1.1 riastrad { 204 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 205 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 206 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 207 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 208 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 209 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 210 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 211 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 212 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 213 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 214 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 215 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 216 1.1 riastrad 0x0C, 0x14, 0x12, 0xAA, 217 1.1 riastrad 0x0C, 0x2F, 0x15, 0xF6, 218 1.1 riastrad 0x15, 0xF6, 0x05, 0x0A, 219 1.1 riastrad 0x05, 0x0A, 0x05, 0x0A 220 1.1 riastrad }; 221 1.1 riastrad 222 1.1 riastrad static const u8 turks_smc_int_vectors[] = 223 1.1 riastrad { 224 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 225 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 226 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 227 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 228 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 229 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 230 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 231 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 232 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 233 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 234 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 235 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 236 1.1 riastrad 0x0C, 0x14, 0x12, 0xAA, 237 1.1 riastrad 0x0C, 0x2F, 0x15, 0xF6, 238 1.1 riastrad 0x15, 0xF6, 0x05, 0x0A, 239 1.1 riastrad 0x05, 0x0A, 0x05, 0x0A 240 1.1 riastrad }; 241 1.1 riastrad 242 1.1 riastrad static const u8 caicos_smc_int_vectors[] = 243 1.1 riastrad { 244 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 245 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 246 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 247 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 248 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 249 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 250 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 251 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 252 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 253 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 254 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 255 1.1 riastrad 0x0C, 0x14, 0x0C, 0x14, 256 1.1 riastrad 0x0C, 0x14, 0x12, 0xAA, 257 1.1 riastrad 0x0C, 0x2F, 0x15, 0xF6, 258 1.1 riastrad 0x15, 0xF6, 0x05, 0x0A, 259 1.1 riastrad 0x05, 0x0A, 0x05, 0x0A 260 1.1 riastrad }; 261 1.1 riastrad 262 1.1 riastrad static const u8 cayman_smc_int_vectors[] = 263 1.1 riastrad { 264 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 265 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 266 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 267 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 268 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 269 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 270 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 271 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 272 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 273 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 274 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 275 1.1 riastrad 0x12, 0x05, 0x12, 0x05, 276 1.1 riastrad 0x12, 0x05, 0x18, 0xEA, 277 1.1 riastrad 0x12, 0x20, 0x1C, 0x34, 278 1.1 riastrad 0x1C, 0x34, 0x08, 0x72, 279 1.1 riastrad 0x08, 0x72, 0x08, 0x72 280 1.1 riastrad }; 281 1.1 riastrad 282 1.1 riastrad static int rv770_set_smc_sram_address(struct radeon_device *rdev, 283 1.1 riastrad u16 smc_address, u16 limit) 284 1.1 riastrad { 285 1.1 riastrad u32 addr; 286 1.1 riastrad 287 1.1 riastrad if (smc_address & 3) 288 1.1 riastrad return -EINVAL; 289 1.1 riastrad if ((smc_address + 3) > limit) 290 1.1 riastrad return -EINVAL; 291 1.1 riastrad 292 1.1 riastrad addr = smc_address; 293 1.1 riastrad addr |= SMC_SRAM_AUTO_INC_DIS; 294 1.1 riastrad 295 1.1 riastrad WREG32(SMC_SRAM_ADDR, addr); 296 1.1 riastrad 297 1.1 riastrad return 0; 298 1.1 riastrad } 299 1.1 riastrad 300 1.1 riastrad int rv770_copy_bytes_to_smc(struct radeon_device *rdev, 301 1.1 riastrad u16 smc_start_address, const u8 *src, 302 1.1 riastrad u16 byte_count, u16 limit) 303 1.1 riastrad { 304 1.1 riastrad unsigned long flags; 305 1.1 riastrad u32 data, original_data, extra_shift; 306 1.1 riastrad u16 addr; 307 1.1 riastrad int ret = 0; 308 1.1 riastrad 309 1.1 riastrad if (smc_start_address & 3) 310 1.1 riastrad return -EINVAL; 311 1.1 riastrad if ((smc_start_address + byte_count) > limit) 312 1.1 riastrad return -EINVAL; 313 1.1 riastrad 314 1.1 riastrad addr = smc_start_address; 315 1.1 riastrad 316 1.1 riastrad spin_lock_irqsave(&rdev->smc_idx_lock, flags); 317 1.1 riastrad while (byte_count >= 4) { 318 1.1 riastrad /* SMC address space is BE */ 319 1.2 msaitoh data = ((u32)src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3]; 320 1.1 riastrad 321 1.1 riastrad ret = rv770_set_smc_sram_address(rdev, addr, limit); 322 1.1 riastrad if (ret) 323 1.1 riastrad goto done; 324 1.1 riastrad 325 1.1 riastrad WREG32(SMC_SRAM_DATA, data); 326 1.1 riastrad 327 1.1 riastrad src += 4; 328 1.1 riastrad byte_count -= 4; 329 1.1 riastrad addr += 4; 330 1.1 riastrad } 331 1.1 riastrad 332 1.1 riastrad /* RMW for final bytes */ 333 1.1 riastrad if (byte_count > 0) { 334 1.1 riastrad data = 0; 335 1.1 riastrad 336 1.1 riastrad ret = rv770_set_smc_sram_address(rdev, addr, limit); 337 1.1 riastrad if (ret) 338 1.1 riastrad goto done; 339 1.1 riastrad 340 1.1 riastrad original_data = RREG32(SMC_SRAM_DATA); 341 1.1 riastrad 342 1.1 riastrad extra_shift = 8 * (4 - byte_count); 343 1.1 riastrad 344 1.1 riastrad while (byte_count > 0) { 345 1.1 riastrad /* SMC address space is BE */ 346 1.1 riastrad data = (data << 8) + *src++; 347 1.1 riastrad byte_count--; 348 1.1 riastrad } 349 1.1 riastrad 350 1.1 riastrad data <<= extra_shift; 351 1.1 riastrad 352 1.1 riastrad data |= (original_data & ~((~0UL) << extra_shift)); 353 1.1 riastrad 354 1.1 riastrad ret = rv770_set_smc_sram_address(rdev, addr, limit); 355 1.1 riastrad if (ret) 356 1.1 riastrad goto done; 357 1.1 riastrad 358 1.1 riastrad WREG32(SMC_SRAM_DATA, data); 359 1.1 riastrad } 360 1.1 riastrad 361 1.1 riastrad done: 362 1.1 riastrad spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 363 1.1 riastrad 364 1.1 riastrad return ret; 365 1.1 riastrad } 366 1.1 riastrad 367 1.1 riastrad static int rv770_program_interrupt_vectors(struct radeon_device *rdev, 368 1.1 riastrad u32 smc_first_vector, const u8 *src, 369 1.1 riastrad u32 byte_count) 370 1.1 riastrad { 371 1.1 riastrad u32 tmp, i; 372 1.1 riastrad 373 1.1 riastrad if (byte_count % 4) 374 1.1 riastrad return -EINVAL; 375 1.1 riastrad 376 1.1 riastrad if (smc_first_vector < FIRST_SMC_INT_VECT_REG) { 377 1.1 riastrad tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector; 378 1.1 riastrad 379 1.1 riastrad if (tmp > byte_count) 380 1.1 riastrad return 0; 381 1.1 riastrad 382 1.1 riastrad byte_count -= tmp; 383 1.1 riastrad src += tmp; 384 1.1 riastrad smc_first_vector = FIRST_SMC_INT_VECT_REG; 385 1.1 riastrad } 386 1.1 riastrad 387 1.1 riastrad for (i = 0; i < byte_count; i += 4) { 388 1.1 riastrad /* SMC address space is BE */ 389 1.1 riastrad tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3]; 390 1.1 riastrad 391 1.1 riastrad WREG32(SMC_ISR_FFD8_FFDB + i, tmp); 392 1.1 riastrad } 393 1.1 riastrad 394 1.1 riastrad return 0; 395 1.1 riastrad } 396 1.1 riastrad 397 1.1 riastrad void rv770_start_smc(struct radeon_device *rdev) 398 1.1 riastrad { 399 1.1 riastrad WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N); 400 1.1 riastrad } 401 1.1 riastrad 402 1.1 riastrad void rv770_reset_smc(struct radeon_device *rdev) 403 1.1 riastrad { 404 1.1 riastrad WREG32_P(SMC_IO, 0, ~SMC_RST_N); 405 1.1 riastrad } 406 1.1 riastrad 407 1.1 riastrad void rv770_stop_smc_clock(struct radeon_device *rdev) 408 1.1 riastrad { 409 1.1 riastrad WREG32_P(SMC_IO, 0, ~SMC_CLK_EN); 410 1.1 riastrad } 411 1.1 riastrad 412 1.1 riastrad void rv770_start_smc_clock(struct radeon_device *rdev) 413 1.1 riastrad { 414 1.1 riastrad WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN); 415 1.1 riastrad } 416 1.1 riastrad 417 1.1 riastrad bool rv770_is_smc_running(struct radeon_device *rdev) 418 1.1 riastrad { 419 1.1 riastrad u32 tmp; 420 1.1 riastrad 421 1.1 riastrad tmp = RREG32(SMC_IO); 422 1.1 riastrad 423 1.1 riastrad if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN)) 424 1.1 riastrad return true; 425 1.1 riastrad else 426 1.1 riastrad return false; 427 1.1 riastrad } 428 1.1 riastrad 429 1.1 riastrad PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg) 430 1.1 riastrad { 431 1.1 riastrad u32 tmp; 432 1.1 riastrad int i; 433 1.1 riastrad PPSMC_Result result; 434 1.1 riastrad 435 1.1 riastrad if (!rv770_is_smc_running(rdev)) 436 1.1 riastrad return PPSMC_Result_Failed; 437 1.1 riastrad 438 1.1 riastrad WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK); 439 1.1 riastrad 440 1.1 riastrad for (i = 0; i < rdev->usec_timeout; i++) { 441 1.1 riastrad tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 442 1.1 riastrad tmp >>= HOST_SMC_RESP_SHIFT; 443 1.1 riastrad if (tmp != 0) 444 1.1 riastrad break; 445 1.1 riastrad udelay(1); 446 1.1 riastrad } 447 1.1 riastrad 448 1.1 riastrad tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK; 449 1.1 riastrad tmp >>= HOST_SMC_RESP_SHIFT; 450 1.1 riastrad 451 1.1 riastrad result = (PPSMC_Result)tmp; 452 1.1 riastrad return result; 453 1.1 riastrad } 454 1.1 riastrad 455 1.1 riastrad PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev) 456 1.1 riastrad { 457 1.1 riastrad int i; 458 1.1 riastrad PPSMC_Result result = PPSMC_Result_OK; 459 1.1 riastrad 460 1.1 riastrad if (!rv770_is_smc_running(rdev)) 461 1.1 riastrad return result; 462 1.1 riastrad 463 1.1 riastrad for (i = 0; i < rdev->usec_timeout; i++) { 464 1.1 riastrad if (RREG32(SMC_IO) & SMC_STOP_MODE) 465 1.1 riastrad break; 466 1.1 riastrad udelay(1); 467 1.1 riastrad } 468 1.1 riastrad 469 1.1 riastrad return result; 470 1.1 riastrad } 471 1.1 riastrad 472 1.1 riastrad static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit) 473 1.1 riastrad { 474 1.1 riastrad unsigned long flags; 475 1.1 riastrad u16 i; 476 1.1 riastrad 477 1.1 riastrad spin_lock_irqsave(&rdev->smc_idx_lock, flags); 478 1.1 riastrad for (i = 0; i < limit; i += 4) { 479 1.1 riastrad rv770_set_smc_sram_address(rdev, i, limit); 480 1.1 riastrad WREG32(SMC_SRAM_DATA, 0); 481 1.1 riastrad } 482 1.1 riastrad spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 483 1.1 riastrad } 484 1.1 riastrad 485 1.1 riastrad int rv770_load_smc_ucode(struct radeon_device *rdev, 486 1.1 riastrad u16 limit) 487 1.1 riastrad { 488 1.1 riastrad int ret; 489 1.1 riastrad const u8 *int_vect; 490 1.1 riastrad u16 int_vect_start_address; 491 1.1 riastrad u16 int_vect_size; 492 1.1 riastrad const u8 *ucode_data; 493 1.1 riastrad u16 ucode_start_address; 494 1.1 riastrad u16 ucode_size; 495 1.1 riastrad 496 1.1 riastrad if (!rdev->smc_fw) 497 1.1 riastrad return -EINVAL; 498 1.1 riastrad 499 1.1 riastrad rv770_clear_smc_sram(rdev, limit); 500 1.1 riastrad 501 1.1 riastrad switch (rdev->family) { 502 1.1 riastrad case CHIP_RV770: 503 1.1 riastrad ucode_start_address = RV770_SMC_UCODE_START; 504 1.1 riastrad ucode_size = RV770_SMC_UCODE_SIZE; 505 1.1 riastrad int_vect = (const u8 *)&rv770_smc_int_vectors; 506 1.1 riastrad int_vect_start_address = RV770_SMC_INT_VECTOR_START; 507 1.1 riastrad int_vect_size = RV770_SMC_INT_VECTOR_SIZE; 508 1.1 riastrad break; 509 1.1 riastrad case CHIP_RV730: 510 1.1 riastrad ucode_start_address = RV730_SMC_UCODE_START; 511 1.1 riastrad ucode_size = RV730_SMC_UCODE_SIZE; 512 1.1 riastrad int_vect = (const u8 *)&rv730_smc_int_vectors; 513 1.1 riastrad int_vect_start_address = RV730_SMC_INT_VECTOR_START; 514 1.1 riastrad int_vect_size = RV730_SMC_INT_VECTOR_SIZE; 515 1.1 riastrad break; 516 1.1 riastrad case CHIP_RV710: 517 1.1 riastrad ucode_start_address = RV710_SMC_UCODE_START; 518 1.1 riastrad ucode_size = RV710_SMC_UCODE_SIZE; 519 1.1 riastrad int_vect = (const u8 *)&rv710_smc_int_vectors; 520 1.1 riastrad int_vect_start_address = RV710_SMC_INT_VECTOR_START; 521 1.1 riastrad int_vect_size = RV710_SMC_INT_VECTOR_SIZE; 522 1.1 riastrad break; 523 1.1 riastrad case CHIP_RV740: 524 1.1 riastrad ucode_start_address = RV740_SMC_UCODE_START; 525 1.1 riastrad ucode_size = RV740_SMC_UCODE_SIZE; 526 1.1 riastrad int_vect = (const u8 *)&rv740_smc_int_vectors; 527 1.1 riastrad int_vect_start_address = RV740_SMC_INT_VECTOR_START; 528 1.1 riastrad int_vect_size = RV740_SMC_INT_VECTOR_SIZE; 529 1.1 riastrad break; 530 1.1 riastrad case CHIP_CEDAR: 531 1.1 riastrad ucode_start_address = CEDAR_SMC_UCODE_START; 532 1.1 riastrad ucode_size = CEDAR_SMC_UCODE_SIZE; 533 1.1 riastrad int_vect = (const u8 *)&cedar_smc_int_vectors; 534 1.1 riastrad int_vect_start_address = CEDAR_SMC_INT_VECTOR_START; 535 1.1 riastrad int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE; 536 1.1 riastrad break; 537 1.1 riastrad case CHIP_REDWOOD: 538 1.1 riastrad ucode_start_address = REDWOOD_SMC_UCODE_START; 539 1.1 riastrad ucode_size = REDWOOD_SMC_UCODE_SIZE; 540 1.1 riastrad int_vect = (const u8 *)&redwood_smc_int_vectors; 541 1.1 riastrad int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START; 542 1.1 riastrad int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE; 543 1.1 riastrad break; 544 1.1 riastrad case CHIP_JUNIPER: 545 1.1 riastrad ucode_start_address = JUNIPER_SMC_UCODE_START; 546 1.1 riastrad ucode_size = JUNIPER_SMC_UCODE_SIZE; 547 1.1 riastrad int_vect = (const u8 *)&juniper_smc_int_vectors; 548 1.1 riastrad int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START; 549 1.1 riastrad int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE; 550 1.1 riastrad break; 551 1.1 riastrad case CHIP_CYPRESS: 552 1.1 riastrad case CHIP_HEMLOCK: 553 1.1 riastrad ucode_start_address = CYPRESS_SMC_UCODE_START; 554 1.1 riastrad ucode_size = CYPRESS_SMC_UCODE_SIZE; 555 1.1 riastrad int_vect = (const u8 *)&cypress_smc_int_vectors; 556 1.1 riastrad int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START; 557 1.1 riastrad int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE; 558 1.1 riastrad break; 559 1.1 riastrad case CHIP_BARTS: 560 1.1 riastrad ucode_start_address = BARTS_SMC_UCODE_START; 561 1.1 riastrad ucode_size = BARTS_SMC_UCODE_SIZE; 562 1.1 riastrad int_vect = (const u8 *)&barts_smc_int_vectors; 563 1.1 riastrad int_vect_start_address = BARTS_SMC_INT_VECTOR_START; 564 1.1 riastrad int_vect_size = BARTS_SMC_INT_VECTOR_SIZE; 565 1.1 riastrad break; 566 1.1 riastrad case CHIP_TURKS: 567 1.1 riastrad ucode_start_address = TURKS_SMC_UCODE_START; 568 1.1 riastrad ucode_size = TURKS_SMC_UCODE_SIZE; 569 1.1 riastrad int_vect = (const u8 *)&turks_smc_int_vectors; 570 1.1 riastrad int_vect_start_address = TURKS_SMC_INT_VECTOR_START; 571 1.1 riastrad int_vect_size = TURKS_SMC_INT_VECTOR_SIZE; 572 1.1 riastrad break; 573 1.1 riastrad case CHIP_CAICOS: 574 1.1 riastrad ucode_start_address = CAICOS_SMC_UCODE_START; 575 1.1 riastrad ucode_size = CAICOS_SMC_UCODE_SIZE; 576 1.1 riastrad int_vect = (const u8 *)&caicos_smc_int_vectors; 577 1.1 riastrad int_vect_start_address = CAICOS_SMC_INT_VECTOR_START; 578 1.1 riastrad int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE; 579 1.1 riastrad break; 580 1.1 riastrad case CHIP_CAYMAN: 581 1.1 riastrad ucode_start_address = CAYMAN_SMC_UCODE_START; 582 1.1 riastrad ucode_size = CAYMAN_SMC_UCODE_SIZE; 583 1.1 riastrad int_vect = (const u8 *)&cayman_smc_int_vectors; 584 1.1 riastrad int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START; 585 1.1 riastrad int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE; 586 1.1 riastrad break; 587 1.1 riastrad default: 588 1.1 riastrad DRM_ERROR("unknown asic in smc ucode loader\n"); 589 1.1 riastrad BUG(); 590 1.1 riastrad } 591 1.1 riastrad 592 1.1 riastrad /* load the ucode */ 593 1.1 riastrad ucode_data = (const u8 *)rdev->smc_fw->data; 594 1.1 riastrad ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address, 595 1.1 riastrad ucode_data, ucode_size, limit); 596 1.1 riastrad if (ret) 597 1.1 riastrad return ret; 598 1.1 riastrad 599 1.1 riastrad /* set up the int vectors */ 600 1.1 riastrad ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address, 601 1.1 riastrad int_vect, int_vect_size); 602 1.1 riastrad if (ret) 603 1.1 riastrad return ret; 604 1.1 riastrad 605 1.1 riastrad return 0; 606 1.1 riastrad } 607 1.1 riastrad 608 1.1 riastrad int rv770_read_smc_sram_dword(struct radeon_device *rdev, 609 1.1 riastrad u16 smc_address, u32 *value, u16 limit) 610 1.1 riastrad { 611 1.1 riastrad unsigned long flags; 612 1.1 riastrad int ret; 613 1.1 riastrad 614 1.1 riastrad spin_lock_irqsave(&rdev->smc_idx_lock, flags); 615 1.1 riastrad ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 616 1.1 riastrad if (ret == 0) 617 1.1 riastrad *value = RREG32(SMC_SRAM_DATA); 618 1.1 riastrad spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 619 1.1 riastrad 620 1.1 riastrad return ret; 621 1.1 riastrad } 622 1.1 riastrad 623 1.1 riastrad int rv770_write_smc_sram_dword(struct radeon_device *rdev, 624 1.1 riastrad u16 smc_address, u32 value, u16 limit) 625 1.1 riastrad { 626 1.1 riastrad unsigned long flags; 627 1.1 riastrad int ret; 628 1.1 riastrad 629 1.1 riastrad spin_lock_irqsave(&rdev->smc_idx_lock, flags); 630 1.1 riastrad ret = rv770_set_smc_sram_address(rdev, smc_address, limit); 631 1.1 riastrad if (ret == 0) 632 1.1 riastrad WREG32(SMC_SRAM_DATA, value); 633 1.1 riastrad spin_unlock_irqrestore(&rdev->smc_idx_lock, flags); 634 1.1 riastrad 635 1.1 riastrad return ret; 636 1.1 riastrad } 637