1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 /* Copyright 2025 ARM Limited. All rights reserved. */
3
4 #include <drm/drm_print.h>
5
6 #include "panthor_device.h"
7 #include "panthor_gpu.h"
8 #include "panthor_hw.h"
9 #include "panthor_pwr.h"
10 #include "panthor_regs.h"
11
12 #define GPU_PROD_ID_MAKE(arch_major, prod_major) \
13 (((arch_major) << 24) | (prod_major))
14
15 /** struct panthor_hw_entry - HW arch major to panthor_hw binding entry */
16 struct panthor_hw_entry {
17 /** @arch_min: Minimum supported architecture major value (inclusive) */
18 u8 arch_min;
19
20 /** @arch_max: Maximum supported architecture major value (inclusive) */
21 u8 arch_max;
22
23 /** @hwdev: Pointer to panthor_hw structure */
24 struct panthor_hw *hwdev;
25 };
26
27 static struct panthor_hw panthor_hw_arch_v10 = {
28 .ops = {
29 .soft_reset = panthor_gpu_soft_reset,
30 .l2_power_off = panthor_gpu_l2_power_off,
31 .l2_power_on = panthor_gpu_l2_power_on,
32 },
33 };
34
35 static struct panthor_hw panthor_hw_arch_v14 = {
36 .ops = {
37 .soft_reset = panthor_pwr_reset_soft,
38 .l2_power_off = panthor_pwr_l2_power_off,
39 .l2_power_on = panthor_pwr_l2_power_on,
40 },
41 };
42
43 static struct panthor_hw_entry panthor_hw_match[] = {
44 {
45 .arch_min = 10,
46 .arch_max = 13,
47 .hwdev = &panthor_hw_arch_v10,
48 },
49 {
50 .arch_min = 14,
51 .arch_max = 14,
52 .hwdev = &panthor_hw_arch_v14,
53 },
54 };
55
get_gpu_model_name(struct panthor_device * ptdev)56 static char *get_gpu_model_name(struct panthor_device *ptdev)
57 {
58 const u32 gpu_id = ptdev->gpu_info.gpu_id;
59 const u32 product_id = GPU_PROD_ID_MAKE(GPU_ARCH_MAJOR(gpu_id),
60 GPU_PROD_MAJOR(gpu_id));
61 const bool ray_intersection = !!(ptdev->gpu_info.gpu_features &
62 GPU_FEATURES_RAY_INTERSECTION);
63 const u8 shader_core_count = hweight64(ptdev->gpu_info.shader_present);
64
65 switch (product_id) {
66 case GPU_PROD_ID_MAKE(10, 2):
67 return "Mali-G710";
68 case GPU_PROD_ID_MAKE(10, 3):
69 return "Mali-G510";
70 case GPU_PROD_ID_MAKE(10, 4):
71 return "Mali-G310";
72 case GPU_PROD_ID_MAKE(10, 7):
73 return "Mali-G610";
74 case GPU_PROD_ID_MAKE(11, 2):
75 if (shader_core_count > 10 && ray_intersection)
76 return "Mali-G715-Immortalis";
77 else if (shader_core_count >= 7)
78 return "Mali-G715";
79
80 fallthrough;
81 case GPU_PROD_ID_MAKE(11, 3):
82 return "Mali-G615";
83 case GPU_PROD_ID_MAKE(12, 0):
84 if (shader_core_count >= 10 && ray_intersection)
85 return "Mali-G720-Immortalis";
86 else if (shader_core_count >= 6)
87 return "Mali-G720";
88
89 fallthrough;
90 case GPU_PROD_ID_MAKE(12, 1):
91 return "Mali-G620";
92 case GPU_PROD_ID_MAKE(13, 0):
93 if (shader_core_count >= 10 && ray_intersection)
94 return "Mali-G925-Immortalis";
95 else if (shader_core_count >= 6)
96 return "Mali-G725";
97
98 fallthrough;
99 case GPU_PROD_ID_MAKE(13, 1):
100 return "Mali-G625";
101 case GPU_PROD_ID_MAKE(14, 0):
102 return "Mali-G1-Ultra";
103 case GPU_PROD_ID_MAKE(14, 1):
104 return "Mali-G1-Premium";
105 case GPU_PROD_ID_MAKE(14, 3):
106 return "Mali-G1-Pro";
107 }
108
109 return "(Unknown Mali GPU)";
110 }
111
panthor_gpu_info_init(struct panthor_device * ptdev)112 static void panthor_gpu_info_init(struct panthor_device *ptdev)
113 {
114 unsigned int i;
115
116 ptdev->gpu_info.csf_id = gpu_read(ptdev, GPU_CSF_ID);
117 ptdev->gpu_info.gpu_rev = gpu_read(ptdev, GPU_REVID);
118 ptdev->gpu_info.core_features = gpu_read(ptdev, GPU_CORE_FEATURES);
119 ptdev->gpu_info.l2_features = gpu_read(ptdev, GPU_L2_FEATURES);
120 ptdev->gpu_info.tiler_features = gpu_read(ptdev, GPU_TILER_FEATURES);
121 ptdev->gpu_info.mem_features = gpu_read(ptdev, GPU_MEM_FEATURES);
122 ptdev->gpu_info.mmu_features = gpu_read(ptdev, GPU_MMU_FEATURES);
123 ptdev->gpu_info.thread_features = gpu_read(ptdev, GPU_THREAD_FEATURES);
124 ptdev->gpu_info.max_threads = gpu_read(ptdev, GPU_THREAD_MAX_THREADS);
125 ptdev->gpu_info.thread_max_workgroup_size = gpu_read(ptdev, GPU_THREAD_MAX_WORKGROUP_SIZE);
126 ptdev->gpu_info.thread_max_barrier_size = gpu_read(ptdev, GPU_THREAD_MAX_BARRIER_SIZE);
127 ptdev->gpu_info.coherency_features = gpu_read(ptdev, GPU_COHERENCY_FEATURES);
128 for (i = 0; i < 4; i++)
129 ptdev->gpu_info.texture_features[i] = gpu_read(ptdev, GPU_TEXTURE_FEATURES(i));
130
131 ptdev->gpu_info.as_present = gpu_read(ptdev, GPU_AS_PRESENT);
132
133 /* Introduced in arch 11.x */
134 ptdev->gpu_info.gpu_features = gpu_read64(ptdev, GPU_FEATURES);
135
136 if (panthor_hw_has_pwr_ctrl(ptdev)) {
137 /* Introduced in arch 14.x */
138 ptdev->gpu_info.l2_present = gpu_read64(ptdev, PWR_L2_PRESENT);
139 ptdev->gpu_info.tiler_present = gpu_read64(ptdev, PWR_TILER_PRESENT);
140 ptdev->gpu_info.shader_present = gpu_read64(ptdev, PWR_SHADER_PRESENT);
141 } else {
142 ptdev->gpu_info.shader_present = gpu_read64(ptdev, GPU_SHADER_PRESENT);
143 ptdev->gpu_info.tiler_present = gpu_read64(ptdev, GPU_TILER_PRESENT);
144 ptdev->gpu_info.l2_present = gpu_read64(ptdev, GPU_L2_PRESENT);
145 }
146 }
147
panthor_hw_info_init(struct panthor_device * ptdev)148 static void panthor_hw_info_init(struct panthor_device *ptdev)
149 {
150 u32 major, minor, status;
151
152 panthor_gpu_info_init(ptdev);
153
154 major = GPU_VER_MAJOR(ptdev->gpu_info.gpu_id);
155 minor = GPU_VER_MINOR(ptdev->gpu_info.gpu_id);
156 status = GPU_VER_STATUS(ptdev->gpu_info.gpu_id);
157
158 drm_info(&ptdev->base,
159 "%s id 0x%x major 0x%x minor 0x%x status 0x%x",
160 get_gpu_model_name(ptdev), ptdev->gpu_info.gpu_id >> 16,
161 major, minor, status);
162
163 drm_info(&ptdev->base,
164 "Features: L2:%#x Tiler:%#x Mem:%#x MMU:%#x AS:%#x",
165 ptdev->gpu_info.l2_features,
166 ptdev->gpu_info.tiler_features,
167 ptdev->gpu_info.mem_features,
168 ptdev->gpu_info.mmu_features,
169 ptdev->gpu_info.as_present);
170
171 drm_info(&ptdev->base,
172 "shader_present=0x%0llx l2_present=0x%0llx tiler_present=0x%0llx",
173 ptdev->gpu_info.shader_present, ptdev->gpu_info.l2_present,
174 ptdev->gpu_info.tiler_present);
175 }
176
panthor_hw_bind_device(struct panthor_device * ptdev)177 static int panthor_hw_bind_device(struct panthor_device *ptdev)
178 {
179 struct panthor_hw *hdev = NULL;
180 const u32 arch_major = GPU_ARCH_MAJOR(ptdev->gpu_info.gpu_id);
181 int i = 0;
182
183 for (i = 0; i < ARRAY_SIZE(panthor_hw_match); i++) {
184 struct panthor_hw_entry *entry = &panthor_hw_match[i];
185
186 if (arch_major >= entry->arch_min && arch_major <= entry->arch_max) {
187 hdev = entry->hwdev;
188 break;
189 }
190 }
191
192 if (!hdev)
193 return -EOPNOTSUPP;
194
195 ptdev->hw = hdev;
196
197 return 0;
198 }
199
panthor_hw_gpu_id_init(struct panthor_device * ptdev)200 static int panthor_hw_gpu_id_init(struct panthor_device *ptdev)
201 {
202 ptdev->gpu_info.gpu_id = gpu_read(ptdev, GPU_ID);
203 if (!ptdev->gpu_info.gpu_id)
204 return -ENXIO;
205
206 return 0;
207 }
208
panthor_hw_init(struct panthor_device * ptdev)209 int panthor_hw_init(struct panthor_device *ptdev)
210 {
211 int ret = 0;
212
213 ret = panthor_hw_gpu_id_init(ptdev);
214 if (ret)
215 return ret;
216
217 ret = panthor_hw_bind_device(ptdev);
218 if (ret)
219 return ret;
220
221 panthor_hw_info_init(ptdev);
222
223 return 0;
224 }
225