]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/pci/intel/ipu6/ipu6.c
UBUNTU: SAUCE: IPU driver release WW14
[mirror_ubuntu-jammy-kernel.git] / drivers / media / pci / intel / ipu6 / ipu6.c
CommitLineData
f2efa4ee
WY
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2020 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
19struct 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
54static 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
61static unsigned int ipu6se_tpg_offsets[] = {
62 IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
63 IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
64 IPU_CSI_PORT_C_PIXGEN_ADDR_OFFSET,
65 IPU_CSI_PORT_D_PIXGEN_ADDR_OFFSET,
66};
67
f2efa4ee
WY
68static unsigned int ipu6_tpg_offsets[] = {
69 IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
70 IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
71 IPU_CSI_PORT_C_PIXGEN_ADDR_OFFSET,
72 IPU_CSI_PORT_D_PIXGEN_ADDR_OFFSET,
73 IPU_CSI_PORT_E_PIXGEN_ADDR_OFFSET,
74 IPU_CSI_PORT_F_PIXGEN_ADDR_OFFSET,
75 IPU_CSI_PORT_G_PIXGEN_ADDR_OFFSET,
76 IPU_CSI_PORT_H_PIXGEN_ADDR_OFFSET
77};
af60d6fc
WY
78
79static unsigned int ipu6_csi_offsets[] = {
80 IPU_CSI_PORT_A_ADDR_OFFSET,
81 IPU_CSI_PORT_B_ADDR_OFFSET,
82 IPU_CSI_PORT_C_ADDR_OFFSET,
83 IPU_CSI_PORT_D_ADDR_OFFSET,
84 IPU_CSI_PORT_E_ADDR_OFFSET,
85 IPU_CSI_PORT_F_ADDR_OFFSET,
86 IPU_CSI_PORT_G_ADDR_OFFSET,
87 IPU_CSI_PORT_H_ADDR_OFFSET
88};
f2efa4ee
WY
89
90struct ipu_isys_internal_pdata isys_ipdata = {
91 .hw_variant = {
92 .offset = IPU_UNIFIED_OFFSET,
93 .nr_mmus = 3,
94 .mmu_hw = {
95 {
96 .offset = IPU_ISYS_IOMMU0_OFFSET,
97 .info_bits =
98 IPU_INFO_REQUEST_DESTINATION_IOSF,
99 .nr_l1streams = 16,
100 .l1_block_sz = {
101 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
102 1, 1, 1, 1, 1, 1
103 },
104 .nr_l2streams = 16,
105 .l2_block_sz = {
106 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
107 2, 2, 2, 2, 2, 2
108 },
109 .insert_read_before_invalidate = false,
110 .zlw_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_IOMMU1_OFFSET,
118 .info_bits = IPU_INFO_STREAM_ID_SET(0),
119 .nr_l1streams = 16,
120 .l1_block_sz = {
121 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
122 2, 2, 2, 1, 1, 4
123 },
124 .nr_l2streams = 16,
125 .l2_block_sz = {
126 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
127 2, 2, 2, 2, 2, 2
128 },
129 .insert_read_before_invalidate = false,
130 .zlw_invalidate = false,
131 .l1_stream_id_reg_offset =
132 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
133 .l2_stream_id_reg_offset =
134 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
135 },
136 {
137 .offset = IPU_ISYS_IOMMUI_OFFSET,
138 .info_bits = IPU_INFO_STREAM_ID_SET(0),
139 .nr_l1streams = 0,
140 .nr_l2streams = 0,
141 .insert_read_before_invalidate = false,
142 },
143 },
144 .cdc_fifos = 3,
145 .cdc_fifo_threshold = {6, 8, 2},
146 .dmem_offset = IPU_ISYS_DMEM_OFFSET,
147 .spc_offset = IPU_ISYS_SPC_OFFSET,
148 },
149 .isys_dma_overshoot = IPU_ISYS_OVERALLOC_MIN,
150};
151
152struct ipu_psys_internal_pdata psys_ipdata = {
153 .hw_variant = {
154 .offset = IPU_UNIFIED_OFFSET,
155 .nr_mmus = 4,
156 .mmu_hw = {
157 {
158 .offset = IPU_PSYS_IOMMU0_OFFSET,
159 .info_bits =
160 IPU_INFO_REQUEST_DESTINATION_IOSF,
161 .nr_l1streams = 16,
162 .l1_block_sz = {
163 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
164 2, 2, 2, 2, 2, 2
165 },
166 .nr_l2streams = 16,
167 .l2_block_sz = {
168 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
169 2, 2, 2, 2, 2, 2
170 },
171 .insert_read_before_invalidate = false,
172 .zlw_invalidate = false,
173 .l1_stream_id_reg_offset =
174 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
175 .l2_stream_id_reg_offset =
176 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
177 },
178 {
179 .offset = IPU_PSYS_IOMMU1_OFFSET,
180 .info_bits = IPU_INFO_STREAM_ID_SET(0),
181 .nr_l1streams = 32,
182 .l1_block_sz = {
183 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
184 2, 2, 2, 2, 2, 10,
185 5, 4, 14, 6, 4, 14, 6, 4, 8,
186 4, 2, 1, 1, 1, 1, 14
187 },
188 .nr_l2streams = 32,
189 .l2_block_sz = {
190 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
191 2, 2, 2, 2, 2, 2,
192 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
193 2, 2, 2, 2, 2, 2
194 },
195 .insert_read_before_invalidate = false,
196 .zlw_invalidate = false,
197 .l1_stream_id_reg_offset =
198 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
199 .l2_stream_id_reg_offset =
200 IPU_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
201 },
202 {
203 .offset = IPU_PSYS_IOMMU1R_OFFSET,
204 .info_bits = IPU_INFO_STREAM_ID_SET(0),
205 .nr_l1streams = 16,
206 .l1_block_sz = {
207 1, 4, 4, 4, 4, 16, 8, 4, 32,
208 16, 16, 2, 2, 2, 1, 12
209 },
210 .nr_l2streams = 16,
211 .l2_block_sz = {
212 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
213 2, 2, 2, 2, 2, 2
214 },
215 .insert_read_before_invalidate = false,
216 .zlw_invalidate = false,
217 .l1_stream_id_reg_offset =
218 IPU_MMU_L1_STREAM_ID_REG_OFFSET,
219 .l2_stream_id_reg_offset =
220 IPU_MMU_L2_STREAM_ID_REG_OFFSET,
221 },
222 {
223 .offset = IPU_PSYS_IOMMUI_OFFSET,
224 .info_bits = IPU_INFO_STREAM_ID_SET(0),
225 .nr_l1streams = 0,
226 .nr_l2streams = 0,
227 .insert_read_before_invalidate = false,
228 },
229 },
230 .dmem_offset = IPU_PSYS_DMEM_OFFSET,
231 },
232};
233
234const struct ipu_buttress_ctrl isys_buttress_ctrl = {
235 .ratio = IPU_IS_FREQ_CTL_DEFAULT_RATIO,
236 .qos_floor = IPU_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
237 .freq_ctl = IPU_BUTTRESS_REG_IS_FREQ_CTL,
238 .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
239 .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_IS_PWR_MASK,
240 .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE,
241 .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE,
242};
243
244const struct ipu_buttress_ctrl psys_buttress_ctrl = {
245 .ratio = IPU_PS_FREQ_CTL_DEFAULT_RATIO,
246 .qos_floor = IPU_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
247 .freq_ctl = IPU_BUTTRESS_REG_PS_FREQ_CTL,
248 .pwr_sts_shift = IPU_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
249 .pwr_sts_mask = IPU_BUTTRESS_PWR_STATE_PS_PWR_MASK,
250 .pwr_sts_on = IPU_BUTTRESS_PWR_STATE_UP_DONE,
251 .pwr_sts_off = IPU_BUTTRESS_PWR_STATE_DN_DONE,
252};
253
254static void ipu6_pkg_dir_configure_spc(struct ipu_device *isp,
255 const struct ipu_hw_variants *hw_variant,
256 int pkg_dir_idx, void __iomem *base,
257 u64 *pkg_dir,
258 dma_addr_t pkg_dir_vied_address)
259{
260 struct ipu_psys *psys = ipu_bus_get_drvdata(isp->psys);
261 struct ipu_isys *isys = ipu_bus_get_drvdata(isp->isys);
262 unsigned int server_fw_virtaddr;
263 struct ipu_cell_program_t *prog;
264 void __iomem *spc_base;
265 dma_addr_t dma_addr;
266
267 if (!pkg_dir || !isp->cpd_fw) {
268 dev_err(&isp->pdev->dev, "invalid addr\n");
269 return;
270 }
271
272 server_fw_virtaddr = *(pkg_dir + (pkg_dir_idx + 1) * 2);
273 if (pkg_dir_idx == IPU_CPD_PKG_DIR_ISYS_SERVER_IDX) {
274 dma_addr = sg_dma_address(isys->fw_sgt.sgl);
275 prog = (struct ipu_cell_program_t *)((u64)isp->cpd_fw->data +
276 (server_fw_virtaddr -
277 dma_addr));
278 } else {
279 dma_addr = sg_dma_address(psys->fw_sgt.sgl);
280 prog = (struct ipu_cell_program_t *)((u64)isp->cpd_fw->data +
281 (server_fw_virtaddr -
282 dma_addr));
283 }
284
285 spc_base = base + prog->regs_addr;
286 if (spc_base != (base + hw_variant->spc_offset))
287 dev_warn(&isp->pdev->dev,
288 "SPC reg addr 0x%p not matching value from CPD 0x%p\n",
289 base + hw_variant->spc_offset, spc_base);
290 writel(server_fw_virtaddr + prog->blob_offset +
291 prog->icache_source, spc_base + IPU_PSYS_REG_SPC_ICACHE_BASE);
292 writel(IPU_INFO_REQUEST_DESTINATION_IOSF,
293 spc_base + IPU_REG_PSYS_INFO_SEG_0_CONFIG_ICACHE_MASTER);
294 writel(prog->start[1], spc_base + IPU_PSYS_REG_SPC_START_PC);
295 writel(pkg_dir_vied_address, base + hw_variant->dmem_offset);
296}
297
298void ipu_configure_spc(struct ipu_device *isp,
299 const struct ipu_hw_variants *hw_variant,
300 int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
301 dma_addr_t pkg_dir_dma_addr)
302{
303 u32 val;
304 void __iomem *dmem_base = base + hw_variant->dmem_offset;
305 void __iomem *spc_regs_base = base + hw_variant->spc_offset;
306
307 val = readl(spc_regs_base + IPU_PSYS_REG_SPC_STATUS_CTRL);
308 val |= IPU_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
309 writel(val, spc_regs_base + IPU_PSYS_REG_SPC_STATUS_CTRL);
310
311 if (isp->secure_mode)
312 writel(IPU_PKG_DIR_IMR_OFFSET, dmem_base);
313 else
314 ipu6_pkg_dir_configure_spc(isp, hw_variant, pkg_dir_idx, base,
315 pkg_dir, pkg_dir_dma_addr);
316}
317EXPORT_SYMBOL(ipu_configure_spc);
318
319int ipu_buttress_psys_freq_get(void *data, u64 *val)
320{
321 struct ipu_device *isp = data;
322 u32 reg_val;
323 int rval;
324
325 rval = pm_runtime_get_sync(&isp->psys->dev);
326 if (rval < 0) {
327 pm_runtime_put(&isp->psys->dev);
328 dev_err(&isp->pdev->dev, "Runtime PM failed (%d)\n", rval);
329 return rval;
330 }
331
332 reg_val = readl(isp->base + BUTTRESS_REG_PS_FREQ_CTL);
333
334 pm_runtime_put(&isp->psys->dev);
335
336 *val = IPU_PS_FREQ_RATIO_BASE *
337 (reg_val & IPU_BUTTRESS_PS_FREQ_CTL_DIVISOR_MASK);
338
339 return 0;
340}
341
f2efa4ee
WY
342void ipu_internal_pdata_init(void)
343{
eaffc3a7 344 if (ipu_ver == IPU_VER_6 || ipu_ver == IPU_VER_6EP) {
f2efa4ee
WY
345 isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6_csi_offsets);
346 isys_ipdata.csi2.offsets = ipu6_csi_offsets;
347 isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6_tpg_offsets);
348 isys_ipdata.tpg.offsets = ipu6_tpg_offsets;
349 isys_ipdata.tpg.sels = NULL;
350 isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
351 psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
352
353 } else if (ipu_ver == IPU_VER_6SE) {
354 isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6se_csi_offsets);
355 isys_ipdata.csi2.offsets = ipu6se_csi_offsets;
356 isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6se_tpg_offsets);
357 isys_ipdata.tpg.offsets = ipu6se_tpg_offsets;
358 isys_ipdata.tpg.sels = NULL;
359 isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
360 psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
361 }
362}