212 строки
7.6 KiB
C
212 строки
7.6 KiB
C
/*
|
|
* (c) 2020, SWD Embedded Systems Limited, http://www.kpda.ru
|
|
*/
|
|
|
|
|
|
/*************************************************/
|
|
/* TI TFP410-EP I2C HDMI transmitter interface */
|
|
/*************************************************/
|
|
|
|
|
|
/*************************************************/
|
|
/* HEADERS */
|
|
/*************************************************/
|
|
|
|
|
|
#include "vpoutfb.h"
|
|
|
|
|
|
/*************************************************/
|
|
/* REGISTERS */
|
|
/*************************************************/
|
|
|
|
|
|
/* Registers access */
|
|
#define REGISTER( addr ) (addr)
|
|
|
|
/* Registers */
|
|
#define REGISTER_VEN_ID REGISTER( 0x00 ) /* R: 16 bit */
|
|
#define REGISTER_DEV_ID REGISTER( 0x02 ) /* R: 16 bit */
|
|
#define REGISTER_REV_ID REGISTER( 0x04 ) /* R: 8 bit */
|
|
#define REGISTER_CTL_1_MODE REGISTER( 0x08 ) /* RW: 8 bit */
|
|
#define REGISTER_CTL_2_MODE REGISTER( 0x09 ) /* RW: 8 bit */
|
|
#define REGISTER_CTL_3_MODE REGISTER( 0x0A ) /* RW: 8 bit */
|
|
#define REGISTER_CFG REGISTER( 0x0B ) /* R: 8 bit */
|
|
#define REGISTER_DE_DLY REGISTER( 0x32 ) /* RW: 8 bit */
|
|
#define REGISTER_DE_CTL REGISTER( 0x33 ) /* RW: 8 bit */
|
|
#define REGISTER_DE_TOP REGISTER( 0x34 ) /* RW: 8 bit */
|
|
#define REGISTER_DE_CNT REGISTER( 0x36 ) /* RW: 16 bit */
|
|
#define REGISTER_DE_LIN REGISTER( 0x38 ) /* RW: 16 bit */
|
|
#define REGISTER_H_RES REGISTER( 0x3A ) /* R: 16 bit */
|
|
#define REGISTER_V_RES REGISTER( 0x3C ) /* R: 16 bit */
|
|
|
|
|
|
/*************************************************/
|
|
/* HARDWARE */
|
|
/*************************************************/
|
|
|
|
|
|
/* Device VID */
|
|
#define TFP410EP_VID 0x014c
|
|
/* Device DID */
|
|
#define TFP410EP_DID 0x0410
|
|
|
|
|
|
/*************************************************/
|
|
/* I2C FUNCTIONS */
|
|
/*************************************************/
|
|
|
|
|
|
static void reg_write8( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port, uint8_t reg, uint8_t val )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
int ret = 0;
|
|
|
|
ret = i2c_write( vpout, vpout_draw, port, vpout->hdmi[port].device.tfp410ep.bus, vpout->hdmi[port].device.tfp410ep.speed,
|
|
vpout->hdmi[port].device.tfp410ep.address, reg, &val, 1 );
|
|
if ( ret < 0 )
|
|
goto fail;
|
|
|
|
return;
|
|
|
|
fail:
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Fatal: I2C HDMI controller register writing failed [I2C issue: port=%d, register=0x%x, status=%d]", port, reg, ret );
|
|
}
|
|
|
|
|
|
static uint8_t reg_read8( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port, uint8_t reg )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
uint8_t val = 0;
|
|
int ret = 0;
|
|
|
|
ret = i2c_read( vpout, vpout_draw, port, vpout->hdmi[port].device.tfp410ep.bus, vpout->hdmi[port].device.tfp410ep.speed,
|
|
vpout->hdmi[port].device.tfp410ep.address, reg, &val, 1 );
|
|
if ( ret < 0 )
|
|
goto fail;
|
|
|
|
return val;
|
|
|
|
fail:
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Fatal: I2C HDMI controller register reading failed [I2C issue: port=%d, register=0x%x, status=%d]", port, reg, ret );
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
static uint16_t reg_read16( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port, uint8_t reg )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
uint8_t val[2] = {0, 0};
|
|
int ret = 0;
|
|
|
|
ret = i2c_read( vpout, vpout_draw, port, vpout->hdmi[port].device.tfp410ep.bus, vpout->hdmi[port].device.tfp410ep.speed,
|
|
vpout->hdmi[port].device.tfp410ep.address, reg, &val[0], 1 );
|
|
if ( ret < 0 )
|
|
goto fail;
|
|
ret = i2c_read( vpout, vpout_draw, port, vpout->hdmi[port].device.tfp410ep.bus, vpout->hdmi[port].device.tfp410ep.speed,
|
|
vpout->hdmi[port].device.tfp410ep.address, reg + 1, &val[1], 1 );
|
|
if ( ret < 0 )
|
|
goto fail;
|
|
|
|
return (uint16_t)val[0] | ((uint16_t)val[1] << 8);
|
|
|
|
fail:
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Fatal: I2C HDMI controller register reading failed [I2C issue: port=%d, register=0x%x, status=%d]", port, reg, ret );
|
|
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*************************************************/
|
|
/* INTERFACE FUNCTIONS */
|
|
/*************************************************/
|
|
|
|
|
|
void tfp410ep_probe( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
|
|
if ( i2c_init( vpout, vpout_draw, vpout->hdmi[port_index].device.tfp410ep.bus, port_index ) )
|
|
{
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Fatal: I2C HDMI controller initialization failed [I2C issue: port=%d]", port_index );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void tfp410ep_reset( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index )
|
|
{
|
|
}
|
|
|
|
|
|
void tfp410ep_remove( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index )
|
|
{
|
|
i2c_fini( vpout, vpout_draw, port_index );
|
|
}
|
|
|
|
|
|
int tfp410ep_init( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index, uint32_t pixel_clock )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
uint16_t vid = 0,
|
|
did = 0,
|
|
rev = 0;
|
|
|
|
/* Device detection */
|
|
vid = reg_read16( vpout, vpout_draw, port_index, REGISTER_VEN_ID );
|
|
did = reg_read16( vpout, vpout_draw, port_index, REGISTER_DEV_ID );
|
|
rev = reg_read8( vpout, vpout_draw, port_index, REGISTER_REV_ID );
|
|
if ( (vid == TFP410EP_VID) && (did == TFP410EP_DID) )
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Info: TFP410-EP transmitter detected (%x:%x:%d)", vid, did, rev );
|
|
else {
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Fatal: I2C HDMI controller initialization failed [found unsupported device: %x:%x]", vid, did );
|
|
goto fail;
|
|
}
|
|
|
|
return (0);
|
|
|
|
fail:
|
|
return (-1);
|
|
}
|
|
|
|
|
|
void tfp410ep_encoder_mode_set( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index, disp_crtc_settings_t *settings )
|
|
{
|
|
/* Enable transmitter 0xbe -> 0xbf */
|
|
reg_write8( vpout, vpout_draw, port_index, REGISTER_CTL_1_MODE, 0xb7 /* RIMR device only (default 0xbf)? */ );
|
|
/* Enable data deskew 0x80 -> 0x90 */
|
|
reg_write8( vpout, vpout_draw, port_index, REGISTER_CTL_3_MODE, 0x10 );
|
|
}
|
|
|
|
|
|
int tfp410ep_read_edid( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw, uint8_t port_index, uint8_t *buf, int size_ )
|
|
{
|
|
disp_adapter_t *adapter = vpout->adapter;
|
|
int ddc_bus = vpout->hdmi[port_index].device.tfp410ep.ddc_bus,
|
|
ddc_port = port_index + 1,
|
|
ddc_slave = vpout->hdmi[port_index].device.tfp410ep.ddc_slave,
|
|
ret = -1;
|
|
|
|
if ( size_ != 256 )
|
|
return (-1);
|
|
|
|
if ( i2c_init( vpout, vpout_draw, ddc_bus, ddc_port ) < 0 )
|
|
{
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Error: DDC bus detection failed (bus: %d)", ddc_bus );
|
|
goto done;
|
|
}
|
|
|
|
if ( i2c_read( vpout, vpout_draw, ddc_port, ddc_bus, 0, ddc_slave, 0, (uint8_t *)buf, size_ ) != 0 )
|
|
{
|
|
disp_printf( adapter, "[vpoutfb: tfp410ep] Error: DDC bus reading failed (bus:%d, slave: 0x%x)", ddc_bus, ddc_slave );
|
|
goto done;
|
|
} else
|
|
ret = size_;
|
|
|
|
done:
|
|
i2c_fini( vpout, vpout_draw, ddc_port );
|
|
|
|
return ret;
|
|
}
|