drm/edid: add EDID block count and size helpers

Add some helpers to figure out the EDID extension block count, block
count, size, pointers to blocks.

Unfortunately, we'll need to cast away the const in a few places where
we actually need to access the data.

v3: fix (!edid_extension_block_count(edid) == 0) (kernel test robot)

v2: fix s/j/i/ introduced in a rebase

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/dc7b0850293d837439fb3914c8a9d81e39018b4b.1649685475.git.jani.nikula@intel.com
This commit is contained in:
Jani Nikula 2022-04-11 17:00:35 +03:00
Родитель 1c788f69f2
Коммит f1e4c916f9
1 изменённых файлов: 57 добавлений и 23 удалений

Просмотреть файл

@ -1568,6 +1568,38 @@ static const struct drm_display_mode edid_4k_modes[] = {
/*** DDC fetch and block validation ***/
static int edid_extension_block_count(const struct edid *edid)
{
return edid->extensions;
}
static int edid_block_count(const struct edid *edid)
{
return edid_extension_block_count(edid) + 1;
}
static int edid_size_by_blocks(int num_blocks)
{
return num_blocks * EDID_LENGTH;
}
static int edid_size(const struct edid *edid)
{
return edid_size_by_blocks(edid_block_count(edid));
}
static const void *edid_block_data(const struct edid *edid, int index)
{
BUILD_BUG_ON(sizeof(*edid) != EDID_LENGTH);
return edid + index;
}
static const void *edid_extension_block_data(const struct edid *edid, int index)
{
return edid_block_data(edid, index + 1);
}
static const u8 edid_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
@ -1654,8 +1686,8 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2)
return false;
if (edid1) {
edid1_len = EDID_LENGTH * (1 + edid1->extensions);
edid2_len = EDID_LENGTH * (1 + edid2->extensions);
edid1_len = edid_size(edid1);
edid2_len = edid_size(edid2);
if (edid1_len != edid2_len)
return false;
@ -1865,14 +1897,16 @@ EXPORT_SYMBOL(drm_edid_block_valid);
bool drm_edid_is_valid(struct edid *edid)
{
int i;
u8 *raw = (u8 *)edid;
if (!edid)
return false;
for (i = 0; i <= edid->extensions; i++)
if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true, NULL))
for (i = 0; i < edid_block_count(edid); i++) {
void *block = (void *)edid_block_data(edid, i);
if (!drm_edid_block_valid(block, i, true, NULL))
return false;
}
return true;
}
@ -1885,13 +1919,13 @@ static struct edid *edid_filter_invalid_blocks(const struct edid *edid,
int valid_extensions = edid->extensions - invalid_blocks;
int i;
new = kmalloc_array(valid_extensions + 1, EDID_LENGTH, GFP_KERNEL);
new = kmalloc(edid_size_by_blocks(valid_extensions + 1), GFP_KERNEL);
if (!new)
goto out;
dest_block = new;
for (i = 0; i <= edid->extensions; i++) {
const void *block = edid + i;
for (i = 0; i < edid_block_count(edid); i++) {
const void *block = edid_block_data(edid, i);
if (edid_block_valid(block, i == 0))
memcpy(dest_block++, block, EDID_LENGTH);
@ -2101,7 +2135,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
void *context)
{
enum edid_block_status status;
int j, invalid_blocks = 0;
int i, invalid_blocks = 0;
struct edid *edid, *new;
edid = drm_get_override_edid(connector);
@ -2133,20 +2167,20 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
goto fail;
}
if (edid->extensions == 0)
if (!edid_extension_block_count(edid))
goto ok;
new = krealloc(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL);
new = krealloc(edid, edid_size(edid), GFP_KERNEL);
if (!new)
goto fail;
edid = new;
for (j = 1; j <= edid->extensions; j++) {
void *block = edid + j;
for (i = 1; i < edid_block_count(edid); i++) {
void *block = (void *)edid_block_data(edid, i);
status = edid_block_read(block, j, read_block, context);
status = edid_block_read(block, i, read_block, context);
edid_block_status_print(status, block, j);
edid_block_status_print(status, block, i);
if (!edid_block_status_valid(status, edid_block_tag(block))) {
if (status == EDID_BLOCK_READ_FAIL)
@ -2156,7 +2190,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
}
if (invalid_blocks) {
connector_bad_edid(connector, edid, edid->extensions + 1);
connector_bad_edid(connector, edid, edid_block_count(edid));
edid = edid_filter_invalid_blocks(edid, invalid_blocks);
}
@ -2321,7 +2355,7 @@ EXPORT_SYMBOL(drm_get_edid_switcheroo);
*/
struct edid *drm_edid_duplicate(const struct edid *edid)
{
return kmemdup(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL);
return kmemdup(edid, edid_size(edid), GFP_KERNEL);
}
EXPORT_SYMBOL(drm_edid_duplicate);
@ -2505,8 +2539,8 @@ drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *clos
for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
cb(&(edid->detailed_timings[i]), closure);
for (i = 1; i <= edid->extensions; i++) {
const u8 *ext = (const u8 *)edid + (i * EDID_LENGTH);
for (i = 0; i < edid_extension_block_count(edid); i++) {
const u8 *ext = edid_extension_block_data(edid, i);
switch (*ext) {
case CEA_EXT:
@ -3476,17 +3510,17 @@ const u8 *drm_find_edid_extension(const struct edid *edid,
int i;
/* No EDID or EDID extensions */
if (edid == NULL || edid->extensions == 0)
if (!edid || !edid_extension_block_count(edid))
return NULL;
/* Find CEA extension */
for (i = *ext_index; i < edid->extensions; i++) {
edid_ext = (const u8 *)edid + EDID_LENGTH * (i + 1);
for (i = *ext_index; i < edid_extension_block_count(edid); i++) {
edid_ext = edid_extension_block_data(edid, i);
if (edid_block_tag(edid_ext) == ext_id)
break;
}
if (i >= edid->extensions)
if (i >= edid_extension_block_count(edid))
return NULL;
*ext_index = i + 1;