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-xinpeng-xpp055c272.c (10751B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Xinpeng xpp055c272 5.5" MIPI-DSI panel driver
      4 * Copyright (C) 2019 Theobroma Systems Design und Consulting GmbH
      5 *
      6 * based on
      7 *
      8 * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
      9 * Copyright (C) Purism SPC 2019
     10 */
     11
     12#include <drm/drm_mipi_dsi.h>
     13#include <drm/drm_modes.h>
     14#include <drm/drm_panel.h>
     15
     16#include <video/display_timing.h>
     17#include <video/mipi_display.h>
     18
     19#include <linux/delay.h>
     20#include <linux/gpio/consumer.h>
     21#include <linux/media-bus-format.h>
     22#include <linux/module.h>
     23#include <linux/of.h>
     24#include <linux/regulator/consumer.h>
     25
     26/* Manufacturer specific Commands send via DSI */
     27#define XPP055C272_CMD_ALL_PIXEL_OFF	0x22
     28#define XPP055C272_CMD_ALL_PIXEL_ON	0x23
     29#define XPP055C272_CMD_SETDISP		0xb2
     30#define XPP055C272_CMD_SETRGBIF		0xb3
     31#define XPP055C272_CMD_SETCYC		0xb4
     32#define XPP055C272_CMD_SETBGP		0xb5
     33#define XPP055C272_CMD_SETVCOM		0xb6
     34#define XPP055C272_CMD_SETOTP		0xb7
     35#define XPP055C272_CMD_SETPOWER_EXT	0xb8
     36#define XPP055C272_CMD_SETEXTC		0xb9
     37#define XPP055C272_CMD_SETMIPI		0xbA
     38#define XPP055C272_CMD_SETVDC		0xbc
     39#define XPP055C272_CMD_SETPCR		0xbf
     40#define XPP055C272_CMD_SETSCR		0xc0
     41#define XPP055C272_CMD_SETPOWER		0xc1
     42#define XPP055C272_CMD_SETECO		0xc6
     43#define XPP055C272_CMD_SETPANEL		0xcc
     44#define XPP055C272_CMD_SETGAMMA		0xe0
     45#define XPP055C272_CMD_SETEQ		0xe3
     46#define XPP055C272_CMD_SETGIP1		0xe9
     47#define XPP055C272_CMD_SETGIP2		0xea
     48
     49struct xpp055c272 {
     50	struct device *dev;
     51	struct drm_panel panel;
     52	struct gpio_desc *reset_gpio;
     53	struct regulator *vci;
     54	struct regulator *iovcc;
     55	bool prepared;
     56};
     57
     58static inline struct xpp055c272 *panel_to_xpp055c272(struct drm_panel *panel)
     59{
     60	return container_of(panel, struct xpp055c272, panel);
     61}
     62
     63#define dsi_generic_write_seq(dsi, cmd, seq...) do {			\
     64		static const u8 b[] = { cmd, seq };			\
     65		int ret;						\
     66		ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b));	\
     67		if (ret < 0)						\
     68			return ret;					\
     69	} while (0)
     70
     71static int xpp055c272_init_sequence(struct xpp055c272 *ctx)
     72{
     73	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
     74	struct device *dev = ctx->dev;
     75
     76	/*
     77	 * Init sequence was supplied by the panel vendor without much
     78	 * documentation.
     79	 */
     80	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEXTC, 0xf1, 0x12, 0x83);
     81	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETMIPI,
     82			      0x33, 0x81, 0x05, 0xf9, 0x0e, 0x0e, 0x00, 0x00,
     83			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x25,
     84			      0x00, 0x91, 0x0a, 0x00, 0x00, 0x02, 0x4f, 0x01,
     85			      0x00, 0x00, 0x37);
     86	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER_EXT, 0x25);
     87	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPCR, 0x02, 0x11, 0x00);
     88	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETRGBIF,
     89			      0x0c, 0x10, 0x0a, 0x50, 0x03, 0xff, 0x00, 0x00,
     90			      0x00, 0x00);
     91	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETSCR,
     92			      0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
     93			      0x00);
     94	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVDC, 0x46);
     95	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPANEL, 0x0b);
     96	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETCYC, 0x80);
     97	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETDISP, 0xc8, 0x12, 0x30);
     98	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETEQ,
     99			      0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
    100			      0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
    101	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETPOWER,
    102			      0x53, 0x00, 0x1e, 0x1e, 0x77, 0xe1, 0xcc, 0xdd,
    103			      0x67, 0x77, 0x33, 0x33);
    104	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETECO, 0x00, 0x00, 0xff,
    105			      0xff, 0x01, 0xff);
    106	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETBGP, 0x09, 0x09);
    107	msleep(20);
    108
    109	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETVCOM, 0x87, 0x95);
    110	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP1,
    111			      0xc2, 0x10, 0x05, 0x05, 0x10, 0x05, 0xa0, 0x12,
    112			      0x31, 0x23, 0x3f, 0x81, 0x0a, 0xa0, 0x37, 0x18,
    113			      0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
    114			      0x01, 0x00, 0x00, 0x00, 0x48, 0xf8, 0x86, 0x42,
    115			      0x08, 0x88, 0x88, 0x80, 0x88, 0x88, 0x88, 0x58,
    116			      0xf8, 0x87, 0x53, 0x18, 0x88, 0x88, 0x81, 0x88,
    117			      0x88, 0x88, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
    118			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
    119	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGIP2,
    120			      0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
    121			      0x00, 0x00, 0x00, 0x00, 0x1f, 0x88, 0x81, 0x35,
    122			      0x78, 0x88, 0x88, 0x85, 0x88, 0x88, 0x88, 0x0f,
    123			      0x88, 0x80, 0x24, 0x68, 0x88, 0x88, 0x84, 0x88,
    124			      0x88, 0x88, 0x23, 0x10, 0x00, 0x00, 0x1c, 0x00,
    125			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    126			      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x05,
    127			      0xa0, 0x00, 0x00, 0x00, 0x00);
    128	dsi_generic_write_seq(dsi, XPP055C272_CMD_SETGAMMA,
    129			      0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38, 0x36,
    130			      0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13, 0x11,
    131			      0x18, 0x00, 0x06, 0x08, 0x2a, 0x31, 0x3f, 0x38,
    132			      0x36, 0x07, 0x0c, 0x0d, 0x11, 0x13, 0x12, 0x13,
    133			      0x11, 0x18);
    134
    135	msleep(60);
    136
    137	dev_dbg(dev, "Panel init sequence done\n");
    138	return 0;
    139}
    140
    141static int xpp055c272_unprepare(struct drm_panel *panel)
    142{
    143	struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
    144	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    145	int ret;
    146
    147	if (!ctx->prepared)
    148		return 0;
    149
    150	ret = mipi_dsi_dcs_set_display_off(dsi);
    151	if (ret < 0)
    152		dev_err(ctx->dev, "failed to set display off: %d\n", ret);
    153
    154	mipi_dsi_dcs_enter_sleep_mode(dsi);
    155	if (ret < 0) {
    156		dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
    157		return ret;
    158	}
    159
    160	regulator_disable(ctx->iovcc);
    161	regulator_disable(ctx->vci);
    162
    163	ctx->prepared = false;
    164
    165	return 0;
    166}
    167
    168static int xpp055c272_prepare(struct drm_panel *panel)
    169{
    170	struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
    171	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
    172	int ret;
    173
    174	if (ctx->prepared)
    175		return 0;
    176
    177	dev_dbg(ctx->dev, "Resetting the panel\n");
    178	ret = regulator_enable(ctx->vci);
    179	if (ret < 0) {
    180		dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
    181		return ret;
    182	}
    183	ret = regulator_enable(ctx->iovcc);
    184	if (ret < 0) {
    185		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
    186		goto disable_vci;
    187	}
    188
    189	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    190	/* T6: 10us */
    191	usleep_range(10, 20);
    192	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
    193
    194	/* T8: 20ms */
    195	msleep(20);
    196
    197	ret = xpp055c272_init_sequence(ctx);
    198	if (ret < 0) {
    199		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
    200		goto disable_iovcc;
    201	}
    202
    203	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
    204	if (ret < 0) {
    205		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
    206		goto disable_iovcc;
    207	}
    208
    209	/* T9: 120ms */
    210	msleep(120);
    211
    212	ret = mipi_dsi_dcs_set_display_on(dsi);
    213	if (ret < 0) {
    214		dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
    215		goto disable_iovcc;
    216	}
    217
    218	msleep(50);
    219
    220	ctx->prepared = true;
    221
    222	return 0;
    223
    224disable_iovcc:
    225	regulator_disable(ctx->iovcc);
    226disable_vci:
    227	regulator_disable(ctx->vci);
    228	return ret;
    229}
    230
    231static const struct drm_display_mode default_mode = {
    232	.hdisplay	= 720,
    233	.hsync_start	= 720 + 40,
    234	.hsync_end	= 720 + 40 + 10,
    235	.htotal		= 720 + 40 + 10 + 40,
    236	.vdisplay	= 1280,
    237	.vsync_start	= 1280 + 22,
    238	.vsync_end	= 1280 + 22 + 4,
    239	.vtotal		= 1280 + 22 + 4 + 11,
    240	.clock		= 64000,
    241	.width_mm	= 68,
    242	.height_mm	= 121,
    243};
    244
    245static int xpp055c272_get_modes(struct drm_panel *panel,
    246				struct drm_connector *connector)
    247{
    248	struct xpp055c272 *ctx = panel_to_xpp055c272(panel);
    249	struct drm_display_mode *mode;
    250
    251	mode = drm_mode_duplicate(connector->dev, &default_mode);
    252	if (!mode) {
    253		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
    254			default_mode.hdisplay, default_mode.vdisplay,
    255			drm_mode_vrefresh(&default_mode));
    256		return -ENOMEM;
    257	}
    258
    259	drm_mode_set_name(mode);
    260
    261	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    262	connector->display_info.width_mm = mode->width_mm;
    263	connector->display_info.height_mm = mode->height_mm;
    264	drm_mode_probed_add(connector, mode);
    265
    266	return 1;
    267}
    268
    269static const struct drm_panel_funcs xpp055c272_funcs = {
    270	.unprepare	= xpp055c272_unprepare,
    271	.prepare	= xpp055c272_prepare,
    272	.get_modes	= xpp055c272_get_modes,
    273};
    274
    275static int xpp055c272_probe(struct mipi_dsi_device *dsi)
    276{
    277	struct device *dev = &dsi->dev;
    278	struct xpp055c272 *ctx;
    279	int ret;
    280
    281	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    282	if (!ctx)
    283		return -ENOMEM;
    284
    285	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
    286	if (IS_ERR(ctx->reset_gpio))
    287		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
    288				     "cannot get reset gpio\n");
    289
    290	ctx->vci = devm_regulator_get(dev, "vci");
    291	if (IS_ERR(ctx->vci))
    292		return dev_err_probe(dev, PTR_ERR(ctx->vci),
    293				     "Failed to request vci regulator\n");
    294
    295	ctx->iovcc = devm_regulator_get(dev, "iovcc");
    296	if (IS_ERR(ctx->iovcc))
    297		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
    298				     "Failed to request iovcc regulator\n");
    299
    300	mipi_dsi_set_drvdata(dsi, ctx);
    301
    302	ctx->dev = dev;
    303
    304	dsi->lanes = 4;
    305	dsi->format = MIPI_DSI_FMT_RGB888;
    306	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
    307			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
    308
    309	drm_panel_init(&ctx->panel, &dsi->dev, &xpp055c272_funcs,
    310		       DRM_MODE_CONNECTOR_DSI);
    311
    312	ret = drm_panel_of_backlight(&ctx->panel);
    313	if (ret)
    314		return ret;
    315
    316	drm_panel_add(&ctx->panel);
    317
    318	ret = mipi_dsi_attach(dsi);
    319	if (ret < 0) {
    320		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
    321		drm_panel_remove(&ctx->panel);
    322		return ret;
    323	}
    324
    325	return 0;
    326}
    327
    328static void xpp055c272_shutdown(struct mipi_dsi_device *dsi)
    329{
    330	struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
    331	int ret;
    332
    333	ret = drm_panel_unprepare(&ctx->panel);
    334	if (ret < 0)
    335		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
    336
    337	ret = drm_panel_disable(&ctx->panel);
    338	if (ret < 0)
    339		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
    340}
    341
    342static int xpp055c272_remove(struct mipi_dsi_device *dsi)
    343{
    344	struct xpp055c272 *ctx = mipi_dsi_get_drvdata(dsi);
    345	int ret;
    346
    347	xpp055c272_shutdown(dsi);
    348
    349	ret = mipi_dsi_detach(dsi);
    350	if (ret < 0)
    351		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
    352
    353	drm_panel_remove(&ctx->panel);
    354
    355	return 0;
    356}
    357
    358static const struct of_device_id xpp055c272_of_match[] = {
    359	{ .compatible = "xinpeng,xpp055c272" },
    360	{ /* sentinel */ }
    361};
    362MODULE_DEVICE_TABLE(of, xpp055c272_of_match);
    363
    364static struct mipi_dsi_driver xpp055c272_driver = {
    365	.driver = {
    366		.name = "panel-xinpeng-xpp055c272",
    367		.of_match_table = xpp055c272_of_match,
    368	},
    369	.probe	= xpp055c272_probe,
    370	.remove = xpp055c272_remove,
    371	.shutdown = xpp055c272_shutdown,
    372};
    373module_mipi_dsi_driver(xpp055c272_driver);
    374
    375MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
    376MODULE_DESCRIPTION("DRM driver for Xinpeng xpp055c272 MIPI DSI panel");
    377MODULE_LICENSE("GPL v2");