]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/media/pci/intel/ipu6/ipu6.c
UBUNTU: SAUCE: IPU6 driver release for kernel 5.13
[mirror_ubuntu-jammy-kernel.git] / drivers / media / pci / intel / ipu6 / ipu6.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 - 2021 Intel Corporation
3
4 #include <linux/device.h>
5 #include <linux/delay.h>
6 #include <linux/firmware.h>
7 #include <linux/module.h>
8 #include <linux/pm_runtime.h>
9
10 #include "ipu.h"
11 #include "ipu-cpd.h"
12 #include "ipu-isys.h"
13 #include "ipu-psys.h"
14 #include "ipu-platform.h"
15 #include "ipu-platform-regs.h"
16 #include "ipu-platform-buttress-regs.h"
17 #include "ipu-platform-isys-csi2-reg.h"
18
19 struct ipu_cell_program_t {
20 unsigned int magic_number;
21
22 unsigned int blob_offset;
23 unsigned int blob_size;
24
25 unsigned int start[3];
26
27 unsigned int icache_source;
28 unsigned int icache_target;
29 unsigned int icache_size;
30
31 unsigned int pmem_source;
32 unsigned int pmem_target;
33 unsigned int pmem_size;
34
35 unsigned int data_source;
36 unsigned int data_target;
37 unsigned int data_size;
38
39 unsigned int bss_target;
40 unsigned int bss_size;
41
42 unsigned int cell_id;
43 unsigned int regs_addr;
44
45 unsigned int cell_pmem_data_bus_address;
46 unsigned int cell_dmem_data_bus_address;
47 unsigned int cell_pmem_control_bus_address;
48 unsigned int cell_dmem_control_bus_address;
49
50 unsigned int next;
51 unsigned int dummy[2];
52 };
53
54 static unsigned int ipu6se_csi_offsets[] = {
55 IPU_CSI_PORT_A_ADDR_OFFSET,
56 IPU_CSI_PORT_B_ADDR_OFFSET,
57 IPU_CSI_PORT_C_ADDR_OFFSET,
58 IPU_CSI_PORT_D_ADDR_OFFSET,
59 };
60
61 static unsigned int ipu6_csi_offsets[] = {
62 IPU_CSI_PORT_A_ADDR_OFFSET,
63 IPU_CSI_PORT_B_ADDR_OFFSET,
64 IPU_CSI_PORT_C_ADDR_OFFSET,
65 IPU_CSI_PORT_D_ADDR_OFFSET,
66 IPU_CSI_PORT_E_ADDR_OFFSET,
67 IPU_CSI_PORT_F_ADDR_OFFSET,
68 IPU_CSI_PORT_G_ADDR_OFFSET,
69 IPU_CSI_PORT_H_ADDR_OFFSET
70 };
71
72 struct ipu_isys_internal_pdata isys_ipdata = {
73 .hw_variant = {
74 .offset = IPU_UNIFIED_OFFSET,
75 .nr_mmus = 3,
76 .mmu_hw = {
77 {
78 .offset = IPU_ISYS_IOMMU0_OFFSET,
79 .info_bits =
80 IPU_INFO_REQUEST_DESTINATION_IOSF,
81 .nr_l1streams = 16,
82 .l1_block_sz = {
83 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
84 1, 1, 1, 1, 1, 1
85 },
86 .nr_l2streams = 16,
87 .l2_block_sz = {
88 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
89 2, 2, 2, 2, 2, 2
90 },
91 .insert_read_before_invalidate = false,
92 .l1_stream_id_reg_offset =
93 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
94 .l2_stream_id_reg_offset =
95 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
96 },
97 {
98 .offset = IPU_ISYS_IOMMU1_OFFSET,
99 .info_bits = IPU_INFO_STREAM_ID_SET(0),
100 .nr_l1streams = 16,
101 .l1_block_sz = {
102 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
103 2, 2, 2, 1, 1, 4
104 },
105 .nr_l2streams = 16,
106 .l2_block_sz = {
107 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
108 2, 2, 2, 2, 2, 2
109 },
110 .insert_read_before_invalidate = false,
111 .l1_stream_id_reg_offset =
112 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
113 .l2_stream_id_reg_offset =
114 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
115 },
116 {
117 .offset = IPU_ISYS_IOMMUI_OFFSET,
118 .info_bits = IPU_INFO_STREAM_ID_SET(0),
119 .nr_l1streams = 0,
120 .nr_l2streams = 0,
121 .insert_read_before_invalidate = false,
122 },
123 },
124 .cdc_fifos = 3,
125 .cdc_fifo_threshold = {6, 8, 2},
126 .dmem_offset = IPU_ISYS_DMEM_OFFSET,
127 .spc_offset = IPU_ISYS_SPC_OFFSET,
128 },
129 .isys_dma_overshoot = IPU_ISYS_OVERALLOC_MIN,
130 };
131
132 struct ipu_psys_internal_pdata psys_ipdata = {
133 .hw_variant = {
134 .offset = IPU_UNIFIED_OFFSET,
135 .nr_mmus = 4,
136 .mmu_hw = {
137 {
138 .offset = IPU_PSYS_IOMMU0_OFFSET,
139 .info_bits =
140 IPU_INFO_REQUEST_DESTINATION_IOSF,
141 .nr_l1streams = 16,
142 .l1_block_sz = {
143 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
144 2, 2, 2, 2, 2, 2
145 },
146 .nr_l2streams = 16,
147 .l2_block_sz = {
148 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
149 2, 2, 2, 2, 2, 2
150 },
151 .insert_read_before_invalidate = false,
152 .l1_stream_id_reg_offset =
153 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
154 .l2_stream_id_reg_offset =
155 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
156 },
157 {
158 .offset = IPU_PSYS_IOMMU1_OFFSET,
159 .info_bits = IPU_INFO_STREAM_ID_SET(0),
160 .nr_l1streams = 32,
161 .l1_block_sz = {
162 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
163 2, 2, 2, 2, 2, 10,
164 5, 4, 14, 6, 4, 14, 6, 4, 8,
165 4, 2, 1, 1, 1, 1, 14
166 },
167 .nr_l2streams = 32,
168 .l2_block_sz = {
169 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
170 2, 2, 2, 2, 2, 2,
171 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
172 2, 2, 2, 2, 2, 2
173 },
174 .insert_read_before_invalidate = false,
175 .l1_stream_id_reg_offset =
176 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
177 .l2_stream_id_reg_offset =
178 IPU_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
179 },
180 {
181 .offset = IPU_PSYS_IOMMU1R_OFFSET,
182 .info_bits = IPU_INFO_STREAM_ID_SET(0),
183 .nr_l1streams = 16,
184 .l1_block_sz = {
185 1, 4, 4, 4, 4, 16, 8, 4, 32,
186 16, 16, 2, 2, 2, 1, 12
187 },
188 .nr_l2streams = 16,
189 .l2_block_sz = {
190 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
191 2, 2, 2, 2, 2, 2
192 },
193 .insert_read_before_invalidate = false,
194 .l1_stream_id_reg_offset =
195 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
196 .l2_stream_id_reg_offset =
197 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
198 },
199 {
200 .offset = IPU_PSYS_IOMMUI_OFFSET,
201 .info_bits = IPU_INFO_STREAM_ID_SET(0),
202 .nr_l1streams = 0,
203 .nr_l2streams = 0,
204 .insert_read_before_invalidate = false,
205 },
206 },
207 .dmem_offset = IPU_PSYS_DMEM_OFFSET,
208 },
209 };
210
211 const struct ipu_buttress_ctrl isys_buttress_ctrl = {
212 .ratio = IPU_IS_FREQ_CTL_DEFAULT_RATIO,
213 .qos_floor = IPU_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
214 .freq_ctl = IPU_BUTTRESS_REG_IS_FREQ_CTL,
215 .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
216 .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK,
217 .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE,
218 .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE,
219 };
220
221 const struct ipu_buttress_ctrl psys_buttress_ctrl = {
222 .ratio = IPU_PS_FREQ_CTL_DEFAULT_RATIO,
223 .qos_floor = IPU_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
224 .freq_ctl = IPU_BUTTRESS_REG_PS_FREQ_CTL,
225 .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
226 .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK,
227 .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE,
228 .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE,
229 };
230
231 static void ipu6_pkg_dir_configure_spc(struct ipu_device *isp,
232 const struct ipu_hw_variants *hw_variant,
233 int pkg_dir_idx, void __iomem *base,
234 u64 *pkg_dir,
235 dma_addr_t pkg_dir_vied_address)
236 {
237 struct ipu_psys *psys = ipu_bus_get_drvdata(isp->psys);
238 struct ipu_isys *isys = ipu_bus_get_drvdata(isp->isys);
239 unsigned int server_fw_virtaddr;
240 struct ipu_cell_program_t *prog;
241 void __iomem *spc_base;
242 dma_addr_t dma_addr;
243
244 if (!pkg_dir || !isp->cpd_fw) {
245 dev_err(&isp->pdev->dev, "invalid addr\n");
246 return;
247 }
248
249 server_fw_virtaddr = *(pkg_dir + (pkg_dir_idx + 1) * 2);
250 if (pkg_dir_idx == IPU_CPD_PKG_DIR_ISYS_SERVER_IDX) {
251 dma_addr = sg_dma_address(isys->fw_sgt.sgl);
252 prog = (struct ipu_cell_program_t *)((u64)isp->cpd_fw->data +
253 (server_fw_virtaddr -
254 dma_addr));
255 } else {
256 dma_addr = sg_dma_address(psys->fw_sgt.sgl);
257 prog = (struct ipu_cell_program_t *)((u64)isp->cpd_fw->data +
258 (server_fw_virtaddr -
259 dma_addr));
260 }
261
262 spc_base = base + prog->regs_addr;
263 if (spc_base != (base + hw_variant->spc_offset))
264 dev_warn(&isp->pdev->dev,
265 "SPC reg addr 0x%p not matching value from CPD 0x%p\n",
266 base + hw_variant->spc_offset, spc_base);
267 writel(server_fw_virtaddr + prog->blob_offset +
268 prog->icache_source, spc_base + IPU_PSYS_REG_SPC_ICACHE_BASE);
269 writel(IPU_INFO_REQUEST_DESTINATION_IOSF,
270 spc_base + IPU_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER);
271 writel(prog->start[1], spc_base + IPU_PSYS_REG_SPC_START_PC);
272 writel(pkg_dir_vied_address, base + hw_variant->dmem_offset);
273 }
274
275 void ipu_configure_spc(struct ipu_device *isp,
276 const struct ipu_hw_variants *hw_variant,
277 int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
278 dma_addr_t pkg_dir_dma_addr)
279 {
280 u32 val;
281 void __iomem *dmem_base = base + hw_variant->dmem_offset;
282 void __iomem *spc_regs_base = base + hw_variant->spc_offset;
283
284 val = readl(spc_regs_base + IPU_PSYS_REG_SPC_STATUS_CTRL);
285 val |= IPU_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
286 writel(val, spc_regs_base + IPU_PSYS_REG_SPC_STATUS_CTRL);
287
288 if (isp->secure_mode)
289 writel(IPU_PKG_DIR_IMR_OFFSET, dmem_base);
290 else
291 ipu6_pkg_dir_configure_spc(isp, hw_variant, pkg_dir_idx, base,
292 pkg_dir, pkg_dir_dma_addr);
293 }
294 EXPORT_SYMBOL(ipu_configure_spc);
295
296 int ipu_buttress_psys_freq_get(void *data, u64 *val)
297 {
298 struct ipu_device *isp = data;
299 u32 reg_val;
300 int rval;
301
302 rval = pm_runtime_get_sync(&isp->psys->dev);
303 if (rval < 0) {
304 pm_runtime_put(&isp->psys->dev);
305 dev_err(&isp->pdev->dev, "Runtime PM failed (%d)\n", rval);
306 return rval;
307 }
308
309 reg_val = readl(isp->base + BUTTRESS_REG_PS_FREQ_CTL);
310
311 pm_runtime_put(&isp->psys->dev);
312
313 *val = IPU_PS_FREQ_RATIO_BASE *
314 (reg_val & IPU_BUTTRESS_PS_FREQ_CTL_DIVISOR_MASK);
315
316 return 0;
317 }
318
319 void ipu_internal_pdata_init(void)
320 {
321 if (ipu_ver == IPU_VER_6 || ipu_ver == IPU_VER_6EP) {
322 isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6_csi_offsets);
323 isys_ipdata.csi2.offsets = ipu6_csi_offsets;
324 isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
325 psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
326
327 } else if (ipu_ver == IPU_VER_6SE) {
328 isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6se_csi_offsets);
329 isys_ipdata.csi2.offsets = ipu6se_csi_offsets;
330 isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
331 psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
332 }
333 }