diff options
Diffstat (limited to 'drivers/gpu/drm/i2c/tda998x_drv.c')
-rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 114 |
1 files changed, 105 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index fddac4c84c28..c9882246d81f 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/hdmi.h> | 20 | #include <linux/hdmi.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/irq.h> | ||
22 | #include <sound/asoundef.h> | 23 | #include <sound/asoundef.h> |
23 | 24 | ||
24 | #include <drm/drmP.h> | 25 | #include <drm/drmP.h> |
@@ -40,6 +41,10 @@ struct tda998x_priv { | |||
40 | u8 vip_cntrl_1; | 41 | u8 vip_cntrl_1; |
41 | u8 vip_cntrl_2; | 42 | u8 vip_cntrl_2; |
42 | struct tda998x_encoder_params params; | 43 | struct tda998x_encoder_params params; |
44 | |||
45 | wait_queue_head_t wq_edid; | ||
46 | volatile int wq_edid_wait; | ||
47 | struct drm_encoder *encoder; | ||
43 | }; | 48 | }; |
44 | 49 | ||
45 | #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) | 50 | #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) |
@@ -306,11 +311,16 @@ struct tda998x_priv { | |||
306 | 311 | ||
307 | /* CEC registers: (not paged) | 312 | /* CEC registers: (not paged) |
308 | */ | 313 | */ |
314 | #define REG_CEC_INTSTATUS 0xee /* read */ | ||
315 | # define CEC_INTSTATUS_CEC (1 << 0) | ||
316 | # define CEC_INTSTATUS_HDMI (1 << 1) | ||
309 | #define REG_CEC_FRO_IM_CLK_CTRL 0xfb /* read/write */ | 317 | #define REG_CEC_FRO_IM_CLK_CTRL 0xfb /* read/write */ |
310 | # define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7) | 318 | # define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7) |
311 | # define CEC_FRO_IM_CLK_CTRL_ENA_OTP (1 << 6) | 319 | # define CEC_FRO_IM_CLK_CTRL_ENA_OTP (1 << 6) |
312 | # define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1) | 320 | # define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1) |
313 | # define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0) | 321 | # define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0) |
322 | #define REG_CEC_RXSHPDINTENA 0xfc /* read/write */ | ||
323 | #define REG_CEC_RXSHPDINT 0xfd /* read */ | ||
314 | #define REG_CEC_RXSHPDLEV 0xfe /* read */ | 324 | #define REG_CEC_RXSHPDLEV 0xfe /* read */ |
315 | # define CEC_RXSHPDLEV_RXSENS (1 << 0) | 325 | # define CEC_RXSHPDLEV_RXSENS (1 << 0) |
316 | # define CEC_RXSHPDLEV_HPD (1 << 1) | 326 | # define CEC_RXSHPDLEV_HPD (1 << 1) |
@@ -524,6 +534,35 @@ tda998x_reset(struct tda998x_priv *priv) | |||
524 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); | 534 | reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); |
525 | } | 535 | } |
526 | 536 | ||
537 | /* | ||
538 | * only 2 interrupts may occur: screen plug/unplug and EDID read | ||
539 | */ | ||
540 | static irqreturn_t tda998x_irq_thread(int irq, void *data) | ||
541 | { | ||
542 | struct tda998x_priv *priv = data; | ||
543 | u8 sta, cec, lvl, flag0, flag1, flag2; | ||
544 | |||
545 | if (!priv) | ||
546 | return IRQ_HANDLED; | ||
547 | sta = cec_read(priv, REG_CEC_INTSTATUS); | ||
548 | cec = cec_read(priv, REG_CEC_RXSHPDINT); | ||
549 | lvl = cec_read(priv, REG_CEC_RXSHPDLEV); | ||
550 | flag0 = reg_read(priv, REG_INT_FLAGS_0); | ||
551 | flag1 = reg_read(priv, REG_INT_FLAGS_1); | ||
552 | flag2 = reg_read(priv, REG_INT_FLAGS_2); | ||
553 | DRM_DEBUG_DRIVER( | ||
554 | "tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n", | ||
555 | sta, cec, lvl, flag0, flag1, flag2); | ||
556 | if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) { | ||
557 | priv->wq_edid_wait = 0; | ||
558 | wake_up(&priv->wq_edid); | ||
559 | } else if (cec != 0) { /* HPD change */ | ||
560 | if (priv->encoder && priv->encoder->dev) | ||
561 | drm_helper_hpd_irq_event(priv->encoder->dev); | ||
562 | } | ||
563 | return IRQ_HANDLED; | ||
564 | } | ||
565 | |||
527 | static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes) | 566 | static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes) |
528 | { | 567 | { |
529 | uint8_t sum = 0; | 568 | uint8_t sum = 0; |
@@ -994,23 +1033,36 @@ read_edid_block(struct drm_encoder *encoder, uint8_t *buf, int blk) | |||
994 | reg_write(priv, REG_DDC_SEGM, segptr); | 1033 | reg_write(priv, REG_DDC_SEGM, segptr); |
995 | 1034 | ||
996 | /* enable reading EDID: */ | 1035 | /* enable reading EDID: */ |
1036 | priv->wq_edid_wait = 1; | ||
997 | reg_write(priv, REG_EDID_CTRL, 0x1); | 1037 | reg_write(priv, REG_EDID_CTRL, 0x1); |
998 | 1038 | ||
999 | /* flag must be cleared by sw: */ | 1039 | /* flag must be cleared by sw: */ |
1000 | reg_write(priv, REG_EDID_CTRL, 0x0); | 1040 | reg_write(priv, REG_EDID_CTRL, 0x0); |
1001 | 1041 | ||
1002 | /* wait for block read to complete: */ | 1042 | /* wait for block read to complete: */ |
1003 | for (i = 100; i > 0; i--) { | 1043 | if (priv->hdmi->irq) { |
1004 | ret = reg_read(priv, REG_INT_FLAGS_2); | 1044 | i = wait_event_timeout(priv->wq_edid, |
1005 | if (ret < 0) | 1045 | !priv->wq_edid_wait, |
1006 | return ret; | 1046 | msecs_to_jiffies(100)); |
1007 | if (ret & INT_FLAGS_2_EDID_BLK_RD) | 1047 | if (i < 0) { |
1008 | break; | 1048 | dev_err(encoder->dev->dev, "read edid wait err %d\n", i); |
1009 | msleep(1); | 1049 | return i; |
1050 | } | ||
1051 | } else { | ||
1052 | for (i = 10; i > 0; i--) { | ||
1053 | msleep(10); | ||
1054 | ret = reg_read(priv, REG_INT_FLAGS_2); | ||
1055 | if (ret < 0) | ||
1056 | return ret; | ||
1057 | if (ret & INT_FLAGS_2_EDID_BLK_RD) | ||
1058 | break; | ||
1059 | } | ||
1010 | } | 1060 | } |
1011 | 1061 | ||
1012 | if (i == 0) | 1062 | if (i == 0) { |
1063 | dev_err(encoder->dev->dev, "read edid timeout\n"); | ||
1013 | return -ETIMEDOUT; | 1064 | return -ETIMEDOUT; |
1065 | } | ||
1014 | 1066 | ||
1015 | ret = reg_read_range(priv, REG_EDID_DATA_0, buf, EDID_LENGTH); | 1067 | ret = reg_read_range(priv, REG_EDID_DATA_0, buf, EDID_LENGTH); |
1016 | if (ret != EDID_LENGTH) { | 1068 | if (ret != EDID_LENGTH) { |
@@ -1108,7 +1160,13 @@ static int | |||
1108 | tda998x_encoder_create_resources(struct drm_encoder *encoder, | 1160 | tda998x_encoder_create_resources(struct drm_encoder *encoder, |
1109 | struct drm_connector *connector) | 1161 | struct drm_connector *connector) |
1110 | { | 1162 | { |
1111 | DBG(""); | 1163 | struct tda998x_priv *priv = to_tda998x_priv(encoder); |
1164 | |||
1165 | if (priv->hdmi->irq) | ||
1166 | connector->polled = DRM_CONNECTOR_POLL_HPD; | ||
1167 | else | ||
1168 | connector->polled = DRM_CONNECTOR_POLL_CONNECT | | ||
1169 | DRM_CONNECTOR_POLL_DISCONNECT; | ||
1112 | return 0; | 1170 | return 0; |
1113 | } | 1171 | } |
1114 | 1172 | ||
@@ -1127,6 +1185,13 @@ tda998x_encoder_destroy(struct drm_encoder *encoder) | |||
1127 | { | 1185 | { |
1128 | struct tda998x_priv *priv = to_tda998x_priv(encoder); | 1186 | struct tda998x_priv *priv = to_tda998x_priv(encoder); |
1129 | drm_i2c_encoder_destroy(encoder); | 1187 | drm_i2c_encoder_destroy(encoder); |
1188 | |||
1189 | /* disable all IRQs and free the IRQ handler */ | ||
1190 | cec_write(priv, REG_CEC_RXSHPDINTENA, 0); | ||
1191 | reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); | ||
1192 | if (priv->hdmi->irq) | ||
1193 | free_irq(priv->hdmi->irq, priv); | ||
1194 | |||
1130 | if (priv->cec) | 1195 | if (priv->cec) |
1131 | i2c_unregister_device(priv->cec); | 1196 | i2c_unregister_device(priv->cec); |
1132 | kfree(priv); | 1197 | kfree(priv); |
@@ -1186,6 +1251,8 @@ tda998x_encoder_init(struct i2c_client *client, | |||
1186 | kfree(priv); | 1251 | kfree(priv); |
1187 | return -ENODEV; | 1252 | return -ENODEV; |
1188 | } | 1253 | } |
1254 | |||
1255 | priv->encoder = &encoder_slave->base; | ||
1189 | priv->dpms = DRM_MODE_DPMS_OFF; | 1256 | priv->dpms = DRM_MODE_DPMS_OFF; |
1190 | 1257 | ||
1191 | encoder_slave->slave_priv = priv; | 1258 | encoder_slave->slave_priv = priv; |
@@ -1242,6 +1309,35 @@ tda998x_encoder_init(struct i2c_client *client, | |||
1242 | cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL, | 1309 | cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL, |
1243 | CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL); | 1310 | CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL); |
1244 | 1311 | ||
1312 | /* initialize the optional IRQ */ | ||
1313 | if (client->irq) { | ||
1314 | int irqf_trigger; | ||
1315 | |||
1316 | /* init read EDID waitqueue */ | ||
1317 | init_waitqueue_head(&priv->wq_edid); | ||
1318 | |||
1319 | /* clear pending interrupts */ | ||
1320 | reg_read(priv, REG_INT_FLAGS_0); | ||
1321 | reg_read(priv, REG_INT_FLAGS_1); | ||
1322 | reg_read(priv, REG_INT_FLAGS_2); | ||
1323 | |||
1324 | irqf_trigger = | ||
1325 | irqd_get_trigger_type(irq_get_irq_data(client->irq)); | ||
1326 | ret = request_threaded_irq(client->irq, NULL, | ||
1327 | tda998x_irq_thread, | ||
1328 | irqf_trigger | IRQF_ONESHOT, | ||
1329 | "tda998x", priv); | ||
1330 | if (ret) { | ||
1331 | dev_err(&client->dev, | ||
1332 | "failed to request IRQ#%u: %d\n", | ||
1333 | client->irq, ret); | ||
1334 | goto fail; | ||
1335 | } | ||
1336 | |||
1337 | /* enable HPD irq */ | ||
1338 | cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD); | ||
1339 | } | ||
1340 | |||
1245 | /* enable EDID read irq: */ | 1341 | /* enable EDID read irq: */ |
1246 | reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); | 1342 | reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); |
1247 | 1343 | ||