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-jdi-fhd-r63452.c (8189B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2021 Raffaele Tranquillini <raffaele.tranquillini@gmail.com>
      4 *
      5 * Generated using linux-mdss-dsi-panel-driver-generator from Lineage OS device tree:
      6 * https://github.com/LineageOS/android_kernel_xiaomi_msm8996/blob/lineage-18.1/arch/arm/boot/dts/qcom/a1-msm8996-mtp.dtsi
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/gpio/consumer.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13
     14#include <video/mipi_display.h>
     15
     16#include <drm/drm_mipi_dsi.h>
     17#include <drm/drm_modes.h>
     18#include <drm/drm_panel.h>
     19
     20struct jdi_fhd_r63452 {
     21	struct drm_panel panel;
     22	struct mipi_dsi_device *dsi;
     23	struct gpio_desc *reset_gpio;
     24	bool prepared;
     25};
     26
     27static inline struct jdi_fhd_r63452 *to_jdi_fhd_r63452(struct drm_panel *panel)
     28{
     29	return container_of(panel, struct jdi_fhd_r63452, panel);
     30}
     31
     32#define dsi_generic_write_seq(dsi, seq...) do {				\
     33		static const u8 d[] = { seq };				\
     34		int ret;						\
     35		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
     36		if (ret < 0)						\
     37			return ret;					\
     38	} while (0)
     39
     40#define dsi_dcs_write_seq(dsi, seq...) do {				\
     41		static const u8 d[] = { seq };				\
     42		int ret;						\
     43		ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d));	\
     44		if (ret < 0)						\
     45			return ret;					\
     46	} while (0)
     47
     48static void jdi_fhd_r63452_reset(struct jdi_fhd_r63452 *ctx)
     49{
     50	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
     51	usleep_range(10000, 11000);
     52	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
     53	usleep_range(1000, 2000);
     54	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
     55	usleep_range(10000, 11000);
     56}
     57
     58static int jdi_fhd_r63452_on(struct jdi_fhd_r63452 *ctx)
     59{
     60	struct mipi_dsi_device *dsi = ctx->dsi;
     61	struct device *dev = &dsi->dev;
     62	int ret;
     63
     64	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
     65
     66	dsi_generic_write_seq(dsi, 0xb0, 0x00);
     67	dsi_generic_write_seq(dsi, 0xd6, 0x01);
     68	dsi_generic_write_seq(dsi, 0xec,
     69			      0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
     70			      0x13, 0x15, 0x68, 0x0b, 0xb5);
     71	dsi_generic_write_seq(dsi, 0xb0, 0x03);
     72
     73	ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
     74	if (ret < 0) {
     75		dev_err(dev, "Failed to set tear on: %d\n", ret);
     76		return ret;
     77	}
     78
     79	dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
     80
     81	ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
     82	if (ret < 0) {
     83		dev_err(dev, "Failed to set pixel format: %d\n", ret);
     84		return ret;
     85	}
     86
     87	ret = mipi_dsi_dcs_set_column_address(dsi, 0x0000, 0x0437);
     88	if (ret < 0) {
     89		dev_err(dev, "Failed to set column address: %d\n", ret);
     90		return ret;
     91	}
     92
     93	ret = mipi_dsi_dcs_set_page_address(dsi, 0x0000, 0x077f);
     94	if (ret < 0) {
     95		dev_err(dev, "Failed to set page address: %d\n", ret);
     96		return ret;
     97	}
     98
     99	ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x0000);
    100	if (ret < 0) {
    101		dev_err(dev, "Failed to set tear scanline: %d\n", ret);
    102		return ret;
    103	}
    104
    105	ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff);
    106	if (ret < 0) {
    107		dev_err(dev, "Failed to set display brightness: %d\n", ret);
    108		return ret;
    109	}
    110
    111	dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
    112	dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
    113	dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00);
    114	dsi_dcs_write_seq(dsi, 0x84, 0x00);
    115
    116	ret = mipi_dsi_dcs_set_display_on(dsi);
    117	if (ret < 0) {
    118		dev_err(dev, "Failed to set display on: %d\n", ret);
    119		return ret;
    120	}
    121	msleep(20);
    122
    123	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
    124	if (ret < 0) {
    125		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
    126		return ret;
    127	}
    128	msleep(80);
    129
    130	dsi_generic_write_seq(dsi, 0xb0, 0x04);
    131	dsi_dcs_write_seq(dsi, 0x84, 0x00);
    132	dsi_generic_write_seq(dsi, 0xc8, 0x11);
    133	dsi_generic_write_seq(dsi, 0xb0, 0x03);
    134
    135	return 0;
    136}
    137
    138static int jdi_fhd_r63452_off(struct jdi_fhd_r63452 *ctx)
    139{
    140	struct mipi_dsi_device *dsi = ctx->dsi;
    141	struct device *dev = &dsi->dev;
    142	int ret;
    143
    144	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    145
    146	dsi_generic_write_seq(dsi, 0xb0, 0x00);
    147	dsi_generic_write_seq(dsi, 0xd6, 0x01);
    148	dsi_generic_write_seq(dsi, 0xec,
    149			      0x64, 0xdc, 0xec, 0x3b, 0x52, 0x00, 0x0b, 0x0b,
    150			      0x13, 0x15, 0x68, 0x0b, 0x95);
    151	dsi_generic_write_seq(dsi, 0xb0, 0x03);
    152
    153	ret = mipi_dsi_dcs_set_display_off(dsi);
    154	if (ret < 0) {
    155		dev_err(dev, "Failed to set display off: %d\n", ret);
    156		return ret;
    157	}
    158	usleep_range(2000, 3000);
    159
    160	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    161	if (ret < 0) {
    162		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
    163		return ret;
    164	}
    165	msleep(120);
    166
    167	return 0;
    168}
    169
    170static int jdi_fhd_r63452_prepare(struct drm_panel *panel)
    171{
    172	struct jdi_fhd_r63452 *ctx = to_jdi_fhd_r63452(panel);
    173	struct device *dev = &ctx->dsi->dev;
    174	int ret;
    175
    176	if (ctx->prepared)
    177		return 0;
    178
    179	jdi_fhd_r63452_reset(ctx);
    180
    181	ret = jdi_fhd_r63452_on(ctx);
    182	if (ret < 0) {
    183		dev_err(dev, "Failed to initialize panel: %d\n", ret);
    184		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    185		return ret;
    186	}
    187
    188	ctx->prepared = true;
    189	return 0;
    190}
    191
    192static int jdi_fhd_r63452_unprepare(struct drm_panel *panel)
    193{
    194	struct jdi_fhd_r63452 *ctx = to_jdi_fhd_r63452(panel);
    195	struct device *dev = &ctx->dsi->dev;
    196	int ret;
    197
    198	if (!ctx->prepared)
    199		return 0;
    200
    201	ret = jdi_fhd_r63452_off(ctx);
    202	if (ret < 0)
    203		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
    204
    205	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
    206
    207	ctx->prepared = false;
    208	return 0;
    209}
    210
    211static const struct drm_display_mode jdi_fhd_r63452_mode = {
    212	.clock = (1080 + 120 + 16 + 40) * (1920 + 4 + 2 + 4) * 60 / 1000,
    213	.hdisplay = 1080,
    214	.hsync_start = 1080 + 120,
    215	.hsync_end = 1080 + 120 + 16,
    216	.htotal = 1080 + 120 + 16 + 40,
    217	.vdisplay = 1920,
    218	.vsync_start = 1920 + 4,
    219	.vsync_end = 1920 + 4 + 2,
    220	.vtotal = 1920 + 4 + 2 + 4,
    221	.width_mm = 64,
    222	.height_mm = 114,
    223};
    224
    225static int jdi_fhd_r63452_get_modes(struct drm_panel *panel,
    226				    struct drm_connector *connector)
    227{
    228	struct drm_display_mode *mode;
    229
    230	mode = drm_mode_duplicate(connector->dev, &jdi_fhd_r63452_mode);
    231	if (!mode)
    232		return -ENOMEM;
    233
    234	drm_mode_set_name(mode);
    235
    236	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    237	connector->display_info.width_mm = mode->width_mm;
    238	connector->display_info.height_mm = mode->height_mm;
    239	drm_mode_probed_add(connector, mode);
    240
    241	return 1;
    242}
    243
    244static const struct drm_panel_funcs jdi_fhd_r63452_panel_funcs = {
    245	.prepare = jdi_fhd_r63452_prepare,
    246	.unprepare = jdi_fhd_r63452_unprepare,
    247	.get_modes = jdi_fhd_r63452_get_modes,
    248};
    249
    250static int jdi_fhd_r63452_probe(struct mipi_dsi_device *dsi)
    251{
    252	struct device *dev = &dsi->dev;
    253	struct jdi_fhd_r63452 *ctx;
    254	int ret;
    255
    256	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    257	if (!ctx)
    258		return -ENOMEM;
    259
    260	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
    261	if (IS_ERR(ctx->reset_gpio))
    262		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
    263				     "Failed to get reset-gpios\n");
    264
    265	ctx->dsi = dsi;
    266	mipi_dsi_set_drvdata(dsi, ctx);
    267
    268	dsi->lanes = 4;
    269	dsi->format = MIPI_DSI_FMT_RGB888;
    270	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
    271			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
    272
    273	drm_panel_init(&ctx->panel, dev, &jdi_fhd_r63452_panel_funcs,
    274		       DRM_MODE_CONNECTOR_DSI);
    275
    276	ret = drm_panel_of_backlight(&ctx->panel);
    277	if (ret)
    278		return dev_err_probe(dev, ret, "Failed to get backlight\n");
    279
    280	drm_panel_add(&ctx->panel);
    281
    282	ret = mipi_dsi_attach(dsi);
    283	if (ret < 0) {
    284		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
    285		return ret;
    286	}
    287
    288	return 0;
    289}
    290
    291static int jdi_fhd_r63452_remove(struct mipi_dsi_device *dsi)
    292{
    293	struct jdi_fhd_r63452 *ctx = mipi_dsi_get_drvdata(dsi);
    294	int ret;
    295
    296	ret = mipi_dsi_detach(dsi);
    297	if (ret < 0)
    298		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
    299
    300	drm_panel_remove(&ctx->panel);
    301
    302	return 0;
    303}
    304
    305static const struct of_device_id jdi_fhd_r63452_of_match[] = {
    306	{ .compatible = "jdi,fhd-r63452" },
    307	{ /* sentinel */ }
    308};
    309MODULE_DEVICE_TABLE(of, jdi_fhd_r63452_of_match);
    310
    311static struct mipi_dsi_driver jdi_fhd_r63452_driver = {
    312	.probe = jdi_fhd_r63452_probe,
    313	.remove = jdi_fhd_r63452_remove,
    314	.driver = {
    315		.name = "panel-jdi-fhd-r63452",
    316		.of_match_table = jdi_fhd_r63452_of_match,
    317	},
    318};
    319module_mipi_dsi_driver(jdi_fhd_r63452_driver);
    320
    321MODULE_AUTHOR("Raffaele Tranquillini <raffaele.tranquillini@gmail.com>");
    322MODULE_DESCRIPTION("DRM driver for JDI FHD R63452 DSI panel, command mode");
    323MODULE_LICENSE("GPL v2");