summaryrefslogtreecommitdiff
path: root/src/soc/mediatek/mt8195/dp_intf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/mediatek/mt8195/dp_intf.c')
-rw-r--r--src/soc/mediatek/mt8195/dp_intf.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/soc/mediatek/mt8195/dp_intf.c b/src/soc/mediatek/mt8195/dp_intf.c
new file mode 100644
index 0000000000..668376739d
--- /dev/null
+++ b/src/soc/mediatek/mt8195/dp_intf.c
@@ -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);
+}