Skip to content

Commit d3b542f

Browse files
Shobhit Kumardanvet
Shobhit Kumar
authored andcommitted
drm/i915: Add parsing support for new MIPI blocks in VBT
The parser extracts the config block(#52) and sequence(#53) data and store in private data structures. v2: Address review comments by Jani - adjust code for the structure changes for bdb_mipi_config - add boundry and buffer overflow checks as suggested - use kmemdup instead of kmalloc and memcpy v3: More strict check while parsing VBT - Ensure that at anytime we do not go beyond sequence block while parsing - On unknown element fail the whole parsing v4: Style changes and spell check mostly as suggested by Jani Signed-off-by: Shobhit Kumar <[email protected]> Reviewed-by: Jani Nikula <[email protected]> Signed-off-by: Daniel Vetter <[email protected]>
1 parent 773875b commit d3b542f

File tree

3 files changed

+236
-5
lines changed

3 files changed

+236
-5
lines changed

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,12 @@ struct intel_vbt_data {
11691169
/* MIPI DSI */
11701170
struct {
11711171
u16 panel_id;
1172+
struct mipi_config *config;
1173+
struct mipi_pps_data *pps;
1174+
u8 seq_version;
1175+
u32 size;
1176+
u8 *data;
1177+
u8 *sequence[MIPI_SEQ_MAX];
11721178
} dsi;
11731179

11741180
int crt_ddc_pin;

drivers/gpu/drm/i915/intel_bios.c

Lines changed: 199 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -626,19 +626,213 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
626626
}
627627
}
628628

629+
static u8 *goto_next_sequence(u8 *data, int *size)
630+
{
631+
u16 len;
632+
int tmp = *size;
633+
634+
if (--tmp < 0)
635+
return NULL;
636+
637+
/* goto first element */
638+
data++;
639+
while (1) {
640+
switch (*data) {
641+
case MIPI_SEQ_ELEM_SEND_PKT:
642+
/*
643+
* skip by this element payload size
644+
* skip elem id, command flag and data type
645+
*/
646+
if ((tmp = tmp - 5) < 0)
647+
return NULL;
648+
649+
data += 3;
650+
len = *((u16 *)data);
651+
652+
if ((tmp = tmp - len) < 0)
653+
return NULL;
654+
655+
/* skip by len */
656+
data = data + 2 + len;
657+
break;
658+
case MIPI_SEQ_ELEM_DELAY:
659+
/* skip by elem id, and delay is 4 bytes */
660+
if ((tmp = tmp - 5) < 0)
661+
return NULL;
662+
663+
data += 5;
664+
break;
665+
case MIPI_SEQ_ELEM_GPIO:
666+
if ((tmp = tmp - 3) < 0)
667+
return NULL;
668+
669+
data += 3;
670+
break;
671+
default:
672+
DRM_ERROR("Unknown element\n");
673+
return NULL;
674+
}
675+
676+
/* end of sequence ? */
677+
if (*data == 0)
678+
break;
679+
}
680+
681+
/* goto next sequence or end of block byte */
682+
if (--tmp < 0)
683+
return NULL;
684+
685+
data++;
686+
687+
/* update amount of data left for the sequence block to be parsed */
688+
*size = tmp;
689+
return data;
690+
}
691+
629692
static void
630693
parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
631694
{
632-
struct bdb_mipi *mipi;
695+
struct bdb_mipi_config *start;
696+
struct bdb_mipi_sequence *sequence;
697+
struct mipi_config *config;
698+
struct mipi_pps_data *pps;
699+
u8 *data, *seq_data;
700+
int i, panel_id, seq_size;
701+
u16 block_size;
702+
703+
/* Initialize this to undefined indicating no generic MIPI support */
704+
dev_priv->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID;
705+
706+
/* Block #40 is already parsed and panel_fixed_mode is
707+
* stored in dev_priv->lfp_lvds_vbt_mode
708+
* resuse this when needed
709+
*/
633710

634-
mipi = find_section(bdb, BDB_MIPI_CONFIG);
635-
if (!mipi) {
636-
DRM_DEBUG_KMS("No MIPI BDB found");
711+
/* Parse #52 for panel index used from panel_type already
712+
* parsed
713+
*/
714+
start = find_section(bdb, BDB_MIPI_CONFIG);
715+
if (!start) {
716+
DRM_DEBUG_KMS("No MIPI config BDB found");
637717
return;
638718
}
639719

640-
/* XXX: add more info */
720+
DRM_DEBUG_DRIVER("Found MIPI Config block, panel index = %d\n",
721+
panel_type);
722+
723+
/*
724+
* get hold of the correct configuration block and pps data as per
725+
* the panel_type as index
726+
*/
727+
config = &start->config[panel_type];
728+
pps = &start->pps[panel_type];
729+
730+
/* store as of now full data. Trim when we realise all is not needed */
731+
dev_priv->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL);
732+
if (!dev_priv->vbt.dsi.config)
733+
return;
734+
735+
dev_priv->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL);
736+
if (!dev_priv->vbt.dsi.pps) {
737+
kfree(dev_priv->vbt.dsi.config);
738+
return;
739+
}
740+
741+
/* We have mandatory mipi config blocks. Initialize as generic panel */
641742
dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
743+
744+
/* Check if we have sequence block as well */
745+
sequence = find_section(bdb, BDB_MIPI_SEQUENCE);
746+
if (!sequence) {
747+
DRM_DEBUG_KMS("No MIPI Sequence found, parsing complete\n");
748+
return;
749+
}
750+
751+
DRM_DEBUG_DRIVER("Found MIPI sequence block\n");
752+
753+
block_size = get_blocksize(sequence);
754+
755+
/*
756+
* parse the sequence block for individual sequences
757+
*/
758+
dev_priv->vbt.dsi.seq_version = sequence->version;
759+
760+
seq_data = &sequence->data[0];
761+
762+
/*
763+
* sequence block is variable length and hence we need to parse and
764+
* get the sequence data for specific panel id
765+
*/
766+
for (i = 0; i < MAX_MIPI_CONFIGURATIONS; i++) {
767+
panel_id = *seq_data;
768+
seq_size = *((u16 *) (seq_data + 1));
769+
if (panel_id == panel_type)
770+
break;
771+
772+
/* skip the sequence including seq header of 3 bytes */
773+
seq_data = seq_data + 3 + seq_size;
774+
if ((seq_data - &sequence->data[0]) > block_size) {
775+
DRM_ERROR("Sequence start is beyond sequence block size, corrupted sequence block\n");
776+
return;
777+
}
778+
}
779+
780+
if (i == MAX_MIPI_CONFIGURATIONS) {
781+
DRM_ERROR("Sequence block detected but no valid configuration\n");
782+
return;
783+
}
784+
785+
/* check if found sequence is completely within the sequence block
786+
* just being paranoid */
787+
if (seq_size > block_size) {
788+
DRM_ERROR("Corrupted sequence/size, bailing out\n");
789+
return;
790+
}
791+
792+
/* skip the panel id(1 byte) and seq size(2 bytes) */
793+
dev_priv->vbt.dsi.data = kmemdup(seq_data + 3, seq_size, GFP_KERNEL);
794+
if (!dev_priv->vbt.dsi.data)
795+
return;
796+
797+
/*
798+
* loop into the sequence data and split into multiple sequneces
799+
* There are only 5 types of sequences as of now
800+
*/
801+
data = dev_priv->vbt.dsi.data;
802+
dev_priv->vbt.dsi.size = seq_size;
803+
804+
/* two consecutive 0x00 indicate end of all sequences */
805+
while (1) {
806+
int seq_id = *data;
807+
if (MIPI_SEQ_MAX > seq_id && seq_id > MIPI_SEQ_UNDEFINED) {
808+
dev_priv->vbt.dsi.sequence[seq_id] = data;
809+
DRM_DEBUG_DRIVER("Found mipi sequence - %d\n", seq_id);
810+
} else {
811+
DRM_ERROR("undefined sequence\n");
812+
goto err;
813+
}
814+
815+
/* partial parsing to skip elements */
816+
data = goto_next_sequence(data, &seq_size);
817+
818+
if (data == NULL) {
819+
DRM_ERROR("Sequence elements going beyond block itself. Sequence block parsing failed\n");
820+
goto err;
821+
}
822+
823+
if (*data == 0)
824+
break; /* end of sequence reached */
825+
}
826+
827+
DRM_DEBUG_DRIVER("MIPI related vbt parsing complete\n");
828+
return;
829+
err:
830+
kfree(dev_priv->vbt.dsi.data);
831+
dev_priv->vbt.dsi.data = NULL;
832+
833+
/* error during parsing so set all pointers to null
834+
* because of partial parsing */
835+
memset(dev_priv->vbt.dsi.sequence, 0, MIPI_SEQ_MAX);
642836
}
643837

644838
static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,

drivers/gpu/drm/i915/intel_bios.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,4 +896,35 @@ struct bdb_mipi_sequence {
896896
u8 data[0];
897897
};
898898

899+
/* MIPI Sequnece Block definitions */
900+
enum mipi_seq {
901+
MIPI_SEQ_UNDEFINED = 0,
902+
MIPI_SEQ_ASSERT_RESET,
903+
MIPI_SEQ_INIT_OTP,
904+
MIPI_SEQ_DISPLAY_ON,
905+
MIPI_SEQ_DISPLAY_OFF,
906+
MIPI_SEQ_DEASSERT_RESET,
907+
MIPI_SEQ_MAX
908+
};
909+
910+
enum mipi_seq_element {
911+
MIPI_SEQ_ELEM_UNDEFINED = 0,
912+
MIPI_SEQ_ELEM_SEND_PKT,
913+
MIPI_SEQ_ELEM_DELAY,
914+
MIPI_SEQ_ELEM_GPIO,
915+
MIPI_SEQ_ELEM_STATUS,
916+
MIPI_SEQ_ELEM_MAX
917+
};
918+
919+
enum mipi_gpio_pin_index {
920+
MIPI_GPIO_UNDEFINED = 0,
921+
MIPI_GPIO_PANEL_ENABLE,
922+
MIPI_GPIO_BL_ENABLE,
923+
MIPI_GPIO_PWM_ENABLE,
924+
MIPI_GPIO_RESET_N,
925+
MIPI_GPIO_PWR_DOWN_R,
926+
MIPI_GPIO_STDBY_RST_N,
927+
MIPI_GPIO_MAX
928+
};
929+
899930
#endif /* _I830_BIOS_H_ */

0 commit comments

Comments
 (0)