aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/panel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
commit988adfdffdd43cfd841df734664727993076d7cb (patch)
tree6794f7bba8f595500c2b7d33376ad6614adcfaf2 /drivers/gpu/drm/panel
parent26178ec11ef3c6c814bf16a0a2b9c2f7242e3c64 (diff)
parent4e0cd68115620bc3236ff4e58e4c073948629b41 (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie: "Highlights: - AMD KFD driver merge This is the AMD HSA interface for exposing a lowlevel interface for GPGPU use. They have an open source userspace built on top of this interface, and the code looks as good as it was going to get out of tree. - Initial atomic modesetting work The need for an atomic modesetting interface to allow userspace to try and send a complete set of modesetting state to the driver has arisen, and been suffering from neglect this past year. No more, the start of the common code and changes for msm driver to use it are in this tree. Ongoing work to get the userspace ioctl finished and the code clean will probably wait until next kernel. - DisplayID 1.3 and tiled monitor exposed to userspace. Tiled monitor property is now exposed for userspace to make use of. - Rockchip drm driver merged. - imx gpu driver moved out of staging Other stuff: - core: panel - MIPI DSI + new panels. expose suggested x/y properties for virtual GPUs - i915: Initial Skylake (SKL) support gen3/4 reset work start of dri1/ums removal infoframe tracking fixes for lots of things. - nouveau: tegra k1 voltage support GM204 modesetting support GT21x memory reclocking work - radeon: CI dpm fixes GPUVM improvements Initial DPM fan control - rcar-du: HDMI support added removed some support for old boards slave encoder driver for Analog Devices adv7511 - exynos: Exynos4415 SoC support - msm: a4xx gpu support atomic helper conversion - tegra: iommu support universal plane support ganged-mode DSI support - sti: HDMI i2c improvements - vmwgfx: some late fixes. - qxl: use suggested x/y properties" * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (969 commits) drm: sti: fix module compilation issue drm/i915: save/restore GMBUS freq across suspend/resume on gen4 drm: sti: correctly cleanup CRTC and planes drm: sti: add HQVDP plane drm: sti: add cursor plane drm: sti: enable auxiliary CRTC drm: sti: fix delay in VTG programming drm: sti: prepare sti_tvout to support auxiliary crtc drm: sti: use drm_crtc_vblank_{on/off} instead of drm_vblank_{on/off} drm: sti: fix hdmi avi infoframe drm: sti: remove event lock while disabling vblank drm: sti: simplify gdp code drm: sti: clear all mixer control drm: sti: remove gpio for HDMI hot plug detection drm: sti: allow to change hdmi ddc i2c adapter drm/doc: Document drm_add_modes_noedid() usage drm/i915: Remove '& 0xffff' from the mask given to WA_REG() drm/i915: Invert the mask and val arguments in wa_add() and WA_REG() drm: Zero out DRM object memory upon cleanup drm/i915/bdw: Fix the write setting up the WIZ hashing mode ...
Diffstat (limited to 'drivers/gpu/drm/panel')
-rw-r--r--drivers/gpu/drm/panel/Kconfig13
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-ld9040.c13
-rw-r--r--drivers/gpu/drm/panel/panel-s6e8aa0.c30
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c464
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c133
6 files changed, 605 insertions, 49 deletions
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index bee9f72b3a93..024e98ef8e4d 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -27,4 +27,17 @@ config DRM_PANEL_S6E8AA0
27 select DRM_MIPI_DSI 27 select DRM_MIPI_DSI
28 select VIDEOMODE_HELPERS 28 select VIDEOMODE_HELPERS
29 29
30config DRM_PANEL_SHARP_LQ101R1SX01
31 tristate "Sharp LQ101R1SX01 panel"
32 depends on OF
33 depends on DRM_MIPI_DSI
34 help
35 Say Y here if you want to enable support for Sharp LQ101R1SX01
36 TFT-LCD modules. The panel has a 2560x1600 resolution and uses
37 24 bit RGB per pixel. It provides a dual MIPI DSI interface to
38 the host and has a built-in LED backlight.
39
40 To compile this driver as a module, choose M here: the module
41 will be called panel-sharp-lq101r1sx01.
42
30endmenu 43endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 8b929212fad7..4b2a0430804b 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o 1obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
2obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o 2obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
3obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o 3obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
4obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c
index 42ac67b21e9f..08cf2c588c3d 100644
--- a/drivers/gpu/drm/panel/panel-ld9040.c
+++ b/drivers/gpu/drm/panel/panel-ld9040.c
@@ -145,7 +145,7 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
145 if (ctx->error < 0 || len == 0) 145 if (ctx->error < 0 || len == 0)
146 return; 146 return;
147 147
148 dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data); 148 dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
149 ret = ld9040_spi_write_word(ctx, *data); 149 ret = ld9040_spi_write_word(ctx, *data);
150 150
151 while (!ret && --len) { 151 while (!ret && --len) {
@@ -154,8 +154,8 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
154 } 154 }
155 155
156 if (ret) { 156 if (ret) {
157 dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, 157 dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret,
158 data); 158 (int)len, data);
159 ctx->error = ret; 159 ctx->error = ret;
160 } 160 }
161 161
@@ -336,17 +336,12 @@ static int ld9040_probe(struct spi_device *spi)
336 if (ret < 0) 336 if (ret < 0)
337 return ret; 337 return ret;
338 338
339 ctx->reset_gpio = devm_gpiod_get(dev, "reset"); 339 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
340 if (IS_ERR(ctx->reset_gpio)) { 340 if (IS_ERR(ctx->reset_gpio)) {
341 dev_err(dev, "cannot get reset-gpios %ld\n", 341 dev_err(dev, "cannot get reset-gpios %ld\n",
342 PTR_ERR(ctx->reset_gpio)); 342 PTR_ERR(ctx->reset_gpio));
343 return PTR_ERR(ctx->reset_gpio); 343 return PTR_ERR(ctx->reset_gpio);
344 } 344 }
345 ret = gpiod_direction_output(ctx->reset_gpio, 1);
346 if (ret < 0) {
347 dev_err(dev, "cannot configure reset-gpios %d\n", ret);
348 return ret;
349 }
350 345
351 spi->bits_per_word = 9; 346 spi->bits_per_word = 9;
352 ret = spi_setup(spi); 347 ret = spi_setup(spi);
diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c
index b5217fe37f02..144b2733e3d7 100644
--- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
@@ -141,10 +141,10 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
141 if (ctx->error < 0) 141 if (ctx->error < 0)
142 return; 142 return;
143 143
144 ret = mipi_dsi_dcs_write(dsi, data, len); 144 ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
145 if (ret < 0) { 145 if (ret < 0) {
146 dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len, 146 dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret,
147 data); 147 (int)len, data);
148 ctx->error = ret; 148 ctx->error = ret;
149 } 149 }
150} 150}
@@ -800,27 +800,15 @@ static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
800} 800}
801 801
802static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx, 802static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
803 int size) 803 u16 size)
804{ 804{
805 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 805 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
806 const struct mipi_dsi_host_ops *ops = dsi->host->ops;
807 u8 buf[] = {size, 0};
808 struct mipi_dsi_msg msg = {
809 .channel = dsi->channel,
810 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
811 .tx_len = sizeof(buf),
812 .tx_buf = buf
813 };
814 int ret; 806 int ret;
815 807
816 if (ctx->error < 0) 808 if (ctx->error < 0)
817 return; 809 return;
818 810
819 if (!ops || !ops->transfer) 811 ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
820 ret = -EIO;
821 else
822 ret = ops->transfer(dsi->host, &msg);
823
824 if (ret < 0) { 812 if (ret < 0) {
825 dev_err(ctx->dev, 813 dev_err(ctx->dev,
826 "error %d setting maximum return packet size to %d\n", 814 "error %d setting maximum return packet size to %d\n",
@@ -1019,17 +1007,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
1019 return ret; 1007 return ret;
1020 } 1008 }
1021 1009
1022 ctx->reset_gpio = devm_gpiod_get(dev, "reset"); 1010 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
1023 if (IS_ERR(ctx->reset_gpio)) { 1011 if (IS_ERR(ctx->reset_gpio)) {
1024 dev_err(dev, "cannot get reset-gpios %ld\n", 1012 dev_err(dev, "cannot get reset-gpios %ld\n",
1025 PTR_ERR(ctx->reset_gpio)); 1013 PTR_ERR(ctx->reset_gpio));
1026 return PTR_ERR(ctx->reset_gpio); 1014 return PTR_ERR(ctx->reset_gpio);
1027 } 1015 }
1028 ret = gpiod_direction_output(ctx->reset_gpio, 1);
1029 if (ret < 0) {
1030 dev_err(dev, "cannot configure reset-gpios %d\n", ret);
1031 return ret;
1032 }
1033 1016
1034 ctx->brightness = GAMMA_LEVEL_NUM - 1; 1017 ctx->brightness = GAMMA_LEVEL_NUM - 1;
1035 1018
@@ -1069,7 +1052,6 @@ static struct mipi_dsi_driver s6e8aa0_driver = {
1069 .remove = s6e8aa0_remove, 1052 .remove = s6e8aa0_remove,
1070 .driver = { 1053 .driver = {
1071 .name = "panel_s6e8aa0", 1054 .name = "panel_s6e8aa0",
1072 .owner = THIS_MODULE,
1073 .of_match_table = s6e8aa0_of_match, 1055 .of_match_table = s6e8aa0_of_match,
1074 }, 1056 },
1075}; 1057};
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
new file mode 100644
index 000000000000..9d81759d82fc
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -0,0 +1,464 @@
1/*
2 * Copyright (C) 2014 NVIDIA Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/backlight.h>
10#include <linux/gpio/consumer.h>
11#include <linux/module.h>
12#include <linux/of.h>
13#include <linux/regulator/consumer.h>
14
15#include <drm/drmP.h>
16#include <drm/drm_crtc.h>
17#include <drm/drm_mipi_dsi.h>
18#include <drm/drm_panel.h>
19
20#include <video/mipi_display.h>
21
22#include <linux/host1x.h>
23
24struct sharp_panel {
25 struct drm_panel base;
26 /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
27 struct mipi_dsi_device *link1;
28 struct mipi_dsi_device *link2;
29
30 struct backlight_device *backlight;
31 struct regulator *supply;
32
33 bool prepared;
34 bool enabled;
35
36 const struct drm_display_mode *mode;
37};
38
39static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel)
40{
41 return container_of(panel, struct sharp_panel, base);
42}
43
44static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
45{
46 u8 payload[3] = { offset >> 8, offset & 0xff, value };
47 struct mipi_dsi_device *dsi = sharp->link1;
48 ssize_t err;
49
50 err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
51 if (err < 0) {
52 dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n",
53 value, offset, err);
54 return err;
55 }
56
57 err = mipi_dsi_dcs_nop(dsi);
58 if (err < 0) {
59 dev_err(&dsi->dev, "failed to send DCS nop: %zd\n", err);
60 return err;
61 }
62
63 usleep_range(10, 20);
64
65 return 0;
66}
67
68static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp,
69 u16 offset, u8 *value)
70{
71 ssize_t err;
72
73 cpu_to_be16s(&offset);
74
75 err = mipi_dsi_generic_read(sharp->link1, &offset, sizeof(offset),
76 value, sizeof(*value));
77 if (err < 0)
78 dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n",
79 offset, err);
80
81 return err;
82}
83
84static int sharp_panel_disable(struct drm_panel *panel)
85{
86 struct sharp_panel *sharp = to_sharp_panel(panel);
87
88 if (!sharp->enabled)
89 return 0;
90
91 if (sharp->backlight) {
92 sharp->backlight->props.power = FB_BLANK_POWERDOWN;
93 backlight_update_status(sharp->backlight);
94 }
95
96 sharp->enabled = false;
97
98 return 0;
99}
100
101static int sharp_panel_unprepare(struct drm_panel *panel)
102{
103 struct sharp_panel *sharp = to_sharp_panel(panel);
104 int err;
105
106 if (!sharp->prepared)
107 return 0;
108
109 err = mipi_dsi_dcs_set_display_off(sharp->link1);
110 if (err < 0)
111 dev_err(panel->dev, "failed to set display off: %d\n", err);
112
113 err = mipi_dsi_dcs_enter_sleep_mode(sharp->link1);
114 if (err < 0)
115 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
116
117 msleep(120);
118
119 regulator_disable(sharp->supply);
120
121 sharp->prepared = false;
122
123 return 0;
124}
125
126static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left,
127 struct mipi_dsi_device *right,
128 const struct drm_display_mode *mode)
129{
130 int err;
131
132 err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1);
133 if (err < 0) {
134 dev_err(&left->dev, "failed to set column address: %d\n", err);
135 return err;
136 }
137
138 err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1);
139 if (err < 0) {
140 dev_err(&left->dev, "failed to set page address: %d\n", err);
141 return err;
142 }
143
144 err = mipi_dsi_dcs_set_column_address(right, mode->hdisplay / 2,
145 mode->hdisplay - 1);
146 if (err < 0) {
147 dev_err(&right->dev, "failed to set column address: %d\n", err);
148 return err;
149 }
150
151 err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1);
152 if (err < 0) {
153 dev_err(&right->dev, "failed to set page address: %d\n", err);
154 return err;
155 }
156
157 return 0;
158}
159
160static int sharp_panel_prepare(struct drm_panel *panel)
161{
162 struct sharp_panel *sharp = to_sharp_panel(panel);
163 u8 format = MIPI_DCS_PIXEL_FMT_24BIT;
164 int err;
165
166 if (sharp->prepared)
167 return 0;
168
169 err = regulator_enable(sharp->supply);
170 if (err < 0)
171 return err;
172
173 usleep_range(10000, 20000);
174
175 err = mipi_dsi_dcs_soft_reset(sharp->link1);
176 if (err < 0) {
177 dev_err(panel->dev, "soft reset failed: %d\n", err);
178 goto poweroff;
179 }
180
181 msleep(120);
182
183 err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
184 if (err < 0) {
185 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
186 goto poweroff;
187 }
188
189 /*
190 * The MIPI DCS specification mandates this delay only between the
191 * exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly
192 * necessary here.
193 */
194 /*
195 msleep(120);
196 */
197
198 /* set left-right mode */
199 err = sharp_panel_write(sharp, 0x1000, 0x2a);
200 if (err < 0) {
201 dev_err(panel->dev, "failed to set left-right mode: %d\n", err);
202 goto poweroff;
203 }
204
205 /* enable command mode */
206 err = sharp_panel_write(sharp, 0x1001, 0x01);
207 if (err < 0) {
208 dev_err(panel->dev, "failed to enable command mode: %d\n", err);
209 goto poweroff;
210 }
211
212 err = mipi_dsi_dcs_set_pixel_format(sharp->link1, format);
213 if (err < 0) {
214 dev_err(panel->dev, "failed to set pixel format: %d\n", err);
215 goto poweroff;
216 }
217
218 /*
219 * TODO: The device supports both left-right and even-odd split
220 * configurations, but this driver currently supports only the left-
221 * right split. To support a different mode a mechanism needs to be
222 * put in place to communicate the configuration back to the DSI host
223 * controller.
224 */
225 err = sharp_setup_symmetrical_split(sharp->link1, sharp->link2,
226 sharp->mode);
227 if (err < 0) {
228 dev_err(panel->dev, "failed to set up symmetrical split: %d\n",
229 err);
230 goto poweroff;
231 }
232
233 err = mipi_dsi_dcs_set_display_on(sharp->link1);
234 if (err < 0) {
235 dev_err(panel->dev, "failed to set display on: %d\n", err);
236 goto poweroff;
237 }
238
239 sharp->prepared = true;
240
241 return 0;
242
243poweroff:
244 regulator_disable(sharp->supply);
245 return err;
246}
247
248static int sharp_panel_enable(struct drm_panel *panel)
249{
250 struct sharp_panel *sharp = to_sharp_panel(panel);
251
252 if (sharp->enabled)
253 return 0;
254
255 if (sharp->backlight) {
256 sharp->backlight->props.power = FB_BLANK_UNBLANK;
257 backlight_update_status(sharp->backlight);
258 }
259
260 sharp->enabled = true;
261
262 return 0;
263}
264
265static const struct drm_display_mode default_mode = {
266 .clock = 278000,
267 .hdisplay = 2560,
268 .hsync_start = 2560 + 128,
269 .hsync_end = 2560 + 128 + 64,
270 .htotal = 2560 + 128 + 64 + 64,
271 .vdisplay = 1600,
272 .vsync_start = 1600 + 4,
273 .vsync_end = 1600 + 4 + 8,
274 .vtotal = 1600 + 4 + 8 + 32,
275 .vrefresh = 60,
276};
277
278static int sharp_panel_get_modes(struct drm_panel *panel)
279{
280 struct drm_display_mode *mode;
281
282 mode = drm_mode_duplicate(panel->drm, &default_mode);
283 if (!mode) {
284 dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
285 default_mode.hdisplay, default_mode.vdisplay,
286 default_mode.vrefresh);
287 return -ENOMEM;
288 }
289
290 drm_mode_set_name(mode);
291
292 drm_mode_probed_add(panel->connector, mode);
293
294 panel->connector->display_info.width_mm = 217;
295 panel->connector->display_info.height_mm = 136;
296
297 return 1;
298}
299
300static const struct drm_panel_funcs sharp_panel_funcs = {
301 .disable = sharp_panel_disable,
302 .unprepare = sharp_panel_unprepare,
303 .prepare = sharp_panel_prepare,
304 .enable = sharp_panel_enable,
305 .get_modes = sharp_panel_get_modes,
306};
307
308static const struct of_device_id sharp_of_match[] = {
309 { .compatible = "sharp,lq101r1sx01", },
310 { }
311};
312MODULE_DEVICE_TABLE(of, sharp_of_match);
313
314static int sharp_panel_add(struct sharp_panel *sharp)
315{
316 struct device_node *np;
317 int err;
318
319 sharp->mode = &default_mode;
320
321 sharp->supply = devm_regulator_get(&sharp->link1->dev, "power");
322 if (IS_ERR(sharp->supply))
323 return PTR_ERR(sharp->supply);
324
325 np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0);
326 if (np) {
327 sharp->backlight = of_find_backlight_by_node(np);
328 of_node_put(np);
329
330 if (!sharp->backlight)
331 return -EPROBE_DEFER;
332 }
333
334 drm_panel_init(&sharp->base);
335 sharp->base.funcs = &sharp_panel_funcs;
336 sharp->base.dev = &sharp->link1->dev;
337
338 err = drm_panel_add(&sharp->base);
339 if (err < 0)
340 goto put_backlight;
341
342 return 0;
343
344put_backlight:
345 if (sharp->backlight)
346 put_device(&sharp->backlight->dev);
347
348 return err;
349}
350
351static void sharp_panel_del(struct sharp_panel *sharp)
352{
353 if (sharp->base.dev)
354 drm_panel_remove(&sharp->base);
355
356 if (sharp->backlight)
357 put_device(&sharp->backlight->dev);
358
359 if (sharp->link2)
360 put_device(&sharp->link2->dev);
361}
362
363static int sharp_panel_probe(struct mipi_dsi_device *dsi)
364{
365 struct mipi_dsi_device *secondary = NULL;
366 struct sharp_panel *sharp;
367 struct device_node *np;
368 int err;
369
370 dsi->lanes = 4;
371 dsi->format = MIPI_DSI_FMT_RGB888;
372 dsi->mode_flags = MIPI_DSI_MODE_LPM;
373
374 /* Find DSI-LINK1 */
375 np = of_parse_phandle(dsi->dev.of_node, "link2", 0);
376 if (np) {
377 secondary = of_find_mipi_dsi_device_by_node(np);
378 of_node_put(np);
379
380 if (!secondary)
381 return -EPROBE_DEFER;
382 }
383
384 /* register a panel for only the DSI-LINK1 interface */
385 if (secondary) {
386 sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL);
387 if (!sharp) {
388 put_device(&secondary->dev);
389 return -ENOMEM;
390 }
391
392 mipi_dsi_set_drvdata(dsi, sharp);
393
394 sharp->link2 = secondary;
395 sharp->link1 = dsi;
396
397 err = sharp_panel_add(sharp);
398 if (err < 0) {
399 put_device(&secondary->dev);
400 return err;
401 }
402 }
403
404 err = mipi_dsi_attach(dsi);
405 if (err < 0) {
406 if (secondary)
407 sharp_panel_del(sharp);
408
409 return err;
410 }
411
412 return 0;
413}
414
415static int sharp_panel_remove(struct mipi_dsi_device *dsi)
416{
417 struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
418 int err;
419
420 /* only detach from host for the DSI-LINK2 interface */
421 if (!sharp) {
422 mipi_dsi_detach(dsi);
423 return 0;
424 }
425
426 err = sharp_panel_disable(&sharp->base);
427 if (err < 0)
428 dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
429
430 err = mipi_dsi_detach(dsi);
431 if (err < 0)
432 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
433
434 drm_panel_detach(&sharp->base);
435 sharp_panel_del(sharp);
436
437 return 0;
438}
439
440static void sharp_panel_shutdown(struct mipi_dsi_device *dsi)
441{
442 struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
443
444 /* nothing to do for DSI-LINK2 */
445 if (!sharp)
446 return;
447
448 sharp_panel_disable(&sharp->base);
449}
450
451static struct mipi_dsi_driver sharp_panel_driver = {
452 .driver = {
453 .name = "panel-sharp-lq101r1sx01",
454 .of_match_table = sharp_of_match,
455 },
456 .probe = sharp_panel_probe,
457 .remove = sharp_panel_remove,
458 .shutdown = sharp_panel_shutdown,
459};
460module_mipi_dsi_driver(sharp_panel_driver);
461
462MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
463MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver");
464MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 12bc8a0ab1cf..e95385bf8356 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -247,21 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
247 if (IS_ERR(panel->supply)) 247 if (IS_ERR(panel->supply))
248 return PTR_ERR(panel->supply); 248 return PTR_ERR(panel->supply);
249 249
250 panel->enable_gpio = devm_gpiod_get_optional(dev, "enable"); 250 panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
251 GPIOD_OUT_LOW);
251 if (IS_ERR(panel->enable_gpio)) { 252 if (IS_ERR(panel->enable_gpio)) {
252 err = PTR_ERR(panel->enable_gpio); 253 err = PTR_ERR(panel->enable_gpio);
253 dev_err(dev, "failed to request GPIO: %d\n", err); 254 dev_err(dev, "failed to request GPIO: %d\n", err);
254 return err; 255 return err;
255 } 256 }
256 257
257 if (panel->enable_gpio) {
258 err = gpiod_direction_output(panel->enable_gpio, 0);
259 if (err < 0) {
260 dev_err(dev, "failed to setup GPIO: %d\n", err);
261 return err;
262 }
263 }
264
265 backlight = of_parse_phandle(dev->of_node, "backlight", 0); 258 backlight = of_parse_phandle(dev->of_node, "backlight", 0);
266 if (backlight) { 259 if (backlight) {
267 panel->backlight = of_find_backlight_by_node(backlight); 260 panel->backlight = of_find_backlight_by_node(backlight);
@@ -376,6 +369,29 @@ static const struct panel_desc auo_b101xtn01 = {
376 }, 369 },
377}; 370};
378 371
372static const struct drm_display_mode auo_b116xw03_mode = {
373 .clock = 70589,
374 .hdisplay = 1366,
375 .hsync_start = 1366 + 40,
376 .hsync_end = 1366 + 40 + 40,
377 .htotal = 1366 + 40 + 40 + 32,
378 .vdisplay = 768,
379 .vsync_start = 768 + 10,
380 .vsync_end = 768 + 10 + 12,
381 .vtotal = 768 + 10 + 12 + 6,
382 .vrefresh = 60,
383};
384
385static const struct panel_desc auo_b116xw03 = {
386 .modes = &auo_b116xw03_mode,
387 .num_modes = 1,
388 .bpc = 6,
389 .size = {
390 .width = 256,
391 .height = 144,
392 },
393};
394
379static const struct drm_display_mode auo_b133xtn01_mode = { 395static const struct drm_display_mode auo_b133xtn01_mode = {
380 .clock = 69500, 396 .clock = 69500,
381 .hdisplay = 1366, 397 .hdisplay = 1366,
@@ -415,6 +431,7 @@ static const struct drm_display_mode auo_b133htn01_mode = {
415static const struct panel_desc auo_b133htn01 = { 431static const struct panel_desc auo_b133htn01 = {
416 .modes = &auo_b133htn01_mode, 432 .modes = &auo_b133htn01_mode,
417 .num_modes = 1, 433 .num_modes = 1,
434 .bpc = 6,
418 .size = { 435 .size = {
419 .width = 293, 436 .width = 293,
420 .height = 165, 437 .height = 165,
@@ -536,22 +553,92 @@ static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
536static const struct panel_desc foxlink_fl500wvr00_a0t = { 553static const struct panel_desc foxlink_fl500wvr00_a0t = {
537 .modes = &foxlink_fl500wvr00_a0t_mode, 554 .modes = &foxlink_fl500wvr00_a0t_mode,
538 .num_modes = 1, 555 .num_modes = 1,
556 .bpc = 8,
539 .size = { 557 .size = {
540 .width = 108, 558 .width = 108,
541 .height = 65, 559 .height = 65,
542 }, 560 },
543}; 561};
544 562
545static const struct drm_display_mode innolux_n116bge_mode = { 563static const struct drm_display_mode hannstar_hsd070pww1_mode = {
564 .clock = 71100,
565 .hdisplay = 1280,
566 .hsync_start = 1280 + 1,
567 .hsync_end = 1280 + 1 + 158,
568 .htotal = 1280 + 1 + 158 + 1,
569 .vdisplay = 800,
570 .vsync_start = 800 + 1,
571 .vsync_end = 800 + 1 + 21,
572 .vtotal = 800 + 1 + 21 + 1,
573 .vrefresh = 60,
574};
575
576static const struct panel_desc hannstar_hsd070pww1 = {
577 .modes = &hannstar_hsd070pww1_mode,
578 .num_modes = 1,
579 .bpc = 6,
580 .size = {
581 .width = 151,
582 .height = 94,
583 },
584};
585
586static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
587 .clock = 33333,
588 .hdisplay = 800,
589 .hsync_start = 800 + 85,
590 .hsync_end = 800 + 85 + 86,
591 .htotal = 800 + 85 + 86 + 85,
592 .vdisplay = 480,
593 .vsync_start = 480 + 16,
594 .vsync_end = 480 + 16 + 13,
595 .vtotal = 480 + 16 + 13 + 16,
596 .vrefresh = 60,
597};
598
599static const struct panel_desc hitachi_tx23d38vm0caa = {
600 .modes = &hitachi_tx23d38vm0caa_mode,
601 .num_modes = 1,
602 .bpc = 6,
603 .size = {
604 .width = 195,
605 .height = 117,
606 },
607};
608
609static const struct drm_display_mode innolux_g121i1_l01_mode = {
546 .clock = 71000, 610 .clock = 71000,
611 .hdisplay = 1280,
612 .hsync_start = 1280 + 64,
613 .hsync_end = 1280 + 64 + 32,
614 .htotal = 1280 + 64 + 32 + 64,
615 .vdisplay = 800,
616 .vsync_start = 800 + 9,
617 .vsync_end = 800 + 9 + 6,
618 .vtotal = 800 + 9 + 6 + 9,
619 .vrefresh = 60,
620};
621
622static const struct panel_desc innolux_g121i1_l01 = {
623 .modes = &innolux_g121i1_l01_mode,
624 .num_modes = 1,
625 .bpc = 6,
626 .size = {
627 .width = 261,
628 .height = 163,
629 },
630};
631
632static const struct drm_display_mode innolux_n116bge_mode = {
633 .clock = 76420,
547 .hdisplay = 1366, 634 .hdisplay = 1366,
548 .hsync_start = 1366 + 64, 635 .hsync_start = 1366 + 136,
549 .hsync_end = 1366 + 64 + 6, 636 .hsync_end = 1366 + 136 + 30,
550 .htotal = 1366 + 64 + 6 + 64, 637 .htotal = 1366 + 136 + 30 + 60,
551 .vdisplay = 768, 638 .vdisplay = 768,
552 .vsync_start = 768 + 8, 639 .vsync_start = 768 + 8,
553 .vsync_end = 768 + 8 + 4, 640 .vsync_end = 768 + 8 + 12,
554 .vtotal = 768 + 8 + 4 + 8, 641 .vtotal = 768 + 8 + 12 + 12,
555 .vrefresh = 60, 642 .vrefresh = 60,
556 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 643 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
557}; 644};
@@ -643,6 +730,9 @@ static const struct of_device_id platform_of_match[] = {
643 .compatible = "auo,b101xtn01", 730 .compatible = "auo,b101xtn01",
644 .data = &auo_b101xtn01, 731 .data = &auo_b101xtn01,
645 }, { 732 }, {
733 .compatible = "auo,b116xw03",
734 .data = &auo_b116xw03,
735 }, {
646 .compatible = "auo,b133htn01", 736 .compatible = "auo,b133htn01",
647 .data = &auo_b133htn01, 737 .data = &auo_b133htn01,
648 }, { 738 }, {
@@ -667,6 +757,15 @@ static const struct of_device_id platform_of_match[] = {
667 .compatible = "foxlink,fl500wvr00-a0t", 757 .compatible = "foxlink,fl500wvr00-a0t",
668 .data = &foxlink_fl500wvr00_a0t, 758 .data = &foxlink_fl500wvr00_a0t,
669 }, { 759 }, {
760 .compatible = "hannstar,hsd070pww1",
761 .data = &hannstar_hsd070pww1,
762 }, {
763 .compatible = "hit,tx23d38vm0caa",
764 .data = &hitachi_tx23d38vm0caa
765 }, {
766 .compatible ="innolux,g121i1-l01",
767 .data = &innolux_g121i1_l01
768 }, {
670 .compatible = "innolux,n116bge", 769 .compatible = "innolux,n116bge",
671 .data = &innolux_n116bge, 770 .data = &innolux_n116bge,
672 }, { 771 }, {
@@ -740,6 +839,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
740 .desc = { 839 .desc = {
741 .modes = &lg_ld070wx3_sl01_mode, 840 .modes = &lg_ld070wx3_sl01_mode,
742 .num_modes = 1, 841 .num_modes = 1,
842 .bpc = 8,
743 .size = { 843 .size = {
744 .width = 94, 844 .width = 94,
745 .height = 151, 845 .height = 151,
@@ -767,6 +867,7 @@ static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
767 .desc = { 867 .desc = {
768 .modes = &lg_lh500wx1_sd03_mode, 868 .modes = &lg_lh500wx1_sd03_mode,
769 .num_modes = 1, 869 .num_modes = 1,
870 .bpc = 8,
770 .size = { 871 .size = {
771 .width = 62, 872 .width = 62,
772 .height = 110, 873 .height = 110,
@@ -794,6 +895,7 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
794 .desc = { 895 .desc = {
795 .modes = &panasonic_vvx10f004b00_mode, 896 .modes = &panasonic_vvx10f004b00_mode,
796 .num_modes = 1, 897 .num_modes = 1,
898 .bpc = 8,
797 .size = { 899 .size = {
798 .width = 217, 900 .width = 217,
799 .height = 136, 901 .height = 136,
@@ -863,7 +965,6 @@ static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi)
863static struct mipi_dsi_driver panel_simple_dsi_driver = { 965static struct mipi_dsi_driver panel_simple_dsi_driver = {
864 .driver = { 966 .driver = {
865 .name = "panel-simple-dsi", 967 .name = "panel-simple-dsi",
866 .owner = THIS_MODULE,
867 .of_match_table = dsi_of_match, 968 .of_match_table = dsi_of_match,
868 }, 969 },
869 .probe = panel_simple_dsi_probe, 970 .probe = panel_simple_dsi_probe,