DWC HDMI Controller

From linux-sunxi.org
Jump to: navigation, search

The A83T/H3/A64/A80 SoCs use a Synopsys DesignWare HDMI controller. A80 (A83T too maybe) seem to use a PHY from Synopsys too, but H3 and A64 PHY is unknown.

Contents

Register Guide

Base address: 0x01ee0000 (sun8i/sun50i), 0x03d00000 (sun9i)

HDMI_READ_LOCK

Offset
0x10010
Name Bits R/W Default Values Description
HDMI_READ_LOCK 31:0
W
0x54524545 = unlock read access
0x57415452 = lock read access

DWC HDMI Controller

0x01ee0000 - 0x01eeffff (only byte-accessible)

(A similar version of) the controller is publicly documented in the i.MX6 Reference Manual, chapter 33. There also is a mainline Linux driver for the controller in drivers/gpu/drm/bridge/dw_hdmi.c.

The design, revision, product and config IDs are 13 2a a0 c1 bf 02 fe 00 on H3/A64/A80 (A83T not tested).

Now the hard part, the register addresses are obfuscated in sunxi SoCs (except A80). To use existing drivers/documentation the address bits have to be rearranged in the following way:

real <-> obfuscated address bits
A1   <-> A15
A3   <-> A14
A5   <-> A13
A7   <-> A12
A9   <-> A11
A11  <-> A10
A13  <-> A9
A15  <-> A8
A14  <-> A7
A12  <-> A6
A10  <-> A5
A8   <-> A4
A6   <-> A3
A4   <-> A2
A2   <-> A1
A0   <-> A0

For example, to access register 0x100D (vsync width) one has to access 0x4043 on sunxi.

# Python functions to translate DWC registers to sunxi register value:
def bitrev32(x):
    x = ((x & 0x55555555) <<  1) | ((x & 0xAAAAAAAA) >>  1)
    x = ((x & 0x33333333) <<  2) | ((x & 0xCCCCCCCC) >>  2)
    x = ((x & 0x0F0F0F0F) <<  4) | ((x & 0xF0F0F0F0) >>  4)
    x = ((x & 0x00FF00FF) <<  8) | ((x & 0xFF00FF00) >>  8)
    x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16)
    return x

def dwc2sunxi(x):
    x = bitrev32(x) | x                 # put bit-reversed version in upper 16bit
    x = x & 0x55555555                  # extract all even bits
    x = (x | (x >> 1)) & 0x33333333     # move all of them to lower 16 bits
    x = (x | (x >> 2)) & 0x0f0f0f0f     # in multiple steps
    x = (x | (x >> 4)) & 0x00ff00ff
    x = (x | (x >> 8)) & 0x0000ffff
    return x
def sunxi2dwc(x):
    x = ((x & 0xff00) << 8) | (x & 0x00ff)
    x = ((x << 4) | x) & 0x0f0f0f0f
    x = ((x << 2) | x) & 0x33333333
    x = ((x << 1) | x) & 0x55555555
    x = (bitrev32(x) | x) & 0xffff
    return x

Optimized version (bitrev32() as defined in linux bitrev.h):

uint16_t dwc2sunxi(uint16_t addr)
{
    uint32_t x = bitrev32((uint32_t)addr) | (uint32_t)addr; // put bit-reversed version in upper 16bit
    x = x & 0x55555555;                                     // then extract all even bits
    x = (x | (x >> 1)) & 0x33333333;                        // and move them all to the lower 16bit
    x = (x | (x >> 2)) & 0x0f0f0f0f;                        // in multiple steps
    x = (x | (x >> 4)) & 0x00ff00ff;                        // ...
    x = (x | (x >> 8)) & 0x0000ffff;
    return (uint16_t)x;
}

DWC HDMI PHY

It looks like A80 uses a Synopsys PHY, connected to controllers internal I2C bus. This PHY is documented in the i.MX6 Reference Manual, chapter 34, too. The existing Linux driver has support for this PHY, but SoC specific parameters are needed for configuration.

H3/A64 HDMI PHY

The H3/A64 PHY is unknown and undocumented.

The HDMI block uses PLL3 as input clock, not HDMI_CLK. It looks like the input clock has to be higher than ~165MHz to get a stable HDMI signal.

Some register guessing, only notes from experiments, no facts yet:

HDMI_H3_PHY_CTRL

Offset
0x10020
Name Bits R/W Default Values Description
HDMI_TMDS_CLK_OUTPUT_EN 15
RW
enable TMDS clock output
HDMI_TMDS_2_OUTPUT_EN 14
RW
enable TMDS data2 output
HDMI_TMDS_1_OUTPUT_EN 13
RW
enable TMDS data1 output
HDMI_TMDS_0_OUTPUT_EN 12
RW
enable TMDS data0 output

HDMI_H3_PHY_PLL

Offset
0x1002c
Name Bits R/W Default Values Description
25
RW
enable pll?
5:0
RW
some pll parameter

HDMI_H3_PHY_CLK

Offset
0x10030
Name Bits R/W Default Values Description
19
RW
?enable 18:16?
18:16
RW
some pll parameter (bandwidth?)
15:12
RW
some pll parameter
HDMI_CLK_DIV 3:0
RW
clock divider

HDMI_H3_PHY_STATUS

Offset
0x10038
Name Bits R/W Default Values Description
HPD 19
RW
HPD status
16:11
RW
some pll calibration? result

HDMI_H3_PHY_CEC

Offset
0x1003c
Name Bits R/W Default Values Description
7
RW
if bit 2=0 send bit 0 on cec line
3
RW
1 = disable input cec line(bit 1) If set to 1 hw tx will send but don't get ACKs
2
RW
1 = pass cec line to hardware cec receiver
0 = pass cec line to hardware cec transmitter. Transmitting works only when bits 2:7 = 0
1
RW
status cec line when bit 3=0
0
RW
output on cec line when bit 2=0 and 7=1
Personal tools
Namespaces

Variants
Actions
Navigation
Tools