xref: /linux/drivers/gpu/drm/panthor/panthor_hw.c (revision 3f1c07fc21c68bd3bd2df9d2c9441f6485e934d9)
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