user can change hdmi_dbg_level value to printf log which you want.
1 : cec
2 : hdmi
3 : hdcp
such as, echo 2 > /sys/module/rockchip_hdmi_sysfs/parameters/hdmi_dbg_level
Change-Id: Iaa5a66c2926789694e0d544196bedc81fb3a755a
Signed-off-by: Shen Zhenyi <szy@rock-chips.com>
(cherry picked from commit 919cb0208a)
995 lines
28 KiB
C
995 lines
28 KiB
C
#include <linux/delay.h>
|
|
#include <linux/io.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/of_irq.h>
|
|
#include "rockchip_hdmiv1.h"
|
|
#include "rockchip_hdmiv1_hw.h"
|
|
#include "rockchip_hdmiv1_hdcp.h"
|
|
|
|
static inline void delay100us(void)
|
|
{
|
|
usleep_range(99, 100);
|
|
}
|
|
|
|
static void rockchip_hdmiv1_av_mute(struct hdmi *hdmi_drv, bool enable)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (enable) {
|
|
hdmi_msk_reg(hdmi_dev, AV_MUTE,
|
|
m_AVMUTE_CLEAR | m_AVMUTE_ENABLE,
|
|
v_AVMUTE_CLEAR(0) | v_AVMUTE_ENABLE(1));
|
|
} else {
|
|
hdmi_msk_reg(hdmi_dev, AV_MUTE,
|
|
m_AVMUTE_CLEAR | m_AVMUTE_ENABLE,
|
|
v_AVMUTE_CLEAR(1) | v_AVMUTE_ENABLE(0));
|
|
}
|
|
hdmi_msk_reg(hdmi_dev, PACKET_SEND_AUTO,
|
|
m_PACKET_GCP_EN, v_PACKET_GCP_EN(1));
|
|
}
|
|
|
|
static void rockchip_hdmiv1_sys_power(struct hdmi *hdmi_drv, bool enable)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (enable)
|
|
hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_POWER, v_PWR_ON);
|
|
else
|
|
hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_POWER, v_PWR_OFF);
|
|
}
|
|
|
|
static void rockchip_hdmiv1_set_pwr_mode(struct hdmi *hdmi_drv, int mode)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (hdmi_dev->pwr_mode == mode)
|
|
return;
|
|
|
|
dev_info(hdmi_drv->dev, "%s change pwr_mode %d --> %d\n", __func__,
|
|
hdmi_dev->pwr_mode, mode);
|
|
|
|
switch (mode) {
|
|
case NORMAL:
|
|
dev_info(hdmi_drv->dev,
|
|
"%s change pwr_mode NORMAL\n",
|
|
__func__);
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, false);
|
|
if (hdmi_dev->soctype == HDMI_SOC_RK3036) {
|
|
hdmi_writel(hdmi_dev, PHY_PRE_EMPHASIS, 0x6f);
|
|
hdmi_writel(hdmi_dev, PHY_DRIVER, 0xbb);
|
|
} else if (hdmi_dev->soctype == HDMI_SOC_RK312X) {
|
|
hdmi_writel(hdmi_dev, PHY_PRE_EMPHASIS, 0x5f);
|
|
hdmi_writel(hdmi_dev, PHY_DRIVER, 0xaa);
|
|
}
|
|
|
|
hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x15);
|
|
hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x14);
|
|
hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x10);
|
|
hdmi_writel(hdmi_dev, PHY_CHG_PWR, 0x0f);
|
|
hdmi_writel(hdmi_dev, 0xce, 0x00);
|
|
hdmi_writel(hdmi_dev, 0xce, 0x01);
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, true);
|
|
break;
|
|
case LOWER_PWR:
|
|
dev_info(hdmi_drv->dev,
|
|
"%s change pwr_mode LOWER_PWR\n",
|
|
__func__);
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, false);
|
|
hdmi_writel(hdmi_dev, PHY_DRIVER, 0x00);
|
|
hdmi_writel(hdmi_dev, PHY_PRE_EMPHASIS, 0x00);
|
|
hdmi_writel(hdmi_dev, PHY_CHG_PWR, 0x00);
|
|
hdmi_writel(hdmi_dev, PHY_SYS_CTL, 0x17);
|
|
break;
|
|
default:
|
|
dev_info(hdmi_drv->dev, "unknown rk3036 hdmi pwr mode %d\n",
|
|
mode);
|
|
}
|
|
|
|
hdmi_dev->pwr_mode = mode;
|
|
}
|
|
|
|
int rockchip_hdmiv1_detect_hotplug(struct hdmi *hdmi_drv)
|
|
{
|
|
int value = 0;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
hdmi_readl(hdmi_dev, HDMI_STATUS, &value);
|
|
value &= m_HOTPLUG;
|
|
if (value == m_HOTPLUG)
|
|
return HDMI_HPD_ACTIVED;
|
|
else if (value)
|
|
return HDMI_HPD_INSERT;
|
|
else
|
|
return HDMI_HPD_REMOVED;
|
|
}
|
|
|
|
int rockchip_hdmiv1_insert(struct hdmi *hdmi_drv)
|
|
{
|
|
rockchip_hdmiv1_set_pwr_mode(hdmi_drv, NORMAL);
|
|
return 0;
|
|
}
|
|
|
|
int rockchip_hdmiv1_read_edid(struct hdmi *hdmi_drv, int block, u8 *buf)
|
|
{
|
|
u32 c = 0;
|
|
u8 segment = 0;
|
|
u8 offset = 0;
|
|
int ret = -1;
|
|
int i, j;
|
|
int ddc_bus_freq;
|
|
int trytime;
|
|
int checksum = 0;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (block % 2)
|
|
offset = HDMI_EDID_BLOCK_SIZE;
|
|
|
|
if (block / 2)
|
|
segment = 1;
|
|
ddc_bus_freq = (hdmi_dev->hclk_rate >> 2) / HDMI_SCL_RATE;
|
|
hdmi_writel(hdmi_dev, DDC_BUS_FREQ_L, ddc_bus_freq & 0xFF);
|
|
hdmi_writel(hdmi_dev, DDC_BUS_FREQ_H, (ddc_bus_freq >> 8) & 0xFF);
|
|
|
|
dev_info(hdmi_drv->dev,
|
|
"EDID DATA (Segment = %d Block = %d Offset = %d):\n",
|
|
(int)segment, (int)block, (int)offset);
|
|
disable_irq(hdmi_dev->irq);
|
|
|
|
/* Enable edid interrupt */
|
|
hdmi_writel(hdmi_dev, INTERRUPT_MASK1, m_INT_EDID_READY);
|
|
|
|
for (trytime = 0; trytime < 10; trytime++) {
|
|
checksum = 0;
|
|
hdmi_writel(hdmi_dev, INTERRUPT_STATUS1, 0x04);
|
|
|
|
/* Set edid fifo first addr */
|
|
hdmi_writel(hdmi_dev, EDID_FIFO_OFFSET, 0x00);
|
|
|
|
/* Set edid word address 0x00/0x80 */
|
|
hdmi_writel(hdmi_dev, EDID_WORD_ADDR, offset);
|
|
|
|
/* Set edid segment pointer */
|
|
hdmi_writel(hdmi_dev, EDID_SEGMENT_POINTER, segment);
|
|
|
|
for (i = 0; i < 200; i++) {
|
|
/* Wait edid interrupt */
|
|
usleep_range(900, 1000);
|
|
c = 0x00;
|
|
hdmi_readl(hdmi_dev, INTERRUPT_STATUS1, &c);
|
|
|
|
if (c & m_INT_EDID_READY)
|
|
break;
|
|
}
|
|
|
|
if (c & m_INT_EDID_READY) {
|
|
for (j = 0; j < HDMI_EDID_BLOCK_SIZE; j++) {
|
|
c = 0;
|
|
hdmi_readl(hdmi_dev, 0x50, &c);
|
|
buf[j] = c;
|
|
checksum += c;
|
|
}
|
|
|
|
if ((checksum & 0xff) == 0) {
|
|
ret = 0;
|
|
dev_info(hdmi_drv->dev,
|
|
"[%s] edid read success\n", __func__);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*close edid irq*/
|
|
hdmi_writel(hdmi_dev, INTERRUPT_MASK1, 0);
|
|
/* clear EDID interrupt reg */
|
|
hdmi_writel(hdmi_dev, INTERRUPT_STATUS1,
|
|
m_INT_EDID_READY);
|
|
|
|
enable_irq(hdmi_dev->irq);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const char coeff_csc[][24] = {
|
|
/* YUV2RGB:601 SD mode(Y[16:235],UV[16:240],RGB[0:255]):
|
|
* R = 1.164*Y +1.596*V - 204
|
|
* G = 1.164*Y - 0.391*U - 0.813*V + 154
|
|
* B = 1.164*Y + 2.018*U - 258
|
|
*/
|
|
{
|
|
0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc,
|
|
0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a,
|
|
0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02},
|
|
|
|
/* YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]):
|
|
* R = Y + 1.402*V - 248
|
|
* G = Y - 0.344*U - 0.714*V + 135
|
|
* B = Y + 1.772*U - 227
|
|
*/
|
|
{
|
|
0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8,
|
|
0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87,
|
|
0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3},
|
|
/* YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]):
|
|
* R = 1.164*Y +1.793*V - 248
|
|
* G = 1.164*Y - 0.213*U - 0.534*V + 77
|
|
* B = 1.164*Y + 2.115*U - 289
|
|
*/
|
|
{
|
|
0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8,
|
|
0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d,
|
|
0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21},
|
|
/* RGB2YUV:601 SD mode:
|
|
* Cb = -0.291G - 0.148R + 0.439B + 128
|
|
* Y = 0.504G + 0.257R + 0.098B + 16
|
|
* Cr = -0.368G + 0.439R - 0.071B + 128
|
|
*/
|
|
{
|
|
0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
|
|
0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
|
|
0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
|
|
},
|
|
|
|
/* RGB2YUV:709 HD mode:
|
|
* Cb = - 0.338G - 0.101R + 0.439B + 128
|
|
* Y = 0.614G + 0.183R + 0.062B + 16
|
|
* Cr = - 0.399G + 0.439R - 0.040B + 128
|
|
*/
|
|
{
|
|
0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
|
|
0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
|
|
0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
|
|
},
|
|
/* RGB[0:255]2RGB[16:235]:
|
|
* R' = R x (235-16)/255 + 16;
|
|
* G' = G x (235-16)/255 + 16;
|
|
* B' = B x (235-16)/255 + 16;
|
|
*/
|
|
{
|
|
0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
|
|
0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
|
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10},
|
|
};
|
|
|
|
static int rockchip_hdmiv1_video_csc(struct hdmi *hdmi_drv,
|
|
struct hdmi_video *vpara)
|
|
{
|
|
int value, i, csc_mode, c0_c2_change, auto_csc, csc_enable;
|
|
const char *coeff = NULL;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
/* Enable or disalbe color space convert */
|
|
dev_info(hdmi_drv->dev, "[%s] input_color=%d,output_color=%d\n",
|
|
__func__, vpara->color_input, vpara->color_output);
|
|
if (vpara->color_input == vpara->color_output) {
|
|
if ((vpara->color_input >= HDMI_COLOR_YCBCR444) ||
|
|
(vpara->color_input == HDMI_COLOR_RGB_0_255)) {
|
|
value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
|
|
v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
|
|
v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
|
|
return 0;
|
|
} else if (vpara->color_input == HDMI_COLOR_RGB_16_235) {
|
|
csc_mode = CSC_RGB_0_255_TO_RGB_16_235_8BIT;
|
|
auto_csc = AUTO_CSC_DISABLE;
|
|
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
|
csc_enable = v_CSC_ENABLE;
|
|
}
|
|
}
|
|
|
|
switch (vpara->vic) {
|
|
case HDMI_720X480I_60HZ_4_3:
|
|
case HDMI_720X576I_50HZ_4_3:
|
|
case HDMI_720X480P_60HZ_4_3:
|
|
case HDMI_720X576P_50HZ_4_3:
|
|
case HDMI_720X480I_60HZ_16_9:
|
|
case HDMI_720X576I_50HZ_16_9:
|
|
case HDMI_720X480P_60HZ_16_9:
|
|
case HDMI_720X576P_50HZ_16_9:
|
|
if (((vpara->color_input == HDMI_COLOR_RGB_0_255) ||
|
|
(vpara->color_input == HDMI_COLOR_RGB_16_235)) &&
|
|
vpara->color_output >= HDMI_COLOR_YCBCR444) {
|
|
csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
|
|
auto_csc = AUTO_CSC_DISABLE;
|
|
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
|
csc_enable = v_CSC_ENABLE;
|
|
} else if (vpara->color_input >= HDMI_COLOR_YCBCR444 &&
|
|
((vpara->color_output == HDMI_COLOR_RGB_0_255) ||
|
|
(vpara->color_output == HDMI_COLOR_RGB_16_235))) {
|
|
#ifdef AUTO_DEFINE_CSC
|
|
csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
|
|
auto_csc = AUTO_CSC_ENABLE;
|
|
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
|
csc_enable = v_CSC_DISABLE;
|
|
#else
|
|
csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
|
|
auto_csc = AUTO_CSC_DISABLE;
|
|
c0_c2_change = C0_C2_CHANGE_ENABLE;
|
|
csc_enable = v_CSC_ENABLE;
|
|
#endif
|
|
}
|
|
break;
|
|
default:
|
|
if (((vpara->color_input == HDMI_COLOR_RGB_0_255) ||
|
|
(vpara->color_input == HDMI_COLOR_RGB_16_235)) &&
|
|
vpara->color_output >= HDMI_COLOR_YCBCR444) {
|
|
csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
|
|
auto_csc = AUTO_CSC_DISABLE;
|
|
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
|
csc_enable = v_CSC_ENABLE;
|
|
} else if (vpara->color_input >= HDMI_COLOR_YCBCR444 &&
|
|
((vpara->color_output == HDMI_COLOR_RGB_0_255) ||
|
|
(vpara->color_output == HDMI_COLOR_RGB_16_235))) {
|
|
#ifdef AUTO_DEFINE_CSC
|
|
csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT;
|
|
auto_csc = AUTO_CSC_ENABLE;
|
|
c0_c2_change = C0_C2_CHANGE_DISABLE;
|
|
csc_enable = v_CSC_DISABLE;
|
|
#else
|
|
/*CSC_ITU709_16_235_TO_RGB_0_255_8BIT;*/
|
|
csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
|
|
auto_csc = AUTO_CSC_DISABLE;
|
|
c0_c2_change = C0_C2_CHANGE_ENABLE;
|
|
csc_enable = v_CSC_ENABLE;
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
coeff = coeff_csc[csc_mode];
|
|
for (i = 0; i < 24; i++)
|
|
hdmi_writel(hdmi_dev, VIDEO_CSC_COEF + i, coeff[i]);
|
|
|
|
value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC |
|
|
m_VIDEO_C0_C2_SWAP,
|
|
v_VIDEO_AUTO_CSC(auto_csc) |
|
|
v_VIDEO_C0_C2_SWAP(c0_c2_change));
|
|
|
|
#if 0
|
|
if (vpara->input_color != vpara->output_color) {
|
|
if (vpara->input_color == VIDEO_INPUT_COLOR_RGB) {/*rgb2yuv*/
|
|
coeff = coeff_csc[3];
|
|
for (i = 0; i < 24; i++)
|
|
hdmi_writel(hdmi_dev,
|
|
VIDEO_CSC_COEF + i, coeff[i]);
|
|
|
|
value = v_SOF_DISABLE | v_CSC_ENABLE;
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_EXCHANGE,
|
|
v_VIDEO_AUTO_CSC(0) |
|
|
v_VIDEO_C0_C2_EXCHANGE(1));
|
|
} else {/*yuv2rgb*/
|
|
#ifdef AUTO_DEFINE_CSC
|
|
value = v_SOF_DISABLE | v_CSC_DISABLE;
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_EXCHANGE,
|
|
v_VIDEO_AUTO_CSC(1) |
|
|
v_VIDEO_C0_C2_EXCHANGE(1));
|
|
#else
|
|
if (hdmi_drv->lcdc->cur_screen->mode.xres <= 576) {
|
|
/*x <= 576,REC-601*/
|
|
coeff = coeff_csc[0];
|
|
pr_info("xres<=576,xres=%d\n",
|
|
hdmi_drv->lcdc->cur_screen->mode.xres);
|
|
} else/*x > 576,REC-709*/{
|
|
coeff = coeff_csc[2];
|
|
pr_info("xres>576,xres=%d\n",
|
|
hdmi_drv->lcdc->cur_screen->mode.xres);
|
|
}
|
|
for (i = 0; i < 24; i++)
|
|
hdmi_writel(hdmi_dev,
|
|
VIDEO_CSC_COEF + i, coeff[i]);
|
|
|
|
value = v_SOF_DISABLE | v_CSC_ENABLE;
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC |
|
|
m_VIDEO_C0_C2_EXCHANGE,
|
|
v_VIDEO_AUTO_CSC(0) |
|
|
v_VIDEO_C0_C2_EXCHANGE(0));
|
|
#endif
|
|
}
|
|
} else {
|
|
if (vpara->input_color == VIDEO_INPUT_COLOR_RGB) {
|
|
/*rgb[0:255]->rbg[16:235]*/
|
|
coeff = coeff_csc[5];
|
|
for (i = 0; i < 24; i++)
|
|
hdmi_writel(hdmi_dev,
|
|
VIDEO_CSC_COEF + i, coeff[i]);
|
|
|
|
value = v_SOF_DISABLE | v_CSC_ENABLE;
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_EXCHANGE,
|
|
v_VIDEO_AUTO_CSC(0) |
|
|
v_VIDEO_C0_C2_EXCHANGE(1));
|
|
} else {
|
|
value = v_SOF_DISABLE;
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL3, value);
|
|
hdmi_msk_reg(hdmi_dev, VIDEO_CONTRL,
|
|
m_VIDEO_AUTO_CSC |
|
|
m_VIDEO_C0_C2_EXCHANGE,
|
|
v_VIDEO_AUTO_CSC(0) |
|
|
v_VIDEO_C0_C2_EXCHANGE(1));
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static int rockchip_hdmiv1_config_vsi(struct hdmi *hdmi,
|
|
unsigned char vic_3d,
|
|
unsigned char format)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi->property->priv;
|
|
char info[SIZE_VSI_INFOFRAME];
|
|
int i;
|
|
|
|
HDMIDBG(2, "[%s] vic_3d %d format %d.\n", __func__, vic_3d, format);
|
|
memset(info, 0, SIZE_VSI_INFOFRAME);
|
|
hdmi_msk_reg(hdmi_dev, PACKET_SEND_AUTO,
|
|
m_PACKET_VSI_EN, v_PACKET_VSI_EN(0));
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_BUF_INDEX, INFOFRAME_VSI);
|
|
/* Header Bytes */
|
|
info[0] = 0x81;
|
|
info[1] = 0x01;
|
|
/* PB1 - PB3 contain the 24bit IEEE Registration Identifier */
|
|
info[4] = 0x03;
|
|
info[5] = 0x0c;
|
|
info[6] = 0x00;
|
|
/* PB4 - HDMI_Video_Format into bits 7:5 */
|
|
info[7] = format << 5;
|
|
/* PB5 - Depending on the video format, this byte will contain either
|
|
* the HDMI_VIC code in buts 7:0, OR the 3D_Structure in bits 7:4.
|
|
*/
|
|
switch (format) {
|
|
case HDMI_VIDEO_FORMAT_4KX2K:
|
|
/* This is a 2x4K mode, set the HDMI_VIC in buts 7:0. Values
|
|
* are from HDMI 1.4 Spec, 8.2.3.1 (Table 8-13).
|
|
*/
|
|
info[2] = 0x06 - 1;
|
|
info[8] = vic_3d;
|
|
info[9] = 0;
|
|
break;
|
|
case HDMI_VIDEO_FORMAT_3D:
|
|
/* This is a 3D mode, set the 3D_Structure in buts 7:4
|
|
* Bits 3:0 are reseved so set to 0. Values are from HDMI 1.4
|
|
* Spec, Appendix H (Table H-2).
|
|
*/
|
|
info[8] = vic_3d << 4;
|
|
/* Add the Extended data field when the 3D format is
|
|
* Side-by-Side(Half). See Spec Table H-3 for details.
|
|
*/
|
|
if ((info[8] >> 4) == HDMI_3D_SIDE_BY_SIDE_HALF) {
|
|
info[2] = 0x06;
|
|
info[9] = 0x00;
|
|
} else {
|
|
info[2] = 0x06 - 1;
|
|
}
|
|
break;
|
|
default:
|
|
info[2] = 0x06 - 2;
|
|
info[8] = 0;
|
|
info[9] = 0;
|
|
break;
|
|
}
|
|
info[3] = info[0] + info[1] + info[2];
|
|
/* Calculate InfoFrame ChecKsum */
|
|
for (i = 4; i < SIZE_VSI_INFOFRAME; i++)
|
|
info[3] += info[i];
|
|
info[3] = 0x100 - info[3];
|
|
|
|
for (i = 0; i < SIZE_VSI_INFOFRAME; i++)
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_ADDR + i, info[i]);
|
|
hdmi_msk_reg(hdmi_dev, PACKET_SEND_AUTO,
|
|
m_PACKET_VSI_EN, v_PACKET_VSI_EN(1));
|
|
return 0;
|
|
}
|
|
|
|
static void rockchip_hdmiv1_config_avi(struct hdmi *hdmi_drv,
|
|
unsigned char vic,
|
|
unsigned char output_color)
|
|
{
|
|
int i;
|
|
int avi_color_mode;
|
|
char info[SIZE_AVI_INFOFRAME];
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
memset(info, 0, SIZE_AVI_INFOFRAME);
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI);
|
|
info[0] = 0x82;
|
|
info[1] = 0x02;
|
|
info[2] = 0x0D;
|
|
info[3] = info[0] + info[1] + info[2];
|
|
|
|
if ((output_color == HDMI_COLOR_RGB_0_255) ||
|
|
(output_color == HDMI_COLOR_RGB_16_235))
|
|
avi_color_mode = AVI_COLOR_MODE_RGB;
|
|
else if (output_color == HDMI_COLOR_YCBCR444)
|
|
avi_color_mode = AVI_COLOR_MODE_YCBCR444;
|
|
else if (output_color == HDMI_COLOR_YCBCR422)
|
|
avi_color_mode = AVI_COLOR_MODE_YCBCR422;
|
|
else
|
|
avi_color_mode = HDMI_COLOR_RGB_0_255;
|
|
info[4] = (avi_color_mode << 5);
|
|
info[5] =
|
|
(AVI_COLORIMETRY_NO_DATA << 6) |
|
|
(AVI_CODED_FRAME_ASPECT_NO_DATA << 4) |
|
|
ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME;
|
|
info[6] = 0;
|
|
info[7] = vic;
|
|
if ((vic == HDMI_720X480I_60HZ_4_3) ||
|
|
(vic == HDMI_720X576I_50HZ_4_3) ||
|
|
(vic == HDMI_720X480I_60HZ_16_9) ||
|
|
(vic == HDMI_720X480I_60HZ_16_9))
|
|
info[8] = 1;
|
|
else
|
|
info[8] = 0;
|
|
|
|
/* Calculate AVI InfoFrame ChecKsum */
|
|
for (i = 4; i < SIZE_AVI_INFOFRAME; i++)
|
|
info[3] += info[i];
|
|
|
|
info[3] = 0x100 - info[3];
|
|
|
|
for (i = 0; i < SIZE_AVI_INFOFRAME; i++)
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_ADDR + i, info[i]);
|
|
}
|
|
|
|
static int rockchip_hdmiv1_config_video(struct hdmi *hdmi_drv,
|
|
struct hdmi_video *vpara)
|
|
{
|
|
struct fb_videomode *mode;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
int value;
|
|
|
|
dev_dbg(hdmi_drv->dev, "[%s]\n", __func__);
|
|
|
|
if (!vpara) {
|
|
dev_err(hdmi_drv->dev, "[%s] input parameter error\n",
|
|
__func__);
|
|
return -1;
|
|
}
|
|
|
|
if (hdmi_dev->soctype == HDMI_SOC_RK3036) {
|
|
/*rk3036 vop only can output rgb fmt*/
|
|
vpara->color_input = HDMI_COLOR_RGB_0_255;
|
|
}
|
|
|
|
mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic);
|
|
if (!mode) {
|
|
dev_err(hdmi_drv->dev, "[%s] not found vic %d\n", __func__,
|
|
vpara->vic);
|
|
return -ENOENT;
|
|
}
|
|
hdmi_dev->tmdsclk = mode->pixclock;
|
|
if (hdmi_drv->uboot)
|
|
return 0;
|
|
/* Disable video and audio output */
|
|
hdmi_msk_reg(hdmi_dev, AV_MUTE,
|
|
m_AUDIO_MUTE | m_AUDIO_PD | m_VIDEO_BLACK,
|
|
v_AUDIO_MUTE(1) | v_AUDIO_PD(1) | v_VIDEO_MUTE(1));
|
|
|
|
/* Input video mode is SDR RGB24bit,
|
|
* Data enable signal from external
|
|
*/
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL1,
|
|
v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444) |
|
|
v_DE_EXTERNAL);
|
|
|
|
value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS);
|
|
if (vpara->color_output <= HDMI_COLOR_RGB_16_235)
|
|
value |= v_VIDEO_OUTPUT_COLOR(0);
|
|
else
|
|
value |= v_VIDEO_OUTPUT_COLOR((vpara->color_output - 2) & 0x3);
|
|
if (vpara->color_input <= HDMI_COLOR_RGB_16_235)
|
|
value |= v_VIDEO_INPUT_CSP(0);
|
|
else
|
|
value |= v_VIDEO_INPUT_CSP((vpara->color_input - 2) & 0x1);
|
|
|
|
hdmi_writel(hdmi_dev, VIDEO_CONTRL2, value);
|
|
/* Set HDMI Mode */
|
|
hdmi_writel(hdmi_dev, HDCP_CTRL, v_HDMI_DVI(vpara->sink_hdmi));
|
|
|
|
/* Enable or disalbe color space convert */
|
|
rockchip_hdmiv1_video_csc(hdmi_drv, vpara);
|
|
|
|
/* Set ext video timing */
|
|
if ((mode->vmode || mode->pixclock <= 27000000) &&
|
|
vpara->format_3d != HDMI_3D_FRAME_PACKING) {
|
|
hdmi_writel(hdmi_dev, VIDEO_TIMING_CTL, 0);
|
|
} else {
|
|
if (vpara->format_3d == HDMI_3D_FRAME_PACKING)
|
|
value = v_EXTERANL_VIDEO(1) |
|
|
v_INETLACE(0);
|
|
else
|
|
value = v_EXTERANL_VIDEO(1) |
|
|
v_INETLACE(mode->vmode);
|
|
if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
|
|
value |= v_HSYNC_POLARITY(1);
|
|
if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
|
|
value |= v_VSYNC_POLARITY(1);
|
|
hdmi_writel(hdmi_dev, VIDEO_TIMING_CTL, value);
|
|
|
|
value = mode->left_margin +
|
|
mode->xres + mode->right_margin +
|
|
mode->hsync_len;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HTOTAL_L, value & 0xFF);
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
|
|
|
|
value = mode->left_margin +
|
|
mode->right_margin +
|
|
mode->hsync_len;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HBLANK_L, value & 0xFF);
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
|
|
|
|
value = mode->left_margin + mode->hsync_len;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HDELAY_L, value & 0xFF);
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
|
|
|
|
value = mode->hsync_len;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HDURATION_L,
|
|
value & 0xFF);
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_HDURATION_H,
|
|
(value >> 8) & 0xFF);
|
|
|
|
if (vpara->format_3d == HDMI_3D_FRAME_PACKING) {
|
|
if (mode->vmode == 0)
|
|
value = mode->upper_margin +
|
|
mode->lower_margin +
|
|
mode->vsync_len +
|
|
2 * mode->yres;
|
|
else
|
|
value = 4 * (mode->upper_margin +
|
|
mode->lower_margin +
|
|
mode->vsync_len) +
|
|
2 * mode->yres + 2;
|
|
} else {
|
|
value = mode->upper_margin +
|
|
mode->lower_margin +
|
|
mode->vsync_len +
|
|
mode->yres;
|
|
}
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_VTOTAL_L, value & 0xFF);
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
|
|
|
|
value = mode->upper_margin +
|
|
mode->vsync_len +
|
|
mode->lower_margin;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_VBLANK, value & 0xFF);
|
|
|
|
if (vpara->vic == HDMI_720X480P_60HZ_4_3 ||
|
|
vpara->vic == HDMI_720X480P_60HZ_16_9)
|
|
value = 42;
|
|
else
|
|
value = mode->upper_margin + mode->vsync_len;
|
|
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_VDELAY, value & 0xFF);
|
|
|
|
value = mode->vsync_len;
|
|
hdmi_writel(hdmi_dev, VIDEO_EXT_VDURATION, value & 0xFF);
|
|
}
|
|
if (vpara->sink_hdmi == OUTPUT_HDMI) {
|
|
rockchip_hdmiv1_config_avi(hdmi_drv, vpara->vic,
|
|
vpara->color_output);
|
|
if (vpara->format_3d != HDMI_3D_NONE) {
|
|
rockchip_hdmiv1_config_vsi(hdmi_drv,
|
|
vpara->format_3d,
|
|
HDMI_VIDEO_FORMAT_3D);
|
|
} else if ((vpara->vic > 92 && vpara->vic < 96) ||
|
|
(vpara->vic == 98)) {
|
|
vpara->vic = (vpara->vic == 98) ?
|
|
4 : (96 - vpara->vic);
|
|
rockchip_hdmiv1_config_vsi(hdmi_drv,
|
|
vpara->vic,
|
|
HDMI_VIDEO_FORMAT_4KX2K);
|
|
} else {
|
|
rockchip_hdmiv1_config_vsi(hdmi_drv,
|
|
vpara->vic,
|
|
HDMI_VIDEO_FORMAT_NORMAL);
|
|
}
|
|
dev_info(hdmi_drv->dev,
|
|
"[%s] success output HDMI.\n", __func__);
|
|
} else {
|
|
dev_info(hdmi_drv->dev,
|
|
"[%s] success output DVI.\n", __func__);
|
|
}
|
|
|
|
/* rk3028a */
|
|
hdmi_writel(hdmi_dev, PHY_PRE_DIV_RATIO, 0x1e);
|
|
hdmi_writel(hdmi_dev, PHY_FEEDBACK_DIV_RATIO_LOW, 0x2c);
|
|
hdmi_writel(hdmi_dev, PHY_FEEDBACK_DIV_RATIO_HIGH, 0x01);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void rockchip_hdmiv1_config_aai(struct hdmi *hdmi_drv)
|
|
{
|
|
int i;
|
|
char info[SIZE_AUDIO_INFOFRAME];
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
memset(info, 0, SIZE_AUDIO_INFOFRAME);
|
|
|
|
info[0] = 0x84;
|
|
info[1] = 0x01;
|
|
info[2] = 0x0A;
|
|
|
|
info[3] = info[0] + info[1] + info[2];
|
|
for (i = 4; i < SIZE_AUDIO_INFOFRAME; i++)
|
|
info[3] += info[i];
|
|
|
|
info[3] = 0x100 - info[3];
|
|
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_BUF_INDEX, INFOFRAME_AAI);
|
|
for (i = 0; i < SIZE_AUDIO_INFOFRAME; i++)
|
|
hdmi_writel(hdmi_dev, CONTROL_PACKET_ADDR + i, info[i]);
|
|
}
|
|
|
|
static int rockchip_hdmiv1_config_audio(struct hdmi *hdmi_drv,
|
|
struct hdmi_audio *audio)
|
|
{
|
|
int rate, N, channel, mclk_fs;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (audio->channel < 3)
|
|
channel = I2S_CHANNEL_1_2;
|
|
else if (audio->channel < 5)
|
|
channel = I2S_CHANNEL_3_4;
|
|
else if (audio->channel < 7)
|
|
channel = I2S_CHANNEL_5_6;
|
|
else
|
|
channel = I2S_CHANNEL_7_8;
|
|
|
|
switch (audio->rate) {
|
|
case HDMI_AUDIO_FS_32000:
|
|
rate = AUDIO_32K;
|
|
N = N_32K;
|
|
mclk_fs = MCLK_384FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_44100:
|
|
rate = AUDIO_441K;
|
|
N = N_441K;
|
|
mclk_fs = MCLK_256FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_48000:
|
|
rate = AUDIO_48K;
|
|
N = N_48K;
|
|
mclk_fs = MCLK_256FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_88200:
|
|
rate = AUDIO_882K;
|
|
N = N_882K;
|
|
mclk_fs = MCLK_128FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_96000:
|
|
rate = AUDIO_96K;
|
|
N = N_96K;
|
|
mclk_fs = MCLK_128FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_176400:
|
|
rate = AUDIO_1764K;
|
|
N = N_1764K;
|
|
mclk_fs = MCLK_128FS;
|
|
break;
|
|
case HDMI_AUDIO_FS_192000:
|
|
rate = AUDIO_192K;
|
|
N = N_192K;
|
|
mclk_fs = MCLK_128FS;
|
|
break;
|
|
default:
|
|
dev_err(hdmi_drv->dev,
|
|
"[%s] not support such sample rate %d\n",
|
|
__func__, audio->rate);
|
|
return -ENOENT;
|
|
}
|
|
|
|
/* set_audio source I2S */
|
|
if (hdmi_dev->audiosrc == HDMI_AUDIO_SRC_IIS) {
|
|
hdmi_writel(hdmi_dev, AUDIO_CTRL1, 0x01);
|
|
hdmi_writel(hdmi_dev, AUDIO_SAMPLE_RATE, rate);
|
|
hdmi_writel(hdmi_dev, AUDIO_I2S_MODE,
|
|
v_I2S_MODE(I2S_STANDARD) |
|
|
v_I2S_CHANNEL(channel));
|
|
hdmi_writel(hdmi_dev, AUDIO_I2S_MAP, 0x00);
|
|
/* no swap */
|
|
hdmi_writel(hdmi_dev, AUDIO_I2S_SWAPS_SPDIF, 0);
|
|
} else {
|
|
hdmi_writel(hdmi_dev, AUDIO_CTRL1, 0x08);
|
|
/* no swap */
|
|
hdmi_writel(hdmi_dev, AUDIO_I2S_SWAPS_SPDIF, 0);
|
|
}
|
|
|
|
/* Set N value */
|
|
hdmi_writel(hdmi_dev, AUDIO_N_H, (N >> 16) & 0x0F);
|
|
hdmi_writel(hdmi_dev, AUDIO_N_M, (N >> 8) & 0xFF);
|
|
hdmi_writel(hdmi_dev, AUDIO_N_L, N & 0xFF);
|
|
|
|
/*Set hdmi nlpcm mode to support hdmi bitstream*/
|
|
if (audio->type == HDMI_AUDIO_NLPCM)
|
|
hdmi_writel(hdmi_dev, AUDIO_CHANNEL_STATUS,
|
|
v_AUDIO_STATUS_NLPCM(1));
|
|
else
|
|
hdmi_writel(hdmi_dev, AUDIO_CHANNEL_STATUS,
|
|
v_AUDIO_STATUS_NLPCM(0));
|
|
|
|
rockchip_hdmiv1_config_aai(hdmi_drv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rockchip_hdmiv1_control_output(struct hdmi *hdmi_drv, int enable)
|
|
{
|
|
int mutestatus = 0;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (hdmi_drv->uboot) {
|
|
hdmi_drv->uboot = 0;
|
|
return 0;
|
|
}
|
|
|
|
if (enable == HDMI_AV_UNMUTE) {
|
|
if (hdmi_dev->pwr_mode == LOWER_PWR)
|
|
rockchip_hdmiv1_set_pwr_mode(hdmi_drv, NORMAL);
|
|
hdmi_readl(hdmi_dev, AV_MUTE, &mutestatus);
|
|
if (mutestatus & m_VIDEO_BLACK) {
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, true);
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, false);
|
|
delay100us();
|
|
rockchip_hdmiv1_sys_power(hdmi_drv, true);
|
|
hdmi_writel(hdmi_dev, 0xce, 0x00);
|
|
delay100us();
|
|
hdmi_writel(hdmi_dev, 0xce, 0x01);
|
|
}
|
|
|
|
if (mutestatus && (m_AUDIO_MUTE | m_VIDEO_BLACK)) {
|
|
hdmi_msk_reg(hdmi_dev, AV_MUTE,
|
|
m_AUDIO_MUTE |
|
|
m_AUDIO_PD |
|
|
m_VIDEO_BLACK,
|
|
v_AUDIO_MUTE(0) |
|
|
v_AUDIO_PD(0) |
|
|
v_VIDEO_MUTE(0));
|
|
}
|
|
rockchip_hdmiv1_av_mute(hdmi_drv, 0);
|
|
} else {
|
|
mutestatus = 0;
|
|
if (enable & HDMI_VIDEO_MUTE)
|
|
mutestatus |= v_VIDEO_MUTE(1);
|
|
if (enable & HDMI_AUDIO_MUTE)
|
|
mutestatus |= (v_AUDIO_MUTE(1) | v_AUDIO_PD(1));
|
|
hdmi_msk_reg(hdmi_dev, AV_MUTE,
|
|
m_AUDIO_MUTE | m_AUDIO_PD | m_VIDEO_BLACK,
|
|
mutestatus);
|
|
|
|
if (enable == (HDMI_VIDEO_MUTE | HDMI_AUDIO_MUTE)) {
|
|
rockchip_hdmiv1_av_mute(hdmi_drv, 1);
|
|
msleep(100);
|
|
rockchip_hdmiv1_set_pwr_mode(hdmi_drv, LOWER_PWR);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int rockchip_hdmiv1_removed(struct hdmi *hdmi_drv)
|
|
{
|
|
dev_info(hdmi_drv->dev, "Removed.\n");
|
|
if (hdmi_drv->ops->hdcp_power_off_cb)
|
|
hdmi_drv->ops->hdcp_power_off_cb(hdmi_drv);
|
|
|
|
rockchip_hdmiv1_control_output(hdmi_drv, -1);
|
|
rockchip_hdmiv1_set_pwr_mode(hdmi_drv, LOWER_PWR);
|
|
|
|
return HDMI_ERROR_SUCCESS;
|
|
}
|
|
|
|
static int rockchip_hdmiv1_enable(struct hdmi *hdmi_drv)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (!hdmi_dev->enable) {
|
|
hdmi_dev->enable = 1;
|
|
hdmi_msk_reg(hdmi_dev, HDMI_STATUS,
|
|
m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1));
|
|
}
|
|
hdmi_submit_work(hdmi_drv, HDMI_HPD_CHANGE, 10, 0);
|
|
return 0;
|
|
}
|
|
|
|
static int rockchip_hdmiv1_disable(struct hdmi *hdmi_drv)
|
|
{
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
if (hdmi_dev->enable) {
|
|
hdmi_dev->enable = 0;
|
|
hdmi_msk_reg(hdmi_dev, HDMI_STATUS,
|
|
m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(0));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void rockchip_hdmiv1_irq(struct hdmi *hdmi_drv)
|
|
{
|
|
u32 interrupt = 0;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
hdmi_readl(hdmi_dev, INTERRUPT_STATUS1, &interrupt);
|
|
if (interrupt) {
|
|
hdmi_writel(hdmi_dev, INTERRUPT_STATUS1, interrupt);
|
|
dev_info(hdmi_drv->dev, "Clear edid irq.\n");
|
|
}
|
|
|
|
hdmi_readl(hdmi_dev, HDMI_STATUS, &interrupt);
|
|
if (interrupt)
|
|
hdmi_writel(hdmi_dev, HDMI_STATUS, interrupt);
|
|
if (interrupt & m_INT_HOTPLUG)
|
|
hdmi_submit_work(hdmi_drv, HDMI_HPD_CHANGE, 20, 0);
|
|
|
|
if (hdmi_drv->ops->hdcp_irq_cb)
|
|
hdmi_drv->ops->hdcp_irq_cb(0);
|
|
if (hdmi_drv->property->feature & SUPPORT_CEC)
|
|
rockchip_hdmiv1_cec_isr(hdmi_dev);
|
|
}
|
|
|
|
static void rockchip_hdmiv1_reset(struct hdmi *hdmi_drv)
|
|
{
|
|
u32 val = 0;
|
|
u32 msk = 0;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
|
|
delay100us();
|
|
hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
|
|
delay100us();
|
|
msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
|
|
val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
|
|
hdmi_msk_reg(hdmi_dev, SYS_CTRL, msk, val);
|
|
|
|
rockchip_hdmiv1_set_pwr_mode(hdmi_drv, LOWER_PWR);
|
|
}
|
|
|
|
void rockchip_hdmiv1_dev_init_ops(struct hdmi_ops *ops)
|
|
{
|
|
if (ops) {
|
|
ops->disable = rockchip_hdmiv1_disable;
|
|
ops->enable = rockchip_hdmiv1_enable;
|
|
ops->remove = rockchip_hdmiv1_removed;
|
|
ops->setmute = rockchip_hdmiv1_control_output;
|
|
ops->setvideo = rockchip_hdmiv1_config_video;
|
|
ops->setaudio = rockchip_hdmiv1_config_audio;
|
|
ops->getstatus = rockchip_hdmiv1_detect_hotplug;
|
|
ops->getedid = rockchip_hdmiv1_read_edid;
|
|
ops->insert = rockchip_hdmiv1_insert;
|
|
ops->setvsi = rockchip_hdmiv1_config_vsi;
|
|
}
|
|
}
|
|
|
|
int rockchip_hdmiv1_initial(struct hdmi *hdmi_drv)
|
|
{
|
|
int rc = HDMI_ERROR_SUCCESS;
|
|
struct hdmi_dev *hdmi_dev = hdmi_drv->property->priv;
|
|
|
|
hdmi_dev->pwr_mode = NORMAL;
|
|
|
|
if (!hdmi_drv->uboot) {
|
|
rockchip_hdmiv1_reset_pclk();
|
|
rockchip_hdmiv1_reset(hdmi_drv);
|
|
hdmi_msk_reg(hdmi_dev, HDMI_STATUS,
|
|
m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(0));
|
|
} else if (hdmi_drv->ops->getstatus(hdmi_drv) == HDMI_HPD_REMOVED) {
|
|
rockchip_hdmiv1_removed(hdmi_drv);
|
|
hdmi_drv->lcdc->uboot_logo = 0;
|
|
hdmi_drv->uboot = 0;
|
|
}
|
|
if (hdmi_drv->property->feature & SUPPORT_CEC)
|
|
rockchip_hdmiv1_cec_init(hdmi_drv);
|
|
if (hdmi_drv->property->feature & SUPPORT_HDCP)
|
|
rockchip_hdmiv1_hdcp_init(hdmi_drv);
|
|
return rc;
|
|
}
|