xref: /openbmc/linux/drivers/media/i2c/ccs/ccs-data.c (revision 1bc0b1ba)
1a6b396f4SSakari Ailus // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2a6b396f4SSakari Ailus /*
3a6b396f4SSakari Ailus  * CCS static data binary parser library
4a6b396f4SSakari Ailus  *
5a6b396f4SSakari Ailus  * Copyright 2019--2020 Intel Corporation
6a6b396f4SSakari Ailus  */
7a6b396f4SSakari Ailus 
8a6b396f4SSakari Ailus #include <linux/device.h>
9a6b396f4SSakari Ailus #include <linux/errno.h>
10a6b396f4SSakari Ailus #include <linux/limits.h>
11a6b396f4SSakari Ailus #include <linux/mm.h>
12a6b396f4SSakari Ailus #include <linux/slab.h>
13a6b396f4SSakari Ailus #include <linux/types.h>
14a6b396f4SSakari Ailus 
15a6b396f4SSakari Ailus #include "ccs-data-defs.h"
16a6b396f4SSakari Ailus 
17a6b396f4SSakari Ailus struct bin_container {
18a6b396f4SSakari Ailus 	void *base;
19a6b396f4SSakari Ailus 	void *now;
20a6b396f4SSakari Ailus 	void *end;
21a6b396f4SSakari Ailus 	size_t size;
22a6b396f4SSakari Ailus };
23a6b396f4SSakari Ailus 
24a6b396f4SSakari Ailus static void *bin_alloc(struct bin_container *bin, size_t len)
25a6b396f4SSakari Ailus {
26a6b396f4SSakari Ailus 	void *ptr;
27a6b396f4SSakari Ailus 
28a6b396f4SSakari Ailus 	len = ALIGN(len, 8);
29a6b396f4SSakari Ailus 
30a6b396f4SSakari Ailus 	if (bin->end - bin->now < len)
31a6b396f4SSakari Ailus 		return NULL;
32a6b396f4SSakari Ailus 
33a6b396f4SSakari Ailus 	ptr = bin->now;
34a6b396f4SSakari Ailus 	bin->now += len;
35a6b396f4SSakari Ailus 
36a6b396f4SSakari Ailus 	return ptr;
37a6b396f4SSakari Ailus }
38a6b396f4SSakari Ailus 
39a6b396f4SSakari Ailus static void bin_reserve(struct bin_container *bin, size_t len)
40a6b396f4SSakari Ailus {
41a6b396f4SSakari Ailus 	bin->size += ALIGN(len, 8);
42a6b396f4SSakari Ailus }
43a6b396f4SSakari Ailus 
44a6b396f4SSakari Ailus static int bin_backing_alloc(struct bin_container *bin)
45a6b396f4SSakari Ailus {
46a6b396f4SSakari Ailus 	bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL);
47a6b396f4SSakari Ailus 	if (!bin->base)
48a6b396f4SSakari Ailus 		return -ENOMEM;
49a6b396f4SSakari Ailus 
50a6b396f4SSakari Ailus 	bin->end = bin->base + bin->size;
51a6b396f4SSakari Ailus 
52a6b396f4SSakari Ailus 	return 0;
53a6b396f4SSakari Ailus }
54a6b396f4SSakari Ailus 
55a6b396f4SSakari Ailus #define is_contained(var, endp)				\
56a6b396f4SSakari Ailus 	(sizeof(*var) <= (endp) - (void *)(var))
57a6b396f4SSakari Ailus #define has_headroom(ptr, headroom, endp)	\
58a6b396f4SSakari Ailus 	((headroom) <= (endp) - (void *)(ptr))
59a6b396f4SSakari Ailus #define is_contained_with_headroom(var, headroom, endp)		\
60a6b396f4SSakari Ailus 	(sizeof(*var) + (headroom) <= (endp) - (void *)(var))
61a6b396f4SSakari Ailus 
62a6b396f4SSakari Ailus static int
63a6b396f4SSakari Ailus ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len,
64a6b396f4SSakari Ailus 				size_t *__hlen, size_t *__plen,
65a6b396f4SSakari Ailus 				const void *endp)
66a6b396f4SSakari Ailus {
67a6b396f4SSakari Ailus 	size_t hlen, plen;
68a6b396f4SSakari Ailus 
69a6b396f4SSakari Ailus 	if (!is_contained(__len, endp))
70a6b396f4SSakari Ailus 		return -ENODATA;
71a6b396f4SSakari Ailus 
72a6b396f4SSakari Ailus 	switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) {
73a6b396f4SSakari Ailus 	case CCS_DATA_LENGTH_SPECIFIER_1:
74a6b396f4SSakari Ailus 		hlen = sizeof(*__len);
75a6b396f4SSakari Ailus 		plen = __len->length &
76a6b396f4SSakari Ailus 			((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1);
77a6b396f4SSakari Ailus 		break;
78a6b396f4SSakari Ailus 	case CCS_DATA_LENGTH_SPECIFIER_2: {
79a6b396f4SSakari Ailus 		struct __ccs_data_length_specifier2 *__len2 = (void *)__len;
80a6b396f4SSakari Ailus 
81a6b396f4SSakari Ailus 		if (!is_contained(__len2, endp))
82a6b396f4SSakari Ailus 			return -ENODATA;
83a6b396f4SSakari Ailus 
84a6b396f4SSakari Ailus 		hlen = sizeof(*__len2);
85a6b396f4SSakari Ailus 		plen = ((size_t)
86a6b396f4SSakari Ailus 			(__len2->length[0] &
87a6b396f4SSakari Ailus 			 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
88a6b396f4SSakari Ailus 			<< 8) + __len2->length[1];
89a6b396f4SSakari Ailus 		break;
90a6b396f4SSakari Ailus 	}
91a6b396f4SSakari Ailus 	case CCS_DATA_LENGTH_SPECIFIER_3: {
92a6b396f4SSakari Ailus 		struct __ccs_data_length_specifier3 *__len3 = (void *)__len;
93a6b396f4SSakari Ailus 
94a6b396f4SSakari Ailus 		if (!is_contained(__len3, endp))
95a6b396f4SSakari Ailus 			return -ENODATA;
96a6b396f4SSakari Ailus 
97a6b396f4SSakari Ailus 		hlen = sizeof(*__len3);
98a6b396f4SSakari Ailus 		plen = ((size_t)
99a6b396f4SSakari Ailus 			(__len3->length[0] &
100a6b396f4SSakari Ailus 			 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
101a6b396f4SSakari Ailus 			<< 16) + (__len3->length[0] << 8) + __len3->length[1];
102a6b396f4SSakari Ailus 		break;
103a6b396f4SSakari Ailus 	}
104a6b396f4SSakari Ailus 	default:
105a6b396f4SSakari Ailus 		return -EINVAL;
106a6b396f4SSakari Ailus 	}
107a6b396f4SSakari Ailus 
108a6b396f4SSakari Ailus 	if (!has_headroom(__len, hlen + plen, endp))
109a6b396f4SSakari Ailus 		return -ENODATA;
110a6b396f4SSakari Ailus 
111a6b396f4SSakari Ailus 	*__hlen = hlen;
112a6b396f4SSakari Ailus 	*__plen = plen;
113a6b396f4SSakari Ailus 
114a6b396f4SSakari Ailus 	return 0;
115a6b396f4SSakari Ailus }
116a6b396f4SSakari Ailus 
117a6b396f4SSakari Ailus static u8
118a6b396f4SSakari Ailus ccs_data_parse_format_version(const struct __ccs_data_block *block)
119a6b396f4SSakari Ailus {
120a6b396f4SSakari Ailus 	return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
121a6b396f4SSakari Ailus }
122a6b396f4SSakari Ailus 
123a6b396f4SSakari Ailus static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block,
124a6b396f4SSakari Ailus 				       bool is_first)
125a6b396f4SSakari Ailus {
126a6b396f4SSakari Ailus 	if (!is_first)
127a6b396f4SSakari Ailus 		return block->id;
128a6b396f4SSakari Ailus 
129a6b396f4SSakari Ailus 	return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1);
130a6b396f4SSakari Ailus }
131a6b396f4SSakari Ailus 
132a6b396f4SSakari Ailus static int ccs_data_parse_version(struct bin_container *bin,
133a6b396f4SSakari Ailus 				  struct ccs_data_container *ccsdata,
134a6b396f4SSakari Ailus 				  const void *payload, const void *endp)
135a6b396f4SSakari Ailus {
136a6b396f4SSakari Ailus 	const struct __ccs_data_block_version *v = payload;
137a6b396f4SSakari Ailus 	struct ccs_data_block_version *vv;
138a6b396f4SSakari Ailus 
139a6b396f4SSakari Ailus 	if (v + 1 != endp)
140a6b396f4SSakari Ailus 		return -ENODATA;
141a6b396f4SSakari Ailus 
142a6b396f4SSakari Ailus 	if (!bin->base) {
143a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(*ccsdata->version));
144a6b396f4SSakari Ailus 		return 0;
145a6b396f4SSakari Ailus 	}
146a6b396f4SSakari Ailus 
147a6b396f4SSakari Ailus 	ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version));
148a6b396f4SSakari Ailus 	if (!ccsdata->version)
149a6b396f4SSakari Ailus 		return -ENOMEM;
150a6b396f4SSakari Ailus 
151a6b396f4SSakari Ailus 	vv = ccsdata->version;
152a6b396f4SSakari Ailus 	vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
153a6b396f4SSakari Ailus 		v->static_data_version_major[1];
154a6b396f4SSakari Ailus 	vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
155*1bc0b1baSSakari Ailus 		v->static_data_version_minor[1];
156a6b396f4SSakari Ailus 	vv->date_year =  ((u16)v->year[0] << 8) + v->year[1];
157a6b396f4SSakari Ailus 	vv->date_month = v->month;
158a6b396f4SSakari Ailus 	vv->date_day = v->day;
159a6b396f4SSakari Ailus 
160a6b396f4SSakari Ailus 	return 0;
161a6b396f4SSakari Ailus }
162a6b396f4SSakari Ailus 
163a6b396f4SSakari Ailus static void print_ccs_data_version(struct device *dev,
164a6b396f4SSakari Ailus 				   struct ccs_data_block_version *v)
165a6b396f4SSakari Ailus {
166a6b396f4SSakari Ailus 	dev_dbg(dev,
167a6b396f4SSakari Ailus 		"static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n",
168a6b396f4SSakari Ailus 		v->version_major, v->version_minor,
169a6b396f4SSakari Ailus 		v->date_year, v->date_month, v->date_day);
170a6b396f4SSakari Ailus }
171a6b396f4SSakari Ailus 
172a6b396f4SSakari Ailus static int ccs_data_block_parse_header(const struct __ccs_data_block *block,
173a6b396f4SSakari Ailus 				       bool is_first, unsigned int *__block_id,
174a6b396f4SSakari Ailus 				       const void **payload,
175a6b396f4SSakari Ailus 				       const struct __ccs_data_block **next_block,
176a6b396f4SSakari Ailus 				       const void *endp, struct device *dev,
177a6b396f4SSakari Ailus 				       bool verbose)
178a6b396f4SSakari Ailus {
179a6b396f4SSakari Ailus 	size_t plen, hlen;
180a6b396f4SSakari Ailus 	u8 block_id;
181a6b396f4SSakari Ailus 	int rval;
182a6b396f4SSakari Ailus 
183a6b396f4SSakari Ailus 	if (!is_contained(block, endp))
184a6b396f4SSakari Ailus 		return -ENODATA;
185a6b396f4SSakari Ailus 
186a6b396f4SSakari Ailus 	rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen,
187a6b396f4SSakari Ailus 					       endp);
188a6b396f4SSakari Ailus 	if (rval < 0)
189a6b396f4SSakari Ailus 		return rval;
190a6b396f4SSakari Ailus 
191a6b396f4SSakari Ailus 	block_id = ccs_data_parse_block_id(block, is_first);
192a6b396f4SSakari Ailus 
193a6b396f4SSakari Ailus 	if (verbose)
194a6b396f4SSakari Ailus 		dev_dbg(dev,
195a6b396f4SSakari Ailus 			"Block ID 0x%2.2x, header length %zu, payload length %zu\n",
196a6b396f4SSakari Ailus 			block_id, hlen, plen);
197a6b396f4SSakari Ailus 
198a6b396f4SSakari Ailus 	if (!has_headroom(&block->length, hlen + plen, endp))
199a6b396f4SSakari Ailus 		return -ENODATA;
200a6b396f4SSakari Ailus 
201a6b396f4SSakari Ailus 	if (__block_id)
202a6b396f4SSakari Ailus 		*__block_id = block_id;
203a6b396f4SSakari Ailus 
204a6b396f4SSakari Ailus 	if (payload)
205a6b396f4SSakari Ailus 		*payload = (void *)&block->length + hlen;
206a6b396f4SSakari Ailus 
207a6b396f4SSakari Ailus 	if (next_block)
208a6b396f4SSakari Ailus 		*next_block = (void *)&block->length + hlen + plen;
209a6b396f4SSakari Ailus 
210a6b396f4SSakari Ailus 	return 0;
211a6b396f4SSakari Ailus }
212a6b396f4SSakari Ailus 
213a6b396f4SSakari Ailus static int ccs_data_parse_regs(struct bin_container *bin,
214a6b396f4SSakari Ailus 			       struct ccs_reg **__regs,
215a6b396f4SSakari Ailus 			       size_t *__num_regs, const void *payload,
216a6b396f4SSakari Ailus 			       const void *endp, struct device *dev)
217a6b396f4SSakari Ailus {
218a6b396f4SSakari Ailus 	struct ccs_reg *regs_base, *regs;
219a6b396f4SSakari Ailus 	size_t num_regs = 0;
220a6b396f4SSakari Ailus 	u16 addr = 0;
221a6b396f4SSakari Ailus 
222a6b396f4SSakari Ailus 	if (bin->base && __regs) {
223a6b396f4SSakari Ailus 		regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs);
224a6b396f4SSakari Ailus 		if (!regs)
225a6b396f4SSakari Ailus 			return -ENOMEM;
226a6b396f4SSakari Ailus 	}
227a6b396f4SSakari Ailus 
228a6b396f4SSakari Ailus 	while (payload < endp && num_regs < INT_MAX) {
229a6b396f4SSakari Ailus 		const struct __ccs_data_block_regs *r = payload;
230a6b396f4SSakari Ailus 		size_t len;
231a6b396f4SSakari Ailus 		const void *data;
232a6b396f4SSakari Ailus 
233a6b396f4SSakari Ailus 		if (!is_contained(r, endp))
234a6b396f4SSakari Ailus 			return -ENODATA;
235a6b396f4SSakari Ailus 
236a6b396f4SSakari Ailus 		switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) {
237a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_REGS_SEL_REGS:
238a6b396f4SSakari Ailus 			addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK;
239a6b396f4SSakari Ailus 			len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK)
240a6b396f4SSakari Ailus 			       >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1;
241a6b396f4SSakari Ailus 
242a6b396f4SSakari Ailus 			if (!is_contained_with_headroom(r, len, endp))
243a6b396f4SSakari Ailus 				return -ENODATA;
244a6b396f4SSakari Ailus 
245a6b396f4SSakari Ailus 			data = r + 1;
246a6b396f4SSakari Ailus 			break;
247a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_REGS_SEL_REGS2: {
248a6b396f4SSakari Ailus 			const struct __ccs_data_block_regs2 *r2 = payload;
249a6b396f4SSakari Ailus 
250a6b396f4SSakari Ailus 			if (!is_contained(r2, endp))
251a6b396f4SSakari Ailus 				return -ENODATA;
252a6b396f4SSakari Ailus 
253a6b396f4SSakari Ailus 			addr += ((u16)(r2->reg_len &
254a6b396f4SSakari Ailus 				       CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8)
255a6b396f4SSakari Ailus 				+ r2->addr;
256a6b396f4SSakari Ailus 			len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK)
257a6b396f4SSakari Ailus 			       >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1;
258a6b396f4SSakari Ailus 
259a6b396f4SSakari Ailus 			if (!is_contained_with_headroom(r2, len, endp))
260a6b396f4SSakari Ailus 				return -ENODATA;
261a6b396f4SSakari Ailus 
262a6b396f4SSakari Ailus 			data = r2 + 1;
263a6b396f4SSakari Ailus 			break;
264a6b396f4SSakari Ailus 		}
265a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_REGS_SEL_REGS3: {
266a6b396f4SSakari Ailus 			const struct __ccs_data_block_regs3 *r3 = payload;
267a6b396f4SSakari Ailus 
268a6b396f4SSakari Ailus 			if (!is_contained(r3, endp))
269a6b396f4SSakari Ailus 				return -ENODATA;
270a6b396f4SSakari Ailus 
271a6b396f4SSakari Ailus 			addr = ((u16)r3->addr[0] << 8) + r3->addr[1];
272a6b396f4SSakari Ailus 			len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1;
273a6b396f4SSakari Ailus 
274a6b396f4SSakari Ailus 			if (!is_contained_with_headroom(r3, len, endp))
275a6b396f4SSakari Ailus 				return -ENODATA;
276a6b396f4SSakari Ailus 
277a6b396f4SSakari Ailus 			data = r3 + 1;
278a6b396f4SSakari Ailus 			break;
279a6b396f4SSakari Ailus 		}
280a6b396f4SSakari Ailus 		default:
281a6b396f4SSakari Ailus 			return -EINVAL;
282a6b396f4SSakari Ailus 		}
283a6b396f4SSakari Ailus 
284a6b396f4SSakari Ailus 		num_regs++;
285a6b396f4SSakari Ailus 
286a6b396f4SSakari Ailus 		if (!bin->base) {
287a6b396f4SSakari Ailus 			bin_reserve(bin, len);
288a6b396f4SSakari Ailus 		} else if (__regs) {
289a6b396f4SSakari Ailus 			regs->addr = addr;
290a6b396f4SSakari Ailus 			regs->len = len;
291a6b396f4SSakari Ailus 			regs->value = bin_alloc(bin, len);
292a6b396f4SSakari Ailus 			if (!regs->value)
293a6b396f4SSakari Ailus 				return -ENOMEM;
294a6b396f4SSakari Ailus 
295a6b396f4SSakari Ailus 			memcpy(regs->value, data, len);
296a6b396f4SSakari Ailus 			regs++;
297a6b396f4SSakari Ailus 		}
298a6b396f4SSakari Ailus 
299a6b396f4SSakari Ailus 		addr += len;
300a6b396f4SSakari Ailus 		payload = data + len;
301a6b396f4SSakari Ailus 	}
302a6b396f4SSakari Ailus 
303a6b396f4SSakari Ailus 	if (!bin->base)
304a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(*regs) * num_regs);
305a6b396f4SSakari Ailus 
306a6b396f4SSakari Ailus 	if (__num_regs)
307a6b396f4SSakari Ailus 		*__num_regs = num_regs;
308a6b396f4SSakari Ailus 
309a6b396f4SSakari Ailus 	if (bin->base && __regs)
310a6b396f4SSakari Ailus 		*__regs = regs_base;
311a6b396f4SSakari Ailus 
312a6b396f4SSakari Ailus 	return 0;
313a6b396f4SSakari Ailus }
314a6b396f4SSakari Ailus 
315a6b396f4SSakari Ailus static int ccs_data_parse_reg_rules(struct bin_container *bin,
316a6b396f4SSakari Ailus 				    struct ccs_reg **__regs,
317a6b396f4SSakari Ailus 				    size_t *__num_regs,
318a6b396f4SSakari Ailus 				    const void *payload,
319a6b396f4SSakari Ailus 				    const void *endp, struct device *dev)
320a6b396f4SSakari Ailus {
321a6b396f4SSakari Ailus 	int rval;
322a6b396f4SSakari Ailus 
323a6b396f4SSakari Ailus 	if (!bin->base)
324a6b396f4SSakari Ailus 		return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev);
325a6b396f4SSakari Ailus 
326a6b396f4SSakari Ailus 	rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev);
327a6b396f4SSakari Ailus 	if (rval)
328a6b396f4SSakari Ailus 		return rval;
329a6b396f4SSakari Ailus 
330a6b396f4SSakari Ailus 	return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp,
331a6b396f4SSakari Ailus 				   dev);
332a6b396f4SSakari Ailus }
333a6b396f4SSakari Ailus 
334a6b396f4SSakari Ailus static void assign_ffd_entry(struct ccs_frame_format_desc *desc,
335a6b396f4SSakari Ailus 			     const struct __ccs_data_block_ffd_entry *ent)
336a6b396f4SSakari Ailus {
337a6b396f4SSakari Ailus 	desc->pixelcode = ent->pixelcode;
338a6b396f4SSakari Ailus 	desc->value = ((u16)ent->value[0] << 8) + ent->value[1];
339a6b396f4SSakari Ailus }
340a6b396f4SSakari Ailus 
341a6b396f4SSakari Ailus static int ccs_data_parse_ffd(struct bin_container *bin,
342a6b396f4SSakari Ailus 			      struct ccs_frame_format_descs **ffd,
343a6b396f4SSakari Ailus 			      const void *payload,
344a6b396f4SSakari Ailus 			      const void *endp, struct device *dev)
345a6b396f4SSakari Ailus {
346a6b396f4SSakari Ailus 	const struct __ccs_data_block_ffd *__ffd = payload;
347a6b396f4SSakari Ailus 	const struct __ccs_data_block_ffd_entry *__entry;
348a6b396f4SSakari Ailus 	unsigned int i;
349a6b396f4SSakari Ailus 
350a6b396f4SSakari Ailus 	if (!is_contained(__ffd, endp))
351a6b396f4SSakari Ailus 		return -ENODATA;
352a6b396f4SSakari Ailus 
353a6b396f4SSakari Ailus 	if ((void *)__ffd + sizeof(*__ffd) +
354a6b396f4SSakari Ailus 	    ((u32)__ffd->num_column_descs +
355a6b396f4SSakari Ailus 	     (u32)__ffd->num_row_descs) *
356a6b396f4SSakari Ailus 	    sizeof(struct __ccs_data_block_ffd_entry) != endp)
357a6b396f4SSakari Ailus 		return -ENODATA;
358a6b396f4SSakari Ailus 
359a6b396f4SSakari Ailus 	if (!bin->base) {
360a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(**ffd));
361a6b396f4SSakari Ailus 		bin_reserve(bin, __ffd->num_column_descs *
362a6b396f4SSakari Ailus 			    sizeof(struct ccs_frame_format_desc));
363a6b396f4SSakari Ailus 		bin_reserve(bin, __ffd->num_row_descs *
364a6b396f4SSakari Ailus 			    sizeof(struct ccs_frame_format_desc));
365a6b396f4SSakari Ailus 
366a6b396f4SSakari Ailus 		return 0;
367a6b396f4SSakari Ailus 	}
368a6b396f4SSakari Ailus 
369a6b396f4SSakari Ailus 	*ffd = bin_alloc(bin, sizeof(**ffd));
370a6b396f4SSakari Ailus 	if (!*ffd)
371a6b396f4SSakari Ailus 		return -ENOMEM;
372a6b396f4SSakari Ailus 
373a6b396f4SSakari Ailus 	(*ffd)->num_column_descs = __ffd->num_column_descs;
374a6b396f4SSakari Ailus 	(*ffd)->num_row_descs = __ffd->num_row_descs;
375a6b396f4SSakari Ailus 	__entry = (void *)(__ffd + 1);
376a6b396f4SSakari Ailus 
377a6b396f4SSakari Ailus 	(*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs *
378a6b396f4SSakari Ailus 					 sizeof(*(*ffd)->column_descs));
379a6b396f4SSakari Ailus 	if (!(*ffd)->column_descs)
380a6b396f4SSakari Ailus 		return -ENOMEM;
381a6b396f4SSakari Ailus 
382a6b396f4SSakari Ailus 	for (i = 0; i < __ffd->num_column_descs; i++, __entry++)
383a6b396f4SSakari Ailus 		assign_ffd_entry(&(*ffd)->column_descs[i], __entry);
384a6b396f4SSakari Ailus 
385a6b396f4SSakari Ailus 	(*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs *
386a6b396f4SSakari Ailus 				      sizeof(*(*ffd)->row_descs));
387a6b396f4SSakari Ailus 	if (!(*ffd)->row_descs)
388a6b396f4SSakari Ailus 		return -ENOMEM;
389a6b396f4SSakari Ailus 
390a6b396f4SSakari Ailus 	for (i = 0; i < __ffd->num_row_descs; i++, __entry++)
391a6b396f4SSakari Ailus 		assign_ffd_entry(&(*ffd)->row_descs[i], __entry);
392a6b396f4SSakari Ailus 
393a6b396f4SSakari Ailus 	if (__entry != endp)
394a6b396f4SSakari Ailus 		return -EPROTO;
395a6b396f4SSakari Ailus 
396a6b396f4SSakari Ailus 	return 0;
397a6b396f4SSakari Ailus }
398a6b396f4SSakari Ailus 
399a6b396f4SSakari Ailus static int ccs_data_parse_pdaf_readout(struct bin_container *bin,
400a6b396f4SSakari Ailus 				       struct ccs_pdaf_readout **pdaf_readout,
401a6b396f4SSakari Ailus 				       const void *payload,
402a6b396f4SSakari Ailus 				       const void *endp, struct device *dev)
403a6b396f4SSakari Ailus {
404a6b396f4SSakari Ailus 	const struct __ccs_data_block_pdaf_readout *__pdaf = payload;
405a6b396f4SSakari Ailus 
406a6b396f4SSakari Ailus 	if (!is_contained(__pdaf, endp))
407a6b396f4SSakari Ailus 		return -ENODATA;
408a6b396f4SSakari Ailus 
409a6b396f4SSakari Ailus 	if (!bin->base) {
410a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(**pdaf_readout));
411a6b396f4SSakari Ailus 	} else {
412a6b396f4SSakari Ailus 		*pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout));
413a6b396f4SSakari Ailus 		if (!*pdaf_readout)
414a6b396f4SSakari Ailus 			return -ENOMEM;
415a6b396f4SSakari Ailus 
416a6b396f4SSakari Ailus 		(*pdaf_readout)->pdaf_readout_info_order =
417a6b396f4SSakari Ailus 			__pdaf->pdaf_readout_info_order;
418a6b396f4SSakari Ailus 	}
419a6b396f4SSakari Ailus 
420a6b396f4SSakari Ailus 	return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd,
421a6b396f4SSakari Ailus 				  __pdaf + 1, endp, dev);
422a6b396f4SSakari Ailus }
423a6b396f4SSakari Ailus 
424a6b396f4SSakari Ailus static int ccs_data_parse_rules(struct bin_container *bin,
425a6b396f4SSakari Ailus 				struct ccs_rule **__rules,
426a6b396f4SSakari Ailus 				size_t *__num_rules, const void *payload,
427a6b396f4SSakari Ailus 				const void *endp, struct device *dev)
428a6b396f4SSakari Ailus {
429a6b396f4SSakari Ailus 	struct ccs_rule *rules_base, *rules = NULL, *next_rule;
430a6b396f4SSakari Ailus 	size_t num_rules = 0;
431a6b396f4SSakari Ailus 	const void *__next_rule = payload;
432a6b396f4SSakari Ailus 	int rval;
433a6b396f4SSakari Ailus 
434a6b396f4SSakari Ailus 	if (bin->base) {
435a6b396f4SSakari Ailus 		rules_base = next_rule =
436a6b396f4SSakari Ailus 			bin_alloc(bin, sizeof(*rules) * *__num_rules);
437a6b396f4SSakari Ailus 		if (!rules_base)
438a6b396f4SSakari Ailus 			return -ENOMEM;
439a6b396f4SSakari Ailus 	}
440a6b396f4SSakari Ailus 
441a6b396f4SSakari Ailus 	while (__next_rule < endp) {
442a6b396f4SSakari Ailus 		size_t rule_hlen, rule_plen, rule_plen2;
443a6b396f4SSakari Ailus 		const u8 *__rule_type;
444a6b396f4SSakari Ailus 		const void *rule_payload;
445a6b396f4SSakari Ailus 
446a6b396f4SSakari Ailus 		/* Size of a single rule */
447a6b396f4SSakari Ailus 		rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen,
448a6b396f4SSakari Ailus 						       &rule_plen, endp);
449a6b396f4SSakari Ailus 
450a6b396f4SSakari Ailus 		if (rval < 0)
451a6b396f4SSakari Ailus 			return rval;
452a6b396f4SSakari Ailus 
453a6b396f4SSakari Ailus 		__rule_type = __next_rule + rule_hlen;
454a6b396f4SSakari Ailus 
455a6b396f4SSakari Ailus 		if (!is_contained(__rule_type, endp))
456a6b396f4SSakari Ailus 			return -ENODATA;
457a6b396f4SSakari Ailus 
458a6b396f4SSakari Ailus 		rule_payload = __rule_type + 1;
459a6b396f4SSakari Ailus 		rule_plen2 = rule_plen - sizeof(*__rule_type);
460a6b396f4SSakari Ailus 
461a6b396f4SSakari Ailus 		switch (*__rule_type) {
462a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_RULE_ID_IF: {
463a6b396f4SSakari Ailus 			const struct __ccs_data_block_rule_if *__if_rules =
464a6b396f4SSakari Ailus 				rule_payload;
465a6b396f4SSakari Ailus 			const size_t __num_if_rules =
466a6b396f4SSakari Ailus 				rule_plen2 / sizeof(*__if_rules);
467a6b396f4SSakari Ailus 			struct ccs_if_rule *if_rule;
468a6b396f4SSakari Ailus 
469a6b396f4SSakari Ailus 			if (!has_headroom(__if_rules,
470a6b396f4SSakari Ailus 					  sizeof(*__if_rules) * __num_if_rules,
471a6b396f4SSakari Ailus 					  rule_payload + rule_plen2))
472a6b396f4SSakari Ailus 				return -ENODATA;
473a6b396f4SSakari Ailus 
474a6b396f4SSakari Ailus 			/* Also check there is no extra data */
475a6b396f4SSakari Ailus 			if (__if_rules + __num_if_rules !=
476a6b396f4SSakari Ailus 			    rule_payload + rule_plen2)
477a6b396f4SSakari Ailus 				return -EINVAL;
478a6b396f4SSakari Ailus 
479a6b396f4SSakari Ailus 			if (!bin->base) {
480a6b396f4SSakari Ailus 				bin_reserve(bin,
481a6b396f4SSakari Ailus 					    sizeof(*if_rule) *
482a6b396f4SSakari Ailus 					    __num_if_rules);
483a6b396f4SSakari Ailus 				num_rules++;
484a6b396f4SSakari Ailus 			} else {
485a6b396f4SSakari Ailus 				unsigned int i;
486a6b396f4SSakari Ailus 
487a6b396f4SSakari Ailus 				rules = next_rule;
488a6b396f4SSakari Ailus 				next_rule++;
489a6b396f4SSakari Ailus 
490a6b396f4SSakari Ailus 				if_rule = bin_alloc(bin,
491a6b396f4SSakari Ailus 						    sizeof(*if_rule) *
492a6b396f4SSakari Ailus 						    __num_if_rules);
493a6b396f4SSakari Ailus 				if (!if_rule)
494a6b396f4SSakari Ailus 					return -ENOMEM;
495a6b396f4SSakari Ailus 
496a6b396f4SSakari Ailus 				for (i = 0; i < __num_if_rules; i++) {
497a6b396f4SSakari Ailus 					if_rule[i].addr =
498a6b396f4SSakari Ailus 						((u16)__if_rules[i].addr[0]
499a6b396f4SSakari Ailus 						 << 8) +
500a6b396f4SSakari Ailus 						__if_rules[i].addr[1];
501a6b396f4SSakari Ailus 					if_rule[i].value = __if_rules[i].value;
502a6b396f4SSakari Ailus 					if_rule[i].mask = __if_rules[i].mask;
503a6b396f4SSakari Ailus 				}
504a6b396f4SSakari Ailus 
505a6b396f4SSakari Ailus 				rules->if_rules = if_rule;
506a6b396f4SSakari Ailus 				rules->num_if_rules = __num_if_rules;
507a6b396f4SSakari Ailus 			}
508a6b396f4SSakari Ailus 			break;
509a6b396f4SSakari Ailus 		}
510a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
511a6b396f4SSakari Ailus 			rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
512a6b396f4SSakari Ailus 							&rules->num_read_only_regs,
513a6b396f4SSakari Ailus 							rule_payload,
514a6b396f4SSakari Ailus 							rule_payload + rule_plen2,
515a6b396f4SSakari Ailus 							dev);
516a6b396f4SSakari Ailus 			if (rval)
517a6b396f4SSakari Ailus 				return rval;
518a6b396f4SSakari Ailus 			break;
519a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_RULE_ID_FFD:
520a6b396f4SSakari Ailus 			rval = ccs_data_parse_ffd(bin, &rules->frame_format,
521a6b396f4SSakari Ailus 						  rule_payload,
522a6b396f4SSakari Ailus 						  rule_payload + rule_plen2,
523a6b396f4SSakari Ailus 						  dev);
524a6b396f4SSakari Ailus 			if (rval)
525a6b396f4SSakari Ailus 				return rval;
526a6b396f4SSakari Ailus 			break;
527a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_RULE_ID_MSR:
528a6b396f4SSakari Ailus 			rval = ccs_data_parse_reg_rules(bin,
529a6b396f4SSakari Ailus 							&rules->manufacturer_regs,
530a6b396f4SSakari Ailus 							&rules->num_manufacturer_regs,
531a6b396f4SSakari Ailus 							rule_payload,
532a6b396f4SSakari Ailus 							rule_payload + rule_plen2,
533a6b396f4SSakari Ailus 							dev);
534a6b396f4SSakari Ailus 			if (rval)
535a6b396f4SSakari Ailus 				return rval;
536a6b396f4SSakari Ailus 			break;
537a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
538a6b396f4SSakari Ailus 			rval = ccs_data_parse_pdaf_readout(bin,
539a6b396f4SSakari Ailus 							   &rules->pdaf_readout,
540a6b396f4SSakari Ailus 							   rule_payload,
541a6b396f4SSakari Ailus 							   rule_payload + rule_plen2,
542a6b396f4SSakari Ailus 							   dev);
543a6b396f4SSakari Ailus 			if (rval)
544a6b396f4SSakari Ailus 				return rval;
545a6b396f4SSakari Ailus 			break;
546a6b396f4SSakari Ailus 		default:
547a6b396f4SSakari Ailus 			dev_dbg(dev,
548a6b396f4SSakari Ailus 				"Don't know how to handle rule type %u!\n",
549a6b396f4SSakari Ailus 				*__rule_type);
550a6b396f4SSakari Ailus 			return -EINVAL;
551a6b396f4SSakari Ailus 		}
552a6b396f4SSakari Ailus 		__next_rule = __next_rule + rule_hlen + rule_plen;
553a6b396f4SSakari Ailus 	}
554a6b396f4SSakari Ailus 
555a6b396f4SSakari Ailus 	if (!bin->base) {
556a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(*rules) * num_rules);
557a6b396f4SSakari Ailus 		*__num_rules = num_rules;
558a6b396f4SSakari Ailus 	} else {
559a6b396f4SSakari Ailus 		*__rules = rules_base;
560a6b396f4SSakari Ailus 	}
561a6b396f4SSakari Ailus 
562a6b396f4SSakari Ailus 	return 0;
563a6b396f4SSakari Ailus }
564a6b396f4SSakari Ailus 
565a6b396f4SSakari Ailus static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf,
566a6b396f4SSakari Ailus 			       const void *payload, const void *endp,
567a6b396f4SSakari Ailus 			       struct device *dev)
568a6b396f4SSakari Ailus {
569a6b396f4SSakari Ailus 	const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload;
570a6b396f4SSakari Ailus 	const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group;
571a6b396f4SSakari Ailus 	const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc;
572a6b396f4SSakari Ailus 	unsigned int i;
573a6b396f4SSakari Ailus 	u16 num_block_desc_groups;
574a6b396f4SSakari Ailus 	u8 max_block_type_id = 0;
575a6b396f4SSakari Ailus 	const u8 *__num_pixel_descs;
576a6b396f4SSakari Ailus 
577a6b396f4SSakari Ailus 	if (!is_contained(__pdaf, endp))
578a6b396f4SSakari Ailus 		return -ENODATA;
579a6b396f4SSakari Ailus 
580a6b396f4SSakari Ailus 	if (bin->base) {
581a6b396f4SSakari Ailus 		*pdaf = bin_alloc(bin, sizeof(**pdaf));
582a6b396f4SSakari Ailus 		if (!*pdaf)
583a6b396f4SSakari Ailus 			return -ENOMEM;
584a6b396f4SSakari Ailus 	} else {
585a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(**pdaf));
586a6b396f4SSakari Ailus 	}
587a6b396f4SSakari Ailus 
588a6b396f4SSakari Ailus 	num_block_desc_groups =
589a6b396f4SSakari Ailus 		((u16)__pdaf->num_block_desc_groups[0] << 8) +
590a6b396f4SSakari Ailus 		__pdaf->num_block_desc_groups[1];
591a6b396f4SSakari Ailus 
592a6b396f4SSakari Ailus 	if (bin->base) {
593a6b396f4SSakari Ailus 		(*pdaf)->main_offset_x =
594a6b396f4SSakari Ailus 			((u16)__pdaf->main_offset_x[0] << 8) +
595a6b396f4SSakari Ailus 			__pdaf->main_offset_x[1];
596a6b396f4SSakari Ailus 		(*pdaf)->main_offset_y =
597a6b396f4SSakari Ailus 			((u16)__pdaf->main_offset_y[0] << 8) +
598a6b396f4SSakari Ailus 			__pdaf->main_offset_y[1];
599a6b396f4SSakari Ailus 		(*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type;
600a6b396f4SSakari Ailus 		(*pdaf)->block_width = __pdaf->block_width;
601a6b396f4SSakari Ailus 		(*pdaf)->block_height = __pdaf->block_height;
602a6b396f4SSakari Ailus 		(*pdaf)->num_block_desc_groups = num_block_desc_groups;
603a6b396f4SSakari Ailus 	}
604a6b396f4SSakari Ailus 
605a6b396f4SSakari Ailus 	__bdesc_group = (const void *)(__pdaf + 1);
606a6b396f4SSakari Ailus 
607a6b396f4SSakari Ailus 	if (bin->base) {
608a6b396f4SSakari Ailus 		(*pdaf)->block_desc_groups =
609a6b396f4SSakari Ailus 			bin_alloc(bin,
610a6b396f4SSakari Ailus 				  sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
611a6b396f4SSakari Ailus 				  num_block_desc_groups);
612a6b396f4SSakari Ailus 		if (!(*pdaf)->block_desc_groups)
613a6b396f4SSakari Ailus 			return -ENOMEM;
614a6b396f4SSakari Ailus 	} else {
615a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
616a6b396f4SSakari Ailus 			    num_block_desc_groups);
617a6b396f4SSakari Ailus 	}
618a6b396f4SSakari Ailus 
619a6b396f4SSakari Ailus 	for (i = 0; i < num_block_desc_groups; i++) {
620a6b396f4SSakari Ailus 		const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc;
621a6b396f4SSakari Ailus 		u16 num_block_descs;
622a6b396f4SSakari Ailus 		unsigned int j;
623a6b396f4SSakari Ailus 
624a6b396f4SSakari Ailus 		if (!is_contained(__bdesc_group, endp))
625a6b396f4SSakari Ailus 			return -ENODATA;
626a6b396f4SSakari Ailus 
627a6b396f4SSakari Ailus 		num_block_descs =
628a6b396f4SSakari Ailus 			((u16)__bdesc_group->num_block_descs[0] << 8) +
629a6b396f4SSakari Ailus 			__bdesc_group->num_block_descs[1];
630a6b396f4SSakari Ailus 
631a6b396f4SSakari Ailus 		if (bin->base) {
632a6b396f4SSakari Ailus 			(*pdaf)->block_desc_groups[i].repeat_y =
633a6b396f4SSakari Ailus 				__bdesc_group->repeat_y;
634a6b396f4SSakari Ailus 			(*pdaf)->block_desc_groups[i].num_block_descs =
635a6b396f4SSakari Ailus 				num_block_descs;
636a6b396f4SSakari Ailus 		}
637a6b396f4SSakari Ailus 
638a6b396f4SSakari Ailus 		__bdesc = (const void *)(__bdesc_group + 1);
639a6b396f4SSakari Ailus 
640a6b396f4SSakari Ailus 		if (bin->base) {
641a6b396f4SSakari Ailus 			(*pdaf)->block_desc_groups[i].block_descs =
642a6b396f4SSakari Ailus 				bin_alloc(bin,
643a6b396f4SSakari Ailus 					  sizeof(struct ccs_pdaf_pix_loc_block_desc) *
644a6b396f4SSakari Ailus 					  num_block_descs);
645a6b396f4SSakari Ailus 			if (!(*pdaf)->block_desc_groups[i].block_descs)
646a6b396f4SSakari Ailus 				return -ENOMEM;
647a6b396f4SSakari Ailus 		} else {
648a6b396f4SSakari Ailus 			bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) *
649a6b396f4SSakari Ailus 				    num_block_descs);
650a6b396f4SSakari Ailus 		}
651a6b396f4SSakari Ailus 
652a6b396f4SSakari Ailus 		for (j = 0; j < num_block_descs; j++, __bdesc++) {
653a6b396f4SSakari Ailus 			struct ccs_pdaf_pix_loc_block_desc *bdesc;
654a6b396f4SSakari Ailus 
655a6b396f4SSakari Ailus 			if (!is_contained(__bdesc, endp))
656a6b396f4SSakari Ailus 				return -ENODATA;
657a6b396f4SSakari Ailus 
658a6b396f4SSakari Ailus 			if (max_block_type_id <= __bdesc->block_type_id)
659a6b396f4SSakari Ailus 				max_block_type_id = __bdesc->block_type_id + 1;
660a6b396f4SSakari Ailus 
661a6b396f4SSakari Ailus 			if (!bin->base)
662a6b396f4SSakari Ailus 				continue;
663a6b396f4SSakari Ailus 
664a6b396f4SSakari Ailus 			bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j];
665a6b396f4SSakari Ailus 
666a6b396f4SSakari Ailus 			bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8)
667a6b396f4SSakari Ailus 				+ __bdesc->repeat_x[1];
668a6b396f4SSakari Ailus 
669a6b396f4SSakari Ailus 			if (__bdesc->block_type_id >= num_block_descs)
670a6b396f4SSakari Ailus 				return -EINVAL;
671a6b396f4SSakari Ailus 
672a6b396f4SSakari Ailus 			bdesc->block_type_id = __bdesc->block_type_id;
673a6b396f4SSakari Ailus 		}
674a6b396f4SSakari Ailus 
675a6b396f4SSakari Ailus 		__bdesc_group = (const void *)__bdesc;
676a6b396f4SSakari Ailus 	}
677a6b396f4SSakari Ailus 
678a6b396f4SSakari Ailus 	__num_pixel_descs = (const void *)__bdesc_group;
679a6b396f4SSakari Ailus 
680a6b396f4SSakari Ailus 	if (bin->base) {
681a6b396f4SSakari Ailus 		(*pdaf)->pixel_desc_groups =
682a6b396f4SSakari Ailus 			bin_alloc(bin,
683a6b396f4SSakari Ailus 				  sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
684a6b396f4SSakari Ailus 				  max_block_type_id);
685a6b396f4SSakari Ailus 		if (!(*pdaf)->pixel_desc_groups)
686a6b396f4SSakari Ailus 			return -ENOMEM;
687a6b396f4SSakari Ailus 		(*pdaf)->num_pixel_desc_grups = max_block_type_id;
688a6b396f4SSakari Ailus 	} else {
689a6b396f4SSakari Ailus 		bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
690a6b396f4SSakari Ailus 			    max_block_type_id);
691a6b396f4SSakari Ailus 	}
692a6b396f4SSakari Ailus 
693a6b396f4SSakari Ailus 	for (i = 0; i < max_block_type_id; i++) {
694a6b396f4SSakari Ailus 		struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup;
695a6b396f4SSakari Ailus 		unsigned int j;
696a6b396f4SSakari Ailus 
697a6b396f4SSakari Ailus 		if (!is_contained(__num_pixel_descs, endp))
698a6b396f4SSakari Ailus 			return -ENODATA;
699a6b396f4SSakari Ailus 
700a6b396f4SSakari Ailus 		if (bin->base) {
701a6b396f4SSakari Ailus 			pdgroup = &(*pdaf)->pixel_desc_groups[i];
702a6b396f4SSakari Ailus 			pdgroup->descs =
703a6b396f4SSakari Ailus 				bin_alloc(bin,
704a6b396f4SSakari Ailus 					  sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
705a6b396f4SSakari Ailus 					  *__num_pixel_descs);
706a6b396f4SSakari Ailus 			if (!pdgroup->descs)
707a6b396f4SSakari Ailus 				return -ENOMEM;
708a6b396f4SSakari Ailus 			pdgroup->num_descs = *__num_pixel_descs;
709a6b396f4SSakari Ailus 		} else {
710a6b396f4SSakari Ailus 			bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
711a6b396f4SSakari Ailus 				    *__num_pixel_descs);
712a6b396f4SSakari Ailus 		}
713a6b396f4SSakari Ailus 
714a6b396f4SSakari Ailus 		__pixel_desc = (const void *)(__num_pixel_descs + 1);
715a6b396f4SSakari Ailus 
716a6b396f4SSakari Ailus 		for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) {
717a6b396f4SSakari Ailus 			struct ccs_pdaf_pix_loc_pixel_desc *pdesc;
718a6b396f4SSakari Ailus 
719a6b396f4SSakari Ailus 			if (!is_contained(__pixel_desc, endp))
720a6b396f4SSakari Ailus 				return -ENODATA;
721a6b396f4SSakari Ailus 
722a6b396f4SSakari Ailus 			if (!bin->base)
723a6b396f4SSakari Ailus 				continue;
724a6b396f4SSakari Ailus 
725a6b396f4SSakari Ailus 			pdesc = &pdgroup->descs[j];
726a6b396f4SSakari Ailus 			pdesc->pixel_type = __pixel_desc->pixel_type;
727a6b396f4SSakari Ailus 			pdesc->small_offset_x = __pixel_desc->small_offset_x;
728a6b396f4SSakari Ailus 			pdesc->small_offset_y = __pixel_desc->small_offset_y;
729a6b396f4SSakari Ailus 		}
730a6b396f4SSakari Ailus 
731a6b396f4SSakari Ailus 		__num_pixel_descs = (const void *)(__pixel_desc + 1);
732a6b396f4SSakari Ailus 	}
733a6b396f4SSakari Ailus 
734a6b396f4SSakari Ailus 	return 0;
735a6b396f4SSakari Ailus }
736a6b396f4SSakari Ailus 
737a6b396f4SSakari Ailus static int ccs_data_parse_license(struct bin_container *bin,
738a6b396f4SSakari Ailus 				  char **__license,
739a6b396f4SSakari Ailus 				  size_t *__license_length,
740a6b396f4SSakari Ailus 				  const void *payload, const void *endp)
741a6b396f4SSakari Ailus {
742a6b396f4SSakari Ailus 	size_t size = endp - payload;
743a6b396f4SSakari Ailus 	char *license;
744a6b396f4SSakari Ailus 
745a6b396f4SSakari Ailus 	if (!bin->base) {
746a6b396f4SSakari Ailus 		bin_reserve(bin, size);
747a6b396f4SSakari Ailus 		return 0;
748a6b396f4SSakari Ailus 	}
749a6b396f4SSakari Ailus 
750a6b396f4SSakari Ailus 	license = bin_alloc(bin, size);
751a6b396f4SSakari Ailus 	if (!license)
752a6b396f4SSakari Ailus 		return -ENOMEM;
753a6b396f4SSakari Ailus 
754a6b396f4SSakari Ailus 	memcpy(license, payload, size);
755a6b396f4SSakari Ailus 
756a6b396f4SSakari Ailus 	*__license = license;
757a6b396f4SSakari Ailus 	*__license_length = size;
758a6b396f4SSakari Ailus 
759a6b396f4SSakari Ailus 	return 0;
760a6b396f4SSakari Ailus }
761a6b396f4SSakari Ailus 
762a6b396f4SSakari Ailus static int ccs_data_parse_end(bool *end, const void *payload, const void *endp,
763a6b396f4SSakari Ailus 			      struct device *dev)
764a6b396f4SSakari Ailus {
765a6b396f4SSakari Ailus 	const struct __ccs_data_block_end *__end = payload;
766a6b396f4SSakari Ailus 
767a6b396f4SSakari Ailus 	if (__end + 1 != endp) {
768a6b396f4SSakari Ailus 		dev_dbg(dev, "Invalid end block length %u\n",
769a6b396f4SSakari Ailus 			(unsigned int)(endp - payload));
770a6b396f4SSakari Ailus 		return -ENODATA;
771a6b396f4SSakari Ailus 	}
772a6b396f4SSakari Ailus 
773a6b396f4SSakari Ailus 	*end = true;
774a6b396f4SSakari Ailus 
775a6b396f4SSakari Ailus 	return 0;
776a6b396f4SSakari Ailus }
777a6b396f4SSakari Ailus 
778a6b396f4SSakari Ailus static int __ccs_data_parse(struct bin_container *bin,
779a6b396f4SSakari Ailus 			    struct ccs_data_container *ccsdata,
780a6b396f4SSakari Ailus 			    const void *data, size_t len, struct device *dev,
781a6b396f4SSakari Ailus 			    bool verbose)
782a6b396f4SSakari Ailus {
783a6b396f4SSakari Ailus 	const struct __ccs_data_block *block = data;
784a6b396f4SSakari Ailus 	const struct __ccs_data_block *endp = data + len;
785a6b396f4SSakari Ailus 	unsigned int version;
786a6b396f4SSakari Ailus 	bool is_first = true;
787a6b396f4SSakari Ailus 	int rval;
788a6b396f4SSakari Ailus 
789a6b396f4SSakari Ailus 	version = ccs_data_parse_format_version(block);
790a6b396f4SSakari Ailus 	if (version != CCS_STATIC_DATA_VERSION) {
791a6b396f4SSakari Ailus 		dev_dbg(dev, "Don't know how to handle version %u\n", version);
792a6b396f4SSakari Ailus 		return -EINVAL;
793a6b396f4SSakari Ailus 	}
794a6b396f4SSakari Ailus 
795a6b396f4SSakari Ailus 	if (verbose)
796a6b396f4SSakari Ailus 		dev_dbg(dev, "Parsing CCS static data version %u\n", version);
797a6b396f4SSakari Ailus 
798a6b396f4SSakari Ailus 	if (!bin->base)
799a6b396f4SSakari Ailus 		*ccsdata = (struct ccs_data_container){ 0 };
800a6b396f4SSakari Ailus 
801a6b396f4SSakari Ailus 	while (block < endp) {
802a6b396f4SSakari Ailus 		const struct __ccs_data_block *next_block;
803a6b396f4SSakari Ailus 		unsigned int block_id;
804a6b396f4SSakari Ailus 		const void *payload;
805a6b396f4SSakari Ailus 
806a6b396f4SSakari Ailus 		rval = ccs_data_block_parse_header(block, is_first, &block_id,
807a6b396f4SSakari Ailus 						   &payload, &next_block, endp,
808a6b396f4SSakari Ailus 						   dev,
809a6b396f4SSakari Ailus 						   bin->base ? false : verbose);
810a6b396f4SSakari Ailus 
811a6b396f4SSakari Ailus 		if (rval < 0)
812a6b396f4SSakari Ailus 			return rval;
813a6b396f4SSakari Ailus 
814a6b396f4SSakari Ailus 		switch (block_id) {
815a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_DUMMY:
816a6b396f4SSakari Ailus 			break;
817a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_DATA_VERSION:
818a6b396f4SSakari Ailus 			rval = ccs_data_parse_version(bin, ccsdata, payload,
819a6b396f4SSakari Ailus 						      next_block);
820a6b396f4SSakari Ailus 			if (rval < 0)
821a6b396f4SSakari Ailus 				return rval;
822a6b396f4SSakari Ailus 			break;
823a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS:
824a6b396f4SSakari Ailus 			rval = ccs_data_parse_regs(
825a6b396f4SSakari Ailus 				bin, &ccsdata->sensor_read_only_regs,
826a6b396f4SSakari Ailus 				&ccsdata->num_sensor_read_only_regs, payload,
827a6b396f4SSakari Ailus 				next_block, dev);
828a6b396f4SSakari Ailus 			if (rval < 0)
829a6b396f4SSakari Ailus 				return rval;
830a6b396f4SSakari Ailus 			break;
831a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS:
832a6b396f4SSakari Ailus 			rval = ccs_data_parse_regs(
833a6b396f4SSakari Ailus 				bin, &ccsdata->sensor_manufacturer_regs,
834a6b396f4SSakari Ailus 				&ccsdata->num_sensor_manufacturer_regs, payload,
835a6b396f4SSakari Ailus 				next_block, dev);
836a6b396f4SSakari Ailus 			if (rval < 0)
837a6b396f4SSakari Ailus 				return rval;
838a6b396f4SSakari Ailus 			break;
839a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS:
840a6b396f4SSakari Ailus 			rval = ccs_data_parse_regs(
841a6b396f4SSakari Ailus 				bin, &ccsdata->module_read_only_regs,
842a6b396f4SSakari Ailus 				&ccsdata->num_module_read_only_regs, payload,
843a6b396f4SSakari Ailus 				next_block, dev);
844a6b396f4SSakari Ailus 			if (rval < 0)
845a6b396f4SSakari Ailus 				return rval;
846a6b396f4SSakari Ailus 			break;
847a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS:
848a6b396f4SSakari Ailus 			rval = ccs_data_parse_regs(
849a6b396f4SSakari Ailus 				bin, &ccsdata->module_manufacturer_regs,
850a6b396f4SSakari Ailus 				&ccsdata->num_module_manufacturer_regs, payload,
851a6b396f4SSakari Ailus 				next_block, dev);
852a6b396f4SSakari Ailus 			if (rval < 0)
853a6b396f4SSakari Ailus 				return rval;
854a6b396f4SSakari Ailus 			break;
855a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION:
856a6b396f4SSakari Ailus 			rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf,
857a6b396f4SSakari Ailus 						   payload, next_block, dev);
858a6b396f4SSakari Ailus 			if (rval < 0)
859a6b396f4SSakari Ailus 				return rval;
860a6b396f4SSakari Ailus 			break;
861a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION:
862a6b396f4SSakari Ailus 			rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf,
863a6b396f4SSakari Ailus 						   payload, next_block, dev);
864a6b396f4SSakari Ailus 			if (rval < 0)
865a6b396f4SSakari Ailus 				return rval;
866a6b396f4SSakari Ailus 			break;
867a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK:
868a6b396f4SSakari Ailus 			rval = ccs_data_parse_rules(
869a6b396f4SSakari Ailus 				bin, &ccsdata->sensor_rules,
870a6b396f4SSakari Ailus 				&ccsdata->num_sensor_rules, payload, next_block,
871a6b396f4SSakari Ailus 				dev);
872a6b396f4SSakari Ailus 			if (rval < 0)
873a6b396f4SSakari Ailus 				return rval;
874a6b396f4SSakari Ailus 			break;
875a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK:
876a6b396f4SSakari Ailus 			rval = ccs_data_parse_rules(
877a6b396f4SSakari Ailus 				bin, &ccsdata->module_rules,
878a6b396f4SSakari Ailus 				&ccsdata->num_module_rules, payload, next_block,
879a6b396f4SSakari Ailus 				dev);
880a6b396f4SSakari Ailus 			if (rval < 0)
881a6b396f4SSakari Ailus 				return rval;
882a6b396f4SSakari Ailus 			break;
883a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_LICENSE:
884a6b396f4SSakari Ailus 			rval = ccs_data_parse_license(bin, &ccsdata->license,
885a6b396f4SSakari Ailus 						      &ccsdata->license_length,
886a6b396f4SSakari Ailus 						      payload, next_block);
887a6b396f4SSakari Ailus 			if (rval < 0)
888a6b396f4SSakari Ailus 				return rval;
889a6b396f4SSakari Ailus 			break;
890a6b396f4SSakari Ailus 		case CCS_DATA_BLOCK_ID_END:
891a6b396f4SSakari Ailus 			rval = ccs_data_parse_end(&ccsdata->end, payload,
892a6b396f4SSakari Ailus 						  next_block, dev);
893a6b396f4SSakari Ailus 			if (rval < 0)
894a6b396f4SSakari Ailus 				return rval;
895a6b396f4SSakari Ailus 			break;
896a6b396f4SSakari Ailus 		default:
897a6b396f4SSakari Ailus 			dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n",
898a6b396f4SSakari Ailus 				block_id);
899a6b396f4SSakari Ailus 		}
900a6b396f4SSakari Ailus 
901a6b396f4SSakari Ailus 		block = next_block;
902a6b396f4SSakari Ailus 		is_first = false;
903a6b396f4SSakari Ailus 	}
904a6b396f4SSakari Ailus 
905a6b396f4SSakari Ailus 	return 0;
906a6b396f4SSakari Ailus }
907a6b396f4SSakari Ailus 
908a6b396f4SSakari Ailus /**
909a6b396f4SSakari Ailus  * ccs_data_parse - Parse a CCS static data file into a usable in-memory
910a6b396f4SSakari Ailus  *		    data structure
911a6b396f4SSakari Ailus  * @ccsdata:	CCS static data in-memory data structure
912a6b396f4SSakari Ailus  * @data:	CCS static data binary
913a6b396f4SSakari Ailus  * @len:	Length of @data
914a6b396f4SSakari Ailus  * @dev:	Device the data is related to (used for printing debug messages)
915a6b396f4SSakari Ailus  * @verbose:	Whether to be verbose or not
916a6b396f4SSakari Ailus  */
917a6b396f4SSakari Ailus int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data,
918a6b396f4SSakari Ailus 		   size_t len, struct device *dev, bool verbose)
919a6b396f4SSakari Ailus {
920a6b396f4SSakari Ailus 	struct bin_container bin = { 0 };
921a6b396f4SSakari Ailus 	int rval;
922a6b396f4SSakari Ailus 
923a6b396f4SSakari Ailus 	rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose);
924a6b396f4SSakari Ailus 	if (rval)
925a6b396f4SSakari Ailus 		return rval;
926a6b396f4SSakari Ailus 
927a6b396f4SSakari Ailus 	rval = bin_backing_alloc(&bin);
928a6b396f4SSakari Ailus 	if (rval)
929a6b396f4SSakari Ailus 		return rval;
930a6b396f4SSakari Ailus 
931a6b396f4SSakari Ailus 	rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false);
932a6b396f4SSakari Ailus 	if (rval)
933a6b396f4SSakari Ailus 		goto out_free;
934a6b396f4SSakari Ailus 
935a6b396f4SSakari Ailus 	if (verbose && ccsdata->version)
936a6b396f4SSakari Ailus 		print_ccs_data_version(dev, ccsdata->version);
937a6b396f4SSakari Ailus 
938a6b396f4SSakari Ailus 	if (bin.now != bin.end) {
939a6b396f4SSakari Ailus 		rval = -EPROTO;
940a6b396f4SSakari Ailus 		dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n",
941a6b396f4SSakari Ailus 			bin.base, bin.now, bin.end);
942a6b396f4SSakari Ailus 		goto out_free;
943a6b396f4SSakari Ailus 	}
944a6b396f4SSakari Ailus 
945a6b396f4SSakari Ailus 	ccsdata->backing = bin.base;
946a6b396f4SSakari Ailus 
947a6b396f4SSakari Ailus 	return 0;
948a6b396f4SSakari Ailus 
949a6b396f4SSakari Ailus out_free:
950a6b396f4SSakari Ailus 	kvfree(bin.base);
951a6b396f4SSakari Ailus 
952a6b396f4SSakari Ailus 	return rval;
953a6b396f4SSakari Ailus }
954