Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 310 lines 8.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 or MIT 2/* Copyright 2025 ARM Limited. All rights reserved. */ 3 4#include <linux/nvmem-consumer.h> 5#include <linux/platform_device.h> 6 7#include <drm/drm_print.h> 8 9#include "panthor_device.h" 10#include "panthor_gpu.h" 11#include "panthor_hw.h" 12#include "panthor_pwr.h" 13#include "panthor_regs.h" 14 15#define GPU_PROD_ID_MAKE(arch_major, prod_major) \ 16 (((arch_major) << 24) | (prod_major)) 17 18/** struct panthor_hw_entry - HW arch major to panthor_hw binding entry */ 19struct panthor_hw_entry { 20 /** @arch_min: Minimum supported architecture major value (inclusive) */ 21 u8 arch_min; 22 23 /** @arch_max: Maximum supported architecture major value (inclusive) */ 24 u8 arch_max; 25 26 /** @hwdev: Pointer to panthor_hw structure */ 27 struct panthor_hw *hwdev; 28}; 29 30static struct panthor_hw panthor_hw_arch_v10 = { 31 .ops = { 32 .soft_reset = panthor_gpu_soft_reset, 33 .l2_power_off = panthor_gpu_l2_power_off, 34 .l2_power_on = panthor_gpu_l2_power_on, 35 .power_changed_off = panthor_gpu_power_changed_off, 36 .power_changed_on = panthor_gpu_power_changed_on, 37 }, 38}; 39 40static struct panthor_hw panthor_hw_arch_v14 = { 41 .ops = { 42 .soft_reset = panthor_pwr_reset_soft, 43 .l2_power_off = panthor_pwr_l2_power_off, 44 .l2_power_on = panthor_pwr_l2_power_on, 45 }, 46}; 47 48static struct panthor_hw_entry panthor_hw_match[] = { 49 { 50 .arch_min = 10, 51 .arch_max = 13, 52 .hwdev = &panthor_hw_arch_v10, 53 }, 54 { 55 .arch_min = 14, 56 .arch_max = 14, 57 .hwdev = &panthor_hw_arch_v14, 58 }, 59}; 60 61static int panthor_hw_set_power_tracing(struct device *dev, void *data) 62{ 63 struct panthor_device *ptdev = dev_get_drvdata(dev); 64 65 if (!ptdev) 66 return -ENODEV; 67 68 if (!ptdev->hw) 69 return 0; 70 71 if (data) { 72 if (ptdev->hw->ops.power_changed_on) 73 return ptdev->hw->ops.power_changed_on(ptdev); 74 } else { 75 if (ptdev->hw->ops.power_changed_off) 76 ptdev->hw->ops.power_changed_off(ptdev); 77 } 78 79 return 0; 80} 81 82int panthor_hw_power_status_register(void) 83{ 84 struct device_driver *drv; 85 int ret; 86 87 drv = driver_find("panthor", &platform_bus_type); 88 if (!drv) 89 return -ENODEV; 90 91 ret = driver_for_each_device(drv, NULL, (void *)true, 92 panthor_hw_set_power_tracing); 93 94 return ret; 95} 96 97void panthor_hw_power_status_unregister(void) 98{ 99 struct device_driver *drv; 100 int ret; 101 102 drv = driver_find("panthor", &platform_bus_type); 103 if (!drv) 104 return; 105 106 ret = driver_for_each_device(drv, NULL, NULL, panthor_hw_set_power_tracing); 107 108 /* 109 * Ideally, it'd be possible to ask driver_for_each_device to hand us 110 * another "start" to keep going after the failing device, but it 111 * doesn't do that. Minor inconvenience in what is probably a bad day 112 * on the computer already though. 113 */ 114 if (ret) 115 pr_warn("Couldn't mask power IRQ for at least one device: %pe\n", 116 ERR_PTR(ret)); 117} 118 119static char *get_gpu_model_name(struct panthor_device *ptdev) 120{ 121 const u32 gpu_id = ptdev->gpu_info.gpu_id; 122 const u32 product_id = GPU_PROD_ID_MAKE(GPU_ARCH_MAJOR(gpu_id), 123 GPU_PROD_MAJOR(gpu_id)); 124 const bool ray_intersection = !!(ptdev->gpu_info.gpu_features & 125 GPU_FEATURES_RAY_INTERSECTION); 126 const u8 shader_core_count = hweight64(ptdev->gpu_info.shader_present); 127 128 switch (product_id) { 129 case GPU_PROD_ID_MAKE(10, 2): 130 return "Mali-G710"; 131 case GPU_PROD_ID_MAKE(10, 3): 132 return "Mali-G510"; 133 case GPU_PROD_ID_MAKE(10, 4): 134 return "Mali-G310"; 135 case GPU_PROD_ID_MAKE(10, 7): 136 return "Mali-G610"; 137 case GPU_PROD_ID_MAKE(11, 2): 138 if (shader_core_count > 10 && ray_intersection) 139 return "Mali-G715-Immortalis"; 140 else if (shader_core_count >= 7) 141 return "Mali-G715"; 142 143 fallthrough; 144 case GPU_PROD_ID_MAKE(11, 3): 145 return "Mali-G615"; 146 case GPU_PROD_ID_MAKE(12, 0): 147 if (shader_core_count >= 10 && ray_intersection) 148 return "Mali-G720-Immortalis"; 149 else if (shader_core_count >= 6) 150 return "Mali-G720"; 151 152 fallthrough; 153 case GPU_PROD_ID_MAKE(12, 1): 154 return "Mali-G620"; 155 case GPU_PROD_ID_MAKE(13, 0): 156 if (shader_core_count >= 10 && ray_intersection) 157 return "Mali-G925-Immortalis"; 158 else if (shader_core_count >= 6) 159 return "Mali-G725"; 160 161 fallthrough; 162 case GPU_PROD_ID_MAKE(13, 1): 163 return "Mali-G625"; 164 case GPU_PROD_ID_MAKE(14, 0): 165 return "Mali-G1-Ultra"; 166 case GPU_PROD_ID_MAKE(14, 1): 167 return "Mali-G1-Premium"; 168 case GPU_PROD_ID_MAKE(14, 3): 169 return "Mali-G1-Pro"; 170 } 171 172 return "(Unknown Mali GPU)"; 173} 174 175static int overload_shader_present(struct panthor_device *ptdev) 176{ 177 u64 contents; 178 int ret; 179 180 ret = nvmem_cell_read_variable_le_u64(ptdev->base.dev, "shader-present", 181 &contents); 182 if (!ret) 183 ptdev->gpu_info.shader_present = contents; 184 else if (ret == -ENOENT) 185 return 0; 186 else 187 return dev_err_probe(ptdev->base.dev, ret, 188 "Failed to read shader-present nvmem cell\n"); 189 190 return 0; 191} 192 193static int panthor_gpu_info_init(struct panthor_device *ptdev) 194{ 195 unsigned int i; 196 197 ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID); 198 ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID); 199 ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES); 200 ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES); 201 ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES); 202 ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES); 203 ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES); 204 ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES); 205 ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS); 206 ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE); 207 ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE); 208 ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES); 209 for (i = 0; i < 4; i++) 210 ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i)); 211 212 ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT); 213 214 /* Introduced in arch 11.x */ 215 ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES); 216 217 if (panthor_hw_has_pwr_ctrl(ptdev)) { 218 /* Introduced in arch 14.x */ 219 ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT); 220 ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT); 221 ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT); 222 } else { 223 ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT); 224 ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT); 225 ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT); 226 } 227 228 return overload_shader_present(ptdev); 229} 230 231static int panthor_hw_info_init(struct panthor_device *ptdev) 232{ 233 u32 major, minor, status; 234 int ret; 235 236 ret = panthor_gpu_info_init(ptdev); 237 if (ret) 238 return ret; 239 240 major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id); 241 minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id); 242 status = GPU_VER_STATUS(ptdev->gpu_info.gpu_id); 243 244 drm_info(&ptdev->base, 245 "%s id 0x%x major 0x%x minor 0x%x status 0x%x", 246 get_gpu_model_name(ptdev), ptdev->gpu_info.gpu_id >> 16, 247 major, minor, status); 248 249 drm_info(&ptdev->base, 250 "Features: L2:%#x Tiler:%#x Mem:%#x MMU:%#x AS:%#x", 251 ptdev->gpu_info.l2_features, 252 ptdev->gpu_info.tiler_features, 253 ptdev->gpu_info.mem_features, 254 ptdev->gpu_info.mmu_features, 255 ptdev->gpu_info.as_present); 256 257 drm_info(&ptdev->base, 258 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx", 259 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present, 260 ptdev->gpu_info.tiler_present); 261 262 return 0; 263} 264 265static int panthor_hw_bind_device(struct panthor_device *ptdev) 266{ 267 struct panthor_hw *hdev = NULL; 268 const u32 arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id); 269 int i = 0; 270 271 for (i = 0; i < ARRAY_SIZE(panthor_hw_match); i++) { 272 struct panthor_hw_entry *entry = &panthor_hw_match[i]; 273 274 if (arch_major >= entry->arch_min && arch_major <= entry->arch_max) { 275 hdev = entry->hwdev; 276 break; 277 } 278 } 279 280 if (!hdev) 281 return -EOPNOTSUPP; 282 283 ptdev->hw = hdev; 284 285 return 0; 286} 287 288static int panthor_hw_gpu_id_init(struct panthor_device *ptdev) 289{ 290 ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID); 291 if (!ptdev->gpu_info.gpu_id) 292 return -ENXIO; 293 294 return 0; 295} 296 297int panthor_hw_init(struct panthor_device *ptdev) 298{ 299 int ret = 0; 300 301 ret = panthor_hw_gpu_id_init(ptdev); 302 if (ret) 303 return ret; 304 305 ret = panthor_hw_bind_device(ptdev); 306 if (ret) 307 return ret; 308 309 return panthor_hw_info_init(ptdev); 310}