Linux Audio

Check our new training course

Loading...
v4.6
   1/*
   2 * Copyright (C) 2013, NVIDIA Corporation.  All rights reserved.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the
  12 * next paragraph) shall be included in all copies or substantial portions
  13 * of the Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21 * DEALINGS IN THE SOFTWARE.
  22 */
  23
  24#include <linux/backlight.h>
  25#include <linux/gpio/consumer.h>
  26#include <linux/module.h>
  27#include <linux/of_platform.h>
  28#include <linux/platform_device.h>
  29#include <linux/regulator/consumer.h>
  30
  31#include <drm/drmP.h>
  32#include <drm/drm_crtc.h>
  33#include <drm/drm_mipi_dsi.h>
  34#include <drm/drm_panel.h>
  35
  36#include <video/display_timing.h>
  37#include <video/videomode.h>
  38
  39struct panel_desc {
  40	const struct drm_display_mode *modes;
  41	unsigned int num_modes;
  42	const struct display_timing *timings;
  43	unsigned int num_timings;
  44
  45	unsigned int bpc;
  46
  47	/**
  48	 * @width: width (in millimeters) of the panel's active display area
  49	 * @height: height (in millimeters) of the panel's active display area
  50	 */
  51	struct {
  52		unsigned int width;
  53		unsigned int height;
  54	} size;
  55
  56	/**
  57	 * @prepare: the time (in milliseconds) that it takes for the panel to
  58	 *           become ready and start receiving video data
  59	 * @enable: the time (in milliseconds) that it takes for the panel to
  60	 *          display the first valid frame after starting to receive
  61	 *          video data
  62	 * @disable: the time (in milliseconds) that it takes for the panel to
  63	 *           turn the display off (no content is visible)
  64	 * @unprepare: the time (in milliseconds) that it takes for the panel
  65	 *             to power itself down completely
  66	 */
  67	struct {
  68		unsigned int prepare;
  69		unsigned int enable;
  70		unsigned int disable;
  71		unsigned int unprepare;
  72	} delay;
  73
  74	u32 bus_format;
  75};
  76
  77struct panel_simple {
  78	struct drm_panel base;
  79	bool prepared;
  80	bool enabled;
  81
  82	const struct panel_desc *desc;
  83
  84	struct backlight_device *backlight;
  85	struct regulator *supply;
  86	struct i2c_adapter *ddc;
  87
  88	struct gpio_desc *enable_gpio;
  89};
  90
  91static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
  92{
  93	return container_of(panel, struct panel_simple, base);
  94}
  95
  96static int panel_simple_get_fixed_modes(struct panel_simple *panel)
  97{
  98	struct drm_connector *connector = panel->base.connector;
  99	struct drm_device *drm = panel->base.drm;
 100	struct drm_display_mode *mode;
 101	unsigned int i, num = 0;
 102
 103	if (!panel->desc)
 104		return 0;
 105
 106	for (i = 0; i < panel->desc->num_timings; i++) {
 107		const struct display_timing *dt = &panel->desc->timings[i];
 108		struct videomode vm;
 109
 110		videomode_from_timing(dt, &vm);
 111		mode = drm_mode_create(drm);
 112		if (!mode) {
 113			dev_err(drm->dev, "failed to add mode %ux%u\n",
 114				dt->hactive.typ, dt->vactive.typ);
 115			continue;
 116		}
 117
 118		drm_display_mode_from_videomode(&vm, mode);
 119		drm_mode_set_name(mode);
 120
 121		drm_mode_probed_add(connector, mode);
 122		num++;
 123	}
 124
 125	for (i = 0; i < panel->desc->num_modes; i++) {
 126		const struct drm_display_mode *m = &panel->desc->modes[i];
 127
 128		mode = drm_mode_duplicate(drm, m);
 129		if (!mode) {
 130			dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
 131				m->hdisplay, m->vdisplay, m->vrefresh);
 132			continue;
 133		}
 134
 135		drm_mode_set_name(mode);
 136
 137		drm_mode_probed_add(connector, mode);
 138		num++;
 139	}
 140
 141	connector->display_info.bpc = panel->desc->bpc;
 142	connector->display_info.width_mm = panel->desc->size.width;
 143	connector->display_info.height_mm = panel->desc->size.height;
 144	if (panel->desc->bus_format)
 145		drm_display_info_set_bus_formats(&connector->display_info,
 146						 &panel->desc->bus_format, 1);
 147
 148	return num;
 149}
 150
 151static int panel_simple_disable(struct drm_panel *panel)
 152{
 153	struct panel_simple *p = to_panel_simple(panel);
 154
 155	if (!p->enabled)
 156		return 0;
 157
 158	if (p->backlight) {
 159		p->backlight->props.power = FB_BLANK_POWERDOWN;
 160		backlight_update_status(p->backlight);
 161	}
 162
 163	if (p->desc->delay.disable)
 164		msleep(p->desc->delay.disable);
 165
 166	p->enabled = false;
 167
 168	return 0;
 169}
 170
 171static int panel_simple_unprepare(struct drm_panel *panel)
 172{
 173	struct panel_simple *p = to_panel_simple(panel);
 174
 175	if (!p->prepared)
 176		return 0;
 177
 178	if (p->enable_gpio)
 179		gpiod_set_value_cansleep(p->enable_gpio, 0);
 180
 181	regulator_disable(p->supply);
 182
 183	if (p->desc->delay.unprepare)
 184		msleep(p->desc->delay.unprepare);
 185
 186	p->prepared = false;
 187
 188	return 0;
 189}
 190
 191static int panel_simple_prepare(struct drm_panel *panel)
 192{
 193	struct panel_simple *p = to_panel_simple(panel);
 194	int err;
 195
 196	if (p->prepared)
 197		return 0;
 198
 199	err = regulator_enable(p->supply);
 200	if (err < 0) {
 201		dev_err(panel->dev, "failed to enable supply: %d\n", err);
 202		return err;
 203	}
 204
 205	if (p->enable_gpio)
 206		gpiod_set_value_cansleep(p->enable_gpio, 1);
 207
 208	if (p->desc->delay.prepare)
 209		msleep(p->desc->delay.prepare);
 210
 211	p->prepared = true;
 212
 213	return 0;
 214}
 215
 216static int panel_simple_enable(struct drm_panel *panel)
 217{
 218	struct panel_simple *p = to_panel_simple(panel);
 219
 220	if (p->enabled)
 221		return 0;
 222
 223	if (p->desc->delay.enable)
 224		msleep(p->desc->delay.enable);
 225
 226	if (p->backlight) {
 227		p->backlight->props.power = FB_BLANK_UNBLANK;
 228		backlight_update_status(p->backlight);
 229	}
 230
 231	p->enabled = true;
 232
 233	return 0;
 234}
 235
 236static int panel_simple_get_modes(struct drm_panel *panel)
 237{
 238	struct panel_simple *p = to_panel_simple(panel);
 239	int num = 0;
 240
 241	/* probe EDID if a DDC bus is available */
 242	if (p->ddc) {
 243		struct edid *edid = drm_get_edid(panel->connector, p->ddc);
 244		drm_mode_connector_update_edid_property(panel->connector, edid);
 245		if (edid) {
 246			num += drm_add_edid_modes(panel->connector, edid);
 247			kfree(edid);
 248		}
 249	}
 250
 251	/* add hard-coded panel modes */
 252	num += panel_simple_get_fixed_modes(p);
 253
 254	return num;
 255}
 256
 257static int panel_simple_get_timings(struct drm_panel *panel,
 258				    unsigned int num_timings,
 259				    struct display_timing *timings)
 260{
 261	struct panel_simple *p = to_panel_simple(panel);
 262	unsigned int i;
 263
 264	if (p->desc->num_timings < num_timings)
 265		num_timings = p->desc->num_timings;
 266
 267	if (timings)
 268		for (i = 0; i < num_timings; i++)
 269			timings[i] = p->desc->timings[i];
 270
 271	return p->desc->num_timings;
 272}
 273
 274static const struct drm_panel_funcs panel_simple_funcs = {
 275	.disable = panel_simple_disable,
 276	.unprepare = panel_simple_unprepare,
 277	.prepare = panel_simple_prepare,
 278	.enable = panel_simple_enable,
 279	.get_modes = panel_simple_get_modes,
 280	.get_timings = panel_simple_get_timings,
 281};
 282
 283static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 284{
 285	struct device_node *backlight, *ddc;
 286	struct panel_simple *panel;
 287	int err;
 288
 289	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
 290	if (!panel)
 291		return -ENOMEM;
 292
 293	panel->enabled = false;
 294	panel->prepared = false;
 295	panel->desc = desc;
 296
 297	panel->supply = devm_regulator_get(dev, "power");
 298	if (IS_ERR(panel->supply))
 299		return PTR_ERR(panel->supply);
 300
 301	panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
 302						     GPIOD_OUT_LOW);
 303	if (IS_ERR(panel->enable_gpio)) {
 304		err = PTR_ERR(panel->enable_gpio);
 305		dev_err(dev, "failed to request GPIO: %d\n", err);
 306		return err;
 
 
 
 
 
 
 
 
 
 
 307	}
 308
 309	backlight = of_parse_phandle(dev->of_node, "backlight", 0);
 310	if (backlight) {
 311		panel->backlight = of_find_backlight_by_node(backlight);
 312		of_node_put(backlight);
 313
 314		if (!panel->backlight)
 315			return -EPROBE_DEFER;
 316	}
 317
 318	ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
 319	if (ddc) {
 320		panel->ddc = of_find_i2c_adapter_by_node(ddc);
 321		of_node_put(ddc);
 322
 323		if (!panel->ddc) {
 324			err = -EPROBE_DEFER;
 325			goto free_backlight;
 326		}
 327	}
 328
 329	drm_panel_init(&panel->base);
 330	panel->base.dev = dev;
 331	panel->base.funcs = &panel_simple_funcs;
 332
 333	err = drm_panel_add(&panel->base);
 334	if (err < 0)
 335		goto free_ddc;
 336
 337	dev_set_drvdata(dev, panel);
 338
 339	return 0;
 340
 341free_ddc:
 342	if (panel->ddc)
 343		put_device(&panel->ddc->dev);
 344free_backlight:
 345	if (panel->backlight)
 346		put_device(&panel->backlight->dev);
 347
 348	return err;
 349}
 350
 351static int panel_simple_remove(struct device *dev)
 352{
 353	struct panel_simple *panel = dev_get_drvdata(dev);
 354
 355	drm_panel_detach(&panel->base);
 356	drm_panel_remove(&panel->base);
 357
 358	panel_simple_disable(&panel->base);
 359
 360	if (panel->ddc)
 361		put_device(&panel->ddc->dev);
 362
 363	if (panel->backlight)
 364		put_device(&panel->backlight->dev);
 365
 366	return 0;
 367}
 368
 369static void panel_simple_shutdown(struct device *dev)
 370{
 371	struct panel_simple *panel = dev_get_drvdata(dev);
 372
 373	panel_simple_disable(&panel->base);
 374}
 375
 376static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = {
 377	.clock = 33333,
 378	.hdisplay = 800,
 379	.hsync_start = 800 + 0,
 380	.hsync_end = 800 + 0 + 255,
 381	.htotal = 800 + 0 + 255 + 0,
 382	.vdisplay = 480,
 383	.vsync_start = 480 + 2,
 384	.vsync_end = 480 + 2 + 45,
 385	.vtotal = 480 + 2 + 45 + 0,
 386	.vrefresh = 60,
 387	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
 388};
 389
 390static const struct panel_desc ampire_am800480r3tmqwa1h = {
 391	.modes = &ampire_am800480r3tmqwa1h_mode,
 392	.num_modes = 1,
 393	.bpc = 6,
 394	.size = {
 395		.width = 152,
 396		.height = 91,
 397	},
 398	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
 399};
 400
 401static const struct drm_display_mode auo_b101aw03_mode = {
 402	.clock = 51450,
 403	.hdisplay = 1024,
 404	.hsync_start = 1024 + 156,
 405	.hsync_end = 1024 + 156 + 8,
 406	.htotal = 1024 + 156 + 8 + 156,
 407	.vdisplay = 600,
 408	.vsync_start = 600 + 16,
 409	.vsync_end = 600 + 16 + 6,
 410	.vtotal = 600 + 16 + 6 + 16,
 411	.vrefresh = 60,
 412};
 413
 414static const struct panel_desc auo_b101aw03 = {
 415	.modes = &auo_b101aw03_mode,
 416	.num_modes = 1,
 417	.bpc = 6,
 418	.size = {
 419		.width = 223,
 420		.height = 125,
 421	},
 422};
 423
 424static const struct drm_display_mode auo_b101ean01_mode = {
 425	.clock = 72500,
 426	.hdisplay = 1280,
 427	.hsync_start = 1280 + 119,
 428	.hsync_end = 1280 + 119 + 32,
 429	.htotal = 1280 + 119 + 32 + 21,
 430	.vdisplay = 800,
 431	.vsync_start = 800 + 4,
 432	.vsync_end = 800 + 4 + 20,
 433	.vtotal = 800 + 4 + 20 + 8,
 434	.vrefresh = 60,
 435};
 436
 437static const struct panel_desc auo_b101ean01 = {
 438	.modes = &auo_b101ean01_mode,
 439	.num_modes = 1,
 440	.bpc = 6,
 441	.size = {
 442		.width = 217,
 443		.height = 136,
 444	},
 445};
 446
 447static const struct drm_display_mode auo_b101xtn01_mode = {
 448	.clock = 72000,
 449	.hdisplay = 1366,
 450	.hsync_start = 1366 + 20,
 451	.hsync_end = 1366 + 20 + 70,
 452	.htotal = 1366 + 20 + 70,
 453	.vdisplay = 768,
 454	.vsync_start = 768 + 14,
 455	.vsync_end = 768 + 14 + 42,
 456	.vtotal = 768 + 14 + 42,
 457	.vrefresh = 60,
 458	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
 459};
 460
 461static const struct panel_desc auo_b101xtn01 = {
 462	.modes = &auo_b101xtn01_mode,
 463	.num_modes = 1,
 464	.bpc = 6,
 465	.size = {
 466		.width = 223,
 467		.height = 125,
 468	},
 469};
 470
 471static const struct drm_display_mode auo_b116xw03_mode = {
 472	.clock = 70589,
 473	.hdisplay = 1366,
 474	.hsync_start = 1366 + 40,
 475	.hsync_end = 1366 + 40 + 40,
 476	.htotal = 1366 + 40 + 40 + 32,
 477	.vdisplay = 768,
 478	.vsync_start = 768 + 10,
 479	.vsync_end = 768 + 10 + 12,
 480	.vtotal = 768 + 10 + 12 + 6,
 481	.vrefresh = 60,
 482};
 483
 484static const struct panel_desc auo_b116xw03 = {
 485	.modes = &auo_b116xw03_mode,
 486	.num_modes = 1,
 487	.bpc = 6,
 488	.size = {
 489		.width = 256,
 490		.height = 144,
 491	},
 492};
 493
 494static const struct drm_display_mode auo_b133xtn01_mode = {
 495	.clock = 69500,
 496	.hdisplay = 1366,
 497	.hsync_start = 1366 + 48,
 498	.hsync_end = 1366 + 48 + 32,
 499	.htotal = 1366 + 48 + 32 + 20,
 500	.vdisplay = 768,
 501	.vsync_start = 768 + 3,
 502	.vsync_end = 768 + 3 + 6,
 503	.vtotal = 768 + 3 + 6 + 13,
 504	.vrefresh = 60,
 505};
 506
 507static const struct panel_desc auo_b133xtn01 = {
 508	.modes = &auo_b133xtn01_mode,
 509	.num_modes = 1,
 510	.bpc = 6,
 511	.size = {
 512		.width = 293,
 513		.height = 165,
 514	},
 515};
 516
 517static const struct drm_display_mode auo_b133htn01_mode = {
 518	.clock = 150660,
 519	.hdisplay = 1920,
 520	.hsync_start = 1920 + 172,
 521	.hsync_end = 1920 + 172 + 80,
 522	.htotal = 1920 + 172 + 80 + 60,
 523	.vdisplay = 1080,
 524	.vsync_start = 1080 + 25,
 525	.vsync_end = 1080 + 25 + 10,
 526	.vtotal = 1080 + 25 + 10 + 10,
 527	.vrefresh = 60,
 528};
 529
 530static const struct panel_desc auo_b133htn01 = {
 531	.modes = &auo_b133htn01_mode,
 532	.num_modes = 1,
 533	.bpc = 6,
 534	.size = {
 535		.width = 293,
 536		.height = 165,
 537	},
 538	.delay = {
 539		.prepare = 105,
 540		.enable = 20,
 541		.unprepare = 50,
 542	},
 543};
 544
 545static const struct drm_display_mode avic_tm070ddh03_mode = {
 546	.clock = 51200,
 547	.hdisplay = 1024,
 548	.hsync_start = 1024 + 160,
 549	.hsync_end = 1024 + 160 + 4,
 550	.htotal = 1024 + 160 + 4 + 156,
 551	.vdisplay = 600,
 552	.vsync_start = 600 + 17,
 553	.vsync_end = 600 + 17 + 1,
 554	.vtotal = 600 + 17 + 1 + 17,
 555	.vrefresh = 60,
 556};
 557
 558static const struct panel_desc avic_tm070ddh03 = {
 559	.modes = &avic_tm070ddh03_mode,
 560	.num_modes = 1,
 561	.bpc = 8,
 562	.size = {
 563		.width = 154,
 564		.height = 90,
 565	},
 566	.delay = {
 567		.prepare = 20,
 568		.enable = 200,
 569		.disable = 200,
 570	},
 571};
 572
 573static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
 574	.clock = 72070,
 575	.hdisplay = 1366,
 576	.hsync_start = 1366 + 58,
 577	.hsync_end = 1366 + 58 + 58,
 578	.htotal = 1366 + 58 + 58 + 58,
 579	.vdisplay = 768,
 580	.vsync_start = 768 + 4,
 581	.vsync_end = 768 + 4 + 4,
 582	.vtotal = 768 + 4 + 4 + 4,
 583	.vrefresh = 60,
 584};
 585
 586static const struct panel_desc chunghwa_claa101wa01a = {
 587	.modes = &chunghwa_claa101wa01a_mode,
 588	.num_modes = 1,
 589	.bpc = 6,
 590	.size = {
 591		.width = 220,
 592		.height = 120,
 593	},
 594};
 595
 596static const struct drm_display_mode chunghwa_claa101wb01_mode = {
 597	.clock = 69300,
 598	.hdisplay = 1366,
 599	.hsync_start = 1366 + 48,
 600	.hsync_end = 1366 + 48 + 32,
 601	.htotal = 1366 + 48 + 32 + 20,
 602	.vdisplay = 768,
 603	.vsync_start = 768 + 16,
 604	.vsync_end = 768 + 16 + 8,
 605	.vtotal = 768 + 16 + 8 + 16,
 606	.vrefresh = 60,
 607};
 608
 609static const struct panel_desc chunghwa_claa101wb01 = {
 610	.modes = &chunghwa_claa101wb01_mode,
 611	.num_modes = 1,
 612	.bpc = 6,
 613	.size = {
 614		.width = 223,
 615		.height = 125,
 616	},
 617};
 618
 619static const struct drm_display_mode edt_et057090dhu_mode = {
 620	.clock = 25175,
 621	.hdisplay = 640,
 622	.hsync_start = 640 + 16,
 623	.hsync_end = 640 + 16 + 30,
 624	.htotal = 640 + 16 + 30 + 114,
 625	.vdisplay = 480,
 626	.vsync_start = 480 + 10,
 627	.vsync_end = 480 + 10 + 3,
 628	.vtotal = 480 + 10 + 3 + 32,
 629	.vrefresh = 60,
 630	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
 631};
 632
 633static const struct panel_desc edt_et057090dhu = {
 634	.modes = &edt_et057090dhu_mode,
 635	.num_modes = 1,
 636	.bpc = 6,
 637	.size = {
 638		.width = 115,
 639		.height = 86,
 640	},
 641};
 642
 643static const struct drm_display_mode edt_etm0700g0dh6_mode = {
 644	.clock = 33260,
 645	.hdisplay = 800,
 646	.hsync_start = 800 + 40,
 647	.hsync_end = 800 + 40 + 128,
 648	.htotal = 800 + 40 + 128 + 88,
 649	.vdisplay = 480,
 650	.vsync_start = 480 + 10,
 651	.vsync_end = 480 + 10 + 2,
 652	.vtotal = 480 + 10 + 2 + 33,
 653	.vrefresh = 60,
 654	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 655};
 656
 657static const struct panel_desc edt_etm0700g0dh6 = {
 658	.modes = &edt_etm0700g0dh6_mode,
 659	.num_modes = 1,
 660	.bpc = 6,
 661	.size = {
 662		.width = 152,
 663		.height = 91,
 664	},
 665};
 666
 667static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
 668	.clock = 32260,
 669	.hdisplay = 800,
 670	.hsync_start = 800 + 168,
 671	.hsync_end = 800 + 168 + 64,
 672	.htotal = 800 + 168 + 64 + 88,
 673	.vdisplay = 480,
 674	.vsync_start = 480 + 37,
 675	.vsync_end = 480 + 37 + 2,
 676	.vtotal = 480 + 37 + 2 + 8,
 677	.vrefresh = 60,
 678};
 679
 680static const struct panel_desc foxlink_fl500wvr00_a0t = {
 681	.modes = &foxlink_fl500wvr00_a0t_mode,
 682	.num_modes = 1,
 683	.bpc = 8,
 684	.size = {
 685		.width = 108,
 686		.height = 65,
 687	},
 688	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 689};
 690
 691static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
 692	.clock = 9000,
 693	.hdisplay = 480,
 694	.hsync_start = 480 + 5,
 695	.hsync_end = 480 + 5 + 1,
 696	.htotal = 480 + 5 + 1 + 40,
 697	.vdisplay = 272,
 698	.vsync_start = 272 + 8,
 699	.vsync_end = 272 + 8 + 1,
 700	.vtotal = 272 + 8 + 1 + 8,
 701	.vrefresh = 60,
 702};
 703
 704static const struct panel_desc giantplus_gpg482739qs5 = {
 705	.modes = &giantplus_gpg482739qs5_mode,
 706	.num_modes = 1,
 707	.bpc = 8,
 708	.size = {
 709		.width = 95,
 710		.height = 54,
 711	},
 712	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 713};
 714
 715static const struct display_timing hannstar_hsd070pww1_timing = {
 716	.pixelclock = { 64300000, 71100000, 82000000 },
 717	.hactive = { 1280, 1280, 1280 },
 718	.hfront_porch = { 1, 1, 10 },
 719	.hback_porch = { 1, 1, 10 },
 720	/*
 721	 * According to the data sheet, the minimum horizontal blanking interval
 722	 * is 54 clocks (1 + 52 + 1), but tests with a Nitrogen6X have shown the
 723	 * minimum working horizontal blanking interval to be 60 clocks.
 724	 */
 725	.hsync_len = { 58, 158, 661 },
 726	.vactive = { 800, 800, 800 },
 727	.vfront_porch = { 1, 1, 10 },
 728	.vback_porch = { 1, 1, 10 },
 729	.vsync_len = { 1, 21, 203 },
 730	.flags = DISPLAY_FLAGS_DE_HIGH,
 731};
 732
 733static const struct panel_desc hannstar_hsd070pww1 = {
 734	.timings = &hannstar_hsd070pww1_timing,
 735	.num_timings = 1,
 736	.bpc = 6,
 737	.size = {
 738		.width = 151,
 739		.height = 94,
 740	},
 741	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
 742};
 743
 744static const struct display_timing hannstar_hsd100pxn1_timing = {
 745	.pixelclock = { 55000000, 65000000, 75000000 },
 746	.hactive = { 1024, 1024, 1024 },
 747	.hfront_porch = { 40, 40, 40 },
 748	.hback_porch = { 220, 220, 220 },
 749	.hsync_len = { 20, 60, 100 },
 750	.vactive = { 768, 768, 768 },
 751	.vfront_porch = { 7, 7, 7 },
 752	.vback_porch = { 21, 21, 21 },
 753	.vsync_len = { 10, 10, 10 },
 754	.flags = DISPLAY_FLAGS_DE_HIGH,
 755};
 756
 757static const struct panel_desc hannstar_hsd100pxn1 = {
 758	.timings = &hannstar_hsd100pxn1_timing,
 759	.num_timings = 1,
 760	.bpc = 6,
 761	.size = {
 762		.width = 203,
 763		.height = 152,
 764	},
 765	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
 766};
 767
 768static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
 769	.clock = 33333,
 770	.hdisplay = 800,
 771	.hsync_start = 800 + 85,
 772	.hsync_end = 800 + 85 + 86,
 773	.htotal = 800 + 85 + 86 + 85,
 774	.vdisplay = 480,
 775	.vsync_start = 480 + 16,
 776	.vsync_end = 480 + 16 + 13,
 777	.vtotal = 480 + 16 + 13 + 16,
 778	.vrefresh = 60,
 779};
 780
 781static const struct panel_desc hitachi_tx23d38vm0caa = {
 782	.modes = &hitachi_tx23d38vm0caa_mode,
 783	.num_modes = 1,
 784	.bpc = 6,
 785	.size = {
 786		.width = 195,
 787		.height = 117,
 788	},
 789};
 790
 791static const struct drm_display_mode innolux_at043tn24_mode = {
 792	.clock = 9000,
 793	.hdisplay = 480,
 794	.hsync_start = 480 + 2,
 795	.hsync_end = 480 + 2 + 41,
 796	.htotal = 480 + 2 + 41 + 2,
 797	.vdisplay = 272,
 798	.vsync_start = 272 + 2,
 799	.vsync_end = 272 + 2 + 11,
 800	.vtotal = 272 + 2 + 11 + 2,
 801	.vrefresh = 60,
 802	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 803};
 804
 805static const struct panel_desc innolux_at043tn24 = {
 806	.modes = &innolux_at043tn24_mode,
 807	.num_modes = 1,
 808	.bpc = 8,
 809	.size = {
 810		.width = 95,
 811		.height = 54,
 812	},
 813	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
 814};
 815
 816static const struct drm_display_mode innolux_g121i1_l01_mode = {
 817	.clock = 71000,
 818	.hdisplay = 1280,
 819	.hsync_start = 1280 + 64,
 820	.hsync_end = 1280 + 64 + 32,
 821	.htotal = 1280 + 64 + 32 + 64,
 822	.vdisplay = 800,
 823	.vsync_start = 800 + 9,
 824	.vsync_end = 800 + 9 + 6,
 825	.vtotal = 800 + 9 + 6 + 9,
 826	.vrefresh = 60,
 827};
 828
 829static const struct panel_desc innolux_g121i1_l01 = {
 830	.modes = &innolux_g121i1_l01_mode,
 831	.num_modes = 1,
 832	.bpc = 6,
 833	.size = {
 834		.width = 261,
 835		.height = 163,
 836	},
 837};
 838
 839static const struct drm_display_mode innolux_g121x1_l03_mode = {
 840	.clock = 65000,
 841	.hdisplay = 1024,
 842	.hsync_start = 1024 + 0,
 843	.hsync_end = 1024 + 1,
 844	.htotal = 1024 + 0 + 1 + 320,
 845	.vdisplay = 768,
 846	.vsync_start = 768 + 38,
 847	.vsync_end = 768 + 38 + 1,
 848	.vtotal = 768 + 38 + 1 + 0,
 849	.vrefresh = 60,
 850	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 851};
 852
 853static const struct panel_desc innolux_g121x1_l03 = {
 854	.modes = &innolux_g121x1_l03_mode,
 855	.num_modes = 1,
 856	.bpc = 6,
 857	.size = {
 858		.width = 246,
 859		.height = 185,
 860	},
 861	.delay = {
 862		.enable = 200,
 863		.unprepare = 200,
 864		.disable = 400,
 865	},
 866};
 867
 868static const struct drm_display_mode innolux_n116bge_mode = {
 869	.clock = 76420,
 870	.hdisplay = 1366,
 871	.hsync_start = 1366 + 136,
 872	.hsync_end = 1366 + 136 + 30,
 873	.htotal = 1366 + 136 + 30 + 60,
 874	.vdisplay = 768,
 875	.vsync_start = 768 + 8,
 876	.vsync_end = 768 + 8 + 12,
 877	.vtotal = 768 + 8 + 12 + 12,
 878	.vrefresh = 60,
 879	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 880};
 881
 882static const struct panel_desc innolux_n116bge = {
 883	.modes = &innolux_n116bge_mode,
 884	.num_modes = 1,
 885	.bpc = 6,
 886	.size = {
 887		.width = 256,
 888		.height = 144,
 889	},
 890};
 891
 892static const struct drm_display_mode innolux_n156bge_l21_mode = {
 893	.clock = 69300,
 894	.hdisplay = 1366,
 895	.hsync_start = 1366 + 16,
 896	.hsync_end = 1366 + 16 + 34,
 897	.htotal = 1366 + 16 + 34 + 50,
 898	.vdisplay = 768,
 899	.vsync_start = 768 + 2,
 900	.vsync_end = 768 + 2 + 6,
 901	.vtotal = 768 + 2 + 6 + 12,
 902	.vrefresh = 60,
 903};
 904
 905static const struct panel_desc innolux_n156bge_l21 = {
 906	.modes = &innolux_n156bge_l21_mode,
 907	.num_modes = 1,
 908	.bpc = 6,
 909	.size = {
 910		.width = 344,
 911		.height = 193,
 912	},
 913};
 914
 915static const struct drm_display_mode innolux_zj070na_01p_mode = {
 916	.clock = 51501,
 917	.hdisplay = 1024,
 918	.hsync_start = 1024 + 128,
 919	.hsync_end = 1024 + 128 + 64,
 920	.htotal = 1024 + 128 + 64 + 128,
 921	.vdisplay = 600,
 922	.vsync_start = 600 + 16,
 923	.vsync_end = 600 + 16 + 4,
 924	.vtotal = 600 + 16 + 4 + 16,
 925	.vrefresh = 60,
 926};
 927
 928static const struct panel_desc innolux_zj070na_01p = {
 929	.modes = &innolux_zj070na_01p_mode,
 930	.num_modes = 1,
 931	.bpc = 6,
 932	.size = {
 933		.width = 1024,
 934		.height = 600,
 935	},
 936};
 937
 938static const struct display_timing kyo_tcg121xglp_timing = {
 939	.pixelclock = { 52000000, 65000000, 71000000 },
 940	.hactive = { 1024, 1024, 1024 },
 941	.hfront_porch = { 2, 2, 2 },
 942	.hback_porch = { 2, 2, 2 },
 943	.hsync_len = { 86, 124, 244 },
 944	.vactive = { 768, 768, 768 },
 945	.vfront_porch = { 2, 2, 2 },
 946	.vback_porch = { 2, 2, 2 },
 947	.vsync_len = { 6, 34, 73 },
 948	.flags = DISPLAY_FLAGS_DE_HIGH,
 949};
 950
 951static const struct panel_desc kyo_tcg121xglp = {
 952	.timings = &kyo_tcg121xglp_timing,
 953	.num_timings = 1,
 954	.bpc = 8,
 955	.size = {
 956		.width = 246,
 957		.height = 184,
 958	},
 959	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
 960};
 961
 962static const struct drm_display_mode lg_lb070wv8_mode = {
 963	.clock = 33246,
 964	.hdisplay = 800,
 965	.hsync_start = 800 + 88,
 966	.hsync_end = 800 + 88 + 80,
 967	.htotal = 800 + 88 + 80 + 88,
 968	.vdisplay = 480,
 969	.vsync_start = 480 + 10,
 970	.vsync_end = 480 + 10 + 25,
 971	.vtotal = 480 + 10 + 25 + 10,
 972	.vrefresh = 60,
 973};
 974
 975static const struct panel_desc lg_lb070wv8 = {
 976	.modes = &lg_lb070wv8_mode,
 977	.num_modes = 1,
 978	.bpc = 16,
 979	.size = {
 980		.width = 151,
 981		.height = 91,
 982	},
 983	.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
 984};
 985
 986static const struct drm_display_mode lg_lp120up1_mode = {
 987	.clock = 162300,
 988	.hdisplay = 1920,
 989	.hsync_start = 1920 + 40,
 990	.hsync_end = 1920 + 40 + 40,
 991	.htotal = 1920 + 40 + 40+ 80,
 992	.vdisplay = 1280,
 993	.vsync_start = 1280 + 4,
 994	.vsync_end = 1280 + 4 + 4,
 995	.vtotal = 1280 + 4 + 4 + 12,
 996	.vrefresh = 60,
 997};
 998
 999static const struct panel_desc lg_lp120up1 = {
1000	.modes = &lg_lp120up1_mode,
1001	.num_modes = 1,
1002	.bpc = 8,
1003	.size = {
1004		.width = 267,
1005		.height = 183,
1006	},
1007};
1008
1009static const struct drm_display_mode lg_lp129qe_mode = {
1010	.clock = 285250,
1011	.hdisplay = 2560,
1012	.hsync_start = 2560 + 48,
1013	.hsync_end = 2560 + 48 + 32,
1014	.htotal = 2560 + 48 + 32 + 80,
1015	.vdisplay = 1700,
1016	.vsync_start = 1700 + 3,
1017	.vsync_end = 1700 + 3 + 10,
1018	.vtotal = 1700 + 3 + 10 + 36,
1019	.vrefresh = 60,
1020};
1021
1022static const struct panel_desc lg_lp129qe = {
1023	.modes = &lg_lp129qe_mode,
1024	.num_modes = 1,
1025	.bpc = 8,
1026	.size = {
1027		.width = 272,
1028		.height = 181,
1029	},
1030};
1031
1032static const struct drm_display_mode nec_nl4827hc19_05b_mode = {
1033	.clock = 10870,
1034	.hdisplay = 480,
1035	.hsync_start = 480 + 2,
1036	.hsync_end = 480 + 2 + 41,
1037	.htotal = 480 + 2 + 41 + 2,
1038	.vdisplay = 272,
1039	.vsync_start = 272 + 2,
1040	.vsync_end = 272 + 2 + 4,
1041	.vtotal = 272 + 2 + 4 + 2,
1042	.vrefresh = 74,
1043	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
1044};
1045
1046static const struct panel_desc nec_nl4827hc19_05b = {
1047	.modes = &nec_nl4827hc19_05b_mode,
1048	.num_modes = 1,
1049	.bpc = 8,
1050	.size = {
1051		.width = 95,
1052		.height = 54,
1053	},
1054	.bus_format = MEDIA_BUS_FMT_RGB888_1X24
1055};
1056
1057static const struct display_timing okaya_rs800480t_7x0gp_timing = {
1058	.pixelclock = { 30000000, 30000000, 40000000 },
1059	.hactive = { 800, 800, 800 },
1060	.hfront_porch = { 40, 40, 40 },
1061	.hback_porch = { 40, 40, 40 },
1062	.hsync_len = { 1, 48, 48 },
1063	.vactive = { 480, 480, 480 },
1064	.vfront_porch = { 13, 13, 13 },
1065	.vback_porch = { 29, 29, 29 },
1066	.vsync_len = { 3, 3, 3 },
1067	.flags = DISPLAY_FLAGS_DE_HIGH,
1068};
1069
1070static const struct panel_desc okaya_rs800480t_7x0gp = {
1071	.timings = &okaya_rs800480t_7x0gp_timing,
1072	.num_timings = 1,
1073	.bpc = 6,
1074	.size = {
1075		.width = 154,
1076		.height = 87,
1077	},
1078	.delay = {
1079		.prepare = 41,
1080		.enable = 50,
1081		.unprepare = 41,
1082		.disable = 50,
1083	},
1084	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
1085};
1086
1087static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = {
1088	.clock = 25000,
1089	.hdisplay = 480,
1090	.hsync_start = 480 + 10,
1091	.hsync_end = 480 + 10 + 10,
1092	.htotal = 480 + 10 + 10 + 15,
1093	.vdisplay = 800,
1094	.vsync_start = 800 + 3,
1095	.vsync_end = 800 + 3 + 3,
1096	.vtotal = 800 + 3 + 3 + 3,
1097	.vrefresh = 60,
1098};
1099
1100static const struct panel_desc ortustech_com43h4m85ulc = {
1101	.modes = &ortustech_com43h4m85ulc_mode,
1102	.num_modes = 1,
1103	.bpc = 8,
1104	.size = {
1105		.width = 56,
1106		.height = 93,
1107	},
1108	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
1109};
1110
1111static const struct drm_display_mode qd43003c0_40_mode = {
1112	.clock = 9000,
1113	.hdisplay = 480,
1114	.hsync_start = 480 + 8,
1115	.hsync_end = 480 + 8 + 4,
1116	.htotal = 480 + 8 + 4 + 39,
1117	.vdisplay = 272,
1118	.vsync_start = 272 + 4,
1119	.vsync_end = 272 + 4 + 10,
1120	.vtotal = 272 + 4 + 10 + 2,
1121	.vrefresh = 60,
1122};
1123
1124static const struct panel_desc qd43003c0_40 = {
1125	.modes = &qd43003c0_40_mode,
1126	.num_modes = 1,
1127	.bpc = 8,
1128	.size = {
1129		.width = 95,
1130		.height = 53,
1131	},
1132	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
1133};
1134
1135static const struct drm_display_mode samsung_ltn101nt05_mode = {
1136	.clock = 54030,
1137	.hdisplay = 1024,
1138	.hsync_start = 1024 + 24,
1139	.hsync_end = 1024 + 24 + 136,
1140	.htotal = 1024 + 24 + 136 + 160,
1141	.vdisplay = 600,
1142	.vsync_start = 600 + 3,
1143	.vsync_end = 600 + 3 + 6,
1144	.vtotal = 600 + 3 + 6 + 61,
1145	.vrefresh = 60,
1146};
1147
1148static const struct panel_desc samsung_ltn101nt05 = {
1149	.modes = &samsung_ltn101nt05_mode,
1150	.num_modes = 1,
1151	.bpc = 6,
1152	.size = {
1153		.width = 1024,
1154		.height = 600,
1155	},
1156};
1157
1158static const struct drm_display_mode samsung_ltn140at29_301_mode = {
1159	.clock = 76300,
1160	.hdisplay = 1366,
1161	.hsync_start = 1366 + 64,
1162	.hsync_end = 1366 + 64 + 48,
1163	.htotal = 1366 + 64 + 48 + 128,
1164	.vdisplay = 768,
1165	.vsync_start = 768 + 2,
1166	.vsync_end = 768 + 2 + 5,
1167	.vtotal = 768 + 2 + 5 + 17,
1168	.vrefresh = 60,
1169};
1170
1171static const struct panel_desc samsung_ltn140at29_301 = {
1172	.modes = &samsung_ltn140at29_301_mode,
1173	.num_modes = 1,
1174	.bpc = 6,
1175	.size = {
1176		.width = 320,
1177		.height = 187,
1178	},
1179};
1180
1181static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = {
1182	.clock = 33300,
1183	.hdisplay = 800,
1184	.hsync_start = 800 + 1,
1185	.hsync_end = 800 + 1 + 64,
1186	.htotal = 800 + 1 + 64 + 64,
1187	.vdisplay = 480,
1188	.vsync_start = 480 + 1,
1189	.vsync_end = 480 + 1 + 23,
1190	.vtotal = 480 + 1 + 23 + 22,
1191	.vrefresh = 60,
1192};
1193
1194static const struct panel_desc shelly_sca07010_bfn_lnn = {
1195	.modes = &shelly_sca07010_bfn_lnn_mode,
1196	.num_modes = 1,
1197	.size = {
1198		.width = 152,
1199		.height = 91,
1200	},
1201	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
1202};
1203
1204static const struct display_timing urt_umsh_8596md_timing = {
1205	.pixelclock = { 33260000, 33260000, 33260000 },
1206	.hactive = { 800, 800, 800 },
1207	.hfront_porch = { 41, 41, 41 },
1208	.hback_porch = { 216 - 128, 216 - 128, 216 - 128 },
1209	.hsync_len = { 71, 128, 128 },
1210	.vactive = { 480, 480, 480 },
1211	.vfront_porch = { 10, 10, 10 },
1212	.vback_porch = { 35 - 2, 35 - 2, 35 - 2 },
1213	.vsync_len = { 2, 2, 2 },
1214	.flags = DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE |
1215		DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
1216};
1217
1218static const struct panel_desc urt_umsh_8596md_lvds = {
1219	.timings = &urt_umsh_8596md_timing,
1220	.num_timings = 1,
1221	.bpc = 6,
1222	.size = {
1223		.width = 152,
1224		.height = 91,
1225	},
1226	.bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
1227};
1228
1229static const struct panel_desc urt_umsh_8596md_parallel = {
1230	.timings = &urt_umsh_8596md_timing,
1231	.num_timings = 1,
1232	.bpc = 6,
1233	.size = {
1234		.width = 152,
1235		.height = 91,
1236	},
1237	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
1238};
1239
1240static const struct of_device_id platform_of_match[] = {
1241	{
1242		.compatible = "ampire,am800480r3tmqwa1h",
1243		.data = &ampire_am800480r3tmqwa1h,
1244	}, {
1245		.compatible = "auo,b101aw03",
1246		.data = &auo_b101aw03,
1247	}, {
1248		.compatible = "auo,b101ean01",
1249		.data = &auo_b101ean01,
1250	}, {
1251		.compatible = "auo,b101xtn01",
1252		.data = &auo_b101xtn01,
1253	}, {
1254		.compatible = "auo,b116xw03",
1255		.data = &auo_b116xw03,
1256	}, {
1257		.compatible = "auo,b133htn01",
1258		.data = &auo_b133htn01,
1259	}, {
1260		.compatible = "auo,b133xtn01",
1261		.data = &auo_b133xtn01,
1262	}, {
1263		.compatible = "avic,tm070ddh03",
1264		.data = &avic_tm070ddh03,
1265	}, {
1266		.compatible = "chunghwa,claa101wa01a",
1267		.data = &chunghwa_claa101wa01a
1268	}, {
1269		.compatible = "chunghwa,claa101wb01",
1270		.data = &chunghwa_claa101wb01
1271	}, {
1272		.compatible = "edt,et057090dhu",
1273		.data = &edt_et057090dhu,
1274	}, {
1275		.compatible = "edt,et070080dh6",
1276		.data = &edt_etm0700g0dh6,
1277	}, {
1278		.compatible = "edt,etm0700g0dh6",
1279		.data = &edt_etm0700g0dh6,
1280	}, {
1281		.compatible = "foxlink,fl500wvr00-a0t",
1282		.data = &foxlink_fl500wvr00_a0t,
1283	}, {
1284		.compatible = "giantplus,gpg482739qs5",
1285		.data = &giantplus_gpg482739qs5
1286	}, {
1287		.compatible = "hannstar,hsd070pww1",
1288		.data = &hannstar_hsd070pww1,
1289	}, {
1290		.compatible = "hannstar,hsd100pxn1",
1291		.data = &hannstar_hsd100pxn1,
1292	}, {
1293		.compatible = "hit,tx23d38vm0caa",
1294		.data = &hitachi_tx23d38vm0caa
1295	}, {
1296		.compatible = "innolux,at043tn24",
1297		.data = &innolux_at043tn24,
1298	}, {
1299		.compatible ="innolux,g121i1-l01",
1300		.data = &innolux_g121i1_l01
1301	}, {
1302		.compatible = "innolux,g121x1-l03",
1303		.data = &innolux_g121x1_l03,
1304	}, {
1305		.compatible = "innolux,n116bge",
1306		.data = &innolux_n116bge,
1307	}, {
1308		.compatible = "innolux,n156bge-l21",
1309		.data = &innolux_n156bge_l21,
1310	}, {
1311		.compatible = "innolux,zj070na-01p",
1312		.data = &innolux_zj070na_01p,
1313	}, {
1314		.compatible = "kyo,tcg121xglp",
1315		.data = &kyo_tcg121xglp,
1316	}, {
1317		.compatible = "lg,lb070wv8",
1318		.data = &lg_lb070wv8,
1319	}, {
1320		.compatible = "lg,lp120up1",
1321		.data = &lg_lp120up1,
1322	}, {
1323		.compatible = "lg,lp129qe",
1324		.data = &lg_lp129qe,
1325	}, {
1326		.compatible = "nec,nl4827hc19-05b",
1327		.data = &nec_nl4827hc19_05b,
1328	}, {
1329		.compatible = "okaya,rs800480t-7x0gp",
1330		.data = &okaya_rs800480t_7x0gp,
1331	}, {
1332		.compatible = "ortustech,com43h4m85ulc",
1333		.data = &ortustech_com43h4m85ulc,
1334	}, {
1335		.compatible = "qiaodian,qd43003c0-40",
1336		.data = &qd43003c0_40,
1337	}, {
1338		.compatible = "samsung,ltn101nt05",
1339		.data = &samsung_ltn101nt05,
1340	}, {
1341		.compatible = "samsung,ltn140at29-301",
1342		.data = &samsung_ltn140at29_301,
1343	}, {
1344		.compatible = "shelly,sca07010-bfn-lnn",
1345		.data = &shelly_sca07010_bfn_lnn,
1346	}, {
1347		.compatible = "urt,umsh-8596md-t",
1348		.data = &urt_umsh_8596md_parallel,
1349	}, {
1350		.compatible = "urt,umsh-8596md-1t",
1351		.data = &urt_umsh_8596md_parallel,
1352	}, {
1353		.compatible = "urt,umsh-8596md-7t",
1354		.data = &urt_umsh_8596md_parallel,
1355	}, {
1356		.compatible = "urt,umsh-8596md-11t",
1357		.data = &urt_umsh_8596md_lvds,
1358	}, {
1359		.compatible = "urt,umsh-8596md-19t",
1360		.data = &urt_umsh_8596md_lvds,
1361	}, {
1362		.compatible = "urt,umsh-8596md-20t",
1363		.data = &urt_umsh_8596md_parallel,
1364	}, {
1365		/* sentinel */
1366	}
1367};
1368MODULE_DEVICE_TABLE(of, platform_of_match);
1369
1370static int panel_simple_platform_probe(struct platform_device *pdev)
1371{
1372	const struct of_device_id *id;
1373
1374	id = of_match_node(platform_of_match, pdev->dev.of_node);
1375	if (!id)
1376		return -ENODEV;
1377
1378	return panel_simple_probe(&pdev->dev, id->data);
1379}
1380
1381static int panel_simple_platform_remove(struct platform_device *pdev)
1382{
1383	return panel_simple_remove(&pdev->dev);
1384}
1385
1386static void panel_simple_platform_shutdown(struct platform_device *pdev)
1387{
1388	panel_simple_shutdown(&pdev->dev);
1389}
1390
1391static struct platform_driver panel_simple_platform_driver = {
1392	.driver = {
1393		.name = "panel-simple",
 
1394		.of_match_table = platform_of_match,
1395	},
1396	.probe = panel_simple_platform_probe,
1397	.remove = panel_simple_platform_remove,
1398	.shutdown = panel_simple_platform_shutdown,
1399};
1400
1401struct panel_desc_dsi {
1402	struct panel_desc desc;
1403
1404	unsigned long flags;
1405	enum mipi_dsi_pixel_format format;
1406	unsigned int lanes;
1407};
1408
1409static const struct drm_display_mode auo_b080uan01_mode = {
1410	.clock = 154500,
1411	.hdisplay = 1200,
1412	.hsync_start = 1200 + 62,
1413	.hsync_end = 1200 + 62 + 4,
1414	.htotal = 1200 + 62 + 4 + 62,
1415	.vdisplay = 1920,
1416	.vsync_start = 1920 + 9,
1417	.vsync_end = 1920 + 9 + 2,
1418	.vtotal = 1920 + 9 + 2 + 8,
1419	.vrefresh = 60,
1420};
1421
1422static const struct panel_desc_dsi auo_b080uan01 = {
1423	.desc = {
1424		.modes = &auo_b080uan01_mode,
1425		.num_modes = 1,
1426		.bpc = 8,
1427		.size = {
1428			.width = 108,
1429			.height = 272,
1430		},
1431	},
1432	.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS,
1433	.format = MIPI_DSI_FMT_RGB888,
1434	.lanes = 4,
1435};
1436
1437static const struct drm_display_mode boe_tv080wum_nl0_mode = {
1438	.clock = 160000,
1439	.hdisplay = 1200,
1440	.hsync_start = 1200 + 120,
1441	.hsync_end = 1200 + 120 + 20,
1442	.htotal = 1200 + 120 + 20 + 21,
1443	.vdisplay = 1920,
1444	.vsync_start = 1920 + 21,
1445	.vsync_end = 1920 + 21 + 3,
1446	.vtotal = 1920 + 21 + 3 + 18,
1447	.vrefresh = 60,
1448	.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
1449};
1450
1451static const struct panel_desc_dsi boe_tv080wum_nl0 = {
1452	.desc = {
1453		.modes = &boe_tv080wum_nl0_mode,
1454		.num_modes = 1,
1455		.size = {
1456			.width = 107,
1457			.height = 172,
1458		},
1459	},
1460	.flags = MIPI_DSI_MODE_VIDEO |
1461		 MIPI_DSI_MODE_VIDEO_BURST |
1462		 MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
1463	.format = MIPI_DSI_FMT_RGB888,
1464	.lanes = 4,
1465};
1466
1467static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
1468	.clock = 71000,
1469	.hdisplay = 800,
1470	.hsync_start = 800 + 32,
1471	.hsync_end = 800 + 32 + 1,
1472	.htotal = 800 + 32 + 1 + 57,
1473	.vdisplay = 1280,
1474	.vsync_start = 1280 + 28,
1475	.vsync_end = 1280 + 28 + 1,
1476	.vtotal = 1280 + 28 + 1 + 14,
1477	.vrefresh = 60,
1478};
1479
1480static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
1481	.desc = {
1482		.modes = &lg_ld070wx3_sl01_mode,
1483		.num_modes = 1,
1484		.bpc = 8,
1485		.size = {
1486			.width = 94,
1487			.height = 151,
1488		},
1489	},
1490	.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS,
1491	.format = MIPI_DSI_FMT_RGB888,
1492	.lanes = 4,
1493};
1494
1495static const struct drm_display_mode lg_lh500wx1_sd03_mode = {
1496	.clock = 67000,
1497	.hdisplay = 720,
1498	.hsync_start = 720 + 12,
1499	.hsync_end = 720 + 12 + 4,
1500	.htotal = 720 + 12 + 4 + 112,
1501	.vdisplay = 1280,
1502	.vsync_start = 1280 + 8,
1503	.vsync_end = 1280 + 8 + 4,
1504	.vtotal = 1280 + 8 + 4 + 12,
1505	.vrefresh = 60,
1506};
1507
1508static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
1509	.desc = {
1510		.modes = &lg_lh500wx1_sd03_mode,
1511		.num_modes = 1,
1512		.bpc = 8,
1513		.size = {
1514			.width = 62,
1515			.height = 110,
1516		},
1517	},
1518	.flags = MIPI_DSI_MODE_VIDEO,
1519	.format = MIPI_DSI_FMT_RGB888,
1520	.lanes = 4,
1521};
1522
1523static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
1524	.clock = 157200,
1525	.hdisplay = 1920,
1526	.hsync_start = 1920 + 154,
1527	.hsync_end = 1920 + 154 + 16,
1528	.htotal = 1920 + 154 + 16 + 32,
1529	.vdisplay = 1200,
1530	.vsync_start = 1200 + 17,
1531	.vsync_end = 1200 + 17 + 2,
1532	.vtotal = 1200 + 17 + 2 + 16,
1533	.vrefresh = 60,
1534};
1535
1536static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
1537	.desc = {
1538		.modes = &panasonic_vvx10f004b00_mode,
1539		.num_modes = 1,
1540		.bpc = 8,
1541		.size = {
1542			.width = 217,
1543			.height = 136,
1544		},
1545	},
1546	.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
1547		 MIPI_DSI_CLOCK_NON_CONTINUOUS,
1548	.format = MIPI_DSI_FMT_RGB888,
1549	.lanes = 4,
1550};
1551
1552
1553static const struct of_device_id dsi_of_match[] = {
1554	{
1555		.compatible = "auo,b080uan01",
1556		.data = &auo_b080uan01
1557	}, {
1558		.compatible = "boe,tv080wum-nl0",
1559		.data = &boe_tv080wum_nl0
1560	}, {
1561		.compatible = "lg,ld070wx3-sl01",
1562		.data = &lg_ld070wx3_sl01
1563	}, {
1564		.compatible = "lg,lh500wx1-sd03",
1565		.data = &lg_lh500wx1_sd03
1566	}, {
1567		.compatible = "panasonic,vvx10f004b00",
1568		.data = &panasonic_vvx10f004b00
1569	}, {
1570		/* sentinel */
1571	}
1572};
1573MODULE_DEVICE_TABLE(of, dsi_of_match);
1574
1575static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
1576{
1577	const struct panel_desc_dsi *desc;
1578	const struct of_device_id *id;
1579	int err;
1580
1581	id = of_match_node(dsi_of_match, dsi->dev.of_node);
1582	if (!id)
1583		return -ENODEV;
1584
1585	desc = id->data;
1586
1587	err = panel_simple_probe(&dsi->dev, &desc->desc);
1588	if (err < 0)
1589		return err;
1590
1591	dsi->mode_flags = desc->flags;
1592	dsi->format = desc->format;
1593	dsi->lanes = desc->lanes;
1594
1595	return mipi_dsi_attach(dsi);
1596}
1597
1598static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
1599{
1600	int err;
1601
1602	err = mipi_dsi_detach(dsi);
1603	if (err < 0)
1604		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
1605
1606	return panel_simple_remove(&dsi->dev);
1607}
1608
1609static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi)
1610{
1611	panel_simple_shutdown(&dsi->dev);
1612}
1613
1614static struct mipi_dsi_driver panel_simple_dsi_driver = {
1615	.driver = {
1616		.name = "panel-simple-dsi",
 
1617		.of_match_table = dsi_of_match,
1618	},
1619	.probe = panel_simple_dsi_probe,
1620	.remove = panel_simple_dsi_remove,
1621	.shutdown = panel_simple_dsi_shutdown,
1622};
1623
1624static int __init panel_simple_init(void)
1625{
1626	int err;
1627
1628	err = platform_driver_register(&panel_simple_platform_driver);
1629	if (err < 0)
1630		return err;
1631
1632	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
1633		err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
1634		if (err < 0)
1635			return err;
1636	}
1637
1638	return 0;
1639}
1640module_init(panel_simple_init);
1641
1642static void __exit panel_simple_exit(void)
1643{
1644	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
1645		mipi_dsi_driver_unregister(&panel_simple_dsi_driver);
1646
1647	platform_driver_unregister(&panel_simple_platform_driver);
1648}
1649module_exit(panel_simple_exit);
1650
1651MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
1652MODULE_DESCRIPTION("DRM Driver for Simple Panels");
1653MODULE_LICENSE("GPL and additional rights");
v3.15
  1/*
  2 * Copyright (C) 2013, NVIDIA Corporation.  All rights reserved.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a
  5 * copy of this software and associated documentation files (the "Software"),
  6 * to deal in the Software without restriction, including without limitation
  7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
  8 * and/or sell copies of the Software, and to permit persons to whom the
  9 * Software is furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice (including the
 12 * next paragraph) shall be included in all copies or substantial portions
 13 * of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 21 * DEALINGS IN THE SOFTWARE.
 22 */
 23
 24#include <linux/backlight.h>
 25#include <linux/gpio/consumer.h>
 26#include <linux/module.h>
 27#include <linux/of_platform.h>
 28#include <linux/platform_device.h>
 29#include <linux/regulator/consumer.h>
 30
 31#include <drm/drmP.h>
 32#include <drm/drm_crtc.h>
 33#include <drm/drm_mipi_dsi.h>
 34#include <drm/drm_panel.h>
 35
 
 
 
 36struct panel_desc {
 37	const struct drm_display_mode *modes;
 38	unsigned int num_modes;
 
 
 
 
 39
 
 
 
 
 40	struct {
 41		unsigned int width;
 42		unsigned int height;
 43	} size;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 44};
 45
 46struct panel_simple {
 47	struct drm_panel base;
 
 48	bool enabled;
 49
 50	const struct panel_desc *desc;
 51
 52	struct backlight_device *backlight;
 53	struct regulator *supply;
 54	struct i2c_adapter *ddc;
 55
 56	struct gpio_desc *enable_gpio;
 57};
 58
 59static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
 60{
 61	return container_of(panel, struct panel_simple, base);
 62}
 63
 64static int panel_simple_get_fixed_modes(struct panel_simple *panel)
 65{
 66	struct drm_connector *connector = panel->base.connector;
 67	struct drm_device *drm = panel->base.drm;
 68	struct drm_display_mode *mode;
 69	unsigned int i, num = 0;
 70
 71	if (!panel->desc)
 72		return 0;
 73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 74	for (i = 0; i < panel->desc->num_modes; i++) {
 75		const struct drm_display_mode *m = &panel->desc->modes[i];
 76
 77		mode = drm_mode_duplicate(drm, m);
 78		if (!mode) {
 79			dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
 80				m->hdisplay, m->vdisplay, m->vrefresh);
 81			continue;
 82		}
 83
 84		drm_mode_set_name(mode);
 85
 86		drm_mode_probed_add(connector, mode);
 87		num++;
 88	}
 89
 
 90	connector->display_info.width_mm = panel->desc->size.width;
 91	connector->display_info.height_mm = panel->desc->size.height;
 
 
 
 92
 93	return num;
 94}
 95
 96static int panel_simple_disable(struct drm_panel *panel)
 97{
 98	struct panel_simple *p = to_panel_simple(panel);
 99
100	if (!p->enabled)
101		return 0;
102
103	if (p->backlight) {
104		p->backlight->props.power = FB_BLANK_POWERDOWN;
105		backlight_update_status(p->backlight);
106	}
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108	if (p->enable_gpio)
109		gpiod_set_value_cansleep(p->enable_gpio, 0);
110
111	regulator_disable(p->supply);
112	p->enabled = false;
 
 
 
 
113
114	return 0;
115}
116
117static int panel_simple_enable(struct drm_panel *panel)
118{
119	struct panel_simple *p = to_panel_simple(panel);
120	int err;
121
122	if (p->enabled)
123		return 0;
124
125	err = regulator_enable(p->supply);
126	if (err < 0) {
127		dev_err(panel->dev, "failed to enable supply: %d\n", err);
128		return err;
129	}
130
131	if (p->enable_gpio)
132		gpiod_set_value_cansleep(p->enable_gpio, 1);
133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134	if (p->backlight) {
135		p->backlight->props.power = FB_BLANK_UNBLANK;
136		backlight_update_status(p->backlight);
137	}
138
139	p->enabled = true;
140
141	return 0;
142}
143
144static int panel_simple_get_modes(struct drm_panel *panel)
145{
146	struct panel_simple *p = to_panel_simple(panel);
147	int num = 0;
148
149	/* probe EDID if a DDC bus is available */
150	if (p->ddc) {
151		struct edid *edid = drm_get_edid(panel->connector, p->ddc);
152		drm_mode_connector_update_edid_property(panel->connector, edid);
153		if (edid) {
154			num += drm_add_edid_modes(panel->connector, edid);
155			kfree(edid);
156		}
157	}
158
159	/* add hard-coded panel modes */
160	num += panel_simple_get_fixed_modes(p);
161
162	return num;
163}
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165static const struct drm_panel_funcs panel_simple_funcs = {
166	.disable = panel_simple_disable,
 
 
167	.enable = panel_simple_enable,
168	.get_modes = panel_simple_get_modes,
 
169};
170
171static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
172{
173	struct device_node *backlight, *ddc;
174	struct panel_simple *panel;
175	int err;
176
177	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
178	if (!panel)
179		return -ENOMEM;
180
181	panel->enabled = false;
 
182	panel->desc = desc;
183
184	panel->supply = devm_regulator_get(dev, "power");
185	if (IS_ERR(panel->supply))
186		return PTR_ERR(panel->supply);
187
188	panel->enable_gpio = devm_gpiod_get(dev, "enable");
 
189	if (IS_ERR(panel->enable_gpio)) {
190		err = PTR_ERR(panel->enable_gpio);
191		if (err != -ENOENT) {
192			dev_err(dev, "failed to request GPIO: %d\n", err);
193			return err;
194		}
195
196		panel->enable_gpio = NULL;
197	} else {
198		err = gpiod_direction_output(panel->enable_gpio, 0);
199		if (err < 0) {
200			dev_err(dev, "failed to setup GPIO: %d\n", err);
201			return err;
202		}
203	}
204
205	backlight = of_parse_phandle(dev->of_node, "backlight", 0);
206	if (backlight) {
207		panel->backlight = of_find_backlight_by_node(backlight);
208		of_node_put(backlight);
209
210		if (!panel->backlight)
211			return -EPROBE_DEFER;
212	}
213
214	ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
215	if (ddc) {
216		panel->ddc = of_find_i2c_adapter_by_node(ddc);
217		of_node_put(ddc);
218
219		if (!panel->ddc) {
220			err = -EPROBE_DEFER;
221			goto free_backlight;
222		}
223	}
224
225	drm_panel_init(&panel->base);
226	panel->base.dev = dev;
227	panel->base.funcs = &panel_simple_funcs;
228
229	err = drm_panel_add(&panel->base);
230	if (err < 0)
231		goto free_ddc;
232
233	dev_set_drvdata(dev, panel);
234
235	return 0;
236
237free_ddc:
238	if (panel->ddc)
239		put_device(&panel->ddc->dev);
240free_backlight:
241	if (panel->backlight)
242		put_device(&panel->backlight->dev);
243
244	return err;
245}
246
247static int panel_simple_remove(struct device *dev)
248{
249	struct panel_simple *panel = dev_get_drvdata(dev);
250
251	drm_panel_detach(&panel->base);
252	drm_panel_remove(&panel->base);
253
254	panel_simple_disable(&panel->base);
255
256	if (panel->ddc)
257		put_device(&panel->ddc->dev);
258
259	if (panel->backlight)
260		put_device(&panel->backlight->dev);
261
262	return 0;
263}
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265static const struct drm_display_mode auo_b101aw03_mode = {
266	.clock = 51450,
267	.hdisplay = 1024,
268	.hsync_start = 1024 + 156,
269	.hsync_end = 1024 + 156 + 8,
270	.htotal = 1024 + 156 + 8 + 156,
271	.vdisplay = 600,
272	.vsync_start = 600 + 16,
273	.vsync_end = 600 + 16 + 6,
274	.vtotal = 600 + 16 + 6 + 16,
275	.vrefresh = 60,
276};
277
278static const struct panel_desc auo_b101aw03 = {
279	.modes = &auo_b101aw03_mode,
280	.num_modes = 1,
 
281	.size = {
282		.width = 223,
283		.height = 125,
284	},
285};
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
288	.clock = 72070,
289	.hdisplay = 1366,
290	.hsync_start = 1366 + 58,
291	.hsync_end = 1366 + 58 + 58,
292	.htotal = 1366 + 58 + 58 + 58,
293	.vdisplay = 768,
294	.vsync_start = 768 + 4,
295	.vsync_end = 768 + 4 + 4,
296	.vtotal = 768 + 4 + 4 + 4,
297	.vrefresh = 60,
298};
299
300static const struct panel_desc chunghwa_claa101wa01a = {
301	.modes = &chunghwa_claa101wa01a_mode,
302	.num_modes = 1,
 
303	.size = {
304		.width = 220,
305		.height = 120,
306	},
307};
308
309static const struct drm_display_mode chunghwa_claa101wb01_mode = {
310	.clock = 69300,
311	.hdisplay = 1366,
312	.hsync_start = 1366 + 48,
313	.hsync_end = 1366 + 48 + 32,
314	.htotal = 1366 + 48 + 32 + 20,
315	.vdisplay = 768,
316	.vsync_start = 768 + 16,
317	.vsync_end = 768 + 16 + 8,
318	.vtotal = 768 + 16 + 8 + 16,
319	.vrefresh = 60,
320};
321
322static const struct panel_desc chunghwa_claa101wb01 = {
323	.modes = &chunghwa_claa101wb01_mode,
324	.num_modes = 1,
 
325	.size = {
326		.width = 223,
327		.height = 125,
328	},
329};
330
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331static const struct drm_display_mode lg_lp129qe_mode = {
332	.clock = 285250,
333	.hdisplay = 2560,
334	.hsync_start = 2560 + 48,
335	.hsync_end = 2560 + 48 + 32,
336	.htotal = 2560 + 48 + 32 + 80,
337	.vdisplay = 1700,
338	.vsync_start = 1700 + 3,
339	.vsync_end = 1700 + 3 + 10,
340	.vtotal = 1700 + 3 + 10 + 36,
341	.vrefresh = 60,
342};
343
344static const struct panel_desc lg_lp129qe = {
345	.modes = &lg_lp129qe_mode,
346	.num_modes = 1,
 
347	.size = {
348		.width = 272,
349		.height = 181,
350	},
351};
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353static const struct drm_display_mode samsung_ltn101nt05_mode = {
354	.clock = 54030,
355	.hdisplay = 1024,
356	.hsync_start = 1024 + 24,
357	.hsync_end = 1024 + 24 + 136,
358	.htotal = 1024 + 24 + 136 + 160,
359	.vdisplay = 600,
360	.vsync_start = 600 + 3,
361	.vsync_end = 600 + 3 + 6,
362	.vtotal = 600 + 3 + 6 + 61,
363	.vrefresh = 60,
364};
365
366static const struct panel_desc samsung_ltn101nt05 = {
367	.modes = &samsung_ltn101nt05_mode,
368	.num_modes = 1,
 
369	.size = {
370		.width = 1024,
371		.height = 600,
372	},
373};
374
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375static const struct of_device_id platform_of_match[] = {
376	{
 
 
 
377		.compatible = "auo,b101aw03",
378		.data = &auo_b101aw03,
379	}, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380		.compatible = "chunghwa,claa101wa01a",
381		.data = &chunghwa_claa101wa01a
382	}, {
383		.compatible = "chunghwa,claa101wb01",
384		.data = &chunghwa_claa101wb01
385	}, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386		.compatible = "lg,lp129qe",
387		.data = &lg_lp129qe,
388	}, {
 
 
 
 
 
 
 
 
 
 
 
 
389		.compatible = "samsung,ltn101nt05",
390		.data = &samsung_ltn101nt05,
391	}, {
392		.compatible = "simple-panel",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393	}, {
394		/* sentinel */
395	}
396};
397MODULE_DEVICE_TABLE(of, platform_of_match);
398
399static int panel_simple_platform_probe(struct platform_device *pdev)
400{
401	const struct of_device_id *id;
402
403	id = of_match_node(platform_of_match, pdev->dev.of_node);
404	if (!id)
405		return -ENODEV;
406
407	return panel_simple_probe(&pdev->dev, id->data);
408}
409
410static int panel_simple_platform_remove(struct platform_device *pdev)
411{
412	return panel_simple_remove(&pdev->dev);
413}
414
 
 
 
 
 
415static struct platform_driver panel_simple_platform_driver = {
416	.driver = {
417		.name = "panel-simple",
418		.owner = THIS_MODULE,
419		.of_match_table = platform_of_match,
420	},
421	.probe = panel_simple_platform_probe,
422	.remove = panel_simple_platform_remove,
 
423};
424
425struct panel_desc_dsi {
426	struct panel_desc desc;
427
428	unsigned long flags;
429	enum mipi_dsi_pixel_format format;
430	unsigned int lanes;
431};
432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
434	.clock = 71000,
435	.hdisplay = 800,
436	.hsync_start = 800 + 32,
437	.hsync_end = 800 + 32 + 1,
438	.htotal = 800 + 32 + 1 + 57,
439	.vdisplay = 1280,
440	.vsync_start = 1280 + 28,
441	.vsync_end = 1280 + 28 + 1,
442	.vtotal = 1280 + 28 + 1 + 14,
443	.vrefresh = 60,
444};
445
446static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
447	.desc = {
448		.modes = &lg_ld070wx3_sl01_mode,
449		.num_modes = 1,
 
450		.size = {
451			.width = 94,
452			.height = 151,
453		},
454	},
455	.flags = MIPI_DSI_MODE_VIDEO,
456	.format = MIPI_DSI_FMT_RGB888,
457	.lanes = 4,
458};
459
460static const struct drm_display_mode lg_lh500wx1_sd03_mode = {
461	.clock = 67000,
462	.hdisplay = 720,
463	.hsync_start = 720 + 12,
464	.hsync_end = 720 + 12 + 4,
465	.htotal = 720 + 12 + 4 + 112,
466	.vdisplay = 1280,
467	.vsync_start = 1280 + 8,
468	.vsync_end = 1280 + 8 + 4,
469	.vtotal = 1280 + 8 + 4 + 12,
470	.vrefresh = 60,
471};
472
473static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
474	.desc = {
475		.modes = &lg_lh500wx1_sd03_mode,
476		.num_modes = 1,
 
477		.size = {
478			.width = 62,
479			.height = 110,
480		},
481	},
482	.flags = MIPI_DSI_MODE_VIDEO,
483	.format = MIPI_DSI_FMT_RGB888,
484	.lanes = 4,
485};
486
487static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
488	.clock = 157200,
489	.hdisplay = 1920,
490	.hsync_start = 1920 + 154,
491	.hsync_end = 1920 + 154 + 16,
492	.htotal = 1920 + 154 + 16 + 32,
493	.vdisplay = 1200,
494	.vsync_start = 1200 + 17,
495	.vsync_end = 1200 + 17 + 2,
496	.vtotal = 1200 + 17 + 2 + 16,
497	.vrefresh = 60,
498};
499
500static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
501	.desc = {
502		.modes = &panasonic_vvx10f004b00_mode,
503		.num_modes = 1,
 
504		.size = {
505			.width = 217,
506			.height = 136,
507		},
508	},
509	.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
 
510	.format = MIPI_DSI_FMT_RGB888,
511	.lanes = 4,
512};
513
 
514static const struct of_device_id dsi_of_match[] = {
515	{
 
 
 
 
 
 
516		.compatible = "lg,ld070wx3-sl01",
517		.data = &lg_ld070wx3_sl01
518	}, {
519		.compatible = "lg,lh500wx1-sd03",
520		.data = &lg_lh500wx1_sd03
521	}, {
522		.compatible = "panasonic,vvx10f004b00",
523		.data = &panasonic_vvx10f004b00
524	}, {
525		/* sentinel */
526	}
527};
528MODULE_DEVICE_TABLE(of, dsi_of_match);
529
530static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
531{
532	const struct panel_desc_dsi *desc;
533	const struct of_device_id *id;
534	int err;
535
536	id = of_match_node(dsi_of_match, dsi->dev.of_node);
537	if (!id)
538		return -ENODEV;
539
540	desc = id->data;
541
542	err = panel_simple_probe(&dsi->dev, &desc->desc);
543	if (err < 0)
544		return err;
545
546	dsi->mode_flags = desc->flags;
547	dsi->format = desc->format;
548	dsi->lanes = desc->lanes;
549
550	return mipi_dsi_attach(dsi);
551}
552
553static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
554{
555	int err;
556
557	err = mipi_dsi_detach(dsi);
558	if (err < 0)
559		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
560
561	return panel_simple_remove(&dsi->dev);
562}
563
 
 
 
 
 
564static struct mipi_dsi_driver panel_simple_dsi_driver = {
565	.driver = {
566		.name = "panel-simple-dsi",
567		.owner = THIS_MODULE,
568		.of_match_table = dsi_of_match,
569	},
570	.probe = panel_simple_dsi_probe,
571	.remove = panel_simple_dsi_remove,
 
572};
573
574static int __init panel_simple_init(void)
575{
576	int err;
577
578	err = platform_driver_register(&panel_simple_platform_driver);
579	if (err < 0)
580		return err;
581
582	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
583		err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
584		if (err < 0)
585			return err;
586	}
587
588	return 0;
589}
590module_init(panel_simple_init);
591
592static void __exit panel_simple_exit(void)
593{
594	if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
595		mipi_dsi_driver_unregister(&panel_simple_dsi_driver);
596
597	platform_driver_unregister(&panel_simple_platform_driver);
598}
599module_exit(panel_simple_exit);
600
601MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
602MODULE_DESCRIPTION("DRM Driver for Simple Panels");
603MODULE_LICENSE("GPL and additional rights");