aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoungJun Cho <yj44.cho@samsung.com>2014-07-22 06:49:44 -0400
committerInki Dae <daeinki@gmail.com>2014-08-03 03:52:15 -0400
commite17ddecc3aa519b7e59edf490e34ac036be1f8b8 (patch)
tree71e40c5b1419488e4506437dc735948a1fa207e5
parent5595d4d821033d4d7c4cc394b3bbc76b020f0342 (diff)
drm/exynos: dsi: add TE interrupt handler to support LCD I80 interface
This is a temporary solution and should be made by more generic way. To support LCD I80 interface, the DSI host should register TE interrupt handler from the TE GPIO of attached panel. So the panel generates a tearing effect synchronization signal then the DSI host calls the CRTC device manager to trigger to transfer video image. Signed-off-by: YoungJun Cho <yj44.cho@samsung.com> Acked-by: Inki Dae <inki.dae@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Inki Dae <inki.dae@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 58bfb2a2a19b..a19107af1c3b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -16,7 +16,9 @@
16#include <drm/drm_panel.h> 16#include <drm/drm_panel.h>
17 17
18#include <linux/clk.h> 18#include <linux/clk.h>
19#include <linux/gpio/consumer.h>
19#include <linux/irq.h> 20#include <linux/irq.h>
21#include <linux/of_gpio.h>
20#include <linux/phy/phy.h> 22#include <linux/phy/phy.h>
21#include <linux/regulator/consumer.h> 23#include <linux/regulator/consumer.h>
22#include <linux/component.h> 24#include <linux/component.h>
@@ -24,6 +26,7 @@
24#include <video/mipi_display.h> 26#include <video/mipi_display.h>
25#include <video/videomode.h> 27#include <video/videomode.h>
26 28
29#include "exynos_drm_crtc.h"
27#include "exynos_drm_drv.h" 30#include "exynos_drm_drv.h"
28 31
29/* returns true iff both arguments logically differs */ 32/* returns true iff both arguments logically differs */
@@ -247,6 +250,7 @@ struct exynos_dsi {
247 struct clk *bus_clk; 250 struct clk *bus_clk;
248 struct regulator_bulk_data supplies[2]; 251 struct regulator_bulk_data supplies[2];
249 int irq; 252 int irq;
253 int te_gpio;
250 254
251 u32 pll_clk_rate; 255 u32 pll_clk_rate;
252 u32 burst_clk_rate; 256 u32 burst_clk_rate;
@@ -954,17 +958,89 @@ static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
954 return IRQ_HANDLED; 958 return IRQ_HANDLED;
955} 959}
956 960
961static irqreturn_t exynos_dsi_te_irq_handler(int irq, void *dev_id)
962{
963 struct exynos_dsi *dsi = (struct exynos_dsi *)dev_id;
964 struct drm_encoder *encoder = dsi->encoder;
965
966 if (dsi->state & DSIM_STATE_ENABLED)
967 exynos_drm_crtc_te_handler(encoder->crtc);
968
969 return IRQ_HANDLED;
970}
971
972static void exynos_dsi_enable_irq(struct exynos_dsi *dsi)
973{
974 enable_irq(dsi->irq);
975
976 if (gpio_is_valid(dsi->te_gpio))
977 enable_irq(gpio_to_irq(dsi->te_gpio));
978}
979
980static void exynos_dsi_disable_irq(struct exynos_dsi *dsi)
981{
982 if (gpio_is_valid(dsi->te_gpio))
983 disable_irq(gpio_to_irq(dsi->te_gpio));
984
985 disable_irq(dsi->irq);
986}
987
957static int exynos_dsi_init(struct exynos_dsi *dsi) 988static int exynos_dsi_init(struct exynos_dsi *dsi)
958{ 989{
959 exynos_dsi_enable_clock(dsi); 990 exynos_dsi_enable_clock(dsi);
960 exynos_dsi_reset(dsi); 991 exynos_dsi_reset(dsi);
961 enable_irq(dsi->irq); 992 exynos_dsi_enable_irq(dsi);
962 exynos_dsi_wait_for_reset(dsi); 993 exynos_dsi_wait_for_reset(dsi);
963 exynos_dsi_init_link(dsi); 994 exynos_dsi_init_link(dsi);
964 995
965 return 0; 996 return 0;
966} 997}
967 998
999static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi)
1000{
1001 int ret;
1002
1003 dsi->te_gpio = of_get_named_gpio(dsi->panel_node, "te-gpios", 0);
1004 if (!gpio_is_valid(dsi->te_gpio)) {
1005 dev_err(dsi->dev, "no te-gpios specified\n");
1006 ret = dsi->te_gpio;
1007 goto out;
1008 }
1009
1010 ret = gpio_request_one(dsi->te_gpio, GPIOF_IN, "te_gpio");
1011 if (ret) {
1012 dev_err(dsi->dev, "gpio request failed with %d\n", ret);
1013 goto out;
1014 }
1015
1016 /*
1017 * This TE GPIO IRQ should not be set to IRQ_NOAUTOEN, because panel
1018 * calls drm_panel_init() first then calls mipi_dsi_attach() in probe().
1019 * It means that te_gpio is invalid when exynos_dsi_enable_irq() is
1020 * called by drm_panel_init() before panel is attached.
1021 */
1022 ret = request_threaded_irq(gpio_to_irq(dsi->te_gpio),
1023 exynos_dsi_te_irq_handler, NULL,
1024 IRQF_TRIGGER_RISING, "TE", dsi);
1025 if (ret) {
1026 dev_err(dsi->dev, "request interrupt failed with %d\n", ret);
1027 gpio_free(dsi->te_gpio);
1028 goto out;
1029 }
1030
1031out:
1032 return ret;
1033}
1034
1035static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi)
1036{
1037 if (gpio_is_valid(dsi->te_gpio)) {
1038 free_irq(gpio_to_irq(dsi->te_gpio), dsi);
1039 gpio_free(dsi->te_gpio);
1040 dsi->te_gpio = -ENOENT;
1041 }
1042}
1043
968static int exynos_dsi_host_attach(struct mipi_dsi_host *host, 1044static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
969 struct mipi_dsi_device *device) 1045 struct mipi_dsi_device *device)
970{ 1046{
@@ -978,6 +1054,19 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
978 if (dsi->connector.dev) 1054 if (dsi->connector.dev)
979 drm_helper_hpd_irq_event(dsi->connector.dev); 1055 drm_helper_hpd_irq_event(dsi->connector.dev);
980 1056
1057 /*
1058 * This is a temporary solution and should be made by more generic way.
1059 *
1060 * If attached panel device is for command mode one, dsi should register
1061 * TE interrupt handler.
1062 */
1063 if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO)) {
1064 int ret = exynos_dsi_register_te_irq(dsi);
1065
1066 if (ret)
1067 return ret;
1068 }
1069
981 return 0; 1070 return 0;
982} 1071}
983 1072
@@ -986,6 +1075,8 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
986{ 1075{
987 struct exynos_dsi *dsi = host_to_dsi(host); 1076 struct exynos_dsi *dsi = host_to_dsi(host);
988 1077
1078 exynos_dsi_unregister_te_irq(dsi);
1079
989 dsi->panel_node = NULL; 1080 dsi->panel_node = NULL;
990 1081
991 if (dsi->connector.dev) 1082 if (dsi->connector.dev)
@@ -1099,7 +1190,7 @@ static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
1099 1190
1100 exynos_dsi_disable_clock(dsi); 1191 exynos_dsi_disable_clock(dsi);
1101 1192
1102 disable_irq(dsi->irq); 1193 exynos_dsi_disable_irq(dsi);
1103 } 1194 }
1104 1195
1105 dsi->state &= ~DSIM_STATE_CMD_LPM; 1196 dsi->state &= ~DSIM_STATE_CMD_LPM;
@@ -1445,6 +1536,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
1445 goto err_del_component; 1536 goto err_del_component;
1446 } 1537 }
1447 1538
1539 /* To be checked as invalid one */
1540 dsi->te_gpio = -ENOENT;
1541
1448 init_completion(&dsi->completed); 1542 init_completion(&dsi->completed);
1449 spin_lock_init(&dsi->transfer_lock); 1543 spin_lock_init(&dsi->transfer_lock);
1450 INIT_LIST_HEAD(&dsi->transfer_list); 1544 INIT_LIST_HEAD(&dsi->transfer_list);