cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

panel-boe-himax8279d.c (18598B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
      4 *
      5 * Author: Jerry Han <jerry.han.hq@gmail.com>
      6 *
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <linux/of_device.h>
     14
     15#include <linux/gpio/consumer.h>
     16#include <linux/regulator/consumer.h>
     17
     18#include <drm/drm_device.h>
     19#include <drm/drm_mipi_dsi.h>
     20#include <drm/drm_modes.h>
     21#include <drm/drm_panel.h>
     22
     23#include <video/mipi_display.h>
     24
     25struct panel_cmd {
     26	char cmd;
     27	char data;
     28};
     29
     30struct panel_desc {
     31	const struct drm_display_mode *display_mode;
     32	unsigned int bpc;
     33	unsigned int width_mm;
     34	unsigned int height_mm;
     35
     36	unsigned long mode_flags;
     37	enum mipi_dsi_pixel_format format;
     38	unsigned int lanes;
     39	const struct panel_cmd *on_cmds;
     40	unsigned int on_cmds_num;
     41};
     42
     43struct panel_info {
     44	struct drm_panel base;
     45	struct mipi_dsi_device *link;
     46	const struct panel_desc *desc;
     47
     48	struct gpio_desc *enable_gpio;
     49	struct gpio_desc *pp33_gpio;
     50	struct gpio_desc *pp18_gpio;
     51
     52	bool prepared;
     53	bool enabled;
     54};
     55
     56static inline struct panel_info *to_panel_info(struct drm_panel *panel)
     57{
     58	return container_of(panel, struct panel_info, base);
     59}
     60
     61static void disable_gpios(struct panel_info *pinfo)
     62{
     63	gpiod_set_value(pinfo->enable_gpio, 0);
     64	gpiod_set_value(pinfo->pp33_gpio, 0);
     65	gpiod_set_value(pinfo->pp18_gpio, 0);
     66}
     67
     68static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
     69{
     70	struct panel_info *pinfo = to_panel_info(panel);
     71	unsigned int i = 0;
     72	int err;
     73
     74	for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
     75		err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
     76						sizeof(struct panel_cmd));
     77
     78		if (err < 0)
     79			return err;
     80	}
     81
     82	return 0;
     83}
     84
     85static int boe_panel_disable(struct drm_panel *panel)
     86{
     87	struct panel_info *pinfo = to_panel_info(panel);
     88	int err;
     89
     90	if (!pinfo->enabled)
     91		return 0;
     92
     93	err = mipi_dsi_dcs_set_display_off(pinfo->link);
     94	if (err < 0) {
     95		dev_err(panel->dev, "failed to set display off: %d\n", err);
     96		return err;
     97	}
     98
     99	pinfo->enabled = false;
    100
    101	return 0;
    102}
    103
    104static int boe_panel_unprepare(struct drm_panel *panel)
    105{
    106	struct panel_info *pinfo = to_panel_info(panel);
    107	int err;
    108
    109	if (!pinfo->prepared)
    110		return 0;
    111
    112	err = mipi_dsi_dcs_set_display_off(pinfo->link);
    113	if (err < 0)
    114		dev_err(panel->dev, "failed to set display off: %d\n", err);
    115
    116	err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
    117	if (err < 0)
    118		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
    119
    120	/* sleep_mode_delay: 1ms - 2ms */
    121	usleep_range(1000, 2000);
    122
    123	disable_gpios(pinfo);
    124
    125	pinfo->prepared = false;
    126
    127	return 0;
    128}
    129
    130static int boe_panel_prepare(struct drm_panel *panel)
    131{
    132	struct panel_info *pinfo = to_panel_info(panel);
    133	int err;
    134
    135	if (pinfo->prepared)
    136		return 0;
    137
    138	gpiod_set_value(pinfo->pp18_gpio, 1);
    139	/* T1: 5ms - 6ms */
    140	usleep_range(5000, 6000);
    141	gpiod_set_value(pinfo->pp33_gpio, 1);
    142
    143	/* reset sequence */
    144	/* T2: 14ms - 15ms */
    145	usleep_range(14000, 15000);
    146	gpiod_set_value(pinfo->enable_gpio, 1);
    147
    148	/* T3: 1ms - 2ms */
    149	usleep_range(1000, 2000);
    150	gpiod_set_value(pinfo->enable_gpio, 0);
    151
    152	/* T4: 1ms - 2ms */
    153	usleep_range(1000, 2000);
    154	gpiod_set_value(pinfo->enable_gpio, 1);
    155
    156	/* T5: 5ms - 6ms */
    157	usleep_range(5000, 6000);
    158
    159	/* send init code */
    160	err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
    161	if (err < 0) {
    162		dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
    163		goto poweroff;
    164	}
    165
    166	err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
    167	if (err < 0) {
    168		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
    169		goto poweroff;
    170	}
    171
    172	/* T6: 120ms - 121ms */
    173	usleep_range(120000, 121000);
    174
    175	err = mipi_dsi_dcs_set_display_on(pinfo->link);
    176	if (err < 0) {
    177		dev_err(panel->dev, "failed to set display on: %d\n", err);
    178		goto poweroff;
    179	}
    180
    181	/* T7: 20ms - 21ms */
    182	usleep_range(20000, 21000);
    183
    184	pinfo->prepared = true;
    185
    186	return 0;
    187
    188poweroff:
    189	disable_gpios(pinfo);
    190	return err;
    191}
    192
    193static int boe_panel_enable(struct drm_panel *panel)
    194{
    195	struct panel_info *pinfo = to_panel_info(panel);
    196	int ret;
    197
    198	if (pinfo->enabled)
    199		return 0;
    200
    201	usleep_range(120000, 121000);
    202
    203	ret = mipi_dsi_dcs_set_display_on(pinfo->link);
    204	if (ret < 0) {
    205		dev_err(panel->dev, "failed to set display on: %d\n", ret);
    206		return ret;
    207	}
    208
    209	pinfo->enabled = true;
    210
    211	return 0;
    212}
    213
    214static int boe_panel_get_modes(struct drm_panel *panel,
    215			       struct drm_connector *connector)
    216{
    217	struct panel_info *pinfo = to_panel_info(panel);
    218	const struct drm_display_mode *m = pinfo->desc->display_mode;
    219	struct drm_display_mode *mode;
    220
    221	mode = drm_mode_duplicate(connector->dev, m);
    222	if (!mode) {
    223		dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
    224			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
    225		return -ENOMEM;
    226	}
    227
    228	drm_mode_set_name(mode);
    229
    230	drm_mode_probed_add(connector, mode);
    231
    232	connector->display_info.width_mm = pinfo->desc->width_mm;
    233	connector->display_info.height_mm = pinfo->desc->height_mm;
    234	connector->display_info.bpc = pinfo->desc->bpc;
    235
    236	return 1;
    237}
    238
    239static const struct drm_panel_funcs panel_funcs = {
    240	.disable = boe_panel_disable,
    241	.unprepare = boe_panel_unprepare,
    242	.prepare = boe_panel_prepare,
    243	.enable = boe_panel_enable,
    244	.get_modes = boe_panel_get_modes,
    245};
    246
    247static const struct drm_display_mode default_display_mode = {
    248	.clock = 159420,
    249	.hdisplay = 1200,
    250	.hsync_start = 1200 + 80,
    251	.hsync_end = 1200 + 80 + 60,
    252	.htotal = 1200 + 80 + 60 + 24,
    253	.vdisplay = 1920,
    254	.vsync_start = 1920 + 10,
    255	.vsync_end = 1920 + 10 + 14,
    256	.vtotal = 1920 + 10 + 14 + 4,
    257};
    258
    259/* 8 inch */
    260static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
    261	{ 0xB0, 0x05 },
    262	{ 0xB1, 0xE5 },
    263	{ 0xB3, 0x52 },
    264	{ 0xC0, 0x00 },
    265	{ 0xC2, 0x57 },
    266	{ 0xD9, 0x85 },
    267	{ 0xB0, 0x01 },
    268	{ 0xC8, 0x00 },
    269	{ 0xC9, 0x00 },
    270	{ 0xCC, 0x26 },
    271	{ 0xCD, 0x26 },
    272	{ 0xDC, 0x00 },
    273	{ 0xDD, 0x00 },
    274	{ 0xE0, 0x26 },
    275	{ 0xE1, 0x26 },
    276	{ 0xB0, 0x03 },
    277	{ 0xC3, 0x2A },
    278	{ 0xE7, 0x2A },
    279	{ 0xC5, 0x2A },
    280	{ 0xDE, 0x2A },
    281	{ 0xBC, 0x02 },
    282	{ 0xCB, 0x02 },
    283	{ 0xB0, 0x00 },
    284	{ 0xB6, 0x03 },
    285	{ 0xBA, 0x8B },
    286	{ 0xBF, 0x15 },
    287	{ 0xC0, 0x18 },
    288	{ 0xC2, 0x14 },
    289	{ 0xC3, 0x02 },
    290	{ 0xC4, 0x14 },
    291	{ 0xC5, 0x02 },
    292	{ 0xCC, 0x0A },
    293	{ 0xB0, 0x06 },
    294	{ 0xC0, 0xA5 },
    295	{ 0xD5, 0x20 },
    296	{ 0xC0, 0x00 },
    297	{ 0xB0, 0x02 },
    298	{ 0xC0, 0x00 },
    299	{ 0xC1, 0x02 },
    300	{ 0xC2, 0x06 },
    301	{ 0xC3, 0x16 },
    302	{ 0xC4, 0x0E },
    303	{ 0xC5, 0x18 },
    304	{ 0xC6, 0x26 },
    305	{ 0xC7, 0x32 },
    306	{ 0xC8, 0x3F },
    307	{ 0xC9, 0x3F },
    308	{ 0xCA, 0x3F },
    309	{ 0xCB, 0x3F },
    310	{ 0xCC, 0x3D },
    311	{ 0xCD, 0x2F },
    312	{ 0xCE, 0x2F },
    313	{ 0xCF, 0x2F },
    314	{ 0xD0, 0x07 },
    315	{ 0xD2, 0x00 },
    316	{ 0xD3, 0x02 },
    317	{ 0xD4, 0x06 },
    318	{ 0xD5, 0x12 },
    319	{ 0xD6, 0x0A },
    320	{ 0xD7, 0x14 },
    321	{ 0xD8, 0x22 },
    322	{ 0xD9, 0x2E },
    323	{ 0xDA, 0x3D },
    324	{ 0xDB, 0x3F },
    325	{ 0xDC, 0x3F },
    326	{ 0xDD, 0x3F },
    327	{ 0xDE, 0x3D },
    328	{ 0xDF, 0x2F },
    329	{ 0xE0, 0x2F },
    330	{ 0xE1, 0x2F },
    331	{ 0xE2, 0x07 },
    332	{ 0xB0, 0x07 },
    333	{ 0xB1, 0x18 },
    334	{ 0xB2, 0x19 },
    335	{ 0xB3, 0x2E },
    336	{ 0xB4, 0x52 },
    337	{ 0xB5, 0x72 },
    338	{ 0xB6, 0x8C },
    339	{ 0xB7, 0xBD },
    340	{ 0xB8, 0xEB },
    341	{ 0xB9, 0x47 },
    342	{ 0xBA, 0x96 },
    343	{ 0xBB, 0x1E },
    344	{ 0xBC, 0x90 },
    345	{ 0xBD, 0x93 },
    346	{ 0xBE, 0xFA },
    347	{ 0xBF, 0x56 },
    348	{ 0xC0, 0x8C },
    349	{ 0xC1, 0xB7 },
    350	{ 0xC2, 0xCC },
    351	{ 0xC3, 0xDF },
    352	{ 0xC4, 0xE8 },
    353	{ 0xC5, 0xF0 },
    354	{ 0xC6, 0xF8 },
    355	{ 0xC7, 0xFA },
    356	{ 0xC8, 0xFC },
    357	{ 0xC9, 0x00 },
    358	{ 0xCA, 0x00 },
    359	{ 0xCB, 0x5A },
    360	{ 0xCC, 0xAF },
    361	{ 0xCD, 0xFF },
    362	{ 0xCE, 0xFF },
    363	{ 0xB0, 0x08 },
    364	{ 0xB1, 0x04 },
    365	{ 0xB2, 0x15 },
    366	{ 0xB3, 0x2D },
    367	{ 0xB4, 0x51 },
    368	{ 0xB5, 0x72 },
    369	{ 0xB6, 0x8D },
    370	{ 0xB7, 0xBE },
    371	{ 0xB8, 0xED },
    372	{ 0xB9, 0x4A },
    373	{ 0xBA, 0x9A },
    374	{ 0xBB, 0x23 },
    375	{ 0xBC, 0x95 },
    376	{ 0xBD, 0x98 },
    377	{ 0xBE, 0xFF },
    378	{ 0xBF, 0x59 },
    379	{ 0xC0, 0x8E },
    380	{ 0xC1, 0xB9 },
    381	{ 0xC2, 0xCD },
    382	{ 0xC3, 0xDF },
    383	{ 0xC4, 0xE8 },
    384	{ 0xC5, 0xF0 },
    385	{ 0xC6, 0xF8 },
    386	{ 0xC7, 0xFA },
    387	{ 0xC8, 0xFC },
    388	{ 0xC9, 0x00 },
    389	{ 0xCA, 0x00 },
    390	{ 0xCB, 0x5A },
    391	{ 0xCC, 0xAF },
    392	{ 0xCD, 0xFF },
    393	{ 0xCE, 0xFF },
    394	{ 0xB0, 0x09 },
    395	{ 0xB1, 0x04 },
    396	{ 0xB2, 0x2C },
    397	{ 0xB3, 0x36 },
    398	{ 0xB4, 0x53 },
    399	{ 0xB5, 0x73 },
    400	{ 0xB6, 0x8E },
    401	{ 0xB7, 0xC0 },
    402	{ 0xB8, 0xEF },
    403	{ 0xB9, 0x4C },
    404	{ 0xBA, 0x9D },
    405	{ 0xBB, 0x25 },
    406	{ 0xBC, 0x96 },
    407	{ 0xBD, 0x9A },
    408	{ 0xBE, 0x01 },
    409	{ 0xBF, 0x59 },
    410	{ 0xC0, 0x8E },
    411	{ 0xC1, 0xB9 },
    412	{ 0xC2, 0xCD },
    413	{ 0xC3, 0xDF },
    414	{ 0xC4, 0xE8 },
    415	{ 0xC5, 0xF0 },
    416	{ 0xC6, 0xF8 },
    417	{ 0xC7, 0xFA },
    418	{ 0xC8, 0xFC },
    419	{ 0xC9, 0x00 },
    420	{ 0xCA, 0x00 },
    421	{ 0xCB, 0x5A },
    422	{ 0xCC, 0xBF },
    423	{ 0xCD, 0xFF },
    424	{ 0xCE, 0xFF },
    425	{ 0xB0, 0x0A },
    426	{ 0xB1, 0x18 },
    427	{ 0xB2, 0x19 },
    428	{ 0xB3, 0x2E },
    429	{ 0xB4, 0x52 },
    430	{ 0xB5, 0x72 },
    431	{ 0xB6, 0x8C },
    432	{ 0xB7, 0xBD },
    433	{ 0xB8, 0xEB },
    434	{ 0xB9, 0x47 },
    435	{ 0xBA, 0x96 },
    436	{ 0xBB, 0x1E },
    437	{ 0xBC, 0x90 },
    438	{ 0xBD, 0x93 },
    439	{ 0xBE, 0xFA },
    440	{ 0xBF, 0x56 },
    441	{ 0xC0, 0x8C },
    442	{ 0xC1, 0xB7 },
    443	{ 0xC2, 0xCC },
    444	{ 0xC3, 0xDF },
    445	{ 0xC4, 0xE8 },
    446	{ 0xC5, 0xF0 },
    447	{ 0xC6, 0xF8 },
    448	{ 0xC7, 0xFA },
    449	{ 0xC8, 0xFC },
    450	{ 0xC9, 0x00 },
    451	{ 0xCA, 0x00 },
    452	{ 0xCB, 0x5A },
    453	{ 0xCC, 0xAF },
    454	{ 0xCD, 0xFF },
    455	{ 0xCE, 0xFF },
    456	{ 0xB0, 0x0B },
    457	{ 0xB1, 0x04 },
    458	{ 0xB2, 0x15 },
    459	{ 0xB3, 0x2D },
    460	{ 0xB4, 0x51 },
    461	{ 0xB5, 0x72 },
    462	{ 0xB6, 0x8D },
    463	{ 0xB7, 0xBE },
    464	{ 0xB8, 0xED },
    465	{ 0xB9, 0x4A },
    466	{ 0xBA, 0x9A },
    467	{ 0xBB, 0x23 },
    468	{ 0xBC, 0x95 },
    469	{ 0xBD, 0x98 },
    470	{ 0xBE, 0xFF },
    471	{ 0xBF, 0x59 },
    472	{ 0xC0, 0x8E },
    473	{ 0xC1, 0xB9 },
    474	{ 0xC2, 0xCD },
    475	{ 0xC3, 0xDF },
    476	{ 0xC4, 0xE8 },
    477	{ 0xC5, 0xF0 },
    478	{ 0xC6, 0xF8 },
    479	{ 0xC7, 0xFA },
    480	{ 0xC8, 0xFC },
    481	{ 0xC9, 0x00 },
    482	{ 0xCA, 0x00 },
    483	{ 0xCB, 0x5A },
    484	{ 0xCC, 0xAF },
    485	{ 0xCD, 0xFF },
    486	{ 0xCE, 0xFF },
    487	{ 0xB0, 0x0C },
    488	{ 0xB1, 0x04 },
    489	{ 0xB2, 0x2C },
    490	{ 0xB3, 0x36 },
    491	{ 0xB4, 0x53 },
    492	{ 0xB5, 0x73 },
    493	{ 0xB6, 0x8E },
    494	{ 0xB7, 0xC0 },
    495	{ 0xB8, 0xEF },
    496	{ 0xB9, 0x4C },
    497	{ 0xBA, 0x9D },
    498	{ 0xBB, 0x25 },
    499	{ 0xBC, 0x96 },
    500	{ 0xBD, 0x9A },
    501	{ 0xBE, 0x01 },
    502	{ 0xBF, 0x59 },
    503	{ 0xC0, 0x8E },
    504	{ 0xC1, 0xB9 },
    505	{ 0xC2, 0xCD },
    506	{ 0xC3, 0xDF },
    507	{ 0xC4, 0xE8 },
    508	{ 0xC5, 0xF0 },
    509	{ 0xC6, 0xF8 },
    510	{ 0xC7, 0xFA },
    511	{ 0xC8, 0xFC },
    512	{ 0xC9, 0x00 },
    513	{ 0xCA, 0x00 },
    514	{ 0xCB, 0x5A },
    515	{ 0xCC, 0xBF },
    516	{ 0xCD, 0xFF },
    517	{ 0xCE, 0xFF },
    518	{ 0xB0, 0x04 },
    519	{ 0xB5, 0x02 },
    520	{ 0xB6, 0x01 },
    521};
    522
    523static const struct panel_desc boe_himax8279d8p_panel_desc = {
    524	.display_mode = &default_display_mode,
    525	.bpc = 8,
    526	.width_mm = 107,
    527	.height_mm = 172,
    528	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
    529			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
    530	.format = MIPI_DSI_FMT_RGB888,
    531	.lanes = 4,
    532	.on_cmds = boe_himax8279d8p_on_cmds,
    533	.on_cmds_num = 260,
    534};
    535
    536/* 10 inch */
    537static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
    538	{ 0xB0, 0x05 },
    539	{ 0xB1, 0xE5 },
    540	{ 0xB3, 0x52 },
    541	{ 0xB0, 0x00 },
    542	{ 0xB6, 0x03 },
    543	{ 0xBA, 0x8B },
    544	{ 0xBF, 0x1A },
    545	{ 0xC0, 0x0F },
    546	{ 0xC2, 0x0C },
    547	{ 0xC3, 0x02 },
    548	{ 0xC4, 0x0C },
    549	{ 0xC5, 0x02 },
    550	{ 0xB0, 0x01 },
    551	{ 0xE0, 0x26 },
    552	{ 0xE1, 0x26 },
    553	{ 0xDC, 0x00 },
    554	{ 0xDD, 0x00 },
    555	{ 0xCC, 0x26 },
    556	{ 0xCD, 0x26 },
    557	{ 0xC8, 0x00 },
    558	{ 0xC9, 0x00 },
    559	{ 0xD2, 0x03 },
    560	{ 0xD3, 0x03 },
    561	{ 0xE6, 0x04 },
    562	{ 0xE7, 0x04 },
    563	{ 0xC4, 0x09 },
    564	{ 0xC5, 0x09 },
    565	{ 0xD8, 0x0A },
    566	{ 0xD9, 0x0A },
    567	{ 0xC2, 0x0B },
    568	{ 0xC3, 0x0B },
    569	{ 0xD6, 0x0C },
    570	{ 0xD7, 0x0C },
    571	{ 0xC0, 0x05 },
    572	{ 0xC1, 0x05 },
    573	{ 0xD4, 0x06 },
    574	{ 0xD5, 0x06 },
    575	{ 0xCA, 0x07 },
    576	{ 0xCB, 0x07 },
    577	{ 0xDE, 0x08 },
    578	{ 0xDF, 0x08 },
    579	{ 0xB0, 0x02 },
    580	{ 0xC0, 0x00 },
    581	{ 0xC1, 0x0D },
    582	{ 0xC2, 0x17 },
    583	{ 0xC3, 0x26 },
    584	{ 0xC4, 0x31 },
    585	{ 0xC5, 0x1C },
    586	{ 0xC6, 0x2C },
    587	{ 0xC7, 0x33 },
    588	{ 0xC8, 0x31 },
    589	{ 0xC9, 0x37 },
    590	{ 0xCA, 0x37 },
    591	{ 0xCB, 0x37 },
    592	{ 0xCC, 0x39 },
    593	{ 0xCD, 0x2E },
    594	{ 0xCE, 0x2F },
    595	{ 0xCF, 0x2F },
    596	{ 0xD0, 0x07 },
    597	{ 0xD2, 0x00 },
    598	{ 0xD3, 0x0D },
    599	{ 0xD4, 0x17 },
    600	{ 0xD5, 0x26 },
    601	{ 0xD6, 0x31 },
    602	{ 0xD7, 0x3F },
    603	{ 0xD8, 0x3F },
    604	{ 0xD9, 0x3F },
    605	{ 0xDA, 0x3F },
    606	{ 0xDB, 0x37 },
    607	{ 0xDC, 0x37 },
    608	{ 0xDD, 0x37 },
    609	{ 0xDE, 0x39 },
    610	{ 0xDF, 0x2E },
    611	{ 0xE0, 0x2F },
    612	{ 0xE1, 0x2F },
    613	{ 0xE2, 0x07 },
    614	{ 0xB0, 0x03 },
    615	{ 0xC8, 0x0B },
    616	{ 0xC9, 0x07 },
    617	{ 0xC3, 0x00 },
    618	{ 0xE7, 0x00 },
    619	{ 0xC5, 0x2A },
    620	{ 0xDE, 0x2A },
    621	{ 0xCA, 0x43 },
    622	{ 0xC9, 0x07 },
    623	{ 0xE4, 0xC0 },
    624	{ 0xE5, 0x0D },
    625	{ 0xCB, 0x01 },
    626	{ 0xBC, 0x01 },
    627	{ 0xB0, 0x06 },
    628	{ 0xB8, 0xA5 },
    629	{ 0xC0, 0xA5 },
    630	{ 0xC7, 0x0F },
    631	{ 0xD5, 0x32 },
    632	{ 0xB8, 0x00 },
    633	{ 0xC0, 0x00 },
    634	{ 0xBC, 0x00 },
    635	{ 0xB0, 0x07 },
    636	{ 0xB1, 0x00 },
    637	{ 0xB2, 0x05 },
    638	{ 0xB3, 0x10 },
    639	{ 0xB4, 0x22 },
    640	{ 0xB5, 0x36 },
    641	{ 0xB6, 0x4A },
    642	{ 0xB7, 0x6C },
    643	{ 0xB8, 0x9A },
    644	{ 0xB9, 0xD7 },
    645	{ 0xBA, 0x17 },
    646	{ 0xBB, 0x92 },
    647	{ 0xBC, 0x15 },
    648	{ 0xBD, 0x18 },
    649	{ 0xBE, 0x8C },
    650	{ 0xBF, 0x00 },
    651	{ 0xC0, 0x3A },
    652	{ 0xC1, 0x72 },
    653	{ 0xC2, 0x8C },
    654	{ 0xC3, 0xA5 },
    655	{ 0xC4, 0xB1 },
    656	{ 0xC5, 0xBE },
    657	{ 0xC6, 0xCA },
    658	{ 0xC7, 0xD1 },
    659	{ 0xC8, 0xD4 },
    660	{ 0xC9, 0x00 },
    661	{ 0xCA, 0x00 },
    662	{ 0xCB, 0x16 },
    663	{ 0xCC, 0xAF },
    664	{ 0xCD, 0xFF },
    665	{ 0xCE, 0xFF },
    666	{ 0xB0, 0x08 },
    667	{ 0xB1, 0x04 },
    668	{ 0xB2, 0x05 },
    669	{ 0xB3, 0x11 },
    670	{ 0xB4, 0x24 },
    671	{ 0xB5, 0x39 },
    672	{ 0xB6, 0x4E },
    673	{ 0xB7, 0x72 },
    674	{ 0xB8, 0xA3 },
    675	{ 0xB9, 0xE1 },
    676	{ 0xBA, 0x25 },
    677	{ 0xBB, 0xA8 },
    678	{ 0xBC, 0x2E },
    679	{ 0xBD, 0x32 },
    680	{ 0xBE, 0xAD },
    681	{ 0xBF, 0x28 },
    682	{ 0xC0, 0x63 },
    683	{ 0xC1, 0x9B },
    684	{ 0xC2, 0xB5 },
    685	{ 0xC3, 0xCF },
    686	{ 0xC4, 0xDB },
    687	{ 0xC5, 0xE8 },
    688	{ 0xC6, 0xF5 },
    689	{ 0xC7, 0xFA },
    690	{ 0xC8, 0xFC },
    691	{ 0xC9, 0x00 },
    692	{ 0xCA, 0x00 },
    693	{ 0xCB, 0x16 },
    694	{ 0xCC, 0xAF },
    695	{ 0xCD, 0xFF },
    696	{ 0xCE, 0xFF },
    697	{ 0xB0, 0x09 },
    698	{ 0xB1, 0x04 },
    699	{ 0xB2, 0x04 },
    700	{ 0xB3, 0x0F },
    701	{ 0xB4, 0x22 },
    702	{ 0xB5, 0x37 },
    703	{ 0xB6, 0x4D },
    704	{ 0xB7, 0x71 },
    705	{ 0xB8, 0xA2 },
    706	{ 0xB9, 0xE1 },
    707	{ 0xBA, 0x26 },
    708	{ 0xBB, 0xA9 },
    709	{ 0xBC, 0x2F },
    710	{ 0xBD, 0x33 },
    711	{ 0xBE, 0xAC },
    712	{ 0xBF, 0x24 },
    713	{ 0xC0, 0x5D },
    714	{ 0xC1, 0x94 },
    715	{ 0xC2, 0xAC },
    716	{ 0xC3, 0xC5 },
    717	{ 0xC4, 0xD1 },
    718	{ 0xC5, 0xDC },
    719	{ 0xC6, 0xE8 },
    720	{ 0xC7, 0xED },
    721	{ 0xC8, 0xF0 },
    722	{ 0xC9, 0x00 },
    723	{ 0xCA, 0x00 },
    724	{ 0xCB, 0x16 },
    725	{ 0xCC, 0xAF },
    726	{ 0xCD, 0xFF },
    727	{ 0xCE, 0xFF },
    728	{ 0xB0, 0x0A },
    729	{ 0xB1, 0x00 },
    730	{ 0xB2, 0x05 },
    731	{ 0xB3, 0x10 },
    732	{ 0xB4, 0x22 },
    733	{ 0xB5, 0x36 },
    734	{ 0xB6, 0x4A },
    735	{ 0xB7, 0x6C },
    736	{ 0xB8, 0x9A },
    737	{ 0xB9, 0xD7 },
    738	{ 0xBA, 0x17 },
    739	{ 0xBB, 0x92 },
    740	{ 0xBC, 0x15 },
    741	{ 0xBD, 0x18 },
    742	{ 0xBE, 0x8C },
    743	{ 0xBF, 0x00 },
    744	{ 0xC0, 0x3A },
    745	{ 0xC1, 0x72 },
    746	{ 0xC2, 0x8C },
    747	{ 0xC3, 0xA5 },
    748	{ 0xC4, 0xB1 },
    749	{ 0xC5, 0xBE },
    750	{ 0xC6, 0xCA },
    751	{ 0xC7, 0xD1 },
    752	{ 0xC8, 0xD4 },
    753	{ 0xC9, 0x00 },
    754	{ 0xCA, 0x00 },
    755	{ 0xCB, 0x16 },
    756	{ 0xCC, 0xAF },
    757	{ 0xCD, 0xFF },
    758	{ 0xCE, 0xFF },
    759	{ 0xB0, 0x0B },
    760	{ 0xB1, 0x04 },
    761	{ 0xB2, 0x05 },
    762	{ 0xB3, 0x11 },
    763	{ 0xB4, 0x24 },
    764	{ 0xB5, 0x39 },
    765	{ 0xB6, 0x4E },
    766	{ 0xB7, 0x72 },
    767	{ 0xB8, 0xA3 },
    768	{ 0xB9, 0xE1 },
    769	{ 0xBA, 0x25 },
    770	{ 0xBB, 0xA8 },
    771	{ 0xBC, 0x2E },
    772	{ 0xBD, 0x32 },
    773	{ 0xBE, 0xAD },
    774	{ 0xBF, 0x28 },
    775	{ 0xC0, 0x63 },
    776	{ 0xC1, 0x9B },
    777	{ 0xC2, 0xB5 },
    778	{ 0xC3, 0xCF },
    779	{ 0xC4, 0xDB },
    780	{ 0xC5, 0xE8 },
    781	{ 0xC6, 0xF5 },
    782	{ 0xC7, 0xFA },
    783	{ 0xC8, 0xFC },
    784	{ 0xC9, 0x00 },
    785	{ 0xCA, 0x00 },
    786	{ 0xCB, 0x16 },
    787	{ 0xCC, 0xAF },
    788	{ 0xCD, 0xFF },
    789	{ 0xCE, 0xFF },
    790	{ 0xB0, 0x0C },
    791	{ 0xB1, 0x04 },
    792	{ 0xB2, 0x04 },
    793	{ 0xB3, 0x0F },
    794	{ 0xB4, 0x22 },
    795	{ 0xB5, 0x37 },
    796	{ 0xB6, 0x4D },
    797	{ 0xB7, 0x71 },
    798	{ 0xB8, 0xA2 },
    799	{ 0xB9, 0xE1 },
    800	{ 0xBA, 0x26 },
    801	{ 0xBB, 0xA9 },
    802	{ 0xBC, 0x2F },
    803	{ 0xBD, 0x33 },
    804	{ 0xBE, 0xAC },
    805	{ 0xBF, 0x24 },
    806	{ 0xC0, 0x5D },
    807	{ 0xC1, 0x94 },
    808	{ 0xC2, 0xAC },
    809	{ 0xC3, 0xC5 },
    810	{ 0xC4, 0xD1 },
    811	{ 0xC5, 0xDC },
    812	{ 0xC6, 0xE8 },
    813	{ 0xC7, 0xED },
    814	{ 0xC8, 0xF0 },
    815	{ 0xC9, 0x00 },
    816	{ 0xCA, 0x00 },
    817	{ 0xCB, 0x16 },
    818	{ 0xCC, 0xAF },
    819	{ 0xCD, 0xFF },
    820	{ 0xCE, 0xFF },
    821};
    822
    823static const struct panel_desc boe_himax8279d10p_panel_desc = {
    824	.display_mode = &default_display_mode,
    825	.bpc = 8,
    826	.width_mm = 135,
    827	.height_mm = 216,
    828	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
    829			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
    830	.format = MIPI_DSI_FMT_RGB888,
    831	.lanes = 4,
    832	.on_cmds = boe_himax8279d10p_on_cmds,
    833	.on_cmds_num = 283,
    834};
    835
    836static const struct of_device_id panel_of_match[] = {
    837	{
    838		.compatible = "boe,himax8279d8p",
    839		.data = &boe_himax8279d8p_panel_desc,
    840	},
    841	{
    842		.compatible = "boe,himax8279d10p",
    843		.data = &boe_himax8279d10p_panel_desc,
    844	},
    845	{
    846		/* sentinel */
    847	}
    848};
    849MODULE_DEVICE_TABLE(of, panel_of_match);
    850
    851static int panel_add(struct panel_info *pinfo)
    852{
    853	struct device *dev = &pinfo->link->dev;
    854	int ret;
    855
    856	pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
    857	if (IS_ERR(pinfo->pp18_gpio)) {
    858		ret = PTR_ERR(pinfo->pp18_gpio);
    859		if (ret != -EPROBE_DEFER)
    860			dev_err(dev, "failed to get pp18 gpio: %d\n", ret);
    861		return ret;
    862	}
    863
    864	pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
    865	if (IS_ERR(pinfo->pp33_gpio)) {
    866		ret = PTR_ERR(pinfo->pp33_gpio);
    867		if (ret != -EPROBE_DEFER)
    868			dev_err(dev, "failed to get pp33 gpio: %d\n", ret);
    869		return ret;
    870	}
    871
    872	pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
    873	if (IS_ERR(pinfo->enable_gpio)) {
    874		ret = PTR_ERR(pinfo->enable_gpio);
    875		if (ret != -EPROBE_DEFER)
    876			dev_err(dev, "failed to get enable gpio: %d\n", ret);
    877		return ret;
    878	}
    879
    880	drm_panel_init(&pinfo->base, dev, &panel_funcs,
    881		       DRM_MODE_CONNECTOR_DSI);
    882
    883	ret = drm_panel_of_backlight(&pinfo->base);
    884	if (ret)
    885		return ret;
    886
    887	drm_panel_add(&pinfo->base);
    888
    889	return 0;
    890}
    891
    892static int panel_probe(struct mipi_dsi_device *dsi)
    893{
    894	struct panel_info *pinfo;
    895	const struct panel_desc *desc;
    896	int err;
    897
    898	pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
    899	if (!pinfo)
    900		return -ENOMEM;
    901
    902	desc = of_device_get_match_data(&dsi->dev);
    903	dsi->mode_flags = desc->mode_flags;
    904	dsi->format = desc->format;
    905	dsi->lanes = desc->lanes;
    906	pinfo->desc = desc;
    907
    908	pinfo->link = dsi;
    909	mipi_dsi_set_drvdata(dsi, pinfo);
    910
    911	err = panel_add(pinfo);
    912	if (err < 0)
    913		return err;
    914
    915	err = mipi_dsi_attach(dsi);
    916	if (err < 0)
    917		drm_panel_remove(&pinfo->base);
    918
    919	return err;
    920}
    921
    922static int panel_remove(struct mipi_dsi_device *dsi)
    923{
    924	struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
    925	int err;
    926
    927	err = boe_panel_disable(&pinfo->base);
    928	if (err < 0)
    929		dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
    930
    931	err = boe_panel_unprepare(&pinfo->base);
    932	if (err < 0)
    933		dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
    934
    935	err = mipi_dsi_detach(dsi);
    936	if (err < 0)
    937		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
    938
    939	drm_panel_remove(&pinfo->base);
    940
    941	return 0;
    942}
    943
    944static void panel_shutdown(struct mipi_dsi_device *dsi)
    945{
    946	struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
    947
    948	boe_panel_disable(&pinfo->base);
    949	boe_panel_unprepare(&pinfo->base);
    950}
    951
    952static struct mipi_dsi_driver panel_driver = {
    953	.driver = {
    954		.name = "panel-boe-himax8279d",
    955		.of_match_table = panel_of_match,
    956	},
    957	.probe = panel_probe,
    958	.remove = panel_remove,
    959	.shutdown = panel_shutdown,
    960};
    961module_mipi_dsi_driver(panel_driver);
    962
    963MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
    964MODULE_DESCRIPTION("Boe Himax8279d driver");
    965MODULE_LICENSE("GPL v2");