soc/mediatek/mt8195: add eDP support

BUG=b:189985956

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Signed-off-by: Rex-BC Chen <rex-bc.chen@mediatek.com>
Change-Id: I37326ad053295aa4944c8291e4e7a7d69c8f3f63
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55573
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Jitao Shi
2021-05-29 16:26:00 +08:00
committed by Hung-Te Lin
parent ff82accadb
commit 56126604e0
8 changed files with 7450 additions and 0 deletions

View File

@@ -49,6 +49,7 @@ romstage-y += ../common/rtc.c ../common/rtc_osc_init.c ../common/rtc_mt6359p.c
ramstage-y += ../common/auxadc.c
ramstage-y += ../common/ddp.c ddp.c
ramstage-y += dp_intf.c dptx.c dptx_hal.c
ramstage-y += emi.c
ramstage-y += ../common/flash_controller.c
ramstage-y += ../common/gpio.c gpio.c

View File

@@ -0,0 +1,309 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <delay.h>
#include <edid.h>
#include <soc/addressmap.h>
#include <soc/dp_intf.h>
#include <soc/mcucfg.h>
#include <soc/pll.h>
#include <soc/pll_common.h>
#include <soc/spm.h>
#include <string.h>
#include <timer.h>
static void mtk_dpintf_mask(struct mtk_dpintf *dpintf, u32 offset, u32 val, u32 mask)
{
clrsetbits32(dpintf->regs + offset, mask, val);
}
static void mtk_dpintf_sw_reset(struct mtk_dpintf *dpintf, bool reset)
{
mtk_dpintf_mask(dpintf, DPINTF_RET, reset ? RST : 0, RST);
}
static void mtk_dpintf_enable(struct mtk_dpintf *dpintf)
{
mtk_dpintf_mask(dpintf, DPINTF_EN, EN, EN);
}
static void mtk_dpintf_config_hsync(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync)
{
mtk_dpintf_mask(dpintf, DPINTF_TGEN_HWIDTH,
sync->sync_width << HPW, HPW_MASK);
mtk_dpintf_mask(dpintf, DPINTF_TGEN_HPORCH,
sync->back_porch << HBP, HBP_MASK);
mtk_dpintf_mask(dpintf, DPINTF_TGEN_HPORCH,
sync->front_porch << HFP, HFP_MASK);
}
static void mtk_dpintf_config_vsync(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync,
u32 width_addr, u32 porch_addr)
{
mtk_dpintf_mask(dpintf, width_addr,
sync->sync_width << VSYNC_WIDTH_SHIFT,
VSYNC_WIDTH_MASK);
mtk_dpintf_mask(dpintf, width_addr,
sync->shift_half_line << VSYNC_HALF_LINE_SHIFT,
VSYNC_HALF_LINE_MASK);
mtk_dpintf_mask(dpintf, porch_addr,
sync->back_porch << VSYNC_BACK_PORCH_SHIFT,
VSYNC_BACK_PORCH_MASK);
mtk_dpintf_mask(dpintf, porch_addr,
sync->front_porch << VSYNC_FRONT_PORCH_SHIFT,
VSYNC_FRONT_PORCH_MASK);
}
static void mtk_dpintf_config_vsync_lodd(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync)
{
mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH,
DPINTF_TGEN_VPORCH);
}
static void mtk_dpintf_config_vsync_leven(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync)
{
mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_LEVEN,
DPINTF_TGEN_VPORCH_LEVEN);
}
static void mtk_dpintf_config_vsync_rodd(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync)
{
mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_RODD,
DPINTF_TGEN_VPORCH_RODD);
}
static void mtk_dpintf_config_vsync_reven(struct mtk_dpintf *dpintf,
struct mtk_dpintf_sync_param *sync)
{
mtk_dpintf_config_vsync(dpintf, sync, DPINTF_TGEN_VWIDTH_REVEN,
DPINTF_TGEN_VPORCH_REVEN);
}
static void mtk_dpintf_config_pol(struct mtk_dpintf *dpintf,
struct mtk_dpintf_polarities *dpintf_pol)
{
u32 pol;
pol = (dpintf_pol->hsync_pol == MTK_DPINTF_POLARITY_RISING ? 0 : HSYNC_POL) |
(dpintf_pol->vsync_pol == MTK_DPINTF_POLARITY_RISING ? 0 : VSYNC_POL);
mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, pol, HSYNC_POL | VSYNC_POL);
}
static void mtk_dpintf_config_3d(struct mtk_dpintf *dpintf, bool en_3d)
{
mtk_dpintf_mask(dpintf, DPINTF_CON, en_3d ? TDFP_EN : 0, TDFP_EN);
}
static void mtk_dpintf_config_interface(struct mtk_dpintf *dpintf, bool inter)
{
mtk_dpintf_mask(dpintf, DPINTF_CON, inter ? INTL_EN : 0, INTL_EN);
}
static void mtk_dpintf_config_fb_size(struct mtk_dpintf *dpintf,
u32 width, u32 height)
{
mtk_dpintf_mask(dpintf, DPINTF_SIZE, width << HSIZE, HSIZE_MASK);
mtk_dpintf_mask(dpintf, DPINTF_SIZE, height << VSIZE, VSIZE_MASK);
}
static void mtk_dpintf_config_channel_limit(struct mtk_dpintf *dpintf,
struct mtk_dpintf_yc_limit *limit)
{
mtk_dpintf_mask(dpintf, DPINTF_Y_LIMIT,
limit->y_bottom << Y_LIMINT_BOT, Y_LIMINT_BOT_MASK);
mtk_dpintf_mask(dpintf, DPINTF_Y_LIMIT,
limit->y_top << Y_LIMINT_TOP, Y_LIMINT_TOP_MASK);
mtk_dpintf_mask(dpintf, DPINTF_C_LIMIT,
limit->c_bottom << C_LIMIT_BOT, C_LIMIT_BOT_MASK);
mtk_dpintf_mask(dpintf, DPINTF_C_LIMIT,
limit->c_top << C_LIMIT_TOP, C_LIMIT_TOP_MASK);
}
static void mtk_dpintf_config_bit_num(struct mtk_dpintf *dpintf,
enum mtk_dpintf_out_bit_num num)
{
u32 val;
switch (num) {
case MTK_DPINTF_OUT_BIT_NUM_8BITS:
val = OUT_BIT_8;
break;
case MTK_DPINTF_OUT_BIT_NUM_10BITS:
val = OUT_BIT_10;
break;
case MTK_DPINTF_OUT_BIT_NUM_12BITS:
val = OUT_BIT_12;
break;
case MTK_DPINTF_OUT_BIT_NUM_16BITS:
val = OUT_BIT_16;
break;
default:
val = OUT_BIT_8;
break;
}
mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, val, OUT_BIT_MASK);
}
static void mtk_dpintf_config_channel_swap(struct mtk_dpintf *dpintf,
enum mtk_dpintf_out_channel_swap swap)
{
u32 val;
switch (swap) {
case MTK_DPINTF_OUT_CHANNEL_SWAP_RGB:
val = SWAP_RGB;
break;
case MTK_DPINTF_OUT_CHANNEL_SWAP_GBR:
val = SWAP_GBR;
break;
case MTK_DPINTF_OUT_CHANNEL_SWAP_BRG:
val = SWAP_BRG;
break;
case MTK_DPINTF_OUT_CHANNEL_SWAP_RBG:
val = SWAP_RBG;
break;
case MTK_DPINTF_OUT_CHANNEL_SWAP_GRB:
val = SWAP_GRB;
break;
case MTK_DPINTF_OUT_CHANNEL_SWAP_BGR:
val = SWAP_BGR;
break;
default:
val = SWAP_RGB;
break;
}
mtk_dpintf_mask(dpintf, DPINTF_OUTPUT_SETTING, val, CH_SWAP_MASK);
}
static void mtk_dpintf_config_yuv422_enable(struct mtk_dpintf *dpintf, bool enable)
{
mtk_dpintf_mask(dpintf, DPINTF_CON, enable ? YUV422_EN : 0, YUV422_EN);
}
static void mtk_dpintf_config_color_format(struct mtk_dpintf *dpintf,
enum mtk_dpintf_out_color_format format)
{
bool enable;
int channel_swap;
if (format == MTK_DPINTF_COLOR_FORMAT_YCBCR_444 ||
format == MTK_DPINTF_COLOR_FORMAT_YCBCR_444_FULL) {
enable = false;
channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_BGR;
} else if (format == MTK_DPINTF_COLOR_FORMAT_YCBCR_422 ||
format == MTK_DPINTF_COLOR_FORMAT_YCBCR_422_FULL) {
enable = true;
channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_RGB;
} else {
enable = false;
channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_RGB;
}
mtk_dpintf_config_yuv422_enable(dpintf, enable);
mtk_dpintf_config_channel_swap(dpintf, channel_swap);
}
static int mtk_dpintf_power_on(struct mtk_dpintf *dpintf, const struct edid *edid)
{
u32 clksrc;
u32 pll_rate;
if (edid->mode.pixel_clock < 70000)
clksrc = TVDPLL_D16;
else if (edid->mode.pixel_clock < 200000)
clksrc = TVDPLL_D8;
else
clksrc = TVDPLL_D4;
pll_rate = edid->mode.pixel_clock * 1000 * (1 << ((clksrc + 1) / 2));
mt_pll_set_tvd_pll1_freq(pll_rate / 4);
edp_mux_set_sel(clksrc);
mtk_dpintf_enable(dpintf);
return 0;
}
static int mtk_dpintf_set_display_mode(struct mtk_dpintf *dpintf,
const struct edid *edid)
{
struct mtk_dpintf_yc_limit limit;
struct mtk_dpintf_polarities dpintf_pol;
struct mtk_dpintf_sync_param hsync;
struct mtk_dpintf_sync_param vsync_lodd = { 0 };
struct mtk_dpintf_sync_param vsync_leven = { 0 };
struct mtk_dpintf_sync_param vsync_rodd = { 0 };
struct mtk_dpintf_sync_param vsync_reven = { 0 };
vsync_lodd.back_porch = edid->mode.vbl - edid->mode.vso -
edid->mode.vspw - edid->mode.vborder;
vsync_lodd.front_porch = edid->mode.vso - edid->mode.vborder;
vsync_lodd.sync_width = edid->mode.vspw;
vsync_lodd.shift_half_line = false;
hsync.sync_width = edid->mode.hspw / 4;
hsync.back_porch = (edid->mode.hbl - edid->mode.hso -
edid->mode.hspw - edid->mode.hborder) / 4;
hsync.front_porch = (edid->mode.hso - edid->mode.hborder) / 4;
hsync.shift_half_line = false;
/* Let pll_rate be able to fix the valid range of tvdpll (1G~2GHz) */
limit.c_bottom = 0x0000;
limit.c_top = 0xfff;
limit.y_bottom = 0x0000;
limit.y_top = 0xfff;
dpintf_pol.ck_pol = MTK_DPINTF_POLARITY_FALLING;
dpintf_pol.de_pol = MTK_DPINTF_POLARITY_RISING;
dpintf_pol.hsync_pol = (edid->mode.phsync == '+') ?
MTK_DPINTF_POLARITY_FALLING :
MTK_DPINTF_POLARITY_RISING;
dpintf_pol.vsync_pol = (edid->mode.pvsync == '+') ?
MTK_DPINTF_POLARITY_FALLING :
MTK_DPINTF_POLARITY_RISING;
mtk_dpintf_sw_reset(dpintf, true);
mtk_dpintf_config_pol(dpintf, &dpintf_pol);
mtk_dpintf_config_hsync(dpintf, &hsync);
mtk_dpintf_config_vsync_lodd(dpintf, &vsync_lodd);
mtk_dpintf_config_vsync_rodd(dpintf, &vsync_rodd);
mtk_dpintf_config_vsync_leven(dpintf, &vsync_leven);
mtk_dpintf_config_vsync_reven(dpintf, &vsync_reven);
mtk_dpintf_config_3d(dpintf, false);
mtk_dpintf_config_interface(dpintf, false);
mtk_dpintf_config_fb_size(dpintf, edid->mode.ha, edid->mode.va);
mtk_dpintf_config_channel_limit(dpintf, &limit);
mtk_dpintf_config_bit_num(dpintf, dpintf->bit_num);
mtk_dpintf_config_channel_swap(dpintf, dpintf->channel_swap);
mtk_dpintf_config_color_format(dpintf, dpintf->color_format);
mtk_dpintf_mask(dpintf, DPINTF_CON, INPUT_2P_EN, INPUT_2P_EN);
mtk_dpintf_sw_reset(dpintf, false);
return 0;
}
void dp_intf_config(const struct edid *edid)
{
struct mtk_dpintf dpintf = {
.regs = (void *)(DP_INTF0_BASE),
.color_format = MTK_DPINTF_COLOR_FORMAT_RGB,
.yc_map = MTK_DPINTF_OUT_YC_MAP_RGB,
.bit_num = MTK_DPINTF_OUT_BIT_NUM_8BITS,
.channel_swap = MTK_DPINTF_OUT_CHANNEL_SWAP_RGB,
};
mtk_dpintf_power_on(&dpintf, edid);
mtk_dpintf_set_display_mode(&dpintf, edid);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,826 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/mmio.h>
#include <delay.h>
#include <edid.h>
#include <soc/dptx.h>
#include <soc/dptx_hal.h>
#include <soc/dptx_reg.h>
#include <string.h>
#include <timer.h>
#define REG_OFFSET_LIMIT 0x8000
struct shift_mask {
u32 shift;
u32 mask;
};
static const struct shift_mask volt_swing[DPTX_LANE_MAX] = {
[DPTX_LANE0] = { DP_TX0_VOLT_SWING_FLDMASK_POS, DP_TX0_VOLT_SWING_FLDMASK },
[DPTX_LANE1] = { DP_TX1_VOLT_SWING_FLDMASK_POS, DP_TX1_VOLT_SWING_FLDMASK },
[DPTX_LANE2] = { DP_TX2_VOLT_SWING_FLDMASK_POS, DP_TX2_VOLT_SWING_FLDMASK },
[DPTX_LANE3] = { DP_TX3_VOLT_SWING_FLDMASK_POS, DP_TX3_VOLT_SWING_FLDMASK },
};
static const struct shift_mask volt_preemphasis[DPTX_LANE_MAX] = {
[DPTX_LANE0] = { DP_TX0_PRE_EMPH_FLDMASK_POS, DP_TX0_PRE_EMPH_FLDMASK },
[DPTX_LANE1] = { DP_TX1_PRE_EMPH_FLDMASK_POS, DP_TX1_PRE_EMPH_FLDMASK },
[DPTX_LANE2] = { DP_TX2_PRE_EMPH_FLDMASK_POS, DP_TX2_PRE_EMPH_FLDMASK },
[DPTX_LANE3] = { DP_TX3_PRE_EMPH_FLDMASK_POS, DP_TX3_PRE_EMPH_FLDMASK },
};
u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset)
{
void *addr = mtk_dp->regs + offset;
if (offset % 4 != 0 || offset > REG_OFFSET_LIMIT) {
printk(BIOS_ERR, "[%s] invalid offset %#x for reg %p\n",
__func__, offset, mtk_dp->regs);
return 0;
}
return read32(addr);
}
void mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val)
{
void *addr = mtk_dp->regs + offset;
if (offset % 4 != 0 || offset > REG_OFFSET_LIMIT) {
printk(BIOS_ERR, "[%s] invalid offset %#x for reg %p\n",
__func__, offset, mtk_dp->regs);
return;
}
write32(addr, val);
}
void mtk_dp_mask(struct mtk_dp *mtk_dp, u32 offset, u32 val, u32 mask)
{
void *addr = mtk_dp->regs + offset;
if (offset % 4 != 0 || offset > REG_OFFSET_LIMIT) {
printk(BIOS_ERR, "[%s] invalid offset %#x for reg %p\n",
__func__, offset, mtk_dp->regs);
return;
}
/*
* TODO: modify to clrsetbits32(addr, mask, val);
* There is asserion error when testing assert((val & mask) == val).
*/
clrsetbits32(addr, mask, val & mask);
}
void mtk_dp_write_byte(struct mtk_dp *mtk_dp, u32 addr, u8 val, u32 mask)
{
if (addr % 2) {
mtk_dp_write(mtk_dp, DP_TX_TOP_APB_WSTRB, 0x12);
mtk_dp_mask(mtk_dp, addr - 1, val << 8, mask << 8);
} else {
mtk_dp_write(mtk_dp, DP_TX_TOP_APB_WSTRB, 0x11);
mtk_dp_mask(mtk_dp, addr, val, mask);
}
mtk_dp_write(mtk_dp, DP_TX_TOP_APB_WSTRB, 0x0);
}
void dptx_hal_verify_clock(struct mtk_dp *mtk_dp)
{
u32 m, n, ls_clk, pix_clk;
m = mtk_dp_read(mtk_dp, REG_33C8_DP_ENCODER1_P0);
n = 0x8000;
ls_clk = mtk_dp->train_info.linkrate;
ls_clk *= 27;
pix_clk = m * ls_clk / n;
printk(BIOS_DEBUG, "DPTX calc pixel clock = %d MHz, dp_intf clock = %dMHz\n",
pix_clk, pix_clk / 4);
}
void dptx_hal_init_setting(struct mtk_dp *mtk_dp)
{
DP_WRITE1BYTE(mtk_dp, REG_342C_DP_TRANS_P0, 0x69);
mtk_dp_mask(mtk_dp, REG_3540_DP_TRANS_P0, BIT(3), BIT(3));
mtk_dp_mask(mtk_dp, REG_31EC_DP_ENCODER0_P0, BIT(4), BIT(4));
mtk_dp_mask(mtk_dp, REG_304C_DP_ENCODER0_P0, 0, BIT(8));
mtk_dp_mask(mtk_dp, DP_TX_TOP_IRQ_MASK, BIT(2), BIT(2));
}
void dptx_hal_bypassmsa_en(struct mtk_dp *mtk_dp, bool enable)
{
mtk_dp_mask(mtk_dp, REG_3030_DP_ENCODER0_P0,
enable ? 0 : 0x3ff, 0x3ff);
}
void dptx_hal_set_msa(struct mtk_dp *mtk_dp)
{
u32 va, vsync, vbp, vfp, vtotal, ha, hsync, hbp, hfp, htotal;
struct edid *edid = mtk_dp->edid;
va = edid->mode.va;
vsync = edid->mode.vspw;
vbp = edid->mode.vbl - edid->mode.vso -
edid->mode.vspw - edid->mode.vborder;
vfp = edid->mode.vso - edid->mode.vborder;
ha = edid->mode.ha;
hsync = edid->mode.hspw;
hbp = edid->mode.hbl - edid->mode.hso -
edid->mode.hspw - edid->mode.hborder;
hfp = edid->mode.hso - edid->mode.hborder;
htotal = ha + hsync + hbp + hfp;
vtotal = va + vsync + vbp + vfp;
DP_WRITE2BYTE(mtk_dp, REG_3010_DP_ENCODER0_P0, htotal);
DP_WRITE2BYTE(mtk_dp, REG_3018_DP_ENCODER0_P0, hsync + hbp);
mtk_dp_mask(mtk_dp, REG_3028_DP_ENCODER0_P0,
hsync << HSW_SW_DP_ENCODER0_P0_FLDMASK_POS,
HSW_SW_DP_ENCODER0_P0_FLDMASK);
mtk_dp_mask(mtk_dp, REG_3028_DP_ENCODER0_P0,
0 << HSP_SW_DP_ENCODER0_P0_FLDMASK_POS,
HSP_SW_DP_ENCODER0_P0_FLDMASK);
DP_WRITE2BYTE(mtk_dp, REG_3020_DP_ENCODER0_P0, ha);
DP_WRITE2BYTE(mtk_dp, REG_3014_DP_ENCODER0_P0, va);
DP_WRITE2BYTE(mtk_dp, REG_301C_DP_ENCODER0_P0, vsync + vbp);
mtk_dp_mask(mtk_dp, REG_302C_DP_ENCODER0_P0,
vsync << VSW_SW_DP_ENCODER0_P0_FLDMASK_POS,
VSW_SW_DP_ENCODER0_P0_FLDMASK);
mtk_dp_mask(mtk_dp, REG_302C_DP_ENCODER0_P0,
0 << VSP_SW_DP_ENCODER0_P0_FLDMASK_POS,
VSP_SW_DP_ENCODER0_P0_FLDMASK);
DP_WRITE2BYTE(mtk_dp, REG_3024_DP_ENCODER0_P0, va);
DP_WRITE2BYTE(mtk_dp, REG_3064_DP_ENCODER0_P0, ha);
DP_WRITE2BYTE(mtk_dp, REG_3154_DP_ENCODER0_P0, htotal);
DP_WRITE2BYTE(mtk_dp, REG_3158_DP_ENCODER0_P0, hfp);
DP_WRITE2BYTE(mtk_dp, REG_315C_DP_ENCODER0_P0, vsync);
DP_WRITE2BYTE(mtk_dp, REG_3160_DP_ENCODER0_P0, hsync + hbp);
DP_WRITE2BYTE(mtk_dp, REG_3164_DP_ENCODER0_P0, ha);
DP_WRITE2BYTE(mtk_dp, REG_3168_DP_ENCODER0_P0, vtotal);
DP_WRITE2BYTE(mtk_dp, REG_316C_DP_ENCODER0_P0, hfp);
DP_WRITE2BYTE(mtk_dp, REG_3170_DP_ENCODER0_P0, vsync);
DP_WRITE2BYTE(mtk_dp, REG_3174_DP_ENCODER0_P0, vsync + vbp);
DP_WRITE2BYTE(mtk_dp, REG_3178_DP_ENCODER0_P0, va);
printk(BIOS_INFO, "MSA:Htt(%d), Vtt(%d), Hact(%d), Vact(%d), FPS(%d)\n",
htotal, vtotal, ha, va,
edid->mode.pixel_clock * 1000 / htotal / vtotal);
}
void dptx_hal_set_color_format(struct mtk_dp *mtk_dp, u8 out_format)
{
/* MISC0 */
mtk_dp_write_byte(mtk_dp, REG_3034_DP_ENCODER0_P0,
out_format << 0x1, MASKBIT(2, 1));
switch (out_format) {
case DP_COLOR_FORMAT_RGB_444:
case DP_COLOR_FORMAT_YUV_444:
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0 + 1,
0, MASKBIT(6, 4));
break;
case DP_COLOR_FORMAT_YUV_422:
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0 + 1,
BIT(4), MASKBIT(6, 4));
break;
case DP_COLOR_FORMAT_YUV_420:
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0 + 1, BIT(5),
MASKBIT(6, 4));
break;
default:
break;
}
}
void dptx_hal_set_color_depth(struct mtk_dp *mtk_dp, u8 color_depth)
{
u8 val;
mtk_dp_write_byte(mtk_dp, REG_3034_DP_ENCODER0_P0,
color_depth << 0x5, 0xe0);
switch (color_depth) {
case DP_COLOR_DEPTH_6BIT:
val = 4;
break;
case DP_COLOR_DEPTH_8BIT:
val = 3;
break;
case DP_COLOR_DEPTH_10BIT:
val = 2;
break;
case DP_COLOR_DEPTH_12BIT:
val = 1;
break;
case DP_COLOR_DEPTH_16BIT:
val = 0;
break;
default:
return;
}
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0 + 1, val, 0x7);
}
void dptx_hal_setmisc(struct mtk_dp *mtk_dp, u8 cmisc[2])
{
mtk_dp_write_byte(mtk_dp, REG_3034_DP_ENCODER0_P0, cmisc[0], 0xfe);
mtk_dp_write_byte(mtk_dp, REG_3034_DP_ENCODER0_P0 + 1, cmisc[1], 0xff);
}
void dptx_hal_overwrite_mn(struct mtk_dp *mtk_dp,
bool enable, u32 video_m, u32 video_n)
{
if (enable) {
/* Turn on overwrite MN */
DP_WRITE2BYTE(mtk_dp, REG_3008_DP_ENCODER0_P0,
video_m & 0xffff);
DP_WRITE1BYTE(mtk_dp, REG_300C_DP_ENCODER0_P0,
(video_m >> 16) & 0xff);
DP_WRITE2BYTE(mtk_dp, REG_3044_DP_ENCODER0_P0,
video_n & 0xffff);
DP_WRITE1BYTE(mtk_dp, REG_3048_DP_ENCODER0_P0,
(video_n >> 16) & 0xff);
DP_WRITE2BYTE(mtk_dp, REG_3050_DP_ENCODER0_P0,
video_n & 0xffff);
/* Add legerII. */
DP_WRITE1BYTE(mtk_dp, REG_3054_DP_ENCODER0_P0,
(video_n >> 16) & 0xff);
mtk_dp_write_byte(mtk_dp, REG_3004_DP_ENCODER0_P0 + 1,
BIT(0), BIT(0));
} else {
/* Turn off overwrite MN */
mtk_dp_write_byte(mtk_dp, REG_3004_DP_ENCODER0_P0 + 1,
0, BIT(0));
}
}
u8 dptx_hal_get_colorbpp(struct mtk_dp *mtk_dp)
{
u8 color_bpp;
u8 color_depth = mtk_dp->info.depth;
u8 color_format = mtk_dp->info.format;
switch (color_depth) {
case DP_COLOR_DEPTH_6BIT:
if (color_format == DP_COLOR_FORMAT_YUV_422)
color_bpp = 16;
else if (color_format == DP_COLOR_FORMAT_YUV_420)
color_bpp = 12;
else
color_bpp = 18;
break;
case DP_COLOR_DEPTH_8BIT:
if (color_format == DP_COLOR_FORMAT_YUV_422)
color_bpp = 16;
else if (color_format == DP_COLOR_FORMAT_YUV_420)
color_bpp = 12;
else
color_bpp = 24;
break;
case DP_COLOR_DEPTH_10BIT:
if (color_format == DP_COLOR_FORMAT_YUV_422)
color_bpp = 20;
else if (color_format == DP_COLOR_FORMAT_YUV_420)
color_bpp = 15;
else
color_bpp = 30;
break;
case DP_COLOR_DEPTH_12BIT:
if (color_format == DP_COLOR_FORMAT_YUV_422)
color_bpp = 24;
else if (color_format == DP_COLOR_FORMAT_YUV_420)
color_bpp = 18;
else
color_bpp = 36;
break;
case DP_COLOR_DEPTH_16BIT:
if (color_format == DP_COLOR_FORMAT_YUV_422)
color_bpp = 32;
else if (color_format == DP_COLOR_FORMAT_YUV_420)
color_bpp = 24;
else
color_bpp = 48;
break;
default:
color_bpp = 24;
printk(BIOS_ERR, "Set wrong bpp = %d\n", color_bpp);
break;
}
return color_bpp;
}
void dptx_hal_settu_sramrd_start(struct mtk_dp *mtk_dp, u16 value)
{
/*
* [5:0] video sram start address
* modify in 480P case only, default=0x1f
*/
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0, (u8)value, 0x3f);
}
void dptx_hal_setsdp_downcnt_init_inhblanking(struct mtk_dp *mtk_dp, u16 value)
{
mtk_dp_mask(mtk_dp, REG_3364_DP_ENCODER1_P0, value, 0xfff);
}
void dptx_hal_setsdp_downcnt_init(struct mtk_dp *mtk_dp, u16 value)
{
mtk_dp_mask(mtk_dp, REG_3040_DP_ENCODER0_P0, value, 0xfff);
}
void dptx_hal_settu_setencoder(struct mtk_dp *mtk_dp)
{
mtk_dp_write_byte(mtk_dp, REG_303C_DP_ENCODER0_P0 + 1,
BIT(7), BIT(7));
DP_WRITE2BYTE(mtk_dp, REG_3040_DP_ENCODER0_P0, 0x2020);
mtk_dp_mask(mtk_dp, REG_3364_DP_ENCODER1_P0, 0x2020, 0xfff);
mtk_dp_write_byte(mtk_dp, REG_3300_DP_ENCODER1_P0 + 1,
0x2, BIT(1) | BIT(0));
mtk_dp_write_byte(mtk_dp, REG_3364_DP_ENCODER1_P0 + 1,
0x40, 0x70);
DP_WRITE2BYTE(mtk_dp, REG_3368_DP_ENCODER1_P0, 0x1111);
}
bool dptx_hal_hpd_high(struct mtk_dp *mtk_dp)
{
return mtk_dp_read(mtk_dp, REG_3414_DP_TRANS_P0) & BIT(2);
}
bool dptx_hal_auxread_bytes(struct mtk_dp *mtk_dp, u8 cmd,
u32 dpcd_addr, size_t length, u8 *rx_buf)
{
bool valid_cmd = false;
u8 reply_cmd, aux_irq_status;
int rd_count;
u32 wait_reply_count = AUX_WAITREPLY_LPNUM;
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
if (length > 16 || (cmd == AUX_CMD_NATIVE_R && length == 0x0))
return false;
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1, 0x1);
DP_WRITE1BYTE(mtk_dp, REG_3644_AUX_TX_P0, cmd);
DP_WRITE2BYTE(mtk_dp, REG_3648_AUX_TX_P0, dpcd_addr & 0xffff);
DP_WRITE1BYTE(mtk_dp, REG_364C_AUX_TX_P0, (dpcd_addr >> 16) & 0xf);
if (length > 0) {
mtk_dp_mask(mtk_dp, REG_3650_AUX_TX_P0,
(length - 1) << MCU_REQ_DATA_NUM_AUX_TX_P0_FLDMASK_POS,
MCU_REQUEST_DATA_NUM_AUX_TX_P0_FLDMASK);
DP_WRITE1BYTE(mtk_dp, REG_362C_AUX_TX_P0, 0x0);
}
if (cmd == AUX_CMD_I2C_R || cmd == AUX_CMD_I2C_R_MOT0)
if (length == 0x0)
mtk_dp_mask(mtk_dp, REG_362C_AUX_TX_P0,
0x1 << AUX_NO_LENGTH_AUX_TX_P0_FLDMASK_POS,
AUX_NO_LENGTH_AUX_TX_P0_FLDMASK);
mtk_dp_mask(mtk_dp, REG_3630_AUX_TX_P0,
0x1 << AUX_TX_REQUEST_READY_AUX_TX_P0_FLDMASK_POS,
AUX_TX_REQUEST_READY_AUX_TX_P0_FLDMASK);
while (--wait_reply_count) {
if (mtk_dp_read(mtk_dp, REG_3618_AUX_TX_P0) &
AUX_RX_FIFO_WRITE_POINTER_AUX_TX_P0_FLDMASK) {
valid_cmd = true;
break;
}
if (mtk_dp_read(mtk_dp, REG_3618_AUX_TX_P0) &
AUX_RX_FIFO_FULL_AUX_TX_P0_FLDMASK) {
valid_cmd = true;
break;
}
aux_irq_status = mtk_dp_read(mtk_dp, REG_3640_AUX_TX_P0) & 0xff;
if (aux_irq_status & AUX_RX_RECV_COMPLETE_IRQ_TX_P0_FLDMASK) {
valid_cmd = true;
break;
}
if (aux_irq_status & AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_FLDMASK) {
printk(BIOS_ERR, "(AUX Read)HW Timeout 400us irq\n");
break;
}
}
reply_cmd = mtk_dp_read(mtk_dp, REG_3624_AUX_TX_P0) & 0xf;
if (reply_cmd)
printk(BIOS_ERR, "reply_cmd(%#x), NACK or Defer\n", reply_cmd);
if (wait_reply_count == 0x0 || reply_cmd) {
u8 phy_status = 0x0;
phy_status = mtk_dp_read(mtk_dp, REG_3628_AUX_TX_P0);
if (phy_status != 0x1)
printk(BIOS_ERR, "Aux read: aux hang, need sw reset\n");
mtk_dp_mask(mtk_dp, REG_3650_AUX_TX_P0,
0x1 << MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_FLDMASK_POS,
MCU_ACK_TRANSACTION_COMPLETE_AUX_TX_P0_FLDMASK);
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
printk(BIOS_ERR, "wait_reply_count(%#x), TimeOut\n",
wait_reply_count);
return false;
}
if (length == 0) {
DP_WRITE1BYTE(mtk_dp, REG_362C_AUX_TX_P0, 0x0);
} else {
if (valid_cmd) {
mtk_dp_mask(mtk_dp, REG_3620_AUX_TX_P0,
0x0 << AUX_RD_MODE_AUX_TX_P0_FLDMASK_POS,
AUX_RD_MODE_AUX_TX_P0_FLDMASK);
for (rd_count = 0; rd_count < length; rd_count++) {
mtk_dp_mask(mtk_dp, REG_3620_AUX_TX_P0,
0x1 << AUX_RX_FIFO_R_PULSE_TX_P0_FLDMASK_POS,
AUX_RX_FIFO_READ_PULSE_TX_P0_FLDMASK);
mdelay(1);
*(rx_buf + rd_count) = mtk_dp_read(mtk_dp,
REG_3620_AUX_TX_P0);
}
} else {
printk(BIOS_INFO, "Read TimeOut %#x\n", dpcd_addr);
}
}
mtk_dp_mask(mtk_dp, REG_3650_AUX_TX_P0,
0x1 << MCU_ACK_TRAN_COMPLETE_AUX_TX_P0_FLDMASK_POS,
MCU_ACK_TRANSACTION_COMPLETE_AUX_TX_P0_FLDMASK);
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
return valid_cmd;
}
bool dptx_hal_auxwrite_bytes(struct mtk_dp *mtk_dp, u8 cmd,
u32 dpcd_addr, size_t length, u8 *data)
{
bool valid_cmd = false;
u8 reply_cmd;
int i;
u16 wait_reply_count = AUX_WAITREPLY_LPNUM;
int reg_idx;
mtk_dp_write_byte(mtk_dp, REG_3704_AUX_TX_P0,
1 << AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_FLDMASK_POS,
AUX_TX_FIFO_NEW_MODE_EN_AUX_TX_P0_FLDMASK);
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1, 0x1);
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1, 0x1);
DP_WRITE1BYTE(mtk_dp, REG_3644_AUX_TX_P0, cmd);
DP_WRITE1BYTE(mtk_dp, REG_3648_AUX_TX_P0, dpcd_addr & 0xff);
DP_WRITE1BYTE(mtk_dp, REG_3648_AUX_TX_P0 + 1,
(dpcd_addr >> 8) & 0xff);
DP_WRITE1BYTE(mtk_dp, REG_364C_AUX_TX_P0,
(dpcd_addr >> 16) & 0xf);
if (length > 0) {
DP_WRITE1BYTE(mtk_dp, REG_362C_AUX_TX_P0, 0x0);
for (i = 0; i < (length + 1) / 2; i++)
for (reg_idx = 0; reg_idx < 2; reg_idx++)
if ((i * 2 + reg_idx) < length)
DP_WRITE1BYTE(mtk_dp,
REG_3708_AUX_TX_P0 + i * 4 + reg_idx,
data[i * 2 + reg_idx]);
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1,
((length - 1) & 0xf) << 4);
} else {
DP_WRITE1BYTE(mtk_dp, REG_362C_AUX_TX_P0, 0x1);
}
mtk_dp_write_byte(mtk_dp, REG_3704_AUX_TX_P0,
AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_FLDMASK,
AUX_TX_FIFO_WRITE_DATA_NEW_MODE_TOGGLE_AUX_TX_P0_FLDMASK);
DP_WRITE1BYTE(mtk_dp, REG_3630_AUX_TX_P0, 0x8);
while (--wait_reply_count) {
u8 aux_irq_status;
aux_irq_status = mtk_dp_read(mtk_dp, REG_3640_AUX_TX_P0) & 0xff;
mdelay(1);
if (aux_irq_status & AUX_RX_RECV_COMPLETE_IRQ_TX_P0_FLDMASK) {
valid_cmd = true;
break;
}
if (aux_irq_status & AUX_400US_TIMEOUT_IRQ_AUX_TX_P0_FLDMASK)
break;
}
reply_cmd = mtk_dp_read(mtk_dp, REG_3624_AUX_TX_P0) & 0xf;
if (reply_cmd)
printk(BIOS_ERR, "reply_cmd(%#x), NACK or Defer\n", reply_cmd);
if (wait_reply_count == 0x0 || reply_cmd) {
u8 phy_status = 0x0;
phy_status = mtk_dp_read(mtk_dp, REG_3628_AUX_TX_P0);
if (phy_status != 0x1)
printk(BIOS_ERR,
"Aux write: aux hang, need SW reset!\n");
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1, 0x1);
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
printk(BIOS_INFO, "reply_cmd(%#x), wait_reply_count(%d)\n",
reply_cmd, wait_reply_count);
return false;
}
DP_WRITE1BYTE(mtk_dp, REG_3650_AUX_TX_P0 + 1, 0x1);
if (length == 0)
DP_WRITE1BYTE(mtk_dp, REG_362C_AUX_TX_P0, 0x0);
DP_WRITE1BYTE(mtk_dp, REG_3640_AUX_TX_P0, 0x7f);
mdelay(1);
return valid_cmd;
}
bool dptx_hal_setswing_preemphasis(struct mtk_dp *mtk_dp, int lane_num,
int swing_value, int preemphasis)
{
printk(BIOS_DEBUG, "lane(%d), set swing(%#x), emp(%#x)\n",
lane_num, swing_value, preemphasis);
if (lane_num >= DPTX_LANE_MAX) {
printk(BIOS_ERR, "invalid lane number: %d\n", lane_num);
return false;
}
mtk_dp_mask(mtk_dp, DP_TX_TOP_SWING_EMP,
swing_value << volt_swing[lane_num].shift,
volt_swing[lane_num].mask);
mtk_dp_mask(mtk_dp, DP_TX_TOP_SWING_EMP,
preemphasis << volt_preemphasis[lane_num].shift,
volt_preemphasis[lane_num].mask);
return true;
}
void dptx_hal_reset_swing_preemphasis(struct mtk_dp *mtk_dp)
{
int lane;
for (lane = 0; lane < DPTX_LANE_MAX; lane++)
mtk_dp_mask(mtk_dp, DP_TX_TOP_SWING_EMP,
0, volt_swing[lane].mask);
for (lane = 0; lane < DPTX_LANE_MAX; lane++)
mtk_dp_mask(mtk_dp, DP_TX_TOP_SWING_EMP,
0, volt_preemphasis[lane].mask);
}
void dptx_hal_hpd_int_en(struct mtk_dp *mtk_dp, bool enable)
{
/* [7]:int, [6]:Con, [5]DisCon, [4]No-Use: UnMASK HPD Port */
mtk_dp_write_byte(mtk_dp, REG_3418_DP_TRANS_P0,
enable ? 0 : MASKBIT(7, 5), MASKBIT(7, 5));
}
void dptx_hal_hpd_detect_setting(struct mtk_dp *mtk_dp)
{
mtk_dp_write_byte(mtk_dp, REG_3410_DP_TRANS_P0,
0x8, MASKBIT(3, 0));
mtk_dp_write_byte(mtk_dp, REG_3410_DP_TRANS_P0,
0xa << 4, MASKBIT(7, 4));
DP_WRITE1BYTE(mtk_dp, REG_3410_DP_TRANS_P0 + 1, 0x55);
DP_WRITE1BYTE(mtk_dp, REG_3430_DP_TRANS_P0, 0x2);
}
void dptx_hal_phy_setting(struct mtk_dp *mtk_dp)
{
mtk_dp_mask(mtk_dp, DP_TX_TOP_PWR_STATE,
0x3 << DP_PWR_STATE_FLDMASK_POS, DP_PWR_STATE_FLDMASK);
mtk_dp_write(mtk_dp, 0x2000, 0x00000001);
mtk_dp_write(mtk_dp, 0x103c, 0x00000000);
mtk_dp_write(mtk_dp, 0x2000, 0x00000003);
mtk_dp_write(mtk_dp, 0x1138, 0x20181410);
mtk_dp_write(mtk_dp, 0x1238, 0x20181410);
mtk_dp_write(mtk_dp, 0x1338, 0x20181410);
mtk_dp_write(mtk_dp, 0x1438, 0x20181410);
mtk_dp_write(mtk_dp, 0x113C, 0x20241e18);
mtk_dp_write(mtk_dp, 0x123C, 0x20241e18);
mtk_dp_write(mtk_dp, 0x133C, 0x20241e18);
mtk_dp_write(mtk_dp, 0x143C, 0x20241e18);
mtk_dp_write(mtk_dp, 0x1140, 0x00003028);
mtk_dp_write(mtk_dp, 0x1240, 0x00003028);
mtk_dp_write(mtk_dp, 0x1340, 0x00003028);
mtk_dp_write(mtk_dp, 0x1440, 0x00003028);
mtk_dp_write(mtk_dp, 0x1144, 0x10080400);
mtk_dp_write(mtk_dp, 0x1244, 0x10080400);
mtk_dp_write(mtk_dp, 0x1344, 0x10080400);
mtk_dp_write(mtk_dp, 0x1444, 0x10080400);
mtk_dp_write(mtk_dp, 0x1148, 0x000c0600);
mtk_dp_write(mtk_dp, 0x1248, 0x000c0600);
mtk_dp_write(mtk_dp, 0x1348, 0x000c0600);
mtk_dp_write(mtk_dp, 0x1448, 0x000c0600);
mtk_dp_write(mtk_dp, 0x114C, 0x00000008);
mtk_dp_write(mtk_dp, 0x124C, 0x00000008);
mtk_dp_write(mtk_dp, 0x134C, 0x00000008);
mtk_dp_write(mtk_dp, 0x144C, 0x00000008);
mtk_dp_mask(mtk_dp, 0x3690, BIT(8), BIT(8));
}
void dptx_hal_ssc_en(struct mtk_dp *mtk_dp, bool enable)
{
mtk_dp_mask(mtk_dp, 0x2000, BIT(0), MASKBIT(1, 0));
if (enable)
mtk_dp_mask(mtk_dp, 0x1014, BIT(3), BIT(3));
else
mtk_dp_mask(mtk_dp, 0x1014, 0x0, BIT(3));
mtk_dp_mask(mtk_dp, 0x2000, MASKBIT(1, 0), MASKBIT(1, 0));
mdelay(1);
}
void dptx_hal_aux_setting(struct mtk_dp *mtk_dp)
{
/* [12 : 8]: modify timeout threshold = 1595 */
mtk_dp_mask(mtk_dp, REG_360C_AUX_TX_P0,
0x1595, AUX_TIMEOUT_THR_AUX_TX_P0_FLDMASK);
mtk_dp_write_byte(mtk_dp, REG_3658_AUX_TX_P0, 0, BIT(0));
/* 0x19 for 26M */
DP_WRITE1BYTE(mtk_dp, REG_3634_AUX_TX_P0 + 1, 0x19);
/* 0xd for 26M */
mtk_dp_write_byte(mtk_dp, REG_3614_AUX_TX_P0,
0xd, MASKBIT(6, 0));
mtk_dp_mask(mtk_dp, REG_37C8_AUX_TX_P0,
0x01 << MTK_ATOP_EN_AUX_TX_P0_FLDMASK_POS,
MTK_ATOP_EN_AUX_TX_P0_FLDMASK);
}
void dptx_hal_digital_setting(struct mtk_dp *mtk_dp)
{
mtk_dp_write_byte(mtk_dp, REG_304C_DP_ENCODER0_P0,
0, VBID_VIDEO_MUTE_DP_ENCODER0_P0_FLDMASK);
/* MISC0 */
dptx_hal_set_color_format(mtk_dp, DP_COLOR_FORMAT_RGB_444);
dptx_hal_set_color_depth(mtk_dp, DP_COLOR_DEPTH_8BIT);
mtk_dp_write_byte(mtk_dp, REG_3368_DP_ENCODER1_P0 + 1,
BIT(4), MASKBIT(5, 4));
/* DPtx encoder reset all sw. */
mtk_dp_write_byte(mtk_dp, REG_3004_DP_ENCODER0_P0 + 1, BIT(1), BIT(1));
mdelay(1);
/* DPtx encoder reset all sw. */
mtk_dp_write_byte(mtk_dp, REG_3004_DP_ENCODER0_P0 + 1, 0, BIT(1));
}
void dptx_hal_digital_swreset(struct mtk_dp *mtk_dp)
{
mtk_dp_write_byte(mtk_dp, REG_340C_DP_TRANS_P0 + 1, BIT(5), BIT(5));
mdelay(1);
mtk_dp_write_byte(mtk_dp, REG_340C_DP_TRANS_P0 + 1, 0, BIT(5));
}
void dptx_hal_phyd_reset(struct mtk_dp *mtk_dp)
{
mtk_dp_write_byte(mtk_dp, 0x1038, 0, BIT(0));
mdelay(1);
mtk_dp_write_byte(mtk_dp, 0x1038, BIT(0), BIT(0));
}
void dptx_hal_set_txlane(struct mtk_dp *mtk_dp, int value)
{
if (value == 0)
mtk_dp_write_byte(mtk_dp, REG_35F0_DP_TRANS_P0,
0, BIT(3) | BIT(2));
else
mtk_dp_write_byte(mtk_dp, REG_35F0_DP_TRANS_P0,
BIT(3), BIT(3) | BIT(2));
if ((value << 2) <= UINT8_MAX) {
mtk_dp_write_byte(mtk_dp, REG_3000_DP_ENCODER0_P0,
value, BIT(1) | BIT(0));
mtk_dp_write_byte(mtk_dp, REG_34A4_DP_TRANS_P0,
value << 2, BIT(3) | BIT(2));
} else {
printk(BIOS_ERR, "ERROR: [%s]value << 2 > 0xff\n", __func__);
}
}
void dptx_hal_set_txrate(struct mtk_dp *mtk_dp, int value)
{
/* Power off TPLL and lane */
mtk_dp_write(mtk_dp, 0x2000, 0x00000001);
/* Set gear : 0x0 : RBR, 0x1 : HBR, 0x2 : HBR2, 0x3 : HBR3 */
switch (value) {
case DP_LINKRATE_RBR:
mtk_dp_write(mtk_dp, 0x103C, 0x0);
break;
case DP_LINKRATE_HBR:
mtk_dp_write(mtk_dp, 0x103C, 0x1);
break;
case DP_LINKRATE_HBR2:
mtk_dp_write(mtk_dp, 0x103C, 0x2);
break;
case DP_LINKRATE_HBR3:
mtk_dp_write(mtk_dp, 0x103C, 0x3);
break;
default:
printk(BIOS_ERR, "ERROR: Link rate not support(%d)\n", value);
break;
}
/* Power on BandGap, TPLL and Lane */
mtk_dp_write(mtk_dp, 0x2000, 0x3);
}
void dptx_hal_set_txtrainingpattern(struct mtk_dp *mtk_dp, int value)
{
/* if Set TPS1. */
if (value == BIT(4))
dptx_hal_phy_setidlepattern(mtk_dp, false);
mtk_dp_write_byte(mtk_dp, REG_3400_DP_TRANS_P0 + 1,
value, MASKBIT(7, 4));
}
void dptx_hal_phy_setidlepattern(struct mtk_dp *mtk_dp, bool enable)
{
mtk_dp_write_byte(mtk_dp, REG_3580_DP_TRANS_P0 + 1,
enable ? 0xf : 0x0, 0xf);
}
void dptx_hal_set_ef_mode(struct mtk_dp *mtk_dp, bool enable)
{
/*
* [4]: REG_enhanced_frame_mode
* [1 : 0]: REG_lane_num
*/
if (enable)
mtk_dp_write_byte(mtk_dp, REG_3000_DP_ENCODER0_P0,
BIT(4), BIT(4));
else
mtk_dp_write_byte(mtk_dp, REG_3000_DP_ENCODER0_P0,
0, BIT(4));
}
void dptx_hal_setscramble(struct mtk_dp *mtk_dp, bool enable)
{
/* [0]: dp tx transmitter scramble enable. */
if (enable)
mtk_dp_write_byte(mtk_dp, REG_3404_DP_TRANS_P0,
BIT(0), BIT(0));
else
mtk_dp_write_byte(mtk_dp, REG_3404_DP_TRANS_P0,
0, BIT(0));
}
void dptx_hal_videomute(struct mtk_dp *mtk_dp, bool enable)
{
if (enable) {
mtk_dp_write_byte(mtk_dp, REG_3000_DP_ENCODER0_P0,
BIT(3) | BIT(2), BIT(3) | BIT(2));
mtk_dp_write_byte(mtk_dp, DP_TX_SECURE_REG11,
BIT(3) | BIT(4), BIT(3) | BIT(4));
} else {
mtk_dp_write_byte(mtk_dp, REG_3000_DP_ENCODER0_P0,
BIT(3), BIT(3) | BIT(2));
mtk_dp_write_byte(mtk_dp, DP_TX_SECURE_REG11,
BIT(4), BIT(3) | BIT(4));
}
printk(BIOS_DEBUG, "mute = %#x\n", read32(mtk_dp->regs + 0x402c));
}
void dptx_hal_analog_power_en(struct mtk_dp *mtk_dp, bool enable)
{
if (enable) {
mtk_dp_write_byte(mtk_dp, DP_TX_TOP_RESET_AND_PROBE,
0, BIT(4));
mdelay(1);
mtk_dp_write_byte(mtk_dp, DP_TX_TOP_RESET_AND_PROBE,
BIT(4), BIT(4));
} else {
DP_WRITE2BYTE(mtk_dp, TOP_OFFSET, 0x0);
mdelay(1);
DP_WRITE2BYTE(mtk_dp, 0x0034, 0x4aa);
DP_WRITE2BYTE(mtk_dp, 0x1040, 0x0);
DP_WRITE2BYTE(mtk_dp, 0x0038, 0x555);
}
}

View File

@@ -0,0 +1,258 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SOC_MEDIATEK_MT8195_DP_INTF_H
#define SOC_MEDIATEK_MT8195_DP_INTF_H
#include <edid.h>
#define DPINTF_EN 0x00
#define EN BIT(0)
#define DPINTF_RET 0x04
#define RST BIT(0)
#define RST_SEL BIT(16)
#define DPINTF_INTEN 0x08
#define INT_VSYNC_EN BIT(0)
#define INT_VDE_EN BIT(1)
#define INT_UNDERFLOW_EN BIT(2)
#define INT_TARGET_LINE_EN BIT(3)
#define DPINTF_INTSTA 0x0C
#define INT_VSYNC_STA BIT(0)
#define INT_VDE_STA BIT(1)
#define INT_UNDERFLOW_STA BIT(2)
#define INT_TARGET_LINE_STA BIT(3)
#define DPINTF_CON 0x10
#define BG_ENABLE BIT(0)
#define INTL_EN BIT(2)
#define TDFP_EN BIT(3)
#define VS_LODD_EN BIT(16)
#define VS_LEVEN_EN BIT(17)
#define VS_RODD_EN BIT(18)
#define VS_REVEN BIT(19)
#define FAKE_DE_LODD BIT(20)
#define FAKE_DE_LEVEN BIT(21)
#define FAKE_DE_RODD BIT(22)
#define FAKE_DE_REVEN BIT(23)
#define YUV422_EN BIT(24)
#define CLPF_EN BIT(25)
#define MATRIX_EN BIT(26)
#define INTERNAL_CG_EN BIT(27)
#define LOWPOWER_EN BIT(28)
#define INPUT_2P_EN BIT(29)
#define EXT_VSYNC_EN BIT(30)
#define DPINTF_OUTPUT_SETTING 0x14
#define PIXEL_SWAP BIT(0)
#define CH_SWAP BIT(1)
#define CH_SWAP_MASK (0x7 << 1)
#define SWAP_RGB (0x00 << 1)
#define SWAP_GBR (0x01 << 1)
#define SWAP_BRG (0x02 << 1)
#define SWAP_RBG (0x03 << 1)
#define SWAP_GRB (0x04 << 1)
#define SWAP_BGR (0x05 << 1)
#define B_MASK BIT(4)
#define G_MASK BIT(5)
#define R_MASK BIT(6)
#define DE_MASK BIT(8)
#define HS_MASK BIT(9)
#define VS_MASK BIT(10)
#define HSYNC_POL BIT(13)
#define VSYNC_POL BIT(14)
#define OUT_BIT BIT(16)
#define OUT_BIT_MASK (0x3 << 18)
#define OUT_BIT_8 (0x00 << 18)
#define OUT_BIT_10 (0x01 << 18)
#define OUT_BIT_12 (0x02 << 18)
#define OUT_BIT_16 (0x03 << 18)
#define DPINTF_SIZE 0x18
#define HSIZE 0
#define HSIZE_MASK (0xffff << 0)
#define VSIZE 16
#define VSIZE_MASK (0xffff << 16)
#define DPINTF_TGEN_HWIDTH 0x20
#define HPW 0
#define HPW_MASK (0xffff << 0)
#define DPINTF_TGEN_HPORCH 0x24
#define HBP 0
#define HBP_MASK (0xffff << 0)
#define HFP 16
#define HFP_MASK (0xffff << 16)
#define DPINTF_TGEN_VWIDTH 0x28
#define VSYNC_WIDTH_SHIFT 0
#define VSYNC_WIDTH_MASK (0xffff << 0)
#define VSYNC_HALF_LINE_SHIFT 16
#define VSYNC_HALF_LINE_MASK BIT(16)
#define DPINTF_TGEN_VPORCH 0x2C
#define VSYNC_BACK_PORCH_SHIFT 0
#define VSYNC_BACK_PORCH_MASK (0xffff << 0)
#define VSYNC_FRONT_PORCH_SHIFT 16
#define VSYNC_FRONT_PORCH_MASK (0xffff << 16)
#define DPINTF_BG_HCNTL 0x30
#define BG_RIGHT (0xffff << 0)
#define BG_LEFT (0xffff << 16)
#define DPINTF_BG_VCNTL 0x34
#define BG_BOT (0xffff << 0)
#define BG_TOP (0xffff << 16)
#define DPINTF_BG_COLOR 0x38
#define BG_B (0x3ff << 0)
#define BG_G (0x3ff << 10)
#define BG_R (0x3ff << 20)
#define DPINTF_FIFO_CTL 0x3C
#define FIFO_VALID_SET (0x1F << 0)
#define FIFO_RST_SEL BIT(8)
#define FIFO_RD_MASK BIT(12)
#define DPINTF_STATUS 0x40
#define VCOUNTER (0x3ffff << 0)
#define DPINTF_BUSY BIT(24)
#define FIELD BIT(28)
#define TDLR BIT(29)
#define DPINTF_TGEN_VWIDTH_LEVEN 0x68
#define DPINTF_TGEN_VPORCH_LEVEN 0x6C
#define DPINTF_TGEN_VWIDTH_RODD 0x70
#define DPINTF_TGEN_VPORCH_RODD 0x74
#define DPINTF_TGEN_VWIDTH_REVEN 0x78
#define DPINTF_TGEN_VPORCH_REVEN 0x7C
#define DPINTF_CLPF_SETTING 0x94
#define CLPF_TYPE (0x3 << 0)
#define ROUND_EN BIT(4)
#define DPINTF_Y_LIMIT 0x98
#define Y_LIMINT_BOT 0
#define Y_LIMINT_BOT_MASK (0xFFF << 0)
#define Y_LIMINT_TOP 16
#define Y_LIMINT_TOP_MASK (0xFFF << 16)
#define DPINTF_C_LIMIT 0x9C
#define C_LIMIT_BOT 0
#define C_LIMIT_BOT_MASK (0xFFF << 0)
#define C_LIMIT_TOP 16
#define C_LIMIT_TOP_MASK (0xFFF << 16)
#define DPINTF_YUV422_SETTING 0xA0
#define UV_SWAP BIT(0)
#define CR_DELSEL BIT(4)
#define CB_DELSEL BIT(5)
#define Y_DELSEL BIT(6)
#define DE_DELSEL BIT(7)
#define DPINTF_MATRIX_SET 0xB4
#define INT_MATRIX_SEL_MASK 0x1f
#define RGB_TO_JPEG 0x00
#define RGB_TO_FULL709 0x01
#define RGB_TO_BT601 0x02
#define RGB_TO_BT709 0x03
#define JPEG_TO_RGB 0x04
#define FULL709_TO_RGB 0x05
#define BT601_TO_RGB 0x06
#define BT709_TO_RGB 0x07
#define JPEG_TO_BT601 0x08
#define JPEG_TO_BT709 0x09
#define BT601_TO_JPEG 0xA
#define BT709_TO_JPEG 0xB
#define BT709_TO_BT601 0xC
#define BT601_TO_BT709 0xD
#define JPEG_TO_CERGB 0x14
#define FULL709_TO_CERGB 0x15
#define BT601_TO_CERGB 0x16
#define BT709_TO_CERGB 0x17
#define RGB_TO_CERGB 0x1C
#define MATRIX_BIT_MASK (0x3 << 8)
#define EXT_MATRIX_EN BIT(12)
enum mtk_dpintf_out_bit_num {
MTK_DPINTF_OUT_BIT_NUM_8BITS,
MTK_DPINTF_OUT_BIT_NUM_10BITS,
MTK_DPINTF_OUT_BIT_NUM_12BITS,
MTK_DPINTF_OUT_BIT_NUM_16BITS,
};
enum mtk_dpintf_out_yc_map {
MTK_DPINTF_OUT_YC_MAP_RGB,
MTK_DPINTF_OUT_YC_MAP_CYCY,
MTK_DPINTF_OUT_YC_MAP_YCYC,
MTK_DPINTF_OUT_YC_MAP_CY,
MTK_DPINTF_OUT_YC_MAP_YC,
};
enum mtk_dpintf_out_channel_swap {
MTK_DPINTF_OUT_CHANNEL_SWAP_RGB,
MTK_DPINTF_OUT_CHANNEL_SWAP_GBR,
MTK_DPINTF_OUT_CHANNEL_SWAP_BRG,
MTK_DPINTF_OUT_CHANNEL_SWAP_RBG,
MTK_DPINTF_OUT_CHANNEL_SWAP_GRB,
MTK_DPINTF_OUT_CHANNEL_SWAP_BGR,
};
enum mtk_dpintf_out_color_format {
MTK_DPINTF_COLOR_FORMAT_RGB,
MTK_DPINTF_COLOR_FORMAT_RGB_FULL,
MTK_DPINTF_COLOR_FORMAT_YCBCR_444,
MTK_DPINTF_COLOR_FORMAT_YCBCR_422,
MTK_DPINTF_COLOR_FORMAT_XV_YCC,
MTK_DPINTF_COLOR_FORMAT_YCBCR_444_FULL,
MTK_DPINTF_COLOR_FORMAT_YCBCR_422_FULL,
};
enum TVDPLL_CLK {
TVDPLL_PLL = 0,
TVDPLL_D2 = 1,
TVDPLL_D4 = 3,
TVDPLL_D8 = 5,
TVDPLL_D16 = 7,
};
struct mtk_dpintf {
void *regs;
enum mtk_dpintf_out_color_format color_format;
enum mtk_dpintf_out_yc_map yc_map;
enum mtk_dpintf_out_bit_num bit_num;
enum mtk_dpintf_out_channel_swap channel_swap;
};
enum mtk_dpintf_polarity {
MTK_DPINTF_POLARITY_RISING,
MTK_DPINTF_POLARITY_FALLING,
};
struct mtk_dpintf_polarities {
enum mtk_dpintf_polarity de_pol;
enum mtk_dpintf_polarity ck_pol;
enum mtk_dpintf_polarity hsync_pol;
enum mtk_dpintf_polarity vsync_pol;
};
struct mtk_dpintf_sync_param {
u32 sync_width;
u32 front_porch;
u32 back_porch;
bool shift_half_line;
};
struct mtk_dpintf_yc_limit {
u16 y_top;
u16 y_bottom;
u16 c_top;
u16 c_bottom;
};
void dp_intf_config(const struct edid *edid);
#endif /* SOC_MEDIATEK_MT8195_DP_INTF_H */

View File

@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SOC_MEDIATEK_MT8195_DPTX_H
#define SOC_MEDIATEK_MT8195_DPTX_H
#define DPTX_TBC_BUF_READSTARTADRTHRD 0x08
#define ENABLE_DPTX_EF_MODE 0x1
#define DPTX_AUX_SET_ENAHNCED_FRAME 0x80
union misc_t {
struct {
u8 is_sync_clock : 1;
u8 color_format : 2;
u8 spec_def1 : 2;
u8 color_depth : 3;
u8 interlaced : 1;
u8 stereo_attr : 2;
u8 reserved : 3;
u8 is_vsc_sdp : 1;
u8 spec_def2 : 1;
} dp_misc;
u8 cmisc[2];
};
struct dptx_training_info {
bool sink_extcap_en;
bool tps3;
bool tps4;
bool sink_ssc_en;
bool dp_mstcap;
bool dp_mstbranch;
bool down_stream_port_present;
bool cr_done;
bool eq_done;
u8 sys_max_linkrate;
u8 linkrate;
u8 linklane_count;
u8 dpcd_rev;
u8 sink_count_num;
};
struct dptx_info {
uint8_t depth;
uint8_t format;
uint8_t resolution;
};
struct mtk_dp {
int id;
struct edid *edid;
u8 rx_cap[16];
struct dptx_info info;
int state;
int state_pre;
struct dptx_training_info train_info;
int training_state;
u8 irq_status;
u32 min_clock;
u32 max_clock;
u32 max_hdisplay;
u32 max_vdisplay;
void *regs;
int disp_status;
bool power_on;
bool audio_enable;
bool video_enable;
bool dp_ready;
bool has_dsc;
bool has_fec;
bool dsc_enable;
bool enabled;
bool powered;
};
int mtk_edp_init(struct edid *edid);
#endif /* SOC_MEDIATEK_MT8195_DPTX_H */

View File

@@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SOC_MEDIATEK_MT8195_DPTX_HAL_H
#define SOC_MEDIATEK_MT8195_DPTX_HAL_H
#define AUX_CMD_I2C_R_MOT0 0x1
#define AUX_CMD_I2C_R 0x5
#define AUX_CMD_NATIVE_R 0x9
#define AUX_WAITREPLY_LPNUM 20000
#define DP_AUX_I2C_WRITE 0x0
#define DP_AUX_I2C_READ 0x1
#define DP_AUX_I2C_WRITE_STATUS_UPDATE 0x2
#define DP_AUX_I2C_MOT 0x4
#define DP_AUX_NATIVE_WRITE 0x8
#define DP_AUX_NATIVE_READ 0x9
#define MASKBIT(a, b) ((a > b) ? (BIT(a + 1) - BIT(b)) : (BIT(b + 1) - BIT(a)))
#define DP_WRITE1BYTE(mtk_dp, reg, u8_val) \
mtk_dp_write_byte(mtk_dp, reg, u8_val, 0xff)
#define DP_WRITE2BYTE(mtk_dp, reg, u16_val) \
mtk_dp_mask(mtk_dp, reg, u16_val, 0xffff)
enum {
DPTX_LANE0 = 0x0,
DPTX_LANE1 = 0x1,
DPTX_LANE2 = 0x2,
DPTX_LANE3 = 0x3,
DPTX_LANE_MAX,
};
enum {
DP_LINKRATE_RBR = 0x6,
DP_LINKRATE_HBR = 0xa,
DP_LINKRATE_HBR2 = 0x14,
DP_LINKRATE_HBR25 = 0x19,
DP_LINKRATE_HBR3 = 0x1e,
};
enum {
DP_COLOR_FORMAT_RGB_444 = 0,
DP_COLOR_FORMAT_YUV_422 = 1,
DP_COLOR_FORMAT_YUV_444 = 2,
DP_COLOR_FORMAT_YUV_420 = 3,
DP_COLOR_FORMAT_YONLY = 4,
DP_COLOR_FORMAT_RAW = 5,
DP_COLOR_FORMAT_RESERVED = 6,
DP_COLOR_FORMAT_DEFAULT = DP_COLOR_FORMAT_RGB_444,
DP_COLOR_FORMAT_UNKNOWN = 15,
};
enum {
DP_COLOR_DEPTH_6BIT = 0,
DP_COLOR_DEPTH_8BIT = 1,
DP_COLOR_DEPTH_10BIT = 2,
DP_COLOR_DEPTH_12BIT = 3,
DP_COLOR_DEPTH_16BIT = 4,
DP_COLOR_DEPTH_UNKNOWN = 5,
};
bool dptx_hal_hpd_high(struct mtk_dp *mtk_dp);
bool dptx_hal_auxread_bytes(struct mtk_dp *mtk_dp, u8 cmd,
u32 dpcd_addr, size_t length, u8 *rx_buf);
bool dptx_hal_auxwrite_bytes(struct mtk_dp *mtk_dp, u8 cmd,
u32 dpcd_addr, size_t length, u8 *data);
bool dptx_hal_setswing_preemphasis(struct mtk_dp *mtk_dp, int lane_num,
int swing_value, int preemphasis);
u8 dptx_hal_get_colorbpp(struct mtk_dp *mtk_dp);
u32 mtk_dp_read(struct mtk_dp *mtk_dp, u32 offset);
void mtk_dp_write_byte(struct mtk_dp *mtk_dp, u32 addr, u8 val, u32 mask);
void mtk_dp_mask(struct mtk_dp *mtk_dp, u32 offset, u32 val, u32 mask);
void mtk_dp_write(struct mtk_dp *mtk_dp, u32 offset, u32 val);
void dptx_hal_verify_clock(struct mtk_dp *mtk_dp);
void dptx_hal_reset_swing_preemphasis(struct mtk_dp *mtk_dp);
void dptx_hal_digital_swreset(struct mtk_dp *mtk_dp);
void dptx_hal_ssc_en(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_hpd_int_en(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_hpd_detect_setting(struct mtk_dp *mtk_dp);
void dptx_hal_phy_setting(struct mtk_dp *mtk_dp);
void dptx_hal_aux_setting(struct mtk_dp *mtk_dp);
void dptx_hal_digital_setting(struct mtk_dp *mtk_dp);
void dptx_hal_set_txlane(struct mtk_dp *mtk_dp, int value);
void dptx_hal_phy_setidlepattern(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_phyd_reset(struct mtk_dp *mtk_dp);
void dptx_hal_set_txtrainingpattern(struct mtk_dp *mtk_dp, int value);
void dptx_hal_set_ef_mode(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_setscramble(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_init_setting(struct mtk_dp *mtk_dp);
void dptx_hal_videomute(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_bypassmsa_en(struct mtk_dp *mtk_dp, bool enable);
void dptx_hal_overwrite_mn(struct mtk_dp *mtk_dp, bool enable,
u32 video_m, u32 video_n);
void dptx_hal_settu_sramrd_start(struct mtk_dp *mtk_dp, u16 value);
void dptx_hal_setsdp_downcnt_init_inhblanking(struct mtk_dp *mtk_dp, u16 value);
void dptx_hal_setsdp_downcnt_init(struct mtk_dp *mtk_dp, u16 value);
void dptx_hal_settu_setencoder(struct mtk_dp *mtk_dp);
void dptx_hal_set_msa(struct mtk_dp *mtk_dp);
void dptx_hal_setmisc(struct mtk_dp *mtk_dp, u8 cmisc[2]);
void dptx_hal_set_color_depth(struct mtk_dp *mtk_dp, u8 color_depth);
void dptx_hal_set_color_format(struct mtk_dp *mtk_dp, u8 color_format);
void dptx_hal_set_txrate(struct mtk_dp *mtk_dp, int value);
void dptx_hal_analog_power_en(struct mtk_dp *mtk_dp, bool enable);
#endif /* SOC_MEDIATEK_MT8195_DPTX_HAL_H */

File diff suppressed because it is too large Load Diff