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-asus-z00t-tm5p5-n35596.c (9489B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include <linux/backlight.h>
      4#include <linux/delay.h>
      5#include <linux/gpio/consumer.h>
      6#include <linux/module.h>
      7#include <linux/of.h>
      8#include <linux/regulator/consumer.h>
      9
     10#include <drm/drm_mipi_dsi.h>
     11#include <drm/drm_modes.h>
     12#include <drm/drm_panel.h>
     13
     14struct tm5p5_nt35596 {
     15	struct drm_panel panel;
     16	struct mipi_dsi_device *dsi;
     17	struct regulator_bulk_data supplies[2];
     18	struct gpio_desc *reset_gpio;
     19	bool prepared;
     20};
     21
     22static inline struct tm5p5_nt35596 *to_tm5p5_nt35596(struct drm_panel *panel)
     23{
     24	return container_of(panel, struct tm5p5_nt35596, panel);
     25}
     26
     27#define dsi_generic_write_seq(dsi, seq...) do {				\
     28		static const u8 d[] = { seq };				\
     29		int ret;						\
     30		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
     31		if (ret < 0)						\
     32			return ret;					\
     33	} while (0)
     34
     35#define dsi_dcs_write_seq(dsi, seq...) do {				\
     36		static const u8 d[] = { seq };				\
     37		int ret;						\
     38		ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d));	\
     39		if (ret < 0)						\
     40			return ret;					\
     41	} while (0)
     42
     43static void tm5p5_nt35596_reset(struct tm5p5_nt35596 *ctx)
     44{
     45	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
     46	usleep_range(1000, 2000);
     47	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
     48	usleep_range(1000, 2000);
     49	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
     50	usleep_range(15000, 16000);
     51}
     52
     53static int tm5p5_nt35596_on(struct tm5p5_nt35596 *ctx)
     54{
     55	struct mipi_dsi_device *dsi = ctx->dsi;
     56
     57	dsi_generic_write_seq(dsi, 0xff, 0x05);
     58	dsi_generic_write_seq(dsi, 0xfb, 0x01);
     59	dsi_generic_write_seq(dsi, 0xc5, 0x31);
     60	dsi_generic_write_seq(dsi, 0xff, 0x04);
     61	dsi_generic_write_seq(dsi, 0x01, 0x84);
     62	dsi_generic_write_seq(dsi, 0x05, 0x25);
     63	dsi_generic_write_seq(dsi, 0x06, 0x01);
     64	dsi_generic_write_seq(dsi, 0x07, 0x20);
     65	dsi_generic_write_seq(dsi, 0x08, 0x06);
     66	dsi_generic_write_seq(dsi, 0x09, 0x08);
     67	dsi_generic_write_seq(dsi, 0x0a, 0x10);
     68	dsi_generic_write_seq(dsi, 0x0b, 0x10);
     69	dsi_generic_write_seq(dsi, 0x0c, 0x10);
     70	dsi_generic_write_seq(dsi, 0x0d, 0x14);
     71	dsi_generic_write_seq(dsi, 0x0e, 0x14);
     72	dsi_generic_write_seq(dsi, 0x0f, 0x14);
     73	dsi_generic_write_seq(dsi, 0x10, 0x14);
     74	dsi_generic_write_seq(dsi, 0x11, 0x14);
     75	dsi_generic_write_seq(dsi, 0x12, 0x14);
     76	dsi_generic_write_seq(dsi, 0x17, 0xf3);
     77	dsi_generic_write_seq(dsi, 0x18, 0xc0);
     78	dsi_generic_write_seq(dsi, 0x19, 0xc0);
     79	dsi_generic_write_seq(dsi, 0x1a, 0xc0);
     80	dsi_generic_write_seq(dsi, 0x1b, 0xb3);
     81	dsi_generic_write_seq(dsi, 0x1c, 0xb3);
     82	dsi_generic_write_seq(dsi, 0x1d, 0xb3);
     83	dsi_generic_write_seq(dsi, 0x1e, 0xb3);
     84	dsi_generic_write_seq(dsi, 0x1f, 0xb3);
     85	dsi_generic_write_seq(dsi, 0x20, 0xb3);
     86	dsi_generic_write_seq(dsi, 0xfb, 0x01);
     87	dsi_generic_write_seq(dsi, 0xff, 0x00);
     88	dsi_generic_write_seq(dsi, 0xfb, 0x01);
     89	dsi_generic_write_seq(dsi, 0x35, 0x01);
     90	dsi_generic_write_seq(dsi, 0xd3, 0x06);
     91	dsi_generic_write_seq(dsi, 0xd4, 0x04);
     92	dsi_generic_write_seq(dsi, 0x5e, 0x0d);
     93	dsi_generic_write_seq(dsi, 0x11, 0x00);
     94	msleep(100);
     95	dsi_generic_write_seq(dsi, 0x29, 0x00);
     96	dsi_generic_write_seq(dsi, 0x53, 0x24);
     97
     98	return 0;
     99}
    100
    101static int tm5p5_nt35596_off(struct tm5p5_nt35596 *ctx)
    102{
    103	struct mipi_dsi_device *dsi = ctx->dsi;
    104	struct device *dev = &dsi->dev;
    105	int ret;
    106
    107	ret = mipi_dsi_dcs_set_display_off(dsi);
    108	if (ret < 0) {
    109		dev_err(dev, "Failed to set display off: %d\n", ret);
    110		return ret;
    111	}
    112	msleep(60);
    113
    114	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    115	if (ret < 0) {
    116		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
    117		return ret;
    118	}
    119
    120	dsi_dcs_write_seq(dsi, 0x4f, 0x01);
    121
    122	return 0;
    123}
    124
    125static int tm5p5_nt35596_prepare(struct drm_panel *panel)
    126{
    127	struct tm5p5_nt35596 *ctx = to_tm5p5_nt35596(panel);
    128	struct device *dev = &ctx->dsi->dev;
    129	int ret;
    130
    131	if (ctx->prepared)
    132		return 0;
    133
    134	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
    135	if (ret < 0) {
    136		dev_err(dev, "Failed to enable regulators: %d\n", ret);
    137		return ret;
    138	}
    139
    140	tm5p5_nt35596_reset(ctx);
    141
    142	ret = tm5p5_nt35596_on(ctx);
    143	if (ret < 0) {
    144		dev_err(dev, "Failed to initialize panel: %d\n", ret);
    145		gpiod_set_value_cansleep(ctx->reset_gpio, 0);
    146		regulator_bulk_disable(ARRAY_SIZE(ctx->supplies),
    147				       ctx->supplies);
    148		return ret;
    149	}
    150
    151	ctx->prepared = true;
    152	return 0;
    153}
    154
    155static int tm5p5_nt35596_unprepare(struct drm_panel *panel)
    156{
    157	struct tm5p5_nt35596 *ctx = to_tm5p5_nt35596(panel);
    158	struct device *dev = &ctx->dsi->dev;
    159	int ret;
    160
    161	if (!ctx->prepared)
    162		return 0;
    163
    164	ret = tm5p5_nt35596_off(ctx);
    165	if (ret < 0)
    166		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
    167
    168	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
    169	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies),
    170			       ctx->supplies);
    171
    172	ctx->prepared = false;
    173	return 0;
    174}
    175
    176static const struct drm_display_mode tm5p5_nt35596_mode = {
    177	.clock = (1080 + 100 + 8 + 16) * (1920 + 4 + 2 + 4) * 60 / 1000,
    178	.hdisplay = 1080,
    179	.hsync_start = 1080 + 100,
    180	.hsync_end = 1080 + 100 + 8,
    181	.htotal = 1080 + 100 + 8 + 16,
    182	.vdisplay = 1920,
    183	.vsync_start = 1920 + 4,
    184	.vsync_end = 1920 + 4 + 2,
    185	.vtotal = 1920 + 4 + 2 + 4,
    186	.width_mm = 68,
    187	.height_mm = 121,
    188};
    189
    190static int tm5p5_nt35596_get_modes(struct drm_panel *panel,
    191				   struct drm_connector *connector)
    192{
    193	struct drm_display_mode *mode;
    194
    195	mode = drm_mode_duplicate(connector->dev, &tm5p5_nt35596_mode);
    196	if (!mode)
    197		return -ENOMEM;
    198
    199	drm_mode_set_name(mode);
    200
    201	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    202	connector->display_info.width_mm = mode->width_mm;
    203	connector->display_info.height_mm = mode->height_mm;
    204	drm_mode_probed_add(connector, mode);
    205
    206	return 1;
    207}
    208
    209static const struct drm_panel_funcs tm5p5_nt35596_panel_funcs = {
    210	.prepare = tm5p5_nt35596_prepare,
    211	.unprepare = tm5p5_nt35596_unprepare,
    212	.get_modes = tm5p5_nt35596_get_modes,
    213};
    214
    215static int tm5p5_nt35596_bl_update_status(struct backlight_device *bl)
    216{
    217	struct mipi_dsi_device *dsi = bl_get_data(bl);
    218	u16 brightness = bl->props.brightness;
    219	int ret;
    220
    221	if (bl->props.power != FB_BLANK_UNBLANK ||
    222	    bl->props.fb_blank != FB_BLANK_UNBLANK ||
    223	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
    224		brightness = 0;
    225
    226	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    227
    228	ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
    229	if (ret < 0)
    230		return ret;
    231
    232	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    233
    234	return 0;
    235}
    236
    237static int tm5p5_nt35596_bl_get_brightness(struct backlight_device *bl)
    238{
    239	struct mipi_dsi_device *dsi = bl_get_data(bl);
    240	u16 brightness = bl->props.brightness;
    241	int ret;
    242
    243	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    244
    245	ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
    246	if (ret < 0)
    247		return ret;
    248
    249	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    250
    251	return brightness & 0xff;
    252}
    253
    254static const struct backlight_ops tm5p5_nt35596_bl_ops = {
    255	.update_status = tm5p5_nt35596_bl_update_status,
    256	.get_brightness = tm5p5_nt35596_bl_get_brightness,
    257};
    258
    259static struct backlight_device *
    260tm5p5_nt35596_create_backlight(struct mipi_dsi_device *dsi)
    261{
    262	struct device *dev = &dsi->dev;
    263	const struct backlight_properties props = {
    264		.type = BACKLIGHT_RAW,
    265		.brightness = 255,
    266		.max_brightness = 255,
    267	};
    268
    269	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
    270					      &tm5p5_nt35596_bl_ops, &props);
    271}
    272
    273static int tm5p5_nt35596_probe(struct mipi_dsi_device *dsi)
    274{
    275	struct device *dev = &dsi->dev;
    276	struct tm5p5_nt35596 *ctx;
    277	int ret;
    278
    279	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    280	if (!ctx)
    281		return -ENOMEM;
    282
    283	ctx->supplies[0].supply = "vdd";
    284	ctx->supplies[1].supply = "vddio";
    285	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
    286				      ctx->supplies);
    287	if (ret < 0) {
    288		dev_err(dev, "Failed to get regulators: %d\n", ret);
    289		return ret;
    290	}
    291
    292	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
    293	if (IS_ERR(ctx->reset_gpio)) {
    294		ret = PTR_ERR(ctx->reset_gpio);
    295		dev_err(dev, "Failed to get reset-gpios: %d\n", ret);
    296		return ret;
    297	}
    298
    299	ctx->dsi = dsi;
    300	mipi_dsi_set_drvdata(dsi, ctx);
    301
    302	dsi->lanes = 4;
    303	dsi->format = MIPI_DSI_FMT_RGB888;
    304	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
    305			  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_NO_EOT_PACKET |
    306			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
    307
    308	drm_panel_init(&ctx->panel, dev, &tm5p5_nt35596_panel_funcs,
    309		       DRM_MODE_CONNECTOR_DSI);
    310
    311	ctx->panel.backlight = tm5p5_nt35596_create_backlight(dsi);
    312	if (IS_ERR(ctx->panel.backlight)) {
    313		ret = PTR_ERR(ctx->panel.backlight);
    314		dev_err(dev, "Failed to create backlight: %d\n", ret);
    315		return ret;
    316	}
    317
    318	drm_panel_add(&ctx->panel);
    319
    320	ret = mipi_dsi_attach(dsi);
    321	if (ret < 0) {
    322		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
    323		return ret;
    324	}
    325
    326	return 0;
    327}
    328
    329static int tm5p5_nt35596_remove(struct mipi_dsi_device *dsi)
    330{
    331	struct tm5p5_nt35596 *ctx = mipi_dsi_get_drvdata(dsi);
    332	int ret;
    333
    334	ret = mipi_dsi_detach(dsi);
    335	if (ret < 0)
    336		dev_err(&dsi->dev,
    337			"Failed to detach from DSI host: %d\n", ret);
    338
    339	drm_panel_remove(&ctx->panel);
    340
    341	return 0;
    342}
    343
    344static const struct of_device_id tm5p5_nt35596_of_match[] = {
    345	{ .compatible = "asus,z00t-tm5p5-n35596" },
    346	{ /* sentinel */ }
    347};
    348MODULE_DEVICE_TABLE(of, tm5p5_nt35596_of_match);
    349
    350static struct mipi_dsi_driver tm5p5_nt35596_driver = {
    351	.probe = tm5p5_nt35596_probe,
    352	.remove = tm5p5_nt35596_remove,
    353	.driver = {
    354		.name = "panel-tm5p5-nt35596",
    355		.of_match_table = tm5p5_nt35596_of_match,
    356	},
    357};
    358module_mipi_dsi_driver(tm5p5_nt35596_driver);
    359
    360MODULE_AUTHOR("Konrad Dybcio <konradybcio@gmail.com>");
    361MODULE_DESCRIPTION("DRM driver for tm5p5 nt35596 1080p video mode dsi panel");
    362MODULE_LICENSE("GPL v2");