soc/mediatek/mt8196: Add DSI dual channel

Add support for DSI dual channel and dual Display Stream Compression
(DSC) features.
- Add DSI dual channel and dual DSC feature.
- Add dsi1, mipi1, dsc0, dsc1 engine drivers.
- Add configuration for dual channel feature selection.
- Add 'dsi.c' for mt8196 mipi data rate calculation.
- Add 'mtk_mipi_dphy.c' for mt8196 timing calculation.

BUG=b:424782827
TEST=Build pass, boot ok.
Verify display output on the following platforms:
- 8196 Navi: eDP path.
- 8189 Skywalker: eDP path.
- 8189 Padme: single MIPI path (without DSC).
- 8196 Sapphire: dual MIPI path (with DSC).

Change-Id: I2bea829da72d23165a74b399eabfcdd55a7f28a1
Signed-off-by: Payne Lin <payne.lin@mediatek.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90504
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
Reviewed-by: Chen-Tsung Hsieh <chentsung@google.com>
Reviewed-by: Yidi Lin <yidilin@google.com>
This commit is contained in:
Payne Lin 2025-11-17 21:02:57 +08:00 committed by Yu-Ping Wu
commit 060d18f070
9 changed files with 656 additions and 137 deletions

View file

@ -69,6 +69,12 @@ config MEDIATEK_WDT_RESET_BY_SW
If the kernel disables WDT external reset (mediatek,disable-extrst),
then this option must be disabled to allow WDT hardware external reset.
config MEDIATEK_DSI_DUAL_CHANNEL
bool
default n
help
The configuration to support DSI dual channel.
config MEMORY_TEST
bool
default y

View file

@ -16,6 +16,25 @@
#define CPHY_SYMBOL_RATE 7
#define CPHY_SYMBOL_RATE_DIVISOR 16
#define COMPRESSION_RATIO 3
#define UNCOMPRESSED_RATIO 1
static const struct {
struct dsi_regs *const dsi_reg;
struct mipi_tx_regs *const mipi_reg;
} dsi_mipi_regs[] = {
{
.dsi_reg = dsi0,
.mipi_reg = mipi_tx0,
},
#if CONFIG(MEDIATEK_DSI_DUAL_CHANNEL)
{
.dsi_reg = dsi1,
.mipi_reg = mipi_tx1,
},
#endif
};
static unsigned int mtk_dsi_get_bits_per_pixel(u32 format)
{
switch (format) {
@ -33,7 +52,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, bool is_cphy)
const struct edid *edid, u32 mode_flags)
{
/* data_rate = pixel_clock * bits_per_pixel * mipi_ratio / lanes
* Note pixel_clock comes in kHz and returned data_rate is in bps.
@ -41,9 +60,18 @@ 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).
*/
u64 pixel_clock = edid->mode.pixel_clock;
u32 data_rate;
u64 dividend = (u64)edid->mode.pixel_clock * bits_per_pixel * 1000 *
MTK_DSI_MIPI_RATIO_NUMERATOR;
bool is_cphy = !!(mode_flags & MIPI_DSI_MODE_CPHY);
bool is_dsi_dual_channel = !!(mode_flags & MIPI_DSI_DUAL_CHANNEL);
bool is_dsc_enabled = !!(mode_flags & MIPI_DSI_DSC_MODE);
if (is_dsc_enabled)
pixel_clock = pixel_clock *
(DIV_ROUND_UP(edid->mode.ha, 3) + edid->mode.hbl) /
(edid->mode.ha + edid->mode.hbl);
u64 dividend = pixel_clock * bits_per_pixel * 1000 * MTK_DSI_MIPI_RATIO_NUMERATOR;
u64 divisor = (u64)lanes * MTK_DSI_MIPI_RATIO_DENOMINATOR;
if (is_cphy) {
@ -51,15 +79,20 @@ static u32 mtk_dsi_get_data_rate(u32 bits_per_pixel, u32 lanes,
divisor *= CPHY_SYMBOL_RATE_DIVISOR;
}
data_rate = DIV_ROUND_UP(dividend, divisor);
printk(BIOS_INFO, "DSI data_rate: %u bps\n", data_rate);
printk(BIOS_INFO, "pixel_clock: %lld\n", pixel_clock);
printk(BIOS_INFO, "bits_per_pixel: %d\n", bits_per_pixel);
if (is_dsi_dual_channel)
data_rate = data_rate / 2;
printk(BIOS_INFO, "DSI final data_rate: %u bps\n", data_rate);
if (data_rate < MTK_DSI_DATA_RATE_MIN_MHZ * MHz) {
printk(BIOS_ERR, "data rate (%ubps) must be >= %ubps. "
"Please check the pixel clock (%u), "
"Please check the pixel clock (%llu), "
"bits per pixel (%u), "
"mipi_ratio (%d%%) and number of lanes (%d)\n",
data_rate, MTK_DSI_DATA_RATE_MIN_MHZ * MHz,
edid->mode.pixel_clock, bits_per_pixel,
pixel_clock, bits_per_pixel,
(100 * MTK_DSI_MIPI_RATIO_NUMERATOR /
MTK_DSI_MIPI_RATIO_DENOMINATOR), lanes);
return 0;
@ -72,7 +105,8 @@ __weak void mtk_dsi_override_phy_timing(struct mtk_phy_timing *timing)
/* Do nothing. */
}
static void mtk_dsi_dphy_timing(u32 data_rate, struct mtk_phy_timing *timing)
static void mtk_dsi_dphy_timing(struct dsi_regs *dsi_reg, u32 data_rate,
struct mtk_phy_timing *timing)
{
u32 timcon0, timcon1, timcon2, timcon3;
u32 data_rate_mhz = DIV_ROUND_UP(data_rate, MHz);
@ -91,23 +125,23 @@ static void mtk_dsi_dphy_timing(u32 data_rate, struct mtk_phy_timing *timing)
timcon3 = timing->clk_hs_prepare | timing->clk_hs_post << 8 |
timing->clk_hs_exit << 16;
write32(&dsi0->dsi_phy_timecon0, timcon0);
write32(&dsi0->dsi_phy_timecon1, timcon1);
write32(&dsi0->dsi_phy_timecon2, timcon2);
write32(&dsi0->dsi_phy_timecon3, timcon3);
write32(&dsi_reg->dsi_phy_timecon0, timcon0);
write32(&dsi_reg->dsi_phy_timecon1, timcon1);
write32(&dsi_reg->dsi_phy_timecon2, timcon2);
write32(&dsi_reg->dsi_phy_timecon3, timcon3);
}
static void mtk_dsi_clk_hs_mode_enable(void)
static void mtk_dsi_clk_hs_mode_enable(struct dsi_regs *dsi_reg)
{
setbits32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
setbits32(&dsi_reg->dsi_phy_lccon, LC_HS_TX_EN);
}
static void mtk_dsi_clk_hs_mode_disable(void)
static void mtk_dsi_clk_hs_mode_disable(struct dsi_regs *dsi_reg)
{
clrbits32(&dsi0->dsi_phy_lccon, LC_HS_TX_EN);
clrbits32(&dsi_reg->dsi_phy_lccon, LC_HS_TX_EN);
}
static void mtk_dsi_set_mode(u32 mode_flags)
static void mtk_dsi_set_mode(struct dsi_regs *dsi_reg, u32 mode_flags)
{
u32 tmp_reg1 = 0;
@ -121,10 +155,10 @@ static void mtk_dsi_set_mode(u32 mode_flags)
tmp_reg1 = SYNC_PULSE_MODE;
}
write32(&dsi0->dsi_mode_ctrl, tmp_reg1);
write32(&dsi_reg->dsi_mode_ctrl, tmp_reg1);
}
static void mtk_dsi_rxtx_control(u32 mode_flags, u32 lanes)
static void mtk_dsi_rxtx_control(struct dsi_regs *dsi_reg, u32 mode_flags, u32 lanes)
{
u32 tmp_reg = 0;
@ -150,7 +184,7 @@ static void mtk_dsi_rxtx_control(u32 mode_flags, u32 lanes)
if (!(mode_flags & MIPI_DSI_MODE_EOT_PACKET))
tmp_reg |= EOTP_DISABLE;
write32(&dsi0->dsi_txrx_ctrl, tmp_reg);
write32(&dsi_reg->dsi_txrx_ctrl, tmp_reg);
}
static void mtk_dsi_dphy_vdo_timing(const u32 mode_flags,
@ -168,6 +202,9 @@ static void mtk_dsi_dphy_vdo_timing(const u32 mode_flags,
phy_timing->da_hs_zero + phy_timing->da_hs_exit + 3;
u32 delta = 10;
int channels = (mode_flags & MIPI_DSI_DUAL_CHANNEL) ? 2 : 1;
int dsc_ratio = (mode_flags & MIPI_DSI_DSC_MODE) ? COMPRESSION_RATIO :
UNCOMPRESSED_RATIO;
if (mode_flags & MIPI_DSI_MODE_EOT_PACKET)
delta += 2;
@ -188,17 +225,44 @@ static void mtk_dsi_dphy_vdo_timing(const u32 mode_flags,
hbp * bytes_per_pixel, d_phy);
}
*hsync_active_byte = edid->mode.hspw * bytes_per_pixel - 10;
*hsync_active_byte = edid->mode.hspw / channels * 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;
*hbp_byte -= (edid->mode.ha / dsc_ratio / channels * bytes_per_pixel + 2) %
lanes;
}
}
static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
const struct edid *edid,
static u32 mtk_dsi_get_packet_fmt(u32 format)
{
u32 packet_fmt;
switch (format) {
case MIPI_DSI_FMT_RGB888:
packet_fmt = PACKED_PS_24BIT_RGB888;
break;
case MIPI_DSI_FMT_RGB666:
packet_fmt = LOOSELY_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
packet_fmt = PACKED_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB565:
packet_fmt = PACKED_PS_16BIT_RGB565;
break;
default:
packet_fmt = PACKED_PS_24BIT_RGB888;
break;
}
return packet_fmt;
}
static void mtk_dsi_config_vdo_timing(struct dsi_regs *const dsi_reg, u32 mode_flags,
u32 format, u32 lanes, const struct edid *edid,
const struct mtk_phy_timing *phy_timing)
{
u32 hsync_active_byte;
@ -211,26 +275,30 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
u32 bytes_per_pixel;
u32 packet_fmt;
u32 hactive;
u32 hbp_offset;
bool is_cphy = !!(mode_flags & MIPI_DSI_MODE_CPHY);
bool is_dsc_enabled = !!(mode_flags & MIPI_DSI_DSC_MODE);
int channels = !!(mode_flags & MIPI_DSI_DUAL_CHANNEL) ? 2 : 1;
int dsc_ratio = is_dsc_enabled ? COMPRESSION_RATIO : UNCOMPRESSED_RATIO;
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);
write32(&dsi_reg->dsi_vsa_nl, edid->mode.vspw);
write32(&dsi_reg->dsi_vbp_nl, vbp_byte);
write32(&dsi_reg->dsi_vfp_nl, vfp_byte);
write32(&dsi_reg->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;
hbp = (edid->mode.hbl - edid->mode.hso - edid->mode.hspw -
edid->mode.hborder) / channels;
hfp = (edid->mode.hso - edid->mode.hborder) / channels;
hbp_offset = (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) ?
0 : (edid->mode.hspw / channels);
hbp_byte = (hbp + hbp_offset) * bytes_per_pixel - 10;
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)
@ -255,49 +323,40 @@ static void mtk_dsi_config_vdo_timing(u32 mode_flags, u32 format, u32 lanes,
hbp_byte = MIN_HBP_BYTE;
}
write32(&dsi0->dsi_hsa_wc, hsync_active_byte);
write32(&dsi0->dsi_hbp_wc, hbp_byte);
write32(&dsi0->dsi_hfp_wc, hfp_byte);
write32(&dsi_reg->dsi_hsa_wc, hsync_active_byte);
write32(&dsi_reg->dsi_hbp_wc, hbp_byte);
write32(&dsi_reg->dsi_hfp_wc, hfp_byte);
switch (format) {
case MIPI_DSI_FMT_RGB888:
packet_fmt = PACKED_PS_24BIT_RGB888;
break;
case MIPI_DSI_FMT_RGB666:
packet_fmt = LOOSELY_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB666_PACKED:
packet_fmt = PACKED_PS_18BIT_RGB666;
break;
case MIPI_DSI_FMT_RGB565:
packet_fmt = PACKED_PS_16BIT_RGB565;
break;
default:
packet_fmt = PACKED_PS_24BIT_RGB888;
break;
}
if (is_dsc_enabled)
packet_fmt = COMPRESSED_PIXEL_STREAM_V2;
else
packet_fmt = mtk_dsi_get_packet_fmt(format);
hactive = edid->mode.ha;
hactive = edid->mode.ha / dsc_ratio / channels;
packet_fmt |= (hactive * bytes_per_pixel) & DSI_PS_WC;
write32(&dsi0->dsi_psctrl,
write32(&dsi_reg->dsi_psctrl,
PIXEL_STREAM_CUSTOM_HEADER << DSI_PSCON_CUSTOM_HEADER_SHIFT |
packet_fmt);
/* Older systems like MT8173 do not support size_con. */
if (MTK_DSI_HAVE_SIZE_CON)
write32(&dsi0->dsi_size_con,
write32(&dsi_reg->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(dsi0);
mtk_dsi_cphy_enable_cmdq_6byte(dsi_reg);
}
static void mtk_dsi_start(void)
static void mtk_dsi_dual_enable(struct dsi_regs *dsi_reg, bool enable)
{
write32(&dsi0->dsi_start, 0);
/* Only start master DSI */
write32(&dsi0->dsi_start, 1);
clrsetbits32(&dsi_reg->dsi_con_ctrl, DSI_DUAL, (enable ? DSI_DUAL : 0));
}
static void mtk_dsi_start(struct dsi_regs *dsi_reg)
{
write32(&dsi_reg->dsi_start, 0);
write32(&dsi_reg->dsi_start, 1);
}
static bool mtk_dsi_is_read_command(enum mipi_dsi_transaction type)
@ -313,60 +372,77 @@ static bool mtk_dsi_is_read_command(enum mipi_dsi_transaction type)
}
}
static void mtk_dsi_enable_and_start(bool is_dsi_dual_channel)
{
/*
* For dual channel synchronization,
* the secondary dsi1 must be dual-enabled before starting the primary dsi0.
*/
if (is_dsi_dual_channel)
mtk_dsi_dual_enable(dsi_mipi_regs[ARRAY_SIZE(dsi_mipi_regs) - 1].dsi_reg, true);
/*
* Only start primary dsi0 for single or dual channel mode.
* The secondary dsi1 is dual-enabled in mtk_dsi_dual_enable()
* and does not require a separate start.
* Starting only the primary dsi0 ensures correct synchronization
* with secondary dsi1 if there is.
*/
mtk_dsi_start(dsi_mipi_regs[0].dsi_reg);
}
static enum cb_err mtk_dsi_cmdq(enum mipi_dsi_transaction type, const u8 *data, u8 len,
void *user_data)
{
const u8 *tx_buf = data;
u32 config;
int i, j;
uint32_t *mode_flags = (uint32_t *)user_data;
bool is_dsi_dual_channel = (*mode_flags & MIPI_DSI_DUAL_CHANNEL);
if (!wait_ms(20, !(read32(&dsi0->dsi_intsta) & DSI_BUSY))) {
printk(BIOS_ERR, "%s: cannot get DSI ready for sending commands"
" after 20ms and the panel may not work properly.\n",
__func__);
return CB_ERR;
}
write32(&dsi0->dsi_intsta, 0);
if (mtk_dsi_is_read_command(type))
config = BTA;
else
config = (len > 2) ? LONG_PACKET : SHORT_PACKET;
if (len <= 2) {
uint32_t val = (type << 8) | config;
for (i = 0; i < len; i++)
val |= tx_buf[i] << (i + 2) * 8;
write32(&dsi0->dsi_cmdq[0], val);
write32(&dsi0->dsi_cmdq_size, 1);
} else {
/* TODO(hungte) Replace by buffer_to_fifo32_prefix */
write32(&dsi0->dsi_cmdq[0], (len << 16) | (type << 8) | config);
for (i = 0; i < len; i += 4) {
uint32_t val = 0;
for (j = 0; j < MIN(len - i, 4); j++)
val |= tx_buf[i + j] << j * 8;
write32(&dsi0->dsi_cmdq[i / 4 + 1], val);
for (unsigned int k = 0; k < ARRAY_SIZE(dsi_mipi_regs); k++) {
struct dsi_regs *dsi = dsi_mipi_regs[k].dsi_reg;
if (!wait_ms(20, !(read32(&dsi->dsi_intsta) & DSI_BUSY))) {
printk(BIOS_ERR, "%s: cannot get DSI-%d ready for sending commands"
" after 20ms and the panel may not work properly.\n",
__func__, k);
return CB_ERR;
}
write32(&dsi0->dsi_cmdq_size, 1 + DIV_ROUND_UP(len, 4));
write32(&dsi->dsi_intsta, 0);
if (mtk_dsi_is_read_command(type))
config = BTA;
else
config = (len > 2) ? LONG_PACKET : SHORT_PACKET;
u32 prefix = config | type << 8;
int prefsz = 2;
if (len > 2) {
prefix |= len << 16;
prefsz += 2;
}
buffer_to_fifo32_prefix(tx_buf, prefix, prefsz, prefsz + len, &dsi->dsi_cmdq[0],
4, 4);
write32(&dsi->dsi_cmdq_size, DIV_ROUND_UP(prefsz + len, 4));
setbits32(&dsi->dsi_cmdq_size, CMDQ_SIZE_SEL);
}
setbits32(&dsi0->dsi_cmdq_size, CMDQ_SIZE_SEL);
mtk_dsi_start();
mtk_dsi_enable_and_start(is_dsi_dual_channel);
if (!wait_us(400, read32(&dsi0->dsi_intsta) & CMD_DONE_INT_FLAG)) {
printk(BIOS_ERR, "%s: failed sending DSI command, "
"panel may not work.\n", __func__);
return CB_ERR;
for (unsigned int k = 0; k < ARRAY_SIZE(dsi_mipi_regs); k++) {
struct dsi_regs *dsi = dsi_mipi_regs[k].dsi_reg;
if (!wait_us(400, read32(&dsi->dsi_intsta) & CMD_DONE_INT_FLAG)) {
printk(BIOS_ERR, "%s: failed sending DSI-%d command, "
"panel may not work.\n", __func__, k);
return CB_ERR;
}
}
return CB_SUCCESS;
}
static void mtk_dsi_reset_phy(void)
static void mtk_dsi_reset_phy(struct dsi_regs *const dsi_reg)
{
setbits32(&dsi0->dsi_con_ctrl, DPHY_RESET);
clrbits32(&dsi0->dsi_con_ctrl, DPHY_RESET);
setbits32(&dsi_reg->dsi_con_ctrl, DPHY_RESET);
clrbits32(&dsi_reg->dsi_con_ctrl, DPHY_RESET);
}
int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid,
@ -375,6 +451,8 @@ 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);
bool is_dsi_dual_channel = !!(mode_flags & MIPI_DSI_DUAL_CHANNEL);
unsigned int num_dsi = is_dsi_dual_channel ? 2 : 1;
if (!CONFIG(MEDIATEK_DSI_CPHY) && is_cphy) {
printk(BIOS_ERR, "%s: Board is built without C-PHY interface support. "
@ -382,27 +460,47 @@ int mtk_dsi_init(u32 mode_flags, u32 format, u32 lanes, const struct edid *edid,
return -1;
}
data_rate = mtk_dsi_get_data_rate(bits_per_pixel, lanes, edid, is_cphy);
if (num_dsi > ARRAY_SIZE(dsi_mipi_regs)) {
printk(BIOS_ERR, "%s: num_dsi %d > %lu\n", __func__,
num_dsi, ARRAY_SIZE(dsi_mipi_regs));
return -1;
}
data_rate = mtk_dsi_get_data_rate(bits_per_pixel, lanes, edid, mode_flags);
if (!data_rate)
return -1;
mtk_dsi_configure_mipi_tx(mipi_tx0, data_rate, lanes, is_cphy);
mtk_dsi_reset(dsi0);
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_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();
for (unsigned int i = 0; i < num_dsi; i++) {
struct dsi_regs *dsi = dsi_mipi_regs[i].dsi_reg;
struct mipi_tx_regs *mipi = dsi_mipi_regs[i].mipi_reg;
if (!dsi || !mipi) {
printk(BIOS_ERR, "%s: Null dsi/mipi reg for DSI-%d\n", __func__, i);
return -1;
}
mtk_dsi_configure_mipi_tx(mipi, data_rate, lanes, is_cphy);
mtk_dsi_reset(dsi);
struct mtk_phy_timing phy_timing = {};
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
/* Dual channel is not implemented for CPHY. */
mtk_dsi_cphy_timing(data_rate, &phy_timing);
else
mtk_dsi_dphy_timing(dsi, data_rate, &phy_timing);
mtk_dsi_rxtx_control(dsi, mode_flags, lanes);
mdelay(1);
mtk_dsi_reset_phy(dsi);
mtk_dsi_clk_hs_mode_disable(dsi);
mtk_dsi_config_vdo_timing(dsi, mode_flags, format, lanes, edid, &phy_timing);
mtk_dsi_clk_hs_mode_enable(dsi);
}
if (init_commands)
mipi_panel_parse_init_commands(init_commands, mtk_dsi_cmdq, NULL);
mtk_dsi_set_mode(mode_flags);
mtk_dsi_start();
mipi_panel_parse_init_commands(init_commands, mtk_dsi_cmdq, &mode_flags);
for (unsigned int i = 0; i < num_dsi; i++)
mtk_dsi_set_mode(dsi_mipi_regs[i].dsi_reg, mode_flags);
mtk_dsi_enable_and_start(is_dsi_dual_channel);
return 0;
}

View file

@ -59,6 +59,7 @@ enum {
LOOSELY_PS_18BIT_RGB666 = (1 << 16),
PACKED_PS_18BIT_RGB666 = (2 << 16),
PACKED_PS_24BIT_RGB888 = (3 << 16),
COMPRESSED_PIXEL_STREAM_V2 = (5 << 16),
DSI_PSCON_CUSTOM_HEADER_SHIFT = 26,
};

View file

@ -18,6 +18,7 @@ config SOC_MEDIATEK_MT8196
select ARM64_USE_ARCH_TIMER
select PCI
select EARLY_MMU_INIT
select MEDIATEK_DSI_DUAL_CHANNEL
if SOC_MEDIATEK_MT8196

View file

@ -64,12 +64,14 @@ ramstage-y += ../common/dp/dp_intf_v2.c
ramstage-y += ../common/dp/dptx_common.c ../common/dp/dptx_v2.c dptx.c
ramstage-y += ../common/dp/dptx_hal_common.c ../common/dp/dptx_hal_v2.c dptx_hal.c
ramstage-y += ../common/dramc_info.c
ramstage-y += ../common/dsi_common.c dsi.c
ramstage-y += ../common/early_init.c
ramstage-y += ../common/emi.c
ramstage-y += gpueb.c
ramstage-y += l2c_ops.c
ramstage-y += ../common/mcu.c mcupm.c
ramstage-y += ../common/mmu_operations.c
ramstage-y += ../common/mtk_mipi_dphy.c mtk_mipi_dphy.c
ramstage-$(CONFIG_PCI) += ../common/pcie.c pcie.c
ramstage-$(CONFIG_COMMONLIB_STORAGE_MMC) += msdc.c
ramstage-y += ../common/mt6363.c mt6363.c

View file

@ -11,6 +11,30 @@
#define SIZE(w, h) ((u32)(h) << 16 | (w))
#define DUAL_PIPE(path) ((path) == DISP_PATH_DUAL_MIPI)
#define DSC_EN BIT(0)
#define DSC_DUAL_INOUT BIT(2)
#define DSC_IN_SRC_SEL BIT(3)
#define DSC_BYPASS BIT(4)
#define DSC_RELAY BIT(5)
#define DSC_PT_MEM_EN BIT(7)
#define DSC_EMPTY_FLAG_SEL GENMASK(15, 14)
#define DSC_EMPTY_FLAG_ALWAYS_LOW BIT(15)
#define DSC_UFOE_SEL BIT(16)
#define DSC_ZERO_FIFO_STALL_DISABLE BIT(20)
#define DSC_INTEN_SEL GENMASK(6, 0)
#define DSC_ZERO_FIFO BIT(2)
#define DSC_INTACK_SEL GENMASK(6, 0)
#define DSC_INTACK_BUF_UNDERFLOW BIT(6)
#define DSC_PIC_PREPAD_HEIGHT_SEL GENMASK(15, 0)
#define DSC_PIC_PREPAD_WIDTH_SEL GENMASK(31, 16)
#define ALIGN_PADDING(V, N) (((N) - ((V) % (N))) % (N))
/* Provide default value for x == 0. */
#define DEF(x, default) ((x) == 0 ? (default) : (x))
struct disp_pipe_regs {
struct disp_mdp_rsz_regs *const mdp_rsz;
struct disp_tdshp_regs *const tdshp;
@ -44,6 +68,245 @@ static const struct disp_pipe_regs disp_pipe1_regs = {
.dsc = disp_dsc3_reg,
};
static void dsc_configure_registers(struct disp_dsc_regs *reg, u16 w, u16 h,
const struct dsc_config *dsc_cfg)
{
u32 init_delay_limit, init_delay_height;
u32 pic_group_width, pic_height_ext_num;
u32 slice_group_width;
u32 pad_num;
u32 slice_mode;
u32 dsc_cfg_mode = 0x22;
u32 mask;
u32 val;
u32 rgb_swap = 0;
if (dsc_cfg->bits_per_component == 0xA)
dsc_cfg_mode = 0x828;
assert(dsc_cfg->pic_width > 0);
assert(dsc_cfg->pic_width >= dsc_cfg->slice_width);
assert(dsc_cfg->slice_width > 0);
slice_mode = dsc_cfg->pic_width / dsc_cfg->slice_width - 1;
pic_group_width = DIV_ROUND_UP(dsc_cfg->pic_width, 3);
pic_height_ext_num = DIV_ROUND_UP(h, dsc_cfg->slice_height);
slice_group_width = DIV_ROUND_UP(dsc_cfg->slice_width, 3);
pad_num = ALIGN_PADDING(dsc_cfg->slice_chunk_size * (slice_mode + 1), 3);
init_delay_limit = DIV_ROUND_UP(dsc_cfg->initial_xmit_delay, 3);
init_delay_limit = DIV_ROUND_UP((128 + init_delay_limit) * 3, dsc_cfg->slice_width);
init_delay_height = MIN(15, init_delay_limit);
mask = DSC_EN | DSC_DUAL_INOUT | DSC_IN_SRC_SEL | DSC_BYPASS | DSC_RELAY |
DSC_PT_MEM_EN | DSC_EMPTY_FLAG_SEL | DSC_UFOE_SEL |
DSC_ZERO_FIFO_STALL_DISABLE;
val = DSC_PT_MEM_EN | DSC_EMPTY_FLAG_ALWAYS_LOW | DSC_UFOE_SEL |
DSC_ZERO_FIFO_STALL_DISABLE;
clrsetbits32(&reg->dsc_con, mask, val);
clrsetbits32(&reg->dsc_inten, DSC_INTEN_SEL, 0x7F);
clrsetbits32(&reg->dsc_intack, DSC_INTACK_SEL, DSC_INTACK_BUF_UNDERFLOW);
write32(&reg->dsc_spr, 0x0);
val = w | (pic_group_width - 1) << 16;
write32(&reg->pic_w, val);
val = (h - 1) | (pic_height_ext_num * dsc_cfg->slice_height - 1) << 16;
write32(&reg->pic_h, val);
val = dsc_cfg->slice_width | (slice_group_width - 1) << 16;
write32(&reg->dsc_slice_w, val);
val = (dsc_cfg->slice_height - 1) | (pic_height_ext_num - 1) << 16 |
(dsc_cfg->slice_width % 3) << 30;
write32(&reg->dsc_slice_h, val);
val = dsc_cfg->slice_chunk_size |
(((dsc_cfg->slice_chunk_size << slice_mode) + 2) / 3) << 16;
write32(&reg->chunk_size, val);
mask = GENMASK(23, 0);
val = dsc_cfg->slice_chunk_size * dsc_cfg->slice_height;
clrsetbits32(&reg->dsc_buf_size, mask, val);
mask = BIT(0) | BIT(2) | GENMASK(11, 8);
val = slice_mode | rgb_swap << 2 | init_delay_height << 8;
clrsetbits32(&reg->dsc_mode, mask, val);
write32(&reg->dsc_cfg, dsc_cfg_mode);
mask = GENMASK(2, 0);
val = pad_num;
clrsetbits32(&reg->dsc_pad, mask, val);
val = dsc_cfg->slice_width | dsc_cfg->pic_width << 16;
write32(&reg->dsc_enc_width, val);
mask = DSC_PIC_PREPAD_HEIGHT_SEL | DSC_PIC_PREPAD_WIDTH_SEL;
val = h | w << 16;
clrsetbits32(&reg->dsc_pic_pre_pad_size, mask, val);
setbits32(&reg->dsc_dbg_con, BIT(9));
write32(&reg->dsc_obuf, 0x410);
DEFINE_BITFIELD(LINE_BUF_DEPTH, 3, 0)
DEFINE_BITFIELD(BITS_PER_COMPONENT, 7, 4)
DEFINE_BITFIELD(BITS_PER_PIXEL, 17, 8)
DEFINE_BIT(CONVERT_RGB, 18)
DEFINE_BIT(BLOCK_PRED_ENABLE, 19)
SET32_BITFIELDS(&reg->dsc_pps[0],
LINE_BUF_DEPTH, DEF(dsc_cfg->line_buf_depth, 0x9),
BITS_PER_COMPONENT, DEF(dsc_cfg->bits_per_component, 0x8),
BITS_PER_PIXEL, DEF(dsc_cfg->bits_per_pixel, 0x80),
CONVERT_RGB, DEF((u8)dsc_cfg->convert_rgb, 1),
BLOCK_PRED_ENABLE, DEF((u8)dsc_cfg->block_pred_enable, 0));
DEFINE_BITFIELD(INITIAL_DEC_DELAY, 31, 16)
DEFINE_BITFIELD(INITIAL_XMIT_DELAY, 15, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[1],
INITIAL_DEC_DELAY, DEF(dsc_cfg->initial_dec_delay, 0x268),
INITIAL_XMIT_DELAY, DEF(dsc_cfg->initial_xmit_delay, 0x200));
DEFINE_BITFIELD(INITIAL_SCALE_VALUE, 15, 0)
DEFINE_BITFIELD(SCALE_INCREMENT_INTERVAL, 31, 16)
WRITE32_BITFIELDS(&reg->dsc_pps[2],
INITIAL_SCALE_VALUE, DEF(dsc_cfg->initial_scale_value, 0x20),
SCALE_INCREMENT_INTERVAL,
DEF(dsc_cfg->scale_increment_interval, 0x387));
DEFINE_BITFIELD(FIRST_LINE_BPG_OFFSET, 31, 16)
DEFINE_BITFIELD(SCALE_DECREMENT_INTERVAL, 15, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[3],
FIRST_LINE_BPG_OFFSET, DEF(dsc_cfg->first_line_bpg_offset, 0xc),
SCALE_DECREMENT_INTERVAL,
DEF(dsc_cfg->scale_decrement_interval, 0xa));
DEFINE_BITFIELD(NFL_BPG_OFFSET, 15, 0)
DEFINE_BITFIELD(SLICE_BPG_OFFSET, 31, 16)
WRITE32_BITFIELDS(&reg->dsc_pps[4],
NFL_BPG_OFFSET, DEF(dsc_cfg->nfl_bpg_offset, 0x319),
SLICE_BPG_OFFSET, DEF(dsc_cfg->slice_bpg_offset, 0x263));
DEFINE_BITFIELD(INITIAL_OFFSET, 15, 0)
DEFINE_BITFIELD(FINAL_OFFSET, 31, 16)
WRITE32_BITFIELDS(&reg->dsc_pps[5],
INITIAL_OFFSET, DEF(dsc_cfg->initial_offset, 0x1800),
FINAL_OFFSET, DEF(dsc_cfg->final_offset, 0x10f0));
DEFINE_BITFIELD(FLATNESS_MIN_QP, 4, 0)
DEFINE_BITFIELD(FLATNESS_MAX_QP, 12, 8)
DEFINE_BITFIELD(RC_MODEL_SIZE, 31, 16)
SET32_BITFIELDS(&reg->dsc_pps[6],
FLATNESS_MIN_QP, DEF(dsc_cfg->flatness_min_qp, 0x3),
FLATNESS_MAX_QP, DEF(dsc_cfg->flatness_max_qp, 0xc),
RC_MODEL_SIZE, DEF(dsc_cfg->rc_model_size, 0x2000));
DEFINE_BITFIELD(RC_TGT_OFFSET_LOW, 31, 28)
DEFINE_BITFIELD(RC_TGT_OFFSET_HIGH, 27, 24)
DEFINE_BITFIELD(RC_QUANT_INCR_LIMIT1, 20, 16)
DEFINE_BITFIELD(RC_QUANT_INCR_LIMIT0, 12, 8)
DEFINE_BITFIELD(RC_EDGE_FACTOR, 7, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[7],
RC_TGT_OFFSET_LOW, dsc_cfg->rc_tgt_offset_low,
RC_TGT_OFFSET_HIGH, dsc_cfg->rc_tgt_offset_high,
RC_QUANT_INCR_LIMIT1, dsc_cfg->rc_quant_incr_limit1,
RC_QUANT_INCR_LIMIT0, dsc_cfg->rc_quant_incr_limit0,
RC_EDGE_FACTOR, dsc_cfg->rc_edge_factor);
DEFINE_BITFIELD(RC_BUF_THRESH_3, 31, 24)
DEFINE_BITFIELD(RC_BUF_THRESH_2, 23, 16)
DEFINE_BITFIELD(RC_BUF_THRESH_1, 15, 8)
DEFINE_BITFIELD(RC_BUF_THRESH_0, 7, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[8],
RC_BUF_THRESH_3, dsc_cfg->rc_buf_thresh[3],
RC_BUF_THRESH_2, dsc_cfg->rc_buf_thresh[2],
RC_BUF_THRESH_1, dsc_cfg->rc_buf_thresh[1],
RC_BUF_THRESH_0, dsc_cfg->rc_buf_thresh[0]);
DEFINE_BITFIELD(RC_BUF_THRESH_7, 31, 24)
DEFINE_BITFIELD(RC_BUF_THRESH_6, 23, 16)
DEFINE_BITFIELD(RC_BUF_THRESH_5, 15, 8)
DEFINE_BITFIELD(RC_BUF_THRESH_4, 7, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[9],
RC_BUF_THRESH_7, dsc_cfg->rc_buf_thresh[7],
RC_BUF_THRESH_6, dsc_cfg->rc_buf_thresh[6],
RC_BUF_THRESH_5, dsc_cfg->rc_buf_thresh[5],
RC_BUF_THRESH_4, dsc_cfg->rc_buf_thresh[4]);
DEFINE_BITFIELD(RC_BUF_THRESH_11, 31, 24)
DEFINE_BITFIELD(RC_BUF_THRESH_10, 23, 16)
DEFINE_BITFIELD(RC_BUF_THRESH_9, 15, 8)
DEFINE_BITFIELD(RC_BUF_THRESH_8, 7, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[10],
RC_BUF_THRESH_11, dsc_cfg->rc_buf_thresh[11],
RC_BUF_THRESH_10, dsc_cfg->rc_buf_thresh[10],
RC_BUF_THRESH_9, dsc_cfg->rc_buf_thresh[9],
RC_BUF_THRESH_8, dsc_cfg->rc_buf_thresh[8]);
DEFINE_BITFIELD(RC_BUF_THRESH_13, 15, 8)
DEFINE_BITFIELD(RC_BUF_THRESH_12, 7, 0)
WRITE32_BITFIELDS(&reg->dsc_pps[11],
RC_BUF_THRESH_13, dsc_cfg->rc_buf_thresh[13],
RC_BUF_THRESH_12, dsc_cfg->rc_buf_thresh[12]);
DEFINE_BITFIELD(RC_RANGE_BPG_OFFSET_ODD, 31, 26)
DEFINE_BITFIELD(RC_RANGE_MAX_QP_ODD, 25, 21)
DEFINE_BITFIELD(RC_RANGE_MIN_QP_ODD, 20, 16)
DEFINE_BITFIELD(RC_RANGE_BPG_OFFSET_EVEN, 15, 10)
DEFINE_BITFIELD(RC_RANGE_MAX_QP_EVEN, 9, 5)
DEFINE_BITFIELD(RC_RANGE_MIN_QP_EVEN, 4, 0)
for (int i = 0; i < 7; i++) {
WRITE32_BITFIELDS(&reg->dsc_pps_rc_range_params[i],
RC_RANGE_BPG_OFFSET_ODD,
dsc_cfg->rc_range_params[2 * i + 1].range_bpg_offset,
RC_RANGE_MAX_QP_ODD,
dsc_cfg->rc_range_params[2 * i + 1].range_max_qp,
RC_RANGE_MIN_QP_ODD,
dsc_cfg->rc_range_params[2 * i + 1].range_min_qp,
RC_RANGE_BPG_OFFSET_EVEN,
dsc_cfg->rc_range_params[2 * i].range_bpg_offset,
RC_RANGE_MAX_QP_EVEN,
dsc_cfg->rc_range_params[2 * i].range_max_qp,
RC_RANGE_MIN_QP_EVEN,
dsc_cfg->rc_range_params[2 * i].range_min_qp);
}
/* Special case for the last register */
WRITE32_BITFIELDS(&reg->dsc_pps_rc_range_params[7],
RC_RANGE_BPG_OFFSET_EVEN,
dsc_cfg->rc_range_params[14].range_bpg_offset,
RC_RANGE_MAX_QP_EVEN, dsc_cfg->rc_range_params[14].range_max_qp,
RC_RANGE_MIN_QP_EVEN, dsc_cfg->rc_range_params[14].range_min_qp);
if (dsc_cfg->dsc_version_minor == 1)
write32(&reg->dsc_shadow, 0x20);
else if (dsc_cfg->dsc_version_minor == 2)
write32(&reg->dsc_shadow, 0x40);
else
printk(BIOS_WARNING, "%s : wrong version minor:%d\n", __func__,
dsc_cfg->dsc_version_minor);
}
static void dsc_config(struct disp_dsc_regs *reg, u16 w, u16 h,
const struct dsc_config *dsc_cfg)
{
bool dsc_enable;
dsc_enable = (dsc_cfg && dsc_cfg->dsc_version_major);
printk(BIOS_INFO, "%s: w:%d, h:%d, dsc enable:%d\n", __func__, w, h, dsc_enable);
if (!dsc_enable) {
setbits32(&reg->dsc_con, DSC_RELAY);
clrsetbits32(&reg->chunk_size, GENMASK(31, 16), w << 16);
clrsetbits32(&reg->pic_w, GENMASK(15, 0), w);
clrsetbits32(&reg->pic_h, GENMASK(15, 0), h);
printk(BIOS_INFO, "%s: DSC_relay mode\n", __func__);
return;
}
dsc_configure_registers(reg, w, h, dsc_cfg);
}
static void blender_config(struct blender *reg, u16 width, u16 height,
enum mtk_disp_blender_layer type)
{
@ -157,17 +420,9 @@ static void dither_start(struct disp_dither_regs *reg)
setbits32(&reg->en, BIT(0));
}
static void dsc_config(struct disp_dsc_regs *reg, u16 width, u16 height)
{
write32(&reg->dsc_con, BIT(5));
write32(&reg->pic_w, width);
write32(&reg->pic_h, height);
write32(&reg->chunk_size, width << 16);
}
static void dsc_start(struct disp_dsc_regs *reg)
{
setbits32(&reg->dsc_con, BIT(0));
setbits32(&reg->dsc_con, DSC_EN);
}
static void ovlsys_path_connect(struct ovlsys_cfg *reg)
@ -325,7 +580,8 @@ static void disp_config_blender(struct blender *const blenders[], size_t size, u
}
}
static void main_disp_path_setup(u16 width, u16 height, u32 vrefresh, enum disp_path_sel path)
static void main_disp_path_setup(u16 width, u16 height, u32 vrefresh, enum disp_path_sel path,
const struct dsc_config *dsc_cfg)
{
u16 w = width;
size_t num_pipe = DUAL_PIPE(path) ? 2 : 1;
@ -361,7 +617,7 @@ static void main_disp_path_setup(u16 width, u16 height, u32 vrefresh, enum disp_
postmask_start(pipes[i].postmask);
dither_config(pipes[i].dither, w, height);
dither_start(pipes[i].dither);
dsc_config(pipes[i].dsc, w, height);
dsc_config(pipes[i].dsc, w, height, dsc_cfg);
dsc_start(pipes[i].dsc);
}
@ -435,7 +691,7 @@ void mtk_ddp_soc_mode_set(u32 fmt, u32 bpp, u32 width, u32 height, u32 vrefresh,
if (width > 0x1FFF || height > 0x1FFF)
printk(BIOS_WARNING, "%s: w/h: %d/%d exceed hw limit %u\n", __func__,
width, height, 0x1FFF);
main_disp_path_setup(width, height, vrefresh, path);
main_disp_path_setup(width, height, vrefresh, path, dsc_config);
ovlsys_layer_config(fmt, bpp, width, height, path);
}

View file

@ -0,0 +1,88 @@
/* 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>
#define RG_DSI_PRD_REF_SEL GENMASK(5, 0)
#define RG_DSI_PRD_REF_MINI 0
#define RG_DSI_PRD_REF_DEF 4
#define RG_DSI_PRD_REF_MAX 7
void mtk_dsi_configure_mipi_tx(struct mipi_tx_regs *mipi_tx_reg, u32 data_rate,
u32 lanes, bool is_cphy)
{
unsigned int txdiv0;
u64 pcw;
/* Select different voltage when different data rate */
if (data_rate < (u32)2500 * MHz) {
clrsetbits32(&mipi_tx_reg->pll_con1, RG_DSI_PRD_REF_SEL, RG_DSI_PRD_REF_MINI);
write32(&mipi_tx_reg->cdphy_preserved, 0xFFFF00F0);
} else {
clrsetbits32(&mipi_tx_reg->pll_con1, RG_DSI_PRD_REF_SEL, RG_DSI_PRD_REF_DEF);
write32(&mipi_tx_reg->cdphy_preserved, 0xFFFF0030);
}
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(mipi_tx_reg);
clrbits32(&mipi_tx_reg->pll_con4, BIT(11) | BIT(10));
setbits32(&mipi_tx_reg->pll_pwr, AD_DSI_PLL_SDM_PWR_ON);
udelay(30);
clrbits32(&mipi_tx_reg->pll_pwr, AD_DSI_PLL_SDM_ISO_EN);
pcw = (u64)(data_rate >> 1) * (1 << txdiv0);
pcw <<= 24;
pcw /= CLK26M_HZ;
write32(&mipi_tx_reg->pll_con0, pcw);
clrsetbits32(&mipi_tx_reg->pll_con1, RG_DSI_PLL_POSDIV, txdiv0 << 8);
udelay(30);
setbits32(&mipi_tx_reg->pll_con1, RG_DSI_PLL_EN);
/* BG_LPF_EN / BG_CORE_EN */
write32(&mipi_tx_reg->lane_con, 0x3FFF0180);
udelay(40);
write32(&mipi_tx_reg->lane_con, 0x3FFF00C0);
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
mtk_dsi_cphy_enable(mipi_tx_reg);
/* Switch OFF each Lane */
clrbits32(&mipi_tx_reg->d0_sw_ctl_en, DSI_SW_CTL_EN);
clrbits32(&mipi_tx_reg->d1_sw_ctl_en, DSI_SW_CTL_EN);
clrbits32(&mipi_tx_reg->d2_sw_ctl_en, DSI_SW_CTL_EN);
clrbits32(&mipi_tx_reg->d3_sw_ctl_en, DSI_SW_CTL_EN);
clrbits32(&mipi_tx_reg->ck_sw_ctl_en, DSI_SW_CTL_EN);
if (CONFIG(MEDIATEK_DSI_CPHY) && is_cphy)
mtk_dsi_cphy_disable_ck_mode(mipi_tx_reg);
else
mtk_dsi_dphy_disable_ck_mode(mipi_tx_reg);
}
void mtk_dsi_reset(struct dsi_regs *dsi_reg)
{
write32(&dsi_reg->dsi_shadow_ctrl, DSI_FORCE_COMMIT_ALWAYS);
write32(&dsi_reg->dsi_con_ctrl, 1);
write32(&dsi_reg->dsi_con_ctrl, 0);
}

View file

@ -539,17 +539,55 @@ check_member(disp_postmask_regs, size, 0x30);
struct disp_dsc_regs {
u32 dsc_con;
u32 reserved0x4[5];
u32 dsc_inten;
u32 dsc_intsta;
u32 dsc_intack;
u32 dsc_sta;
u32 dsc_spr;
u32 pic_w;
u32 pic_h;
u32 reserved0x20;
u32 reserved0x24;
u32 dsc_slice_w;
u32 dsc_slice_h;
u32 chunk_size;
u32 dsc_buf_size;
u32 dsc_mode;
u32 dsc_cfg;
u32 dsc_pad;
u32 dsc_enc_width;
u32 dsc_pic_pre_pad_size;
u32 dsc_pic_pre_pad_value;
u32 reserved0[6];
u32 dsc_dbg_con;
u32 dsc_cksm_mon0;
u32 dsc_cksm_mon1;
u32 dsc_resv;
u32 dsc_obuf;
u32 dsc_obuf_mon;
u32 dsc_mute_con;
u32 dsc_ddren;
u32 dsc_pps[12];
u32 dsc_pps_rc_range_params[8];
u32 reserved1[12];
u32 dsc_dbg[21];
u32 reserved2[3];
u32 dsc_enc_dbg[5];
u32 dsc_enc_cov;
u32 reserved3[34];
u32 dsc_shadow;
u32 reserved4[7];
u32 dsc_dummy;
u32 reserved5;
u32 shadow_ctrl;
u32 reserved6;
u32 dsc_up_inten;
u32 dsc_up_intsta;
u32 dsc_up_intack;
};
check_member(disp_dsc_regs, dsc_con, 0x0);
check_member(disp_dsc_regs, pic_w, 0x18);
check_member(disp_dsc_regs, pic_h, 0x1C);
check_member(disp_dsc_regs, chunk_size, 0x28);
check_member(disp_dsc_regs, dsc_slice_w, 0x20);
check_member(disp_dsc_regs, dsc_dbg_con, 0x60);
check_member(disp_dsc_regs, dsc_enc_cov, 0x174);
check_member(disp_dsc_regs, dsc_shadow, 0x200);
check_member(disp_dsc_regs, dsc_up_intack, 0x238);
static struct disp_mdp_rsz_regs *const disp_mdp_rsz0_reg = (void *)DISP_MDP_RSZ0_BASE;
static struct disp_mdp_rsz_regs *const disp_mdp_rsz1_reg = (void *)DISP_MDP_RSZ1_BASE;

View file

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
#include <device/mmio.h>
#include <soc/dsi.h>
#define PHY_TIMING_DIV(x) (((x) / 8000) + 1)
void mtk_dsi_dphy_timing_calculation(u32 data_rate_mhz, struct mtk_phy_timing *timing)
{
u32 temp;
timing->lpx = ALIGN_UP(PHY_TIMING_DIV(80 * data_rate_mhz), 2);
timing->da_hs_prepare = ALIGN_UP(PHY_TIMING_DIV(59 * data_rate_mhz + 4 * 1000), 2);
timing->da_hs_zero = PHY_TIMING_DIV(163 * data_rate_mhz + 11 * 1000) -
timing->da_hs_prepare;
temp = data_rate_mhz < 740 ? 443 : 420;
timing->da_hs_trail = PHY_TIMING_DIV(66 * data_rate_mhz + temp * 100);
timing->ta_go = 4 * timing->lpx;
timing->ta_sure = 3 * timing->lpx / 2;
timing->ta_get = 5 * timing->lpx;
timing->da_hs_exit = ALIGN_UP(PHY_TIMING_DIV(118 * data_rate_mhz), 2);
timing->da_hs_sync = 1;
timing->clk_hs_prepare = ALIGN_UP(PHY_TIMING_DIV(57 * data_rate_mhz), 2);
timing->clk_hs_post = PHY_TIMING_DIV(65 * data_rate_mhz + 53 * 1000);
timing->clk_hs_trail = PHY_TIMING_DIV(65 * data_rate_mhz + 52 * 1000);
timing->clk_hs_zero = PHY_TIMING_DIV(330 * data_rate_mhz) - timing->clk_hs_prepare;
timing->clk_hs_exit = PHY_TIMING_DIV(118 * data_rate_mhz);
}