1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  */
27 
28 #include <linux/firmware.h>
29 #include <linux/mfd/core.h>
30 
31 #include "amdgpu.h"
32 #include "amdgpu_isp.h"
33 
34 #include "ivsrcid/isp/irqsrcs_isp_4_1.h"
35 
36 #define mmDAGB0_WRCLI5_V4_1	0x6811C
37 #define mmDAGB0_WRCLI9_V4_1	0x6812C
38 #define mmDAGB0_WRCLI10_V4_1	0x68130
39 #define mmDAGB0_WRCLI14_V4_1	0x68140
40 #define mmDAGB0_WRCLI19_V4_1	0x68154
41 #define mmDAGB0_WRCLI20_V4_1	0x68158
42 
43 static const unsigned int isp_int_srcid[MAX_ISP_INT_SRC] = {
44 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9,
45 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT10,
46 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT11,
47 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12,
48 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT13,
49 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT14,
50 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT15,
51 	ISP_4_1__SRCID__ISP_RINGBUFFER_WPT16
52 };
53 
54 static int isp_sw_init(void *handle)
55 {
56 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
57 
58 	adev->isp.parent = adev->dev;
59 
60 	adev->isp.cgs_device = amdgpu_cgs_create_device(adev);
61 	if (!adev->isp.cgs_device)
62 		return -EINVAL;
63 
64 	return 0;
65 }
66 
67 static int isp_sw_fini(void *handle)
68 {
69 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
70 
71 	if (adev->isp.cgs_device)
72 		amdgpu_cgs_destroy_device(adev->isp.cgs_device);
73 
74 	return 0;
75 }
76 
77 /**
78  * isp_hw_init - start and test isp block
79  *
80  * @handle: handle for amdgpu_device pointer
81  *
82  */
83 static int isp_hw_init(void *handle)
84 {
85 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
86 	const struct amdgpu_ip_block *ip_block =
87 		amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_ISP);
88 	u64 isp_base;
89 	int int_idx;
90 	int r;
91 
92 	if (!ip_block)
93 		return -EINVAL;
94 
95 	if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289)
96 		return -EINVAL;
97 
98 	isp_base = adev->rmmio_base;
99 
100 	adev->isp.isp_cell = kcalloc(1, sizeof(struct mfd_cell), GFP_KERNEL);
101 	if (!adev->isp.isp_cell) {
102 		r = -ENOMEM;
103 		DRM_ERROR("%s: isp mfd cell alloc failed\n", __func__);
104 		goto failure;
105 	}
106 
107 	adev->isp.isp_res = kcalloc(9, sizeof(struct resource), GFP_KERNEL);
108 	if (!adev->isp.isp_res) {
109 		r = -ENOMEM;
110 		DRM_ERROR("%s: isp mfd res alloc failed\n", __func__);
111 		goto failure;
112 	}
113 
114 	adev->isp.isp_pdata = kzalloc(sizeof(*adev->isp.isp_pdata), GFP_KERNEL);
115 	if (!adev->isp.isp_pdata) {
116 		r = -ENOMEM;
117 		DRM_ERROR("%s: isp platform data alloc failed\n", __func__);
118 		goto failure;
119 	}
120 
121 	/* initialize isp platform data */
122 	adev->isp.isp_pdata->adev = (void *)adev;
123 	adev->isp.isp_pdata->asic_type = adev->asic_type;
124 	adev->isp.isp_pdata->base_rmmio_size = adev->rmmio_size;
125 
126 	adev->isp.isp_res[0].name = "isp_reg";
127 	adev->isp.isp_res[0].flags = IORESOURCE_MEM;
128 	adev->isp.isp_res[0].start = isp_base;
129 	adev->isp.isp_res[0].end = isp_base + ISP_REGS_OFFSET_END;
130 
131 	for (int_idx = 0; int_idx < MAX_ISP_INT_SRC; int_idx++) {
132 		adev->isp.isp_res[int_idx + 1].name = "isp_irq";
133 		adev->isp.isp_res[int_idx + 1].flags = IORESOURCE_IRQ;
134 		adev->isp.isp_res[int_idx + 1].start =
135 			amdgpu_irq_create_mapping(adev, isp_int_srcid[int_idx]);
136 		adev->isp.isp_res[int_idx + 1].end =
137 			adev->isp.isp_res[int_idx + 1].start;
138 	}
139 
140 	adev->isp.isp_cell[0].name = "amd_isp_capture";
141 	adev->isp.isp_cell[0].num_resources = 9;
142 	adev->isp.isp_cell[0].resources = &adev->isp.isp_res[0];
143 	adev->isp.isp_cell[0].platform_data = adev->isp.isp_pdata;
144 	adev->isp.isp_cell[0].pdata_size = sizeof(struct isp_platform_data);
145 
146 	r = mfd_add_hotplug_devices(adev->isp.parent, adev->isp.isp_cell, 1);
147 	if (r) {
148 		DRM_ERROR("%s: add mfd hotplug device failed\n", __func__);
149 		goto failure;
150 	}
151 
152 	/*
153 	 * Temporary WA added to disable MMHUB TLSi until the GART initialization
154 	 * is ready to support MMHUB TLSi and SAW for ISP HW to access GART memory
155 	 * using the TLSi path
156 	 */
157 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI5_V4_1 >> 2, 0xFE5FEAA8);
158 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI9_V4_1 >> 2, 0xFE5FEAA8);
159 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI10_V4_1 >> 2, 0xFE5FEAA8);
160 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI14_V4_1 >> 2, 0xFE5FEAA8);
161 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI19_V4_1 >> 2, 0xFE5FEAA8);
162 	cgs_write_register(adev->isp.cgs_device, mmDAGB0_WRCLI20_V4_1 >> 2, 0xFE5FEAA8);
163 
164 	return 0;
165 
166 failure:
167 
168 	kfree(adev->isp.isp_pdata);
169 	kfree(adev->isp.isp_res);
170 	kfree(adev->isp.isp_cell);
171 
172 	return r;
173 }
174 
175 /**
176  * isp_hw_fini - stop the hardware block
177  *
178  * @handle: handle for amdgpu_device pointer
179  *
180  */
181 static int isp_hw_fini(void *handle)
182 {
183 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
184 
185 	/* remove isp mfd device */
186 	mfd_remove_devices(adev->isp.parent);
187 
188 	kfree(adev->isp.isp_res);
189 	kfree(adev->isp.isp_cell);
190 	kfree(adev->isp.isp_pdata);
191 
192 	return 0;
193 }
194 
195 static int isp_suspend(void *handle)
196 {
197 	return 0;
198 }
199 
200 static int isp_resume(void *handle)
201 {
202 	return 0;
203 }
204 
205 static int isp_load_fw_by_psp(struct amdgpu_device *adev)
206 {
207 	const struct common_firmware_header *hdr;
208 	char ucode_prefix[30];
209 	char fw_name[40];
210 	int r = 0;
211 
212 	/* get isp fw binary name and path */
213 	amdgpu_ucode_ip_version_decode(adev, ISP_HWIP, ucode_prefix,
214 				       sizeof(ucode_prefix));
215 	snprintf(fw_name, sizeof(fw_name), "amdgpu/%s.bin", ucode_prefix);
216 
217 	/* read isp fw */
218 	r = amdgpu_ucode_request(adev, &adev->isp.fw, fw_name);
219 	if (r) {
220 		amdgpu_ucode_release(&adev->isp.fw);
221 		return r;
222 	}
223 
224 	hdr = (const struct common_firmware_header *)adev->isp.fw->data;
225 
226 	adev->firmware.ucode[AMDGPU_UCODE_ID_ISP].ucode_id =
227 		AMDGPU_UCODE_ID_ISP;
228 	adev->firmware.ucode[AMDGPU_UCODE_ID_ISP].fw = adev->isp.fw;
229 
230 	adev->firmware.fw_size +=
231 		ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE);
232 
233 	return r;
234 }
235 
236 static int isp_early_init(void *handle)
237 {
238 	int ret = 0;
239 	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
240 
241 	ret = isp_load_fw_by_psp(adev);
242 	if (ret) {
243 		DRM_WARN("%s: isp fw load failed %d\n", __func__, ret);
244 		/* allow amdgpu init to proceed though isp fw load fails */
245 		ret = 0;
246 	}
247 
248 	return ret;
249 }
250 
251 static bool isp_is_idle(void *handle)
252 {
253 	return true;
254 }
255 
256 static int isp_wait_for_idle(void *handle)
257 {
258 	return 0;
259 }
260 
261 static int isp_soft_reset(void *handle)
262 {
263 	return 0;
264 }
265 
266 static int isp_set_clockgating_state(void *handle,
267 				     enum amd_clockgating_state state)
268 {
269 	return 0;
270 }
271 
272 static int isp_set_powergating_state(void *handle,
273 				     enum amd_powergating_state state)
274 {
275 	return 0;
276 }
277 
278 static const struct amd_ip_funcs isp_ip_funcs = {
279 	.name = "isp_ip",
280 	.early_init = isp_early_init,
281 	.late_init = NULL,
282 	.sw_init = isp_sw_init,
283 	.sw_fini = isp_sw_fini,
284 	.hw_init = isp_hw_init,
285 	.hw_fini = isp_hw_fini,
286 	.suspend = isp_suspend,
287 	.resume = isp_resume,
288 	.is_idle = isp_is_idle,
289 	.wait_for_idle = isp_wait_for_idle,
290 	.soft_reset = isp_soft_reset,
291 	.set_clockgating_state = isp_set_clockgating_state,
292 	.set_powergating_state = isp_set_powergating_state,
293 };
294 
295 const struct amdgpu_ip_block_version isp_ip_block = {
296 	.type = AMD_IP_BLOCK_TYPE_ISP,
297 	.major = 4,
298 	.minor = 1,
299 	.rev = 0,
300 	.funcs = &isp_ip_funcs,
301 };
302