aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2014-08-07 05:51:52 -0400
committerDave Airlie <airlied@gmail.com>2014-08-07 05:51:52 -0400
commit0c6287ec12fa8f7e295a6ebc5fd331647c5a5469 (patch)
treeac16fd3160e5d17fa225643683f7dbb7322f1d2e
parent21d70354bba9965a098382fc4d7fb17e138111f3 (diff)
parent9746c61960b63d2cea41333bca00c60f032052bb (diff)
Merge tag 'drm/panel/for-3.17-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/panel: Changes for v3.17-rc1 Panels can now be more finely controlled via .prepare() and .unprepare() callbacks in addition to .enable() and .disable(). New kerneldoc details what they are supposed to do and when they should be called. The simple panel driver gained support for a couple of new panels and it is now possible to specify additional delays during power up and power down sequences if panels require it. DSI devices can now advertise that they support non-continuous clock mode which will allow DSI host controllers to disable the high speed clock after transmissions to save power. * tag 'drm/panel/for-3.17-rc1' of git://anongit.freedesktop.org/tegra/linux: (30 commits) drm/panel: simple: Use devm_gpiod_get_optional() drm/dsi: Replace upcasting macro by function drm/panel: ld9040: Replace upcasting macro by function drm/exynos: dp: Modify driver to support drm_panel drm/exynos: Move DP setup into commit() drm/panel: simple: Add AUO B133HTN01 panel support drm/panel: simple: Support delays in panel functions drm/panel: simple: Add proper definition for prepare and unprepare drm/panel: s6e8aa0: Add proper definition for prepare and unprepare drm/panel: ld9040: Add proper definition for prepare and unprepare drm/tegra: Add support for panel prepare and unprepare routines drm/exynos: dsi: Add support for panel prepare and unprepare routines drm/exynos: dpi: Add support for panel prepare and unprepare routines drm/panel: simple: Add dummy prepare and unprepare routines drm/panel: s6e8aa0: Add dummy prepare and unprepare routines drm/panel: ld9040: Add dummy prepare and unprepare routines drm/panel: Provide convenience wrapper for .get_modes() drm/panel: add .prepare() and .unprepare() functions drm/panel: simple: Remove simple-panel compatible drm/panel: simple: Add Innolux N116BGE panel support ...
-rw-r--r--Documentation/devicetree/bindings/panel/auo,b133htn01.txt7
-rw-r--r--Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt7
-rw-r--r--Documentation/devicetree/bindings/panel/innolux,n116bge.txt7
-rw-r--r--Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt7
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c14
-rw-r--r--drivers/gpu/drm/exynos/Kconfig1
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.c112
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dpi.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c13
-rw-r--r--drivers/gpu/drm/panel/Kconfig7
-rw-r--r--drivers/gpu/drm/panel/panel-ld9040.c21
-rw-r--r--drivers/gpu/drm/panel/panel-s6e8aa0.c29
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c203
-rw-r--r--drivers/gpu/drm/tegra/output.c2
-rw-r--r--include/drm/drm_mipi_dsi.h21
-rw-r--r--include/drm/drm_panel.h58
17 files changed, 447 insertions, 73 deletions
diff --git a/Documentation/devicetree/bindings/panel/auo,b133htn01.txt b/Documentation/devicetree/bindings/panel/auo,b133htn01.txt
new file mode 100644
index 000000000000..302226b5bb55
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/auo,b133htn01.txt
@@ -0,0 +1,7 @@
1AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel
2
3Required properties:
4- compatible: should be "auo,b133htn01"
5
6This binding is compatible with the simple-panel binding, which is specified
7in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt b/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt
new file mode 100644
index 000000000000..b47f9d87bc19
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/foxlink,fl500wvr00-a0t.txt
@@ -0,0 +1,7 @@
1Foxlink Group 5" WVGA TFT LCD panel
2
3Required properties:
4- compatible: should be "foxlink,fl500wvr00-a0t"
5
6This binding is compatible with the simple-panel binding, which is specified
7in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,n116bge.txt b/Documentation/devicetree/bindings/panel/innolux,n116bge.txt
new file mode 100644
index 000000000000..081bb939ed31
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/innolux,n116bge.txt
@@ -0,0 +1,7 @@
1Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel
2
3Required properties:
4- compatible: should be "innolux,n116bge"
5
6This binding is compatible with the simple-panel binding, which is specified
7in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt b/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt
new file mode 100644
index 000000000000..7825844aafdf
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/innolux,n156bge-l21.txt
@@ -0,0 +1,7 @@
1InnoLux 15.6" WXGA TFT LCD panel
2
3Required properties:
4- compatible: should be "innolux,n156bge-l21"
5
6This binding is compatible with the simple-panel binding, which is specified
7in simple-panel.txt in this directory.
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index e633df2f68d8..6aa6a9e95570 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -201,16 +201,15 @@ EXPORT_SYMBOL(mipi_dsi_detach);
201/** 201/**
202 * mipi_dsi_dcs_write - send DCS write command 202 * mipi_dsi_dcs_write - send DCS write command
203 * @dsi: DSI device 203 * @dsi: DSI device
204 * @channel: virtual channel
205 * @data: pointer to the command followed by parameters 204 * @data: pointer to the command followed by parameters
206 * @len: length of @data 205 * @len: length of @data
207 */ 206 */
208int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, 207ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
209 const void *data, size_t len) 208 size_t len)
210{ 209{
211 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 210 const struct mipi_dsi_host_ops *ops = dsi->host->ops;
212 struct mipi_dsi_msg msg = { 211 struct mipi_dsi_msg msg = {
213 .channel = channel, 212 .channel = dsi->channel,
214 .tx_buf = data, 213 .tx_buf = data,
215 .tx_len = len 214 .tx_len = len
216 }; 215 };
@@ -239,19 +238,18 @@ EXPORT_SYMBOL(mipi_dsi_dcs_write);
239/** 238/**
240 * mipi_dsi_dcs_read - send DCS read request command 239 * mipi_dsi_dcs_read - send DCS read request command
241 * @dsi: DSI device 240 * @dsi: DSI device
242 * @channel: virtual channel
243 * @cmd: DCS read command 241 * @cmd: DCS read command
244 * @data: pointer to read buffer 242 * @data: pointer to read buffer
245 * @len: length of @data 243 * @len: length of @data
246 * 244 *
247 * Function returns number of read bytes or error code. 245 * Function returns number of read bytes or error code.
248 */ 246 */
249ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, 247ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
250 u8 cmd, void *data, size_t len) 248 size_t len)
251{ 249{
252 const struct mipi_dsi_host_ops *ops = dsi->host->ops; 250 const struct mipi_dsi_host_ops *ops = dsi->host->ops;
253 struct mipi_dsi_msg msg = { 251 struct mipi_dsi_msg msg = {
254 .channel = channel, 252 .channel = dsi->channel,
255 .type = MIPI_DSI_DCS_READ, 253 .type = MIPI_DSI_DCS_READ,
256 .tx_buf = &cmd, 254 .tx_buf = &cmd,
257 .tx_len = 1, 255 .tx_len = 1,
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 9ba1aaeb8070..7f9f6f9e9b7e 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -53,6 +53,7 @@ config DRM_EXYNOS_DP
53 bool "EXYNOS DRM DP driver support" 53 bool "EXYNOS DRM DP driver support"
54 depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) 54 depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
55 default DRM_EXYNOS 55 default DRM_EXYNOS
56 select DRM_PANEL
56 help 57 help
57 This enables support for DP device. 58 This enables support for DP device.
58 59
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 31c3de98b885..4f3c7eb2d37d 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -16,7 +16,6 @@
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/io.h> 17#include <linux/io.h>
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/delay.h>
20#include <linux/of.h> 19#include <linux/of.h>
21#include <linux/of_gpio.h> 20#include <linux/of_gpio.h>
22#include <linux/gpio.h> 21#include <linux/gpio.h>
@@ -28,6 +27,7 @@
28#include <drm/drmP.h> 27#include <drm/drmP.h>
29#include <drm/drm_crtc.h> 28#include <drm/drm_crtc.h>
30#include <drm/drm_crtc_helper.h> 29#include <drm/drm_crtc_helper.h>
30#include <drm/drm_panel.h>
31#include <drm/bridge/ptn3460.h> 31#include <drm/bridge/ptn3460.h>
32 32
33#include "exynos_drm_drv.h" 33#include "exynos_drm_drv.h"
@@ -41,7 +41,7 @@ struct bridge_init {
41 struct device_node *node; 41 struct device_node *node;
42}; 42};
43 43
44static int exynos_dp_init_dp(struct exynos_dp_device *dp) 44static void exynos_dp_init_dp(struct exynos_dp_device *dp)
45{ 45{
46 exynos_dp_reset(dp); 46 exynos_dp_reset(dp);
47 47
@@ -58,8 +58,6 @@ static int exynos_dp_init_dp(struct exynos_dp_device *dp)
58 58
59 exynos_dp_init_hpd(dp); 59 exynos_dp_init_hpd(dp);
60 exynos_dp_init_aux(dp); 60 exynos_dp_init_aux(dp);
61
62 return 0;
63} 61}
64 62
65static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) 63static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
@@ -875,10 +873,24 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
875static void exynos_dp_hotplug(struct work_struct *work) 873static void exynos_dp_hotplug(struct work_struct *work)
876{ 874{
877 struct exynos_dp_device *dp; 875 struct exynos_dp_device *dp;
878 int ret;
879 876
880 dp = container_of(work, struct exynos_dp_device, hotplug_work); 877 dp = container_of(work, struct exynos_dp_device, hotplug_work);
881 878
879 if (dp->drm_dev)
880 drm_helper_hpd_irq_event(dp->drm_dev);
881}
882
883static void exynos_dp_commit(struct exynos_drm_display *display)
884{
885 struct exynos_dp_device *dp = display->ctx;
886 int ret;
887
888 /* Keep the panel disabled while we configure video */
889 if (dp->panel) {
890 if (drm_panel_disable(dp->panel))
891 DRM_ERROR("failed to disable the panel\n");
892 }
893
882 ret = exynos_dp_detect_hpd(dp); 894 ret = exynos_dp_detect_hpd(dp);
883 if (ret) { 895 if (ret) {
884 /* Cable has been disconnected, we're done */ 896 /* Cable has been disconnected, we're done */
@@ -909,6 +921,12 @@ static void exynos_dp_hotplug(struct work_struct *work)
909 ret = exynos_dp_config_video(dp); 921 ret = exynos_dp_config_video(dp);
910 if (ret) 922 if (ret)
911 dev_err(dp->dev, "unable to config video\n"); 923 dev_err(dp->dev, "unable to config video\n");
924
925 /* Safe to enable the panel now */
926 if (dp->panel) {
927 if (drm_panel_enable(dp->panel))
928 DRM_ERROR("failed to enable the panel\n");
929 }
912} 930}
913 931
914static enum drm_connector_status exynos_dp_detect( 932static enum drm_connector_status exynos_dp_detect(
@@ -933,15 +951,18 @@ static int exynos_dp_get_modes(struct drm_connector *connector)
933 struct exynos_dp_device *dp = ctx_from_connector(connector); 951 struct exynos_dp_device *dp = ctx_from_connector(connector);
934 struct drm_display_mode *mode; 952 struct drm_display_mode *mode;
935 953
954 if (dp->panel)
955 return drm_panel_get_modes(dp->panel);
956
936 mode = drm_mode_create(connector->dev); 957 mode = drm_mode_create(connector->dev);
937 if (!mode) { 958 if (!mode) {
938 DRM_ERROR("failed to create a new display mode.\n"); 959 DRM_ERROR("failed to create a new display mode.\n");
939 return 0; 960 return 0;
940 } 961 }
941 962
942 drm_display_mode_from_videomode(&dp->panel.vm, mode); 963 drm_display_mode_from_videomode(&dp->priv.vm, mode);
943 mode->width_mm = dp->panel.width_mm; 964 mode->width_mm = dp->priv.width_mm;
944 mode->height_mm = dp->panel.height_mm; 965 mode->height_mm = dp->priv.height_mm;
945 connector->display_info.width_mm = mode->width_mm; 966 connector->display_info.width_mm = mode->width_mm;
946 connector->display_info.height_mm = mode->height_mm; 967 connector->display_info.height_mm = mode->height_mm;
947 968
@@ -1021,7 +1042,10 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
1021 drm_connector_register(connector); 1042 drm_connector_register(connector);
1022 drm_mode_connector_attach_encoder(connector, encoder); 1043 drm_mode_connector_attach_encoder(connector, encoder);
1023 1044
1024 return 0; 1045 if (dp->panel)
1046 ret = drm_panel_attach(dp->panel, &dp->connector);
1047
1048 return ret;
1025} 1049}
1026 1050
1027static void exynos_dp_phy_init(struct exynos_dp_device *dp) 1051static void exynos_dp_phy_init(struct exynos_dp_device *dp)
@@ -1050,26 +1074,50 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
1050 } 1074 }
1051} 1075}
1052 1076
1053static void exynos_dp_poweron(struct exynos_dp_device *dp) 1077static void exynos_dp_poweron(struct exynos_drm_display *display)
1054{ 1078{
1079 struct exynos_dp_device *dp = display->ctx;
1080
1055 if (dp->dpms_mode == DRM_MODE_DPMS_ON) 1081 if (dp->dpms_mode == DRM_MODE_DPMS_ON)
1056 return; 1082 return;
1057 1083
1084 if (dp->panel) {
1085 if (drm_panel_prepare(dp->panel)) {
1086 DRM_ERROR("failed to setup the panel\n");
1087 return;
1088 }
1089 }
1090
1058 clk_prepare_enable(dp->clock); 1091 clk_prepare_enable(dp->clock);
1059 exynos_dp_phy_init(dp); 1092 exynos_dp_phy_init(dp);
1060 exynos_dp_init_dp(dp); 1093 exynos_dp_init_dp(dp);
1061 enable_irq(dp->irq); 1094 enable_irq(dp->irq);
1095 exynos_dp_commit(display);
1062} 1096}
1063 1097
1064static void exynos_dp_poweroff(struct exynos_dp_device *dp) 1098static void exynos_dp_poweroff(struct exynos_drm_display *display)
1065{ 1099{
1100 struct exynos_dp_device *dp = display->ctx;
1101
1066 if (dp->dpms_mode != DRM_MODE_DPMS_ON) 1102 if (dp->dpms_mode != DRM_MODE_DPMS_ON)
1067 return; 1103 return;
1068 1104
1105 if (dp->panel) {
1106 if (drm_panel_disable(dp->panel)) {
1107 DRM_ERROR("failed to disable the panel\n");
1108 return;
1109 }
1110 }
1111
1069 disable_irq(dp->irq); 1112 disable_irq(dp->irq);
1070 flush_work(&dp->hotplug_work); 1113 flush_work(&dp->hotplug_work);
1071 exynos_dp_phy_exit(dp); 1114 exynos_dp_phy_exit(dp);
1072 clk_disable_unprepare(dp->clock); 1115 clk_disable_unprepare(dp->clock);
1116
1117 if (dp->panel) {
1118 if (drm_panel_unprepare(dp->panel))
1119 DRM_ERROR("failed to turnoff the panel\n");
1120 }
1073} 1121}
1074 1122
1075static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) 1123static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
@@ -1078,12 +1126,12 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
1078 1126
1079 switch (mode) { 1127 switch (mode) {
1080 case DRM_MODE_DPMS_ON: 1128 case DRM_MODE_DPMS_ON:
1081 exynos_dp_poweron(dp); 1129 exynos_dp_poweron(display);
1082 break; 1130 break;
1083 case DRM_MODE_DPMS_STANDBY: 1131 case DRM_MODE_DPMS_STANDBY:
1084 case DRM_MODE_DPMS_SUSPEND: 1132 case DRM_MODE_DPMS_SUSPEND:
1085 case DRM_MODE_DPMS_OFF: 1133 case DRM_MODE_DPMS_OFF:
1086 exynos_dp_poweroff(dp); 1134 exynos_dp_poweroff(display);
1087 break; 1135 break;
1088 default: 1136 default:
1089 break; 1137 break;
@@ -1094,6 +1142,7 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
1094static struct exynos_drm_display_ops exynos_dp_display_ops = { 1142static struct exynos_drm_display_ops exynos_dp_display_ops = {
1095 .create_connector = exynos_dp_create_connector, 1143 .create_connector = exynos_dp_create_connector,
1096 .dpms = exynos_dp_dpms, 1144 .dpms = exynos_dp_dpms,
1145 .commit = exynos_dp_commit,
1097}; 1146};
1098 1147
1099static struct exynos_drm_display exynos_dp_display = { 1148static struct exynos_drm_display exynos_dp_display = {
@@ -1201,7 +1250,7 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
1201{ 1250{
1202 int ret; 1251 int ret;
1203 1252
1204 ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm, 1253 ret = of_get_videomode(dp->dev->of_node, &dp->priv.vm,
1205 OF_USE_NATIVE_MODE); 1254 OF_USE_NATIVE_MODE);
1206 if (ret) { 1255 if (ret) {
1207 DRM_ERROR("failed: of_get_videomode() : %d\n", ret); 1256 DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
@@ -1215,16 +1264,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
1215 struct platform_device *pdev = to_platform_device(dev); 1264 struct platform_device *pdev = to_platform_device(dev);
1216 struct drm_device *drm_dev = data; 1265 struct drm_device *drm_dev = data;
1217 struct resource *res; 1266 struct resource *res;
1218 struct exynos_dp_device *dp; 1267 struct exynos_dp_device *dp = exynos_dp_display.ctx;
1219 unsigned int irq_flags; 1268 unsigned int irq_flags;
1220
1221 int ret = 0; 1269 int ret = 0;
1222 1270
1223 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1224 GFP_KERNEL);
1225 if (!dp)
1226 return -ENOMEM;
1227
1228 dp->dev = &pdev->dev; 1271 dp->dev = &pdev->dev;
1229 dp->dpms_mode = DRM_MODE_DPMS_OFF; 1272 dp->dpms_mode = DRM_MODE_DPMS_OFF;
1230 1273
@@ -1236,9 +1279,11 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
1236 if (ret) 1279 if (ret)
1237 return ret; 1280 return ret;
1238 1281
1239 ret = exynos_dp_dt_parse_panel(dp); 1282 if (!dp->panel) {
1240 if (ret) 1283 ret = exynos_dp_dt_parse_panel(dp);
1241 return ret; 1284 if (ret)
1285 return ret;
1286 }
1242 1287
1243 dp->clock = devm_clk_get(&pdev->dev, "dp"); 1288 dp->clock = devm_clk_get(&pdev->dev, "dp");
1244 if (IS_ERR(dp->clock)) { 1289 if (IS_ERR(dp->clock)) {
@@ -1298,7 +1343,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
1298 disable_irq(dp->irq); 1343 disable_irq(dp->irq);
1299 1344
1300 dp->drm_dev = drm_dev; 1345 dp->drm_dev = drm_dev;
1301 exynos_dp_display.ctx = dp;
1302 1346
1303 platform_set_drvdata(pdev, &exynos_dp_display); 1347 platform_set_drvdata(pdev, &exynos_dp_display);
1304 1348
@@ -1325,6 +1369,9 @@ static const struct component_ops exynos_dp_ops = {
1325 1369
1326static int exynos_dp_probe(struct platform_device *pdev) 1370static int exynos_dp_probe(struct platform_device *pdev)
1327{ 1371{
1372 struct device *dev = &pdev->dev;
1373 struct device_node *panel_node;
1374 struct exynos_dp_device *dp;
1328 int ret; 1375 int ret;
1329 1376
1330 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, 1377 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
@@ -1332,6 +1379,21 @@ static int exynos_dp_probe(struct platform_device *pdev)
1332 if (ret) 1379 if (ret)
1333 return ret; 1380 return ret;
1334 1381
1382 dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
1383 GFP_KERNEL);
1384 if (!dp)
1385 return -ENOMEM;
1386
1387 panel_node = of_parse_phandle(dev->of_node, "panel", 0);
1388 if (panel_node) {
1389 dp->panel = of_drm_find_panel(panel_node);
1390 of_node_put(panel_node);
1391 if (!dp->panel)
1392 return -EPROBE_DEFER;
1393 }
1394
1395 exynos_dp_display.ctx = dp;
1396
1335 ret = component_add(&pdev->dev, &exynos_dp_ops); 1397 ret = component_add(&pdev->dev, &exynos_dp_ops);
1336 if (ret) 1398 if (ret)
1337 exynos_drm_component_del(&pdev->dev, 1399 exynos_drm_component_del(&pdev->dev,
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 02cc4f9ab903..a1aee6931bd7 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -149,6 +149,7 @@ struct exynos_dp_device {
149 struct drm_device *drm_dev; 149 struct drm_device *drm_dev;
150 struct drm_connector connector; 150 struct drm_connector connector;
151 struct drm_encoder *encoder; 151 struct drm_encoder *encoder;
152 struct drm_panel *panel;
152 struct clk *clock; 153 struct clk *clock;
153 unsigned int irq; 154 unsigned int irq;
154 void __iomem *reg_base; 155 void __iomem *reg_base;
@@ -162,7 +163,7 @@ struct exynos_dp_device {
162 int dpms_mode; 163 int dpms_mode;
163 int hpd_gpio; 164 int hpd_gpio;
164 165
165 struct exynos_drm_panel_info panel; 166 struct exynos_drm_panel_info priv;
166}; 167};
167 168
168/* exynos_dp_reg.c */ 169/* exynos_dp_reg.c */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 3aa1c7ebbfcc..fa08f05e3e34 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -125,14 +125,18 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display,
125 125
126static void exynos_dpi_poweron(struct exynos_dpi *ctx) 126static void exynos_dpi_poweron(struct exynos_dpi *ctx)
127{ 127{
128 if (ctx->panel) 128 if (ctx->panel) {
129 drm_panel_prepare(ctx->panel);
129 drm_panel_enable(ctx->panel); 130 drm_panel_enable(ctx->panel);
131 }
130} 132}
131 133
132static void exynos_dpi_poweroff(struct exynos_dpi *ctx) 134static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
133{ 135{
134 if (ctx->panel) 136 if (ctx->panel) {
135 drm_panel_disable(ctx->panel); 137 drm_panel_disable(ctx->panel);
138 drm_panel_unprepare(ctx->panel);
139 }
136} 140}
137 141
138static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) 142static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 86aebd83a71b..442aa2d00132 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1333,7 +1333,7 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
1333 if (ret < 0) 1333 if (ret < 0)
1334 return ret; 1334 return ret;
1335 1335
1336 ret = drm_panel_enable(dsi->panel); 1336 ret = drm_panel_prepare(dsi->panel);
1337 if (ret < 0) { 1337 if (ret < 0) {
1338 exynos_dsi_poweroff(dsi); 1338 exynos_dsi_poweroff(dsi);
1339 return ret; 1339 return ret;
@@ -1342,6 +1342,14 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
1342 exynos_dsi_set_display_mode(dsi); 1342 exynos_dsi_set_display_mode(dsi);
1343 exynos_dsi_set_display_enable(dsi, true); 1343 exynos_dsi_set_display_enable(dsi, true);
1344 1344
1345 ret = drm_panel_enable(dsi->panel);
1346 if (ret < 0) {
1347 exynos_dsi_set_display_enable(dsi, false);
1348 drm_panel_unprepare(dsi->panel);
1349 exynos_dsi_poweroff(dsi);
1350 return ret;
1351 }
1352
1345 dsi->state |= DSIM_STATE_ENABLED; 1353 dsi->state |= DSIM_STATE_ENABLED;
1346 1354
1347 return 0; 1355 return 0;
@@ -1352,8 +1360,9 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
1352 if (!(dsi->state & DSIM_STATE_ENABLED)) 1360 if (!(dsi->state & DSIM_STATE_ENABLED))
1353 return; 1361 return;
1354 1362
1355 exynos_dsi_set_display_enable(dsi, false);
1356 drm_panel_disable(dsi->panel); 1363 drm_panel_disable(dsi->panel);
1364 exynos_dsi_set_display_enable(dsi, false);
1365 drm_panel_unprepare(dsi->panel);
1357 exynos_dsi_poweroff(dsi); 1366 exynos_dsi_poweroff(dsi);
1358 1367
1359 dsi->state &= ~DSIM_STATE_ENABLED; 1368 dsi->state &= ~DSIM_STATE_ENABLED;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 4ec874da5668..bee9f72b3a93 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -5,7 +5,7 @@ config DRM_PANEL
5 Panel registration and lookup framework. 5 Panel registration and lookup framework.
6 6
7menu "Display Panels" 7menu "Display Panels"
8 depends on DRM_PANEL 8 depends on DRM && DRM_PANEL
9 9
10config DRM_PANEL_SIMPLE 10config DRM_PANEL_SIMPLE
11 tristate "support for simple panels" 11 tristate "support for simple panels"
@@ -18,14 +18,11 @@ config DRM_PANEL_SIMPLE
18 18
19config DRM_PANEL_LD9040 19config DRM_PANEL_LD9040
20 tristate "LD9040 RGB/SPI panel" 20 tristate "LD9040 RGB/SPI panel"
21 depends on DRM && DRM_PANEL 21 depends on OF && SPI
22 depends on OF
23 select SPI
24 select VIDEOMODE_HELPERS 22 select VIDEOMODE_HELPERS
25 23
26config DRM_PANEL_S6E8AA0 24config DRM_PANEL_S6E8AA0
27 tristate "S6E8AA0 DSI video mode panel" 25 tristate "S6E8AA0 DSI video mode panel"
28 depends on DRM && DRM_PANEL
29 depends on OF 26 depends on OF
30 select DRM_MIPI_DSI 27 select DRM_MIPI_DSI
31 select VIDEOMODE_HELPERS 28 select VIDEOMODE_HELPERS
diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c
index db1601fdbe29..42ac67b21e9f 100644
--- a/drivers/gpu/drm/panel/panel-ld9040.c
+++ b/drivers/gpu/drm/panel/panel-ld9040.c
@@ -110,7 +110,10 @@ struct ld9040 {
110 int error; 110 int error;
111}; 111};
112 112
113#define panel_to_ld9040(p) container_of(p, struct ld9040, panel) 113static inline struct ld9040 *panel_to_ld9040(struct drm_panel *panel)
114{
115 return container_of(panel, struct ld9040, panel);
116}
114 117
115static int ld9040_clear_error(struct ld9040 *ctx) 118static int ld9040_clear_error(struct ld9040 *ctx)
116{ 119{
@@ -216,6 +219,11 @@ static int ld9040_power_off(struct ld9040 *ctx)
216 219
217static int ld9040_disable(struct drm_panel *panel) 220static int ld9040_disable(struct drm_panel *panel)
218{ 221{
222 return 0;
223}
224
225static int ld9040_unprepare(struct drm_panel *panel)
226{
219 struct ld9040 *ctx = panel_to_ld9040(panel); 227 struct ld9040 *ctx = panel_to_ld9040(panel);
220 228
221 msleep(120); 229 msleep(120);
@@ -228,7 +236,7 @@ static int ld9040_disable(struct drm_panel *panel)
228 return ld9040_power_off(ctx); 236 return ld9040_power_off(ctx);
229} 237}
230 238
231static int ld9040_enable(struct drm_panel *panel) 239static int ld9040_prepare(struct drm_panel *panel)
232{ 240{
233 struct ld9040 *ctx = panel_to_ld9040(panel); 241 struct ld9040 *ctx = panel_to_ld9040(panel);
234 int ret; 242 int ret;
@@ -242,11 +250,16 @@ static int ld9040_enable(struct drm_panel *panel)
242 ret = ld9040_clear_error(ctx); 250 ret = ld9040_clear_error(ctx);
243 251
244 if (ret < 0) 252 if (ret < 0)
245 ld9040_disable(panel); 253 ld9040_unprepare(panel);
246 254
247 return ret; 255 return ret;
248} 256}
249 257
258static int ld9040_enable(struct drm_panel *panel)
259{
260 return 0;
261}
262
250static int ld9040_get_modes(struct drm_panel *panel) 263static int ld9040_get_modes(struct drm_panel *panel)
251{ 264{
252 struct drm_connector *connector = panel->connector; 265 struct drm_connector *connector = panel->connector;
@@ -273,6 +286,8 @@ static int ld9040_get_modes(struct drm_panel *panel)
273 286
274static const struct drm_panel_funcs ld9040_drm_funcs = { 287static const struct drm_panel_funcs ld9040_drm_funcs = {
275 .disable = ld9040_disable, 288 .disable = ld9040_disable,
289 .unprepare = ld9040_unprepare,
290 .prepare = ld9040_prepare,
276 .enable = ld9040_enable, 291 .enable = ld9040_enable,
277 .get_modes = ld9040_get_modes, 292 .get_modes = ld9040_get_modes,
278}; 293};
diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c
index 06e57a26db7a..b5217fe37f02 100644
--- a/drivers/gpu/drm/panel/panel-s6e8aa0.c
+++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
@@ -120,7 +120,10 @@ struct s6e8aa0 {
120 int error; 120 int error;
121}; 121};
122 122
123#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel) 123static inline struct s6e8aa0 *panel_to_s6e8aa0(struct drm_panel *panel)
124{
125 return container_of(panel, struct s6e8aa0, panel);
126}
124 127
125static int s6e8aa0_clear_error(struct s6e8aa0 *ctx) 128static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
126{ 129{
@@ -133,14 +136,14 @@ static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
133static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) 136static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
134{ 137{
135 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 138 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
136 int ret; 139 ssize_t ret;
137 140
138 if (ctx->error < 0) 141 if (ctx->error < 0)
139 return; 142 return;
140 143
141 ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len); 144 ret = mipi_dsi_dcs_write(dsi, data, len);
142 if (ret < 0) { 145 if (ret < 0) {
143 dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, 146 dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
144 data); 147 data);
145 ctx->error = ret; 148 ctx->error = ret;
146 } 149 }
@@ -154,7 +157,7 @@ static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len)
154 if (ctx->error < 0) 157 if (ctx->error < 0)
155 return ctx->error; 158 return ctx->error;
156 159
157 ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len); 160 ret = mipi_dsi_dcs_read(dsi, cmd, data, len);
158 if (ret < 0) { 161 if (ret < 0) {
159 dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd); 162 dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
160 ctx->error = ret; 163 ctx->error = ret;
@@ -889,6 +892,11 @@ static int s6e8aa0_power_off(struct s6e8aa0 *ctx)
889 892
890static int s6e8aa0_disable(struct drm_panel *panel) 893static int s6e8aa0_disable(struct drm_panel *panel)
891{ 894{
895 return 0;
896}
897
898static int s6e8aa0_unprepare(struct drm_panel *panel)
899{
892 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); 900 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
893 901
894 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); 902 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
@@ -900,7 +908,7 @@ static int s6e8aa0_disable(struct drm_panel *panel)
900 return s6e8aa0_power_off(ctx); 908 return s6e8aa0_power_off(ctx);
901} 909}
902 910
903static int s6e8aa0_enable(struct drm_panel *panel) 911static int s6e8aa0_prepare(struct drm_panel *panel)
904{ 912{
905 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); 913 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
906 int ret; 914 int ret;
@@ -913,11 +921,16 @@ static int s6e8aa0_enable(struct drm_panel *panel)
913 ret = ctx->error; 921 ret = ctx->error;
914 922
915 if (ret < 0) 923 if (ret < 0)
916 s6e8aa0_disable(panel); 924 s6e8aa0_unprepare(panel);
917 925
918 return ret; 926 return ret;
919} 927}
920 928
929static int s6e8aa0_enable(struct drm_panel *panel)
930{
931 return 0;
932}
933
921static int s6e8aa0_get_modes(struct drm_panel *panel) 934static int s6e8aa0_get_modes(struct drm_panel *panel)
922{ 935{
923 struct drm_connector *connector = panel->connector; 936 struct drm_connector *connector = panel->connector;
@@ -944,6 +957,8 @@ static int s6e8aa0_get_modes(struct drm_panel *panel)
944 957
945static const struct drm_panel_funcs s6e8aa0_drm_funcs = { 958static const struct drm_panel_funcs s6e8aa0_drm_funcs = {
946 .disable = s6e8aa0_disable, 959 .disable = s6e8aa0_disable,
960 .unprepare = s6e8aa0_unprepare,
961 .prepare = s6e8aa0_prepare,
947 .enable = s6e8aa0_enable, 962 .enable = s6e8aa0_enable,
948 .get_modes = s6e8aa0_get_modes, 963 .get_modes = s6e8aa0_get_modes,
949}; 964};
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index a25136132c31..4ce1db0a68ff 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -37,14 +37,35 @@ struct panel_desc {
37 const struct drm_display_mode *modes; 37 const struct drm_display_mode *modes;
38 unsigned int num_modes; 38 unsigned int num_modes;
39 39
40 unsigned int bpc;
41
40 struct { 42 struct {
41 unsigned int width; 43 unsigned int width;
42 unsigned int height; 44 unsigned int height;
43 } size; 45 } size;
46
47 /**
48 * @prepare: the time (in milliseconds) that it takes for the panel to
49 * become ready and start receiving video data
50 * @enable: the time (in milliseconds) that it takes for the panel to
51 * display the first valid frame after starting to receive
52 * video data
53 * @disable: the time (in milliseconds) that it takes for the panel to
54 * turn the display off (no content is visible)
55 * @unprepare: the time (in milliseconds) that it takes for the panel
56 * to power itself down completely
57 */
58 struct {
59 unsigned int prepare;
60 unsigned int enable;
61 unsigned int disable;
62 unsigned int unprepare;
63 } delay;
44}; 64};
45 65
46struct panel_simple { 66struct panel_simple {
47 struct drm_panel base; 67 struct drm_panel base;
68 bool prepared;
48 bool enabled; 69 bool enabled;
49 70
50 const struct panel_desc *desc; 71 const struct panel_desc *desc;
@@ -87,6 +108,7 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
87 num++; 108 num++;
88 } 109 }
89 110
111 connector->display_info.bpc = panel->desc->bpc;
90 connector->display_info.width_mm = panel->desc->size.width; 112 connector->display_info.width_mm = panel->desc->size.width;
91 connector->display_info.height_mm = panel->desc->size.height; 113 connector->display_info.height_mm = panel->desc->size.height;
92 114
@@ -105,21 +127,40 @@ static int panel_simple_disable(struct drm_panel *panel)
105 backlight_update_status(p->backlight); 127 backlight_update_status(p->backlight);
106 } 128 }
107 129
130 if (p->desc->delay.disable)
131 msleep(p->desc->delay.disable);
132
133 p->enabled = false;
134
135 return 0;
136}
137
138static int panel_simple_unprepare(struct drm_panel *panel)
139{
140 struct panel_simple *p = to_panel_simple(panel);
141
142 if (!p->prepared)
143 return 0;
144
108 if (p->enable_gpio) 145 if (p->enable_gpio)
109 gpiod_set_value_cansleep(p->enable_gpio, 0); 146 gpiod_set_value_cansleep(p->enable_gpio, 0);
110 147
111 regulator_disable(p->supply); 148 regulator_disable(p->supply);
112 p->enabled = false; 149
150 if (p->desc->delay.unprepare)
151 msleep(p->desc->delay.unprepare);
152
153 p->prepared = false;
113 154
114 return 0; 155 return 0;
115} 156}
116 157
117static int panel_simple_enable(struct drm_panel *panel) 158static int panel_simple_prepare(struct drm_panel *panel)
118{ 159{
119 struct panel_simple *p = to_panel_simple(panel); 160 struct panel_simple *p = to_panel_simple(panel);
120 int err; 161 int err;
121 162
122 if (p->enabled) 163 if (p->prepared)
123 return 0; 164 return 0;
124 165
125 err = regulator_enable(p->supply); 166 err = regulator_enable(p->supply);
@@ -131,6 +172,24 @@ static int panel_simple_enable(struct drm_panel *panel)
131 if (p->enable_gpio) 172 if (p->enable_gpio)
132 gpiod_set_value_cansleep(p->enable_gpio, 1); 173 gpiod_set_value_cansleep(p->enable_gpio, 1);
133 174
175 if (p->desc->delay.prepare)
176 msleep(p->desc->delay.prepare);
177
178 p->prepared = true;
179
180 return 0;
181}
182
183static int panel_simple_enable(struct drm_panel *panel)
184{
185 struct panel_simple *p = to_panel_simple(panel);
186
187 if (p->enabled)
188 return 0;
189
190 if (p->desc->delay.enable)
191 msleep(p->desc->delay.enable);
192
134 if (p->backlight) { 193 if (p->backlight) {
135 p->backlight->props.power = FB_BLANK_UNBLANK; 194 p->backlight->props.power = FB_BLANK_UNBLANK;
136 backlight_update_status(p->backlight); 195 backlight_update_status(p->backlight);
@@ -164,6 +223,8 @@ static int panel_simple_get_modes(struct drm_panel *panel)
164 223
165static const struct drm_panel_funcs panel_simple_funcs = { 224static const struct drm_panel_funcs panel_simple_funcs = {
166 .disable = panel_simple_disable, 225 .disable = panel_simple_disable,
226 .unprepare = panel_simple_unprepare,
227 .prepare = panel_simple_prepare,
167 .enable = panel_simple_enable, 228 .enable = panel_simple_enable,
168 .get_modes = panel_simple_get_modes, 229 .get_modes = panel_simple_get_modes,
169}; 230};
@@ -179,22 +240,21 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
179 return -ENOMEM; 240 return -ENOMEM;
180 241
181 panel->enabled = false; 242 panel->enabled = false;
243 panel->prepared = false;
182 panel->desc = desc; 244 panel->desc = desc;
183 245
184 panel->supply = devm_regulator_get(dev, "power"); 246 panel->supply = devm_regulator_get(dev, "power");
185 if (IS_ERR(panel->supply)) 247 if (IS_ERR(panel->supply))
186 return PTR_ERR(panel->supply); 248 return PTR_ERR(panel->supply);
187 249
188 panel->enable_gpio = devm_gpiod_get(dev, "enable"); 250 panel->enable_gpio = devm_gpiod_get_optional(dev, "enable");
189 if (IS_ERR(panel->enable_gpio)) { 251 if (IS_ERR(panel->enable_gpio)) {
190 err = PTR_ERR(panel->enable_gpio); 252 err = PTR_ERR(panel->enable_gpio);
191 if (err != -ENOENT) { 253 dev_err(dev, "failed to request GPIO: %d\n", err);
192 dev_err(dev, "failed to request GPIO: %d\n", err); 254 return err;
193 return err; 255 }
194 }
195 256
196 panel->enable_gpio = NULL; 257 if (panel->enable_gpio) {
197 } else {
198 err = gpiod_direction_output(panel->enable_gpio, 0); 258 err = gpiod_direction_output(panel->enable_gpio, 0);
199 if (err < 0) { 259 if (err < 0) {
200 dev_err(dev, "failed to setup GPIO: %d\n", err); 260 dev_err(dev, "failed to setup GPIO: %d\n", err);
@@ -285,6 +345,7 @@ static const struct drm_display_mode auo_b101aw03_mode = {
285static const struct panel_desc auo_b101aw03 = { 345static const struct panel_desc auo_b101aw03 = {
286 .modes = &auo_b101aw03_mode, 346 .modes = &auo_b101aw03_mode,
287 .num_modes = 1, 347 .num_modes = 1,
348 .bpc = 6,
288 .size = { 349 .size = {
289 .width = 223, 350 .width = 223,
290 .height = 125, 351 .height = 125,
@@ -307,12 +368,40 @@ static const struct drm_display_mode auo_b133xtn01_mode = {
307static const struct panel_desc auo_b133xtn01 = { 368static const struct panel_desc auo_b133xtn01 = {
308 .modes = &auo_b133xtn01_mode, 369 .modes = &auo_b133xtn01_mode,
309 .num_modes = 1, 370 .num_modes = 1,
371 .bpc = 6,
310 .size = { 372 .size = {
311 .width = 293, 373 .width = 293,
312 .height = 165, 374 .height = 165,
313 }, 375 },
314}; 376};
315 377
378static const struct drm_display_mode auo_b133htn01_mode = {
379 .clock = 150660,
380 .hdisplay = 1920,
381 .hsync_start = 1920 + 172,
382 .hsync_end = 1920 + 172 + 80,
383 .htotal = 1920 + 172 + 80 + 60,
384 .vdisplay = 1080,
385 .vsync_start = 1080 + 25,
386 .vsync_end = 1080 + 25 + 10,
387 .vtotal = 1080 + 25 + 10 + 10,
388 .vrefresh = 60,
389};
390
391static const struct panel_desc auo_b133htn01 = {
392 .modes = &auo_b133htn01_mode,
393 .num_modes = 1,
394 .size = {
395 .width = 293,
396 .height = 165,
397 },
398 .delay = {
399 .prepare = 105,
400 .enable = 20,
401 .unprepare = 50,
402 },
403};
404
316static const struct drm_display_mode chunghwa_claa101wa01a_mode = { 405static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
317 .clock = 72070, 406 .clock = 72070,
318 .hdisplay = 1366, 407 .hdisplay = 1366,
@@ -329,6 +418,7 @@ static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
329static const struct panel_desc chunghwa_claa101wa01a = { 418static const struct panel_desc chunghwa_claa101wa01a = {
330 .modes = &chunghwa_claa101wa01a_mode, 419 .modes = &chunghwa_claa101wa01a_mode,
331 .num_modes = 1, 420 .num_modes = 1,
421 .bpc = 6,
332 .size = { 422 .size = {
333 .width = 220, 423 .width = 220,
334 .height = 120, 424 .height = 120,
@@ -351,6 +441,7 @@ static const struct drm_display_mode chunghwa_claa101wb01_mode = {
351static const struct panel_desc chunghwa_claa101wb01 = { 441static const struct panel_desc chunghwa_claa101wb01 = {
352 .modes = &chunghwa_claa101wb01_mode, 442 .modes = &chunghwa_claa101wb01_mode,
353 .num_modes = 1, 443 .num_modes = 1,
444 .bpc = 6,
354 .size = { 445 .size = {
355 .width = 223, 446 .width = 223,
356 .height = 125, 447 .height = 125,
@@ -374,6 +465,7 @@ static const struct drm_display_mode edt_et057090dhu_mode = {
374static const struct panel_desc edt_et057090dhu = { 465static const struct panel_desc edt_et057090dhu = {
375 .modes = &edt_et057090dhu_mode, 466 .modes = &edt_et057090dhu_mode,
376 .num_modes = 1, 467 .num_modes = 1,
468 .bpc = 6,
377 .size = { 469 .size = {
378 .width = 115, 470 .width = 115,
379 .height = 86, 471 .height = 86,
@@ -397,12 +489,82 @@ static const struct drm_display_mode edt_etm0700g0dh6_mode = {
397static const struct panel_desc edt_etm0700g0dh6 = { 489static const struct panel_desc edt_etm0700g0dh6 = {
398 .modes = &edt_etm0700g0dh6_mode, 490 .modes = &edt_etm0700g0dh6_mode,
399 .num_modes = 1, 491 .num_modes = 1,
492 .bpc = 6,
400 .size = { 493 .size = {
401 .width = 152, 494 .width = 152,
402 .height = 91, 495 .height = 91,
403 }, 496 },
404}; 497};
405 498
499static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
500 .clock = 32260,
501 .hdisplay = 800,
502 .hsync_start = 800 + 168,
503 .hsync_end = 800 + 168 + 64,
504 .htotal = 800 + 168 + 64 + 88,
505 .vdisplay = 480,
506 .vsync_start = 480 + 37,
507 .vsync_end = 480 + 37 + 2,
508 .vtotal = 480 + 37 + 2 + 8,
509 .vrefresh = 60,
510};
511
512static const struct panel_desc foxlink_fl500wvr00_a0t = {
513 .modes = &foxlink_fl500wvr00_a0t_mode,
514 .num_modes = 1,
515 .size = {
516 .width = 108,
517 .height = 65,
518 },
519};
520
521static const struct drm_display_mode innolux_n116bge_mode = {
522 .clock = 71000,
523 .hdisplay = 1366,
524 .hsync_start = 1366 + 64,
525 .hsync_end = 1366 + 64 + 6,
526 .htotal = 1366 + 64 + 6 + 64,
527 .vdisplay = 768,
528 .vsync_start = 768 + 8,
529 .vsync_end = 768 + 8 + 4,
530 .vtotal = 768 + 8 + 4 + 8,
531 .vrefresh = 60,
532 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
533};
534
535static const struct panel_desc innolux_n116bge = {
536 .modes = &innolux_n116bge_mode,
537 .num_modes = 1,
538 .bpc = 6,
539 .size = {
540 .width = 256,
541 .height = 144,
542 },
543};
544
545static const struct drm_display_mode innolux_n156bge_l21_mode = {
546 .clock = 69300,
547 .hdisplay = 1366,
548 .hsync_start = 1366 + 16,
549 .hsync_end = 1366 + 16 + 34,
550 .htotal = 1366 + 16 + 34 + 50,
551 .vdisplay = 768,
552 .vsync_start = 768 + 2,
553 .vsync_end = 768 + 2 + 6,
554 .vtotal = 768 + 2 + 6 + 12,
555 .vrefresh = 60,
556};
557
558static const struct panel_desc innolux_n156bge_l21 = {
559 .modes = &innolux_n156bge_l21_mode,
560 .num_modes = 1,
561 .bpc = 6,
562 .size = {
563 .width = 344,
564 .height = 193,
565 },
566};
567
406static const struct drm_display_mode lg_lp129qe_mode = { 568static const struct drm_display_mode lg_lp129qe_mode = {
407 .clock = 285250, 569 .clock = 285250,
408 .hdisplay = 2560, 570 .hdisplay = 2560,
@@ -419,6 +581,7 @@ static const struct drm_display_mode lg_lp129qe_mode = {
419static const struct panel_desc lg_lp129qe = { 581static const struct panel_desc lg_lp129qe = {
420 .modes = &lg_lp129qe_mode, 582 .modes = &lg_lp129qe_mode,
421 .num_modes = 1, 583 .num_modes = 1,
584 .bpc = 8,
422 .size = { 585 .size = {
423 .width = 272, 586 .width = 272,
424 .height = 181, 587 .height = 181,
@@ -441,6 +604,7 @@ static const struct drm_display_mode samsung_ltn101nt05_mode = {
441static const struct panel_desc samsung_ltn101nt05 = { 604static const struct panel_desc samsung_ltn101nt05 = {
442 .modes = &samsung_ltn101nt05_mode, 605 .modes = &samsung_ltn101nt05_mode,
443 .num_modes = 1, 606 .num_modes = 1,
607 .bpc = 6,
444 .size = { 608 .size = {
445 .width = 1024, 609 .width = 1024,
446 .height = 600, 610 .height = 600,
@@ -452,6 +616,9 @@ static const struct of_device_id platform_of_match[] = {
452 .compatible = "auo,b101aw03", 616 .compatible = "auo,b101aw03",
453 .data = &auo_b101aw03, 617 .data = &auo_b101aw03,
454 }, { 618 }, {
619 .compatible = "auo,b133htn01",
620 .data = &auo_b133htn01,
621 }, {
455 .compatible = "auo,b133xtn01", 622 .compatible = "auo,b133xtn01",
456 .data = &auo_b133xtn01, 623 .data = &auo_b133xtn01,
457 }, { 624 }, {
@@ -470,14 +637,21 @@ static const struct of_device_id platform_of_match[] = {
470 .compatible = "edt,etm0700g0dh6", 637 .compatible = "edt,etm0700g0dh6",
471 .data = &edt_etm0700g0dh6, 638 .data = &edt_etm0700g0dh6,
472 }, { 639 }, {
640 .compatible = "foxlink,fl500wvr00-a0t",
641 .data = &foxlink_fl500wvr00_a0t,
642 }, {
643 .compatible = "innolux,n116bge",
644 .data = &innolux_n116bge,
645 }, {
646 .compatible = "innolux,n156bge-l21",
647 .data = &innolux_n156bge_l21,
648 }, {
473 .compatible = "lg,lp129qe", 649 .compatible = "lg,lp129qe",
474 .data = &lg_lp129qe, 650 .data = &lg_lp129qe,
475 }, { 651 }, {
476 .compatible = "samsung,ltn101nt05", 652 .compatible = "samsung,ltn101nt05",
477 .data = &samsung_ltn101nt05, 653 .data = &samsung_ltn101nt05,
478 }, { 654 }, {
479 .compatible = "simple-panel",
480 }, {
481 /* sentinel */ 655 /* sentinel */
482 } 656 }
483}; 657};
@@ -545,7 +719,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
545 .height = 151, 719 .height = 151,
546 }, 720 },
547 }, 721 },
548 .flags = MIPI_DSI_MODE_VIDEO, 722 .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS,
549 .format = MIPI_DSI_FMT_RGB888, 723 .format = MIPI_DSI_FMT_RGB888,
550 .lanes = 4, 724 .lanes = 4,
551}; 725};
@@ -599,7 +773,8 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
599 .height = 136, 773 .height = 136,
600 }, 774 },
601 }, 775 },
602 .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, 776 .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
777 MIPI_DSI_CLOCK_NON_CONTINUOUS,
603 .format = MIPI_DSI_FMT_RGB888, 778 .format = MIPI_DSI_FMT_RGB888,
604 .lanes = 4, 779 .lanes = 4,
605}; 780};
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 446837e955b6..0c67d7eebc94 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -140,7 +140,9 @@ static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
140 if (mode != DRM_MODE_DPMS_ON) { 140 if (mode != DRM_MODE_DPMS_ON) {
141 drm_panel_disable(panel); 141 drm_panel_disable(panel);
142 tegra_output_disable(output); 142 tegra_output_disable(output);
143 drm_panel_unprepare(panel);
143 } else { 144 } else {
145 drm_panel_prepare(panel);
144 tegra_output_enable(output); 146 tegra_output_enable(output);
145 drm_panel_enable(panel); 147 drm_panel_enable(panel);
146 } 148 }
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 944f33f8ba38..2bb55b8b9031 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -94,6 +94,8 @@ void mipi_dsi_host_unregister(struct mipi_dsi_host *host);
94#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) 94#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
95/* disable EoT packets in HS mode */ 95/* disable EoT packets in HS mode */
96#define MIPI_DSI_MODE_EOT_PACKET BIT(9) 96#define MIPI_DSI_MODE_EOT_PACKET BIT(9)
97/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
98#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
97 99
98enum mipi_dsi_pixel_format { 100enum mipi_dsi_pixel_format {
99 MIPI_DSI_FMT_RGB888, 101 MIPI_DSI_FMT_RGB888,
@@ -121,14 +123,17 @@ struct mipi_dsi_device {
121 unsigned long mode_flags; 123 unsigned long mode_flags;
122}; 124};
123 125
124#define to_mipi_dsi_device(d) container_of(d, struct mipi_dsi_device, dev) 126static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
127{
128 return container_of(dev, struct mipi_dsi_device, dev);
129}
125 130
126int mipi_dsi_attach(struct mipi_dsi_device *dsi); 131int mipi_dsi_attach(struct mipi_dsi_device *dsi);
127int mipi_dsi_detach(struct mipi_dsi_device *dsi); 132int mipi_dsi_detach(struct mipi_dsi_device *dsi);
128int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, 133ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
129 const void *data, size_t len); 134 size_t len);
130ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, 135ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
131 u8 cmd, void *data, size_t len); 136 size_t len);
132 137
133/** 138/**
134 * struct mipi_dsi_driver - DSI driver 139 * struct mipi_dsi_driver - DSI driver
@@ -144,7 +149,11 @@ struct mipi_dsi_driver {
144 void (*shutdown)(struct mipi_dsi_device *dsi); 149 void (*shutdown)(struct mipi_dsi_device *dsi);
145}; 150};
146 151
147#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver, driver) 152static inline struct mipi_dsi_driver *
153to_mipi_dsi_driver(struct device_driver *driver)
154{
155 return container_of(driver, struct mipi_dsi_driver, driver);
156}
148 157
149static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi) 158static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi)
150{ 159{
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index c2ab77add67c..1fbcc96063a7 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -30,8 +30,42 @@ struct drm_connector;
30struct drm_device; 30struct drm_device;
31struct drm_panel; 31struct drm_panel;
32 32
33/**
34 * struct drm_panel_funcs - perform operations on a given panel
35 * @disable: disable panel (turn off back light, etc.)
36 * @unprepare: turn off panel
37 * @prepare: turn on panel and perform set up
38 * @enable: enable panel (turn on back light, etc.)
39 * @get_modes: add modes to the connector that the panel is attached to and
40 * return the number of modes added
41 *
42 * The .prepare() function is typically called before the display controller
43 * starts to transmit video data. Panel drivers can use this to turn the panel
44 * on and wait for it to become ready. If additional configuration is required
45 * (via a control bus such as I2C, SPI or DSI for example) this is a good time
46 * to do that.
47 *
48 * After the display controller has started transmitting video data, it's safe
49 * to call the .enable() function. This will typically enable the backlight to
50 * make the image on screen visible. Some panels require a certain amount of
51 * time or frames before the image is displayed. This function is responsible
52 * for taking this into account before enabling the backlight to avoid visual
53 * glitches.
54 *
55 * Before stopping video transmission from the display controller it can be
56 * necessary to turn off the panel to avoid visual glitches. This is done in
57 * the .disable() function. Analogously to .enable() this typically involves
58 * turning off the backlight and waiting for some time to make sure no image
59 * is visible on the panel. It is then safe for the display controller to
60 * cease transmission of video data.
61 *
62 * To save power when no video data is transmitted, a driver can power down
63 * the panel. This is the job of the .unprepare() function.
64 */
33struct drm_panel_funcs { 65struct drm_panel_funcs {
34 int (*disable)(struct drm_panel *panel); 66 int (*disable)(struct drm_panel *panel);
67 int (*unprepare)(struct drm_panel *panel);
68 int (*prepare)(struct drm_panel *panel);
35 int (*enable)(struct drm_panel *panel); 69 int (*enable)(struct drm_panel *panel);
36 int (*get_modes)(struct drm_panel *panel); 70 int (*get_modes)(struct drm_panel *panel);
37}; 71};
@@ -46,6 +80,14 @@ struct drm_panel {
46 struct list_head list; 80 struct list_head list;
47}; 81};
48 82
83static inline int drm_panel_unprepare(struct drm_panel *panel)
84{
85 if (panel && panel->funcs && panel->funcs->unprepare)
86 return panel->funcs->unprepare(panel);
87
88 return panel ? -ENOSYS : -EINVAL;
89}
90
49static inline int drm_panel_disable(struct drm_panel *panel) 91static inline int drm_panel_disable(struct drm_panel *panel)
50{ 92{
51 if (panel && panel->funcs && panel->funcs->disable) 93 if (panel && panel->funcs && panel->funcs->disable)
@@ -54,6 +96,14 @@ static inline int drm_panel_disable(struct drm_panel *panel)
54 return panel ? -ENOSYS : -EINVAL; 96 return panel ? -ENOSYS : -EINVAL;
55} 97}
56 98
99static inline int drm_panel_prepare(struct drm_panel *panel)
100{
101 if (panel && panel->funcs && panel->funcs->prepare)
102 return panel->funcs->prepare(panel);
103
104 return panel ? -ENOSYS : -EINVAL;
105}
106
57static inline int drm_panel_enable(struct drm_panel *panel) 107static inline int drm_panel_enable(struct drm_panel *panel)
58{ 108{
59 if (panel && panel->funcs && panel->funcs->enable) 109 if (panel && panel->funcs && panel->funcs->enable)
@@ -62,6 +112,14 @@ static inline int drm_panel_enable(struct drm_panel *panel)
62 return panel ? -ENOSYS : -EINVAL; 112 return panel ? -ENOSYS : -EINVAL;
63} 113}
64 114
115static inline int drm_panel_get_modes(struct drm_panel *panel)
116{
117 if (panel && panel->funcs && panel->funcs->get_modes)
118 return panel->funcs->get_modes(panel);
119
120 return panel ? -ENOSYS : -EINVAL;
121}
122
65void drm_panel_init(struct drm_panel *panel); 123void drm_panel_init(struct drm_panel *panel);
66 124
67int drm_panel_add(struct drm_panel *panel); 125int drm_panel_add(struct drm_panel *panel);