162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CCS static data binary parser library 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019--2020 Intel Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/errno.h> 1062306a36Sopenharmony_ci#include <linux/limits.h> 1162306a36Sopenharmony_ci#include <linux/mm.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "ccs-data-defs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct bin_container { 1762306a36Sopenharmony_ci void *base; 1862306a36Sopenharmony_ci void *now; 1962306a36Sopenharmony_ci void *end; 2062306a36Sopenharmony_ci size_t size; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void *bin_alloc(struct bin_container *bin, size_t len) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci void *ptr; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci len = ALIGN(len, 8); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (bin->end - bin->now < len) 3062306a36Sopenharmony_ci return NULL; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci ptr = bin->now; 3362306a36Sopenharmony_ci bin->now += len; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return ptr; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void bin_reserve(struct bin_container *bin, size_t len) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci bin->size += ALIGN(len, 8); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic int bin_backing_alloc(struct bin_container *bin) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL); 4662306a36Sopenharmony_ci if (!bin->base) 4762306a36Sopenharmony_ci return -ENOMEM; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci bin->end = bin->base + bin->size; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define is_contained(var, endp) \ 5562306a36Sopenharmony_ci (sizeof(*var) <= (endp) - (void *)(var)) 5662306a36Sopenharmony_ci#define has_headroom(ptr, headroom, endp) \ 5762306a36Sopenharmony_ci ((headroom) <= (endp) - (void *)(ptr)) 5862306a36Sopenharmony_ci#define is_contained_with_headroom(var, headroom, endp) \ 5962306a36Sopenharmony_ci (sizeof(*var) + (headroom) <= (endp) - (void *)(var)) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int 6262306a36Sopenharmony_ciccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len, 6362306a36Sopenharmony_ci size_t *__hlen, size_t *__plen, 6462306a36Sopenharmony_ci const void *endp) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci size_t hlen, plen; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (!is_contained(__len, endp)) 6962306a36Sopenharmony_ci return -ENODATA; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) { 7262306a36Sopenharmony_ci case CCS_DATA_LENGTH_SPECIFIER_1: 7362306a36Sopenharmony_ci hlen = sizeof(*__len); 7462306a36Sopenharmony_ci plen = __len->length & 7562306a36Sopenharmony_ci ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1); 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci case CCS_DATA_LENGTH_SPECIFIER_2: { 7862306a36Sopenharmony_ci struct __ccs_data_length_specifier2 *__len2 = (void *)__len; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!is_contained(__len2, endp)) 8162306a36Sopenharmony_ci return -ENODATA; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci hlen = sizeof(*__len2); 8462306a36Sopenharmony_ci plen = ((size_t) 8562306a36Sopenharmony_ci (__len2->length[0] & 8662306a36Sopenharmony_ci ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) 8762306a36Sopenharmony_ci << 8) + __len2->length[1]; 8862306a36Sopenharmony_ci break; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci case CCS_DATA_LENGTH_SPECIFIER_3: { 9162306a36Sopenharmony_ci struct __ccs_data_length_specifier3 *__len3 = (void *)__len; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (!is_contained(__len3, endp)) 9462306a36Sopenharmony_ci return -ENODATA; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci hlen = sizeof(*__len3); 9762306a36Sopenharmony_ci plen = ((size_t) 9862306a36Sopenharmony_ci (__len3->length[0] & 9962306a36Sopenharmony_ci ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) 10062306a36Sopenharmony_ci << 16) + (__len3->length[0] << 8) + __len3->length[1]; 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (!has_headroom(__len, hlen + plen, endp)) 10862306a36Sopenharmony_ci return -ENODATA; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci *__hlen = hlen; 11162306a36Sopenharmony_ci *__plen = plen; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic u8 11762306a36Sopenharmony_ciccs_data_parse_format_version(const struct __ccs_data_block *block) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic u8 ccs_data_parse_block_id(const struct __ccs_data_block *block, 12362306a36Sopenharmony_ci bool is_first) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci if (!is_first) 12662306a36Sopenharmony_ci return block->id; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int ccs_data_parse_version(struct bin_container *bin, 13262306a36Sopenharmony_ci struct ccs_data_container *ccsdata, 13362306a36Sopenharmony_ci const void *payload, const void *endp) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci const struct __ccs_data_block_version *v = payload; 13662306a36Sopenharmony_ci struct ccs_data_block_version *vv; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (v + 1 != endp) 13962306a36Sopenharmony_ci return -ENODATA; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (!bin->base) { 14262306a36Sopenharmony_ci bin_reserve(bin, sizeof(*ccsdata->version)); 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version)); 14762306a36Sopenharmony_ci if (!ccsdata->version) 14862306a36Sopenharmony_ci return -ENOMEM; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci vv = ccsdata->version; 15162306a36Sopenharmony_ci vv->version_major = ((u16)v->static_data_version_major[0] << 8) + 15262306a36Sopenharmony_ci v->static_data_version_major[1]; 15362306a36Sopenharmony_ci vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) + 15462306a36Sopenharmony_ci v->static_data_version_minor[1]; 15562306a36Sopenharmony_ci vv->date_year = ((u16)v->year[0] << 8) + v->year[1]; 15662306a36Sopenharmony_ci vv->date_month = v->month; 15762306a36Sopenharmony_ci vv->date_day = v->day; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void print_ccs_data_version(struct device *dev, 16362306a36Sopenharmony_ci struct ccs_data_block_version *v) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci dev_dbg(dev, 16662306a36Sopenharmony_ci "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n", 16762306a36Sopenharmony_ci v->version_major, v->version_minor, 16862306a36Sopenharmony_ci v->date_year, v->date_month, v->date_day); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int ccs_data_block_parse_header(const struct __ccs_data_block *block, 17262306a36Sopenharmony_ci bool is_first, unsigned int *__block_id, 17362306a36Sopenharmony_ci const void **payload, 17462306a36Sopenharmony_ci const struct __ccs_data_block **next_block, 17562306a36Sopenharmony_ci const void *endp, struct device *dev, 17662306a36Sopenharmony_ci bool verbose) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci size_t plen, hlen; 17962306a36Sopenharmony_ci u8 block_id; 18062306a36Sopenharmony_ci int rval; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (!is_contained(block, endp)) 18362306a36Sopenharmony_ci return -ENODATA; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen, 18662306a36Sopenharmony_ci endp); 18762306a36Sopenharmony_ci if (rval < 0) 18862306a36Sopenharmony_ci return rval; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci block_id = ccs_data_parse_block_id(block, is_first); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (verbose) 19362306a36Sopenharmony_ci dev_dbg(dev, 19462306a36Sopenharmony_ci "Block ID 0x%2.2x, header length %zu, payload length %zu\n", 19562306a36Sopenharmony_ci block_id, hlen, plen); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!has_headroom(&block->length, hlen + plen, endp)) 19862306a36Sopenharmony_ci return -ENODATA; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (__block_id) 20162306a36Sopenharmony_ci *__block_id = block_id; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (payload) 20462306a36Sopenharmony_ci *payload = (void *)&block->length + hlen; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (next_block) 20762306a36Sopenharmony_ci *next_block = (void *)&block->length + hlen + plen; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int ccs_data_parse_regs(struct bin_container *bin, 21362306a36Sopenharmony_ci struct ccs_reg **__regs, 21462306a36Sopenharmony_ci size_t *__num_regs, const void *payload, 21562306a36Sopenharmony_ci const void *endp, struct device *dev) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct ccs_reg *regs_base = NULL, *regs = NULL; 21862306a36Sopenharmony_ci size_t num_regs = 0; 21962306a36Sopenharmony_ci u16 addr = 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (bin->base && __regs) { 22262306a36Sopenharmony_ci regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs); 22362306a36Sopenharmony_ci if (!regs) 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci while (payload < endp && num_regs < INT_MAX) { 22862306a36Sopenharmony_ci const struct __ccs_data_block_regs *r = payload; 22962306a36Sopenharmony_ci size_t len; 23062306a36Sopenharmony_ci const void *data; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (!is_contained(r, endp)) 23362306a36Sopenharmony_ci return -ENODATA; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) { 23662306a36Sopenharmony_ci case CCS_DATA_BLOCK_REGS_SEL_REGS: 23762306a36Sopenharmony_ci addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK; 23862306a36Sopenharmony_ci len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK) 23962306a36Sopenharmony_ci >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (!is_contained_with_headroom(r, len, endp)) 24262306a36Sopenharmony_ci return -ENODATA; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci data = r + 1; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci case CCS_DATA_BLOCK_REGS_SEL_REGS2: { 24762306a36Sopenharmony_ci const struct __ccs_data_block_regs2 *r2 = payload; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!is_contained(r2, endp)) 25062306a36Sopenharmony_ci return -ENODATA; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci addr += ((u16)(r2->reg_len & 25362306a36Sopenharmony_ci CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8) 25462306a36Sopenharmony_ci + r2->addr; 25562306a36Sopenharmony_ci len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK) 25662306a36Sopenharmony_ci >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!is_contained_with_headroom(r2, len, endp)) 25962306a36Sopenharmony_ci return -ENODATA; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci data = r2 + 1; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci case CCS_DATA_BLOCK_REGS_SEL_REGS3: { 26562306a36Sopenharmony_ci const struct __ccs_data_block_regs3 *r3 = payload; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (!is_contained(r3, endp)) 26862306a36Sopenharmony_ci return -ENODATA; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci addr = ((u16)r3->addr[0] << 8) + r3->addr[1]; 27162306a36Sopenharmony_ci len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!is_contained_with_headroom(r3, len, endp)) 27462306a36Sopenharmony_ci return -ENODATA; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci data = r3 + 1; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci default: 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci num_regs++; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (!bin->base) { 28662306a36Sopenharmony_ci bin_reserve(bin, len); 28762306a36Sopenharmony_ci } else if (__regs) { 28862306a36Sopenharmony_ci if (!regs) 28962306a36Sopenharmony_ci return -EIO; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci regs->addr = addr; 29262306a36Sopenharmony_ci regs->len = len; 29362306a36Sopenharmony_ci regs->value = bin_alloc(bin, len); 29462306a36Sopenharmony_ci if (!regs->value) 29562306a36Sopenharmony_ci return -ENOMEM; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci memcpy(regs->value, data, len); 29862306a36Sopenharmony_ci regs++; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci addr += len; 30262306a36Sopenharmony_ci payload = data + len; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!bin->base) 30662306a36Sopenharmony_ci bin_reserve(bin, sizeof(*regs) * num_regs); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (__num_regs) 30962306a36Sopenharmony_ci *__num_regs = num_regs; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (bin->base && __regs) { 31262306a36Sopenharmony_ci if (!regs_base) 31362306a36Sopenharmony_ci return -EIO; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci *__regs = regs_base; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int ccs_data_parse_reg_rules(struct bin_container *bin, 32262306a36Sopenharmony_ci struct ccs_reg **__regs, 32362306a36Sopenharmony_ci size_t *__num_regs, 32462306a36Sopenharmony_ci const void *payload, 32562306a36Sopenharmony_ci const void *endp, struct device *dev) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci int rval; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (!bin->base) 33062306a36Sopenharmony_ci return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev); 33362306a36Sopenharmony_ci if (rval) 33462306a36Sopenharmony_ci return rval; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp, 33762306a36Sopenharmony_ci dev); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void assign_ffd_entry(struct ccs_frame_format_desc *desc, 34162306a36Sopenharmony_ci const struct __ccs_data_block_ffd_entry *ent) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci desc->pixelcode = ent->pixelcode; 34462306a36Sopenharmony_ci desc->value = ((u16)ent->value[0] << 8) + ent->value[1]; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int ccs_data_parse_ffd(struct bin_container *bin, 34862306a36Sopenharmony_ci struct ccs_frame_format_descs **ffd, 34962306a36Sopenharmony_ci const void *payload, 35062306a36Sopenharmony_ci const void *endp, struct device *dev) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci const struct __ccs_data_block_ffd *__ffd = payload; 35362306a36Sopenharmony_ci const struct __ccs_data_block_ffd_entry *__entry; 35462306a36Sopenharmony_ci unsigned int i; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!is_contained(__ffd, endp)) 35762306a36Sopenharmony_ci return -ENODATA; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if ((void *)__ffd + sizeof(*__ffd) + 36062306a36Sopenharmony_ci ((u32)__ffd->num_column_descs + 36162306a36Sopenharmony_ci (u32)__ffd->num_row_descs) * 36262306a36Sopenharmony_ci sizeof(struct __ccs_data_block_ffd_entry) != endp) 36362306a36Sopenharmony_ci return -ENODATA; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!bin->base) { 36662306a36Sopenharmony_ci bin_reserve(bin, sizeof(**ffd)); 36762306a36Sopenharmony_ci bin_reserve(bin, __ffd->num_column_descs * 36862306a36Sopenharmony_ci sizeof(struct ccs_frame_format_desc)); 36962306a36Sopenharmony_ci bin_reserve(bin, __ffd->num_row_descs * 37062306a36Sopenharmony_ci sizeof(struct ccs_frame_format_desc)); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci *ffd = bin_alloc(bin, sizeof(**ffd)); 37662306a36Sopenharmony_ci if (!*ffd) 37762306a36Sopenharmony_ci return -ENOMEM; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci (*ffd)->num_column_descs = __ffd->num_column_descs; 38062306a36Sopenharmony_ci (*ffd)->num_row_descs = __ffd->num_row_descs; 38162306a36Sopenharmony_ci __entry = (void *)(__ffd + 1); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs * 38462306a36Sopenharmony_ci sizeof(*(*ffd)->column_descs)); 38562306a36Sopenharmony_ci if (!(*ffd)->column_descs) 38662306a36Sopenharmony_ci return -ENOMEM; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci for (i = 0; i < __ffd->num_column_descs; i++, __entry++) 38962306a36Sopenharmony_ci assign_ffd_entry(&(*ffd)->column_descs[i], __entry); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs * 39262306a36Sopenharmony_ci sizeof(*(*ffd)->row_descs)); 39362306a36Sopenharmony_ci if (!(*ffd)->row_descs) 39462306a36Sopenharmony_ci return -ENOMEM; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci for (i = 0; i < __ffd->num_row_descs; i++, __entry++) 39762306a36Sopenharmony_ci assign_ffd_entry(&(*ffd)->row_descs[i], __entry); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (__entry != endp) 40062306a36Sopenharmony_ci return -EPROTO; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic int ccs_data_parse_pdaf_readout(struct bin_container *bin, 40662306a36Sopenharmony_ci struct ccs_pdaf_readout **pdaf_readout, 40762306a36Sopenharmony_ci const void *payload, 40862306a36Sopenharmony_ci const void *endp, struct device *dev) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci const struct __ccs_data_block_pdaf_readout *__pdaf = payload; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!is_contained(__pdaf, endp)) 41362306a36Sopenharmony_ci return -ENODATA; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (!bin->base) { 41662306a36Sopenharmony_ci bin_reserve(bin, sizeof(**pdaf_readout)); 41762306a36Sopenharmony_ci } else { 41862306a36Sopenharmony_ci *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout)); 41962306a36Sopenharmony_ci if (!*pdaf_readout) 42062306a36Sopenharmony_ci return -ENOMEM; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci (*pdaf_readout)->pdaf_readout_info_order = 42362306a36Sopenharmony_ci __pdaf->pdaf_readout_info_order; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd, 42762306a36Sopenharmony_ci __pdaf + 1, endp, dev); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic int ccs_data_parse_rules(struct bin_container *bin, 43162306a36Sopenharmony_ci struct ccs_rule **__rules, 43262306a36Sopenharmony_ci size_t *__num_rules, const void *payload, 43362306a36Sopenharmony_ci const void *endp, struct device *dev) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct ccs_rule *rules_base = NULL, *rules = NULL, *next_rule = NULL; 43662306a36Sopenharmony_ci size_t num_rules = 0; 43762306a36Sopenharmony_ci const void *__next_rule = payload; 43862306a36Sopenharmony_ci int rval; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (bin->base) { 44162306a36Sopenharmony_ci rules_base = next_rule = 44262306a36Sopenharmony_ci bin_alloc(bin, sizeof(*rules) * *__num_rules); 44362306a36Sopenharmony_ci if (!rules_base) 44462306a36Sopenharmony_ci return -ENOMEM; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci while (__next_rule < endp) { 44862306a36Sopenharmony_ci size_t rule_hlen, rule_plen, rule_plen2; 44962306a36Sopenharmony_ci const u8 *__rule_type; 45062306a36Sopenharmony_ci const void *rule_payload; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* Size of a single rule */ 45362306a36Sopenharmony_ci rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen, 45462306a36Sopenharmony_ci &rule_plen, endp); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (rval < 0) 45762306a36Sopenharmony_ci return rval; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci __rule_type = __next_rule + rule_hlen; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!is_contained(__rule_type, endp)) 46262306a36Sopenharmony_ci return -ENODATA; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci rule_payload = __rule_type + 1; 46562306a36Sopenharmony_ci rule_plen2 = rule_plen - sizeof(*__rule_type); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (*__rule_type == CCS_DATA_BLOCK_RULE_ID_IF) { 46862306a36Sopenharmony_ci const struct __ccs_data_block_rule_if *__if_rules = 46962306a36Sopenharmony_ci rule_payload; 47062306a36Sopenharmony_ci const size_t __num_if_rules = 47162306a36Sopenharmony_ci rule_plen2 / sizeof(*__if_rules); 47262306a36Sopenharmony_ci struct ccs_if_rule *if_rule; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!has_headroom(__if_rules, 47562306a36Sopenharmony_ci sizeof(*__if_rules) * __num_if_rules, 47662306a36Sopenharmony_ci rule_payload + rule_plen2)) 47762306a36Sopenharmony_ci return -ENODATA; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Also check there is no extra data */ 48062306a36Sopenharmony_ci if (__if_rules + __num_if_rules != 48162306a36Sopenharmony_ci rule_payload + rule_plen2) 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (!bin->base) { 48562306a36Sopenharmony_ci bin_reserve(bin, 48662306a36Sopenharmony_ci sizeof(*if_rule) * 48762306a36Sopenharmony_ci __num_if_rules); 48862306a36Sopenharmony_ci num_rules++; 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci unsigned int i; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!next_rule) 49362306a36Sopenharmony_ci return -EIO; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci rules = next_rule; 49662306a36Sopenharmony_ci next_rule++; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if_rule = bin_alloc(bin, 49962306a36Sopenharmony_ci sizeof(*if_rule) * 50062306a36Sopenharmony_ci __num_if_rules); 50162306a36Sopenharmony_ci if (!if_rule) 50262306a36Sopenharmony_ci return -ENOMEM; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci for (i = 0; i < __num_if_rules; i++) { 50562306a36Sopenharmony_ci if_rule[i].addr = 50662306a36Sopenharmony_ci ((u16)__if_rules[i].addr[0] 50762306a36Sopenharmony_ci << 8) + 50862306a36Sopenharmony_ci __if_rules[i].addr[1]; 50962306a36Sopenharmony_ci if_rule[i].value = __if_rules[i].value; 51062306a36Sopenharmony_ci if_rule[i].mask = __if_rules[i].mask; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci rules->if_rules = if_rule; 51462306a36Sopenharmony_ci rules->num_if_rules = __num_if_rules; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci } else { 51762306a36Sopenharmony_ci /* Check there was an if rule before any other rules */ 51862306a36Sopenharmony_ci if (bin->base && !rules) 51962306a36Sopenharmony_ci return -EINVAL; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci switch (*__rule_type) { 52262306a36Sopenharmony_ci case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: 52362306a36Sopenharmony_ci rval = ccs_data_parse_reg_rules(bin, 52462306a36Sopenharmony_ci rules ? 52562306a36Sopenharmony_ci &rules->read_only_regs : NULL, 52662306a36Sopenharmony_ci rules ? 52762306a36Sopenharmony_ci &rules->num_read_only_regs : NULL, 52862306a36Sopenharmony_ci rule_payload, 52962306a36Sopenharmony_ci rule_payload + rule_plen2, 53062306a36Sopenharmony_ci dev); 53162306a36Sopenharmony_ci if (rval) 53262306a36Sopenharmony_ci return rval; 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci case CCS_DATA_BLOCK_RULE_ID_FFD: 53562306a36Sopenharmony_ci rval = ccs_data_parse_ffd(bin, rules ? 53662306a36Sopenharmony_ci &rules->frame_format : NULL, 53762306a36Sopenharmony_ci rule_payload, 53862306a36Sopenharmony_ci rule_payload + rule_plen2, 53962306a36Sopenharmony_ci dev); 54062306a36Sopenharmony_ci if (rval) 54162306a36Sopenharmony_ci return rval; 54262306a36Sopenharmony_ci break; 54362306a36Sopenharmony_ci case CCS_DATA_BLOCK_RULE_ID_MSR: 54462306a36Sopenharmony_ci rval = ccs_data_parse_reg_rules(bin, 54562306a36Sopenharmony_ci rules ? 54662306a36Sopenharmony_ci &rules->manufacturer_regs : NULL, 54762306a36Sopenharmony_ci rules ? 54862306a36Sopenharmony_ci &rules->num_manufacturer_regs : NULL, 54962306a36Sopenharmony_ci rule_payload, 55062306a36Sopenharmony_ci rule_payload + rule_plen2, 55162306a36Sopenharmony_ci dev); 55262306a36Sopenharmony_ci if (rval) 55362306a36Sopenharmony_ci return rval; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: 55662306a36Sopenharmony_ci rval = ccs_data_parse_pdaf_readout(bin, 55762306a36Sopenharmony_ci rules ? 55862306a36Sopenharmony_ci &rules->pdaf_readout : NULL, 55962306a36Sopenharmony_ci rule_payload, 56062306a36Sopenharmony_ci rule_payload + rule_plen2, 56162306a36Sopenharmony_ci dev); 56262306a36Sopenharmony_ci if (rval) 56362306a36Sopenharmony_ci return rval; 56462306a36Sopenharmony_ci break; 56562306a36Sopenharmony_ci default: 56662306a36Sopenharmony_ci dev_dbg(dev, 56762306a36Sopenharmony_ci "Don't know how to handle rule type %u!\n", 56862306a36Sopenharmony_ci *__rule_type); 56962306a36Sopenharmony_ci return -EINVAL; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci __next_rule = __next_rule + rule_hlen + rule_plen; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (!bin->base) { 57662306a36Sopenharmony_ci bin_reserve(bin, sizeof(*rules) * num_rules); 57762306a36Sopenharmony_ci *__num_rules = num_rules; 57862306a36Sopenharmony_ci } else { 57962306a36Sopenharmony_ci if (!rules_base) 58062306a36Sopenharmony_ci return -EIO; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci *__rules = rules_base; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf, 58962306a36Sopenharmony_ci const void *payload, const void *endp, 59062306a36Sopenharmony_ci struct device *dev) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload; 59362306a36Sopenharmony_ci const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group; 59462306a36Sopenharmony_ci const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc; 59562306a36Sopenharmony_ci unsigned int i; 59662306a36Sopenharmony_ci u16 num_block_desc_groups; 59762306a36Sopenharmony_ci u8 max_block_type_id = 0; 59862306a36Sopenharmony_ci const u8 *__num_pixel_descs; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (!is_contained(__pdaf, endp)) 60162306a36Sopenharmony_ci return -ENODATA; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (bin->base) { 60462306a36Sopenharmony_ci *pdaf = bin_alloc(bin, sizeof(**pdaf)); 60562306a36Sopenharmony_ci if (!*pdaf) 60662306a36Sopenharmony_ci return -ENOMEM; 60762306a36Sopenharmony_ci } else { 60862306a36Sopenharmony_ci bin_reserve(bin, sizeof(**pdaf)); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci num_block_desc_groups = 61262306a36Sopenharmony_ci ((u16)__pdaf->num_block_desc_groups[0] << 8) + 61362306a36Sopenharmony_ci __pdaf->num_block_desc_groups[1]; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (bin->base) { 61662306a36Sopenharmony_ci (*pdaf)->main_offset_x = 61762306a36Sopenharmony_ci ((u16)__pdaf->main_offset_x[0] << 8) + 61862306a36Sopenharmony_ci __pdaf->main_offset_x[1]; 61962306a36Sopenharmony_ci (*pdaf)->main_offset_y = 62062306a36Sopenharmony_ci ((u16)__pdaf->main_offset_y[0] << 8) + 62162306a36Sopenharmony_ci __pdaf->main_offset_y[1]; 62262306a36Sopenharmony_ci (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type; 62362306a36Sopenharmony_ci (*pdaf)->block_width = __pdaf->block_width; 62462306a36Sopenharmony_ci (*pdaf)->block_height = __pdaf->block_height; 62562306a36Sopenharmony_ci (*pdaf)->num_block_desc_groups = num_block_desc_groups; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci __bdesc_group = (const void *)(__pdaf + 1); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (bin->base) { 63162306a36Sopenharmony_ci (*pdaf)->block_desc_groups = 63262306a36Sopenharmony_ci bin_alloc(bin, 63362306a36Sopenharmony_ci sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 63462306a36Sopenharmony_ci num_block_desc_groups); 63562306a36Sopenharmony_ci if (!(*pdaf)->block_desc_groups) 63662306a36Sopenharmony_ci return -ENOMEM; 63762306a36Sopenharmony_ci } else { 63862306a36Sopenharmony_ci bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 63962306a36Sopenharmony_ci num_block_desc_groups); 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci for (i = 0; i < num_block_desc_groups; i++) { 64362306a36Sopenharmony_ci const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc; 64462306a36Sopenharmony_ci u16 num_block_descs; 64562306a36Sopenharmony_ci unsigned int j; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (!is_contained(__bdesc_group, endp)) 64862306a36Sopenharmony_ci return -ENODATA; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci num_block_descs = 65162306a36Sopenharmony_ci ((u16)__bdesc_group->num_block_descs[0] << 8) + 65262306a36Sopenharmony_ci __bdesc_group->num_block_descs[1]; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (bin->base) { 65562306a36Sopenharmony_ci (*pdaf)->block_desc_groups[i].repeat_y = 65662306a36Sopenharmony_ci __bdesc_group->repeat_y; 65762306a36Sopenharmony_ci (*pdaf)->block_desc_groups[i].num_block_descs = 65862306a36Sopenharmony_ci num_block_descs; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci __bdesc = (const void *)(__bdesc_group + 1); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (bin->base) { 66462306a36Sopenharmony_ci (*pdaf)->block_desc_groups[i].block_descs = 66562306a36Sopenharmony_ci bin_alloc(bin, 66662306a36Sopenharmony_ci sizeof(struct ccs_pdaf_pix_loc_block_desc) * 66762306a36Sopenharmony_ci num_block_descs); 66862306a36Sopenharmony_ci if (!(*pdaf)->block_desc_groups[i].block_descs) 66962306a36Sopenharmony_ci return -ENOMEM; 67062306a36Sopenharmony_ci } else { 67162306a36Sopenharmony_ci bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) * 67262306a36Sopenharmony_ci num_block_descs); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci for (j = 0; j < num_block_descs; j++, __bdesc++) { 67662306a36Sopenharmony_ci struct ccs_pdaf_pix_loc_block_desc *bdesc; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (!is_contained(__bdesc, endp)) 67962306a36Sopenharmony_ci return -ENODATA; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (max_block_type_id <= __bdesc->block_type_id) 68262306a36Sopenharmony_ci max_block_type_id = __bdesc->block_type_id + 1; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (!bin->base) 68562306a36Sopenharmony_ci continue; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j]; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8) 69062306a36Sopenharmony_ci + __bdesc->repeat_x[1]; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (__bdesc->block_type_id >= num_block_descs) 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci bdesc->block_type_id = __bdesc->block_type_id; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci __bdesc_group = (const void *)__bdesc; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci __num_pixel_descs = (const void *)__bdesc_group; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (bin->base) { 70462306a36Sopenharmony_ci (*pdaf)->pixel_desc_groups = 70562306a36Sopenharmony_ci bin_alloc(bin, 70662306a36Sopenharmony_ci sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 70762306a36Sopenharmony_ci max_block_type_id); 70862306a36Sopenharmony_ci if (!(*pdaf)->pixel_desc_groups) 70962306a36Sopenharmony_ci return -ENOMEM; 71062306a36Sopenharmony_ci (*pdaf)->num_pixel_desc_grups = max_block_type_id; 71162306a36Sopenharmony_ci } else { 71262306a36Sopenharmony_ci bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 71362306a36Sopenharmony_ci max_block_type_id); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci for (i = 0; i < max_block_type_id; i++) { 71762306a36Sopenharmony_ci struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL; 71862306a36Sopenharmony_ci unsigned int j; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!is_contained(__num_pixel_descs, endp)) 72162306a36Sopenharmony_ci return -ENODATA; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (bin->base) { 72462306a36Sopenharmony_ci pdgroup = &(*pdaf)->pixel_desc_groups[i]; 72562306a36Sopenharmony_ci pdgroup->descs = 72662306a36Sopenharmony_ci bin_alloc(bin, 72762306a36Sopenharmony_ci sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 72862306a36Sopenharmony_ci *__num_pixel_descs); 72962306a36Sopenharmony_ci if (!pdgroup->descs) 73062306a36Sopenharmony_ci return -ENOMEM; 73162306a36Sopenharmony_ci pdgroup->num_descs = *__num_pixel_descs; 73262306a36Sopenharmony_ci } else { 73362306a36Sopenharmony_ci bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 73462306a36Sopenharmony_ci *__num_pixel_descs); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci __pixel_desc = (const void *)(__num_pixel_descs + 1); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) { 74062306a36Sopenharmony_ci struct ccs_pdaf_pix_loc_pixel_desc *pdesc; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!is_contained(__pixel_desc, endp)) 74362306a36Sopenharmony_ci return -ENODATA; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!bin->base) 74662306a36Sopenharmony_ci continue; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (!pdgroup) 74962306a36Sopenharmony_ci return -EIO; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci pdesc = &pdgroup->descs[j]; 75262306a36Sopenharmony_ci pdesc->pixel_type = __pixel_desc->pixel_type; 75362306a36Sopenharmony_ci pdesc->small_offset_x = __pixel_desc->small_offset_x; 75462306a36Sopenharmony_ci pdesc->small_offset_y = __pixel_desc->small_offset_y; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci __num_pixel_descs = (const void *)(__pixel_desc + 1); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic int ccs_data_parse_license(struct bin_container *bin, 76462306a36Sopenharmony_ci char **__license, 76562306a36Sopenharmony_ci size_t *__license_length, 76662306a36Sopenharmony_ci const void *payload, const void *endp) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci size_t size = endp - payload; 76962306a36Sopenharmony_ci char *license; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!bin->base) { 77262306a36Sopenharmony_ci bin_reserve(bin, size); 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci license = bin_alloc(bin, size); 77762306a36Sopenharmony_ci if (!license) 77862306a36Sopenharmony_ci return -ENOMEM; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci memcpy(license, payload, size); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci *__license = license; 78362306a36Sopenharmony_ci *__license_length = size; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return 0; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int ccs_data_parse_end(bool *end, const void *payload, const void *endp, 78962306a36Sopenharmony_ci struct device *dev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci const struct __ccs_data_block_end *__end = payload; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (__end + 1 != endp) { 79462306a36Sopenharmony_ci dev_dbg(dev, "Invalid end block length %u\n", 79562306a36Sopenharmony_ci (unsigned int)(endp - payload)); 79662306a36Sopenharmony_ci return -ENODATA; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci *end = true; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int __ccs_data_parse(struct bin_container *bin, 80562306a36Sopenharmony_ci struct ccs_data_container *ccsdata, 80662306a36Sopenharmony_ci const void *data, size_t len, struct device *dev, 80762306a36Sopenharmony_ci bool verbose) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci const struct __ccs_data_block *block = data; 81062306a36Sopenharmony_ci const struct __ccs_data_block *endp = data + len; 81162306a36Sopenharmony_ci unsigned int version; 81262306a36Sopenharmony_ci bool is_first = true; 81362306a36Sopenharmony_ci int rval; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci version = ccs_data_parse_format_version(block); 81662306a36Sopenharmony_ci if (version != CCS_STATIC_DATA_VERSION) { 81762306a36Sopenharmony_ci dev_dbg(dev, "Don't know how to handle version %u\n", version); 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (verbose) 82262306a36Sopenharmony_ci dev_dbg(dev, "Parsing CCS static data version %u\n", version); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (!bin->base) 82562306a36Sopenharmony_ci *ccsdata = (struct ccs_data_container){ 0 }; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci while (block < endp) { 82862306a36Sopenharmony_ci const struct __ccs_data_block *next_block; 82962306a36Sopenharmony_ci unsigned int block_id; 83062306a36Sopenharmony_ci const void *payload; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rval = ccs_data_block_parse_header(block, is_first, &block_id, 83362306a36Sopenharmony_ci &payload, &next_block, endp, 83462306a36Sopenharmony_ci dev, 83562306a36Sopenharmony_ci bin->base ? false : verbose); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (rval < 0) 83862306a36Sopenharmony_ci return rval; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci switch (block_id) { 84162306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_DUMMY: 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_DATA_VERSION: 84462306a36Sopenharmony_ci rval = ccs_data_parse_version(bin, ccsdata, payload, 84562306a36Sopenharmony_ci next_block); 84662306a36Sopenharmony_ci if (rval < 0) 84762306a36Sopenharmony_ci return rval; 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS: 85062306a36Sopenharmony_ci rval = ccs_data_parse_regs( 85162306a36Sopenharmony_ci bin, &ccsdata->sensor_read_only_regs, 85262306a36Sopenharmony_ci &ccsdata->num_sensor_read_only_regs, payload, 85362306a36Sopenharmony_ci next_block, dev); 85462306a36Sopenharmony_ci if (rval < 0) 85562306a36Sopenharmony_ci return rval; 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS: 85862306a36Sopenharmony_ci rval = ccs_data_parse_regs( 85962306a36Sopenharmony_ci bin, &ccsdata->sensor_manufacturer_regs, 86062306a36Sopenharmony_ci &ccsdata->num_sensor_manufacturer_regs, payload, 86162306a36Sopenharmony_ci next_block, dev); 86262306a36Sopenharmony_ci if (rval < 0) 86362306a36Sopenharmony_ci return rval; 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS: 86662306a36Sopenharmony_ci rval = ccs_data_parse_regs( 86762306a36Sopenharmony_ci bin, &ccsdata->module_read_only_regs, 86862306a36Sopenharmony_ci &ccsdata->num_module_read_only_regs, payload, 86962306a36Sopenharmony_ci next_block, dev); 87062306a36Sopenharmony_ci if (rval < 0) 87162306a36Sopenharmony_ci return rval; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS: 87462306a36Sopenharmony_ci rval = ccs_data_parse_regs( 87562306a36Sopenharmony_ci bin, &ccsdata->module_manufacturer_regs, 87662306a36Sopenharmony_ci &ccsdata->num_module_manufacturer_regs, payload, 87762306a36Sopenharmony_ci next_block, dev); 87862306a36Sopenharmony_ci if (rval < 0) 87962306a36Sopenharmony_ci return rval; 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION: 88262306a36Sopenharmony_ci rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf, 88362306a36Sopenharmony_ci payload, next_block, dev); 88462306a36Sopenharmony_ci if (rval < 0) 88562306a36Sopenharmony_ci return rval; 88662306a36Sopenharmony_ci break; 88762306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION: 88862306a36Sopenharmony_ci rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf, 88962306a36Sopenharmony_ci payload, next_block, dev); 89062306a36Sopenharmony_ci if (rval < 0) 89162306a36Sopenharmony_ci return rval; 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK: 89462306a36Sopenharmony_ci rval = ccs_data_parse_rules( 89562306a36Sopenharmony_ci bin, &ccsdata->sensor_rules, 89662306a36Sopenharmony_ci &ccsdata->num_sensor_rules, payload, next_block, 89762306a36Sopenharmony_ci dev); 89862306a36Sopenharmony_ci if (rval < 0) 89962306a36Sopenharmony_ci return rval; 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK: 90262306a36Sopenharmony_ci rval = ccs_data_parse_rules( 90362306a36Sopenharmony_ci bin, &ccsdata->module_rules, 90462306a36Sopenharmony_ci &ccsdata->num_module_rules, payload, next_block, 90562306a36Sopenharmony_ci dev); 90662306a36Sopenharmony_ci if (rval < 0) 90762306a36Sopenharmony_ci return rval; 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_LICENSE: 91062306a36Sopenharmony_ci rval = ccs_data_parse_license(bin, &ccsdata->license, 91162306a36Sopenharmony_ci &ccsdata->license_length, 91262306a36Sopenharmony_ci payload, next_block); 91362306a36Sopenharmony_ci if (rval < 0) 91462306a36Sopenharmony_ci return rval; 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci case CCS_DATA_BLOCK_ID_END: 91762306a36Sopenharmony_ci rval = ccs_data_parse_end(&ccsdata->end, payload, 91862306a36Sopenharmony_ci next_block, dev); 91962306a36Sopenharmony_ci if (rval < 0) 92062306a36Sopenharmony_ci return rval; 92162306a36Sopenharmony_ci break; 92262306a36Sopenharmony_ci default: 92362306a36Sopenharmony_ci dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n", 92462306a36Sopenharmony_ci block_id); 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci block = next_block; 92862306a36Sopenharmony_ci is_first = false; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return 0; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci/** 93562306a36Sopenharmony_ci * ccs_data_parse - Parse a CCS static data file into a usable in-memory 93662306a36Sopenharmony_ci * data structure 93762306a36Sopenharmony_ci * @ccsdata: CCS static data in-memory data structure 93862306a36Sopenharmony_ci * @data: CCS static data binary 93962306a36Sopenharmony_ci * @len: Length of @data 94062306a36Sopenharmony_ci * @dev: Device the data is related to (used for printing debug messages) 94162306a36Sopenharmony_ci * @verbose: Whether to be verbose or not 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ciint ccs_data_parse(struct ccs_data_container *ccsdata, const void *data, 94462306a36Sopenharmony_ci size_t len, struct device *dev, bool verbose) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct bin_container bin = { 0 }; 94762306a36Sopenharmony_ci int rval; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose); 95062306a36Sopenharmony_ci if (rval) 95162306a36Sopenharmony_ci return rval; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci rval = bin_backing_alloc(&bin); 95462306a36Sopenharmony_ci if (rval) 95562306a36Sopenharmony_ci return rval; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false); 95862306a36Sopenharmony_ci if (rval) 95962306a36Sopenharmony_ci goto out_free; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (verbose && ccsdata->version) 96262306a36Sopenharmony_ci print_ccs_data_version(dev, ccsdata->version); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (bin.now != bin.end) { 96562306a36Sopenharmony_ci rval = -EPROTO; 96662306a36Sopenharmony_ci dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n", 96762306a36Sopenharmony_ci bin.base, bin.now, bin.end); 96862306a36Sopenharmony_ci goto out_free; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ccsdata->backing = bin.base; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return 0; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ciout_free: 97662306a36Sopenharmony_ci kvfree(bin.base); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return rval; 97962306a36Sopenharmony_ci} 980