Synopsys Designware HDMI Video Capture Controller + PHY
Subsystems (2)
v2 cover Synopsys Designware HDMI Video Capture Controller + PHY
The Synopsys Designware HDMI RX controller is an HDMI receiver controller that is responsible to process digital data that comes from a phy. The final result is a stream of raw video data that can then be connected to a video DMA, for example, and transfered into RAM so that it can be displayed.
The controller + phy available in this series natively support all HDMI 1.4 and HDMI 2.0 modes, including deep color. Although, the driver is quite in its initial stage and unfortunatelly only non deep color modes are supported. Also, audio is not yet supported in the driver (the controller has several audio output interfaces).
Version 2 is just a respin of the previous version with some minor bug fixes in the controller driver and I also added CEC support.
This series was tested in a FPGA platform.
Jose Abreu (4):
[media] platform: Add Synopsys Designware HDMI RX PHY e405 Driver [media] platform: Add Synopsys Designware HDMI RX Controller Driver
MAINTAINERS: Add entry for Synopsys Designware HDMI drivers
dt-bindings: media: Document Synopsys Designware HDMI RX
.../devicetree/bindings/media/snps,dw-hdmi-rx.txt | 41 + MAINTAINERS | 7 + drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 2 + drivers/media/platform/dwc/Kconfig | 18 + drivers/media/platform/dwc/Makefile | 2 + drivers/media/platform/dwc/dw-hdmi-phy-e405.c | 783 +++++++++ drivers/media/platform/dwc/dw-hdmi-phy-e405.h | 63 + drivers/media/platform/dwc/dw-hdmi-rx.c | 1764 ++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-rx.h | 435 +++++ include/media/dwc/dw-hdmi-phy-pdata.h | 131 ++ include/media/dwc/dw-hdmi-rx-pdata.h | 63 + 12 files changed, 3311 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.txt create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefile create mode 100644 drivers/media/platform/dwc/dw-hdmi-phy-e405.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-phy-e405.h create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.h create mode 100644 include/media/dwc/dw-hdmi-phy-pdata.h create mode 100644 include/media/dwc/dw-hdmi-rx-pdata.h
Signature · 1 line
1.9.1
PATCH v2 1/4 platform: Add Synopsys Designware HDMI RX PHY e405 Driver
This adds support for the Synopsys Designware HDMI RX PHY e405. This phy receives and decodes HDMI video that is delivered to a controller.
Main features included in this driver are:
- Equalizer algorithm that chooses the phy best settings according to the detected HDMI cable characteristics.
- Support for scrambling
- Support for HDMI 2.0 modes up to 6G (HDMI 4k@60Hz).
The driver was implemented as a standalone V4L2 subdevice and the phy interface with the controller was implemented using V4L2 ioctls. I do not know if this is the best option but it is not possible to use the existing API functions directly as we need specific functions that will be called by the controller at specific configuration stages.
There is also a bidirectional communication between controller and phy:
The phy must provide functions that the controller will call (i.e. configuration functions) and the controller must provide read/write callbacks, as well as other specific functions.
Changes from RFC:
- Remove a bunch of functions that can be collapsed into a single config() function
- Add comments for the callbacks and structures (Hans)
--- drivers/media/platform/Kconfig | 2 + drivers/media/platform/Makefile | 2 + drivers/media/platform/dwc/Kconfig | 8 + drivers/media/platform/dwc/Makefile | 1 + drivers/media/platform/dwc/dw-hdmi-phy-e405.c | 783 ++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-phy-e405.h | 63 +++ include/media/dwc/dw-hdmi-phy-pdata.h | 131 +++++ 7 files changed, 990 insertions(+) create mode 100644 drivers/media/platform/dwc/Kconfig create mode 100644 drivers/media/platform/dwc/Makefile create mode 100644 drivers/media/platform/dwc/dw-hdmi-phy-e405.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-phy-e405.h create mode 100644 include/media/dwc/dw-hdmi-phy-pdata.h
drivers/media/platform/Kconfig +2 -0
@@ -33,6 +33,8 @@ source "drivers/media/platform/omap/Kconfig" source "drivers/media/platform/blackfin/Kconfig" +source "drivers/media/platform/dwc/Kconfig" + config VIDEO_SH_VOU tristate "SuperH VOU video output driver" depends on MEDIA_CAMERA_SUPPORT
drivers/media/platform/Makefile +2 -0
@@ -79,3 +79,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/ obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/ + +obj-y += dwc/
drivers/media/platform/dwc/Kconfig new file +8 -0
@@ -0,0 +1,8 @@ +config VIDEO_DWC_HDMI_PHY_E405 + tristate "Synopsys Designware HDMI RX PHY e405 driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + help + Support for Synopsys Designware HDMI RX PHY. Version is e405. + + To compile this driver as a module, choose M here. The module + will be called dw-hdmi-phy-e405.
drivers/media/platform/dwc/Makefile new file +1 -0
@@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_DWC_HDMI_PHY_E405) += dw-hdmi-phy-e405.o
drivers/media/platform/dwc/dw-hdmi-phy-e405.c new file +783 -0
783 lines not on this page · raw message
drivers/media/platform/dwc/dw-hdmi-phy-e405.h new file +63 -0
63 lines not on this page · raw message
include/media/dwc/dw-hdmi-phy-pdata.h new file +131 -0
131 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v2 2/4 platform: Add Synopsys Designware HDMI RX Controller Driver
In reply to Jose AbreuThis is an initial submission for the Synopsys Designware HDMI RX Controller Driver. This driver interacts with a phy driver so that a communication between them is created and a video pipeline is configured.
The controller + phy pipeline can then be integrated into a fully featured system that can be able to receive video up to 4k@60Hz with deep color 48bit RGB, depending on the platform. Although, this initial version does not yet handle deep color modes.
This driver was implemented as a standard V4L2 subdevice and its main features are:
- Internal state machine that reconfigures phy until the video is not stable
- JTAG communication with phy
- Inter-module communication with phy driver
- Debug write/read ioctls
Some notes:
- RX sense controller (cable connection/disconnection) must be handled by the platform wrapper as this is not integrated into the controller RTL
- The same goes for EDID ROM's
- ZCAL calibration is needed only in FPGA platforms, in ASIC this is not needed
- The state machine is not an ideal solution as it creates a kthread but it is needed because some sources might not be very stable at sending the video (i.e. we must react accordingly).
Changes from v1:
- Added support for CEC
- Correct typo errors
- Correctly detect interlaced video modes
- Correct VIC parsing
Changes from RFC:
- Added support for HDCP 1.4
- Fixup HDMI_VIC not being parsed (Hans)
- Send source change signal when powering off (Hans)
- Added a "wait stable delay"
- Detect interlaced video modes (Hans)
- Restrain g/s_register from reading/writing to HDCP regs (Hans)
--- drivers/media/platform/dwc/Kconfig | 10 + drivers/media/platform/dwc/Makefile | 1 + drivers/media/platform/dwc/dw-hdmi-rx.c | 1764 +++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-rx.h | 435 ++++++++ include/media/dwc/dw-hdmi-rx-pdata.h | 63 ++ 5 files changed, 2273 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.h create mode 100644 include/media/dwc/dw-hdmi-rx-pdata.h
drivers/media/platform/dwc/Kconfig +10 -0
@@ -6,3 +6,13 @@ config VIDEO_DWC_HDMI_PHY_E405 To compile this driver as a module, choose M here. The module will be called dw-hdmi-phy-e405. + +config VIDEO_DWC_HDMI_RX + tristate "Synopsys Designware HDMI Receiver driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select CEC_CORE + help + Support for Synopsys Designware HDMI RX controller. + + To compile this driver as a module, choose M here. The module + will be called dw-hdmi-rx.
drivers/media/platform/dwc/Makefile +1 -0
@@ -1 +1,2 @@ obj-$(CONFIG_VIDEO_DWC_HDMI_PHY_E405) += dw-hdmi-phy-e405.o +obj-$(CONFIG_VIDEO_DWC_HDMI_RX) += dw-hdmi-rx.o
drivers/media/platform/dwc/dw-hdmi-rx.c new file +1764 -0
1,764 lines not on this page · raw message
drivers/media/platform/dwc/dw-hdmi-rx.h new file +435 -0
435 lines not on this page · raw message
include/media/dwc/dw-hdmi-rx-pdata.h new file +63 -0
63 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v2 2/4] [media] platform: Add Synopsys Designware HDMI RX Controller Driver
Hi Jose,
Just a quick review of the new CEC code:
Quoted 67 lines · Jose Abreu
This is an initial submission for the Synopsys Designware HDMI RX Controller Driver. This driver interacts with a phy driver so that a communication between them is created and a video pipeline is configured.
The controller + phy pipeline can then be integrated into a fully featured system that can be able to receive video up to 4k@60Hz with deep color 48bit RGB, depending on the platform. Although, this initial version does not yet handle deep color modes.
This driver was implemented as a standard V4L2 subdevice and its main features are:
- Internal state machine that reconfigures phy until the video is not stable
- JTAG communication with phy
- Inter-module communication with phy driver
- Debug write/read ioctlsSome notes:
- RX sense controller (cable connection/disconnection) must be handled by the platform wrapper as this is not integrated into the controller RTL
- The same goes for EDID ROM's
- ZCAL calibration is needed only in FPGA platforms, in ASIC this is not needed
- The state machine is not an ideal solution as it creates a kthread but it is needed because some sources might not be very stable at sending the video (i.e. we must react accordingly).Signed-off-by Jose Abreu <[email protected]>Cc Carlos Palminha <[email protected]>Cc Mauro Carvalho Chehab <[email protected]>Cc Hans Verkuil <[email protected]>Changes from v1:
- Added support for CEC
- Correct typo errors
- Correctly detect interlaced video modes
- Correct VIC parsing
Changes from RFC:
- Added support for HDCP 1.4
- FixupHDMI_VICnot being parsed (Hans)
- Send source change signal when powering off (Hans)
- Added a "wait stable delay"
- Detect interlaced video modes (Hans)
- Restrain g/s_register from reading/writing to HDCP regs (Hans)Signed-off-by Jose Abreu <[email protected]>--- drivers/media/platform/dwc/Kconfig | 10 + drivers/media/platform/dwc/Makefile | 1 + drivers/media/platform/dwc/dw-hdmi-rx.c | 1764 +++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-rx.h | 435 ++++++++ include/media/dwc/dw-hdmi-rx-pdata.h | 63 ++ 5 files changed, 2273 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.h create mode 100644 include/media/dwc/dw-hdmi-rx-pdata.hdrivers/media/platform/dwc/Kconfig +0
-0@@ -6,3 +6,13 @@ config VIDEO_DWC_HDMI_PHY_E405 To compile this driver as a module, choose M here. The module will be called dw-hdmi-phy-e405.
drivers/media/platform/dwc/Kconfig config VIDEO_DWC_HDMI_PHY_E405 · line 18
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ +config VIDEO_DWC_HDMI_RX + tristate "Synopsys Designware HDMI Receiver driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select CEC_CORE + help + Support for Synopsys Designware HDMI RX controller. + + To compile this driver as a module, choose M here. The module + will be called dw-hdmi-rx.
Add a separate config VIDEO_DWC_HDMI_RX_CEC to explicitly enable CEC. CEC is an optional component of HDMI and supporting CEC should be something you select in the kernel config.
<snip>
General question: is this CEC IP the same IP as is used in the HDMI transmitter? If so, then it is not a good idea to duplicate the code.
If they are different, then that should be noted in the source.
Quoted 51 lines
drivers/media/platform/dwc/Kconfig +50
-0+static void dw_hdmi_cec_enable_ints(struct dw_hdmi_dev *dw_dev) +{ + u32 mask = HDMI_AUD_CEC_ISTS_DONE | HDMI_AUD_CEC_ISTS_EOM | + HDMI_AUD_CEC_ISTS_NACK | HDMI_AUD_CEC_ISTS_ARBLST | + HDMI_AUD_CEC_ISTS_ERROR_INIT | HDMI_AUD_CEC_ISTS_ERROR_FOLL; + + hdmi_writel(dw_dev, mask, HDMI_AUD_CEC_IEN_SET); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_disable_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_IEN_CLR); + hdmi_writel(dw_dev, ~0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_clear_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_ICLR); +} + +static void dw_hdmi_cec_tx_raw_status(struct dw_hdmi_dev *dw_dev, u32 stat) +{ + u32 error_mask = HDMI_AUD_CEC_ISTS_NACK | + HDMI_AUD_CEC_ISTS_ERROR_INIT; + + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_dbg(dw_dev->dev, "%s: tx is busy\n", __func__); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_ARBLST) { + dev_dbg(dw_dev->dev, "%s: arbitration lost\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_ARB_LOST, + 1, 0, 0, 0); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_DONE) { + dev_dbg(dw_dev->dev, "%s: transmission done\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); + return; + } + + if (stat & error_mask) { + /* If we reached here we have an error */ + u8 status = 0, nack_cnt = 0, error_cnt = 0; + + dev_dbg(dw_dev->dev, "%s: error found (stat=0x%x)\n", __func__, + stat);
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ + if (stat & HDMI_AUD_CEC_ISTS_NACK) { + status |= CEC_TX_STATUS_NACK; + nack_cnt++; + } + + if (stat & HDMI_AUD_CEC_ISTS_ERROR_INIT) { + status |= CEC_TX_STATUS_ERROR; + error_cnt++; + }
What does it mean if you have both NACK and ERROR_INIT flags set? Is that an error or a NACK? You have to chose here which one you pick when calling cec_transmit_done.
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ + cec_transmit_done(dw_dev->cec_adap, status, 0, nack_cnt, 0, + error_cnt); + return; + }
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static void dw_hdmi_cec_received_msg(struct dw_hdmi_dev *dw_dev) +{ + struct cec_msg msg; + u8 i; + + msg.len = hdmi_readl(dw_dev, HDMI_CEC_RX_CNT); + if (!msg.len || msg.len > HDMI_CEC_RX_DATA_MAX) + return; /* its an invalid/non-existent message */
it's
Quoted 22 lines
drivers/media/platform/dwc/Kconfig +22
-0+ + for (i = 0; i < msg.len; i++) + msg.msg[i] = hdmi_readl(dw_dev, HDMI_CEC_RX_DATA(i)); + + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + cec_received_msg(dw_dev->cec_adap, &msg); +} + +static int dw_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + + if (!dw_dev->cec_enabled_adap && enable) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + dw_hdmi_cec_enable_ints(dw_dev); + } else if (dw_dev->cec_enabled_adap && !enable) { + dw_hdmi_cec_disable_ints(dw_dev); + dw_dev->cec_valid_addrs = 0; + } + + dw_dev->cec_enabled_adap = enable; + return 0;
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static int dw_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + int i, free_idx = HDMI_CEC_MAX_LOG_ADDRS; + u32 tmp; + + if (!dw_dev->cec_enabled_adap) + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;
This can't be called unless the adapter is enabled. So this check can be removed.
Quoted 25 lines
drivers/media/platform/dwc/Kconfig +25
-0+ + if (addr == CEC_LOG_ADDR_INVALID) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_L); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_H); + dw_dev->cec_valid_addrs = 0; + return 0; + } + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (free_idx == HDMI_CEC_MAX_LOG_ADDRS && !is_valid) + free_idx = i; + if (is_valid && dw_dev->cec_addr[i] == addr) + return 0; + } + + if (i == HDMI_CEC_MAX_LOG_ADDRS) { + i = free_idx; + if (i == HDMI_CEC_MAX_LOG_ADDRS) + return -ENXIO; + } + + dw_dev->cec_addr[i] = addr; + dw_dev->cec_valid_addrs |= 1 << i;
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ + if (i >= 8) { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_H); + tmp |= BIT(i - 8); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_H); + } else { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_L); + tmp |= BIT(i); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_L); + }
This seems overengineered. HDMI_CEC_ADDR_H/L is just a bitmask, so just set the bit corresponding to addr. I'm not sure what the point of cec_addr[] and cec_valid_addrs is.
Quoted 6 lines
drivers/media/platform/dwc/Kconfig +6
-0+ + return 0; +} + +static int dw_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg)
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + u8 len = msg->len; + u32 reg; + int i; + + if (len > HDMI_CEC_TX_DATA_MAX) { + dev_err(dw_dev->dev, "%s: invalid len (%d)\n", __func__, len); + return -EINVAL; + }
Can't happen.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_err(dw_dev->dev, "%s: tx is busy\n", __func__); + return -EBUSY;
This should never happen, but it doesn't hurt to check.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ } + + for (i = 0; i < HDMI_CEC_TX_DATA_MAX; i++) + hdmi_writel(dw_dev, 0x0, HDMI_CEC_TX_DATA(i));
Why clear this? Is it necessary?
drivers/media/platform/dwc/Kconfig
Quoted 11 lines
drivers/media/platform/dwc/Kconfig +11
-0+ for (i = 0; i < len; i++) + hdmi_writel(dw_dev, msg->msg[i], HDMI_CEC_TX_DATA(i)); + + switch (signal_free_time) { + case 3: + reg = 0x0; + break; + case 7: + reg = 0x2; + break; + case 5:
Use the defines in media/cec.h instead of hardcoding these values.
Quoted 20 lines
drivers/media/platform/dwc/Kconfig +20
-0+ default: + reg = 0x1; + break; + } + + hdmi_writel(dw_dev, len, HDMI_CEC_TX_CNT); + hdmi_mask_writel(dw_dev, reg, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_FRAME_TYP_OFFSET, + HDMI_CEC_CTRL_FRAME_TYP_MASK); + hdmi_mask_writel(dw_dev, 0x1, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_SEND_OFFSET, + HDMI_CEC_CTRL_SEND_MASK); + return 0; +} + +static const struct cec_adap_ops dw_hdmi_cec_adap_ops = { + .adap_enable = dw_hdmi_cec_adap_enable, + .adap_log_addr = dw_hdmi_cec_adap_log_addr, + .adap_transmit = dw_hdmi_cec_adap_transmit, +};
<snip>
Quoted 19 lines
drivers/media/platform/dwc/Kconfig +19
-0+static int dw_hdmi_log_status(struct v4l2_subdev *sd) +{ + struct dw_hdmi_dev *dw_dev = to_dw_dev(sd); + struct v4l2_dv_timings timings; + + v4l2_info(sd, "--- Chip configuration ---\n"); + v4l2_info(sd, "cfg_clk=%dMHz\n", dw_dev->cfg_clk); + v4l2_info(sd, "phy_drv=%s, phy_jtag_addr=0x%x\n", dw_dev->phy_drv, + dw_dev->phy_jtag_addr); + + v4l2_info(sd, "--- Chip status ---\n"); + v4l2_info(sd, "selected_input=%d: signal=%d\n", dw_dev->selected_input, + has_signal(dw_dev, dw_dev->selected_input)); + v4l2_info(sd, "configured_input=%d: signal=%d\n", + dw_dev->configured_input, + has_signal(dw_dev, dw_dev->configured_input)); + + v4l2_info(sd, "--- CEC status ---\n"); + if (dw_dev->cec_enabled_adap) {
drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ int i; + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (is_valid) + v4l2_info(sd, "cec_logical_address=0x%x\n", + dw_dev->cec_addr[i]); + } + }
I'm not sure how useful this is. The same information is available through /sys/kernel/debug/cec/cecX/status.
And just running cec-ctl gives it as well.
Up to you, though.
Quoted 18 lines
drivers/media/platform/dwc/Kconfig +18
-0+ + v4l2_info(sd, "--- Video status ---\n"); + v4l2_info(sd, "type=%s, color_depth=%dbits", + hdmi_readl(dw_dev, HDMI_PDEC_STS) & + HDMI_PDEC_STS_DVIDET ? "dvi" : "hdmi", + dw_hdmi_get_colordepth(dw_dev)); + + v4l2_info(sd, "--- Video timings ---\n"); + if (dw_hdmi_query_dv_timings(sd, &timings)) + v4l2_info(sd, "No video detected\n"); + else + v4l2_print_dv_timings(sd->name, "Detected format: ", + &timings, true); + v4l2_print_dv_timings(sd->name, "Configured format: ", + &dw_dev->timings, true); + return 0; +} +
<snip>
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ /* CEC */ + dw_dev->cec_adap = cec_allocate_adapter(&dw_hdmi_cec_adap_ops, + dw_dev, dev_name(dev), CEC_CAP_TRANSMIT | + CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS,
Add CEC_CAP_RC and CEC_CAP_PASSTHROUGH.
I'm not sure about CEC_CAP_PHYS_ADDR. The problem here is that this driver doesn't handle the EDID, but without that it doesn't know what physical address to use.
I wonder if the cec-notifier can be used for this, possibly with adaptations. Relying on users to set the physical address is a last resort since it is very painful to do so. cec-notifier was specifically designed to solve this.
drivers/media/platform/dwc/Kconfig
Quoted 6 lines
drivers/media/platform/dwc/Kconfig +6
-0+ HDMI_CEC_MAX_LOG_ADDRS); + ret = PTR_ERR_OR_ZERO(dw_dev->cec_adap); + if (ret) { + dev_err(dev, "failed to allocate CEC adapter\n"); + goto err_phy; + }
Regards,
Hans
Re: [PATCH v2 2/4] [media] platform: Add Synopsys Designware HDMI RX Controller Driver
Hi Hans,
Quoted 3 lines · Hans Verkuil
Hi Jose,
Just a quick review of the new CEC code:
Thanks!
Quoted 67 lines · Jose Abreu
Quoted 65 lines
This is an initial submission for the Synopsys Designware HDMI RX Controller Driver. This driver interacts with a phy driver so that a communication between them is created and a video pipeline is configured.
The controller + phy pipeline can then be integrated into a fully featured system that can be able to receive video up to 4k@60Hz with deep color 48bit RGB, depending on the platform. Although, this initial version does not yet handle deep color modes.
This driver was implemented as a standard V4L2 subdevice and its main features are:
- Internal state machine that reconfigures phy until the video is not stable
- JTAG communication with phy
- Inter-module communication with phy driver
- Debug write/read ioctlsSome notes:
- RX sense controller (cable connection/disconnection) must be handled by the platform wrapper as this is not integrated into the controller RTL
- The same goes for EDID ROM's
- ZCAL calibration is needed only in FPGA platforms, in ASIC this is not needed
- The state machine is not an ideal solution as it creates a kthread but it is needed because some sources might not be very stable at sending the video (i.e. we must react accordingly).Cc Carlos Palminha <palminha-HKixBCOQz3hWk0Htik3J/[email protected]>Cc Mauro Carvalho Chehab <[email protected]>Cc Hans Verkuil <[email protected]>Changes from v1:
- Added support for CEC
- Correct typo errors
- Correctly detect interlaced video modes
- Correct VIC parsing
Changes from RFC:
- Added support for HDCP 1.4
- FixupHDMI_VICnot being parsed (Hans)
- Send source change signal when powering off (Hans)
- Added a "wait stable delay"
- Detect interlaced video modes (Hans)
- Restrain g/s_register from reading/writing to HDCP regs (Hans)--- drivers/media/platform/dwc/Kconfig | 10 + drivers/media/platform/dwc/Makefile | 1 + drivers/media/platform/dwc/dw-hdmi-rx.c | 1764 +++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-rx.h | 435 ++++++++ include/media/dwc/dw-hdmi-rx-pdata.h | 63 ++ 5 files changed, 2273 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.h create mode 100644 include/media/dwc/dw-hdmi-rx-pdata.hdrivers/media/platform/dwc/Kconfig +0
-0@@ -6,3 +6,13 @@ config VIDEO_DWC_HDMI_PHY_E405
Quoted 15 lines
drivers/media/platform/dwc/Kconfig config VIDEO_DWC_HDMI_PHY_E405 · line 18
Quoted 12 lines
drivers/media/platform/dwc/Kconfig +10
-0To compile this driver as a module, choose M here. The module will be called dw-hdmi-phy-e405. + +config VIDEO_DWC_HDMI_RX + tristate "Synopsys Designware HDMI Receiver driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select CEC_CORE + help + Support for Synopsys Designware HDMI RX controller. + + To compile this driver as a module, choose M here. The module + will be called dw-hdmi-rx.Add a separate config
VIDEO_DWC_HDMI_RX_CECto explicitly enable CEC. CEC is an optional component of HDMI and supporting CEC should be something you select in the kernel config.
Ok, will add, but see bellow.
Quoted 8 lines
<snip>
General question: is this CEC IP the same IP as is used in the HDMI transmitter? If so, then it is not a good idea to duplicate the code.
If they are different, then that should be noted in the source.
Well, at regbank they are :) I mean, CEC is not a separate IP, its directly integrated in the controller so they probably just reused the block in TX and in RX. CEC is optional in the controller configuration (as well as many other functionalities). Unfortunately there is no register in this controller that can be used to tell the configuration that was used (i.e. tell if CEC interface is present). I could read registers and check against default values, but that doesn't seem very nice. Either way I think the CEC Kconfig bool in this should be hidden from users and just let the wrapper driver activate if needed, because the wrapper driver will probably know if the platform has cec support or not. Or we could add a node in the DT.
Quoted 56 lines
Quoted 56 lines
drivers/media/platform/dwc/Kconfig +55
-0+static void dw_hdmi_cec_enable_ints(struct dw_hdmi_dev *dw_dev) +{ + u32 mask = HDMI_AUD_CEC_ISTS_DONE | HDMI_AUD_CEC_ISTS_EOM | + HDMI_AUD_CEC_ISTS_NACK | HDMI_AUD_CEC_ISTS_ARBLST | + HDMI_AUD_CEC_ISTS_ERROR_INIT | HDMI_AUD_CEC_ISTS_ERROR_FOLL; + + hdmi_writel(dw_dev, mask, HDMI_AUD_CEC_IEN_SET); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_disable_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_IEN_CLR); + hdmi_writel(dw_dev, ~0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_clear_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_ICLR); +} + +static void dw_hdmi_cec_tx_raw_status(struct dw_hdmi_dev *dw_dev, u32 stat) +{ + u32 error_mask = HDMI_AUD_CEC_ISTS_NACK | + HDMI_AUD_CEC_ISTS_ERROR_INIT; + + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_dbg(dw_dev->dev, "%s: tx is busy\n", __func__); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_ARBLST) { + dev_dbg(dw_dev->dev, "%s: arbitration lost\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_ARB_LOST, + 1, 0, 0, 0); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_DONE) { + dev_dbg(dw_dev->dev, "%s: transmission done\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); + return; + } + + if (stat & error_mask) { + /* If we reached here we have an error */ + u8 status = 0, nack_cnt = 0, error_cnt = 0; + + dev_dbg(dw_dev->dev, "%s: error found (stat=0x%x)\n", __func__, + stat); + + if (stat & HDMI_AUD_CEC_ISTS_NACK) { + status |= CEC_TX_STATUS_NACK; + nack_cnt++; + }
Quoted 8 lines
drivers/media/platform/dwc/Kconfig
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ + if (stat & HDMI_AUD_CEC_ISTS_ERROR_INIT) { + status |= CEC_TX_STATUS_ERROR; + error_cnt++; + }What does it mean if you have both NACK and
ERROR_INITflags set? Is that an error or a NACK? You have to chose here which one you pick when callingcec_transmit_done.
I don't know if these can happen simultaneously. I remember I could provoke NACK's but I never got ERROR_INIT.
Quoted 83 lines
Quoted 6 lines
drivers/media/platform/dwc/Kconfig +5
-0+ + cec_transmit_done(dw_dev->cec_adap, status, 0, nack_cnt, 0, + error_cnt); + return; + }drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static void dw_hdmi_cec_received_msg(struct dw_hdmi_dev *dw_dev) +{ + struct cec_msg msg; + u8 i; + + msg.len = hdmi_readl(dw_dev, HDMI_CEC_RX_CNT); + if (!msg.len || msg.len > HDMI_CEC_RX_DATA_MAX) + return; /* its an invalid/non-existent message */it's
Quoted 22 lines
drivers/media/platform/dwc/Kconfig +22
-0+ + for (i = 0; i < msg.len; i++) + msg.msg[i] = hdmi_readl(dw_dev, HDMI_CEC_RX_DATA(i)); + + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + cec_received_msg(dw_dev->cec_adap, &msg); +} + +static int dw_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + + if (!dw_dev->cec_enabled_adap && enable) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + dw_hdmi_cec_enable_ints(dw_dev); + } else if (dw_dev->cec_enabled_adap && !enable) { + dw_hdmi_cec_disable_ints(dw_dev); + dw_dev->cec_valid_addrs = 0; + } + + dw_dev->cec_enabled_adap = enable; + return 0;drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static int dw_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + int i, free_idx = HDMI_CEC_MAX_LOG_ADDRS; + u32 tmp; + + if (!dw_dev->cec_enabled_adap) + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;This can't be called unless the adapter is enabled. So this check can be removed.
Quoted 30 lines
drivers/media/platform/dwc/Kconfig +30
-0+ + if (addr == CEC_LOG_ADDR_INVALID) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_L); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_H); + dw_dev->cec_valid_addrs = 0; + return 0; + } + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (free_idx == HDMI_CEC_MAX_LOG_ADDRS && !is_valid) + free_idx = i; + if (is_valid && dw_dev->cec_addr[i] == addr) + return 0; + } + + if (i == HDMI_CEC_MAX_LOG_ADDRS) { + i = free_idx; + if (i == HDMI_CEC_MAX_LOG_ADDRS) + return -ENXIO; + } + + dw_dev->cec_addr[i] = addr; + dw_dev->cec_valid_addrs |= 1 << i; + + if (i >= 8) { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_H); + tmp |= BIT(i - 8); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_H);
Quoted 8 lines
drivers/media/platform/dwc/Kconfig
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ } else { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_L); + tmp |= BIT(i); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_L); + }This seems overengineered. HDMI_CEC_ADDR_H/L is just a bitmask, so just set the bit corresponding to addr. I'm not sure what the point of cec_addr[] and
cec_valid_addrsis.
You mean I can only select between these:
ADDR_L:
Logical address 0 - Device TV
Logical address 1 - Recording Device 1
Logical address 2 - Recording Device 2
Logical address 3 - Tuner 1
Logical address 4 - Playback Device 1
Logical address 5 - Audio System
Logical address 6 - Tuner 2
Logical address 7 - Tuner 3
ADDR_H:
Logical address 8 - Playback Device 2
Logical address 9 - Playback Device 3
Logical address 10 - Tuner 4
Logical address 11 - Playback Device 3
Logical address 12 - Reserved
Logical address 13 - Reserved
Logical address 14 - Free use
Logical address 15 - Unregistered (as initiator address), Broadcast (as destination address)
?
But I still need to know if I got exhausted of logical addresses, right? (And now I realized this code is not respecting the logical addresses allocation :/)
Quoted 128 lines
Quoted 7 lines
drivers/media/platform/dwc/Kconfig +6
-0+ + return 0; +} + +static int dw_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg)drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + u8 len = msg->len; + u32 reg; + int i; + + if (len > HDMI_CEC_TX_DATA_MAX) { + dev_err(dw_dev->dev, "%s: invalid len (%d)\n", __func__, len); + return -EINVAL; + }Can't happen.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_err(dw_dev->dev, "%s: tx is busy\n", __func__); + return -EBUSY;This should never happen, but it doesn't hurt to check.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ } + + for (i = 0; i < HDMI_CEC_TX_DATA_MAX; i++) + hdmi_writel(dw_dev, 0x0, HDMI_CEC_TX_DATA(i));Why clear this? Is it necessary?
drivers/media/platform/dwc/Kconfig
Quoted 11 lines
drivers/media/platform/dwc/Kconfig +11
-0+ for (i = 0; i < len; i++) + hdmi_writel(dw_dev, msg->msg[i], HDMI_CEC_TX_DATA(i)); + + switch (signal_free_time) { + case 3: + reg = 0x0; + break; + case 7: + reg = 0x2; + break; + case 5:Use the defines in
media/cec.hinstead of hardcoding these values.Quoted 20 lines
drivers/media/platform/dwc/Kconfig +20
-0+ default: + reg = 0x1; + break; + } + + hdmi_writel(dw_dev, len, HDMI_CEC_TX_CNT); + hdmi_mask_writel(dw_dev, reg, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_FRAME_TYP_OFFSET, + HDMI_CEC_CTRL_FRAME_TYP_MASK); + hdmi_mask_writel(dw_dev, 0x1, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_SEND_OFFSET, + HDMI_CEC_CTRL_SEND_MASK); + return 0; +} + +static const struct cec_adap_ops dw_hdmi_cec_adap_ops = { + .adap_enable = dw_hdmi_cec_adap_enable, + .adap_log_addr = dw_hdmi_cec_adap_log_addr, + .adap_transmit = dw_hdmi_cec_adap_transmit, +};<snip>
Quoted 19 lines
drivers/media/platform/dwc/Kconfig +19
-0+static int dw_hdmi_log_status(struct v4l2_subdev *sd) +{ + struct dw_hdmi_dev *dw_dev = to_dw_dev(sd); + struct v4l2_dv_timings timings; + + v4l2_info(sd, "--- Chip configuration ---\n"); + v4l2_info(sd, "cfg_clk=%dMHz\n", dw_dev->cfg_clk); + v4l2_info(sd, "phy_drv=%s, phy_jtag_addr=0x%x\n", dw_dev->phy_drv, + dw_dev->phy_jtag_addr); + + v4l2_info(sd, "--- Chip status ---\n"); + v4l2_info(sd, "selected_input=%d: signal=%d\n", dw_dev->selected_input, + has_signal(dw_dev, dw_dev->selected_input)); + v4l2_info(sd, "configured_input=%d: signal=%d\n", + dw_dev->configured_input, + has_signal(dw_dev, dw_dev->configured_input)); + + v4l2_info(sd, "--- CEC status ---\n"); + if (dw_dev->cec_enabled_adap) {drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ int i; + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (is_valid) + v4l2_info(sd, "cec_logical_address=0x%x\n", + dw_dev->cec_addr[i]); + } + }I'm not sure how useful this is. The same information is available through
/sys/kernel/debug/cec/cecX/status.And just running cec-ctl gives it as well.
Up to you, though.
Quoted 18 lines
drivers/media/platform/dwc/Kconfig +18
-0+ + v4l2_info(sd, "--- Video status ---\n"); + v4l2_info(sd, "type=%s, color_depth=%dbits", + hdmi_readl(dw_dev, HDMI_PDEC_STS) & + HDMI_PDEC_STS_DVIDET ? "dvi" : "hdmi", + dw_hdmi_get_colordepth(dw_dev)); + + v4l2_info(sd, "--- Video timings ---\n"); + if (dw_hdmi_query_dv_timings(sd, &timings)) + v4l2_info(sd, "No video detected\n"); + else + v4l2_print_dv_timings(sd->name, "Detected format: ", + &timings, true); + v4l2_print_dv_timings(sd->name, "Configured format: ", + &dw_dev->timings, true); + return 0; +} +<snip>
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ /* CEC */ + dw_dev->cec_adap = cec_allocate_adapter(&dw_hdmi_cec_adap_ops, + dw_dev, dev_name(dev), CEC_CAP_TRANSMIT | + CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS,Add
CEC_CAP_RCandCEC_CAP_PASSTHROUGH.
Quoted 7 lines
I'm not sure about
CEC_CAP_PHYS_ADDR. The problem here is that this driver doesn't handle the EDID, but without that it doesn't know what physical address to use.I wonder if the cec-notifier can be used for this, possibly with adaptations. Relying on users to set the physical address is a last resort since it is very painful to do so. cec-notifier was specifically designed to solve this.
Yes, EDID ROM is not integrated into the controller so I can't add the code. How exactly can I use cec-notifier here?
Best regards,
Jose Miguel Abreu
Quoted 10 lines
drivers/media/platform/dwc/Kconfig
Quoted 7 lines
drivers/media/platform/dwc/Kconfig +6
-0+ HDMI_CEC_MAX_LOG_ADDRS); + ret = PTR_ERR_OR_ZERO(dw_dev->cec_adap); + if (ret) { + dev_err(dev, "failed to allocate CEC adapter\n"); + goto err_phy; + }Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/4] [media] platform: Add Synopsys Designware HDMI RX Controller Driver
Quoted 102 lines · Jose Abreu
Hi Hans,
Quoted 3 lines · Hans Verkuil
Hi Jose,
Just a quick review of the new CEC code:
Thanks!
Quoted 67 lines · Jose Abreu
Quoted 65 lines
This is an initial submission for the Synopsys Designware HDMI RX Controller Driver. This driver interacts with a phy driver so that a communication between them is created and a video pipeline is configured.
The controller + phy pipeline can then be integrated into a fully featured system that can be able to receive video up to 4k@60Hz with deep color 48bit RGB, depending on the platform. Although, this initial version does not yet handle deep color modes.
This driver was implemented as a standard V4L2 subdevice and its main features are:
- Internal state machine that reconfigures phy until the video is not stable
- JTAG communication with phy
- Inter-module communication with phy driver
- Debug write/read ioctlsSome notes:
- RX sense controller (cable connection/disconnection) must be handled by the platform wrapper as this is not integrated into the controller RTL
- The same goes for EDID ROM's
- ZCAL calibration is needed only in FPGA platforms, in ASIC this is not needed
- The state machine is not an ideal solution as it creates a kthread but it is needed because some sources might not be very stable at sending the video (i.e. we must react accordingly).Cc Carlos Palminha <palminha-HKixBCOQz3hWk0Htik3J/[email protected]>Cc Mauro Carvalho Chehab <[email protected]>Cc Hans Verkuil <[email protected]>Changes from v1:
- Added support for CEC
- Correct typo errors
- Correctly detect interlaced video modes
- Correct VIC parsing
Changes from RFC:
- Added support for HDCP 1.4
- FixupHDMI_VICnot being parsed (Hans)
- Send source change signal when powering off (Hans)
- Added a "wait stable delay"
- Detect interlaced video modes (Hans)
- Restrain g/s_register from reading/writing to HDCP regs (Hans)--- drivers/media/platform/dwc/Kconfig | 10 + drivers/media/platform/dwc/Makefile | 1 + drivers/media/platform/dwc/dw-hdmi-rx.c | 1764 +++++++++++++++++++++++++++++++ drivers/media/platform/dwc/dw-hdmi-rx.h | 435 ++++++++ include/media/dwc/dw-hdmi-rx-pdata.h | 63 ++ 5 files changed, 2273 insertions(+) create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.c create mode 100644 drivers/media/platform/dwc/dw-hdmi-rx.h create mode 100644 include/media/dwc/dw-hdmi-rx-pdata.hdrivers/media/platform/dwc/Kconfig +0
-0@@ -6,3 +6,13 @@ config VIDEO_DWC_HDMI_PHY_E405Quoted 15 lines
drivers/media/platform/dwc/Kconfig config VIDEO_DWC_HDMI_PHY_E405 · line 18
Quoted 12 lines
drivers/media/platform/dwc/Kconfig +10
-0To compile this driver as a module, choose M here. The module will be called dw-hdmi-phy-e405. + +config VIDEO_DWC_HDMI_RX + tristate "Synopsys Designware HDMI Receiver driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select CEC_CORE + help + Support for Synopsys Designware HDMI RX controller. + + To compile this driver as a module, choose M here. The module + will be called dw-hdmi-rx.Add a separate config
VIDEO_DWC_HDMI_RX_CECto explicitly enable CEC. CEC is an optional component of HDMI and supporting CEC should be something you select in the kernel config.Ok, will add, but see bellow.
Quoted 7 lines
<snip>
General question: is this CEC IP the same IP as is used in the HDMI transmitter? If so, then it is not a good idea to duplicate the code.
Quoted 5 lines
Quoted 1 line
If they are different, then that should be noted in the source.
Well, at regbank they are :) I mean, CEC is not a separate IP, its directly integrated in the controller so they probably just reused the block in TX and in RX.
I compared the registers of this driver with that of Russell's CEC driver, and esp. the interrupt handling part is quite different.
Since that's really the meat of the CEC code, I agree that it is OK to keep this separate.
Perhaps a comment about these differences might be useful.
Quoted 10 lines
CEC is optional in the
controller configuration (as well as many other functionalities). Unfortunately there is no register in this controller that can be used to tell the configuration that was used (i.e. tell if CEC interface is present). I could read registers and check against default values, but that doesn't seem very nice. Either way I think the CECKconfigbool in this should be hidden from users and just let the wrapper driver activate if needed, because the wrapper driver will probably know if the platform has cec support or not. Or we could add a node in the DT.
As long as the CEC part can be disabled if it is not needed. It avoid having to load the cec.ko module.
Quoted 66 lines
Quoted 57 lines
Quoted 57 lines
drivers/media/platform/dwc/Kconfig +55
-0+static void dw_hdmi_cec_enable_ints(struct dw_hdmi_dev *dw_dev) +{ + u32 mask = HDMI_AUD_CEC_ISTS_DONE | HDMI_AUD_CEC_ISTS_EOM | + HDMI_AUD_CEC_ISTS_NACK | HDMI_AUD_CEC_ISTS_ARBLST | + HDMI_AUD_CEC_ISTS_ERROR_INIT | HDMI_AUD_CEC_ISTS_ERROR_FOLL; + + hdmi_writel(dw_dev, mask, HDMI_AUD_CEC_IEN_SET); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_disable_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_IEN_CLR); + hdmi_writel(dw_dev, ~0x0, HDMI_CEC_MASK); +} + +static void dw_hdmi_cec_clear_ints(struct dw_hdmi_dev *dw_dev) +{ + hdmi_writel(dw_dev, ~0x0, HDMI_AUD_CEC_ICLR); +} + +static void dw_hdmi_cec_tx_raw_status(struct dw_hdmi_dev *dw_dev, u32 stat) +{ + u32 error_mask = HDMI_AUD_CEC_ISTS_NACK | + HDMI_AUD_CEC_ISTS_ERROR_INIT; + + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_dbg(dw_dev->dev, "%s: tx is busy\n", __func__); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_ARBLST) { + dev_dbg(dw_dev->dev, "%s: arbitration lost\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_ARB_LOST, + 1, 0, 0, 0); + return; + } + + if (stat & HDMI_AUD_CEC_ISTS_DONE) { + dev_dbg(dw_dev->dev, "%s: transmission done\n", __func__); + cec_transmit_done(dw_dev->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); + return; + } + + if (stat & error_mask) { + /* If we reached here we have an error */ + u8 status = 0, nack_cnt = 0, error_cnt = 0; + + dev_dbg(dw_dev->dev, "%s: error found (stat=0x%x)\n", __func__, + stat); + + if (stat & HDMI_AUD_CEC_ISTS_NACK) { + status |= CEC_TX_STATUS_NACK; + nack_cnt++; + }Quoted 8 lines
drivers/media/platform/dwc/Kconfig
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ + if (stat & HDMI_AUD_CEC_ISTS_ERROR_INIT) { + status |= CEC_TX_STATUS_ERROR; + error_cnt++; + }What does it mean if you have both NACK and
ERROR_INITflags set? Is that an error or a NACK? You have to chose here which one you pick when callingcec_transmit_done.
Quoted 2 lines
I don't know if these can happen simultaneously. I remember I could provoke NACK's but I never got
ERROR_INIT.
I would put an else before the ERROR_INIT if. The combination makes no sense and it would confuse the CEC framework.
Quoted 116 lines
Quoted 84 lines
Quoted 7 lines
drivers/media/platform/dwc/Kconfig +5
-0+ + cec_transmit_done(dw_dev->cec_adap, status, 0, nack_cnt, 0, + error_cnt); + return; + }drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static void dw_hdmi_cec_received_msg(struct dw_hdmi_dev *dw_dev) +{ + struct cec_msg msg; + u8 i; + + msg.len = hdmi_readl(dw_dev, HDMI_CEC_RX_CNT); + if (!msg.len || msg.len > HDMI_CEC_RX_DATA_MAX) + return; /* its an invalid/non-existent message */it's
Quoted 22 lines
drivers/media/platform/dwc/Kconfig +22
-0+ + for (i = 0; i < msg.len; i++) + msg.msg[i] = hdmi_readl(dw_dev, HDMI_CEC_RX_DATA(i)); + + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + cec_received_msg(dw_dev->cec_adap, &msg); +} + +static int dw_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + + if (!dw_dev->cec_enabled_adap && enable) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_LOCK); + dw_hdmi_cec_enable_ints(dw_dev); + } else if (dw_dev->cec_enabled_adap && !enable) { + dw_hdmi_cec_disable_ints(dw_dev); + dw_dev->cec_valid_addrs = 0; + } + + dw_dev->cec_enabled_adap = enable; + return 0;drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+} + +static int dw_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + int i, free_idx = HDMI_CEC_MAX_LOG_ADDRS; + u32 tmp; + + if (!dw_dev->cec_enabled_adap) + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO;This can't be called unless the adapter is enabled. So this check can be removed.
Quoted 30 lines
drivers/media/platform/dwc/Kconfig +30
-0+ + if (addr == CEC_LOG_ADDR_INVALID) { + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_L); + hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_H); + dw_dev->cec_valid_addrs = 0; + return 0; + } + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (free_idx == HDMI_CEC_MAX_LOG_ADDRS && !is_valid) + free_idx = i; + if (is_valid && dw_dev->cec_addr[i] == addr) + return 0; + } + + if (i == HDMI_CEC_MAX_LOG_ADDRS) { + i = free_idx; + if (i == HDMI_CEC_MAX_LOG_ADDRS) + return -ENXIO; + } + + dw_dev->cec_addr[i] = addr; + dw_dev->cec_valid_addrs |= 1 << i; + + if (i >= 8) { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_H); + tmp |= BIT(i - 8); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_H);Quoted 8 lines
drivers/media/platform/dwc/Kconfig
Quoted 5 lines
drivers/media/platform/dwc/Kconfig +5
-0+ } else { + tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_L); + tmp |= BIT(i); + hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_L); + }This seems overengineered. HDMI_CEC_ADDR_H/L is just a bitmask, so just set the bit corresponding to addr. I'm not sure what the point of cec_addr[] and
cec_valid_addrsis.You mean I can only select between these:
ADDR_L:
Logical address 0 - Device TV
Logical address 1 - Recording Device 1
Logical address 2 - Recording Device 2
Logical address 3 - Tuner 1
Logical address 4 - Playback Device 1
Logical address 5 - Audio System
Logical address 6 - Tuner 2
Logical address 7 - Tuner 3
ADDR_H:
Logical address 8 - Playback Device 2
Logical address 9 - Playback Device 3
Logical address 10 - Tuner 4
Logical address 11 - Playback Device 3
Logical address 12 - Reserved
Logical address 13 - Reserved
Logical address 14 - Free use
Logical address 15 - Unregistered (as initiator address), Broadcast (as destination address)
Quoted 5 lines
?
But I still need to know if I got exhausted of logical addresses, right? (And now I realized this code is not respecting the logical addresses allocation :/)
You tell the framework about the maximum number of LAs that you support simultaneously when you call cec_allocate_adapter. The framework will take care of checking that that max is never exceeded. No need to check again.
You're asked here to either clear the logical address mask (when INVALID is passed in) or to activate the given logical address. So:
if (addr == CEC_LOG_ADDR_INVALID) {
hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_L);
hdmi_writel(dw_dev, 0x0, HDMI_CEC_ADDR_H);
return 0;
}
if (i >= 8) {
tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_H);
tmp |= BIT(i - 8);
hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_H);
} else {
tmp = hdmi_readl(dw_dev, HDMI_CEC_ADDR_L);
tmp |= BIT(i);
hdmi_writel(dw_dev, tmp, HDMI_CEC_ADDR_L);
}That's all you need to do.
Quoted 133 lines
Quoted 133 lines
Quoted 8 lines
drivers/media/platform/dwc/Kconfig +6
-0+ + return 0; +} + +static int dw_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg)drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+{ + struct dw_hdmi_dev *dw_dev = cec_get_drvdata(adap); + u8 len = msg->len; + u32 reg; + int i; + + if (len > HDMI_CEC_TX_DATA_MAX) { + dev_err(dw_dev->dev, "%s: invalid len (%d)\n", __func__, len); + return -EINVAL; + }Can't happen.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ + if (hdmi_readl(dw_dev, HDMI_CEC_CTRL) & HDMI_CEC_CTRL_SEND_MASK) { + dev_err(dw_dev->dev, "%s: tx is busy\n", __func__); + return -EBUSY;This should never happen, but it doesn't hurt to check.
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ } + + for (i = 0; i < HDMI_CEC_TX_DATA_MAX; i++) + hdmi_writel(dw_dev, 0x0, HDMI_CEC_TX_DATA(i));Why clear this? Is it necessary?
drivers/media/platform/dwc/Kconfig
Quoted 11 lines
drivers/media/platform/dwc/Kconfig +11
-0+ for (i = 0; i < len; i++) + hdmi_writel(dw_dev, msg->msg[i], HDMI_CEC_TX_DATA(i)); + + switch (signal_free_time) { + case 3: + reg = 0x0; + break; + case 7: + reg = 0x2; + break; + case 5:Use the defines in
media/cec.hinstead of hardcoding these values.Quoted 20 lines
drivers/media/platform/dwc/Kconfig +20
-0+ default: + reg = 0x1; + break; + } + + hdmi_writel(dw_dev, len, HDMI_CEC_TX_CNT); + hdmi_mask_writel(dw_dev, reg, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_FRAME_TYP_OFFSET, + HDMI_CEC_CTRL_FRAME_TYP_MASK); + hdmi_mask_writel(dw_dev, 0x1, HDMI_CEC_CTRL, + HDMI_CEC_CTRL_SEND_OFFSET, + HDMI_CEC_CTRL_SEND_MASK); + return 0; +} + +static const struct cec_adap_ops dw_hdmi_cec_adap_ops = { + .adap_enable = dw_hdmi_cec_adap_enable, + .adap_log_addr = dw_hdmi_cec_adap_log_addr, + .adap_transmit = dw_hdmi_cec_adap_transmit, +};<snip>
Quoted 19 lines
drivers/media/platform/dwc/Kconfig +19
-0+static int dw_hdmi_log_status(struct v4l2_subdev *sd) +{ + struct dw_hdmi_dev *dw_dev = to_dw_dev(sd); + struct v4l2_dv_timings timings; + + v4l2_info(sd, "--- Chip configuration ---\n"); + v4l2_info(sd, "cfg_clk=%dMHz\n", dw_dev->cfg_clk); + v4l2_info(sd, "phy_drv=%s, phy_jtag_addr=0x%x\n", dw_dev->phy_drv, + dw_dev->phy_jtag_addr); + + v4l2_info(sd, "--- Chip status ---\n"); + v4l2_info(sd, "selected_input=%d: signal=%d\n", dw_dev->selected_input, + has_signal(dw_dev, dw_dev->selected_input)); + v4l2_info(sd, "configured_input=%d: signal=%d\n", + dw_dev->configured_input, + has_signal(dw_dev, dw_dev->configured_input)); + + v4l2_info(sd, "--- CEC status ---\n"); + if (dw_dev->cec_enabled_adap) {drivers/media/platform/dwc/Kconfig
Quoted 10 lines
drivers/media/platform/dwc/Kconfig +10
-0+ int i; + + for (i = 0; i < HDMI_CEC_MAX_LOG_ADDRS; i++) { + bool is_valid = dw_dev->cec_valid_addrs & (1 << i); + + if (is_valid) + v4l2_info(sd, "cec_logical_address=0x%x\n", + dw_dev->cec_addr[i]); + } + }I'm not sure how useful this is. The same information is available through
/sys/kernel/debug/cec/cecX/status.And just running cec-ctl gives it as well.
Up to you, though.
Quoted 18 lines
drivers/media/platform/dwc/Kconfig +18
-0+ + v4l2_info(sd, "--- Video status ---\n"); + v4l2_info(sd, "type=%s, color_depth=%dbits", + hdmi_readl(dw_dev, HDMI_PDEC_STS) & + HDMI_PDEC_STS_DVIDET ? "dvi" : "hdmi", + dw_hdmi_get_colordepth(dw_dev)); + + v4l2_info(sd, "--- Video timings ---\n"); + if (dw_hdmi_query_dv_timings(sd, &timings)) + v4l2_info(sd, "No video detected\n"); + else + v4l2_print_dv_timings(sd->name, "Detected format: ", + &timings, true); + v4l2_print_dv_timings(sd->name, "Configured format: ", + &dw_dev->timings, true); + return 0; +} +<snip>
drivers/media/platform/dwc/Kconfig
Quoted 4 lines
drivers/media/platform/dwc/Kconfig +4
-0+ /* CEC */ + dw_dev->cec_adap = cec_allocate_adapter(&dw_hdmi_cec_adap_ops, + dw_dev, dev_name(dev), CEC_CAP_TRANSMIT | + CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS,Add
CEC_CAP_RCandCEC_CAP_PASSTHROUGH.I'm not sure about
CEC_CAP_PHYS_ADDR. The problem here is that this driver doesn't handle the EDID, but without that it doesn't know what physical address to use.
Quoted 6 lines
Quoted 3 lines
I wonder if the cec-notifier can be used for this, possibly with adaptations. Relying on users to set the physical address is a last resort since it is very painful to do so. cec-notifier was specifically designed to solve this.
Yes, EDID ROM is not integrated into the controller so I can't add the code. How exactly can I use cec-notifier here?
drivers/media/platform/sti/cec/stih-cec.c is a good example. The notifier is called by drivers/gpu/drm/sti/sti_hdmi.c.
Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/4] [media] platform: Add Synopsys Designware HDMI RX Controller Driver
Hi Hans,
Quoted 13 lines · Hans Verkuil
Quoted 13 lines
Quoted 13 lines
<snip>
drivers/media/platform/dwc/dw-hdmi-rx.c line 1709
Quoted 4 lines
drivers/media/platform/dwc/dw-hdmi-rx.c new file +4
-0+/* CEC */ + dw_dev->cec_adap = cec_allocate_adapter(&dw_hdmi_cec_adap_ops, + dw_dev, dev_name(dev), CEC_CAP_TRANSMIT | + CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS,Add
CEC_CAP_RCandCEC_CAP_PASSTHROUGH.I'm not sure about
CEC_CAP_PHYS_ADDR. The problem here is that this driver doesn't handle the EDID, but without that it doesn't know what physical address to use.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
I wonder if the cec-notifier can be used for this, possibly with adaptations. Relying on users to set the physical address is a last resort since it is very painful to do so. cec-notifier was specifically designed to solve this.
Yes, EDID ROM is not integrated into the controller so I can't add the code. How exactly can I use cec-notifier here?
drivers/media/platform/sti/cec/stih-cec.cis a good example. The notifier is called bydrivers/gpu/drm/sti/sti_hdmi.c.
Done! Implemented and working :) I'm wondering if you want me to wait some more time for other comments or just send the v3 now? I also added support for SCDC read request (its a matter of activating a bit).
BTW, I used the DT node name "hdmi-phandle" but I don't know if it is the best because it can cause confusion about the hdmi-phandle that you documented in media/cec.txt
Best regards,
Jose Miguel Abreu
Quoted 5 lines
Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/4] [media] platform: Add Synopsys Designware HDMI RX Controller Driver
Quoted 22 lines · Jose Abreu
Hi Hans,
Quoted 18 lines · Hans Verkuil
Quoted 18 lines
Quoted 9 lines
<snip>
drivers/media/platform/dwc/dw-hdmi-rx.c line 1709
Quoted 4 lines
drivers/media/platform/dwc/dw-hdmi-rx.c new file +4
-0+/* CEC */ + dw_dev->cec_adap = cec_allocate_adapter(&dw_hdmi_cec_adap_ops, + dw_dev, dev_name(dev), CEC_CAP_TRANSMIT | + CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS,Add
CEC_CAP_RCandCEC_CAP_PASSTHROUGH.Quoted 7 lines
I'm not sure about
CEC_CAP_PHYS_ADDR. The problem here is that this driver doesn't handle the EDID, but without that it doesn't know what physical address to use.I wonder if the cec-notifier can be used for this, possibly with adaptations. Relying on users to set the physical address is a last resort since it is very painful to do so. cec-notifier was specifically designed to solve this.
Yes, EDID ROM is not integrated into the controller so I can't add the code. How exactly can I use cec-notifier here?
Quoted 7 lines
Quoted 2 lines
drivers/media/platform/sti/cec/stih-cec.cis a good example. The notifier is called bydrivers/gpu/drm/sti/sti_hdmi.c.Done! Implemented and working :) I'm wondering if you want me to wait some more time for other comments or just send the v3 now? I also added support for SCDC read request (its a matter of activating a bit).
Well, if it is ready, then just send a v3!
Quoted 3 lines
BTW, I used the DT node name "hdmi-phandle" but I don't know if it is the best because it can cause confusion about the hdmi-phandle that you documented in
media/cec.txt
I had the same thought. It doesn't really fit for CEC adapters on HDMI receivers.
Perhaps edid-phandle? Or something else?
Regards,
Hans
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 3/4 MAINTAINERS: Add entry for Synopsys Designware HDMI drivers
In reply to Jose AbreuAdd a entry for Synopsys Designware HDMI Receivers drivers and phys.
--- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+)
MAINTAINERS +7 -0
@@ -11294,6 +11294,13 @@ L: [email protected] S: Supported F: drivers/net/ethernet/synopsys/ +SYNOPSYS DESIGNWARE HDMI RECEIVERS AND PHY DRIVERS +M: Jose Abreu <[email protected]> +L: [email protected] +S: Maintained +F: drivers/media/platform/dwc/* +F: include/media/dwc/* + SYNOPSYS DESIGNWARE I2C DRIVER M: Jarkko Nikula <[email protected]> R: Andy Shevchenko <[email protected]>
Signature · 1 line
1.9.1
PATCH v2 4/4 dt-bindings: media: Document Synopsys Designware HDMI RX
In reply to Jose AbreuDocument the bindings for the Synopsys Designware HDMI RX.
--- .../devicetree/bindings/media/snps,dw-hdmi-rx.txt | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.txt
Documentation/devicetree/bindings/media/snps,dw-hdmi-rx.txt new file +41 -0
@@ -0,0 +1,41 @@ +Synopsys DesignWare HDMI RX Decoder +=================================== + +This document defines device tree properties for the Synopsys DesignWare HDMI +RX Decoder (DWC HDMI RX). It doesn't constitute a device tree binding +specification by itself but is meant to be referenced by platform-specific +device tree bindings. + +When referenced from platform device tree bindings the properties defined in +this document are defined as follows. + +- reg: Memory mapped base address and length of the DWC HDMI RX registers. + +- interrupts: Reference to the DWC HDMI RX interrupt and 5v sense interrupt. + +- snps,hdmi-phy-jtag-addr: JTAG address of the phy to be used. + +- snps,hdmi-phy-version: Version of the phy to be used. + +- snps,hdmi-phy-cfg-clk: Value of the cfg clk that is delivered to phy. + +- snps,hdmi-phy-driver: *Exact* name of the phy driver to be used. + +- snps,hdmi-ctl-cfg-clk: Value of the cfg clk that is delivered to the +controller. + +A sample binding is now provided. The compatible string is for a wrapper driver +which then instantiates the Synopsys Designware HDMI RX decoder driver. + +Example: + +dw_hdmi_wrapper: dw-hdmi-wrapper@0 { + compatible = "snps,dw-hdmi-rx-wrapper"; + reg = <0x0 0x10000>; /* controller regbank */ + interrupts = <1 3>; /* controller interrupt + 5v sense interrupt */ + snps,hdmi-phy-driver = "dw-hdmi-phy-e405"; + snps,hdmi-phy-version = <405>; + snps,hdmi-phy-cfg-clk = <25>; /* MHz */ + snps,hdmi-ctl-cfg-clk = <25>; /* MHz */ + snps,hdmi-phy-jtag-addr = /bits/ 8 <0xfc>; +};
Signature · 1 line
1.9.1