HDMI

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.

  1. State
  2. Initialisation
  3. Clock Configuration
  4. Power Configuration
  5. Register Access
  6. Registers
    1. Identification Registers
    2. PHY Registers
      1. HDMI_PHY_I2CM_OPERATION_ADDR
      2. HDMI_PHY_CONF0
    3. Interrupt Registers
      1. HDMI_IH_MUTE
    4. PHY Interrupt Registers
      1. HDMI_IH_PHY_STAT0
      2. HDMI_IH_I2CMPHY_STAT0
      3. HDMI_IH_MUTE_PHY_STAT0
      4. HDMI_IH_MUTE_I2CMPHY_STAT0
    5. Overflow Interrupt Registers
  7. I2C Signalling
  8. Audio Sampling
  9. Enabling Output
  10. PHY Configuration
    1. CPCE_CTRL
    2. GMPCTRL
    3. CURRCTRL

State

In dwc_hdmi.h, struct dwc_hdmi retains state for various things:

Initialisation

The probe operation in dwc_hdmi.c obtains device details from the device tree:

Some other operations occur:

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

Clock Configuration

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.

Power Configuration

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.

Register Access

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.

Registers

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.

Identification Registers

Register Offset
HDMI_DESIGN_ID 0x0000
HDMI_REVISION_ID 0x0001
HDMI_PRODUCT_ID0 0x0002
HDMI_PRODUCT_ID1 0x0003

PHY Registers

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

HDMI_PHY_I2CM_OPERATION_ADDR

Flag Bit Description
WRITE 1 Write data
READ 0 Read data

HDMI_PHY_CONF0

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

Interrupt Registers

Register Offset Description
HDMI_IH_MUTE 0x01FF Top-level interrupt disable

HDMI_IH_MUTE

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.

PHY Interrupt Registers

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?

HDMI_IH_PHY_STAT0

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)

HDMI_IH_I2CMPHY_STAT0

Flag Bit Description
... ... ...
I2CMPHYDONE 1 Command done (set to clear)
I2CMPHYERROR 0 Command error (set to clear)

HDMI_IH_MUTE_PHY_STAT0

Flag Bit Description
... ... ...
HPD 0 Hotplug interrupt (set to disable)

HDMI_IH_MUTE_I2CMPHY_STAT0

Flag Bit Description
... ... ...
I2CMPHYDONE 1 Command done (set to disable)
I2CMPHYERROR 0 Command error (set to disable)

Overflow Interrupt Registers

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.

I2C Signalling

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:

  1. Writes 0xFF to HDMI_IH_I2CMPHY_STAT0 to clear all I2C PHY interrupt conditions.
  2. Writes a register address to HDMI_PHY_I2CM_ADDRESS_ADDR.
  3. Writes output data to HDMI_PHY_I2CM_DATAO_0_ADDR and HDMI_PHY_I2CM_DATAO_1_ADDR.
  4. Writes an operation code to HDMI_PHY_I2CM_OPERATION_ADDR.
  5. Waits for completion.

Audio Sampling

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.

Enabling Output

In the 3.18 driver, the HDMI output is enabled when one of the following occurs:

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.

  1. Overflow interrupts are disabled (hdmi_disable_overflow_interrupts).
  2. 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.
  3. The input and output video encoding formats are set to RGB.
  4. Picture configuration is performed (hdmi_av_composer).
  5. 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).
  6. dwc_hdmi_enable_video_path
  7. hdmi_clk_regenerator_update_pixel_clock
  8. hdmi_enable_audio_clk
  9. hdmi_config_AVI
  10. hdmi_video_packetize
  11. hdmi_video_csc
  12. hdmi_video_sample
  13. hdmi_tx_hdcp_config
  14. dwc_hdmi_clear_overflow
  15. If connected and not in DVI mode, hdmi_enable_overflow_interrupts is invoked.

PHY Configuration

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

CPCE_CTRL

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.

GMPCTRL

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.

CURRCTRL

Address 0x10 (CURRCTRL) appears to use values related to colour resolution and frequency range in various combinations.