Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only
2 : /*
3 : * Copyright (C) 2013--2024 Intel Corporation
4 : */
5 :
6 : #include <linux/bitfield.h>
7 : #include <linux/bits.h>
8 : #include <linux/dma-mapping.h>
9 : #include <linux/err.h>
10 : #include <linux/firmware.h>
11 : #include <linux/kernel.h>
12 : #include <linux/interrupt.h>
13 : #include <linux/io.h>
14 : #include <linux/list.h>
15 : #include <linux/module.h>
16 : #include <linux/pci-ats.h>
17 : #include <linux/pm_runtime.h>
18 : #include <linux/property.h>
19 : #include <linux/scatterlist.h>
20 : #include <linux/slab.h>
21 : #include <linux/types.h>
22 :
23 : #ifdef IPU6
24 : #include <media/ipu-bridge.h>
25 : #include <media/ipu6-pci-table.h>
26 : #else
27 : #include "ambu-ipu-bridge.h"
28 : #include "virt-sensor.h"
29 : #endif
30 :
31 : #include "ipu6.h"
32 : #include "ipu6-bus.h"
33 : #include "ipu6-buttress.h"
34 : #include "ipu6-cpd.h"
35 : #include "ipu6-isys.h"
36 : #include "ipu6-mmu.h"
37 : #include "ipu6-platform-buttress-regs.h"
38 : #include "ipu6-platform-isys-csi2-reg.h"
39 : #include "ipu6-platform-regs.h"
40 :
41 : #define IPU6_PCI_BAR 0
42 :
43 : struct ipu6_cell_program {
44 : u32 magic_number;
45 :
46 : u32 blob_offset;
47 : u32 blob_size;
48 :
49 : u32 start[3];
50 :
51 : u32 icache_source;
52 : u32 icache_target;
53 : u32 icache_size;
54 :
55 : u32 pmem_source;
56 : u32 pmem_target;
57 : u32 pmem_size;
58 :
59 : u32 data_source;
60 : u32 data_target;
61 : u32 data_size;
62 :
63 : u32 bss_target;
64 : u32 bss_size;
65 :
66 : u32 cell_id;
67 : u32 regs_addr;
68 :
69 : u32 cell_pmem_data_bus_address;
70 : u32 cell_dmem_data_bus_address;
71 : u32 cell_pmem_control_bus_address;
72 : u32 cell_dmem_control_bus_address;
73 :
74 : u32 next;
75 : u32 dummy[2];
76 : };
77 :
78 : #ifdef IPU6
79 : static struct ipu6_isys_internal_pdata isys_ipdata = {
80 : .hw_variant = {
81 : .offset = IPU6_UNIFIED_OFFSET,
82 : .nr_mmus = 3,
83 : .mmu_hw = {
84 : {
85 : .offset = IPU6_ISYS_IOMMU0_OFFSET,
86 : .info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
87 : .nr_l1streams = 16,
88 : .l1_block_sz = {
89 : 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
90 : 1, 1, 1, 1, 1, 1
91 : },
92 : .nr_l2streams = 16,
93 : .l2_block_sz = {
94 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
95 : 2, 2, 2, 2, 2, 2
96 : },
97 : .insert_read_before_invalidate = false,
98 : .l1_stream_id_reg_offset =
99 : IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
100 : .l2_stream_id_reg_offset =
101 : IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
102 : },
103 : {
104 : .offset = IPU6_ISYS_IOMMU1_OFFSET,
105 : .info_bits = 0,
106 : .nr_l1streams = 16,
107 : .l1_block_sz = {
108 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
109 : 2, 2, 2, 1, 1, 4
110 : },
111 : .nr_l2streams = 16,
112 : .l2_block_sz = {
113 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
114 : 2, 2, 2, 2, 2, 2
115 : },
116 : .insert_read_before_invalidate = false,
117 : .l1_stream_id_reg_offset =
118 : IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
119 : .l2_stream_id_reg_offset =
120 : IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
121 : },
122 : {
123 : .offset = IPU6_ISYS_IOMMUI_OFFSET,
124 : .info_bits = 0,
125 : .nr_l1streams = 0,
126 : .nr_l2streams = 0,
127 : .insert_read_before_invalidate = false,
128 : },
129 : },
130 : .cdc_fifos = 3,
131 : .cdc_fifo_threshold = {6, 8, 2},
132 : .dmem_offset = IPU6_ISYS_DMEM_OFFSET,
133 : .spc_offset = IPU6_ISYS_SPC_OFFSET,
134 : },
135 : .isys_dma_overshoot = IPU6_ISYS_OVERALLOC_MIN,
136 : };
137 :
138 : static struct ipu6_psys_internal_pdata psys_ipdata = {
139 : .hw_variant = {
140 : .offset = IPU6_UNIFIED_OFFSET,
141 : .nr_mmus = 4,
142 : .mmu_hw = {
143 : {
144 : .offset = IPU6_PSYS_IOMMU0_OFFSET,
145 : .info_bits =
146 : IPU6_INFO_REQUEST_DESTINATION_IOSF,
147 : .nr_l1streams = 16,
148 : .l1_block_sz = {
149 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
150 : 2, 2, 2, 2, 2, 2
151 : },
152 : .nr_l2streams = 16,
153 : .l2_block_sz = {
154 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
155 : 2, 2, 2, 2, 2, 2
156 : },
157 : .insert_read_before_invalidate = false,
158 : .l1_stream_id_reg_offset =
159 : IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
160 : .l2_stream_id_reg_offset =
161 : IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
162 : },
163 : {
164 : .offset = IPU6_PSYS_IOMMU1_OFFSET,
165 : .info_bits = 0,
166 : .nr_l1streams = 32,
167 : .l1_block_sz = {
168 : 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
169 : 2, 2, 2, 2, 2, 10,
170 : 5, 4, 14, 6, 4, 14, 6, 4, 8,
171 : 4, 2, 1, 1, 1, 1, 14
172 : },
173 : .nr_l2streams = 32,
174 : .l2_block_sz = {
175 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
176 : 2, 2, 2, 2, 2, 2,
177 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
178 : 2, 2, 2, 2, 2, 2
179 : },
180 : .insert_read_before_invalidate = false,
181 : .l1_stream_id_reg_offset =
182 : IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
183 : .l2_stream_id_reg_offset =
184 : IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
185 : },
186 : {
187 : .offset = IPU6_PSYS_IOMMU1R_OFFSET,
188 : .info_bits = 0,
189 : .nr_l1streams = 16,
190 : .l1_block_sz = {
191 : 1, 4, 4, 4, 4, 16, 8, 4, 32,
192 : 16, 16, 2, 2, 2, 1, 12
193 : },
194 : .nr_l2streams = 16,
195 : .l2_block_sz = {
196 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
197 : 2, 2, 2, 2, 2, 2
198 : },
199 : .insert_read_before_invalidate = false,
200 : .l1_stream_id_reg_offset =
201 : IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
202 : .l2_stream_id_reg_offset =
203 : IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
204 : },
205 : {
206 : .offset = IPU6_PSYS_IOMMUI_OFFSET,
207 : .info_bits = 0,
208 : .nr_l1streams = 0,
209 : .nr_l2streams = 0,
210 : .insert_read_before_invalidate = false,
211 : },
212 : },
213 : .dmem_offset = IPU6_PSYS_DMEM_OFFSET,
214 : },
215 : };
216 : #else
217 : static const struct ipu6_isys_internal_pdata isys_ipdata = {
218 : .hw_variant = {
219 : .offset = IPU4_ISYS_OFFSET,
220 : .nr_mmus = 2,
221 : .mmu_hw = {{
222 : .offset = IPU4_ISYS_IOMMU0_OFFSET,
223 : .info_bits = IPU4_INFO_REQUEST_DESTINATION_PRIMARY,
224 : .nr_l1streams = 0,
225 : .nr_l2streams = 0,
226 : .insert_read_before_invalidate = true,
227 : },
228 : {
229 : .offset = IPU4_ISYS_IOMMU1_OFFSET,
230 : .info_bits = IPU4_INFO_STREAM_ID_SET(0),
231 : .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
232 : .l1_block_sz = {
233 : 8, 16, 16, 16, 0, 0, 0, 0, 0,
234 : 0, 0, 0, 0, 0, 0, 8
235 : },
236 : .l1_zlw_en = {
237 : 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
238 : 0, 0, 0, 0, 0, 0
239 : },
240 : .l1_zlw_1d_mode = {
241 : 0, 1, 1, 1, 0, 0, 0, 0,
242 : 0, 0, 0, 0, 0, 0, 0, 0
243 : },
244 : .l1_ins_zlw_ahead_pages = {
245 : 0, 3, 3, 3, 0, 0,
246 : 0, 0, 0, 0, 0, 0,
247 : 0, 0, 0, 0
248 : },
249 : .l1_zlw_2d_mode = {
250 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
251 : 0, 0, 0, 0, 0, 0, 0
252 : },
253 : .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
254 : .l2_block_sz = {
255 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
256 : 2, 2, 2, 2, 2, 2
257 : },
258 : .insert_read_before_invalidate = false,
259 : .zlw_invalidate = false,
260 : .l1_stream_id_reg_offset =
261 : IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
262 : .l2_stream_id_reg_offset =
263 : IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
264 : },
265 : },
266 : .dmem_offset = IPU4_ISYS_DMEM_OFFSET,
267 : .spc_offset = IPU4_ISYS_SPC_OFFSET,
268 : },
269 : .isys_dma_overshoot = IPU6_ISYS_OVERALLOC_MIN,
270 : .num_parallel_streams = IPU4_STREAM_ID_MAX,
271 : .csi2.nports = ARRAY_SIZE(ipu4_csi_offsets),
272 : .max_streams = IPU4_ISYS_MAX_STREAMS,
273 : .max_sram_blocks = IPU4_ISYS_MAX_STREAMS,
274 : .max_send_queues = IPU4_N_MAX_SEND_QUEUES,
275 :
276 : /* Consider 1 slot per stream since driver is not expected to pipeline
277 : * device commands for the same stream
278 : */
279 : .max_devq_size = IPU4_ISYS_MAX_STREAMS,
280 : };
281 :
282 : static const struct ipu6_psys_internal_pdata psys_ipdata = {
283 : .hw_variant = {
284 : .offset = IPU4_PSYS_OFFSET,
285 : .nr_mmus = 3,
286 : .mmu_hw = {
287 : {
288 : .offset = IPU4_PSYS_IOMMU0_OFFSET,
289 : .info_bits =
290 : IPU4_INFO_REQUEST_DESTINATION_PRIMARY,
291 : .nr_l1streams = 0,
292 : .nr_l2streams = 0,
293 : .insert_read_before_invalidate = true,
294 : },
295 : {
296 : .offset = IPU4_PSYS_IOMMU1_OFFSET,
297 : .info_bits = IPU4_INFO_STREAM_ID_SET(0),
298 : .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
299 : .l1_block_sz = {
300 : 0, 0, 0, 0, 10, 8, 10, 8, 0,
301 : 4, 4, 12, 0, 0, 0, 8
302 : },
303 : .l1_zlw_en = {
304 : 0, 0, 0, 0, 1, 1, 1, 1, 0, 1,
305 : 1, 1, 0, 0, 0, 0
306 : },
307 : .l1_zlw_1d_mode = {
308 : 0, 0, 0, 0, 1, 1, 1, 1, 0,
309 : 1, 1, 1, 0, 0, 0, 0
310 : },
311 : .l1_ins_zlw_ahead_pages = {
312 : 0, 0, 0, 0, 3, 3,
313 : 3, 3, 0, 3, 1, 3,
314 : 0, 0, 0, 0
315 : },
316 : .l1_zlw_2d_mode = {
317 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
318 : 0, 0, 0, 0, 0, 0, 0
319 : },
320 : .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
321 : .l2_block_sz = {
322 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
323 : 2, 2, 2, 2, 2, 2
324 : },
325 : .insert_read_before_invalidate = false,
326 : .zlw_invalidate = false,
327 : .l1_stream_id_reg_offset =
328 : IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
329 : .l2_stream_id_reg_offset =
330 : IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
331 : },
332 : {
333 : .offset = IPU4_PSYS_IOMMU1R_OFFSET,
334 : .info_bits = IPU4_INFO_STREAM_ID_SET(0),
335 : .nr_l1streams = IPU4_MMU_MAX_TLB_L1_STREAMS,
336 : .l1_block_sz = {
337 : 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,
338 : 0, 0, 16, 12, 12, 16
339 : },
340 : .l1_zlw_en = {
341 : 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
342 : 0, 0, 1, 1, 1, 1
343 : },
344 : .l1_zlw_1d_mode = {
345 : 0, 0, 0, 0, 0, 0, 0, 0, 1,
346 : 0, 0, 0, 0, 1, 1, 1
347 : },
348 : .l1_ins_zlw_ahead_pages = {
349 : 0, 0, 0, 0, 0, 0,
350 : 0, 0, 3, 0, 0, 0,
351 : 0, 0, 0, 0
352 : },
353 : .l1_zlw_2d_mode = {
354 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
355 : 0, 0, 0, 0, 1, 1, 1
356 : },
357 : .nr_l2streams = IPU4_MMU_MAX_TLB_L2_STREAMS,
358 : .l2_block_sz = {
359 : 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
360 : 2, 2, 2, 2, 2, 2
361 : },
362 : .insert_read_before_invalidate = false,
363 : .zlw_invalidate = false,
364 : .l1_stream_id_reg_offset =
365 : IPU4_MMU_L1_STREAM_ID_REG_OFFSET,
366 : .l2_stream_id_reg_offset =
367 : IPU4_MMU_L2_STREAM_ID_REG_OFFSET,
368 : },
369 : },
370 : .dmem_offset = IPU4_PSYS_DMEM_OFFSET,
371 : .spc_offset = IPU4_PSYS_SPC_OFFSET,
372 : },
373 : };
374 : #endif
375 :
376 : static const struct ipu6_buttress_ctrl ipu6_isys_buttress_ctrl = {
377 : .ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
378 : .qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
379 : .freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
380 : .pwr_sts_shift = IPU6_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
381 : .pwr_sts_mask = IPU6_BUTTRESS_PWR_STATE_IS_PWR_MASK,
382 : .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
383 : .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
384 : };
385 :
386 : static const struct ipu6_buttress_ctrl ipu6_psys_buttress_ctrl = {
387 : .ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
388 : .qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
389 : .freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
390 : .pwr_sts_shift = IPU6_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
391 : .pwr_sts_mask = IPU6_BUTTRESS_PWR_STATE_PS_PWR_MASK,
392 : .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
393 : .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
394 : };
395 :
396 : /* Non-static: declared extern in ipu6.h so ipu4_buttress_math_kunit
397 : * can pin every field against the IPU4 platform constants. The struct
398 : * uses designated initializers, so what the kunit catches is value
399 : * drift in the bindings — not struct-layout reorders, which are
400 : * compiler no-ops.
401 : */
402 : const struct ipu6_buttress_ctrl ipu4_isys_buttress_ctrl = {
403 : .ratio = IPU4_IS_FREQ_CTL_DIVISOR,
404 : .qos_floor = 0,
405 : .freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
406 : .pwr_sts_shift = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_SHIFT,
407 : .pwr_sts_mask = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_MASK,
408 : .pwr_sts_on = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_IS_RDY,
409 : .pwr_sts_off = IPU4_BUTTRESS_PWR_STATE_IS_PWR_FSM_IDLE,
410 : };
411 :
412 : const struct ipu6_buttress_ctrl ipu4_psys_buttress_ctrl = {
413 : .ratio = IPU4_PS_FREQ_CTL_DEFAULT_RATIO,
414 : .qos_floor = IPU4_PS_FREQ_CTL_DEFAULT_RATIO,
415 : .freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
416 : .pwr_sts_shift = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_SHIFT,
417 : .pwr_sts_mask = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_MASK,
418 : .pwr_sts_on = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_PS_PWR_UP,
419 : .pwr_sts_off = IPU4_BUTTRESS_PWR_STATE_PS_PWR_FSM_IDLE,
420 : };
421 :
422 : static void
423 0 : ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
424 : const struct ipu6_hw_variants *hw_variant,
425 : int pkg_dir_idx, void __iomem *base,
426 : u64 *pkg_dir, dma_addr_t pkg_dir_vied_address)
427 : {
428 : struct ipu6_cell_program *prog;
429 : void __iomem *spc_base;
430 : u32 server_fw_addr;
431 : dma_addr_t dma_addr;
432 : u32 pg_offset;
433 :
434 0 : server_fw_addr = lower_32_bits(*(pkg_dir + (pkg_dir_idx + 1) * 2));
435 : /*
436 : * The stub CPD blob shipped by tools/firmware/gen-cpd.py has
437 : * zeroed pkg_dir entries — enough to satisfy
438 : * ipu6_cpd_validate_cpd_file() but not to point at a real SPC
439 : * program. Walking the cell_program at the resulting wild
440 : * pointer would deref invalid memory. Skip the SPC-program
441 : * load when there's nothing to load; the QEMU device model
442 : * just absorbs the SPC writes that did fire and the syscom
443 : * boot handshake completes via the model's SYSCOM_STATE
444 : * shortcut.
445 : */
446 0 : if (!server_fw_addr) {
447 0 : dev_dbg(&isp->pdev->dev,
448 : "skipping SPC program load: empty pkg_dir entry %d\n",
449 : pkg_dir_idx);
450 0 : return;
451 : }
452 0 : if (pkg_dir_idx == IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX)
453 0 : dma_addr = sg_dma_address(isp->isys->fw_sgt.sgl);
454 : else
455 0 : dma_addr = sg_dma_address(isp->psys->fw_sgt.sgl);
456 :
457 0 : pg_offset = server_fw_addr - dma_addr;
458 0 : prog = (struct ipu6_cell_program *)((uintptr_t)isp->cpd_fw->data +
459 : pg_offset);
460 0 : spc_base = base + prog->regs_addr;
461 0 : if (spc_base != (base + hw_variant->spc_offset))
462 0 : dev_warn(&isp->pdev->dev,
463 : "SPC reg addr %p not matching value from CPD %p\n",
464 : base + hw_variant->spc_offset, spc_base);
465 0 : writel(server_fw_addr + prog->blob_offset +
466 0 : prog->icache_source, spc_base + IPU6_PSYS_REG_SPC_ICACHE_BASE);
467 : writel(IPU6_INFO_REQUEST_DESTINATION_IOSF,
468 0 : spc_base + IPU6_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER);
469 0 : writel(prog->start[1], spc_base + IPU6_PSYS_REG_SPC_START_PC);
470 0 : writel(pkg_dir_vied_address, base + hw_variant->dmem_offset);
471 : }
472 :
473 1 : void ipu6_configure_spc(struct ipu6_device *isp,
474 : const struct ipu6_hw_variants *hw_variant,
475 : int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
476 : dma_addr_t pkg_dir_dma_addr)
477 : {
478 1 : void __iomem *dmem_base = base + hw_variant->dmem_offset;
479 1 : void __iomem *spc_regs_base = base + hw_variant->spc_offset;
480 : u32 val;
481 :
482 : val = readl(spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
483 1 : val |= IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
484 : writel(val, spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
485 :
486 1 : if (isp->secure_mode)
487 : writel(IPU6_PKG_DIR_IMR_OFFSET, dmem_base);
488 : else
489 0 : ipu6_pkg_dir_configure_spc(isp, hw_variant, pkg_dir_idx, base,
490 : pkg_dir, pkg_dir_dma_addr);
491 1 : }
492 : EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, INTEL_IPU6);
493 :
494 1 : static int ipu6_isys_check_fwnode_graph(struct fwnode_handle *fwnode)
495 : {
496 : struct fwnode_handle *endpoint;
497 :
498 : if (IS_ERR_OR_NULL(fwnode))
499 : return -EINVAL;
500 :
501 1 : endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
502 1 : if (endpoint) {
503 0 : fwnode_handle_put(endpoint);
504 0 : return 0;
505 : }
506 :
507 1 : return ipu6_isys_check_fwnode_graph(fwnode->secondary);
508 : }
509 :
510 : #define IPU6_ISYS_CSI2_NPORTS 4
511 : #define IPU6SE_ISYS_CSI2_NPORTS 4
512 : #define IPU6_TGL_ISYS_CSI2_NPORTS 8
513 : #define IPU6EP_MTL_ISYS_CSI2_NPORTS 6
514 :
515 : static void ipu6_internal_pdata_init(struct ipu6_device *isp)
516 : {
517 : #ifdef IPU6
518 : u8 hw_ver = isp->hw_ver;
519 :
520 : isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
521 : isys_ipdata.sram_gran_shift = IPU6_SRAM_GRANULARITY_SHIFT;
522 : isys_ipdata.sram_gran_size = IPU6_SRAM_GRANULARITY_SIZE;
523 : isys_ipdata.max_sram_size = IPU6_MAX_SRAM_SIZE;
524 : isys_ipdata.sensor_type_start = IPU6_FW_ISYS_SENSOR_TYPE_START;
525 : isys_ipdata.sensor_type_end = IPU6_FW_ISYS_SENSOR_TYPE_END;
526 : isys_ipdata.max_streams = IPU6_ISYS_NUM_STREAMS;
527 : isys_ipdata.max_send_queues = IPU6_N_MAX_SEND_QUEUES;
528 : isys_ipdata.max_sram_blocks = IPU6_NOF_SRAM_BLOCKS_MAX;
529 : isys_ipdata.max_devq_size = IPU6_DEV_SEND_QUEUE_SIZE;
530 : isys_ipdata.csi2.nports = IPU6_ISYS_CSI2_NPORTS;
531 : isys_ipdata.csi2.irq_mask = IPU6_CSI_RX_ERROR_IRQ_MASK;
532 : isys_ipdata.csi2.ctrl0_irq_edge = IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE;
533 : isys_ipdata.csi2.ctrl0_irq_clear =
534 : IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
535 : isys_ipdata.csi2.ctrl0_irq_mask = IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK;
536 : isys_ipdata.csi2.ctrl0_irq_enable =
537 : IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE;
538 : isys_ipdata.csi2.ctrl0_irq_status =
539 : IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
540 : isys_ipdata.csi2.ctrl0_irq_lnp =
541 : IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
542 : isys_ipdata.enhanced_iwake = is_ipu6ep_mtl(hw_ver) || is_ipu6ep(hw_ver);
543 : psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
544 : isys_ipdata.csi2.fw_access_port_ofs = CSI_REG_HUB_FW_ACCESS_PORT_OFS;
545 :
546 : if (is_ipu6ep(hw_ver)) {
547 : isys_ipdata.ltr = IPU6EP_LTR_VALUE;
548 : isys_ipdata.memopen_threshold = IPU6EP_MIN_MEMOPEN_TH;
549 : }
550 :
551 : if (is_ipu6_tgl(hw_ver))
552 : isys_ipdata.csi2.nports = IPU6_TGL_ISYS_CSI2_NPORTS;
553 :
554 : if (is_ipu6ep_mtl(hw_ver)) {
555 : isys_ipdata.csi2.nports = IPU6EP_MTL_ISYS_CSI2_NPORTS;
556 :
557 : isys_ipdata.csi2.ctrl0_irq_edge =
558 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE;
559 : isys_ipdata.csi2.ctrl0_irq_clear =
560 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
561 : isys_ipdata.csi2.ctrl0_irq_mask =
562 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK;
563 : isys_ipdata.csi2.ctrl0_irq_enable =
564 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE;
565 : isys_ipdata.csi2.ctrl0_irq_lnp =
566 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
567 : isys_ipdata.csi2.ctrl0_irq_status =
568 : IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
569 : isys_ipdata.csi2.fw_access_port_ofs =
570 : CSI_REG_HUB_FW_ACCESS_PORT_V6OFS;
571 : isys_ipdata.ltr = IPU6EP_MTL_LTR_VALUE;
572 : isys_ipdata.memopen_threshold = IPU6EP_MTL_MIN_MEMOPEN_TH;
573 : }
574 :
575 : if (is_ipu6se(hw_ver)) {
576 : isys_ipdata.csi2.nports = IPU6SE_ISYS_CSI2_NPORTS;
577 : isys_ipdata.csi2.irq_mask = IPU6SE_CSI_RX_ERROR_IRQ_MASK;
578 : isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
579 : isys_ipdata.sram_gran_shift = IPU6SE_SRAM_GRANULARITY_SHIFT;
580 : isys_ipdata.sram_gran_size = IPU6SE_SRAM_GRANULARITY_SIZE;
581 : isys_ipdata.max_sram_size = IPU6SE_MAX_SRAM_SIZE;
582 : isys_ipdata.sensor_type_start =
583 : IPU6SE_FW_ISYS_SENSOR_TYPE_START;
584 : isys_ipdata.sensor_type_end = IPU6SE_FW_ISYS_SENSOR_TYPE_END;
585 : isys_ipdata.max_streams = IPU6SE_ISYS_NUM_STREAMS;
586 : isys_ipdata.max_send_queues = IPU6SE_N_MAX_SEND_QUEUES;
587 : isys_ipdata.max_sram_blocks = IPU6SE_NOF_SRAM_BLOCKS_MAX;
588 : isys_ipdata.max_devq_size = IPU6SE_DEV_SEND_QUEUE_SIZE;
589 : psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
590 : }
591 : #else
592 : (void)isp;
593 : #endif
594 : }
595 :
596 : static struct ipu6_bus_device *
597 1 : ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
598 : const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
599 : const struct ipu6_isys_internal_pdata *ipdata)
600 : {
601 : #ifndef IPU6
602 1 : struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
603 : #endif
604 : struct device *dev = &pdev->dev;
605 : struct ipu6_bus_device *isys_adev;
606 : struct ipu6_isys_pdata *pdata;
607 : int ret;
608 :
609 : #ifdef IPU6
610 : ret = ipu_bridge_init(dev, ipu_bridge_parse_ssdb);
611 : if (ret) {
612 : dev_err_probe(dev, ret, "IPU6 bridge init failed\n");
613 : return ERR_PTR(ret);
614 : }
615 : #else
616 : /* check fwnode at first, fallback into bridge if no fwnode graph */
617 1 : ret = ipu6_isys_check_fwnode_graph(fwnode);
618 1 : if (ret) {
619 2 : if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) {
620 0 : dev_err(&pdev->dev,
621 : "fwnode graph has no endpoints connection\n");
622 0 : return ERR_PTR(-EINVAL);
623 : }
624 :
625 : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
626 1 : ret = ipu4_virt_sensor_install(pdev);
627 : #else
628 : ret = ambu_ipu_bridge_init(dev);
629 : #endif
630 1 : if (ret) {
631 0 : if (ret != -EPROBE_DEFER)
632 0 : dev_err_probe(dev, ret, "IPU6 bridge init failed\n");
633 0 : return ERR_PTR(ret);
634 : }
635 : }
636 : #endif
637 :
638 1 : pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
639 1 : if (!pdata)
640 : return ERR_PTR(-ENOMEM);
641 :
642 1 : pdata->base = base;
643 1 : pdata->ipdata = ipdata;
644 :
645 1 : isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
646 : IPU6_ISYS_NAME);
647 1 : if (IS_ERR(isys_adev)) {
648 0 : kfree(pdata);
649 0 : return dev_err_cast_probe(dev, isys_adev,
650 : "ipu6_bus_initialize_device isys failed\n");
651 : }
652 :
653 1 : isys_adev->mmu = ipu6_mmu_init(dev, base, ISYS_MMID,
654 : &ipdata->hw_variant);
655 1 : if (IS_ERR(isys_adev->mmu)) {
656 0 : put_device(&isys_adev->auxdev.dev);
657 0 : kfree(pdata);
658 0 : return dev_err_cast_probe(dev, isys_adev->mmu,
659 : "ipu6_mmu_init(isys_adev->mmu) failed\n");
660 : }
661 :
662 1 : isys_adev->mmu->dev = &isys_adev->auxdev.dev;
663 :
664 1 : ret = ipu6_bus_add_device(isys_adev);
665 1 : if (ret) {
666 0 : kfree(pdata);
667 0 : return ERR_PTR(ret);
668 : }
669 :
670 : return isys_adev;
671 : }
672 :
673 : static struct ipu6_bus_device *
674 1 : ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
675 : const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
676 : const struct ipu6_psys_internal_pdata *ipdata)
677 : {
678 : struct ipu6_bus_device *psys_adev;
679 : struct ipu6_psys_pdata *pdata;
680 : int ret;
681 :
682 1 : pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
683 1 : if (!pdata)
684 : return ERR_PTR(-ENOMEM);
685 :
686 1 : pdata->base = base;
687 1 : pdata->ipdata = ipdata;
688 :
689 1 : psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
690 : IPU6_PSYS_NAME);
691 1 : if (IS_ERR(psys_adev)) {
692 0 : kfree(pdata);
693 0 : return dev_err_cast_probe(&pdev->dev, psys_adev,
694 : "ipu6_bus_initialize_device psys failed\n");
695 : }
696 :
697 1 : psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, PSYS_MMID,
698 : &ipdata->hw_variant);
699 1 : if (IS_ERR(psys_adev->mmu)) {
700 0 : put_device(&psys_adev->auxdev.dev);
701 0 : kfree(pdata);
702 0 : return dev_err_cast_probe(&pdev->dev, psys_adev->mmu,
703 : "ipu6_mmu_init(psys_adev->mmu) failed\n");
704 : }
705 :
706 1 : psys_adev->mmu->dev = &psys_adev->auxdev.dev;
707 :
708 1 : ret = ipu6_bus_add_device(psys_adev);
709 1 : if (ret) {
710 0 : kfree(pdata);
711 0 : return ERR_PTR(ret);
712 : }
713 :
714 : return psys_adev;
715 : }
716 :
717 1 : static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver)
718 : {
719 : int ret;
720 :
721 : /* No PCI msi capability for IPU6EP */
722 1 : if (is_ipu6ep(hw_ver) || is_ipu6ep_mtl(hw_ver)) {
723 : /* likely do nothing as msi not enabled by default */
724 0 : pci_disable_msi(dev);
725 0 : return 0;
726 : }
727 :
728 1 : ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_MSI);
729 1 : if (ret < 0)
730 0 : return dev_err_probe(&dev->dev, ret, "Request msi failed");
731 :
732 : return 0;
733 : }
734 :
735 : static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
736 : {
737 4 : u32 val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
738 :
739 : if (IPU6_BTRS_ARB_STALL_MODE_VC0 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
740 : val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
741 : else
742 : val &= ~BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
743 :
744 : if (IPU6_BTRS_ARB_STALL_MODE_VC1 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
745 : val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1;
746 : else
747 4 : val &= ~BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC1;
748 :
749 4 : writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
750 : }
751 :
752 1 : static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
753 : {
754 : const struct ipu6_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl = NULL;
755 1 : struct device *dev = &pdev->dev;
756 : void __iomem *isys_base = NULL;
757 : void __iomem *psys_base = NULL;
758 : struct ipu6_device *isp;
759 1 : phys_addr_t phys;
760 : int ret;
761 :
762 : isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
763 1 : if (!isp)
764 : return -ENOMEM;
765 :
766 1 : isp->pdev = pdev;
767 1 : INIT_LIST_HEAD(&isp->devices);
768 :
769 1 : ret = pcim_enable_device(pdev);
770 1 : if (ret)
771 0 : return dev_err_probe(dev, ret, "Enable PCI device failed\n");
772 :
773 1 : phys = pci_resource_start(pdev, IPU6_PCI_BAR);
774 1 : dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
775 :
776 1 : isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
777 1 : if (IS_ERR(isp->base))
778 0 : return dev_err_probe(dev, PTR_ERR(isp->base),
779 : "Failed to I/O mem remapping\n");
780 :
781 : pci_set_drvdata(pdev, isp);
782 1 : pci_set_master(pdev);
783 :
784 1 : isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
785 1 : switch (id->device) {
786 0 : case PCI_DEVICE_ID_INTEL_IPU6:
787 0 : isp->hw_ver = IPU6_VER_6;
788 0 : isp->cpd_fw_name = IPU6_FIRMWARE_NAME;
789 0 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
790 0 : break;
791 0 : case PCI_DEVICE_ID_INTEL_IPU6SE:
792 0 : isp->hw_ver = IPU6_VER_6SE;
793 0 : isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
794 0 : isp->cpd_metadata_cmpnt_size =
795 : sizeof(struct ipu6se_cpd_metadata_cmpnt);
796 0 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
797 0 : break;
798 0 : case PCI_DEVICE_ID_INTEL_IPU6EP_ADLP:
799 : case PCI_DEVICE_ID_INTEL_IPU6EP_RPLP:
800 0 : isp->hw_ver = IPU6_VER_6EP;
801 0 : isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
802 0 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
803 0 : break;
804 0 : case PCI_DEVICE_ID_INTEL_IPU6EP_ADLN:
805 0 : isp->hw_ver = IPU6_VER_6EP;
806 0 : isp->cpd_fw_name = IPU6EPADLN_FIRMWARE_NAME;
807 0 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
808 0 : break;
809 0 : case PCI_DEVICE_ID_INTEL_IPU6EP_MTL:
810 0 : isp->hw_ver = IPU6_VER_6EP_MTL;
811 0 : isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
812 0 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
813 0 : break;
814 1 : case PCI_DEVICE_ID_INTEL_IPU4:
815 1 : isp->hw_ver = IPU4_VER_4;
816 1 : isp->cpd_fw_name = IPU4_FIRMWARE_NAME;
817 : // IPU4 uses same cpd metadata cmpnt as ipu6se
818 : // (smaller hash size)
819 1 : isp->cpd_metadata_cmpnt_size =
820 : sizeof(struct ipu6se_cpd_metadata_cmpnt);
821 1 : isp->buttress.reg_irq_sts = BUTTRESS_REG_ISR_ENABLED_STATUS;
822 1 : break;
823 0 : default:
824 0 : return dev_err_probe(dev, -ENODEV,
825 : "Unsupported IPU6 device %x\n",
826 : id->device);
827 : }
828 :
829 : ipu6_internal_pdata_init(isp);
830 :
831 1 : isys_base = isp->base + isys_ipdata.hw_variant.offset;
832 1 : psys_base = isp->base + psys_ipdata.hw_variant.offset;
833 :
834 1 : ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(39));
835 1 : if (ret)
836 0 : return dev_err_probe(&pdev->dev, ret,
837 : "Failed to set DMA mask\n");
838 :
839 1 : dma_set_max_seg_size(dev, UINT_MAX);
840 :
841 1 : ret = ipu6_pci_config_setup(pdev, isp->hw_ver);
842 1 : if (ret)
843 : return ret;
844 :
845 1 : ret = ipu6_buttress_init(isp);
846 1 : if (ret)
847 : return ret;
848 :
849 1 : ret = request_firmware(&isp->cpd_fw, isp->cpd_fw_name, dev);
850 1 : if (ret) {
851 0 : dev_err_probe(&isp->pdev->dev, ret,
852 : "Requesting signed firmware %s failed\n",
853 : isp->cpd_fw_name);
854 0 : goto buttress_exit;
855 : }
856 :
857 1 : ret = ipu6_cpd_validate_cpd_file(isp, isp->cpd_fw->data,
858 1 : isp->cpd_fw->size);
859 1 : if (ret) {
860 0 : dev_err_probe(&isp->pdev->dev, ret,
861 : "Failed to validate cpd\n");
862 0 : goto out_ipu6_bus_del_devices;
863 : }
864 :
865 1 : isys_ctrl = is_ipu4(isp->hw_ver) ?
866 1 : &ipu4_isys_buttress_ctrl : &ipu6_isys_buttress_ctrl;
867 1 : isp->isys = ipu6_isys_init(pdev, &pdev->dev, isys_ctrl, isys_base,
868 : &isys_ipdata);
869 1 : if (IS_ERR(isp->isys)) {
870 0 : ret = PTR_ERR(isp->isys);
871 0 : goto out_ipu6_bus_del_devices;
872 : }
873 :
874 1 : psys_ctrl = is_ipu4(isp->hw_ver) ?
875 1 : &ipu4_psys_buttress_ctrl : &ipu6_psys_buttress_ctrl;
876 :
877 1 : isp->psys = ipu6_psys_init(pdev, &isp->isys->auxdev.dev, psys_ctrl,
878 : psys_base, &psys_ipdata);
879 1 : if (IS_ERR(isp->psys)) {
880 0 : ret = PTR_ERR(isp->psys);
881 0 : goto out_ipu_bridge_uninit;
882 : }
883 :
884 1 : ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev);
885 1 : if (ret < 0)
886 0 : goto out_ipu_bridge_uninit;
887 :
888 1 : ret = ipu6_mmu_hw_init(isp->psys->mmu);
889 1 : if (ret) {
890 0 : dev_err_probe(&isp->pdev->dev, ret,
891 : "Failed to set MMU hardware\n");
892 0 : goto out_ipu_bridge_uninit;
893 : }
894 :
895 1 : ret = ipu6_buttress_map_fw_image(isp->psys, isp->cpd_fw,
896 1 : &isp->psys->fw_sgt);
897 1 : if (ret) {
898 0 : dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
899 0 : goto out_ipu_bridge_uninit;
900 : }
901 :
902 1 : ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
903 1 : if (ret) {
904 0 : dev_err_probe(&isp->pdev->dev, ret,
905 : "failed to create pkg dir\n");
906 0 : goto out_ipu_bridge_uninit;
907 : }
908 :
909 1 : ret = devm_request_threaded_irq(&pdev->dev, pdev->irq,
910 : ipu6_buttress_isr,
911 : ipu6_buttress_isr_threaded,
912 : IRQF_SHARED, IPU4_NAME, isp);
913 1 : if (ret) {
914 0 : dev_err_probe(&pdev->dev, ret, "Requesting irq failed\n");
915 0 : goto out_ipu_bridge_uninit;
916 : }
917 :
918 1 : ret = ipu6_buttress_authenticate(isp);
919 1 : if (ret) {
920 0 : dev_err_probe(&isp->pdev->dev, ret,
921 : "FW authentication failed\n");
922 0 : goto out_free_irq;
923 : }
924 :
925 1 : ipu6_mmu_hw_cleanup(isp->psys->mmu);
926 1 : pm_runtime_put(&isp->psys->auxdev.dev);
927 :
928 : /* Configure the arbitration mechanisms for VC requests */
929 : ipu6_configure_vc_mechanism(isp);
930 :
931 : #ifdef IPU6
932 : val = readl(isp->base + BUTTRESS_REG_SKU);
933 : sku_id = FIELD_GET(GENMASK(6, 4), val);
934 : version = FIELD_GET(GENMASK(3, 0), val);
935 : dev_info(dev, "IPU%u-v%u[%x] hardware version %d\n", version, sku_id,
936 : pdev->device, isp->hw_ver);
937 : #else
938 : // NB: Don't change, currently used as done signal in test
939 1 : dev_info(&pdev->dev, "IPU4 PCI driver ready\n");
940 : #endif
941 :
942 1 : pm_runtime_put_noidle(dev);
943 1 : pm_runtime_allow(dev);
944 :
945 1 : isp->bus_ready_to_probe = true;
946 :
947 1 : return 0;
948 :
949 : out_free_irq:
950 0 : devm_free_irq(dev, pdev->irq, isp);
951 0 : out_ipu_bridge_uninit:
952 : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
953 0 : ipu4_virt_sensor_remove(pdev);
954 : #else
955 : ambu_ipu_bridge_uninit(&pdev->dev);
956 : #endif
957 0 : out_ipu6_bus_del_devices:
958 0 : if (isp->psys) {
959 0 : ipu6_cpd_free_pkg_dir(isp->psys);
960 0 : ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
961 : }
962 0 : if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
963 0 : ipu6_mmu_cleanup(isp->psys->mmu);
964 0 : if (!IS_ERR_OR_NULL(isp->isys) && !IS_ERR_OR_NULL(isp->isys->mmu))
965 0 : ipu6_mmu_cleanup(isp->isys->mmu);
966 0 : ipu6_bus_del_devices(pdev);
967 0 : release_firmware(isp->cpd_fw);
968 0 : buttress_exit:
969 0 : ipu6_buttress_exit(isp);
970 :
971 0 : return ret;
972 : }
973 :
974 0 : static void ipu6_pci_remove(struct pci_dev *pdev)
975 : {
976 : struct ipu6_device *isp = pci_get_drvdata(pdev);
977 0 : struct ipu6_mmu *isys_mmu = isp->isys->mmu;
978 0 : struct ipu6_mmu *psys_mmu = isp->psys->mmu;
979 :
980 0 : devm_free_irq(&pdev->dev, pdev->irq, isp);
981 0 : ipu6_cpd_free_pkg_dir(isp->psys);
982 :
983 0 : ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
984 :
985 0 : ipu6_buttress_exit(isp);
986 :
987 0 : ipu6_bus_del_devices(pdev);
988 :
989 0 : pm_runtime_forbid(&pdev->dev);
990 : pm_runtime_get_noresume(&pdev->dev);
991 :
992 0 : release_firmware(isp->cpd_fw);
993 :
994 0 : ipu6_mmu_cleanup(psys_mmu);
995 0 : ipu6_mmu_cleanup(isys_mmu);
996 :
997 : #if IS_ENABLED(CONFIG_VIDEO_IPU4_VIRT_SENSOR)
998 0 : ipu4_virt_sensor_remove(pdev);
999 : #else
1000 : ambu_ipu_bridge_uninit(&pdev->dev);
1001 : #endif
1002 0 : }
1003 :
1004 0 : static void ipu6_pci_reset_prepare(struct pci_dev *pdev)
1005 : {
1006 : struct ipu6_device *isp = pci_get_drvdata(pdev);
1007 :
1008 0 : pm_runtime_forbid(&isp->pdev->dev);
1009 0 : }
1010 :
1011 0 : static void ipu6_pci_reset_done(struct pci_dev *pdev)
1012 : {
1013 : struct ipu6_device *isp = pci_get_drvdata(pdev);
1014 :
1015 0 : ipu6_buttress_restore(isp);
1016 0 : if (isp->secure_mode)
1017 0 : ipu6_buttress_reset_authentication(isp);
1018 :
1019 0 : isp->need_ipc_reset = true;
1020 0 : pm_runtime_allow(&isp->pdev->dev);
1021 0 : }
1022 :
1023 : /*
1024 : * PCI base driver code requires driver to provide these to enable
1025 : * PCI device level PM state transitions (D0<->D3)
1026 : */
1027 4 : static int ipu6_suspend(struct device *dev)
1028 : {
1029 : struct pci_dev *pdev = to_pci_dev(dev);
1030 :
1031 4 : synchronize_irq(pdev->irq);
1032 4 : return 0;
1033 : }
1034 :
1035 : static int ipu6_resume(struct device *dev)
1036 : {
1037 : struct pci_dev *pdev = to_pci_dev(dev);
1038 : struct ipu6_device *isp = pci_get_drvdata(pdev);
1039 : struct ipu6_buttress *b = &isp->buttress;
1040 : int ret;
1041 :
1042 : /* Configure the arbitration mechanisms for VC requests */
1043 : ipu6_configure_vc_mechanism(isp);
1044 :
1045 : isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
1046 : dev_info(dev, "IPU6 in %s mode\n",
1047 : isp->secure_mode ? "secure" : "non-secure");
1048 :
1049 : ipu6_buttress_restore(isp);
1050 :
1051 : ret = ipu6_buttress_ipc_reset(isp, &b->cse);
1052 : if (ret)
1053 : dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
1054 :
1055 : ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev);
1056 : if (ret < 0) {
1057 : dev_err(&isp->psys->auxdev.dev, "Failed to get runtime PM\n");
1058 : return 0;
1059 : }
1060 :
1061 : ret = ipu6_buttress_authenticate(isp);
1062 : if (ret)
1063 : dev_err(&isp->pdev->dev, "FW authentication failed(%d)\n", ret);
1064 :
1065 : pm_runtime_put(&isp->psys->auxdev.dev);
1066 :
1067 : return 0;
1068 : }
1069 :
1070 3 : static int ipu6_runtime_resume(struct device *dev)
1071 : {
1072 : struct pci_dev *pdev = to_pci_dev(dev);
1073 : struct ipu6_device *isp = pci_get_drvdata(pdev);
1074 : int ret;
1075 :
1076 : ipu6_configure_vc_mechanism(isp);
1077 3 : ipu6_buttress_restore(isp);
1078 :
1079 3 : if (isp->need_ipc_reset) {
1080 : struct ipu6_buttress *b = &isp->buttress;
1081 :
1082 0 : isp->need_ipc_reset = false;
1083 0 : ret = ipu6_buttress_ipc_reset(isp, &b->cse);
1084 0 : if (ret)
1085 0 : dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
1086 : }
1087 :
1088 3 : return 0;
1089 : }
1090 :
1091 : static const struct dev_pm_ops ipu6_pm_ops = {
1092 : SYSTEM_SLEEP_PM_OPS(&ipu6_suspend, &ipu6_resume)
1093 : RUNTIME_PM_OPS(&ipu6_suspend, &ipu6_runtime_resume, NULL)
1094 : };
1095 :
1096 : static const struct pci_device_id ipu6_pci_tbl[] = {
1097 : { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU4)},
1098 : { }
1099 : };
1100 : MODULE_DEVICE_TABLE(pci, ipu6_pci_tbl);
1101 :
1102 : static const struct pci_error_handlers pci_err_handlers = {
1103 : .reset_prepare = ipu6_pci_reset_prepare,
1104 : .reset_done = ipu6_pci_reset_done,
1105 : };
1106 :
1107 : static struct pci_driver ipu6_pci_driver = {
1108 : .name = IPU4_NAME,
1109 : .id_table = ipu6_pci_tbl,
1110 : .probe = ipu6_pci_probe,
1111 : .remove = ipu6_pci_remove,
1112 : .driver = {
1113 : .pm = pm_ptr(&ipu6_pm_ops),
1114 : },
1115 : .err_handler = &pci_err_handlers,
1116 : };
1117 :
1118 1 : module_pci_driver(ipu6_pci_driver);
1119 :
1120 : MODULE_IMPORT_NS(INTEL_IPU_BRIDGE);
1121 : MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1122 : MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
1123 : MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
1124 : MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>");
1125 : MODULE_AUTHOR("Yunliang Ding <yunliang.ding@intel.com>");
1126 : MODULE_AUTHOR("Hongju Wang <hongju.wang@intel.com>");
1127 : MODULE_LICENSE("GPL");
1128 : MODULE_DESCRIPTION("Intel IPU4 PCI driver");
|