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-kingdisplay-kd097d04.c (10073B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
      4 */
      5
      6#include <linux/delay.h>
      7#include <linux/gpio/consumer.h>
      8#include <linux/module.h>
      9#include <linux/of.h>
     10#include <linux/regulator/consumer.h>
     11
     12#include <video/mipi_display.h>
     13
     14#include <drm/drm_crtc.h>
     15#include <drm/drm_device.h>
     16#include <drm/drm_mipi_dsi.h>
     17#include <drm/drm_modes.h>
     18#include <drm/drm_panel.h>
     19
     20struct kingdisplay_panel {
     21	struct drm_panel base;
     22	struct mipi_dsi_device *link;
     23
     24	struct regulator *supply;
     25	struct gpio_desc *enable_gpio;
     26
     27	bool prepared;
     28	bool enabled;
     29};
     30
     31struct kingdisplay_panel_cmd {
     32	char cmd;
     33	char data;
     34};
     35
     36/*
     37 * According to the discussion on
     38 * https://review.coreboot.org/#/c/coreboot/+/22472/
     39 * the panel init array is not part of the panels datasheet but instead
     40 * just came in this form from the panel vendor.
     41 */
     42static const struct kingdisplay_panel_cmd init_code[] = {
     43	/* voltage setting */
     44	{ 0xB0, 0x00 },
     45	{ 0xB2, 0x02 },
     46	{ 0xB3, 0x11 },
     47	{ 0xB4, 0x00 },
     48	{ 0xB6, 0x80 },
     49	/* VCOM disable */
     50	{ 0xB7, 0x02 },
     51	{ 0xB8, 0x80 },
     52	{ 0xBA, 0x43 },
     53	/* VCOM setting */
     54	{ 0xBB, 0x53 },
     55	/* VSP setting */
     56	{ 0xBC, 0x0A },
     57	/* VSN setting */
     58	{ 0xBD, 0x4A },
     59	/* VGH setting */
     60	{ 0xBE, 0x2F },
     61	/* VGL setting */
     62	{ 0xBF, 0x1A },
     63	{ 0xF0, 0x39 },
     64	{ 0xF1, 0x22 },
     65	/* Gamma setting */
     66	{ 0xB0, 0x02 },
     67	{ 0xC0, 0x00 },
     68	{ 0xC1, 0x01 },
     69	{ 0xC2, 0x0B },
     70	{ 0xC3, 0x15 },
     71	{ 0xC4, 0x22 },
     72	{ 0xC5, 0x11 },
     73	{ 0xC6, 0x15 },
     74	{ 0xC7, 0x19 },
     75	{ 0xC8, 0x1A },
     76	{ 0xC9, 0x16 },
     77	{ 0xCA, 0x18 },
     78	{ 0xCB, 0x13 },
     79	{ 0xCC, 0x18 },
     80	{ 0xCD, 0x13 },
     81	{ 0xCE, 0x1C },
     82	{ 0xCF, 0x19 },
     83	{ 0xD0, 0x21 },
     84	{ 0xD1, 0x2C },
     85	{ 0xD2, 0x2F },
     86	{ 0xD3, 0x30 },
     87	{ 0xD4, 0x19 },
     88	{ 0xD5, 0x1F },
     89	{ 0xD6, 0x00 },
     90	{ 0xD7, 0x01 },
     91	{ 0xD8, 0x0B },
     92	{ 0xD9, 0x15 },
     93	{ 0xDA, 0x22 },
     94	{ 0xDB, 0x11 },
     95	{ 0xDC, 0x15 },
     96	{ 0xDD, 0x19 },
     97	{ 0xDE, 0x1A },
     98	{ 0xDF, 0x16 },
     99	{ 0xE0, 0x18 },
    100	{ 0xE1, 0x13 },
    101	{ 0xE2, 0x18 },
    102	{ 0xE3, 0x13 },
    103	{ 0xE4, 0x1C },
    104	{ 0xE5, 0x19 },
    105	{ 0xE6, 0x21 },
    106	{ 0xE7, 0x2C },
    107	{ 0xE8, 0x2F },
    108	{ 0xE9, 0x30 },
    109	{ 0xEA, 0x19 },
    110	{ 0xEB, 0x1F },
    111	/* GOA MUX setting */
    112	{ 0xB0, 0x01 },
    113	{ 0xC0, 0x10 },
    114	{ 0xC1, 0x0F },
    115	{ 0xC2, 0x0E },
    116	{ 0xC3, 0x0D },
    117	{ 0xC4, 0x0C },
    118	{ 0xC5, 0x0B },
    119	{ 0xC6, 0x0A },
    120	{ 0xC7, 0x09 },
    121	{ 0xC8, 0x08 },
    122	{ 0xC9, 0x07 },
    123	{ 0xCA, 0x06 },
    124	{ 0xCB, 0x05 },
    125	{ 0xCC, 0x00 },
    126	{ 0xCD, 0x01 },
    127	{ 0xCE, 0x02 },
    128	{ 0xCF, 0x03 },
    129	{ 0xD0, 0x04 },
    130	{ 0xD6, 0x10 },
    131	{ 0xD7, 0x0F },
    132	{ 0xD8, 0x0E },
    133	{ 0xD9, 0x0D },
    134	{ 0xDA, 0x0C },
    135	{ 0xDB, 0x0B },
    136	{ 0xDC, 0x0A },
    137	{ 0xDD, 0x09 },
    138	{ 0xDE, 0x08 },
    139	{ 0xDF, 0x07 },
    140	{ 0xE0, 0x06 },
    141	{ 0xE1, 0x05 },
    142	{ 0xE2, 0x00 },
    143	{ 0xE3, 0x01 },
    144	{ 0xE4, 0x02 },
    145	{ 0xE5, 0x03 },
    146	{ 0xE6, 0x04 },
    147	{ 0xE7, 0x00 },
    148	{ 0xEC, 0xC0 },
    149	/* GOA timing setting */
    150	{ 0xB0, 0x03 },
    151	{ 0xC0, 0x01 },
    152	{ 0xC2, 0x6F },
    153	{ 0xC3, 0x6F },
    154	{ 0xC5, 0x36 },
    155	{ 0xC8, 0x08 },
    156	{ 0xC9, 0x04 },
    157	{ 0xCA, 0x41 },
    158	{ 0xCC, 0x43 },
    159	{ 0xCF, 0x60 },
    160	{ 0xD2, 0x04 },
    161	{ 0xD3, 0x04 },
    162	{ 0xD4, 0x03 },
    163	{ 0xD5, 0x02 },
    164	{ 0xD6, 0x01 },
    165	{ 0xD7, 0x00 },
    166	{ 0xDB, 0x01 },
    167	{ 0xDE, 0x36 },
    168	{ 0xE6, 0x6F },
    169	{ 0xE7, 0x6F },
    170	/* GOE setting */
    171	{ 0xB0, 0x06 },
    172	{ 0xB8, 0xA5 },
    173	{ 0xC0, 0xA5 },
    174	{ 0xD5, 0x3F },
    175};
    176
    177static inline
    178struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
    179{
    180	return container_of(panel, struct kingdisplay_panel, base);
    181}
    182
    183static int kingdisplay_panel_disable(struct drm_panel *panel)
    184{
    185	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
    186	int err;
    187
    188	if (!kingdisplay->enabled)
    189		return 0;
    190
    191	err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
    192	if (err < 0)
    193		dev_err(panel->dev, "failed to set display off: %d\n", err);
    194
    195	kingdisplay->enabled = false;
    196
    197	return 0;
    198}
    199
    200static int kingdisplay_panel_unprepare(struct drm_panel *panel)
    201{
    202	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
    203	int err;
    204
    205	if (!kingdisplay->prepared)
    206		return 0;
    207
    208	err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
    209	if (err < 0) {
    210		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
    211		return err;
    212	}
    213
    214	/* T15: 120ms */
    215	msleep(120);
    216
    217	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
    218
    219	err = regulator_disable(kingdisplay->supply);
    220	if (err < 0)
    221		return err;
    222
    223	kingdisplay->prepared = false;
    224
    225	return 0;
    226}
    227
    228static int kingdisplay_panel_prepare(struct drm_panel *panel)
    229{
    230	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
    231	int err, regulator_err;
    232	unsigned int i;
    233
    234	if (kingdisplay->prepared)
    235		return 0;
    236
    237	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
    238
    239	err = regulator_enable(kingdisplay->supply);
    240	if (err < 0)
    241		return err;
    242
    243	/* T2: 15ms */
    244	usleep_range(15000, 16000);
    245
    246	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
    247
    248	/* T4: 15ms */
    249	usleep_range(15000, 16000);
    250
    251	for (i = 0; i < ARRAY_SIZE(init_code); i++) {
    252		err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
    253					sizeof(struct kingdisplay_panel_cmd));
    254		if (err < 0) {
    255			dev_err(panel->dev, "failed write init cmds: %d\n", err);
    256			goto poweroff;
    257		}
    258	}
    259
    260	err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
    261	if (err < 0) {
    262		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
    263		goto poweroff;
    264	}
    265
    266	/* T6: 120ms */
    267	msleep(120);
    268
    269	err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
    270	if (err < 0) {
    271		dev_err(panel->dev, "failed to set display on: %d\n", err);
    272		goto poweroff;
    273	}
    274
    275	/* T7: 10ms */
    276	usleep_range(10000, 11000);
    277
    278	kingdisplay->prepared = true;
    279
    280	return 0;
    281
    282poweroff:
    283	gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
    284
    285	regulator_err = regulator_disable(kingdisplay->supply);
    286	if (regulator_err)
    287		dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err);
    288
    289	return err;
    290}
    291
    292static int kingdisplay_panel_enable(struct drm_panel *panel)
    293{
    294	struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
    295
    296	if (kingdisplay->enabled)
    297		return 0;
    298
    299	kingdisplay->enabled = true;
    300
    301	return 0;
    302}
    303
    304static const struct drm_display_mode default_mode = {
    305	.clock = 229000,
    306	.hdisplay = 1536,
    307	.hsync_start = 1536 + 100,
    308	.hsync_end = 1536 + 100 + 24,
    309	.htotal = 1536 + 100 + 24 + 100,
    310	.vdisplay = 2048,
    311	.vsync_start = 2048 + 95,
    312	.vsync_end = 2048 + 95 + 2,
    313	.vtotal = 2048 + 95 + 2 + 23,
    314};
    315
    316static int kingdisplay_panel_get_modes(struct drm_panel *panel,
    317				       struct drm_connector *connector)
    318{
    319	struct drm_display_mode *mode;
    320
    321	mode = drm_mode_duplicate(connector->dev, &default_mode);
    322	if (!mode) {
    323		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
    324			default_mode.hdisplay, default_mode.vdisplay,
    325			drm_mode_vrefresh(&default_mode));
    326		return -ENOMEM;
    327	}
    328
    329	drm_mode_set_name(mode);
    330
    331	drm_mode_probed_add(connector, mode);
    332
    333	connector->display_info.width_mm = 147;
    334	connector->display_info.height_mm = 196;
    335	connector->display_info.bpc = 8;
    336
    337	return 1;
    338}
    339
    340static const struct drm_panel_funcs kingdisplay_panel_funcs = {
    341	.disable = kingdisplay_panel_disable,
    342	.unprepare = kingdisplay_panel_unprepare,
    343	.prepare = kingdisplay_panel_prepare,
    344	.enable = kingdisplay_panel_enable,
    345	.get_modes = kingdisplay_panel_get_modes,
    346};
    347
    348static const struct of_device_id kingdisplay_of_match[] = {
    349	{ .compatible = "kingdisplay,kd097d04", },
    350	{ }
    351};
    352MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
    353
    354static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
    355{
    356	struct device *dev = &kingdisplay->link->dev;
    357	int err;
    358
    359	kingdisplay->supply = devm_regulator_get(dev, "power");
    360	if (IS_ERR(kingdisplay->supply))
    361		return PTR_ERR(kingdisplay->supply);
    362
    363	kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
    364							   GPIOD_OUT_HIGH);
    365	if (IS_ERR(kingdisplay->enable_gpio)) {
    366		err = PTR_ERR(kingdisplay->enable_gpio);
    367		dev_dbg(dev, "failed to get enable gpio: %d\n", err);
    368		kingdisplay->enable_gpio = NULL;
    369	}
    370
    371	drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,
    372		       &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI);
    373
    374	err = drm_panel_of_backlight(&kingdisplay->base);
    375	if (err)
    376		return err;
    377
    378	drm_panel_add(&kingdisplay->base);
    379
    380	return 0;
    381}
    382
    383static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
    384{
    385	drm_panel_remove(&kingdisplay->base);
    386}
    387
    388static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
    389{
    390	struct kingdisplay_panel *kingdisplay;
    391	int err;
    392
    393	dsi->lanes = 4;
    394	dsi->format = MIPI_DSI_FMT_RGB888;
    395	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
    396			  MIPI_DSI_MODE_LPM;
    397
    398	kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
    399	if (!kingdisplay)
    400		return -ENOMEM;
    401
    402	mipi_dsi_set_drvdata(dsi, kingdisplay);
    403	kingdisplay->link = dsi;
    404
    405	err = kingdisplay_panel_add(kingdisplay);
    406	if (err < 0)
    407		return err;
    408
    409	err = mipi_dsi_attach(dsi);
    410	if (err < 0) {
    411		kingdisplay_panel_del(kingdisplay);
    412		return err;
    413	}
    414
    415	return 0;
    416}
    417
    418static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
    419{
    420	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
    421	int err;
    422
    423	err = drm_panel_unprepare(&kingdisplay->base);
    424	if (err < 0)
    425		dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
    426
    427	err = drm_panel_disable(&kingdisplay->base);
    428	if (err < 0)
    429		dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
    430
    431	err = mipi_dsi_detach(dsi);
    432	if (err < 0)
    433		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
    434
    435	kingdisplay_panel_del(kingdisplay);
    436
    437	return 0;
    438}
    439
    440static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
    441{
    442	struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
    443
    444	drm_panel_unprepare(&kingdisplay->base);
    445	drm_panel_disable(&kingdisplay->base);
    446}
    447
    448static struct mipi_dsi_driver kingdisplay_panel_driver = {
    449	.driver = {
    450		.name = "panel-kingdisplay-kd097d04",
    451		.of_match_table = kingdisplay_of_match,
    452	},
    453	.probe = kingdisplay_panel_probe,
    454	.remove = kingdisplay_panel_remove,
    455	.shutdown = kingdisplay_panel_shutdown,
    456};
    457module_mipi_dsi_driver(kingdisplay_panel_driver);
    458
    459MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
    460MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
    461MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
    462MODULE_LICENSE("GPL v2");