Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] cec: add CEC_CAP_NEEDS_HPD

Add a new capability CEC_CAP_NEEDS_HPD. If this capability is set
then the hardware can only use CEC if the HDMI Hotplug Detect pin
is high. Such hardware cannot handle the corner case in the CEC specification
where it is possible to transmit messages even if no hotplug signal is
present (needed for some displays that turn off the HPD when in standby,
but still have CEC enabled).

Typically hardware that needs this capability have the HPD wired to the CEC
block, often to a 'power' or 'active' pin.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
f902c1e9 2613cc6f

+22 -7
+14 -6
drivers/media/cec/cec-adap.c
··· 368 368 * transmit should be canceled. 369 369 */ 370 370 err = wait_event_interruptible_timeout(adap->kthread_waitq, 371 + (adap->needs_hpd && 372 + (!adap->is_configured && !adap->is_configuring)) || 371 373 kthread_should_stop() || 372 374 (!adap->transmitting && 373 375 !list_empty(&adap->transmit_queue)), ··· 385 383 386 384 mutex_lock(&adap->lock); 387 385 388 - if (kthread_should_stop()) { 386 + if ((adap->needs_hpd && 387 + (!adap->is_configured && !adap->is_configuring)) || 388 + kthread_should_stop()) { 389 389 cec_flush(adap); 390 390 goto unlock; 391 391 } ··· 686 682 return -EINVAL; 687 683 } 688 684 if (!adap->is_configured && !adap->is_configuring) { 689 - if (msg->msg[0] != 0xf0) { 685 + if (adap->needs_hpd || msg->msg[0] != 0xf0) { 690 686 dprintk(1, "%s: adapter is unconfigured\n", __func__); 691 687 return -ENONET; 692 688 } ··· 1162 1158 */ 1163 1159 static void cec_adap_unconfigure(struct cec_adapter *adap) 1164 1160 { 1165 - WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); 1161 + if (!adap->needs_hpd || 1162 + adap->phys_addr != CEC_PHYS_ADDR_INVALID) 1163 + WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); 1166 1164 adap->log_addrs.log_addr_mask = 0; 1167 1165 adap->is_configuring = false; 1168 1166 adap->is_configured = false; ··· 1393 1387 if (phys_addr == adap->phys_addr || adap->devnode.unregistered) 1394 1388 return; 1395 1389 1390 + dprintk(1, "new physical address %x.%x.%x.%x\n", 1391 + cec_phys_addr_exp(phys_addr)); 1396 1392 if (phys_addr == CEC_PHYS_ADDR_INVALID || 1397 1393 adap->phys_addr != CEC_PHYS_ADDR_INVALID) { 1398 1394 adap->phys_addr = CEC_PHYS_ADDR_INVALID; ··· 1404 1396 if (adap->monitor_all_cnt) 1405 1397 WARN_ON(call_op(adap, adap_monitor_all_enable, false)); 1406 1398 mutex_lock(&adap->devnode.lock); 1407 - if (list_empty(&adap->devnode.fhs)) 1399 + if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) 1408 1400 WARN_ON(adap->ops->adap_enable(adap, false)); 1409 1401 mutex_unlock(&adap->devnode.lock); 1410 1402 if (phys_addr == CEC_PHYS_ADDR_INVALID) ··· 1412 1404 } 1413 1405 1414 1406 mutex_lock(&adap->devnode.lock); 1415 - if (list_empty(&adap->devnode.fhs) && 1407 + if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) && 1416 1408 adap->ops->adap_enable(adap, true)) { 1417 1409 mutex_unlock(&adap->devnode.lock); 1418 1410 return; ··· 1420 1412 1421 1413 if (adap->monitor_all_cnt && 1422 1414 call_op(adap, adap_monitor_all_enable, true)) { 1423 - if (list_empty(&adap->devnode.fhs)) 1415 + if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) 1424 1416 WARN_ON(adap->ops->adap_enable(adap, false)); 1425 1417 mutex_unlock(&adap->devnode.lock); 1426 1418 return;
+4 -1
drivers/media/cec/cec-api.c
··· 202 202 err = -EPERM; 203 203 else if (adap->is_configuring) 204 204 err = -ENONET; 205 - else if (!adap->is_configured && msg.msg[0] != 0xf0) 205 + else if (!adap->is_configured && 206 + (adap->needs_hpd || msg.msg[0] != 0xf0)) 206 207 err = -ENONET; 207 208 else if (cec_is_busy(adap, fh)) 208 209 err = -EBUSY; ··· 522 521 523 522 mutex_lock(&devnode->lock); 524 523 if (list_empty(&devnode->fhs) && 524 + !adap->needs_hpd && 525 525 adap->phys_addr == CEC_PHYS_ADDR_INVALID) { 526 526 err = adap->ops->adap_enable(adap, true); 527 527 if (err) { ··· 567 565 mutex_lock(&devnode->lock); 568 566 list_del(&fh->list); 569 567 if (list_empty(&devnode->fhs) && 568 + !adap->needs_hpd && 570 569 adap->phys_addr == CEC_PHYS_ADDR_INVALID) { 571 570 WARN_ON(adap->ops->adap_enable(adap, false)); 572 571 }
+1
drivers/media/cec/cec-core.c
··· 230 230 adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; 231 231 adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; 232 232 adap->capabilities = caps; 233 + adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD; 233 234 adap->available_log_addrs = available_las; 234 235 adap->sequence = 0; 235 236 adap->ops = ops;
+1
include/media/cec.h
··· 164 164 u8 available_log_addrs; 165 165 166 166 u16 phys_addr; 167 + bool needs_hpd; 167 168 bool is_configuring; 168 169 bool is_configured; 169 170 u32 monitor_all_cnt;
+2
include/uapi/linux/cec.h
··· 336 336 #define CEC_CAP_RC (1 << 4) 337 337 /* Hardware can monitor all messages, not just directed and broadcast. */ 338 338 #define CEC_CAP_MONITOR_ALL (1 << 5) 339 + /* Hardware can use CEC only if the HDMI HPD pin is high. */ 340 + #define CEC_CAP_NEEDS_HPD (1 << 6) 339 341 340 342 /** 341 343 * struct cec_caps - CEC capabilities structure.