| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <linux/delay.h> |
| #include <linux/interrupt.h> |
| #include <linux/fs.h> |
| #include <linux/init.h> |
| #include <linux/device.h> |
| #include <linux/mm.h> |
| #include <linux/major.h> |
| #include <linux/platform_device.h> |
| #include <linux/mutex.h> |
| #include <linux/cdev.h> |
| #include <linux/slab.h> |
| #include <linux/uaccess.h> |
| #include <linux/delay.h> |
| #include <linux/clk.h> |
| #include <linux/reset.h> |
| #include <linux/compiler.h> |
| #include <linux/arm-smccc.h> |
| |
| #include <linux/amlogic/media/vout/vinfo.h> |
| #include <linux/amlogic/media/vout/hdmi_tx21/enc_clk_config.h> |
| #include <linux/amlogic/media/vout/hdmi_tx21/hdmi_info_global.h> |
| #include <linux/amlogic/media/vout/hdmi_tx21/hdmi_tx_module.h> |
| #include <linux/amlogic/media/vout/hdmi_tx21/hdmi_tx_ddc.h> |
| #include <linux/arm-smccc.h> |
| #include "common.h" |
| |
| #define MESON_CPU_ID_T7 0 |
| static void hdmi_phy_suspend(void); |
| static void hdmi_phy_wakeup(struct hdmitx_dev *hdev); |
| static void hdmitx_set_phy(struct hdmitx_dev *hdev); |
| static void hdmitx_set_hw(struct hdmitx_dev *hdev); |
| static void hdmitx_csc_config(u8 input_color_format, |
| u8 output_color_format, |
| u8 color_depth); |
| static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev, |
| u32 dvi_mode); |
| |
| static int hdmitx_set_dispmode(struct hdmitx_dev *hdev); |
| static int hdmitx_set_audmode(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param); |
| static void hdmitx_debug(struct hdmitx_dev *hdev, const char *buf); |
| static void hdmitx_debug_bist(struct hdmitx_dev *hdev, u32 num); |
| static void hdmitx_uninit(struct hdmitx_dev *hdev); |
| static int hdmitx_cntl(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv); |
| static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, u32 cmd, |
| unsigned long argv); |
| static int hdmitx_get_state(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv); |
| static int hdmitx_cntl_config(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv); |
| static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv); |
| static enum hdmi_vic get_vic_from_pkt(void); |
| |
| #define EDID_RAM_ADDR_SIZE (8) |
| |
| /* HSYNC polarity: active high */ |
| #define HSYNC_POLARITY 1 |
| /* VSYNC polarity: active high */ |
| #define VSYNC_POLARITY 1 |
| /* Pixel format: 0=RGB444; 1=YCbCr444; 2=Rsrv; 3=YCbCr422. */ |
| #define TX_INPUT_COLOR_FORMAT HDMI_COLORSPACE_YUV444 |
| /* Pixel range: 0=16-235/240; 1=16-240; 2=1-254; 3=0-255. */ |
| #define TX_INPUT_COLOR_RANGE 0 |
| /* Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit. */ |
| #define TX_COLOR_DEPTH COLORDEPTH_24B |
| |
| int hdmitx21_hpd_hw_op(enum hpd_op cmd) |
| { |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| default: |
| return !!(hd21_read_reg(PADCTRL_GPIOW_I) & (1 << 15)); |
| } |
| return 0; |
| } |
| EXPORT_SYMBOL(hdmitx21_hpd_hw_op); |
| |
| int read21_hpd_gpio(void) |
| { |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| default: |
| return 1; |
| } |
| return 0; |
| } |
| EXPORT_SYMBOL(read21_hpd_gpio); |
| |
| int hdmitx21_ddc_hw_op(enum ddc_op cmd) |
| { |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| default: |
| return 1; |
| } |
| return 0; |
| } |
| EXPORT_SYMBOL(hdmitx21_ddc_hw_op); |
| |
| static void config_avmute(u32 val) |
| { |
| pr_info(HW "avmute set to %d\n", val); |
| switch (val) { |
| case SET_AVMUTE: |
| break; |
| case CLR_AVMUTE: |
| break; |
| case OFF_AVMUTE: |
| default: |
| break; |
| } |
| } |
| |
| void hdmitx21_set_avi_vic(enum hdmi_vic vic) |
| { |
| } |
| |
| static int read_avmute(void) |
| { |
| return 0; |
| } |
| |
| static void config_video_mapping(enum hdmi_colorspace cs, |
| enum hdmi_color_depth cd) |
| { |
| u32 val = 0; |
| |
| pr_info("config: cs = %d cd = %d\n", cs, cd); |
| switch (cs) { |
| case HDMI_COLORSPACE_RGB: |
| switch (cd) { |
| case COLORDEPTH_24B: |
| val = 0x1; |
| break; |
| case COLORDEPTH_30B: |
| val = 0x3; |
| break; |
| case COLORDEPTH_36B: |
| val = 0x5; |
| break; |
| case COLORDEPTH_48B: |
| val = 0x7; |
| break; |
| default: |
| break; |
| } |
| break; |
| case HDMI_COLORSPACE_YUV444: |
| case HDMI_COLORSPACE_YUV420: |
| switch (cd) { |
| case COLORDEPTH_24B: |
| val = 0x9; |
| break; |
| case COLORDEPTH_30B: |
| val = 0xb; |
| break; |
| case COLORDEPTH_36B: |
| val = 0xd; |
| break; |
| case COLORDEPTH_48B: |
| val = 0xf; |
| break; |
| default: |
| break; |
| } |
| break; |
| case HDMI_COLORSPACE_YUV422: |
| switch (cd) { |
| case COLORDEPTH_24B: |
| val = 0x16; |
| break; |
| case COLORDEPTH_30B: |
| val = 0x14; |
| break; |
| case COLORDEPTH_36B: |
| val = 0x12; |
| break; |
| case COLORDEPTH_48B: |
| pr_info("y422 no 48bits mode\n"); |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| switch (cd) { |
| case COLORDEPTH_24B: |
| val = 0x4; |
| break; |
| case COLORDEPTH_30B: |
| val = 0x5; |
| break; |
| case COLORDEPTH_36B: |
| val = 0x6; |
| break; |
| case COLORDEPTH_48B: |
| val = 0x7; |
| break; |
| default: |
| break; |
| } |
| switch (cd) { |
| case COLORDEPTH_30B: |
| case COLORDEPTH_36B: |
| case COLORDEPTH_48B: |
| break; |
| case COLORDEPTH_24B: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* reset HDMITX APB & TX */ |
| void hdmitx21_sys_reset(void) |
| { |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| hdmitx21_sys_reset_t7(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static bool hdmitx_uboot_already_display(void) |
| { |
| if (hd21_read_reg(ANACTRL_HDMIPHY_CTRL0)) |
| return 1; |
| return 0; |
| } |
| |
| static enum hdmi_color_depth _get_colordepth(void) |
| { |
| u32 data; |
| u8 val; |
| enum hdmi_color_depth depth = COLORDEPTH_24B; |
| |
| data = hdmitx21_rd_reg(P2T_CTRL_IVCTX); |
| if (data & (1 << 7)) { |
| val = data & 0x3; |
| switch (val) { |
| case 1: |
| depth = COLORDEPTH_30B; |
| break; |
| case 2: |
| depth = COLORDEPTH_36B; |
| break; |
| case 3: |
| depth = COLORDEPTH_48B; |
| break; |
| case 0: |
| default: |
| depth = COLORDEPTH_24B; |
| break; |
| } |
| } |
| |
| return depth; |
| } |
| |
| static enum hdmi_vic _get_vic_from_vsif(struct hdmitx_dev *hdev) |
| { |
| int ret; |
| u8 body[32] = {0}; |
| enum hdmi_vic hdmi4k_vic = HDMI_0_UNKNOWN; |
| union hdmi_infoframe *infoframe = &hdev->infoframes.vend; |
| struct hdmi_vendor_infoframe *vendor = &infoframe->vendor.hdmi; |
| |
| hdmitx_infoframe_rawget(HDMI_INFOFRAME_TYPE_VENDOR, body); |
| ret = hdmi_infoframe_unpack(infoframe, body, sizeof(body)); |
| if (ret < 0) { |
| pr_info("hdmitx21: parsing VEND failed %d\n", ret); |
| } else { |
| switch (vendor->vic) { |
| case 1: |
| hdmi4k_vic = HDMI_95_3840x2160p30_16x9; |
| break; |
| case 2: |
| hdmi4k_vic = HDMI_94_3840x2160p25_16x9; |
| break; |
| case 3: |
| hdmi4k_vic = HDMI_93_3840x2160p24_16x9; |
| break; |
| case 4: |
| hdmi4k_vic = HDMI_98_4096x2160p24_256x135; |
| break; |
| default: |
| break; |
| } |
| } |
| return hdmi4k_vic; |
| } |
| |
| static void hdmi_hwp_init(struct hdmitx_dev *hdev) |
| { |
| u32 data32; |
| |
| if (hdmitx_uboot_already_display()) { |
| int ret; |
| u8 body[32] = {0}; |
| union hdmi_infoframe *infoframe = &hdev->infoframes.avi; |
| struct hdmi_avi_infoframe *avi = &infoframe->avi; |
| const struct hdmi_timing *tp; |
| const char *name; |
| enum hdmi_vic vic = HDMI_0_UNKNOWN; |
| |
| hdmitx_infoframe_rawget(HDMI_INFOFRAME_TYPE_AVI, body); |
| ret = hdmi_infoframe_unpack(infoframe, body, sizeof(body)); |
| if (ret < 0) { |
| pr_info("hdmitx21: parsing AVI failed %d\n", ret); |
| } else { |
| if (!hdev->para) |
| return; |
| if (hdev->para) { |
| hdev->para->cs = avi->colorspace; |
| hdev->para->cd = _get_colordepth(); |
| if (hdev->para->cs == HDMI_COLORSPACE_YUV422) |
| hdev->para->cd = COLORDEPTH_36B; |
| hdmitx21_fmt_attr(hdev); |
| vic = avi->video_code; |
| if (vic == HDMI_0_UNKNOWN) |
| vic = _get_vic_from_vsif(hdev); |
| tp = hdmitx21_gettiming_from_vic(vic); |
| name = tp->sname ? tp->sname : tp->name; |
| hdev->para = hdmitx21_get_fmtpara(name, |
| hdev->fmt_attr); |
| } else { |
| pr_info("hdmitx21: failed to get para\n"); |
| hdev->para->cs = HDMI_COLORSPACE_YUV444; |
| hdev->para->cd = COLORDEPTH_24B; |
| } |
| pr_info("hdmitx21: parsing AVI CS%d CD%d\n", |
| avi->colorspace, hdev->para->cd); |
| } |
| return; |
| } |
| |
| // -------------------------------------------------------- |
| // Program core_pin_mux to enable HDMI pins |
| // -------------------------------------------------------- |
| data32 = 0; |
| data32 |= (1 << 28); // [31:28] GPIOW_15_SEL=1 for hdmitx_hpd |
| data32 |= (1 << 24); // [27:24] GPIOW_14_SEL=1 for hdmitx_scl |
| data32 |= (1 << 20); // [23:20] GPIOW_13_SEL=1 for hdmitx_sda |
| data32 |= (1 << 12); // [15:12] GPIOW_11_SEL=1 for hdmirx_scl_B |
| data32 |= (1 << 8); // [11: 8] GPIOW_10_SEL=1 for hdmirx_sda_B |
| data32 |= (1 << 4); // [ 7: 4] GPIOW_9_SEL=1 for hdmirx_5v_B |
| data32 |= (1 << 0); // [ 3: 0] GPIOW_8_SEL=1 for hdmirx_hpd_B |
| hd21_write_reg(PADCTRL_PIN_MUX_REGN, data32); |
| |
| hdmitx21_set_default_clk(); // set MPEG, audio and default video |
| // [8] hdcp_topology_err |
| // [7] rxsense_fall |
| // [6] rxsense_rise |
| // [5] err_i2c_timeout_pls |
| // [4] hs_intr |
| // [3] core_aon_intr_rise |
| // [2] hpd_fall |
| // [1] hpd_rise |
| // [0] core_pwd_intr_rise |
| hdmitx21_wr_reg(HDMITX_TOP_INTR_STAT_CLR, 0x000001ff); |
| |
| // Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk |
| // [ 31] free_clk_en |
| // [ 13] aud_mclk_sel: 0=Use i2s_mclk; 1=Use spdif_clk. For ACR. |
| // [ 12] i2s_ws_inv |
| // [ 11] i2s_clk_inv |
| // [ 9] tmds_clk_inv |
| // [ 8] pixel_clk_inv |
| // [ 3] i2s_clk_enable |
| // [ 1] tmds_clk_enable |
| // [ 0] pixel_clk_enable |
| data32 = 0; |
| data32 |= (0 << 31); |
| data32 |= ((1 - 0) << 13); |
| data32 |= (0 << 12); |
| data32 |= (0 << 11); |
| data32 |= (0 << 9); |
| data32 |= (0 << 8); |
| data32 |= (1 << 3); |
| data32 |= (1 << 1); |
| data32 |= (1 << 0); |
| hdmitx21_wr_reg(HDMITX_TOP_CLK_CNTL, data32); |
| data32 = 0; |
| data32 |= (1 << 8); // [ 8] hdcp_topology_err |
| data32 |= (1 << 7); // [ 7] rxsense_fall |
| data32 |= (1 << 6); // [ 6] rxsense_rise |
| data32 |= (1 << 5); // [ 5] err_i2c_timeout_pls |
| data32 |= (1 << 4); // [ 4] hs_intr |
| data32 |= (1 << 3); // [ 3] core_aon_intr_rise |
| data32 |= (1 << 2); // [ 2] hpd_fall_intr |
| data32 |= (1 << 1); // [ 1] hpd_rise_intr |
| data32 |= (1 << 0); // [ 0] core_pwd_intr_rise |
| hdmitx21_wr_reg(HDMITX_TOP_INTR_MASKN, 0x6); |
| |
| //-------------------------------------------------------------------------- |
| // Configure E-DDC interface |
| //-------------------------------------------------------------------------- |
| data32 = 0; |
| data32 |= (1 << 24); // [26:24] infilter_ddc_intern_clk_divide |
| data32 |= (0 << 16); // [23:16] infilter_ddc_sample_clk_divide |
| hdmitx21_wr_reg(HDMITX_TOP_INFILTER, data32); |
| hdmitx21_set_reg_bits(AON_CYP_CTL_IVCTX, 2, 0, 2); |
| } |
| |
| int hdmitx21_uboot_audio_en(void) |
| { |
| u32 data; |
| |
| data = hdmitx21_rd_reg(0); |
| pr_info("%s[%d] data = 0x%x\n", __func__, __LINE__, data); |
| if ((data & 1) || ((data >> 3) & 1)) |
| return 1; |
| else |
| return 0; |
| } |
| |
| void hdmitx21_meson_init(struct hdmitx_dev *hdev) |
| { |
| hdev->hwop.setdispmode = hdmitx_set_dispmode; |
| hdev->hwop.setaudmode = hdmitx_set_audmode; |
| hdev->hwop.debugfun = hdmitx_debug; |
| hdev->hwop.debug_bist = hdmitx_debug_bist; |
| hdev->hwop.uninit = hdmitx_uninit; |
| hdev->hwop.cntl = hdmitx_cntl; /* todo */ |
| hdev->hwop.cntlddc = hdmitx_cntl_ddc; |
| hdev->hwop.getstate = hdmitx_get_state; |
| hdev->hwop.cntlpacket = hdmitx_cntl; |
| hdev->hwop.cntlconfig = hdmitx_cntl_config; |
| hdev->hwop.cntlmisc = hdmitx_cntl_misc; |
| hdmi_hwp_init(hdev); |
| hdmitx21_debugfs_init(); |
| hdev->hwop.cntlmisc(hdev, MISC_AVMUTE_OP, CLR_AVMUTE); |
| } |
| |
| void phy_hpll_off(void) |
| { |
| hdmi_phy_suspend(); |
| } |
| |
| static void set_phy_by_mode(u32 mode) |
| { |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| default: |
| set21_phy_by_mode_t7(mode); |
| break; |
| } |
| } |
| |
| static void hdmitx_set_phy(struct hdmitx_dev *hdev) |
| { |
| u32 phy_addr = 0; |
| |
| if (!hdev) |
| return; |
| |
| phy_addr = ANACTRL_HDMIPHY_CTRL0; |
| hd21_write_reg(phy_addr, 0x0); |
| |
| phy_addr = ANACTRL_HDMIPHY_CTRL1; |
| |
| /* P_HHI_HDMI_PHY_CNTL1 bit[1]: enable clock bit[0]: soft reset */ |
| #define RESET_HDMI_PHY() \ |
| do { \ |
| hd21_set_reg_bits(phy_addr, 0xf, 0, 4); \ |
| mdelay(2); \ |
| hd21_set_reg_bits(phy_addr, 0xe, 0, 4); \ |
| mdelay(2); \ |
| } while (0) |
| |
| hd21_set_reg_bits(phy_addr, 0x0390, 16, 16); |
| hd21_set_reg_bits(phy_addr, 0x1, 17, 1); |
| hd21_set_reg_bits(phy_addr, 0x0, 17, 1); |
| hd21_set_reg_bits(phy_addr, 0x0, 0, 4); |
| msleep(20); |
| RESET_HDMI_PHY(); |
| RESET_HDMI_PHY(); |
| RESET_HDMI_PHY(); |
| #undef RESET_HDMI_PHY |
| |
| if (hdev->para->tmds_clk > 340000) |
| set_phy_by_mode(HDMI_PHYPARA_6G); |
| else |
| set_phy_by_mode(HDMI_PHYPARA_DEF); |
| } |
| |
| static void set_vid_clk_div(u32 div) |
| { |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL, 0, 16, 3); |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_DIV, div - 1, 0, 8); |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL, 7, 0, 3); |
| } |
| |
| static void set_hdmi_tx_pixel_div(u32 div) |
| { |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL2, 1, 5, 1); |
| } |
| |
| static void set_encp_div(u32 div) |
| { |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_DIV, div, 24, 4); |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL, 1, 19, 1); |
| } |
| |
| static void hdmitx_enable_encp_clk(void) |
| { |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL2, 1, 2, 1); |
| } |
| |
| static void set_hdmitx_fe_clk(void) |
| { |
| u32 tmp = 0; |
| u32 vid_clk_cntl2; |
| u32 vid_clk_div; |
| u32 hdmi_clk_cntl; |
| |
| vid_clk_cntl2 = CLKCTRL_VID_CLK0_CTRL2; |
| vid_clk_div = CLKCTRL_VID_CLK0_DIV; |
| hdmi_clk_cntl = CLKCTRL_HDMI_CLK_CTRL; |
| |
| hd21_set_reg_bits(vid_clk_cntl2, 1, 9, 1); |
| |
| tmp = (hd21_read_reg(vid_clk_div) >> 24) & 0xf; |
| hd21_set_reg_bits(hdmi_clk_cntl, tmp, 20, 4); |
| } |
| |
| static void _hdmitx21_set_clk(void) |
| { |
| set_vid_clk_div(1); |
| set_hdmi_tx_pixel_div(1); |
| set_encp_div(1); |
| hdmitx_enable_encp_clk(); |
| set_hdmitx_fe_clk(); |
| } |
| |
| void enable_crt_video_encl2(u32 enable, u32 in_sel) |
| { |
| //encl_clk_sel:hi_viid_clk_div[15:12] |
| hd21_set_reg_bits(CLKCTRL_VIID_CLK2_DIV, in_sel, 12, 4); |
| if (in_sel <= 4) { //V1 |
| //#if (SDF_CORNER == 0 || SDF_CORNER == 2) //ss_corner |
| // hd21_set_reg_bits(CLKCTRL_VID_CLK_CTRL, 1, 16, 3); //sel div4 : 500M |
| //#endif |
| hd21_set_reg_bits(CLKCTRL_VID_CLK2_CTRL, 3, 0, 2); |
| } else { |
| hd21_set_reg_bits(CLKCTRL_VIID_CLK2_CTRL, 1, in_sel - 8, 1); |
| } |
| //gclk_encl_clk:hi_vid_clk_cntl2[3] |
| hd21_set_reg_bits(CLKCTRL_VID_CLK2_CTRL2, enable, 3, 1); /* cts_enc2_clk */ |
| } |
| |
| //Enable CLK_ENCL |
| void enable_crt_video_encl(u32 enable, u32 in_sel) |
| { |
| //encl_clk_sel:hi_viid_clk_div[15:12] |
| hd21_set_reg_bits(CLKCTRL_VIID_CLK0_DIV, in_sel, 12, 4); |
| if (in_sel <= 4) { //V1 |
| //#if (SDF_CORNER == 0 || SDF_CORNER == 2) //ss_corner |
| // hd21_set_reg_bits(CLKCTRL_VID_CLK_CTRL, 1, 16, 3); //sel div4 : 500M |
| //#endif |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL, 1, in_sel, 1); |
| } else { |
| hd21_set_reg_bits(CLKCTRL_VIID_CLK0_CTRL, 1, in_sel - 8, 1); |
| } |
| |
| //gclk_encl_clk:hi_vid_clk_cntl2[3] |
| hd21_set_reg_bits(CLKCTRL_VID_CLK0_CTRL2, enable, 3, 1); |
| } |
| |
| //Enable CLK_ENCP |
| void enable_crt_video_encp(u32 enable, u32 in_sel) |
| { |
| enable_crt_video_encl(enable, in_sel); |
| } |
| |
| //Enable HDMI_TX_PIXEL_CLK |
| //Note: when in_sel == 15, select tcon_clko |
| void enable_crt_video_hdmi(u32 enable, u32 in_sel, u8 enc_sel) |
| { |
| u32 data32; |
| u32 addr_enc02_hdmi_clk; |
| u32 addr_vid_clk02; |
| u32 addr_viid_clk02; |
| u32 addr_vid_clk022; |
| u32 val = 0; |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| struct hdmi_format_para *para = hdev->para; |
| |
| if (para->cs == HDMI_COLORSPACE_YUV420) |
| val = 1; |
| |
| addr_enc02_hdmi_clk = (enc_sel == 0) ? |
| CLKCTRL_ENC0_HDMI_CLK_CTRL : CLKCTRL_ENC2_HDMI_CLK_CTRL; |
| addr_vid_clk02 = (enc_sel == 0) ? CLKCTRL_VID_CLK0_CTRL : CLKCTRL_VID_CLK2_CTRL; |
| addr_viid_clk02 = (enc_sel == 0) ? CLKCTRL_VIID_CLK0_CTRL : CLKCTRL_VIID_CLK2_CTRL; |
| addr_vid_clk022 = (enc_sel == 0) ? CLKCTRL_VID_CLK0_CTRL2 : CLKCTRL_VID_CLK2_CTRL2; |
| |
| // hdmi_tx_pnx_clk |
| //clk_sel:hi_hdmi_clk_cntl[27:24]; |
| hd21_set_reg_bits(addr_enc02_hdmi_clk, val, 24, 4); |
| // hdmi_tx_fe_clk: for 420 mode, Freq(hdmi_tx_pixel_clk) = Freq(hdmi_tx_fe_clk)/2, |
| // otherwise Freq(hdmi_tx_pixel_clk) = Freq(hdmi_tx_fe_clk). |
| // clk_sel:hi_hdmi_clk_cntl[23:20]; |
| hd21_set_reg_bits(addr_enc02_hdmi_clk, (in_sel == 1) ? 0 : in_sel, 20, 4); |
| // hdmi_tx_pixel_clk |
| //clk_sel:hi_hdmi_clk_cntl[19:16]; |
| hd21_set_reg_bits(addr_enc02_hdmi_clk, val, 16, 4); |
| if (in_sel <= 4) { //V1 |
| if (in_sel == 1) |
| // If 420 mode, need to turn on div1_clk for hdmi_tx_fe_clk |
| // For hdmi_tx_fe_clk and hdmi_tx_pnx_clk |
| hd21_set_reg_bits(addr_vid_clk02, 3, 0, 2); |
| } else if (in_sel <= 9) { //V2 |
| // For hdmi_tx_pixel_clk |
| hd21_set_reg_bits(addr_viid_clk02, 1, in_sel - 8, 1); |
| } |
| |
| // Enable hdmi_tx_pnx_clk |
| hd21_set_reg_bits(addr_vid_clk022, enable, 10, 1); |
| // Enable hdmi_tx_fe_clk |
| hd21_set_reg_bits(addr_vid_clk022, enable, 9, 1); |
| // Enable hdmi_tx_pixel_clk |
| hd21_set_reg_bits(addr_vid_clk022, enable, 5, 1); |
| |
| // [22:21] clk_sl: 0=enc0_hdmi_tx_pnx_clk, 1=enc2_hdmi_tx_pnx_clk. |
| // [ 20] clk_en for hdmi_tx_pnx_clk |
| // [19:16] clk_div for hdmi_tx_pnx_clk |
| // [14:13] clk_sl: 0=enc0_hdmi_tx_fe_clk, 1=enc2_hdmi_tx_fe_clk. |
| // [ 12] clk_en for hdmi_tx_fe_clk |
| // [11: 8] clk_div for hdmi_tx_fe_clk |
| // [ 6: 5] clk_sl: 0=enc0_hdmi_tx_pixel_clk, 1=enc2_hdmi_tx_pixel_clk. |
| // [ 4] clk_en for hdmi_tx_pixel_clk |
| // [ 3: 0] clk_div for hdmi_tx_pixel_clk |
| data32 = 0; |
| data32 = (enc_sel << 21) | |
| (0 << 20) | |
| (0 << 16) | |
| (enc_sel << 13) | |
| (0 << 12) | |
| (0 << 8) | |
| (enc_sel << 5) | |
| (0 << 4) | |
| (0 << 0); |
| hd21_write_reg(CLKCTRL_ENC_HDMI_CLK_CTRL, data32); |
| hd21_set_reg_bits(CLKCTRL_ENC_HDMI_CLK_CTRL, 1, 20, 1); |
| hd21_set_reg_bits(CLKCTRL_ENC_HDMI_CLK_CTRL, 1, 12, 1); |
| hd21_set_reg_bits(CLKCTRL_ENC_HDMI_CLK_CTRL, 1, 4, 1); |
| } // enable_crt_video_hdmi |
| |
| //Enable CLK_ENCP |
| void enable_crt_video_encp2(u32 enable, u32 in_sel) |
| { |
| enable_crt_video_encl2(enable, in_sel); |
| } |
| |
| static void set_hdmitx_enc_idx(unsigned int val) |
| { |
| struct arm_smccc_res res; |
| |
| arm_smccc_smc(HDCPTX_IOOPR, CONF_ENC_IDX, 1, !!val, 0, 0, 0, 0, &res); |
| } |
| |
| static int hdmitx_set_dispmode(struct hdmitx_dev *hdev) |
| { |
| struct hdmi_format_para *para = hdev->para; |
| u32 data32; |
| enum hdmi_vic vic = para->timing.vic; |
| |
| if (hdev->enc_idx == 2) { |
| set_hdmitx_enc_idx(2); |
| hd21_set_reg_bits(VPU_DISP_VIU2_CTRL, 1, 29, 1); |
| hd21_set_reg_bits(VPU_VIU_VENC_MUX_CTRL, 2, 2, 2); |
| } |
| hdmitx21_venc_en(0, 0); |
| hd21_set_reg_bits(VPU_HDMI_SETTING, 0, (hdev->enc_idx == 0) ? 0 : 1, 1); |
| if (hdev->enc_idx == 0) |
| enable_crt_video_encp(1, 0); |
| else |
| enable_crt_video_encp2(1, 0); |
| enable_crt_video_hdmi(1, |
| (TX_INPUT_COLOR_FORMAT == HDMI_COLORSPACE_YUV420) ? 1 : 0, |
| hdev->enc_idx); |
| // configure GCP |
| if (para->cs == HDMI_COLORSPACE_YUV422 || para->cd == COLORDEPTH_24B) { |
| hdmitx21_set_reg_bits(GCP_CNTL_IVCTX, 0, 0, 1); |
| hdmi_gcppkt_manual_set(1); |
| } else { |
| hdmi_gcppkt_manual_set(0); |
| hdmitx21_set_reg_bits(GCP_CNTL_IVCTX, 1, 0, 1); |
| } |
| // -------------------------------------------------------- |
| // Enable viu vsync interrupt, enable hdmitx interrupt, enable htx_hdcp22 interrupt |
| // -------------------------------------------------------- |
| hd21_write_reg(VPU_VENC_CTRL, 1); |
| if (hdev->enc_idx == 2) { |
| // Enable VENC2 to HDMITX path |
| hd21_set_reg_bits(SYSCTRL_VPU_SECURE_REG0, 1, 16, 1); |
| } |
| |
| // -------------------------------------------------------- |
| // Set TV encoder for HDMI |
| // -------------------------------------------------------- |
| pr_info("configure venc\n"); |
| // enc_index output_type enable) |
| // only 480i / 576i use the ENCI |
| if (para->timing.pi_mode == 0 && |
| (para->timing.v_active == 480 || para->timing.v_active == 576)) { |
| hd21_write_reg(VPU_VENC_CTRL, 0); // sel enci timming |
| set_tv_enci_new(hdev, hdev->enc_idx, vic, 1); |
| } else { |
| hd21_write_reg(VPU_VENC_CTRL, 1); // sel encp timming |
| set_tv_encp_new(hdev, hdev->enc_idx, vic, 1); |
| } |
| |
| // -------------------------------------------------------- |
| // Configure video format timing for HDMI: |
| // Based on the corresponding settings in set_tv_enc.c, calculate |
| // the register values to meet the timing requirements defined in CEA-861-D |
| // -------------------------------------------------------- |
| pr_info("configure hdmitx video format timing\n"); |
| |
| // [ 1: 0] hdmi_vid_fmt. 0=444; 1=convert to 422; 2=convert to 420. |
| // [ 3: 2] chroma_dnsmp_h. 0=use pixel 0; 1=use pixel 1; 2=use average. |
| // [ 4] dith_en. 1=enable dithering before HDMI TX input. |
| // [ 5] hdmi_dith_md: random noise selector. |
| // [ 9: 6] hdmi_dith10_cntl. |
| // [ 10] hdmi_round_en. 1= enable 12-b rounded to 10-b. |
| // [ 11] tunnel_en |
| // [21:12] hdmi_dith_new |
| // [23:22] chroma_dnsmp_v. 0=use line 0; 1=use line 1; 2=use average. |
| // [27:24] pix_repeat |
| data32 = 0; |
| data32 = (((para->cs == HDMI_COLORSPACE_YUV420) ? 2 : |
| (para->cs == HDMI_COLORSPACE_YUV422) ? 1 : 0) << 0) | |
| (2 << 2) | |
| (0 << 4) | |
| (0 << 5) | |
| (0 << 6) | |
| (((para->cd == COLORDEPTH_24B) ? 1 : 0) << 10) | |
| (0 << 11) | |
| (0 << 12) | |
| (2 << 22) | |
| (0 << 24); |
| hd21_write_reg(VPU_HDMI_FMT_CTRL, data32); |
| |
| // [ 2] inv_hsync_b |
| // [ 3] inv_vsync_b |
| // [ 4] hdmi_dith_en_b. For 10-b to 8-b. |
| // [ 5] hdmi_dith_md_b. For 10-b to 8-b. |
| // [ 9: 6] hdmi_dith10_b. For 10-b to 8-b. |
| // [ 10] hdmi_round_en_b. For 10-b to 8-b. |
| // [21:12] hdmi_dith_new_b. For 10-b to 8-b. |
| data32 = 0; |
| data32 = (0 << 2) | |
| (0 << 3) | |
| (0 << 4) | |
| (0 << 5) | |
| (0 << 6) | |
| (((para->cd == COLORDEPTH_24B) ? 1 : 0) << 10) | |
| (0 << 12); |
| hd21_write_reg(VPU_HDMI_DITH_CNTL, data32); |
| |
| _hdmitx21_set_clk(); |
| |
| // Set this timer very small on purpose, to test the new function |
| hdmitx21_wr_reg(HDMITX_TOP_I2C_BUSY_CNT_MAX, 30); |
| |
| data32 = 0; |
| data32 |= (1 << 31); // [ 31] cntl_hdcp14_min_size_v_en |
| data32 |= (240 << 16); // [28:16] cntl_hdcp14_min_size_v |
| data32 |= (1 << 15); // [ 15] cntl_hdcp14_min_size_h_en |
| data32 |= (640 << 0); // [13: 0] cntl_hdcp14_min_size_h |
| hdmitx21_wr_reg(HDMITX_TOP_HDCP14_MIN_SIZE, data32); |
| |
| data32 = 0; |
| data32 |= (1 << 31); // [ 31] cntl_hdcp22_min_size_v_en |
| data32 |= (1080 << 16); // [28:16] cntl_hdcp22_min_size_v |
| data32 |= (1 << 15); // [ 15] cntl_hdcp22_min_size_h_en |
| data32 |= (1920 << 0); // [13: 0] cntl_hdcp22_min_size_h |
| hdmitx21_wr_reg(HDMITX_TOP_HDCP22_MIN_SIZE, data32); |
| |
| hdev->cur_VIC = hdev->para->timing.vic; |
| |
| pr_info("%s[%d]\n", __func__, __LINE__); |
| hdmitx21_set_clk(hdev); |
| |
| hdmitx_set_hw(hdev); |
| if (para->timing.pi_mode == 0 && |
| (para->timing.v_active == 480 || para->timing.v_active == 576)) |
| hdmitx21_venc_en(1, 0); |
| else |
| hdmitx21_venc_en(1, 1); |
| |
| // [ 0] src_sel_enci |
| // [ 1] src_sel_encp |
| // [ 2] inv_hsync. 1=Invert Hsync polarity. |
| // [ 3] inv_vsync. 1=Invert Vsync polarity. |
| // [ 4] inv_dvi_clk. 1=Invert clock to external DVI, |
| // (clock invertion exists at internal HDMI). |
| // YUV420. Output Y1Y0C to hdmitx. |
| // YUV444/422/RGB. Output CrYCb, CY0, or RGB to hdmitx. |
| // [ 7: 5] comp_map_post. Data from vfmt is CrYCb(444), CY0(422), CY0Y1(420) or RGB, |
| // map the data to desired format before go to hdmitx: |
| // 0=output {2, 1,0}; |
| // 1=output {1,0,2}; |
| // 2=output {1,2,0}; |
| // 3=output {0,2,1}; |
| // 4=output {0, 1,2}; |
| // 5=output {2.0,1}; |
| // 6,7=Rsrv. |
| // [11: 8] wr_rate_pre. 0=A write every clk1; 1=A write every 2 clk1; ...; |
| // 15=A write every 16 clk1. |
| // [15:12] rd_rate_pre. 0=A read every clk2; 1=A read every 2 clk2; ...; |
| // 15=A read every 16 clk2. |
| // RGB. Output RGB to vfmt. |
| // YUV. Output CrYCb to vfmt. |
| // [18:16] comp_map_pre. Data from VENC is YCbCr or RGB, map data to desired |
| // format before go to vfmt: |
| // 0=output YCbCr(RGB); |
| // 1=output CbCrY(GBR); |
| // 2=output CbYCr(GRB); |
| // 3=output CrYCb(BRG); |
| // 4=output CrCbY(BGR); |
| // 5=output YCrCb(RBG); |
| // 6,7=Rsrv. |
| // [23:20] wr_rate_post. 0=A write every clk1; 1=A write every 2 clk1; ...; |
| // 15=A write every 16 clk1. |
| // [27:24] rd_rate_post. 0=A read every clk2; 1=A read every 2 clk2; ...; |
| // 15=A read every 16 clk2. |
| data32 = 0; |
| data32 = (0 << 0) | |
| (0 << 1) | |
| (para->timing.h_pol << 2) | |
| (para->timing.v_pol << 3) | |
| (0 << 4) | |
| (((para->cs == HDMI_COLORSPACE_YUV420) ? 4 : 0) << 5) | |
| (0 << 8) | |
| (0 << 12) | |
| (((TX_INPUT_COLOR_FORMAT == HDMI_COLORSPACE_RGB) ? 0 : 3) << 16) | |
| (((para->cs == HDMI_COLORSPACE_YUV420) ? 1 : 0) << 20) | |
| (0 << 24); |
| hd21_write_reg(VPU_HDMI_SETTING, data32); |
| // [ 1] src_sel_encp: Enable ENCI or ENCP output to HDMI |
| hd21_set_reg_bits(VPU_HDMI_SETTING, 1, (hdev->enc_idx == 0) ? 0 : 1, 1); |
| |
| hdmitx_set_phy(hdev); |
| return 0; |
| } |
| |
| enum hdmi_tf_type hdmitx21_get_cur_hdr_st(void) |
| { |
| int ret; |
| u8 body[31] = {0}; |
| enum hdmi_tf_type mytype = HDMI_NONE; |
| enum hdmi_eotf type = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; |
| union hdmi_infoframe info; |
| struct hdmi_drm_infoframe *drm = &info.drm; |
| |
| ret = hdmitx_infoframe_rawget(HDMI_INFOFRAME_TYPE_DRM, body); |
| if (ret == -1 || ret == 0) { |
| type = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; |
| } else { |
| ret = hdmi_infoframe_unpack(&info, body, sizeof(body)); |
| if (ret == 0) |
| type = drm->eotf; |
| } |
| if (type == HDMI_EOTF_SMPTE_ST2084) |
| mytype = HDMI_HDR_SMPTE_2084; |
| if (type == HDMI_EOTF_BT_2100_HLG) |
| mytype = HDMI_HDR_HLG; |
| |
| return mytype; |
| } |
| |
| static bool hdmitx_vsif_en(u8 *body) |
| { |
| int ret; |
| |
| ret = hdmitx_infoframe_rawget(HDMI_INFOFRAME_TYPE_VENDOR, body); |
| if (ret != -1 && ret != 0) |
| return 0; |
| else |
| return 1; |
| } |
| |
| enum hdmi_tf_type hdmitx21_get_cur_dv_st(void) |
| { |
| int ret; |
| u8 body[31] = {0}; |
| enum hdmi_tf_type type = HDMI_NONE; |
| union hdmi_infoframe info; |
| struct hdmi_vendor_infoframe *vend = (struct hdmi_vendor_infoframe *)&info; |
| struct hdmi_avi_infoframe *avi = (struct hdmi_avi_infoframe *)&info; |
| unsigned int ieee_code = 0; |
| unsigned int size = 0; |
| enum hdmi_colorspace cs = 0; |
| |
| if (!hdmitx_vsif_en(body)) |
| return type; |
| |
| ret = hdmi_infoframe_unpack(&info, body, sizeof(body)); |
| if (ret) |
| return type; |
| ieee_code = vend->oui; |
| size = vend->length; |
| |
| ret = hdmitx_infoframe_rawget(HDMI_INFOFRAME_TYPE_AVI, body); |
| if (ret <= 0) |
| return type; |
| ret = hdmi_infoframe_unpack(&info, body, sizeof(body)); |
| if (ret) |
| return type; |
| cs = avi->colorspace; |
| |
| if ((ieee_code == HDMI_IEEE_OUI && size == 0x18) || |
| (ieee_code == DOVI_IEEEOUI && size == 0x1b)) { |
| if (cs == HDMI_COLORSPACE_YUV422) /* Y422 */ |
| type = HDMI_DV_VSIF_LL; |
| if (cs == HDMI_COLORSPACE_RGB) /* RGB */ |
| type = HDMI_DV_VSIF_STD; |
| } |
| return type; |
| } |
| |
| enum hdmi_tf_type hdmitx21_get_cur_hdr10p_st(void) |
| { |
| int ret; |
| unsigned int ieee_code = 0; |
| u8 body[31] = {0}; |
| enum hdmi_tf_type type = HDMI_NONE; |
| union hdmi_infoframe info; |
| struct hdmi_vendor_infoframe *vend = (struct hdmi_vendor_infoframe *)&info; |
| |
| if (!hdmitx_vsif_en(body)) |
| return type; |
| |
| ret = hdmi_infoframe_unpack(&info, body, sizeof(body)); |
| if (ret) |
| return type; |
| ieee_code = vend->oui; |
| if (ieee_code == HDR10PLUS_IEEEOUI) |
| type = HDMI_HDR10P_DV_VSIF; |
| |
| return type; |
| } |
| |
| bool hdmitx21_hdr_en(void) |
| { |
| return (hdmitx21_get_cur_hdr_st() & HDMI_HDR_TYPE) == HDMI_HDR_TYPE; |
| } |
| |
| bool hdmitx21_dv_en(void) |
| { |
| return (hdmitx21_get_cur_dv_st() & HDMI_DV_TYPE) == HDMI_DV_TYPE; |
| } |
| |
| bool hdmitx21_hdr10p_en(void) |
| { |
| return (hdmitx21_get_cur_hdr10p_st() & HDMI_HDR10P_TYPE) == HDMI_HDR10P_TYPE; |
| } |
| |
| static void set_aud_chnls(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param) |
| { |
| pr_info(HW "set channel status\n"); |
| /* set default 48k 2ch pcm */ |
| if (audio_param->type == CT_PCM && |
| (audio_param->channel_num == (2 - 1))) { |
| } else { |
| } |
| switch (audio_param->type) { |
| case CT_AC_3: |
| case CT_DOLBY_D: |
| case CT_DST: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| #define GET_OUTCHN_NO(a) (((a) >> 4) & 0xf) |
| #define GET_OUTCHN_MSK(a) ((a) & 0xf) |
| |
| static void set_aud_info_pkt(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param) |
| { |
| switch (audio_param->type) { |
| case CT_MAT: |
| case CT_DTS_HD_MA: |
| /* CC: 8ch */ |
| break; |
| case CT_PCM: |
| break; |
| case CT_DTS: |
| case CT_DTS_HD: |
| default: |
| /* CC: 2ch */ |
| break; |
| } |
| } |
| |
| static void set_aud_acr_pkt(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param) |
| { |
| u32 data32; |
| u32 aud_n_para; |
| u32 char_rate = 0; /* TODO */ |
| |
| if (hdev->para->cs == HDMI_COLORSPACE_YUV422) |
| aud_n_para = hdmi21_get_aud_n_paras(audio_param->sample_rate, |
| COLORDEPTH_24B, char_rate); |
| else |
| aud_n_para = hdmi21_get_aud_n_paras(audio_param->sample_rate, |
| hdev->para->cd, char_rate); |
| /* N must mutiples 4 for DD+ */ |
| switch (audio_param->type) { |
| case CT_DOLBY_D: |
| aud_n_para *= 4; |
| break; |
| default: |
| break; |
| } |
| pr_info(HW "aud_n_para = %d\n", aud_n_para); |
| |
| /* ACR packet configuration */ |
| data32 = 0; |
| data32 |= (1 << 7); /* [ 7] ncts_atomic_write */ |
| data32 |= (0 << 0); /* [3:0] AudN[19:16] */ |
| |
| data32 = 0; |
| data32 |= (0 << 7); /* [7:5] N_shift */ |
| data32 |= (0 << 4); /* [ 4] CTS_manual */ |
| data32 |= (0 << 0); /* [3:0] manual AudCTS[19:16] */ |
| |
| data32 = 0; |
| data32 |= (1 << 7); /* [ 7] ncts_atomic_write */ |
| data32 |= (((aud_n_para >> 16) & 0xf) << 0); /* [3:0] AudN[19:16] */ |
| } |
| |
| static void set_aud_fifo_rst(void) |
| { |
| /* reset audio fifo */ |
| } |
| |
| static void set_aud_samp_pkt(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param) |
| { |
| switch (audio_param->type) { |
| case CT_MAT: /* HBR */ |
| case CT_DTS_HD_MA: |
| break; |
| case CT_PCM: /* AudSamp */ |
| break; |
| case CT_AC_3: |
| case CT_DOLBY_D: |
| case CT_DTS: |
| case CT_DTS_HD: |
| default: |
| break; |
| } |
| } |
| |
| static int amute_flag = -1; |
| static void audio_mute_op(bool flag) |
| { |
| if (amute_flag != flag) |
| amute_flag = flag; |
| else |
| return; |
| } |
| |
| static int hdmitx_set_audmode(struct hdmitx_dev *hdev, |
| struct hdmitx_audpara *audio_param) |
| { |
| u32 data32; |
| |
| if (!hdev) |
| return 0; |
| if (!audio_param) |
| return 0; |
| pr_info(HW "set audio\n"); |
| |
| hdmitx21_set_audioclk(1); |
| audio_mute_op(hdev->tx_aud_cfg); |
| /* PCM & multi channel use I2S */ |
| if (audio_param->type == CT_PCM && |
| audio_param->channel_num > 2) |
| hdev->tx_aud_src = 1; |
| else |
| hdev->tx_aud_src = 0; |
| |
| /* if hdev->aud_output_ch is true, select I2S as 8ch in, 2ch out */ |
| if (hdev->aud_output_ch) |
| hdev->tx_aud_src = 1; |
| |
| pr_info(HW "hdmitx tx_aud_src = %d\n", hdev->tx_aud_src); |
| |
| data32 = 0; |
| data32 |= (0 << 7); /* [ 7] sw_audio_fifo_rst */ |
| |
| set_aud_info_pkt(hdev, audio_param); |
| set_aud_acr_pkt(hdev, audio_param); |
| set_aud_samp_pkt(hdev, audio_param); |
| |
| set_aud_chnls(hdev, audio_param); |
| |
| if (hdev->tx_aud_src == 1) { |
| /* Enable audi2s_fifo_overrun interrupt */ |
| /* Wait for 40 us for TX I2S decoder to settle */ |
| msleep(20); |
| } |
| set_aud_fifo_rst(); |
| usleep_range(9, 11); |
| /* double confirm that ACR packet is enabled |
| * simultaneously with audio sample packet |
| */ |
| data32 = hdmitx21_rd_reg(0); |
| |
| return 1; |
| } |
| |
| static void hdmitx_uninit(struct hdmitx_dev *phdev) |
| { |
| free_irq(phdev->irq_hpd, (void *)phdev); |
| pr_info(HW "power off hdmi, unmux hpd\n"); |
| |
| phy_hpll_off(); |
| hdmitx21_hpd_hw_op(HPD_UNMUX_HPD); |
| } |
| |
| static void hw_reset_dbg(void) |
| { |
| } |
| |
| static int hdmitx_cntl(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv) |
| { |
| if (cmd == HDMITX_AVMUTE_CNTL) { |
| return 0; |
| } else if (cmd == HDMITX_EARLY_SUSPEND_RESUME_CNTL) { |
| if (argv == HDMITX_EARLY_SUSPEND) { |
| u32 pll_cntl = ANACTRL_HDMIPLL_CTRL0; |
| |
| hd21_set_reg_bits(pll_cntl, 1, 28, 1); |
| usleep_range(49, 51); |
| hd21_set_reg_bits(pll_cntl, 0, 30, 1); |
| |
| hdmi_phy_suspend(); |
| } |
| if (argv == HDMITX_LATE_RESUME) { |
| /* No need below, will be set at set_disp_mode_auto() */ |
| /* hd21_set_reg_bits(HHI_HDMI_PLL_CNTL, 1, 30, 1); */ |
| hw_reset_dbg(); |
| pr_info(HW "swrstzreq\n"); |
| } |
| return 0; |
| } else if (cmd == HDMITX_HWCMD_MUX_HPD_IF_PIN_HIGH) { |
| /* turnon digital module if gpio is high */ |
| if (hdmitx21_hpd_hw_op(HPD_IS_HPD_MUXED) == 0) { |
| if (hdmitx21_hpd_hw_op(HPD_READ_HPD_GPIO)) { |
| msleep(500); |
| if (hdmitx21_hpd_hw_op(HPD_READ_HPD_GPIO)) { |
| pr_info(HPD "mux hpd\n"); |
| msleep(100); |
| hdmitx21_hpd_hw_op(HPD_MUX_HPD); |
| } |
| } |
| } |
| } else if (cmd == HDMITX_HWCMD_MUX_HPD) { |
| hdmitx21_hpd_hw_op(HPD_MUX_HPD); |
| /* For test only. */ |
| } else if (cmd == HDMITX_HWCMD_TURNOFF_HDMIHW) { |
| int unmux_hpd_flag = argv; |
| |
| if (unmux_hpd_flag) { |
| pr_info(HW "power off hdmi, unmux hpd\n"); |
| phy_hpll_off(); |
| hdmitx21_hpd_hw_op(HPD_UNMUX_HPD); |
| } else { |
| pr_info(HW "power off hdmi\n"); |
| phy_hpll_off(); |
| } |
| } |
| return 0; |
| } |
| |
| #define DUMP_CVREG_SECTION(_start, _end) \ |
| do { \ |
| typeof(_start) start = (_start); \ |
| typeof(_end) end = (_end); \ |
| if (start > end) { \ |
| pr_info("Error start = 0x%x > end = 0x%x\n", \ |
| ((start & 0xffff) >> 2), ((end & 0xffff) >> 2)); \ |
| break; \ |
| } \ |
| pr_info("Start = 0x%x[0x%x] End = 0x%x[0x%x]\n", \ |
| start, ((start & 0xffff) >> 2), end, ((end & 0xffff) >> 2)); \ |
| for (addr = start; addr < end + 1; addr += 4) { \ |
| val = hd21_read_reg(addr); \ |
| if (val) \ |
| pr_info("0x%08x[0x%04x]: 0x%08x\n", addr, \ |
| ((addr & 0xffff) >> 2), val); \ |
| } \ |
| } while (0) |
| |
| #define DUMP_HDMITXREG_SECTION(_start, _end) \ |
| do { \ |
| typeof(_start) start = (_start); \ |
| typeof(_end) end = (_end); \ |
| if (start > end) \ |
| break; \ |
| \ |
| for (addr = start; addr < end + 1; addr++) { \ |
| val = hdmitx21_rd_reg(addr); \ |
| if (val) \ |
| pr_info("[0x%08x]: 0x%08x\n", addr, val); \ |
| } \ |
| } while (0) |
| |
| static void hdmitx_dump_intr(void) |
| { |
| } |
| |
| #undef pr_fmt |
| #define pr_fmt(fmt) "hdmitx: " fmt |
| |
| static void hdmitx_debug(struct hdmitx_dev *hdev, const char *buf) |
| { |
| char tmpbuf[128]; |
| int i = 0; |
| int ret; |
| unsigned long adr = 0; |
| unsigned long value = 0; |
| |
| if (!buf) |
| return; |
| |
| while ((buf[i]) && (buf[i] != ',') && (buf[i] != ' ')) { |
| tmpbuf[i] = buf[i]; |
| i++; |
| } |
| tmpbuf[i] = 0; |
| |
| if (strncmp(tmpbuf, "testhpll", 8) == 0) { |
| ret = kstrtoul(tmpbuf + 8, 10, &value); |
| hdev->cur_VIC = value; |
| hdmitx21_set_clk(hdev); |
| return; |
| } else if (strncmp(tmpbuf, "testedid", 8) == 0) { |
| hdev->hwop.cntlddc(hdev, DDC_RESET_EDID, 0); |
| hdev->hwop.cntlddc(hdev, DDC_EDID_READ_DATA, 0); |
| return; |
| } else if (strncmp(tmpbuf, "i2creactive", 11) == 0) { |
| hdev->hwop.cntlmisc(hdev, MISC_I2C_REACTIVE, 0); |
| return; |
| } else if (strncmp(tmpbuf, "bist", 4) == 0) { |
| if (strncmp(tmpbuf + 4, "off", 3) == 0) { |
| hdev->bist_lock = 0; |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 1, 3, 1); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 0); |
| return; |
| } |
| hdev->bist_lock = 1; |
| if (!hdev->para) |
| return; |
| hdmi_avi_infoframe_config(CONF_AVI_CS, hdev->para->cs); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| if (strncmp(tmpbuf + 4, "line", 4) == 0) { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 2); |
| return; |
| } |
| if (strncmp(tmpbuf + 4, "dot", 3) == 0) { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 3); |
| return; |
| } |
| if (strncmp(tmpbuf + 4, "start", 5) == 0) { |
| ret = kstrtoul(tmpbuf + 9, 10, &value); |
| hd21_write_reg(VENC_VIDEO_TST_CLRBAR_STRT, value); |
| return; |
| } |
| if (strncmp(tmpbuf + 4, "shift", 5) == 0) { |
| ret = kstrtoul(tmpbuf + 9, 10, &value); |
| hd21_write_reg(VENC_VIDEO_TST_VDCNT_STSET, value); |
| return; |
| } |
| if (strncmp(tmpbuf + 4, "auto", 4) == 0) { |
| const struct hdmi_timing *t; |
| |
| if (!hdev->para) |
| return; |
| t = &hdev->para->timing; |
| value = t->h_active; |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 1); |
| hd21_write_reg(VENC_VIDEO_TST_CLRBAR_WIDTH, value / 8); |
| return; |
| } |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 1); |
| value = 1920; |
| ret = kstrtoul(tmpbuf + 4, 10, &value); |
| hd21_write_reg(VENC_VIDEO_TST_CLRBAR_WIDTH, value / 8); |
| return; |
| } else if (strncmp(tmpbuf, "testaudio", 9) == 0) { |
| hdmitx_set_audmode(hdev, NULL); |
| } else if (strncmp(tmpbuf, "dumpintr", 8) == 0) { |
| hdmitx_dump_intr(); |
| } else if (strncmp(tmpbuf, "chkfmt", 6) == 0) { |
| check21_detail_fmt(); |
| return; |
| } else if (strncmp(tmpbuf, "ss", 2) == 0) { |
| pr_info("hdev->output_blank_flag: 0x%x\n", |
| hdev->output_blank_flag); |
| pr_info("hdev->hpd_state: 0x%x\n", hdev->hpd_state); |
| pr_info("hdev->cur_VIC: 0x%x\n", hdev->cur_VIC); |
| } else if (strncmp(tmpbuf, "hpd_lock", 8) == 0) { |
| if (tmpbuf[8] == '1') { |
| hdev->hpd_lock = 1; |
| pr_info(HPD "hdmitx: lock hpd\n"); |
| } else { |
| hdev->hpd_lock = 0; |
| pr_info(HPD "hdmitx: unlock hpd\n"); |
| } |
| return; |
| } else if (strncmp(tmpbuf, "vic", 3) == 0) { |
| pr_info(HW "hdmi vic count = %d\n", hdev->vic_count); |
| if ((tmpbuf[3] >= '0') && (tmpbuf[3] <= '9')) { |
| hdev->vic_count = tmpbuf[3] - '0'; |
| pr_info(HW "set hdmi vic count = %d\n", |
| hdev->vic_count); |
| } |
| } else if (strncmp(tmpbuf, "dumpcecreg", 10) == 0) { |
| u8 cec_val = 0; |
| u32 cec_adr = 0; |
| /* HDMI CEC Regs address range:0xc000~0xc01c;0xc080~0xc094 */ |
| for (cec_adr = 0xc000; cec_adr < 0xc01d; cec_adr++) { |
| cec_val = hdmitx21_rd_reg(cec_adr); |
| pr_info(CEC "HDMI CEC Regs[0x%x]: 0x%x\n", |
| cec_adr, cec_val); |
| } |
| for (cec_adr = 0xc080; cec_adr < 0xc095; cec_adr++) { |
| cec_val = hdmitx21_rd_reg(cec_adr); |
| pr_info(CEC "HDMI CEC Regs[0x%x]: 0x%x\n", |
| cec_adr, cec_val); |
| } |
| return; |
| } else if (tmpbuf[0] == 'w') { |
| unsigned long read_back = 0; |
| |
| ret = kstrtoul(tmpbuf + 2, 16, &adr); |
| ret = kstrtoul(buf + i + 1, 16, &value); |
| if (buf[1] == 'h') { |
| hdmitx21_wr_reg((unsigned int)adr, (unsigned int)value); |
| read_back = hdmitx21_rd_reg(adr); |
| } |
| pr_info(HW "write %lx to %s reg[%lx]\n", value, "HDMI", adr); |
| /* read back in order to check writing is OK or NG. */ |
| pr_info(HW "Read Back %s reg[%lx]=%lx\n", "HDMI", |
| adr, read_back); |
| } else if (tmpbuf[0] == 'r') { |
| ret = kstrtoul(tmpbuf + 2, 16, &adr); |
| if (buf[1] == 'h') |
| value = hdmitx21_rd_reg(adr); |
| pr_info(HW "%s reg[%lx]=%lx\n", "HDMI", adr, value); |
| } else if (strncmp(tmpbuf, "prbs", 4) == 0) { |
| u32 phy_cntl1 = ANACTRL_HDMIPHY_CTRL1; |
| u32 phy_cntl4 = ANACTRL_HDMIPHY_CTRL4; |
| u32 phy_status = ANACTRL_HDMIPHY_STS; |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| phy_cntl1 = ANACTRL_HDMIPHY_CTRL1; |
| phy_cntl4 = ANACTRL_HDMIPHY_CTRL4; |
| phy_status = ANACTRL_HDMIPHY_STS; |
| break; |
| default: |
| break; |
| } |
| /* test prbs */ |
| for (i = 0; i < 4; i++) { |
| hd21_write_reg(phy_cntl1, 0x0390000f); |
| hd21_write_reg(phy_cntl1, 0x0390000e); |
| hd21_write_reg(phy_cntl1, 0x03904002); |
| hd21_write_reg(phy_cntl4, 0x0001efff |
| | (i << 20)); |
| hd21_write_reg(phy_cntl1, 0xef904002); |
| mdelay(10); |
| if (i > 0) |
| pr_info("prbs D[%d]:%x\n", i - 1, |
| hd21_read_reg(phy_status)); |
| else |
| pr_info("prbs clk :%x\n", |
| hd21_read_reg(phy_status)); |
| } |
| } |
| } |
| |
| static char *hdmitx_bist_str[] = { |
| "0-None", /* 0 */ |
| "1-Color Bar", /* 1 */ |
| "2-Thin Line", /* 2 */ |
| "3-Dot Grid", /* 3 */ |
| "4-Gray", /* 4 */ |
| "5-Red", /* 5 */ |
| "6-Green", /* 6 */ |
| "7-Blue", /* 7 */ |
| "8-Black", /* 8 */ |
| }; |
| |
| static void hdmitx_debug_bist(struct hdmitx_dev *hdev, u32 num) |
| { |
| u32 h_active, video_start; |
| struct vinfo_s *vinfo; |
| |
| if (!hdev->para) |
| return; |
| vinfo = &hdev->para->hdmitx_vinfo; |
| switch (num) { |
| case 1: |
| case 2: |
| case 3: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_CLRBAR_STRT, 0x112); |
| hd21_write_reg(ENCI_TST_CLRBAR_WIDTH, 0xb4); |
| hd21_write_reg(ENCI_TST_MDSEL, num); |
| hd21_write_reg(ENCI_TST_Y, 0x200); |
| hd21_write_reg(ENCI_TST_CB, 0x200); |
| hd21_write_reg(ENCI_TST_CR, 0x200); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| video_start = hd21_read_reg(ENCP_VIDEO_HAVON_BEGIN); |
| h_active = vinfo->width; |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, num); |
| hd21_write_reg(VENC_VIDEO_TST_CLRBAR_STRT, video_start); |
| hd21_write_reg(VENC_VIDEO_TST_CLRBAR_WIDTH, |
| h_active / 8); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 4: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_MDSEL, 0); |
| hd21_write_reg(ENCI_TST_Y, 0x3ff); |
| hd21_write_reg(ENCI_TST_CB, 0x200); |
| hd21_write_reg(ENCI_TST_CR, 0x200); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x3ff); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 5: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_MDSEL, 0); |
| hd21_write_reg(ENCI_TST_Y, 0x200); |
| hd21_write_reg(ENCI_TST_CB, 0x0); |
| hd21_write_reg(ENCI_TST_CR, 0x3ff); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x3ff); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 6: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_MDSEL, 0); |
| hd21_write_reg(ENCI_TST_Y, 0x200); |
| hd21_write_reg(ENCI_TST_CB, 0x0); |
| hd21_write_reg(ENCI_TST_CR, 0x0); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 7: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_MDSEL, 0); |
| hd21_write_reg(ENCI_TST_Y, 0x200); |
| hd21_write_reg(ENCI_TST_CB, 0x3ff); |
| hd21_write_reg(ENCI_TST_CR, 0x0); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x3ff); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 8: |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_MDSEL, 0); |
| hd21_write_reg(ENCI_TST_Y, 0x0); |
| hd21_write_reg(ENCI_TST_CB, 0x200); |
| hd21_write_reg(ENCI_TST_CR, 0x200); |
| hd21_write_reg(ENCI_TST_EN, 1); |
| } else { |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| } |
| pr_info("show bist pattern %d: %s\n", |
| num, hdmitx_bist_str[num]); |
| break; |
| case 0: |
| default: |
| /*hdev->bist_lock = 0;*/ |
| if (vinfo->viu_mux == VIU_MUX_ENCI) { |
| hd21_write_reg(ENCI_TST_EN, 0); |
| } else { |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 1, 3, 1); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 0); |
| } |
| pr_info("disable bist pattern"); |
| break; |
| } |
| } |
| |
| static void hdmitx_getediddata(u8 *des, u8 *src) |
| { |
| int i = 0; |
| u32 blk = src[126] + 1; |
| |
| if (blk > 4) |
| blk = 4; |
| |
| for (i = 0; i < 128 * blk; i++) |
| des[i] = src[i]; |
| } |
| |
| void hdmitx_set_scdc_div40(u32 div40) |
| { |
| u32 addr = 0x20; |
| u32 data; |
| |
| if (div40) |
| data = 0x3; |
| else |
| data = 0; |
| hdmitx21_set_reg_bits(HDCP2X_CTL_0_IVCTX, 0, 0, 1); |
| hdmitx21_wr_reg(LM_DDC_IVCTX, 0x80); |
| hdmitx21_wr_reg(DDC_ADDR_IVCTX, 0xa8); //SCDC slave addr |
| hdmitx21_wr_reg(DDC_OFFSET_IVCTX, addr & 0xff); //SCDC slave offset |
| hdmitx21_wr_reg(DDC_DATA_AON_IVCTX, data & 0xff); //SCDC slave offset data to ddc fifo |
| hdmitx21_wr_reg(DDC_DIN_CNT1_IVCTX, 0x01); //data length lo |
| hdmitx21_wr_reg(DDC_DIN_CNT2_IVCTX, 0x00); //data length hi |
| hdmitx21_wr_reg(DDC_CMD_IVCTX, 0x06); //DDC Write CMD |
| hdmitx21_poll_reg(DDC_STATUS_IVCTX, 1 << 4, ~(1 << 4), HZ / 100); //i2c process |
| hdmitx21_poll_reg(DDC_STATUS_IVCTX, 0 << 4, ~(1 << 4), HZ / 100); //i2c done |
| } |
| |
| static void set_top_div40(u32 div40) |
| { |
| u32 data32; |
| |
| // Enable normal output to PHY |
| if (div40) { |
| data32 = 0; |
| data32 |= (0 << 16); // [25:16] tmds_clk_pttn[19:10] |
| data32 |= (0 << 0); // [ 9: 0] tmds_clk_pttn[ 9: 0] |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_01, data32); |
| |
| data32 = 0; |
| data32 |= (0x3ff << 16); // [25:16] tmds_clk_pttn[39:30] |
| data32 |= (0x3ff << 0); // [ 9: 0] tmds_clk_pttn[29:20] |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_23, data32); |
| } else { |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f); |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f); |
| } |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); |
| // [14:12] tmds_sel: 0=output 0; 1=output normal data; |
| // 2=output PRBS; 4=output shift pattn |
| // [11: 8] shift_pttn |
| // [ 4: 0] prbs_pttn |
| data32 = 0; |
| data32 |= (1 << 12); |
| data32 |= (0 << 8); |
| data32 |= (0 << 0); |
| hdmitx21_wr_reg(HDMITX_TOP_BIST_CNTL, data32); |
| |
| if (div40) |
| hdmitx21_wr_reg(HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); |
| } |
| |
| static void hdmitx_set_div40(u32 div40) |
| { |
| hdmitx_set_scdc_div40(div40); |
| set_top_div40(div40); |
| hdmitx21_wr_reg(SCRCTL_IVCTX, (1 << 5) | !!div40); |
| } |
| |
| static int hdmitx_cntl_ddc(struct hdmitx_dev *hdev, u32 cmd, |
| unsigned long argv) |
| { |
| if ((cmd & CMD_DDC_OFFSET) != CMD_DDC_OFFSET) { |
| pr_err(HW "ddc: invalid cmd 0x%x\n", cmd); |
| return -1; |
| } |
| |
| switch (cmd) { |
| case DDC_RESET_EDID: |
| memset(hdev->tmp_edid_buf, 0, ARRAY_SIZE(hdev->tmp_edid_buf)); |
| break; |
| case DDC_EDID_READ_DATA: |
| hdmitx21_read_edid(hdev->tmp_edid_buf); |
| break; |
| case DDC_EDID_GET_DATA: |
| if (argv == 0) |
| hdmitx_getediddata(hdev->EDID_buf, hdev->tmp_edid_buf); |
| else |
| hdmitx_getediddata(hdev->EDID_buf1, hdev->tmp_edid_buf); |
| break; |
| case DDC_GLITCH_FILTER_RESET: |
| hdmitx21_set_reg_bits(HDMITX_TOP_SW_RESET, 1, 6, 1); |
| /*keep resetting DDC for some time*/ |
| usleep_range(1000, 2000); |
| hdmitx21_set_reg_bits(HDMITX_TOP_SW_RESET, 0, 6, 1); |
| /*wait recover for resetting DDC*/ |
| usleep_range(1000, 2000); |
| break; |
| case DDC_PIN_MUX_OP: |
| if (argv == PIN_MUX) |
| hdmitx21_ddc_hw_op(DDC_MUX_DDC); |
| if (argv == PIN_UNMUX) |
| hdmitx21_ddc_hw_op(DDC_UNMUX_DDC); |
| break; |
| case DDC_EDID_CLEAR_RAM: |
| break; |
| case DDC_SCDC_DIV40_SCRAMB: |
| hdmitx_set_div40(argv == 1); |
| break; |
| default: |
| break; |
| } |
| return 1; |
| } |
| |
| static int hdmitx_hdmi_dvi_config(struct hdmitx_dev *hdev, |
| u32 dvi_mode) |
| { |
| if (dvi_mode == 1) |
| hdmitx_csc_config(TX_INPUT_COLOR_FORMAT, HDMI_COLORSPACE_RGB, hdev->para->cd); |
| |
| return 0; |
| } |
| |
| static int hdmitx_get_hdmi_dvi_config(struct hdmitx_dev *hdev) |
| { |
| /* TODO */ |
| return HDMI_MODE; |
| } |
| |
| static int hdmitx_cntl_config(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv) |
| { |
| int ret = 0; |
| |
| if ((cmd & CMD_CONF_OFFSET) != CMD_CONF_OFFSET) { |
| pr_err(HW "config: invalid cmd 0x%x\n", cmd); |
| return -1; |
| } |
| |
| switch (cmd) { |
| case CONF_HDMI_DVI_MODE: |
| hdmitx_hdmi_dvi_config(hdev, (argv == DVI_MODE) ? 1 : 0); |
| break; |
| case CONF_GET_HDMI_DVI_MODE: |
| ret = hdmitx_get_hdmi_dvi_config(hdev); |
| break; |
| case CONF_AUDIO_MUTE_OP: |
| audio_mute_op(argv == AUDIO_MUTE ? 0 : 1); |
| break; |
| case CONF_VIDEO_MUTE_OP: |
| if (argv == VIDEO_MUTE) { |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 0, 3, 1); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 1); |
| hd21_write_reg(VENC_VIDEO_TST_MDSEL, 0); |
| /*_Y/CB/CR, 10bits Unsigned/Signed/Signed */ |
| hd21_write_reg(VENC_VIDEO_TST_Y, 0x0); |
| hd21_write_reg(VENC_VIDEO_TST_CB, 0x200); |
| hd21_write_reg(VENC_VIDEO_TST_CR, 0x200); |
| } |
| if (argv == VIDEO_UNMUTE) { |
| hd21_set_reg_bits(ENCP_VIDEO_MODE_ADV, 1, 3, 1); |
| hd21_write_reg(VENC_VIDEO_TST_EN, 0); |
| } |
| break; |
| case CONF_CLR_AVI_PACKET: |
| break; |
| case CONF_CLR_VSDB_PACKET: |
| break; |
| case CONF_VIDEO_MAPPING: |
| config_video_mapping(hdev->para->cs, hdev->para->cd); |
| break; |
| case CONF_CLR_AUDINFO_PACKET: |
| break; |
| case CONF_AVI_BT2020: |
| break; |
| case CONF_CLR_DV_VS10_SIG: |
| break; |
| case CONF_CT_MODE: |
| break; |
| case CONF_EMP_NUMBER: |
| break; |
| case CONF_EMP_PHY_ADDR: |
| break; |
| default: |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static int hdmitx_tmds_rxsense(void) |
| { |
| int ret = 0; |
| struct hdmitx_dev *hdev = get_hdmitx21_device(); |
| |
| switch (hdev->data->chip_type) { |
| case MESON_CPU_ID_T7: |
| hd21_set_reg_bits(ANACTRL_HDMIPHY_CTRL0, 1, 16, 1); |
| hd21_set_reg_bits(ANACTRL_HDMIPHY_CTRL3, 1, 23, 1); |
| hd21_set_reg_bits(ANACTRL_HDMIPHY_CTRL3, 0, 24, 1); |
| hd21_set_reg_bits(ANACTRL_HDMIPHY_CTRL3, 3, 20, 3); |
| ret = hd21_read_reg(ANACTRL_HDMIPHY_CTRL2) & 0x1; |
| return ret; |
| default: |
| break; |
| } |
| if (!(hdev->hwop.cntlmisc(hdev, MISC_HPD_GPI_ST, 0))) |
| return 0; |
| return ret; |
| } |
| |
| /*Check from SCDC Status_Flags_0/1 */ |
| /* 0 means TMDS ok */ |
| static int hdmitx_tmds_cedst(struct hdmitx_dev *hdev) |
| { |
| return scdc21_status_flags(hdev); |
| } |
| |
| static int hdmitx_cntl_misc(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv) |
| { |
| if ((cmd & CMD_MISC_OFFSET) != CMD_MISC_OFFSET) { |
| pr_err(HW "misc: w: invalid cmd 0x%x\n", cmd); |
| return -1; |
| } |
| |
| switch (cmd) { |
| case MISC_HPD_MUX_OP: |
| if (argv == PIN_MUX) |
| argv = HPD_MUX_HPD; |
| else |
| argv = HPD_UNMUX_HPD; |
| return hdmitx21_hpd_hw_op(argv); |
| case MISC_HPD_GPI_ST: |
| return hdmitx21_hpd_hw_op(HPD_READ_HPD_GPIO); |
| case MISC_TRIGGER_HPD: |
| hdmitx21_wr_reg(HDMITX_TOP_INTR_STAT, 1 << 1); |
| return 0; |
| break; |
| case MISC_TMDS_PHY_OP: |
| if (argv == TMDS_PHY_ENABLE) |
| hdmi_phy_wakeup(hdev); /* TODO */ |
| if (argv == TMDS_PHY_DISABLE) { |
| hdev->hdcp_mode = 0x00; |
| if (get_hdcp2_lstore() || get_hdcp1_lstore()) |
| hdcp_mode_set(0); |
| hdmi_phy_suspend(); |
| } |
| break; |
| case MISC_TMDS_RXSENSE: |
| return hdmitx_tmds_rxsense(); |
| case MISC_TMDS_CEDST: |
| return hdmitx_tmds_cedst(hdev); |
| case MISC_VIID_IS_USING: |
| break; |
| case MISC_AVMUTE_OP: |
| config_avmute(argv); |
| break; |
| case MISC_READ_AVMUTE_OP: |
| return read_avmute(); |
| case MISC_I2C_RESET: |
| hdmitx21_set_reg_bits(HDMITX_TOP_SW_RESET, 1, 9, 1); |
| usleep_range(1000, 2000); |
| hdmitx21_set_reg_bits(HDMITX_TOP_SW_RESET, 0, 9, 1); |
| usleep_range(1000, 2000); |
| break; |
| case MISC_I2C_REACTIVE: |
| break; |
| default: |
| break; |
| } |
| return 1; |
| } |
| |
| static enum hdmi_vic get_vic_from_pkt(void) |
| { |
| enum hdmi_vic vic = HDMI_0_UNKNOWN; |
| |
| return vic; |
| } |
| |
| static int hdmitx_get_state(struct hdmitx_dev *hdev, u32 cmd, |
| u32 argv) |
| { |
| if ((cmd & CMD_STAT_OFFSET) != CMD_STAT_OFFSET) { |
| pr_err(HW "state: invalid cmd 0x%x\n", cmd); |
| return -1; |
| } |
| |
| switch (cmd) { |
| case STAT_VIDEO_VIC: |
| return (int)get_vic_from_pkt(); |
| case STAT_VIDEO_CLK: |
| break; |
| case STAT_HDR_TYPE: |
| return 0; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| static void hdmi_phy_suspend(void) |
| { |
| u32 phy_cntl0 = ANACTRL_HDMIPHY_CTRL0; |
| u32 phy_cntl3 = ANACTRL_HDMIPHY_CTRL3; |
| u32 phy_cntl5 = ANACTRL_HDMIPHY_CTRL5; |
| |
| hd21_write_reg(phy_cntl0, 0x0); |
| /* keep PHY_CNTL3 bit[1:0] as 0b11, |
| * otherwise may cause HDCP22 boot failed |
| */ |
| hd21_write_reg(phy_cntl3, 0x3); |
| hd21_write_reg(phy_cntl5, 0x800); |
| } |
| |
| static void hdmi_phy_wakeup(struct hdmitx_dev *hdev) |
| { |
| hdmitx_set_phy(hdev); |
| } |
| |
| #define COLORDEPTH_24B 4 |
| #define HDMI_COLOR_DEPTH_30B 5 |
| #define HDMI_COLOR_DEPTH_36B 6 |
| #define HDMI_COLOR_DEPTH_48B 7 |
| |
| #define HDMI_COLOR_FORMAT_RGB 0 |
| #define HDMI_COLORSPACE_YUV422 1 |
| #define HDMI_COLOR_FORMAT_444 2 |
| #define HDMI_COLORSPACE_YUV420 3 |
| |
| #define HDMI_COLOR_RANGE_LIM 0 |
| #define HDMI_COLOR_RANGE_FUL 1 |
| |
| #define HDMI_AUDIO_PACKET_SMP 0x02 |
| #define HDMI_AUDIO_PACKET_1BT 0x07 |
| #define HDMI_AUDIO_PACKET_DST 0x08 |
| #define HDMI_AUDIO_PACKET_HBR 0x09 |
| #define HDMI_AUDIO_PACKET_MUL 0x0e |
| |
| /* |
| * color_depth: Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit. |
| * input_color_format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420. |
| * input_color_range: 0=limited; 1=full. |
| * output_color_format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420 |
| */ |
| static void config_hdmi21_tx(struct hdmitx_dev *hdev) |
| { |
| struct hdmi_format_para *para = hdev->para; |
| u8 color_depth = COLORDEPTH_24B; // Pixel bit width: 4=24-bit; 5=30-bit; 6=36-bit; 7=48-bit. |
| // Pixel format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420. |
| u8 input_color_format = HDMI_COLORSPACE_YUV444; |
| u8 input_color_range = COLORRANGE_LIM; // Pixel range: 0=limited; 1=full. |
| // Pixel format: 0=RGB444; 1=YCbCr422; 2=YCbCr444; 3=YCbCr420. |
| u8 output_color_format = HDMI_COLORSPACE_YUV444; |
| u8 output_color_range = COLORRANGE_LIM; // Pixel range: 0=limited; 1=full. |
| u8 vic = 16; // Video format identification code |
| u32 active_pixels = 1920; // Number of active pixels per line |
| u32 active_lines = 1080; // Number of active lines per field |
| u32 aud_n = 6144; // ACR N |
| // 0=I2S 2-channel; 1=I2S 4 x 2-channel; 2=channel 0/1, 4/5 valid. |
| // 2=audio sample packet; 7=one bit audio; 8=DST audio packet; 9=HBR audio packet. |
| u8 audio_packet_type = 2; |
| u32 data32; |
| u8 data8; |
| u8 csc_en; |
| u8 dp_color_depth = 0; |
| |
| vic = para->timing.vic; |
| if (vic) |
| audio_packet_type = 2; |
| else |
| audio_packet_type = 9; |
| if (para->tmds_clk > 340000) { |
| para->scrambler_en = 1; |
| para->tmds_clk_div40 = 1; |
| } else { |
| para->scrambler_en = 0; |
| para->tmds_clk_div40 = 0; |
| } |
| color_depth = para->cd; |
| output_color_format = para->cs; |
| active_pixels = para->timing.h_active; |
| active_lines = para->timing.v_active; |
| dp_color_depth = (output_color_format == HDMI_COLORSPACE_YUV422) ? |
| COLORDEPTH_24B : color_depth; |
| |
| pr_info("configure hdmitx21\n"); |
| hdmitx21_wr_reg(HDMITX_TOP_SW_RESET, 0); |
| hdmitx_set_div40(para->tmds_clk_div40); |
| |
| //-------------------------------------------------------------------------- |
| // Glitch-filter HPD and RxSense |
| //-------------------------------------------------------------------------- |
| // [31:28] rxsense_glitch_width: Filter out glitch width <= hpd_glitch_width |
| // [27:16] rxsense_valid_width: Filter out signal stable width <= hpd_valid_width*1024 |
| // [15:12] hpd_glitch_width: Filter out glitch width <= hpd_glitch_width |
| // [11: 0] hpd_valid_width: Filter out signal stable width <= hpd_valid_width*1024 |
| data32 = 0; |
| data32 |= (8 << 28); |
| data32 |= (0 << 16); |
| data32 |= (7 << 12); |
| data32 |= (0 << 0); |
| hdmitx21_wr_reg(HDMITX_TOP_HPD_FILTER, data32); |
| |
| //------------- |
| //config video |
| //------------- |
| data8 = 0; |
| data8 |= (dp_color_depth & 0x03); // [1:0]color depth. 00:8bpp;01:10bpp;10:12bpp;11:16bpp |
| data8 |= (((dp_color_depth != 4) ? 1 : 0) << 7); // [7] deep color enable bit |
| hdmitx21_wr_reg(P2T_CTRL_IVCTX, data8); |
| data32 = 0; |
| data32 |= (1 << 5); // [ 5] reg_hdmi2_on |
| data32 |= (para->scrambler_en & 0x01 << 0); // [ 0] scrambler_en. |
| hdmitx21_wr_reg(SCRCTL_IVCTX, data32 & 0xff); |
| |
| hdmitx21_wr_reg(CLK_DIV_CNTRL_IVCTX, 0x1); |
| //hdmitx21_wr_reg(H21TXSB_PKT_PRD_IVCTX, 0x1); |
| //hdmitx21_wr_reg(HOST_CTRL2_IVCTX, 0x80); //INT active high |
| hdmitx21_wr_reg(CLKPWD_IVCTX, 0xf4); |
| hdmitx21_wr_reg(SOC_FUNC_SEL_IVCTX, 0x01); |
| //hdmitx21_wr_reg(SYS_MISC_IVCTX, 0x00); config same with default |
| //hdmitx21_wr_reg(DIPT_CNTL_IVCTX, 0x06); config same with default |
| hdmitx21_wr_reg(TEST_TXCTRL_IVCTX, 0x02); //[1] enable hdmi |
| //hdmitx21_wr_reg(TX_ZONE_CTL4_IVCTX, 0x04); config same with default |
| hdmitx21_wr_reg(CLKRATIO_IVCTX, 0x8a); |
| |
| //--------------- |
| //config vp core |
| //--------------- |
| csc_en = (input_color_format != output_color_format || |
| input_color_range != output_color_range) ? 1 : 0; |
| //some common register are configuration here TODO why config this value |
| hdmitx21_wr_reg(VP_CMS_CSC0_MULTI_CSC_CONFIG_IVCTX, 0x00); |
| hdmitx21_wr_reg((VP_CMS_CSC0_MULTI_CSC_CONFIG_IVCTX + 1), 0x08); |
| hdmitx21_wr_reg(VP_CMS_CSC1_MULTI_CSC_CONFIG_IVCTX, 0x00); |
| hdmitx21_wr_reg((VP_CMS_CSC1_MULTI_CSC_CONFIG_IVCTX + 1), 0x08); |
| if (output_color_format == HDMI_COLORSPACE_RGB) { |
| hdmitx21_wr_reg(VP_CMS_CSC0_MULTI_CSC_CONFIG_IVCTX, 0x65); |
| hdmitx21_wr_reg((VP_CMS_CSC0_MULTI_CSC_CONFIG_IVCTX + 1), 0x08); |
| } |
| |
| // [5:4] disable_lsbs_cr / [3:2] disable_lsbs_cb / [1:0] disable_lsbs_y |
| // 0=12bit; 1=10bit(disable 2-LSB), 2=8bit(disable 4-LSB), 3=6bit(disable 6-LSB) |
| data8 = 0; |
| data8 |= ((6 - color_depth) << 4); |
| data8 |= ((6 - color_depth) << 2); |
| data8 |= ((6 - color_depth) << 0); |
| hdmitx21_wr_reg(VP_INPUT_MASK_IVCTX, data8); |
| |
| // [11: 9] select_cr: 0=y; 1=cb; 2=Cr; 3={cr[11:4],cb[7:4]}; |
| // 4={cr[3:0],y[3:0],cb[3:0]}; |
| // 5={y[3:0],cr[3:0],cb[3:0]}; |
| // 6={cb[3:0],y[3:0],cr[3:0]}; |
| // 7={y[3:0],cb[3:0],cr[3:0]}. |
| // [ 8: 6] select_cb: 0=y; 1=cb; 2=Cr; 3={cr[11:4],cb[7:4]}; |
| // 4={cr[3:0],y[3:0],cb[3:0]}; |
| // 5={y[3:0],cr[3:0],cb[3:0]}; |
| // 6={cb[3:0],y[3:0],cr[3:0]}; |
| // 7={y[3:0],cb[3:0],cr[3:0]}. |
| // [ 5: 3] select_y : 0=y; 1=cb; 2=Cr; 3={y[11:4],cb[7:4]}; |
| // 4={cb[3:0],cr[3:0],y[3:0]}; |
| // 5={cr[3:0],cb[3:0],y[3:0]}; |
| // 6={y[3:0],cb[3:0],cr[3:0]}; |
| // 7={y[3:0],cr[3:0],cb[3:0]}. |
| // [ 2] reverse_cr |
| // [ 1] reverse_cb |
| // [ 0] reverse_y |
| data32 = 0; |
| data32 |= (2 << 9); |
| data32 |= (1 << 6); |
| data32 |= (0 << 3); |
| data32 |= (0 << 2); |
| data32 |= (0 << 1); |
| data32 |= (0 << 0); |
| hdmitx21_wr_reg(VP_OUTPUT_MAPPING_IVCTX, data32 & 0xff); |
| hdmitx21_wr_reg((VP_OUTPUT_MAPPING_IVCTX + 1), (data32 >> 8) & 0xff); |
| |
| // [5:4] disable_lsbs_cr / [3:2] disable_lsbs_cb / [1:0] disable_lsbs_y |
| // 0=12bit; 1=10bit(disable 2-LSB), |
| // 2=8bit(disable 4-LSB), 3=6bit(disable 6-LSB) |
| data8 = 0; |
| data8 |= (0 << 4); |
| data8 |= (0 << 2); |
| data8 |= (0 << 0); |
| hdmitx21_wr_reg(VP_OUTPUT_MASK_IVCTX, data8); |
| |
| //--------------- |
| // config I2S |
| //--------------- |
| //some common reister config,why config this value ?? TODO |
| hdmitx21_wr_reg(AIP_HDMI2MHL_IVCTX, 0x00); //AIP |
| hdmitx21_wr_reg(PKT_FILTER_0_IVCTX, 0x02); //PKT FILTER |
| hdmitx21_wr_reg(ASRC_IVCTX, 0x00); //ASRC |
| hdmitx21_wr_reg(VP_INPUT_SYNC_ADJUST_CONFIG_IVCTX, 0x01); //vp__ |
| |
| data32 = 0; |
| //AUDP_TXCTRL : [1] layout; [7] aud_mute_en |
| hdmitx21_wr_reg(AUDP_TXCTRL_IVCTX, data32 & 0xff); |
| //ACR_CTRL bit[3]:reg_no_mclk_ctsgen_sel_pclk. bit[0]: make hw_cts_hw_sw_sel = 0 |
| hdmitx21_wr_reg(ACR_CTRL_IVCTX, 0x02); |
| hdmitx21_wr_reg(N_SVAL1_IVCTX, (aud_n >> 0) & 0xff); //N_SVAL1 |
| hdmitx21_wr_reg(N_SVAL2_IVCTX, (aud_n >> 8) & 0xff); //N_SVAL2 |
| hdmitx21_wr_reg(N_SVAL3_IVCTX, (aud_n >> 16) & 0xff); //N_SVAL3 |
| |
| //FREQ 00:mclk=128*Fs;01:mclk=256*Fs;10:mclk=384*Fs;11:mclk=512*Fs;... |
| hdmitx21_wr_reg(FREQ_SVAL_IVCTX, 0); |
| |
| // [7:6] reg_tpi_spdif_sample_size: 0=Refer to stream header; 1=16-bit; 2=20-bit; 3=24-bit |
| // [ 4] reg_tpi_aud_mute |
| data32 = 0; |
| data32 |= (3 << 6); |
| data32 |= (0 << 4); |
| hdmitx21_wr_reg(TPI_AUD_CONFIG_IVCTX, data32); |
| |
| if (0) { /* i2s_spdif */ |
| hdmitx21_wr_reg(I2S_IN_MAP_IVCTX, 0xE4); //I2S_IN_MAP |
| hdmitx21_wr_reg(I2S_IN_CTRL_IVCTX, 0x20); //I2S_IN_CTRL [5] reg_cbit_order TODO |
| hdmitx21_wr_reg(I2S_IN_SIZE_IVCTX, 0x0b); //I2S_IN_SIZE |
| hdmitx21_wr_reg(I2S_CHST0_IVCTX, 0x15); //I2S_CHST0 |
| hdmitx21_wr_reg(I2S_CHST1_IVCTX, 0x55); //I2S_CHST1 |
| hdmitx21_wr_reg(I2S_CHST2_IVCTX, 0xfa); //I2S_CHST2 |
| hdmitx21_wr_reg(I2S_CHST3_IVCTX, 0x32); //I2S_CHST3 |
| hdmitx21_wr_reg(I2S_CHST4_IVCTX, 0x2b); //I2S_CHST4 |
| } |
| |
| //[7:4] I2S_EN SD0~SD3 |
| //[ 3] DSD_EN |
| //[ 2] HBRA_EN |
| //[ 1] SPID_EN Enable later in test.c, otherwise initial junk data will be sent |
| //[ 0] PKT_EN |
| data32 = 0; |
| data32 |= (0 << 4); |
| data32 |= (0 << 3); |
| data32 |= ((audio_packet_type == HDMI_AUDIO_PACKET_HBR) << 2); |
| data32 |= (0 << 1); |
| data32 |= (0 << 0); |
| hdmitx21_wr_reg(AUD_MODE_IVCTX, 0x2); //AUD_MODE |
| |
| hdmitx21_wr_reg(AUD_EN_IVCTX, 0x03); //AUD_EN |
| |
| //--------------- |
| // config Packet |
| //--------------- |
| hdmitx21_wr_reg(VTEM_CTRL_IVCTX, 0x04); //[2] reg_vtem_ctrl |
| |
| //drm,emp pacekt |
| hdmitx21_wr_reg(HDMITX_TOP_HS_INTR_CNTL, 0x010); //set TX hs_int h_cnt |
| //tx_program_drm_emp(int_ext,active_lines,blank_lines,128); |
| |
| //-------------------------------------------------------------------------- |
| // Configure HDCP |
| //-------------------------------------------------------------------------- |
| |
| data32 = 0; |
| data32 |= (0xef << 22); // [29:20] channel2 override |
| data32 |= (0xcd << 12); // [19:10] channel1 override |
| data32 |= (0xab << 2); // [ 9: 0] channel0 override |
| hdmitx21_wr_reg(HDMITX_TOP_SEC_VIDEO_OVR, data32); |
| |
| hdmitx21_wr_reg(HDMITX_TOP_HDCP14_MIN_SIZE, 0); |
| hdmitx21_wr_reg(HDMITX_TOP_HDCP22_MIN_SIZE, 0); |
| |
| data32 = 0; |
| data32 |= (active_lines << 16); // [30:16] cntl_vactive |
| data32 |= (active_pixels << 0); // [14: 0] cntl_hactive |
| hdmitx21_wr_reg(HDMITX_TOP_HV_ACTIVE, data32); |
| hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 3, 1, 2); |
| hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 0, 1, 2); |
| if (hdev->rxcap.ieeeoui == HDMI_IEEE_OUI) |
| hdmitx21_set_reg_bits(TPI_SC_IVCTX, 1, 0, 1); |
| else |
| hdmitx21_set_reg_bits(TPI_SC_IVCTX, 0, 0, 1); |
| } /* config_hdmi21_tx */ |
| |
| static void hdmitx_csc_config(u8 input_color_format, |
| u8 output_color_format, |
| u8 color_depth) |
| { |
| u8 conv_en; |
| u8 csc_scale; |
| u8 rgb_ycc_indicator; |
| unsigned long csc_coeff_a1, csc_coeff_a2, csc_coeff_a3, csc_coeff_a4; |
| unsigned long csc_coeff_b1, csc_coeff_b2, csc_coeff_b3, csc_coeff_b4; |
| unsigned long csc_coeff_c1, csc_coeff_c2, csc_coeff_c3, csc_coeff_c4; |
| unsigned long data32; |
| |
| conv_en = (((input_color_format == HDMI_COLORSPACE_RGB) || |
| (output_color_format == HDMI_COLORSPACE_RGB)) && |
| (input_color_format != output_color_format)) ? 1 : 0; |
| |
| if (conv_en) { |
| if (output_color_format == HDMI_COLORSPACE_RGB) { |
| csc_coeff_a1 = 0x2000; |
| csc_coeff_a2 = 0x6926; |
| csc_coeff_a3 = 0x74fd; |
| csc_coeff_a4 = (color_depth == COLORDEPTH_24B) ? |
| 0x010e : |
| (color_depth == COLORDEPTH_30B) ? 0x043b : |
| (color_depth == COLORDEPTH_36B) ? 0x10ee : |
| (color_depth == COLORDEPTH_48B) ? 0x10ee : 0x010e; |
| csc_coeff_b1 = 0x2000; |
| csc_coeff_b2 = 0x2cdd; |
| csc_coeff_b3 = 0x0000; |
| csc_coeff_b4 = (color_depth == COLORDEPTH_24B) ? 0x7e9a : |
| (color_depth == COLORDEPTH_30B) ? 0x7a65 : |
| (color_depth == COLORDEPTH_36B) ? 0x6992 : |
| (color_depth == COLORDEPTH_48B) ? 0x6992 : 0x7e9a; |
| csc_coeff_c1 = 0x2000; |
| csc_coeff_c2 = 0x0000; |
| csc_coeff_c3 = 0x38b4; |
| csc_coeff_c4 = (color_depth == COLORDEPTH_24B) ? 0x7e3b : |
| (color_depth == COLORDEPTH_30B) ? 0x78ea : |
| (color_depth == COLORDEPTH_36B) ? 0x63a6 : |
| (color_depth == COLORDEPTH_48B) ? 0x63a6 : 0x7e3b; |
| csc_scale = 1; |
| } else { /* input_color_format == HDMI_COLORSPACE_RGB */ |
| csc_coeff_a1 = 0x2591; |
| csc_coeff_a2 = 0x1322; |
| csc_coeff_a3 = 0x074b; |
| csc_coeff_a4 = 0x0000; |
| csc_coeff_b1 = 0x6535; |
| csc_coeff_b2 = 0x2000; |
| csc_coeff_b3 = 0x7acc; |
| csc_coeff_b4 = (color_depth == COLORDEPTH_24B) ? 0x0200 : |
| (color_depth == COLORDEPTH_30B) ? 0x0800 : |
| (color_depth == COLORDEPTH_36B) ? 0x2000 : |
| (color_depth == COLORDEPTH_48B) ? 0x2000 : 0x0200; |
| csc_coeff_c1 = 0x6acd; |
| csc_coeff_c2 = 0x7534; |
| csc_coeff_c3 = 0x2000; |
| csc_coeff_c4 = (color_depth == COLORDEPTH_24B) ? 0x0200 : |
| (color_depth == COLORDEPTH_30B) ? 0x0800 : |
| (color_depth == COLORDEPTH_36B) ? 0x2000 : |
| (color_depth == COLORDEPTH_48B) ? 0x2000 : 0x0200; |
| csc_scale = 0; |
| } |
| } else { |
| csc_coeff_a1 = 0x2000; |
| csc_coeff_a2 = 0x0000; |
| csc_coeff_a3 = 0x0000; |
| csc_coeff_a4 = 0x0000; |
| csc_coeff_b1 = 0x0000; |
| csc_coeff_b2 = 0x2000; |
| csc_coeff_b3 = 0x0000; |
| csc_coeff_b4 = 0x0000; |
| csc_coeff_c1 = 0x0000; |
| csc_coeff_c2 = 0x0000; |
| csc_coeff_c3 = 0x2000; |
| csc_coeff_c4 = 0x0000; |
| csc_scale = 1; |
| } |
| |
| data32 = 0; |
| data32 |= (color_depth << 4); /* [7:4] csc_color_depth */ |
| data32 |= (csc_scale << 0); /* [1:0] cscscale */ |
| |
| /* set csc in video path */ |
| /* set rgb_ycc indicator */ |
| switch (output_color_format) { |
| case HDMI_COLORSPACE_RGB: |
| rgb_ycc_indicator = 0x0; |
| break; |
| case HDMI_COLORSPACE_YUV422: |
| rgb_ycc_indicator = 0x1; |
| break; |
| case HDMI_COLORSPACE_YUV420: |
| rgb_ycc_indicator = 0x3; |
| break; |
| case HDMI_COLORSPACE_YUV444: |
| default: |
| rgb_ycc_indicator = 0x2; |
| break; |
| } |
| } /* hdmitx_csc_config */ |
| |
| static void hdmitx_set_hw(struct hdmitx_dev *hdev) |
| { |
| pr_info(HW " config hdmitx IP vic = %d cd:%d cs: %d\n", |
| hdev->para->timing.vic, hdev->para->cd, hdev->para->cs); |
| |
| config_hdmi21_tx(hdev); |
| } |