Some notes about the HDMI driver, found in the specific 3.18 kernel at drivers/gpu/drm/jz4780. The newer generic driver is found in more recent kernels at drivers/gpu/drm/bridge/synopsys/dw-hdmi.c. Meanwhile, the older HDMI driver functionality can be found in the specific 3.0.8 kernel at drivers/video/jz4780-hdmi.
Contents
In dwc_hdmi.h, struct dwc_hdmi retains state for various things:
Device type details, used to distinguish between different configurations of the common functionality
Device tree node reference
DRM connectors, encoders and devices
HDMI data, featuring input and output formats, HDCP status, video mode details
Audio device reference
Clock references
DDC device reference
Display mode information
EDID information
Peripheral register details
Pixel and sample clock rates
The probe operation in dwc_hdmi.c obtains device details from the device tree:
Device type details: "dwc-hdmi" should yield a type of DWC_HDMI
DDC device reference (this is I2C4 employing port F in the CI20)
Interrupt details from the "interrupt-parent" and "interrupts" properties
Peripheral register memory from the "reg" property
Register stepping details from the "reg-shift" property
HDMI/SFR and AHB clock details using the "clocks" and "clock-names" properties
HDMI clock frequency from the "clock-frequency" property
Some other operations occur:
HDMI block interrupts are reset
HDMI block clocks are configured using the pixel and sample rates
HDMI block interrupts are enabled
Driver state information is populated
The 3.0.8 driver sets the following parameters in hdmi_init, with parameter documentation in core/audioParams.h and core/videoParams.h:
| Audio interface type | I2S |
| Audio coding type | PCM |
| Audio channel allocation | 0 |
| Audio packet type (audio sample or high bit rate) | AUDIO_SAMPLE |
| Audio sample size | 16 |
| Audio sampling frequency | 44100 |
| Audio level shift value | 0 |
| Audio down mix inhibit flag | 0 |
| Audio input clock frequency scaling factor | 64 |
| Video input encoding | RGB |
| Video output encoding | RGB |
The 3.18 device tree in arch/mips/boot/dts/jz4780.dtsi has a node setting the clock frequency to 27MHz. In the 3.0.8 kernel driver, the probe mechanism in jz4780_hdmi.c sets the same frequency.
The 3.18 device tree in arch/mips/boot/dts/ci20.dts configures an active-high, always-on fixed regulator on GPIO A25.
The 3.0.8 kernel obtains a reference to the vhdmi regulator but does not seem to manipulate it. This regulator is defined in various board definitions in arch/mips/xburst/soc-4780/board.
Power control is actually performed by a separate regulator IC whose 3.0.8 and 3.18 drivers are found in drivers/regulator/act8600-regulator.c.
The power supply to the PHY is set in the dwc_hdmi_phy_enable_power function which sets the PDZ flag in the HDMI_PHY_CONF0 register.
The 3.0.8 driver defines register access primitives in bsp/access.c that employ 16-bit addresses (relative to the peripheral base address) and 8-bit values.
The 3.18 kernel maintains this style of access with the hdmi_readb and hdmi_writeb functions.
More recent kernels maintain this style of access, too. See drivers/gpu/drm/bridge/synopsys/dw-hdmi.c.
From dwc_hdmi_regs.h in 3.18. More recent kernels have a more comprehensive set of definitions in drivers/gpu/drm/bridge/synopsys/dw-hdmi.h.
| Register | Offset |
| HDMI_DESIGN_ID | 0x0000 |
| HDMI_REVISION_ID | 0x0001 |
| HDMI_PRODUCT_ID0 | 0x0002 |
| HDMI_PRODUCT_ID1 | 0x0003 |
| Register | Offset | Description |
| HDMI_PHY_CONF0 | 0x3000 | PHY configuration |
| HDMI_PHY_I2CM_SLAVE_ADDR | 0x3020 | Device address |
| HDMI_PHY_I2CM_ADDRESS_ADDR | 0x3021 | Output data register |
| HDMI_PHY_I2CM_DATAO_1_ADDR | 0x3022 | Output data high byte |
| HDMI_PHY_I2CM_DATAO_0_ADDR | 0x3023 | Output data low byte |
| HDMI_PHY_I2CM_OPERATION_ADDR | 0x3026 | Operation code |
| Flag | Bit | Description |
| WRITE | 1 | Write data |
| READ | 0 | Read data |
| Flag | Bit | Description |
| PDZ | 7 | Power enable |
| ENTMDS | 6 | Enable TMDS |
| SPARECTRL | 5 | |
| GEN2_PDDQ | 4 | "gen2 pddq" |
| GEN2_TXPWRON | 3 | "gen2" transmitter power on |
| GEN2_ENHPDRXSENSE | 2 | |
| SELDATAENPOL | 1 | "sel" data enable polarity? |
| SELDIPIF | 0 | "sel" interface control |
| Register | Offset | Description |
| HDMI_IH_MUTE | 0x01FF | Top-level interrupt disable |
| Flag | Bit | Description |
| ... | ... | ... |
| WAKEUP_INTERRUPT | 1 | Wakeup interrupt disable |
| ALL_INTERRUPT | 0 | Disable all interrupts |
Presumably, the ALL_INTERRUPT flag prevents specific interrupt conditions from occurring if set, even if those are enabled individually.
| Register | Offset | Description |
| HDMI_IH_PHY_STAT0 | 0x0104 | PHY interrupt status |
| HDMI_IH_I2CMPHY_STAT0 | 0x0108 | PHY I2C interrupt status |
| HDMI_IH_MUTE_PHY_STAT0 | 0x0184 | PHY interrupt disable |
| HDMI_IH_MUTE_I2CMPHY_STAT0 | 0x0188 | PHY I2C interrupt disable |
| HDMI_PHY_MASK0 | 0x3006 | PHY interrupt mask |
| HDMI_PHY_POL0 | 0x3007 | PHY condition polarity? |
| Flag | Bit | Description |
| ... | ... | ... |
| RX_SENSE3 | 5 | |
| RX_SENSE2 | 4 | |
| RX_SENSE1 | 3 | |
| RX_SENSE0 | 2 | |
| TX_PHY_LOCK | 1 | |
| HPD | 0 | Hotplug interrupt status (set to clear) |
| Flag | Bit | Description |
| ... | ... | ... |
| I2CMPHYDONE | 1 | Command done (set to clear) |
| I2CMPHYERROR | 0 | Command error (set to clear) |
| Flag | Bit | Description |
| ... | ... | ... |
| HPD | 0 | Hotplug interrupt (set to disable) |
| Flag | Bit | Description |
| ... | ... | ... |
| I2CMPHYDONE | 1 | Command done (set to disable) |
| I2CMPHYERROR | 0 | Command error (set to disable) |
| Register | Offset | Description |
| HDMI_IH_FC_STAT2 | 0x0102 | Overflow interrupt status |
| HDMI_IH_MUTE_FC_STAT2 | 0x0182 | Overflow interrupt disable |
| HDMI_FC_MASK2 | 0x10DA | Overflow interrupt mask |
FC stands for Frame Composer.
There is a connection employing I2C to the PHY that involves the hdmi_phy_i2c_write function. This uses the HDMI peripheral's own I2C functionality, not the JZ4780 I2C peripherals. (Note that this peripheral can also be used to query the DDC for EDID information.)
The hdmi_phy_wait_i2c_done function is used after each write operation to test whether the transfer was successful by testing the lower two bits of HDMI_IH_I2CMPHY_STAT0 every millisecond until one of the bits is set. The overall timeout in the __hdmi_phy_i2c_write function is one second.
The __hdmi_phy_i2c_write function does the following:
Writes 0xFF to HDMI_IH_I2CMPHY_STAT0 to clear all I2C PHY interrupt conditions.
Writes a register address to HDMI_PHY_I2CM_ADDRESS_ADDR.
Writes output data to HDMI_PHY_I2CM_DATAO_0_ADDR and HDMI_PHY_I2CM_DATAO_1_ADDR.
Writes an operation code to HDMI_PHY_I2CM_OPERATION_ADDR.
Waits for completion.
The pixel clock appears to be converted to two quantities: n and cts.
According to the driver, the JZ4780 uses "automatic CTS/N generation" and clears the HDMI_AUD_CTS3_CTS_MANUAL bit of HDMI_AUD_CTS3. According to the newer driver, CTS only needs setting for other SoCs if "internal AHB audio" is used (discovered by testing the HDMI_CONFIG3_AHBAUDDMA bit of HDMI_CONFIG3_ID).
The older driver seems to test pixel clock and sample rate combinations, returning various predefined results, whereas the newer driver calculates it as follows:
cts = (pixel_clock * n) / (128 * sample_rate)
For n, both drivers appear to test pixel clock and sample rate combinations, returning an appropriate value.
According to dwc_hdmi_regs.h, the hardware appears to provide three byte-sized registers together supporting a 20-bit value for n:
| Register | Offset | Description |
| HDMI_AUD_N1 | 0x3200 | n bits 7..0 |
| HDMI_AUD_N2 | 0x3201 | n bits 15..8 |
| HDMI_AUD_N3 | 0x3202 | n bits 19..16 |
The different portions of n are presented to these registers, and a field is cleared in the HDMI_AUD_CTS3 register to assert HDMI_AUD_CTS3_N_SHIFT_1, which perhaps causes n to be shifted by 1.
In the 3.18 driver, the HDMI output is enabled when one of the following occurs:
The HDMI cable is plugged in (the HDMI_IH_PHY_STAT0 register has the HPD flag set, and the HDMI_PHY_POL0 register has the HPD flag set to indicate a plug-in event).
A DPMS operation indicates a powering up condition (dwc_hdmi_encoder_dpms).
A commit operation occurs (dwc_hdmi_encoder_commit).
These cause the dwc_hdmi_poweron function to be called which in turn calls dwc_hdmi_setup. This performs a number of operations as described below.
Overflow interrupts are disabled (hdmi_disable_overflow_interrupts).
Video mode configuration is performed, employing drm_match_cea_mode to match a CEA-861 mode, returning a VIC (video identifier), adjusting various parameters. Without a CEA mode, DVI-compatible output is selected.
The input and output video encoding formats are set to RGB.
Picture configuration is performed (hdmi_av_composer).
PHY initialisation is performed (dwc_hdmi_phy_init). This involves the hdmi_phy_configure function and ultimately the enabling of power to the peripheral (dwc_hdmi_phy_enable_power).
dwc_hdmi_enable_video_path
hdmi_clk_regenerator_update_pixel_clock
hdmi_enable_audio_clk
hdmi_config_AVI
hdmi_video_packetize
hdmi_video_csc
hdmi_video_sample
hdmi_tx_hdcp_config
dwc_hdmi_clear_overflow
If connected and not in DVI mode, hdmi_enable_overflow_interrupts is invoked.
I2C operations involve setting the device to HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 and performing configuration operations using I2C writes. The following registers are involved:
| Address | Register |
| 0x05 | CKCALCTRL |
| 0x06 | CPCE_CTRL |
| 0x09 | CKSYMTXCTRL |
| 0x0E | VLEVCTRL |
| 0x10 | CURRCTRL |
| 0x13 | PLLPHBYCTRL |
| 0x15 | GMPCTRL |
| 0x17 | MSM_CTRL |
| 0x19 | TXTERM |
Address 0x06 (CPCE_CTRL) is written with a value that appears to set various bits according to the selected colour depth/resolution:
| Value | Colour Depth |
| 0x0000 | 8 |
| 0x2001 | 10 |
| 0x4002 | 12 |
This value is combined with a value that appears to be connected to the pixel clock frequency.
| Value | Frequency |
| 0x01e0 | <= 45.25MHz |
| 0x0140 | <= 92.50MHz |
| 0x00a0 | <= 148.50MHz |
| 0x0000 | <= 216.00MHz |
For a colour depth of 8, the final value is given as 0x00a0 in the 3.18 and more recent drivers without explanation.
Address 0x15 (GMPCTRL) is written with a value that apparently corresponds to the pixel clock frequency range:
| Value | Frequency |
| 0x0000 | <= 45.25MHz |
| 0x0005 | <= 92.50MHz |
| 0x000a | <= 148.50MHz |
| 0x000f | <= 216.00MHz |
For a colour depth of 8, the final value is given as 0x000a in the 3.18 and more recent drivers without explanation.
Address 0x10 (CURRCTRL) appears to use values related to colour resolution and frequency range in various combinations.