soc/mediatek/common: Add C-PHY support for MIPI DSI
Introduce C-PHY support by adding PANEL_FLAG_CPHY flag, updating data rate calculations, timing configurations, and register settings for C-PHY operation. To improve code reusability, the D-PHY and C-PHY specific implementations are moved to `mtk_mipi_dphy.c` and `mtk_mipi_cphy.c`, respectively. BUG=b:433422905,b:428854543 BRANCH=skywalker TEST=check log on padme mtk_display_init: 'TM TL121BVMS07' 1600x2560@60Hz Change-Id: I9e81551484e605e1d74b9983fe00b5d0eba69358 Signed-off-by: Bincai Liu <bincai.liu@mediatek.corp-partner.google.com> Signed-off-by: Vince Liu <vince-wl.liu@mediatek.corp-partner.google.com> (cherry picked from commit 22a499836eeb6904e114023da6222b29da10f62f) Reviewed-on: https://review.coreboot.org/c/coreboot/+/89567 Reviewed-by: Yidi Lin <yidilin@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
parent
c63e901b99
commit
44635f328c
9 changed files with 309 additions and 113 deletions
|
|
@ -54,6 +54,12 @@ config MEDIATEK_DRAM_SCRAMBLE
|
|||
This option enables DRAM data scramble, which can prevent DRAM data from
|
||||
being hacked.
|
||||
|
||||
config MEDIATEK_DSI_CPHY
|
||||
bool
|
||||
default n
|
||||
help
|
||||
The configuration to support DSI C-PHY.
|
||||
|
||||
config MEMORY_TEST
|
||||
bool
|
||||
default y
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ int mtk_display_init(void)
|
|||
const char *name;
|
||||
struct panel_description *panel = get_active_panel();
|
||||
uintptr_t fb_addr;
|
||||
u32 lanes;
|
||||
|
||||
if (!panel || panel->disp_path == DISP_PATH_NONE) {
|
||||
printk(BIOS_ERR, "%s: Failed to get the active panel\n", __func__);
|
||||
|
|
@ -146,7 +147,14 @@ int mtk_display_init(void)
|
|||
MIPI_DSI_MODE_LPM |
|
||||
MIPI_DSI_MODE_EOT_PACKET);
|
||||
|
||||
if (mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, &edid,
|
||||
if (mipi_data->flags & PANEL_FLAG_CPHY) {
|
||||
mipi_dsi_flags |= MIPI_DSI_MODE_CPHY;
|
||||
lanes = 3;
|
||||
} else {
|
||||
lanes = 4;
|
||||
}
|
||||
|
||||
if (mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, lanes, &edid,
|
||||
mipi_data ? mipi_data->init : NULL) < 0) {
|
||||
printk(BIOS_ERR, "%s: Failed in DSI init\n", __func__);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
#define MIN_HFP_BYTE 2
|
||||
#define MIN_HBP_BYTE 2
|
||||
|
||||
#define CPHY_SYMBOL_RATE 7
|
||||
#define CPHY_SYMBOL_RATE_DIVISOR 16
|
||||
|
||||
static unsigned int mtk_dsi_get_bits_per_pixel(u32 format)
|
||||
{
|
||||
switch (format) {
|
||||
|
|
@ -29,7 +32,7 @@ static unsigned int mtk_dsi_get_bits_per_pixel(u32 format)
|
|||
}
|
||||
|
||||
static u32 mtk_dsi_get_data_rate(u32 bits_per_pixel, u32 lanes,
|
||||
const struct edid *edid)
|
||||
const struct edid *edid, bool is_cphy)
|
||||
{
|
||||
/* data_rate = pixel_clock * bits_per_pixel * mipi_ratio / lanes
|
||||
* Note pixel_clock comes in kHz and returned data_rate is in bps.
|
||||
|
|
@ -37,11 +40,16 @@ static u32 mtk_dsi_get_data_rate(u32 bits_per_pixel, u32 lanes,
|
|||
* for older platforms which do not have complete implementation in HFP.
|
||||
* Newer platforms should just set that to 1.0 (100 / 100).
|
||||
*/
|
||||
u32 data_rate = DIV_ROUND_UP((u64)edid->mode.pixel_clock *
|
||||
bits_per_pixel * 1000 *
|
||||
MTK_DSI_MIPI_RATIO_NUMERATOR,
|
||||
(u64)lanes *
|
||||
MTK_DSI_MIPI_RATIO_DENOMINATOR);
|
||||
u32 data_rate;
|
||||
u64 dividend = (u64)edid->mode.pixel_clock * bits_per_pixel * 1000 *
|
||||
MTK_DSI_MIPI_RATIO_NUMERATOR;
|
||||
u64 divisor = (u64)lanes * MTK_DSI_MIPI_RATIO_DENOMINATOR;
|
||||
|
||||
if (is_cphy) {
|
||||
dividend *= CPHY_SYMBOL_RATE;
|
||||
divisor *= CPHY_SYMBOL_RATE_DIVISOR;
|
||||
}
|
||||
data_rate = DIV_ROUND_UP(dividend, divisor);
|
||||
printk(BIOS_INFO, "DSI data_rate: %u bps\n", data_rate);
|
||||
|
||||
if (data_rate < MTK_DSI_DATA_RATE_MIN_MHZ * MHz) {
|
||||
|
|
@ -63,13 +71,11 @@ __weak void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing)
|
|||
/* Do nothing. */
|
||||
}
|
||||
|
||||
static void mtk_dsi_phy_timing(u32 data_rate, struct mtk_phy_timing *timing)
|
||||
static void mtk_dsi_dphy_timing(u32 data_rate, struct mtk_phy_timing *timing)
|
||||
{
|
||||
u32 timcon0, timcon1, timcon2, timcon3;
|
||||
u32 data_rate_mhz = DIV_ROUND_UP(data_rate, MHz);
|
||||
|
||||
memset(timing, 0, sizeof(*timing));
|
||||
|
||||
timing->lpx = (60 * data_rate_mhz / (8 * 1000)) + 1;
|
||||
timing->da_hs_prepare = (80 * data_rate_mhz + 4 * 1000) / 8000;
|
||||
timing->da_hs_zero = (170 * data_rate_mhz + 10 * 1000) / 8000 + 1 -
|
||||
|
|
@ -163,46 +169,19 @@ static void mtk_dsi_rxtx_control(u32 mode_flags, u32 lanes)
|
|||
write32(&dsi0->dsi_txrx_ctrl, tmp_reg);
|
||||
}
|
||||
|
||||
static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
||||
const struct edid *edid,
|
||||
const struct mtk_phy_timing *phy_timing)
|
||||
static void mtk_dsi_dphy_vdo_timing(const u32 mode_flags,
|
||||
const u32 lanes,
|
||||
const struct edid *edid,
|
||||
const struct mtk_phy_timing *phy_timing,
|
||||
const u32 bytes_per_pixel,
|
||||
const u32 hbp,
|
||||
const u32 hfp,
|
||||
s32 *hbp_byte,
|
||||
s32 *hfp_byte,
|
||||
u32 *hsync_active_byte)
|
||||
{
|
||||
u32 hsync_active_byte;
|
||||
u32 hbp;
|
||||
u32 hfp;
|
||||
s32 hbp_byte;
|
||||
s32 hfp_byte;
|
||||
u32 vbp_byte;
|
||||
u32 vfp_byte;
|
||||
u32 bytes_per_pixel;
|
||||
u32 packet_fmt;
|
||||
u32 hactive;
|
||||
u32 data_phy_cycles;
|
||||
|
||||
bytes_per_pixel = DIV_ROUND_UP(mtk_dsi_get_bits_per_pixel(format), 8);
|
||||
vbp_byte = edid->mode.vbl - edid->mode.vso - edid->mode.vspw -
|
||||
edid->mode.vborder;
|
||||
vfp_byte = edid->mode.vso - edid->mode.vborder;
|
||||
|
||||
write32(&dsi0->dsi_vsa_nl, edid->mode.vspw);
|
||||
write32(&dsi0->dsi_vbp_nl, vbp_byte);
|
||||
write32(&dsi0->dsi_vfp_nl, vfp_byte);
|
||||
write32(&dsi0->dsi_vact_nl, edid->mode.va);
|
||||
|
||||
hsync_active_byte = edid->mode.hspw * bytes_per_pixel - 10;
|
||||
|
||||
hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw -
|
||||
edid->mode.hborder;
|
||||
hfp = edid->mode.hso - edid->mode.hborder;
|
||||
|
||||
if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
||||
hbp_byte = hbp * bytes_per_pixel - 10;
|
||||
else
|
||||
hbp_byte = (hbp + edid->mode.hspw) * bytes_per_pixel - 10;
|
||||
hfp_byte = hfp * bytes_per_pixel;
|
||||
|
||||
data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
|
||||
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 3;
|
||||
u32 data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
|
||||
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 3;
|
||||
|
||||
u32 delta = 10;
|
||||
|
||||
|
|
@ -217,20 +196,65 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
|||
d_phy = data_phy_cycles * lanes + delta;
|
||||
|
||||
if ((hfp + hbp) * bytes_per_pixel > d_phy) {
|
||||
hfp_byte -= d_phy * hfp / (hfp + hbp);
|
||||
hbp_byte -= d_phy * hbp / (hfp + hbp);
|
||||
*hfp_byte -= d_phy * hfp / (hfp + hbp);
|
||||
*hbp_byte -= d_phy * hbp / (hfp + hbp);
|
||||
} else {
|
||||
printk(BIOS_ERR, "HFP %u plus HBP %u is not greater than d_phy %u, "
|
||||
"the panel may not work properly.\n", hfp * bytes_per_pixel,
|
||||
hbp * bytes_per_pixel, d_phy);
|
||||
"the panel may not work properly.\n", hfp * bytes_per_pixel,
|
||||
hbp * bytes_per_pixel, d_phy);
|
||||
}
|
||||
|
||||
*hsync_active_byte = edid->mode.hspw * bytes_per_pixel - 10;
|
||||
if (mode_flags & MIPI_DSI_MODE_LINE_END) {
|
||||
hsync_active_byte = DIV_ROUND_UP(hsync_active_byte, lanes) * lanes - 2;
|
||||
hbp_byte = DIV_ROUND_UP(hbp_byte, lanes) * lanes - 2;
|
||||
hfp_byte = DIV_ROUND_UP(hfp_byte, lanes) * lanes - 2;
|
||||
hbp_byte -= (edid->mode.ha * bytes_per_pixel + 2) % lanes;
|
||||
*hsync_active_byte = DIV_ROUND_UP(*hsync_active_byte, lanes) * lanes - 2;
|
||||
*hbp_byte = DIV_ROUND_UP(*hbp_byte, lanes) * lanes - 2;
|
||||
*hfp_byte = DIV_ROUND_UP(*hfp_byte, lanes) * lanes - 2;
|
||||
*hbp_byte -= (edid->mode.ha * bytes_per_pixel + 2) % lanes;
|
||||
}
|
||||
}
|
||||
|
||||
static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
||||
const struct edid *edid,
|
||||
const struct mtk_phy_timing *phy_timing)
|
||||
{
|
||||
u32 hsync_active_byte;
|
||||
u32 hbp;
|
||||
u32 hfp;
|
||||
s32 hbp_byte;
|
||||
s32 hfp_byte;
|
||||
u32 vbp_byte;
|
||||
u32 vfp_byte;
|
||||
u32 bytes_per_pixel;
|
||||
u32 packet_fmt;
|
||||
u32 hactive;
|
||||
bool is_cphy = !!(mode_flags & MIPI_DSI_MODE_CPHY);
|
||||
|
||||
bytes_per_pixel = DIV_ROUND_UP(mtk_dsi_get_bits_per_pixel(format), 8);
|
||||
vbp_byte = edid->mode.vbl - edid->mode.vso - edid->mode.vspw -
|
||||
edid->mode.vborder;
|
||||
vfp_byte = edid->mode.vso - edid->mode.vborder;
|
||||
|
||||
write32(&dsi0->dsi_vsa_nl, edid->mode.vspw);
|
||||
write32(&dsi0->dsi_vbp_nl, vbp_byte);
|
||||
write32(&dsi0->dsi_vfp_nl, vfp_byte);
|
||||
write32(&dsi0->dsi_vact_nl, edid->mode.va);
|
||||
|
||||
hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw -
|
||||
edid->mode.hborder;
|
||||
hfp = edid->mode.hso - edid->mode.hborder;
|
||||
|
||||
if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
|
||||
hbp_byte = hbp * bytes_per_pixel - 10;
|
||||
else
|
||||
hbp_byte = (hbp + edid->mode.hspw) * bytes_per_pixel - 10;
|
||||
hfp_byte = hfp * bytes_per_pixel;
|
||||
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_vdo_timing(lanes, edid, phy_timing, bytes_per_pixel, hbp, hfp,
|
||||
&hbp_byte, &hfp_byte, &hsync_active_byte);
|
||||
else
|
||||
mtk_dsi_dphy_vdo_timing(mode_flags, lanes, edid, phy_timing, bytes_per_pixel,
|
||||
hbp, hfp, &hbp_byte, &hfp_byte, &hsync_active_byte);
|
||||
|
||||
if (hfp_byte + hbp_byte < MIN_HFP_BYTE + MIN_HBP_BYTE) {
|
||||
printk(BIOS_ERR, "Calculated hfp_byte %d and hbp_byte %d are too small, "
|
||||
|
|
@ -281,6 +305,8 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
|
|||
write32(&dsi0->dsi_size_con,
|
||||
edid->mode.va << DSI_SIZE_CON_HEIGHT_SHIFT |
|
||||
hactive << DSI_SIZE_CON_WIDTH_SHIFT);
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_enable_cmdq_6byte();
|
||||
}
|
||||
|
||||
static void mtk_dsi_start(void)
|
||||
|
|
@ -339,6 +365,7 @@ static enum cb_err mtk_dsi_cmdq(enum mipi_dsi_transaction type, const u8 *data,
|
|||
}
|
||||
write32(&dsi0->dsi_cmdq_size, 1 + DIV_ROUND_UP(len, 4));
|
||||
}
|
||||
setbits32(&dsi0->dsi_cmdq_size, CMDQ_SIZE_SEL);
|
||||
|
||||
mtk_dsi_start();
|
||||
|
||||
|
|
@ -351,7 +378,7 @@ static enum cb_err mtk_dsi_cmdq(enum mipi_dsi_transaction type, const u8 *data,
|
|||
return CB_SUCCESS;
|
||||
}
|
||||
|
||||
static void mtk_dsi_reset_dphy(void)
|
||||
static void mtk_dsi_reset_phy(void)
|
||||
{
|
||||
setbits32(&dsi0->dsi_con_ctrl, DPHY_RESET);
|
||||
clrbits32(&dsi0->dsi_con_ctrl, DPHY_RESET);
|
||||
|
|
@ -362,18 +389,28 @@ int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid,
|
|||
{
|
||||
u32 data_rate;
|
||||
u32 bits_per_pixel = mtk_dsi_get_bits_per_pixel(format);
|
||||
bool is_cphy = !!(mode_flags & MIPI_DSI_MODE_CPHY);
|
||||
|
||||
data_rate = mtk_dsi_get_data_rate(bits_per_pixel, lanes, edid);
|
||||
if (!CONFIG(MEDIATEK_DSI_CPHY) && is_cphy) {
|
||||
printk(BIOS_ERR, "%s: Board is built without C-PHY interface support. "
|
||||
"Please check Kconfig MEDIATEK_DSI_CPHY.\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data_rate = mtk_dsi_get_data_rate(bits_per_pixel, lanes, edid, is_cphy);
|
||||
if (!data_rate)
|
||||
return -1;
|
||||
|
||||
mtk_dsi_configure_mipi_tx(data_rate, lanes);
|
||||
mtk_dsi_configure_mipi_tx(data_rate, lanes, is_cphy);
|
||||
mtk_dsi_reset();
|
||||
struct mtk_phy_timing phy_timing;
|
||||
mtk_dsi_phy_timing(data_rate, &phy_timing);
|
||||
struct mtk_phy_timing phy_timing = {};
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_timing(data_rate, &phy_timing);
|
||||
else
|
||||
mtk_dsi_dphy_timing(data_rate, &phy_timing);
|
||||
mtk_dsi_rxtx_control(mode_flags, lanes);
|
||||
mdelay(1);
|
||||
mtk_dsi_reset_dphy();
|
||||
mtk_dsi_reset_phy();
|
||||
mtk_dsi_clk_hs_mode_disable();
|
||||
mtk_dsi_config_vdo_timing(mode_flags, format, lanes, edid, &phy_timing);
|
||||
mtk_dsi_clk_hs_mode_enable();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,69 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
||||
|
||||
#include <assert.h>
|
||||
#include <delay.h>
|
||||
#include <device/mmio.h>
|
||||
#include <soc/dsi.h>
|
||||
#include <soc/pll.h>
|
||||
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes, bool is_cphy)
|
||||
{
|
||||
unsigned int txdiv0;
|
||||
u64 pcw;
|
||||
|
||||
if (data_rate >= 2000 * MHz) {
|
||||
txdiv0 = 0;
|
||||
} else if (data_rate >= 1000 * MHz) {
|
||||
txdiv0 = 1;
|
||||
} else if (data_rate >= 500 * MHz) {
|
||||
txdiv0 = 2;
|
||||
} else if (data_rate > 250 * MHz) {
|
||||
/* (data_rate == 250MHz) is a special case that should go to the
|
||||
else-block below (txdiv0 = 4) */
|
||||
txdiv0 = 3;
|
||||
} else {
|
||||
/* MIN = 125 */
|
||||
assert(data_rate >= MTK_DSI_DATA_RATE_MIN_MHZ * MHz);
|
||||
txdiv0 = 4;
|
||||
}
|
||||
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_lane_sel_setting();
|
||||
|
||||
clrbits32(&mipi_tx->pll_con4, BIT(11) | BIT(10));
|
||||
setbits32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_PWR_ON);
|
||||
udelay(30);
|
||||
clrbits32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_ISO_EN);
|
||||
|
||||
pcw = (u64)data_rate * (1 << txdiv0);
|
||||
pcw <<= 24;
|
||||
pcw /= CLK26M_HZ;
|
||||
|
||||
write32(&mipi_tx->pll_con0, pcw);
|
||||
clrsetbits32(&mipi_tx->pll_con1, RG_DSI_PLL_POSDIV, txdiv0 << 8);
|
||||
udelay(30);
|
||||
setbits32(&mipi_tx->pll_con1, RG_DSI_PLL_EN);
|
||||
|
||||
/* BG_LPF_EN / BG_CORE_EN */
|
||||
write32(&mipi_tx->lane_con, 0x3FFF0180);
|
||||
udelay(40);
|
||||
write32(&mipi_tx->lane_con, 0x3FFF00C0);
|
||||
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_enable();
|
||||
|
||||
/* Switch OFF each Lane */
|
||||
clrbits32(&mipi_tx->d0_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d1_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d2_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d3_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->ck_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
|
||||
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
|
||||
mtk_dsi_cphy_disable_ck_mode();
|
||||
else
|
||||
mtk_dsi_dphy_disable_ck_mode();
|
||||
}
|
||||
|
||||
void mtk_dsi_reset(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ enum {
|
|||
MIPI_DSI_MODE_LPM = BIT(11),
|
||||
/* dsi per line's data end same time on all lanes */
|
||||
MIPI_DSI_MODE_LINE_END = BIT(12),
|
||||
/* mipi is in CPHY mode */
|
||||
MIPI_DSI_MODE_CPHY = BIT(13),
|
||||
};
|
||||
|
||||
static struct dsi_regs *const dsi0 = (void *)DSI0_BASE;
|
||||
|
|
@ -57,6 +59,11 @@ enum {
|
|||
DSI_BUSY = BIT(31),
|
||||
};
|
||||
|
||||
/* DSI_CMD_TYPE1_HS */
|
||||
enum {
|
||||
CMD_CPHY_6BYTE_EN = BIT(18),
|
||||
};
|
||||
|
||||
/* DSI_CON_CTRL */
|
||||
enum {
|
||||
DSI_RESET = BIT(0),
|
||||
|
|
@ -103,6 +110,7 @@ enum {
|
|||
/* DSI_CMDQ_SIZE */
|
||||
enum {
|
||||
CMDQ_SIZE = 0x3f,
|
||||
CMDQ_SIZE_SEL = BIT(15),
|
||||
};
|
||||
|
||||
/* DSI_PHY_LCCON */
|
||||
|
|
@ -192,13 +200,25 @@ struct mtk_phy_timing {
|
|||
|
||||
/* Functions that each SOC should provide. */
|
||||
void mtk_dsi_reset(void);
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes);
|
||||
|
||||
/* Functions as weak no-ops that can be overridden. */
|
||||
void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing);
|
||||
|
||||
/* Public API provided in common/dsi_common.c */
|
||||
int mtk_dsi_bpp_from_format(u32 format);
|
||||
/*
|
||||
* Public API provided in common/dsi_common.c, common/dsi_v1.c, and
|
||||
* common/mtk_mipi_{c/d}phy.c
|
||||
*/
|
||||
void mtk_dsi_cphy_enable(void);
|
||||
void mtk_dsi_cphy_enable_cmdq_6byte(void);
|
||||
void mtk_dsi_cphy_lane_sel_setting(void);
|
||||
void mtk_dsi_cphy_timing(u32 data_rate, struct mtk_phy_timing *timing);
|
||||
void mtk_dsi_cphy_vdo_timing(const u32 lanes, const struct edid *edid,
|
||||
const struct mtk_phy_timing *phy_timing,
|
||||
const u32 bytes_per_pixel, const u32 hbp, const u32 hfp,
|
||||
s32 *hbp_byte, s32 *hfp_byte, u32 *hsync_active_byte);
|
||||
void mtk_dsi_cphy_disable_ck_mode(void);
|
||||
void mtk_dsi_dphy_disable_ck_mode(void);
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes, bool is_cphy);
|
||||
int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid,
|
||||
const u8 *init_commands);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,24 +31,29 @@ struct dsi_regs {
|
|||
u32 dsi_bllp_wc;
|
||||
u32 dsi_cmdq_size;
|
||||
u32 dsi_hstx_cklp_wc;
|
||||
u8 reserved2[156];
|
||||
u8 reserved2[4];
|
||||
u32 dsi_cmd_type1_hs;
|
||||
u8 reserved3[148];
|
||||
u32 dsi_phy_lccon;
|
||||
u32 dsi_phy_ld0con;
|
||||
u8 reserved3[4];
|
||||
u8 reserved4[4];
|
||||
u32 dsi_phy_timecon0;
|
||||
u32 dsi_phy_timecon1;
|
||||
u32 dsi_phy_timecon2;
|
||||
u32 dsi_phy_timecon3;
|
||||
u8 reserved4[16];
|
||||
u32 dsi_cphy_con0;
|
||||
u8 reserved5[12];
|
||||
u32 dsi_vm_cmd_con;
|
||||
u8 reserved5[92];
|
||||
u8 reserved6[92];
|
||||
u32 dsi_force_commit; /* Available since MT8183 */
|
||||
u8 reserved6[2924];
|
||||
u8 reserved7[2924];
|
||||
u32 dsi_cmdq[128];
|
||||
};
|
||||
|
||||
check_member(dsi_regs, dsi_cmd_type1_hs, 0x6c);
|
||||
check_member(dsi_regs, dsi_phy_lccon, 0x104);
|
||||
check_member(dsi_regs, dsi_phy_timecon3, 0x11c);
|
||||
check_member(dsi_regs, dsi_cphy_con0, 0x120);
|
||||
check_member(dsi_regs, dsi_vm_cmd_con, 0x130);
|
||||
check_member(dsi_regs, dsi_force_commit, 0x190);
|
||||
check_member(dsi_regs, dsi_cmdq, 0xd00);
|
||||
|
|
|
|||
112
src/soc/mediatek/common/mtk_mipi_cphy.c
Normal file
112
src/soc/mediatek/common/mtk_mipi_cphy.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
||||
|
||||
#include <assert.h>
|
||||
#include <device/mmio.h>
|
||||
#include <delay.h>
|
||||
#include <soc/dsi.h>
|
||||
#include <soc/pll.h>
|
||||
#include <types.h>
|
||||
|
||||
#define DE_EMPHASIS_EN BIT(9)
|
||||
#define DSI_CPHY_EN BIT(3)
|
||||
#define DSI_HSTX_LDO_REF_SEL GENMASK(9, 6)
|
||||
#define HFP_HS_EN BIT(31)
|
||||
|
||||
#define MIPITX_CPHY_LANE_SEL0_SETTING 0x65432101
|
||||
#define MIPITX_CPHY_LANE_SEL1_SETTING 0x24210987
|
||||
#define MIPITX_CPHY_LANE_SEL2_SETTING 0x68543102
|
||||
#define MIPITX_CPHY_LANE_SEL3_SETTING 0x00000007
|
||||
|
||||
void mtk_dsi_cphy_lane_sel_setting(void)
|
||||
{
|
||||
write32(&mipi_tx->phy_sel[0], MIPITX_CPHY_LANE_SEL0_SETTING);
|
||||
write32(&mipi_tx->phy_sel[1], MIPITX_CPHY_LANE_SEL1_SETTING);
|
||||
write32(&mipi_tx->phy_sel[2], MIPITX_CPHY_LANE_SEL2_SETTING);
|
||||
write32(&mipi_tx->phy_sel[3], MIPITX_CPHY_LANE_SEL3_SETTING);
|
||||
}
|
||||
|
||||
void mtk_dsi_cphy_enable(void)
|
||||
{
|
||||
setbits32(&mipi_tx->lane_con, DSI_CPHY_EN);
|
||||
}
|
||||
|
||||
void mtk_dsi_cphy_disable_ck_mode(void)
|
||||
{
|
||||
clrsetbits32(&mipi_tx->voltage_sel, DSI_HSTX_LDO_REF_SEL, 0xF << 6);
|
||||
clrbits32(&mipi_tx->ck_ckmode_en, DSI_CK_CKMODE_EN);
|
||||
setbits32(&mipi_tx->lane_con, DE_EMPHASIS_EN);
|
||||
}
|
||||
|
||||
void mtk_dsi_cphy_enable_cmdq_6byte(void)
|
||||
{
|
||||
clrbits32(&dsi0->dsi_cmd_type1_hs, CMD_CPHY_6BYTE_EN);
|
||||
}
|
||||
|
||||
void mtk_dsi_cphy_timing(u32 data_rate, struct mtk_phy_timing *timing)
|
||||
{
|
||||
u32 cycle_time, value;
|
||||
|
||||
data_rate = data_rate / MHz;
|
||||
cycle_time = 7000 / data_rate;
|
||||
printk(BIOS_INFO, "cycle_time = %d data_rate= %d\n", cycle_time, data_rate);
|
||||
/* spec. lpx > 50ns */
|
||||
timing->lpx = DIV_ROUND_UP(75, cycle_time);
|
||||
/* spec. 38ns < hs_prpr < 95ns */
|
||||
timing->da_hs_prepare = DIV_ROUND_UP(64, cycle_time);
|
||||
/* spec. 7ui < hs_zero(prebegin) < 448ui */
|
||||
timing->da_hs_zero = 48;
|
||||
/* spec. 7ui < hs_trail(post) < 224ui */
|
||||
timing->da_hs_trail = 32;
|
||||
|
||||
/* spec. ta_get = 5*lpx */
|
||||
timing->ta_get = 5 * timing->lpx;
|
||||
/* spec. ta_sure = 1.5*lpx */
|
||||
timing->ta_sure = 3 * timing->lpx / 2;
|
||||
/* spec. ta_go = 4*lpx */
|
||||
timing->ta_go = 4 * timing->lpx;
|
||||
/* spec. da_hs_exit > 100ns */
|
||||
timing->da_hs_exit = DIV_ROUND_UP(125, cycle_time);
|
||||
|
||||
/* Allow board-specific tuning. */
|
||||
mtk_dsi_override_phy_timing(timing);
|
||||
|
||||
value = timing->lpx | timing->da_hs_prepare << 8 |
|
||||
timing->da_hs_zero << 16 | timing->da_hs_trail << 24;
|
||||
write32(&dsi0->dsi_phy_timecon0, value);
|
||||
|
||||
value = timing->ta_go | timing->ta_sure << 8 |
|
||||
timing->ta_get << 16 | timing->da_hs_exit << 24;
|
||||
write32(&dsi0->dsi_phy_timecon1, value);
|
||||
|
||||
write32(&dsi0->dsi_cphy_con0, 0x012C0003);
|
||||
write32(&dsi0->dsi_bllp_wc, 16 * 3);
|
||||
}
|
||||
|
||||
void mtk_dsi_cphy_vdo_timing(const u32 lanes,
|
||||
const struct edid *edid,
|
||||
const struct mtk_phy_timing *phy_timing,
|
||||
const u32 bytes_per_pixel,
|
||||
const u32 hbp,
|
||||
const u32 hfp,
|
||||
s32 *hbp_byte,
|
||||
s32 *hfp_byte,
|
||||
u32 *hsync_active_byte)
|
||||
{
|
||||
s32 active_byte, phy_cycle, phy_trail, tmp;
|
||||
u32 hs_vb_ps_wc, ps_wc, data_phy_cycles;
|
||||
|
||||
active_byte = edid->mode.hspw * bytes_per_pixel - 10 * lanes - 26;
|
||||
*hsync_active_byte = MAX(4, active_byte);
|
||||
active_byte = hbp * bytes_per_pixel - 12 * lanes - 26;
|
||||
*hbp_byte = MAX(4, active_byte);
|
||||
data_phy_cycles = phy_timing->lpx + phy_timing->da_hs_prepare +
|
||||
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 5;
|
||||
phy_cycle = 8 * lanes + 28 + 2 * data_phy_cycles * lanes;
|
||||
phy_trail = 2 * (phy_timing->da_hs_trail + 1) * lanes - 6 * lanes - 14;
|
||||
tmp = hfp * bytes_per_pixel - phy_cycle;
|
||||
*hfp_byte = MIN(MAX(8, tmp), phy_trail);
|
||||
ps_wc = edid->mode.ha * bytes_per_pixel;
|
||||
hs_vb_ps_wc = ps_wc - (phy_timing->lpx + phy_timing->da_hs_exit +
|
||||
phy_timing->da_hs_prepare + phy_timing->da_hs_zero + 2) * lanes;
|
||||
*hfp_byte |= hs_vb_ps_wc << 16 | HFP_HS_EN;
|
||||
}
|
||||
|
|
@ -1,63 +1,9 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <assert.h>
|
||||
#include <device/mmio.h>
|
||||
#include <delay.h>
|
||||
#include <soc/dsi.h>
|
||||
#include <soc/pll.h>
|
||||
#include <types.h>
|
||||
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes)
|
||||
void mtk_dsi_dphy_disable_ck_mode(void)
|
||||
{
|
||||
unsigned int txdiv0, txdiv1;
|
||||
u64 pcw;
|
||||
|
||||
if (data_rate >= 2000 * MHz) {
|
||||
txdiv0 = 0;
|
||||
txdiv1 = 0;
|
||||
} else if (data_rate >= 1000 * MHz) {
|
||||
txdiv0 = 1;
|
||||
txdiv1 = 0;
|
||||
} else if (data_rate >= 500 * MHz) {
|
||||
txdiv0 = 2;
|
||||
txdiv1 = 0;
|
||||
} else if (data_rate > 250 * MHz) {
|
||||
/* (data_rate == 250MHz) is a special case that should go to the
|
||||
else-block below (txdiv0 = 4) */
|
||||
txdiv0 = 3;
|
||||
txdiv1 = 0;
|
||||
} else {
|
||||
/* MIN = 125 */
|
||||
assert(data_rate >= MTK_DSI_DATA_RATE_MIN_MHZ * MHz);
|
||||
txdiv0 = 4;
|
||||
txdiv1 = 0;
|
||||
}
|
||||
|
||||
clrbits32(&mipi_tx->pll_con4, BIT(11) | BIT(10));
|
||||
setbits32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_PWR_ON);
|
||||
udelay(30);
|
||||
clrbits32(&mipi_tx->pll_pwr, AD_DSI_PLL_SDM_ISO_EN);
|
||||
|
||||
pcw = (u64)data_rate * (1 << txdiv0) * (1 << txdiv1);
|
||||
pcw <<= 24;
|
||||
pcw /= CLK26M_HZ;
|
||||
|
||||
write32(&mipi_tx->pll_con0, pcw);
|
||||
clrsetbits32(&mipi_tx->pll_con1, RG_DSI_PLL_POSDIV, txdiv0 << 8);
|
||||
udelay(30);
|
||||
setbits32(&mipi_tx->pll_con1, RG_DSI_PLL_EN);
|
||||
|
||||
/* BG_LPF_EN / BG_CORE_EN */
|
||||
write32(&mipi_tx->lane_con, 0x3fff0180);
|
||||
udelay(40);
|
||||
write32(&mipi_tx->lane_con, 0x3fff00c0);
|
||||
|
||||
/* Switch OFF each Lane */
|
||||
clrbits32(&mipi_tx->d0_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d1_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d2_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->d3_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
clrbits32(&mipi_tx->ck_sw_ctl_en, DSI_SW_CTL_EN);
|
||||
|
||||
setbits32(&mipi_tx->ck_ckmode_en, DSI_CK_CKMODE_EN);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <soc/dsi.h>
|
||||
#include <timer.h>
|
||||
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes)
|
||||
void mtk_dsi_configure_mipi_tx(u32 data_rate, u32 lanes, bool is_cphy)
|
||||
{
|
||||
u32 txdiv0, txdiv1;
|
||||
u64 pcw;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue