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-newvision-nv3052c.c (10441B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * NewVision NV3052C IPS LCD panel driver
      4 *
      5 * Copyright (C) 2020, Paul Cercueil <paul@crapouillou.net>
      6 * Copyright (C) 2022, Christophe Branchereau <cbranchereau@gmail.com>
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/device.h>
     11#include <linux/gpio/consumer.h>
     12#include <linux/media-bus-format.h>
     13#include <linux/module.h>
     14#include <linux/of_device.h>
     15#include <linux/regulator/consumer.h>
     16#include <linux/spi/spi.h>
     17#include <video/mipi_display.h>
     18#include <drm/drm_mipi_dbi.h>
     19#include <drm/drm_modes.h>
     20#include <drm/drm_panel.h>
     21
     22struct nv3052c_panel_info {
     23	const struct drm_display_mode *display_modes;
     24	unsigned int num_modes;
     25	u16 width_mm, height_mm;
     26	u32 bus_format, bus_flags;
     27};
     28
     29struct nv3052c {
     30	struct device *dev;
     31	struct drm_panel panel;
     32	struct mipi_dbi dbi;
     33	const struct nv3052c_panel_info *panel_info;
     34	struct regulator *supply;
     35	struct gpio_desc *reset_gpio;
     36};
     37
     38struct nv3052c_reg {
     39	u8 cmd;
     40	u8 val;
     41};
     42
     43static const struct nv3052c_reg nv3052c_panel_regs[] = {
     44	{ 0xff, 0x30 },
     45	{ 0xff, 0x52 },
     46	{ 0xff, 0x01 },
     47	{ 0xe3, 0x00 },
     48	{ 0x40, 0x00 },
     49	{ 0x03, 0x40 },
     50	{ 0x04, 0x00 },
     51	{ 0x05, 0x03 },
     52	{ 0x08, 0x00 },
     53	{ 0x09, 0x07 },
     54	{ 0x0a, 0x01 },
     55	{ 0x0b, 0x32 },
     56	{ 0x0c, 0x32 },
     57	{ 0x0d, 0x0b },
     58	{ 0x0e, 0x00 },
     59	{ 0x23, 0xa0 },
     60	{ 0x24, 0x0c },
     61	{ 0x25, 0x06 },
     62	{ 0x26, 0x14 },
     63	{ 0x27, 0x14 },
     64	{ 0x38, 0xcc },
     65	{ 0x39, 0xd7 },
     66	{ 0x3a, 0x4a },
     67	{ 0x28, 0x40 },
     68	{ 0x29, 0x01 },
     69	{ 0x2a, 0xdf },
     70	{ 0x49, 0x3c },
     71	{ 0x91, 0x77 },
     72	{ 0x92, 0x77 },
     73	{ 0xa0, 0x55 },
     74	{ 0xa1, 0x50 },
     75	{ 0xa4, 0x9c },
     76	{ 0xa7, 0x02 },
     77	{ 0xa8, 0x01 },
     78	{ 0xa9, 0x01 },
     79	{ 0xaa, 0xfc },
     80	{ 0xab, 0x28 },
     81	{ 0xac, 0x06 },
     82	{ 0xad, 0x06 },
     83	{ 0xae, 0x06 },
     84	{ 0xaf, 0x03 },
     85	{ 0xb0, 0x08 },
     86	{ 0xb1, 0x26 },
     87	{ 0xb2, 0x28 },
     88	{ 0xb3, 0x28 },
     89	{ 0xb4, 0x33 },
     90	{ 0xb5, 0x08 },
     91	{ 0xb6, 0x26 },
     92	{ 0xb7, 0x08 },
     93	{ 0xb8, 0x26 },
     94	{ 0xf0, 0x00 },
     95	{ 0xf6, 0xc0 },
     96	{ 0xff, 0x30 },
     97	{ 0xff, 0x52 },
     98	{ 0xff, 0x02 },
     99	{ 0xb0, 0x0b },
    100	{ 0xb1, 0x16 },
    101	{ 0xb2, 0x17 },
    102	{ 0xb3, 0x2c },
    103	{ 0xb4, 0x32 },
    104	{ 0xb5, 0x3b },
    105	{ 0xb6, 0x29 },
    106	{ 0xb7, 0x40 },
    107	{ 0xb8, 0x0d },
    108	{ 0xb9, 0x05 },
    109	{ 0xba, 0x12 },
    110	{ 0xbb, 0x10 },
    111	{ 0xbc, 0x12 },
    112	{ 0xbd, 0x15 },
    113	{ 0xbe, 0x19 },
    114	{ 0xbf, 0x0e },
    115	{ 0xc0, 0x16 },
    116	{ 0xc1, 0x0a },
    117	{ 0xd0, 0x0c },
    118	{ 0xd1, 0x17 },
    119	{ 0xd2, 0x14 },
    120	{ 0xd3, 0x2e },
    121	{ 0xd4, 0x32 },
    122	{ 0xd5, 0x3c },
    123	{ 0xd6, 0x22 },
    124	{ 0xd7, 0x3d },
    125	{ 0xd8, 0x0d },
    126	{ 0xd9, 0x07 },
    127	{ 0xda, 0x13 },
    128	{ 0xdb, 0x13 },
    129	{ 0xdc, 0x11 },
    130	{ 0xdd, 0x15 },
    131	{ 0xde, 0x19 },
    132	{ 0xdf, 0x10 },
    133	{ 0xe0, 0x17 },
    134	{ 0xe1, 0x0a },
    135	{ 0xff, 0x30 },
    136	{ 0xff, 0x52 },
    137	{ 0xff, 0x03 },
    138	{ 0x00, 0x2a },
    139	{ 0x01, 0x2a },
    140	{ 0x02, 0x2a },
    141	{ 0x03, 0x2a },
    142	{ 0x04, 0x61 },
    143	{ 0x05, 0x80 },
    144	{ 0x06, 0xc7 },
    145	{ 0x07, 0x01 },
    146	{ 0x08, 0x03 },
    147	{ 0x09, 0x04 },
    148	{ 0x70, 0x22 },
    149	{ 0x71, 0x80 },
    150	{ 0x30, 0x2a },
    151	{ 0x31, 0x2a },
    152	{ 0x32, 0x2a },
    153	{ 0x33, 0x2a },
    154	{ 0x34, 0x61 },
    155	{ 0x35, 0xc5 },
    156	{ 0x36, 0x80 },
    157	{ 0x37, 0x23 },
    158	{ 0x40, 0x03 },
    159	{ 0x41, 0x04 },
    160	{ 0x42, 0x05 },
    161	{ 0x43, 0x06 },
    162	{ 0x44, 0x11 },
    163	{ 0x45, 0xe8 },
    164	{ 0x46, 0xe9 },
    165	{ 0x47, 0x11 },
    166	{ 0x48, 0xea },
    167	{ 0x49, 0xeb },
    168	{ 0x50, 0x07 },
    169	{ 0x51, 0x08 },
    170	{ 0x52, 0x09 },
    171	{ 0x53, 0x0a },
    172	{ 0x54, 0x11 },
    173	{ 0x55, 0xec },
    174	{ 0x56, 0xed },
    175	{ 0x57, 0x11 },
    176	{ 0x58, 0xef },
    177	{ 0x59, 0xf0 },
    178	{ 0xb1, 0x01 },
    179	{ 0xb4, 0x15 },
    180	{ 0xb5, 0x16 },
    181	{ 0xb6, 0x09 },
    182	{ 0xb7, 0x0f },
    183	{ 0xb8, 0x0d },
    184	{ 0xb9, 0x0b },
    185	{ 0xba, 0x00 },
    186	{ 0xc7, 0x02 },
    187	{ 0xca, 0x17 },
    188	{ 0xcb, 0x18 },
    189	{ 0xcc, 0x0a },
    190	{ 0xcd, 0x10 },
    191	{ 0xce, 0x0e },
    192	{ 0xcf, 0x0c },
    193	{ 0xd0, 0x00 },
    194	{ 0x81, 0x00 },
    195	{ 0x84, 0x15 },
    196	{ 0x85, 0x16 },
    197	{ 0x86, 0x10 },
    198	{ 0x87, 0x0a },
    199	{ 0x88, 0x0c },
    200	{ 0x89, 0x0e },
    201	{ 0x8a, 0x02 },
    202	{ 0x97, 0x00 },
    203	{ 0x9a, 0x17 },
    204	{ 0x9b, 0x18 },
    205	{ 0x9c, 0x0f },
    206	{ 0x9d, 0x09 },
    207	{ 0x9e, 0x0b },
    208	{ 0x9f, 0x0d },
    209	{ 0xa0, 0x01 },
    210	{ 0xff, 0x30 },
    211	{ 0xff, 0x52 },
    212	{ 0xff, 0x02 },
    213	{ 0x01, 0x01 },
    214	{ 0x02, 0xda },
    215	{ 0x03, 0xba },
    216	{ 0x04, 0xa8 },
    217	{ 0x05, 0x9a },
    218	{ 0x06, 0x70 },
    219	{ 0x07, 0xff },
    220	{ 0x08, 0x91 },
    221	{ 0x09, 0x90 },
    222	{ 0x0a, 0xff },
    223	{ 0x0b, 0x8f },
    224	{ 0x0c, 0x60 },
    225	{ 0x0d, 0x58 },
    226	{ 0x0e, 0x48 },
    227	{ 0x0f, 0x38 },
    228	{ 0x10, 0x2b },
    229	{ 0xff, 0x30 },
    230	{ 0xff, 0x52 },
    231	{ 0xff, 0x00 },
    232	{ 0x36, 0x0a },
    233};
    234
    235static inline struct nv3052c *to_nv3052c(struct drm_panel *panel)
    236{
    237	return container_of(panel, struct nv3052c, panel);
    238}
    239
    240static int nv3052c_prepare(struct drm_panel *panel)
    241{
    242	struct nv3052c *priv = to_nv3052c(panel);
    243	struct mipi_dbi *dbi = &priv->dbi;
    244	unsigned int i;
    245	int err;
    246
    247	err = regulator_enable(priv->supply);
    248	if (err) {
    249		dev_err(priv->dev, "Failed to enable power supply: %d\n", err);
    250		return err;
    251	}
    252
    253	/* Reset the chip */
    254	gpiod_set_value_cansleep(priv->reset_gpio, 1);
    255	usleep_range(10, 1000);
    256	gpiod_set_value_cansleep(priv->reset_gpio, 0);
    257	usleep_range(5000, 20000);
    258
    259	for (i = 0; i < ARRAY_SIZE(nv3052c_panel_regs); i++) {
    260		err = mipi_dbi_command(dbi, nv3052c_panel_regs[i].cmd,
    261				       nv3052c_panel_regs[i].val);
    262
    263		if (err) {
    264			dev_err(priv->dev, "Unable to set register: %d\n", err);
    265			goto err_disable_regulator;
    266		}
    267	}
    268
    269	err = mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
    270	if (err) {
    271		dev_err(priv->dev, "Unable to exit sleep mode: %d\n", err);
    272		goto err_disable_regulator;
    273	}
    274
    275	return 0;
    276
    277err_disable_regulator:
    278	regulator_disable(priv->supply);
    279	return err;
    280}
    281
    282static int nv3052c_unprepare(struct drm_panel *panel)
    283{
    284	struct nv3052c *priv = to_nv3052c(panel);
    285	struct mipi_dbi *dbi = &priv->dbi;
    286	int err;
    287
    288	err = mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
    289	if (err)
    290		dev_err(priv->dev, "Unable to enter sleep mode: %d\n", err);
    291
    292	gpiod_set_value_cansleep(priv->reset_gpio, 1);
    293	regulator_disable(priv->supply);
    294
    295	return 0;
    296}
    297
    298static int nv3052c_enable(struct drm_panel *panel)
    299{
    300	struct nv3052c *priv = to_nv3052c(panel);
    301	struct mipi_dbi *dbi = &priv->dbi;
    302	int err;
    303
    304	err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
    305	if (err) {
    306		dev_err(priv->dev, "Unable to enable display: %d\n", err);
    307		return err;
    308	}
    309
    310	if (panel->backlight) {
    311		/* Wait for the picture to be ready before enabling backlight */
    312		msleep(120);
    313	}
    314
    315	return 0;
    316}
    317
    318static int nv3052c_disable(struct drm_panel *panel)
    319{
    320	struct nv3052c *priv = to_nv3052c(panel);
    321	struct mipi_dbi *dbi = &priv->dbi;
    322	int err;
    323
    324	err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
    325	if (err) {
    326		dev_err(priv->dev, "Unable to disable display: %d\n", err);
    327		return err;
    328	}
    329
    330	return 0;
    331}
    332
    333static int nv3052c_get_modes(struct drm_panel *panel,
    334			     struct drm_connector *connector)
    335{
    336	struct nv3052c *priv = to_nv3052c(panel);
    337	const struct nv3052c_panel_info *panel_info = priv->panel_info;
    338	struct drm_display_mode *mode;
    339	unsigned int i;
    340
    341	for (i = 0; i < panel_info->num_modes; i++) {
    342		mode = drm_mode_duplicate(connector->dev,
    343					  &panel_info->display_modes[i]);
    344		if (!mode)
    345			return -ENOMEM;
    346
    347		drm_mode_set_name(mode);
    348
    349		mode->type = DRM_MODE_TYPE_DRIVER;
    350		if (panel_info->num_modes == 1)
    351			mode->type |= DRM_MODE_TYPE_PREFERRED;
    352
    353		drm_mode_probed_add(connector, mode);
    354	}
    355
    356	connector->display_info.bpc = 8;
    357	connector->display_info.width_mm = panel_info->width_mm;
    358	connector->display_info.height_mm = panel_info->height_mm;
    359
    360	drm_display_info_set_bus_formats(&connector->display_info,
    361					 &panel_info->bus_format, 1);
    362	connector->display_info.bus_flags = panel_info->bus_flags;
    363
    364	return panel_info->num_modes;
    365}
    366
    367static const struct drm_panel_funcs nv3052c_funcs = {
    368	.prepare	= nv3052c_prepare,
    369	.unprepare	= nv3052c_unprepare,
    370	.enable		= nv3052c_enable,
    371	.disable	= nv3052c_disable,
    372	.get_modes	= nv3052c_get_modes,
    373};
    374
    375static int nv3052c_probe(struct spi_device *spi)
    376{
    377	struct device *dev = &spi->dev;
    378	struct nv3052c *priv;
    379	int err;
    380
    381	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    382	if (!priv)
    383		return -ENOMEM;
    384
    385	priv->dev = dev;
    386
    387	priv->panel_info = of_device_get_match_data(dev);
    388	if (!priv->panel_info)
    389		return -EINVAL;
    390
    391	priv->supply = devm_regulator_get(dev, "power");
    392	if (IS_ERR(priv->supply))
    393		return dev_err_probe(dev, PTR_ERR(priv->supply), "Failed to get power supply\n");
    394
    395	priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
    396	if (IS_ERR(priv->reset_gpio))
    397		return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), "Failed to get reset GPIO\n");
    398
    399	err = mipi_dbi_spi_init(spi, &priv->dbi, NULL);
    400	if (err)
    401		return dev_err_probe(dev, err, "MIPI DBI init failed\n");
    402
    403	priv->dbi.read_commands = NULL;
    404
    405	spi_set_drvdata(spi, priv);
    406
    407	drm_panel_init(&priv->panel, dev, &nv3052c_funcs,
    408		       DRM_MODE_CONNECTOR_DPI);
    409
    410	err = drm_panel_of_backlight(&priv->panel);
    411	if (err)
    412		return dev_err_probe(dev, err, "Failed to attach backlight\n");
    413
    414	drm_panel_add(&priv->panel);
    415
    416	return 0;
    417}
    418
    419static void nv3052c_remove(struct spi_device *spi)
    420{
    421	struct nv3052c *priv = spi_get_drvdata(spi);
    422
    423	drm_panel_remove(&priv->panel);
    424	drm_panel_disable(&priv->panel);
    425	drm_panel_unprepare(&priv->panel);
    426}
    427
    428static const struct drm_display_mode ltk035c5444t_modes[] = {
    429	{ /* 60 Hz */
    430		.clock = 24000,
    431		.hdisplay = 640,
    432		.hsync_start = 640 + 96,
    433		.hsync_end = 640 + 96 + 16,
    434		.htotal = 640 + 96 + 16 + 48,
    435		.vdisplay = 480,
    436		.vsync_start = 480 + 5,
    437		.vsync_end = 480 + 5 + 2,
    438		.vtotal = 480 + 5 + 2 + 13,
    439		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
    440	},
    441	{ /* 50 Hz */
    442		.clock = 18000,
    443		.hdisplay = 640,
    444		.hsync_start = 640 + 39,
    445		.hsync_end = 640 + 39 + 2,
    446		.htotal = 640 + 39 + 2 + 39,
    447		.vdisplay = 480,
    448		.vsync_start = 480 + 5,
    449		.vsync_end = 480 + 5 + 2,
    450		.vtotal = 480 + 5 + 2 + 13,
    451		.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
    452	},
    453};
    454
    455static const struct nv3052c_panel_info ltk035c5444t_panel_info = {
    456	.display_modes = ltk035c5444t_modes,
    457	.num_modes = ARRAY_SIZE(ltk035c5444t_modes),
    458	.width_mm = 77,
    459	.height_mm = 64,
    460	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
    461	.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
    462};
    463
    464static const struct of_device_id nv3052c_of_match[] = {
    465	{ .compatible = "leadtek,ltk035c5444t", .data = &ltk035c5444t_panel_info },
    466	{ /* sentinel */ }
    467};
    468MODULE_DEVICE_TABLE(of, nv3052c_of_match);
    469
    470static struct spi_driver nv3052c_driver = {
    471	.driver = {
    472		.name = "nv3052c",
    473		.of_match_table = nv3052c_of_match,
    474	},
    475	.probe = nv3052c_probe,
    476	.remove = nv3052c_remove,
    477};
    478module_spi_driver(nv3052c_driver);
    479
    480MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
    481MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>");
    482MODULE_LICENSE("GPL v2");