Commit f1e4c916 authored by Jani Nikula's avatar Jani Nikula

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: default avatarJani Nikula <jani.nikula@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/dc7b0850293d837439fb3914c8a9d81e39018b4b.1649685475.git.jani.nikula@intel.com
parent 1c788f69
...@@ -1568,6 +1568,38 @@ static const struct drm_display_mode edid_4k_modes[] = { ...@@ -1568,6 +1568,38 @@ static const struct drm_display_mode edid_4k_modes[] = {
/*** DDC fetch and block validation ***/ /*** 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[] = { static const u8 edid_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 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) ...@@ -1654,8 +1686,8 @@ bool drm_edid_are_equal(const struct edid *edid1, const struct edid *edid2)
return false; return false;
if (edid1) { if (edid1) {
edid1_len = EDID_LENGTH * (1 + edid1->extensions); edid1_len = edid_size(edid1);
edid2_len = EDID_LENGTH * (1 + edid2->extensions); edid2_len = edid_size(edid2);
if (edid1_len != edid2_len) if (edid1_len != edid2_len)
return false; return false;
...@@ -1865,14 +1897,16 @@ EXPORT_SYMBOL(drm_edid_block_valid); ...@@ -1865,14 +1897,16 @@ EXPORT_SYMBOL(drm_edid_block_valid);
bool drm_edid_is_valid(struct edid *edid) bool drm_edid_is_valid(struct edid *edid)
{ {
int i; int i;
u8 *raw = (u8 *)edid;
if (!edid) if (!edid)
return false; return false;
for (i = 0; i <= edid->extensions; i++) for (i = 0; i < edid_block_count(edid); i++) {
if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true, NULL)) void *block = (void *)edid_block_data(edid, i);
if (!drm_edid_block_valid(block, i, true, NULL))
return false; return false;
}
return true; return true;
} }
...@@ -1885,13 +1919,13 @@ static struct edid *edid_filter_invalid_blocks(const struct edid *edid, ...@@ -1885,13 +1919,13 @@ static struct edid *edid_filter_invalid_blocks(const struct edid *edid,
int valid_extensions = edid->extensions - invalid_blocks; int valid_extensions = edid->extensions - invalid_blocks;
int i; 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) if (!new)
goto out; goto out;
dest_block = new; dest_block = new;
for (i = 0; i <= edid->extensions; i++) { for (i = 0; i < edid_block_count(edid); i++) {
const void *block = edid + i; const void *block = edid_block_data(edid, i);
if (edid_block_valid(block, i == 0)) if (edid_block_valid(block, i == 0))
memcpy(dest_block++, block, EDID_LENGTH); memcpy(dest_block++, block, EDID_LENGTH);
...@@ -2101,7 +2135,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -2101,7 +2135,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
void *context) void *context)
{ {
enum edid_block_status status; enum edid_block_status status;
int j, invalid_blocks = 0; int i, invalid_blocks = 0;
struct edid *edid, *new; struct edid *edid, *new;
edid = drm_get_override_edid(connector); edid = drm_get_override_edid(connector);
...@@ -2133,20 +2167,20 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -2133,20 +2167,20 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
goto fail; goto fail;
} }
if (edid->extensions == 0) if (!edid_extension_block_count(edid))
goto ok; goto ok;
new = krealloc(edid, (edid->extensions + 1) * EDID_LENGTH, GFP_KERNEL); new = krealloc(edid, edid_size(edid), GFP_KERNEL);
if (!new) if (!new)
goto fail; goto fail;
edid = new; edid = new;
for (j = 1; j <= edid->extensions; j++) { for (i = 1; i < edid_block_count(edid); i++) {
void *block = edid + j; 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 (!edid_block_status_valid(status, edid_block_tag(block))) {
if (status == EDID_BLOCK_READ_FAIL) if (status == EDID_BLOCK_READ_FAIL)
...@@ -2156,7 +2190,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, ...@@ -2156,7 +2190,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
} }
if (invalid_blocks) { 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); edid = edid_filter_invalid_blocks(edid, invalid_blocks);
} }
...@@ -2321,7 +2355,7 @@ EXPORT_SYMBOL(drm_get_edid_switcheroo); ...@@ -2321,7 +2355,7 @@ EXPORT_SYMBOL(drm_get_edid_switcheroo);
*/ */
struct edid *drm_edid_duplicate(const struct edid *edid) 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); EXPORT_SYMBOL(drm_edid_duplicate);
...@@ -2505,8 +2539,8 @@ drm_for_each_detailed_block(const struct edid *edid, detailed_cb *cb, void *clos ...@@ -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++) for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
cb(&(edid->detailed_timings[i]), closure); cb(&(edid->detailed_timings[i]), closure);
for (i = 1; i <= edid->extensions; i++) { for (i = 0; i < edid_extension_block_count(edid); i++) {
const u8 *ext = (const u8 *)edid + (i * EDID_LENGTH); const u8 *ext = edid_extension_block_data(edid, i);
switch (*ext) { switch (*ext) {
case CEA_EXT: case CEA_EXT:
...@@ -3476,17 +3510,17 @@ const u8 *drm_find_edid_extension(const struct edid *edid, ...@@ -3476,17 +3510,17 @@ const u8 *drm_find_edid_extension(const struct edid *edid,
int i; int i;
/* No EDID or EDID extensions */ /* No EDID or EDID extensions */
if (edid == NULL || edid->extensions == 0) if (!edid || !edid_extension_block_count(edid))
return NULL; return NULL;
/* Find CEA extension */ /* Find CEA extension */
for (i = *ext_index; i < edid->extensions; i++) { for (i = *ext_index; i < edid_extension_block_count(edid); i++) {
edid_ext = (const u8 *)edid + EDID_LENGTH * (i + 1); edid_ext = edid_extension_block_data(edid, i);
if (edid_block_tag(edid_ext) == ext_id) if (edid_block_tag(edid_ext) == ext_id)
break; break;
} }
if (i >= edid->extensions) if (i >= edid_extension_block_count(edid))
return NULL; return NULL;
*ext_index = i + 1; *ext_index = i + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment