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-visionox-rm69299.c (7220B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2019, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/delay.h>
      7#include <linux/module.h>
      8#include <linux/of_device.h>
      9#include <linux/gpio/consumer.h>
     10#include <linux/regulator/consumer.h>
     11
     12#include <video/mipi_display.h>
     13
     14#include <drm/drm_mipi_dsi.h>
     15#include <drm/drm_modes.h>
     16#include <drm/drm_panel.h>
     17
     18struct visionox_rm69299 {
     19	struct drm_panel panel;
     20	struct regulator_bulk_data supplies[2];
     21	struct gpio_desc *reset_gpio;
     22	struct mipi_dsi_device *dsi;
     23	bool prepared;
     24	bool enabled;
     25};
     26
     27static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel)
     28{
     29	return container_of(panel, struct visionox_rm69299, panel);
     30}
     31
     32static int visionox_rm69299_power_on(struct visionox_rm69299 *ctx)
     33{
     34	int ret;
     35
     36	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
     37	if (ret < 0)
     38		return ret;
     39
     40	/*
     41	 * Reset sequence of visionox panel requires the panel to be
     42	 * out of reset for 10ms, followed by being held in reset
     43	 * for 10ms and then out again
     44	 */
     45	gpiod_set_value(ctx->reset_gpio, 1);
     46	usleep_range(10000, 20000);
     47	gpiod_set_value(ctx->reset_gpio, 0);
     48	usleep_range(10000, 20000);
     49	gpiod_set_value(ctx->reset_gpio, 1);
     50	usleep_range(10000, 20000);
     51
     52	return 0;
     53}
     54
     55static int visionox_rm69299_power_off(struct visionox_rm69299 *ctx)
     56{
     57	gpiod_set_value(ctx->reset_gpio, 0);
     58
     59	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
     60}
     61
     62static int visionox_rm69299_unprepare(struct drm_panel *panel)
     63{
     64	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
     65	int ret;
     66
     67	ctx->dsi->mode_flags = 0;
     68
     69	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
     70	if (ret < 0)
     71		dev_err(ctx->panel.dev, "set_display_off cmd failed ret = %d\n", ret);
     72
     73	/* 120ms delay required here as per DCS spec */
     74	msleep(120);
     75
     76	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
     77	if (ret < 0) {
     78		dev_err(ctx->panel.dev, "enter_sleep cmd failed ret = %d\n", ret);
     79	}
     80
     81	ret = visionox_rm69299_power_off(ctx);
     82
     83	ctx->prepared = false;
     84	return ret;
     85}
     86
     87static int visionox_rm69299_prepare(struct drm_panel *panel)
     88{
     89	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
     90	int ret;
     91
     92	if (ctx->prepared)
     93		return 0;
     94
     95	ret = visionox_rm69299_power_on(ctx);
     96	if (ret < 0)
     97		return ret;
     98
     99	ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    100
    101	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2);
    102	if (ret < 0) {
    103		dev_err(ctx->panel.dev, "cmd set tx 0 failed, ret = %d\n", ret);
    104		goto power_off;
    105	}
    106
    107	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2);
    108	if (ret < 0) {
    109		dev_err(ctx->panel.dev, "cmd set tx 1 failed, ret = %d\n", ret);
    110		goto power_off;
    111	}
    112
    113	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2);
    114	if (ret < 0) {
    115		dev_err(ctx->panel.dev, "cmd set tx 2 failed, ret = %d\n", ret);
    116		goto power_off;
    117	}
    118
    119	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2);
    120	if (ret < 0) {
    121		dev_err(ctx->panel.dev, "cmd set tx 3 failed, ret = %d\n", ret);
    122		goto power_off;
    123	}
    124
    125	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
    126	if (ret < 0) {
    127		dev_err(ctx->panel.dev, "exit_sleep_mode cmd failed ret = %d\n", ret);
    128		goto power_off;
    129	}
    130
    131	/* Per DSI spec wait 120ms after sending exit sleep DCS command */
    132	msleep(120);
    133
    134	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
    135	if (ret < 0) {
    136		dev_err(ctx->panel.dev, "set_display_on cmd failed ret = %d\n", ret);
    137		goto power_off;
    138	}
    139
    140	/* Per DSI spec wait 120ms after sending set_display_on DCS command */
    141	msleep(120);
    142
    143	ctx->prepared = true;
    144
    145	return 0;
    146
    147power_off:
    148	return ret;
    149}
    150
    151static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = {
    152	.name = "1080x2248",
    153	.clock = 158695,
    154	.hdisplay = 1080,
    155	.hsync_start = 1080 + 26,
    156	.hsync_end = 1080 + 26 + 2,
    157	.htotal = 1080 + 26 + 2 + 36,
    158	.vdisplay = 2248,
    159	.vsync_start = 2248 + 56,
    160	.vsync_end = 2248 + 56 + 4,
    161	.vtotal = 2248 + 56 + 4 + 4,
    162	.flags = 0,
    163};
    164
    165static int visionox_rm69299_get_modes(struct drm_panel *panel,
    166				      struct drm_connector *connector)
    167{
    168	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
    169	struct drm_display_mode *mode;
    170
    171	mode = drm_mode_duplicate(connector->dev,
    172				  &visionox_rm69299_1080x2248_60hz);
    173	if (!mode) {
    174		dev_err(ctx->panel.dev, "failed to create a new display mode\n");
    175		return 0;
    176	}
    177
    178	connector->display_info.width_mm = 74;
    179	connector->display_info.height_mm = 131;
    180	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
    181	drm_mode_probed_add(connector, mode);
    182
    183	return 1;
    184}
    185
    186static const struct drm_panel_funcs visionox_rm69299_drm_funcs = {
    187	.unprepare = visionox_rm69299_unprepare,
    188	.prepare = visionox_rm69299_prepare,
    189	.get_modes = visionox_rm69299_get_modes,
    190};
    191
    192static int visionox_rm69299_probe(struct mipi_dsi_device *dsi)
    193{
    194	struct device *dev = &dsi->dev;
    195	struct visionox_rm69299 *ctx;
    196	int ret;
    197
    198	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
    199	if (!ctx)
    200		return -ENOMEM;
    201
    202	mipi_dsi_set_drvdata(dsi, ctx);
    203
    204	ctx->panel.dev = dev;
    205	ctx->dsi = dsi;
    206
    207	ctx->supplies[0].supply = "vdda";
    208	ctx->supplies[1].supply = "vdd3p3";
    209
    210	ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies),
    211				      ctx->supplies);
    212	if (ret < 0)
    213		return ret;
    214
    215	ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev,
    216					 "reset", GPIOD_OUT_LOW);
    217	if (IS_ERR(ctx->reset_gpio)) {
    218		dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio));
    219		return PTR_ERR(ctx->reset_gpio);
    220	}
    221
    222	drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs,
    223		       DRM_MODE_CONNECTOR_DSI);
    224	ctx->panel.dev = dev;
    225	ctx->panel.funcs = &visionox_rm69299_drm_funcs;
    226	drm_panel_add(&ctx->panel);
    227
    228	dsi->lanes = 4;
    229	dsi->format = MIPI_DSI_FMT_RGB888;
    230	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
    231			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
    232	ret = mipi_dsi_attach(dsi);
    233	if (ret < 0) {
    234		dev_err(dev, "dsi attach failed ret = %d\n", ret);
    235		goto err_dsi_attach;
    236	}
    237
    238	ret = regulator_set_load(ctx->supplies[0].consumer, 32000);
    239	if (ret) {
    240		dev_err(dev, "regulator set load failed for vdda supply ret = %d\n", ret);
    241		goto err_set_load;
    242	}
    243
    244	ret = regulator_set_load(ctx->supplies[1].consumer, 13200);
    245	if (ret) {
    246		dev_err(dev, "regulator set load failed for vdd3p3 supply ret = %d\n", ret);
    247		goto err_set_load;
    248	}
    249
    250	return 0;
    251
    252err_set_load:
    253	mipi_dsi_detach(dsi);
    254err_dsi_attach:
    255	drm_panel_remove(&ctx->panel);
    256	return ret;
    257}
    258
    259static int visionox_rm69299_remove(struct mipi_dsi_device *dsi)
    260{
    261	struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi);
    262
    263	mipi_dsi_detach(ctx->dsi);
    264	mipi_dsi_device_unregister(ctx->dsi);
    265
    266	drm_panel_remove(&ctx->panel);
    267	return 0;
    268}
    269
    270static const struct of_device_id visionox_rm69299_of_match[] = {
    271	{ .compatible = "visionox,rm69299-1080p-display", },
    272	{ /* sentinel */ }
    273};
    274MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match);
    275
    276static struct mipi_dsi_driver visionox_rm69299_driver = {
    277	.driver = {
    278		.name = "panel-visionox-rm69299",
    279		.of_match_table = visionox_rm69299_of_match,
    280	},
    281	.probe = visionox_rm69299_probe,
    282	.remove = visionox_rm69299_remove,
    283};
    284module_mipi_dsi_driver(visionox_rm69299_driver);
    285
    286MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver");
    287MODULE_LICENSE("GPL v2");