diff options
author | Ajay Kumar <ajaykumar.rs@samsung.com> | 2014-07-31 13:42:14 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-08-06 10:44:16 -0400 |
commit | 5f1dcd8b7ec8189c2b147cdaa1589d5644c3cef3 (patch) | |
tree | 515c9198065ff932810886ecfeb532801bbce5be | |
parent | 4deabfa00049465cc1e4ed6fe0b5082bcff98d57 (diff) |
drm/exynos: dp: Modify driver to support drm_panel
Add drm_panel controls to support powerup/down of the
eDP panel, if one is present at the sink side.
Signed-off-by: Ajay Kumar <ajaykumar.rs@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/exynos/Kconfig | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_dp_core.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_dp_core.h | 3 |
3 files changed, 71 insertions, 21 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 178d2a9672a8..fd1c070f0297 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig | |||
@@ -52,6 +52,7 @@ config DRM_EXYNOS_DP | |||
52 | bool "EXYNOS DRM DP driver support" | 52 | bool "EXYNOS DRM DP driver support" |
53 | depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) | 53 | depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS) |
54 | default DRM_EXYNOS | 54 | default DRM_EXYNOS |
55 | select DRM_PANEL | ||
55 | help | 56 | help |
56 | This enables support for DP device. | 57 | This enables support for DP device. |
57 | 58 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index c33a9d0a87c1..0d3f88bfeca5 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 | ||
44 | static int exynos_dp_init_dp(struct exynos_dp_device *dp) | 44 | static 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 | ||
65 | static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) | 63 | static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) |
@@ -887,6 +885,12 @@ static void exynos_dp_commit(struct exynos_drm_display *display) | |||
887 | struct exynos_dp_device *dp = display->ctx; | 885 | struct exynos_dp_device *dp = display->ctx; |
888 | int ret; | 886 | int ret; |
889 | 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 | |||
890 | ret = exynos_dp_detect_hpd(dp); | 894 | ret = exynos_dp_detect_hpd(dp); |
891 | if (ret) { | 895 | if (ret) { |
892 | /* Cable has been disconnected, we're done */ | 896 | /* Cable has been disconnected, we're done */ |
@@ -917,6 +921,12 @@ static void exynos_dp_commit(struct exynos_drm_display *display) | |||
917 | ret = exynos_dp_config_video(dp); | 921 | ret = exynos_dp_config_video(dp); |
918 | if (ret) | 922 | if (ret) |
919 | 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 | } | ||
920 | } | 930 | } |
921 | 931 | ||
922 | static enum drm_connector_status exynos_dp_detect( | 932 | static enum drm_connector_status exynos_dp_detect( |
@@ -941,15 +951,18 @@ static int exynos_dp_get_modes(struct drm_connector *connector) | |||
941 | struct exynos_dp_device *dp = ctx_from_connector(connector); | 951 | struct exynos_dp_device *dp = ctx_from_connector(connector); |
942 | struct drm_display_mode *mode; | 952 | struct drm_display_mode *mode; |
943 | 953 | ||
954 | if (dp->panel) | ||
955 | return drm_panel_get_modes(dp->panel); | ||
956 | |||
944 | mode = drm_mode_create(connector->dev); | 957 | mode = drm_mode_create(connector->dev); |
945 | if (!mode) { | 958 | if (!mode) { |
946 | DRM_ERROR("failed to create a new display mode.\n"); | 959 | DRM_ERROR("failed to create a new display mode.\n"); |
947 | return 0; | 960 | return 0; |
948 | } | 961 | } |
949 | 962 | ||
950 | drm_display_mode_from_videomode(&dp->panel.vm, mode); | 963 | drm_display_mode_from_videomode(&dp->priv.vm, mode); |
951 | mode->width_mm = dp->panel.width_mm; | 964 | mode->width_mm = dp->priv.width_mm; |
952 | mode->height_mm = dp->panel.height_mm; | 965 | mode->height_mm = dp->priv.height_mm; |
953 | connector->display_info.width_mm = mode->width_mm; | 966 | connector->display_info.width_mm = mode->width_mm; |
954 | connector->display_info.height_mm = mode->height_mm; | 967 | connector->display_info.height_mm = mode->height_mm; |
955 | 968 | ||
@@ -1029,7 +1042,10 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, | |||
1029 | drm_sysfs_connector_add(connector); | 1042 | drm_sysfs_connector_add(connector); |
1030 | drm_mode_connector_attach_encoder(connector, encoder); | 1043 | drm_mode_connector_attach_encoder(connector, encoder); |
1031 | 1044 | ||
1032 | return 0; | 1045 | if (dp->panel) |
1046 | ret = drm_panel_attach(dp->panel, &dp->connector); | ||
1047 | |||
1048 | return ret; | ||
1033 | } | 1049 | } |
1034 | 1050 | ||
1035 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | 1051 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) |
@@ -1065,6 +1081,13 @@ static void exynos_dp_poweron(struct exynos_drm_display *display) | |||
1065 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) | 1081 | if (dp->dpms_mode == DRM_MODE_DPMS_ON) |
1066 | return; | 1082 | return; |
1067 | 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 | |||
1068 | clk_prepare_enable(dp->clock); | 1091 | clk_prepare_enable(dp->clock); |
1069 | exynos_dp_phy_init(dp); | 1092 | exynos_dp_phy_init(dp); |
1070 | exynos_dp_init_dp(dp); | 1093 | exynos_dp_init_dp(dp); |
@@ -1079,10 +1102,22 @@ static void exynos_dp_poweroff(struct exynos_drm_display *display) | |||
1079 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) | 1102 | if (dp->dpms_mode != DRM_MODE_DPMS_ON) |
1080 | return; | 1103 | return; |
1081 | 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 | |||
1082 | disable_irq(dp->irq); | 1112 | disable_irq(dp->irq); |
1083 | flush_work(&dp->hotplug_work); | 1113 | flush_work(&dp->hotplug_work); |
1084 | exynos_dp_phy_exit(dp); | 1114 | exynos_dp_phy_exit(dp); |
1085 | 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 | } | ||
1086 | } | 1121 | } |
1087 | 1122 | ||
1088 | static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) | 1123 | static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) |
@@ -1215,7 +1250,7 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) | |||
1215 | { | 1250 | { |
1216 | int ret; | 1251 | int ret; |
1217 | 1252 | ||
1218 | ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm, | 1253 | ret = of_get_videomode(dp->dev->of_node, &dp->priv.vm, |
1219 | OF_USE_NATIVE_MODE); | 1254 | OF_USE_NATIVE_MODE); |
1220 | if (ret) { | 1255 | if (ret) { |
1221 | DRM_ERROR("failed: of_get_videomode() : %d\n", ret); | 1256 | DRM_ERROR("failed: of_get_videomode() : %d\n", ret); |
@@ -1229,16 +1264,10 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
1229 | struct platform_device *pdev = to_platform_device(dev); | 1264 | struct platform_device *pdev = to_platform_device(dev); |
1230 | struct drm_device *drm_dev = data; | 1265 | struct drm_device *drm_dev = data; |
1231 | struct resource *res; | 1266 | struct resource *res; |
1232 | struct exynos_dp_device *dp; | 1267 | struct exynos_dp_device *dp = exynos_dp_display.ctx; |
1233 | unsigned int irq_flags; | 1268 | unsigned int irq_flags; |
1234 | |||
1235 | int ret = 0; | 1269 | int ret = 0; |
1236 | 1270 | ||
1237 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | ||
1238 | GFP_KERNEL); | ||
1239 | if (!dp) | ||
1240 | return -ENOMEM; | ||
1241 | |||
1242 | dp->dev = &pdev->dev; | 1271 | dp->dev = &pdev->dev; |
1243 | dp->dpms_mode = DRM_MODE_DPMS_OFF; | 1272 | dp->dpms_mode = DRM_MODE_DPMS_OFF; |
1244 | 1273 | ||
@@ -1250,9 +1279,11 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
1250 | if (ret) | 1279 | if (ret) |
1251 | return ret; | 1280 | return ret; |
1252 | 1281 | ||
1253 | ret = exynos_dp_dt_parse_panel(dp); | 1282 | if (!dp->panel) { |
1254 | if (ret) | 1283 | ret = exynos_dp_dt_parse_panel(dp); |
1255 | return ret; | 1284 | if (ret) |
1285 | return ret; | ||
1286 | } | ||
1256 | 1287 | ||
1257 | dp->clock = devm_clk_get(&pdev->dev, "dp"); | 1288 | dp->clock = devm_clk_get(&pdev->dev, "dp"); |
1258 | if (IS_ERR(dp->clock)) { | 1289 | if (IS_ERR(dp->clock)) { |
@@ -1312,7 +1343,6 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
1312 | disable_irq(dp->irq); | 1343 | disable_irq(dp->irq); |
1313 | 1344 | ||
1314 | dp->drm_dev = drm_dev; | 1345 | dp->drm_dev = drm_dev; |
1315 | exynos_dp_display.ctx = dp; | ||
1316 | 1346 | ||
1317 | platform_set_drvdata(pdev, &exynos_dp_display); | 1347 | platform_set_drvdata(pdev, &exynos_dp_display); |
1318 | 1348 | ||
@@ -1339,6 +1369,9 @@ static const struct component_ops exynos_dp_ops = { | |||
1339 | 1369 | ||
1340 | static int exynos_dp_probe(struct platform_device *pdev) | 1370 | static int exynos_dp_probe(struct platform_device *pdev) |
1341 | { | 1371 | { |
1372 | struct device *dev = &pdev->dev; | ||
1373 | struct device_node *panel_node; | ||
1374 | struct exynos_dp_device *dp; | ||
1342 | int ret; | 1375 | int ret; |
1343 | 1376 | ||
1344 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, | 1377 | ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR, |
@@ -1346,6 +1379,21 @@ static int exynos_dp_probe(struct platform_device *pdev) | |||
1346 | if (ret) | 1379 | if (ret) |
1347 | return ret; | 1380 | return ret; |
1348 | 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 | |||
1349 | ret = component_add(&pdev->dev, &exynos_dp_ops); | 1397 | ret = component_add(&pdev->dev, &exynos_dp_ops); |
1350 | if (ret) | 1398 | if (ret) |
1351 | 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 */ |