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-lt070me05000.c (11657B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2016 InforceComputing
      4 * Author: Vinay Simha BN <simhavcs@gmail.com>
      5 *
      6 * Copyright (C) 2016 Linaro Ltd
      7 * Author: Sumit Semwal <sumit.semwal@linaro.org>
      8 *
      9 * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
     10 * JDI model LT070ME05000, and its data sheet is at:
     11 * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
     12 */
     13
     14#include <linux/backlight.h>
     15#include <linux/delay.h>
     16#include <linux/gpio/consumer.h>
     17#include <linux/module.h>
     18#include <linux/of.h>
     19#include <linux/regulator/consumer.h>
     20
     21#include <video/mipi_display.h>
     22
     23#include <drm/drm_crtc.h>
     24#include <drm/drm_mipi_dsi.h>
     25#include <drm/drm_modes.h>
     26#include <drm/drm_panel.h>
     27
     28static const char * const regulator_names[] = {
     29	"vddp",
     30	"iovcc"
     31};
     32
     33struct jdi_panel {
     34	struct drm_panel base;
     35	struct mipi_dsi_device *dsi;
     36
     37	struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
     38
     39	struct gpio_desc *enable_gpio;
     40	struct gpio_desc *reset_gpio;
     41	struct gpio_desc *dcdc_en_gpio;
     42	struct backlight_device *backlight;
     43
     44	bool prepared;
     45	bool enabled;
     46
     47	const struct drm_display_mode *mode;
     48};
     49
     50static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)
     51{
     52	return container_of(panel, struct jdi_panel, base);
     53}
     54
     55static int jdi_panel_init(struct jdi_panel *jdi)
     56{
     57	struct mipi_dsi_device *dsi = jdi->dsi;
     58	struct device *dev = &jdi->dsi->dev;
     59	int ret;
     60
     61	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
     62
     63	ret = mipi_dsi_dcs_soft_reset(dsi);
     64	if (ret < 0)
     65		return ret;
     66
     67	usleep_range(10000, 20000);
     68
     69	ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
     70	if (ret < 0) {
     71		dev_err(dev, "failed to set pixel format: %d\n", ret);
     72		return ret;
     73	}
     74
     75	ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);
     76	if (ret < 0) {
     77		dev_err(dev, "failed to set column address: %d\n", ret);
     78		return ret;
     79	}
     80
     81	ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);
     82	if (ret < 0) {
     83		dev_err(dev, "failed to set page address: %d\n", ret);
     84		return ret;
     85	}
     86
     87	/*
     88	 * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers
     89	 *                  are active
     90	 * BIT(3) BL = 1    Backlight Control On
     91	 * BIT(2) DD = 0    Display Dimming is Off
     92	 */
     93	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
     94				 (u8[]){ 0x24 }, 1);
     95	if (ret < 0) {
     96		dev_err(dev, "failed to write control display: %d\n", ret);
     97		return ret;
     98	}
     99
    100	/* CABC off */
    101	ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
    102				 (u8[]){ 0x00 }, 1);
    103	if (ret < 0) {
    104		dev_err(dev, "failed to set cabc off: %d\n", ret);
    105		return ret;
    106	}
    107
    108	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
    109	if (ret < 0) {
    110		dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
    111		return ret;
    112	}
    113
    114	msleep(120);
    115
    116	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);
    117	if (ret < 0) {
    118		dev_err(dev, "failed to set mcap: %d\n", ret);
    119		return ret;
    120	}
    121
    122	mdelay(10);
    123
    124	/* Interface setting, video mode */
    125	ret = mipi_dsi_generic_write(dsi, (u8[])
    126				     {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);
    127	if (ret < 0) {
    128		dev_err(dev, "failed to set display interface setting: %d\n"
    129			, ret);
    130		return ret;
    131	}
    132
    133	mdelay(20);
    134
    135	ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);
    136	if (ret < 0) {
    137		dev_err(dev, "failed to set default values for mcap: %d\n"
    138			, ret);
    139		return ret;
    140	}
    141
    142	return 0;
    143}
    144
    145static int jdi_panel_on(struct jdi_panel *jdi)
    146{
    147	struct mipi_dsi_device *dsi = jdi->dsi;
    148	struct device *dev = &jdi->dsi->dev;
    149	int ret;
    150
    151	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    152
    153	ret = mipi_dsi_dcs_set_display_on(dsi);
    154	if (ret < 0)
    155		dev_err(dev, "failed to set display on: %d\n", ret);
    156
    157	return ret;
    158}
    159
    160static void jdi_panel_off(struct jdi_panel *jdi)
    161{
    162	struct mipi_dsi_device *dsi = jdi->dsi;
    163	struct device *dev = &jdi->dsi->dev;
    164	int ret;
    165
    166	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    167
    168	ret = mipi_dsi_dcs_set_display_off(dsi);
    169	if (ret < 0)
    170		dev_err(dev, "failed to set display off: %d\n", ret);
    171
    172	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
    173	if (ret < 0)
    174		dev_err(dev, "failed to enter sleep mode: %d\n", ret);
    175
    176	msleep(100);
    177}
    178
    179static int jdi_panel_disable(struct drm_panel *panel)
    180{
    181	struct jdi_panel *jdi = to_jdi_panel(panel);
    182
    183	if (!jdi->enabled)
    184		return 0;
    185
    186	backlight_disable(jdi->backlight);
    187
    188	jdi->enabled = false;
    189
    190	return 0;
    191}
    192
    193static int jdi_panel_unprepare(struct drm_panel *panel)
    194{
    195	struct jdi_panel *jdi = to_jdi_panel(panel);
    196	struct device *dev = &jdi->dsi->dev;
    197	int ret;
    198
    199	if (!jdi->prepared)
    200		return 0;
    201
    202	jdi_panel_off(jdi);
    203
    204	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
    205	if (ret < 0)
    206		dev_err(dev, "regulator disable failed, %d\n", ret);
    207
    208	gpiod_set_value(jdi->enable_gpio, 0);
    209
    210	gpiod_set_value(jdi->reset_gpio, 1);
    211
    212	gpiod_set_value(jdi->dcdc_en_gpio, 0);
    213
    214	jdi->prepared = false;
    215
    216	return 0;
    217}
    218
    219static int jdi_panel_prepare(struct drm_panel *panel)
    220{
    221	struct jdi_panel *jdi = to_jdi_panel(panel);
    222	struct device *dev = &jdi->dsi->dev;
    223	int ret;
    224
    225	if (jdi->prepared)
    226		return 0;
    227
    228	ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
    229	if (ret < 0) {
    230		dev_err(dev, "regulator enable failed, %d\n", ret);
    231		return ret;
    232	}
    233
    234	msleep(20);
    235
    236	gpiod_set_value(jdi->dcdc_en_gpio, 1);
    237	usleep_range(10, 20);
    238
    239	gpiod_set_value(jdi->reset_gpio, 0);
    240	usleep_range(10, 20);
    241
    242	gpiod_set_value(jdi->enable_gpio, 1);
    243	usleep_range(10, 20);
    244
    245	ret = jdi_panel_init(jdi);
    246	if (ret < 0) {
    247		dev_err(dev, "failed to init panel: %d\n", ret);
    248		goto poweroff;
    249	}
    250
    251	ret = jdi_panel_on(jdi);
    252	if (ret < 0) {
    253		dev_err(dev, "failed to set panel on: %d\n", ret);
    254		goto poweroff;
    255	}
    256
    257	jdi->prepared = true;
    258
    259	return 0;
    260
    261poweroff:
    262	ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
    263	if (ret < 0)
    264		dev_err(dev, "regulator disable failed, %d\n", ret);
    265
    266	gpiod_set_value(jdi->enable_gpio, 0);
    267
    268	gpiod_set_value(jdi->reset_gpio, 1);
    269
    270	gpiod_set_value(jdi->dcdc_en_gpio, 0);
    271
    272	return ret;
    273}
    274
    275static int jdi_panel_enable(struct drm_panel *panel)
    276{
    277	struct jdi_panel *jdi = to_jdi_panel(panel);
    278
    279	if (jdi->enabled)
    280		return 0;
    281
    282	backlight_enable(jdi->backlight);
    283
    284	jdi->enabled = true;
    285
    286	return 0;
    287}
    288
    289static const struct drm_display_mode default_mode = {
    290		.clock = 155493,
    291		.hdisplay = 1200,
    292		.hsync_start = 1200 + 48,
    293		.hsync_end = 1200 + 48 + 32,
    294		.htotal = 1200 + 48 + 32 + 60,
    295		.vdisplay = 1920,
    296		.vsync_start = 1920 + 3,
    297		.vsync_end = 1920 + 3 + 5,
    298		.vtotal = 1920 + 3 + 5 + 6,
    299		.flags = 0,
    300};
    301
    302static int jdi_panel_get_modes(struct drm_panel *panel,
    303			       struct drm_connector *connector)
    304{
    305	struct drm_display_mode *mode;
    306	struct jdi_panel *jdi = to_jdi_panel(panel);
    307	struct device *dev = &jdi->dsi->dev;
    308
    309	mode = drm_mode_duplicate(connector->dev, &default_mode);
    310	if (!mode) {
    311		dev_err(dev, "failed to add mode %ux%ux@%u\n",
    312			default_mode.hdisplay, default_mode.vdisplay,
    313			drm_mode_vrefresh(&default_mode));
    314		return -ENOMEM;
    315	}
    316
    317	drm_mode_set_name(mode);
    318
    319	drm_mode_probed_add(connector, mode);
    320
    321	connector->display_info.width_mm = 95;
    322	connector->display_info.height_mm = 151;
    323
    324	return 1;
    325}
    326
    327static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
    328{
    329	struct mipi_dsi_device *dsi = bl_get_data(bl);
    330	int ret;
    331	u16 brightness = bl->props.brightness;
    332
    333	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    334
    335	ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
    336	if (ret < 0)
    337		return ret;
    338
    339	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    340
    341	return brightness & 0xff;
    342}
    343
    344static int dsi_dcs_bl_update_status(struct backlight_device *bl)
    345{
    346	struct mipi_dsi_device *dsi = bl_get_data(bl);
    347	int ret;
    348
    349	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
    350
    351	ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
    352	if (ret < 0)
    353		return ret;
    354
    355	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
    356
    357	return 0;
    358}
    359
    360static const struct backlight_ops dsi_bl_ops = {
    361	.update_status = dsi_dcs_bl_update_status,
    362	.get_brightness = dsi_dcs_bl_get_brightness,
    363};
    364
    365static struct backlight_device *
    366drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
    367{
    368	struct device *dev = &dsi->dev;
    369	struct backlight_properties props;
    370
    371	memset(&props, 0, sizeof(props));
    372	props.type = BACKLIGHT_RAW;
    373	props.brightness = 255;
    374	props.max_brightness = 255;
    375
    376	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
    377					      &dsi_bl_ops, &props);
    378}
    379
    380static const struct drm_panel_funcs jdi_panel_funcs = {
    381	.disable = jdi_panel_disable,
    382	.unprepare = jdi_panel_unprepare,
    383	.prepare = jdi_panel_prepare,
    384	.enable = jdi_panel_enable,
    385	.get_modes = jdi_panel_get_modes,
    386};
    387
    388static const struct of_device_id jdi_of_match[] = {
    389	{ .compatible = "jdi,lt070me05000", },
    390	{ }
    391};
    392MODULE_DEVICE_TABLE(of, jdi_of_match);
    393
    394static int jdi_panel_add(struct jdi_panel *jdi)
    395{
    396	struct device *dev = &jdi->dsi->dev;
    397	int ret;
    398	unsigned int i;
    399
    400	jdi->mode = &default_mode;
    401
    402	for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
    403		jdi->supplies[i].supply = regulator_names[i];
    404
    405	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
    406				      jdi->supplies);
    407	if (ret < 0) {
    408		dev_err(dev, "failed to init regulator, ret=%d\n", ret);
    409		return ret;
    410	}
    411
    412	jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
    413	if (IS_ERR(jdi->enable_gpio)) {
    414		ret = PTR_ERR(jdi->enable_gpio);
    415		dev_err(dev, "cannot get enable-gpio %d\n", ret);
    416		return ret;
    417	}
    418
    419	jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
    420	if (IS_ERR(jdi->reset_gpio)) {
    421		ret = PTR_ERR(jdi->reset_gpio);
    422		dev_err(dev, "cannot get reset-gpios %d\n", ret);
    423		return ret;
    424	}
    425
    426	jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
    427	if (IS_ERR(jdi->dcdc_en_gpio)) {
    428		ret = PTR_ERR(jdi->dcdc_en_gpio);
    429		dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
    430		return ret;
    431	}
    432
    433	jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
    434	if (IS_ERR(jdi->backlight)) {
    435		ret = PTR_ERR(jdi->backlight);
    436		dev_err(dev, "failed to register backlight %d\n", ret);
    437		return ret;
    438	}
    439
    440	drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
    441		       DRM_MODE_CONNECTOR_DSI);
    442
    443	drm_panel_add(&jdi->base);
    444
    445	return 0;
    446}
    447
    448static void jdi_panel_del(struct jdi_panel *jdi)
    449{
    450	if (jdi->base.dev)
    451		drm_panel_remove(&jdi->base);
    452}
    453
    454static int jdi_panel_probe(struct mipi_dsi_device *dsi)
    455{
    456	struct jdi_panel *jdi;
    457	int ret;
    458
    459	dsi->lanes = 4;
    460	dsi->format = MIPI_DSI_FMT_RGB888;
    461	dsi->mode_flags =  MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
    462			   MIPI_DSI_CLOCK_NON_CONTINUOUS;
    463
    464	jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
    465	if (!jdi)
    466		return -ENOMEM;
    467
    468	mipi_dsi_set_drvdata(dsi, jdi);
    469
    470	jdi->dsi = dsi;
    471
    472	ret = jdi_panel_add(jdi);
    473	if (ret < 0)
    474		return ret;
    475
    476	ret = mipi_dsi_attach(dsi);
    477	if (ret < 0) {
    478		jdi_panel_del(jdi);
    479		return ret;
    480	}
    481
    482	return 0;
    483}
    484
    485static int jdi_panel_remove(struct mipi_dsi_device *dsi)
    486{
    487	struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
    488	int ret;
    489
    490	ret = jdi_panel_disable(&jdi->base);
    491	if (ret < 0)
    492		dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
    493
    494	ret = mipi_dsi_detach(dsi);
    495	if (ret < 0)
    496		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
    497			ret);
    498
    499	jdi_panel_del(jdi);
    500
    501	return 0;
    502}
    503
    504static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
    505{
    506	struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
    507
    508	jdi_panel_disable(&jdi->base);
    509}
    510
    511static struct mipi_dsi_driver jdi_panel_driver = {
    512	.driver = {
    513		.name = "panel-jdi-lt070me05000",
    514		.of_match_table = jdi_of_match,
    515	},
    516	.probe = jdi_panel_probe,
    517	.remove = jdi_panel_remove,
    518	.shutdown = jdi_panel_shutdown,
    519};
    520module_mipi_dsi_driver(jdi_panel_driver);
    521
    522MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
    523MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
    524MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
    525MODULE_LICENSE("GPL v2");