1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Intel Corporation
4 #include <linux/device.h>
5 #include <linux/firmware.h>
7 #include <linux/slab.h>
10 #include "ipu3-css-fw.h"
11 #include "ipu3-dmamap.h"
13 static void ipu3_css_fw_show_binary(struct device
*dev
, struct imgu_fw_info
*bi
,
18 dev_dbg(dev
, "found firmware binary type %i size %i name %s\n",
19 bi
->type
, bi
->blob
.size
, name
);
20 if (bi
->type
!= IMGU_FW_ISP_FIRMWARE
)
23 dev_dbg(dev
, " id %i mode %i bds 0x%x veceven %i/%i out_pins %i\n",
24 bi
->info
.isp
.sp
.id
, bi
->info
.isp
.sp
.pipeline
.mode
,
25 bi
->info
.isp
.sp
.bds
.supported_bds_factors
,
26 bi
->info
.isp
.sp
.enable
.vf_veceven
,
27 bi
->info
.isp
.sp
.vf_dec
.is_variable
,
28 bi
->info
.isp
.num_output_pins
);
30 dev_dbg(dev
, " input (%i,%i)-(%i,%i) formats %s%s%s\n",
31 bi
->info
.isp
.sp
.input
.min_width
,
32 bi
->info
.isp
.sp
.input
.min_height
,
33 bi
->info
.isp
.sp
.input
.max_width
,
34 bi
->info
.isp
.sp
.input
.max_height
,
35 bi
->info
.isp
.sp
.enable
.input_yuv
? "yuv420 " : "",
36 bi
->info
.isp
.sp
.enable
.input_feeder
||
37 bi
->info
.isp
.sp
.enable
.input_raw
? "raw8 raw10 " : "",
38 bi
->info
.isp
.sp
.enable
.input_raw
? "raw12" : "");
40 dev_dbg(dev
, " internal (%i,%i)\n",
41 bi
->info
.isp
.sp
.internal
.max_width
,
42 bi
->info
.isp
.sp
.internal
.max_height
);
44 dev_dbg(dev
, " output (%i,%i)-(%i,%i) formats",
45 bi
->info
.isp
.sp
.output
.min_width
,
46 bi
->info
.isp
.sp
.output
.min_height
,
47 bi
->info
.isp
.sp
.output
.max_width
,
48 bi
->info
.isp
.sp
.output
.max_height
);
49 for (i
= 0; i
< bi
->info
.isp
.num_output_formats
; i
++)
50 dev_dbg(dev
, " %i", bi
->info
.isp
.output_formats
[i
]);
52 for (i
= 0; i
< bi
->info
.isp
.num_vf_formats
; i
++)
53 dev_dbg(dev
, " %i", bi
->info
.isp
.vf_formats
[i
]);
57 unsigned int ipu3_css_fw_obgrid_size(const struct imgu_fw_info
*bi
)
59 unsigned int width
= DIV_ROUND_UP(bi
->info
.isp
.sp
.internal
.max_width
,
60 IMGU_OBGRID_TILE_SIZE
* 2) + 1;
61 unsigned int height
= DIV_ROUND_UP(bi
->info
.isp
.sp
.internal
.max_height
,
62 IMGU_OBGRID_TILE_SIZE
* 2) + 1;
63 unsigned int obgrid_size
;
65 width
= ALIGN(width
, IPU3_UAPI_ISP_VEC_ELEMS
/ 4);
66 obgrid_size
= PAGE_ALIGN(width
* height
*
67 sizeof(struct ipu3_uapi_obgrid_param
)) *
68 bi
->info
.isp
.sp
.iterator
.num_stripes
;
72 void *ipu3_css_fw_pipeline_params(struct ipu3_css
*css
, unsigned int pipe
,
73 enum imgu_abi_param_class cls
,
74 enum imgu_abi_memories mem
,
75 struct imgu_fw_isp_parameter
*par
,
76 size_t par_size
, void *binary_params
)
78 struct imgu_fw_info
*bi
=
79 &css
->fwp
->binary_header
[css
->pipes
[pipe
].bindex
];
81 if (par
->offset
+ par
->size
>
82 bi
->info
.isp
.sp
.mem_initializers
.params
[cls
][mem
].size
)
85 if (par
->size
!= par_size
)
86 pr_warn("parameter size doesn't match defined size\n");
88 if (par
->size
< par_size
)
91 return binary_params
+ par
->offset
;
94 void ipu3_css_fw_cleanup(struct ipu3_css
*css
)
96 struct imgu_device
*imgu
= dev_get_drvdata(css
->dev
);
101 for (i
= 0; i
< css
->fwp
->file_header
.binary_nr
; i
++)
102 ipu3_dmamap_free(imgu
, &css
->binary
[i
]);
106 release_firmware(css
->fw
);
112 int ipu3_css_fw_init(struct ipu3_css
*css
)
114 static const u32 BLOCK_MAX
= 65536;
115 struct imgu_device
*imgu
= dev_get_drvdata(css
->dev
);
116 struct device
*dev
= css
->dev
;
117 unsigned int i
, j
, binary_nr
;
120 r
= request_firmware(&css
->fw
, IMGU_FW_NAME
, css
->dev
);
124 /* Check and display fw header info */
126 css
->fwp
= (struct imgu_fw_header
*)css
->fw
->data
;
127 if (css
->fw
->size
< sizeof(struct imgu_fw_header
*) ||
128 css
->fwp
->file_header
.h_size
!= sizeof(struct imgu_fw_bi_file_h
))
130 if (sizeof(struct imgu_fw_bi_file_h
) +
131 css
->fwp
->file_header
.binary_nr
* sizeof(struct imgu_fw_info
) >
135 dev_info(dev
, "loaded firmware version %.64s, %u binaries, %zu bytes\n",
136 css
->fwp
->file_header
.version
, css
->fwp
->file_header
.binary_nr
,
139 /* Validate and display info on fw binaries */
141 binary_nr
= css
->fwp
->file_header
.binary_nr
;
147 for (i
= 0; i
< binary_nr
; i
++) {
148 struct imgu_fw_info
*bi
= &css
->fwp
->binary_header
[i
];
149 const char *name
= (void *)css
->fwp
+ bi
->blob
.prog_name_offset
;
152 if (bi
->blob
.prog_name_offset
>= css
->fw
->size
)
154 len
= strnlen(name
, css
->fw
->size
- bi
->blob
.prog_name_offset
);
155 if (len
+ 1 > css
->fw
->size
- bi
->blob
.prog_name_offset
||
156 len
+ 1 >= IMGU_ABI_MAX_BINARY_NAME
)
159 if (bi
->blob
.size
!= bi
->blob
.text_size
+ bi
->blob
.icache_size
160 + bi
->blob
.data_size
+ bi
->blob
.padding_size
)
162 if (bi
->blob
.offset
+ bi
->blob
.size
> css
->fw
->size
)
165 if (bi
->type
== IMGU_FW_BOOTLOADER_FIRMWARE
) {
167 if (bi
->info
.bl
.sw_state
>= css
->iomem_length
||
168 bi
->info
.bl
.num_dma_cmds
>= css
->iomem_length
||
169 bi
->info
.bl
.dma_cmd_list
>= css
->iomem_length
)
172 if (bi
->type
== IMGU_FW_SP_FIRMWARE
||
173 bi
->type
== IMGU_FW_SP1_FIRMWARE
) {
174 css
->fw_sp
[bi
->type
== IMGU_FW_SP_FIRMWARE
? 0 : 1] = i
;
175 if (bi
->info
.sp
.per_frame_data
>= css
->iomem_length
||
176 bi
->info
.sp
.init_dmem_data
>= css
->iomem_length
||
177 bi
->info
.sp
.host_sp_queue
>= css
->iomem_length
||
178 bi
->info
.sp
.isp_started
>= css
->iomem_length
||
179 bi
->info
.sp
.sw_state
>= css
->iomem_length
||
180 bi
->info
.sp
.sleep_mode
>= css
->iomem_length
||
181 bi
->info
.sp
.invalidate_tlb
>= css
->iomem_length
||
182 bi
->info
.sp
.host_sp_com
>= css
->iomem_length
||
183 bi
->info
.sp
.output
+ 12 >= css
->iomem_length
||
184 bi
->info
.sp
.host_sp_queues_initialized
>=
188 if (bi
->type
!= IMGU_FW_ISP_FIRMWARE
)
191 if (bi
->info
.isp
.sp
.pipeline
.mode
>= IPU3_CSS_PIPE_ID_NUM
)
194 if (bi
->info
.isp
.sp
.iterator
.num_stripes
>
195 IPU3_UAPI_MAX_STRIPES
)
198 if (bi
->info
.isp
.num_vf_formats
> IMGU_ABI_FRAME_FORMAT_NUM
||
199 bi
->info
.isp
.num_output_formats
> IMGU_ABI_FRAME_FORMAT_NUM
)
202 for (j
= 0; j
< bi
->info
.isp
.num_output_formats
; j
++)
203 if (bi
->info
.isp
.output_formats
[j
] < 0 ||
204 bi
->info
.isp
.output_formats
[j
] >=
205 IMGU_ABI_FRAME_FORMAT_NUM
)
207 for (j
= 0; j
< bi
->info
.isp
.num_vf_formats
; j
++)
208 if (bi
->info
.isp
.vf_formats
[j
] < 0 ||
209 bi
->info
.isp
.vf_formats
[j
] >=
210 IMGU_ABI_FRAME_FORMAT_NUM
)
213 if (bi
->info
.isp
.sp
.block
.block_width
<= 0 ||
214 bi
->info
.isp
.sp
.block
.block_width
> BLOCK_MAX
||
215 bi
->info
.isp
.sp
.block
.output_block_height
<= 0 ||
216 bi
->info
.isp
.sp
.block
.output_block_height
> BLOCK_MAX
)
219 if (bi
->blob
.memory_offsets
.offsets
[IMGU_ABI_PARAM_CLASS_PARAM
]
220 + sizeof(struct imgu_fw_param_memory_offsets
) >
222 bi
->blob
.memory_offsets
.offsets
[IMGU_ABI_PARAM_CLASS_CONFIG
]
223 + sizeof(struct imgu_fw_config_memory_offsets
) >
225 bi
->blob
.memory_offsets
.offsets
[IMGU_ABI_PARAM_CLASS_STATE
]
226 + sizeof(struct imgu_fw_state_memory_offsets
) >
230 ipu3_css_fw_show_binary(dev
, bi
, name
);
233 if (css
->fw_bl
== -1 || css
->fw_sp
[0] == -1 || css
->fw_sp
[1] == -1)
236 /* Allocate and map fw binaries into IMGU */
238 css
->binary
= kcalloc(binary_nr
, sizeof(*css
->binary
), GFP_KERNEL
);
244 for (i
= 0; i
< css
->fwp
->file_header
.binary_nr
; i
++) {
245 struct imgu_fw_info
*bi
= &css
->fwp
->binary_header
[i
];
246 void *blob
= (void *)css
->fwp
+ bi
->blob
.offset
;
247 size_t size
= bi
->blob
.size
;
249 if (!ipu3_dmamap_alloc(imgu
, &css
->binary
[i
], size
)) {
253 memcpy(css
->binary
[i
].vaddr
, blob
, size
);
259 dev_err(dev
, "invalid firmware binary, size %u\n", (int)css
->fw
->size
);
263 ipu3_css_fw_cleanup(css
);