330 lines
9.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Rockchip Electronics Co., Ltd.
*
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
*/
#include "hal/cru_api.h"
#include "rkx110_x120.h"
#include "rkx110_x120_display.h"
#include "rkx110_dsi_rx.h"
#include "rkx120_dsi_tx.h"
int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
{
u32 local_port;
local_port = route->local_port0 ? route->local_port0 : route->local_port1;
switch (local_port) {
case RK_SERDES_RGB_RX:
rkx110_rgb_rx_enable(serdes, route);
break;
case RK_SERDES_LVDS_RX0:
rkx110_lvds_rx_enable(serdes, route, 0);
break;
case RK_SERDES_LVDS_RX1:
rkx110_lvds_rx_enable(serdes, route, 1);
break;
case RK_SERDES_DUAL_LVDS_RX:
rkx110_lvds_rx_enable(serdes, route, 0);
rkx110_lvds_rx_enable(serdes, route, 1);
break;
case RK_SERDES_DSI_RX0:
rkx110_dsi_rx_enable(serdes, route, 0);
break;
case RK_SERDES_DSI_RX1:
rkx110_dsi_rx_enable(serdes, route, 1);
break;
default:
dev_info(serdes->dev, "undefined local port\n");
}
rkx110_display_linktx_enable(serdes, route);
if (route->local_port0) {
rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0);
if (serdes->remote_nr == 2 && serdes->route_nr != 2)
rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1);
if (route->remote0_port0 & RK_SERDES_DSI_TX0)
rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE0);
if (route->remote1_port0 & RK_SERDES_DSI_TX0)
rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1);
}
if (route->local_port1) {
if (serdes->remote_nr == 2)
rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE1);
else
rkx120_display_linkrx_enable(serdes, route, DEVICE_REMOTE0);
if (route->remote1_port0 & RK_SERDES_DSI_TX0)
rkx120_dsi_tx_pre_enable(serdes, route, DEVICE_REMOTE1);
}
return 0;
}
int rk_serdes_display_video_start(struct rk_serdes *serdes,
struct rk_serdes_route *route, bool enable)
{
if (route->local_port0) {
if (route->route_flag & ROUTE_MULTI_CHANNEL) {
if (route->route_flag & ROUTE_MULTI_REMOTE) {
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable);
} else {
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable);
}
rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable);
rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable);
} else {
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, enable);
rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, enable);
}
} else {
if (serdes->remote_nr == 2)
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, enable);
else
rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, enable);
rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, enable);
}
return 0;
}
int rk_serdes_display_route_init(struct rk_serdes *serdes)
{
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, false);
if (serdes->remote_nr == 2)
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE1, false);
else
rkx120_linkrx_engine_enable(serdes, 1, DEVICE_REMOTE0, false);
rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, false);
rkx110_linktx_channel_enable(serdes, 1, DEVICE_LOCAL, false);
return 0;
}
int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route)
{
if (route->remote0_port0) {
switch (route->remote0_port0) {
case RK_SERDES_RGB_TX:
rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE0);
break;
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
break;
case RK_SERDES_DUAL_LVDS_TX:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
break;
case RK_SERDES_DSI_TX0:
rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE0);
break;
default:
dev_err(serdes->dev, "undefined remote0_port0\n");
break;
}
}
if (route->remote1_port0) {
switch (route->remote1_port0) {
case RK_SERDES_RGB_TX:
rkx120_rgb_tx_enable(serdes, route, DEVICE_REMOTE1);
break;
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1);
break;
case RK_SERDES_DUAL_LVDS_TX:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 0);
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE1, 1);
break;
case RK_SERDES_DSI_TX0:
rkx120_dsi_tx_enable(serdes, route, DEVICE_REMOTE1);
break;
default:
dev_err(serdes->dev, "undefined remote1_port0\n");
break;
}
}
if (route->remote0_port1) {
switch (route->remote0_port1) {
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
break;
default:
dev_err(serdes->dev, "undefined remote0_port1\n");
break;
}
}
if (serdes->version == SERDES_V1)
rk_serdes_display_video_start(serdes, route, true);
rkx110_linktx_video_enable(serdes, DEVICE_LOCAL, true);
return 0;
}
int rk_serdes_display_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route)
{
if (route->remote0_port0) {
switch (route->remote0_port0) {
case RK_SERDES_RGB_TX:
break;
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
break;
case RK_SERDES_DUAL_LVDS_TX:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
break;
case RK_SERDES_DSI_TX0:
rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0);
break;
default:
dev_err(serdes->dev, "undefined remote0_port0\n");
break;
}
}
if (route->remote1_port0) {
switch (route->remote1_port0) {
case RK_SERDES_RGB_TX:
break;
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 1);
break;
case RK_SERDES_DUAL_LVDS_TX:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 0);
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE1, 1);
break;
case RK_SERDES_DSI_TX0:
rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE1);
break;
default:
dev_err(serdes->dev, "undefined remote1_port0\n");
break;
}
}
if (route->remote0_port1) {
switch (route->remote0_port1) {
case RK_SERDES_LVDS_TX0:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 0);
break;
case RK_SERDES_LVDS_TX1:
rkx120_lvds_tx_disable(serdes, route, DEVICE_REMOTE0, 1);
break;
default:
dev_err(serdes->dev, "undefined remote0_port1\n");
break;
}
}
if (serdes->version == SERDES_V1) {
rk_serdes_display_video_start(serdes, route, false);
if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) {
rkx110_set_stream_source(serdes, RK_SERDES_RGB_RX,
DEVICE_LOCAL);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
}
if ((route->local_port0 == RK_SERDES_DSI_RX0) ||
(route->local_port1 == RK_SERDES_DSI_RX0)) {
serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
0x1400140);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
}
if ((route->local_port0 == RK_SERDES_DSI_RX1) ||
(route->local_port1 == RK_SERDES_DSI_RX1)) {
serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
0x2800280);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
}
}
return 0;
}
int rk_serdes_display_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
{
if (route->remote0_port0 & RK_SERDES_DSI_TX0)
rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE0);
if (route->remote1_port0 & RK_SERDES_DSI_TX0)
rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE1);
if (serdes->version == SERDES_V1) {
if (route->local_port0 == RK_SERDES_DUAL_LVDS_RX) {
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
rkx110_set_stream_source(serdes, RK_SERDES_DUAL_LVDS_RX,
DEVICE_LOCAL);
}
if ((route->local_port0 == RK_SERDES_DSI_RX0) ||
(route->local_port1 == RK_SERDES_DSI_RX0)) {
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
0x1400000);
}
if ((route->local_port0 == RK_SERDES_DSI_RX1) ||
(route->local_port1 == RK_SERDES_DSI_RX1)) {
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
0x2800000);
}
}
return 0;
}