mfd: rkx110_x120: register 2 panel when attach 2 screen
Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com> Change-Id: I9469fd964871ca26484f95d532a87db7a936937d
This commit is contained in:
@@ -12,6 +12,7 @@ rkx110_x120-objs := \
|
||||
rkx110_combrxphy.o \
|
||||
rkx110_dsi_rx.o \
|
||||
rkx110_x120_core.o \
|
||||
rkx110_x120_display.o\
|
||||
rkx110_linktx.o \
|
||||
rkx110.o \
|
||||
rkx120.o \
|
||||
|
||||
@@ -295,9 +295,11 @@ int rkx110_rgb_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route
|
||||
|
||||
int rkx110_lvds_rx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, int id)
|
||||
{
|
||||
rkx110_combrxphy_set_mode(serdes, COMBRX_PHY_MODE_VIDEO_LVDS);
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy;
|
||||
|
||||
rkx110_combrxphy_power_on(serdes, id ? COMBPHY_1 : COMBPHY_0);
|
||||
rkx110_combrxphy_set_mode(combrxphy, COMBRX_PHY_MODE_VIDEO_LVDS);
|
||||
rkx110_combrxphy_power_on(serdes, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,15 +114,18 @@
|
||||
#define LVDS0_MSBSEL(x) HIWORD_UPDATE(x, BIT(2), 2)
|
||||
|
||||
static void
|
||||
rkx110_combrxphy_dsi_timing_init(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
rkx110_combrxphy_dsi_timing_init(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct hwclk *hwclk = ser->chip[DEVICE_LOCAL].hwclk;
|
||||
struct rkx110_combrxphy *combrxphy = &ser->combrxphy;
|
||||
struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
|
||||
struct hwclk *hwclk = ser->chip[dev_id].hwclk;
|
||||
struct i2c_client *client = ser->chip[dev_id].client;
|
||||
u32 val = 0;
|
||||
u32 grf_base;
|
||||
|
||||
@@ -144,7 +147,7 @@ static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_i
|
||||
serdes_combphy_get_default_config(combrxphy->rate,
|
||||
&combrxphy->mipi_dphy_cfg);
|
||||
|
||||
switch (ser->dsi_rx.lanes) {
|
||||
switch (combrxphy->lanes) {
|
||||
case 4:
|
||||
val |= LANE3_ENABLE(1);
|
||||
fallthrough;
|
||||
@@ -164,12 +167,14 @@ static void rkx110_combrxphy_dsi_power_on(struct rk_serdes *ser, enum comb_phy_i
|
||||
ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0,
|
||||
PHY_MODE(COMBRX_PHY_MODE_VIDEO_MIPI) | val);
|
||||
|
||||
rkx110_combrxphy_dsi_timing_init(ser, id);
|
||||
rkx110_combrxphy_dsi_timing_init(ser, combrxphy, dev_id, id);
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
|
||||
struct i2c_client *client = ser->chip[dev_id].client;
|
||||
u32 grf_base;
|
||||
|
||||
grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE;
|
||||
@@ -178,9 +183,11 @@ static void rkx110_combrxphy_dsi_power_off(struct rk_serdes *ser, enum comb_phy_
|
||||
LANE1_ENABLE(0) | LANE0_ENABLE(0));
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
|
||||
struct i2c_client *client = ser->chip[dev_id].client;
|
||||
u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -209,9 +216,11 @@ static void rkx110_combrxphy_lvds_power_on(struct rk_serdes *ser, enum comb_phy_
|
||||
LVDS_RX1_PD(0) | LVDS_RX0_PD(0));
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct i2c_client *client = ser->chip[DEVICE_LOCAL].client;
|
||||
struct i2c_client *client = ser->chip[dev_id].client;
|
||||
u32 grf_base = id ? RKX110_GRF_MIPI1_BASE : RKX110_GRF_MIPI0_BASE;
|
||||
|
||||
ser->i2c_write_reg(client, grf_base + GRF_MIPI_RX_CON0,
|
||||
@@ -219,62 +228,65 @@ static void rkx110_combrxphy_lvds_power_off(struct rk_serdes *ser, enum comb_phy
|
||||
LVDS_RX1_PD(1) | LVDS_RX0_PD(1));
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_lvds_camera_power_on(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_lvds_camera_power_on(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
}
|
||||
|
||||
static void rkx110_combrxphy_lvds_camera_power_off(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
static void rkx110_combrxphy_lvds_camera_power_off(struct rk_serdes *ser,
|
||||
struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
}
|
||||
|
||||
void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
void rkx110_combrxphy_power_on(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct rkx110_combrxphy *combrxphy = &ser->combrxphy;
|
||||
|
||||
switch (combrxphy->mode) {
|
||||
case COMBRX_PHY_MODE_VIDEO_MIPI:
|
||||
rkx110_combrxphy_dsi_power_on(ser, id);
|
||||
rkx110_combrxphy_dsi_power_on(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
case COMBRX_PHY_MODE_VIDEO_LVDS:
|
||||
rkx110_combrxphy_lvds_power_on(ser, id);
|
||||
rkx110_combrxphy_lvds_power_on(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
case COMBRX_PHY_MODE_LVDS_CAMERA:
|
||||
rkx110_combrxphy_lvds_camera_power_on(ser, id);
|
||||
rkx110_combrxphy_lvds_camera_power_on(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id)
|
||||
void rkx110_combrxphy_power_off(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id)
|
||||
{
|
||||
struct rkx110_combrxphy *combrxphy = &ser->combrxphy;
|
||||
|
||||
switch (combrxphy->mode) {
|
||||
case COMBRX_PHY_MODE_VIDEO_MIPI:
|
||||
rkx110_combrxphy_dsi_power_off(ser, id);
|
||||
rkx110_combrxphy_dsi_power_off(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
case COMBRX_PHY_MODE_VIDEO_LVDS:
|
||||
rkx110_combrxphy_lvds_power_off(ser, id);
|
||||
rkx110_combrxphy_lvds_power_off(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
case COMBRX_PHY_MODE_LVDS_CAMERA:
|
||||
rkx110_combrxphy_lvds_camera_power_off(ser, id);
|
||||
rkx110_combrxphy_lvds_camera_power_off(ser, combrxphy, dev_id, id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate)
|
||||
void rkx110_combrxphy_set_rate(struct rkx110_combrxphy *combrxphy, u64 rate)
|
||||
{
|
||||
struct rkx110_combrxphy *combrxphy = &ser->combrxphy;
|
||||
|
||||
combrxphy->rate = rate;
|
||||
}
|
||||
|
||||
void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode)
|
||||
void rkx110_combrxphy_set_lanes(struct rkx110_combrxphy *combrxphy, uint8_t lanes)
|
||||
{
|
||||
struct rkx110_combrxphy *combrxphy = &ser->combrxphy;
|
||||
combrxphy->lanes = lanes;
|
||||
}
|
||||
|
||||
void rkx110_combrxphy_set_mode(struct rkx110_combrxphy *combrxphy, enum combrx_phy_mode mode)
|
||||
{
|
||||
combrxphy->mode = mode;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,9 @@ static inline int dsi_rx_update_bits(struct rk_serdes *ser,
|
||||
|
||||
void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route, int id)
|
||||
{
|
||||
struct rkx110_dsi_rx *dsi = &ser->dsi_rx;
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx110_dsi_rx *dsi = &sd_panel->dsi_rx;
|
||||
struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy;
|
||||
const struct videomode *vm = &route->vm;
|
||||
unsigned long pixelclock;
|
||||
u32 hactive, vactive;
|
||||
@@ -87,9 +89,10 @@ void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route,
|
||||
|
||||
rate = DIV_ROUND_CLOSEST_ULL(pixelclock, dsi->lanes);
|
||||
|
||||
rkx110_combrxphy_set_mode(ser, COMBRX_PHY_MODE_VIDEO_MIPI);
|
||||
rkx110_combrxphy_set_rate(ser, rate * MSEC_PER_SEC);
|
||||
rkx110_combrxphy_power_on(ser, id ? COMBPHY_1 : COMBPHY_0);
|
||||
rkx110_combrxphy_set_mode(combrxphy, COMBRX_PHY_MODE_VIDEO_MIPI);
|
||||
rkx110_combrxphy_set_rate(combrxphy, rate * MSEC_PER_SEC);
|
||||
rkx110_combrxphy_set_lanes(combrxphy, dsi->lanes);
|
||||
rkx110_combrxphy_power_on(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0);
|
||||
|
||||
csi_base = id ? RKX110_CSI2HOST1_BASE : RKX110_CSI2HOST0_BASE;
|
||||
dsirx_base = id ? RKX110_DSI_RX1_BASE : RKX110_DSI_RX0_BASE;
|
||||
@@ -120,5 +123,8 @@ void rkx110_dsi_rx_enable(struct rk_serdes *ser, struct rk_serdes_route *route,
|
||||
|
||||
void rkx110_dsi_rx_disable(struct rk_serdes *ser, struct rk_serdes_route *route, int id)
|
||||
{
|
||||
rkx110_combrxphy_power_off(ser, id ? COMBPHY_1 : COMBPHY_0);
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx110_combrxphy *combrxphy = &sd_panel->combrxphy;
|
||||
|
||||
rkx110_combrxphy_power_off(ser, combrxphy, DEVICE_LOCAL, id ? COMBPHY_1 : COMBPHY_0);
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#define SER_EN BIT(0)
|
||||
|
||||
#define RKLINK_TX_VIDEO_CTRL LINK_REG(0x0004)
|
||||
#define VIDEO_REPKT_LENGTH_MASK GENMASK(29, 16)
|
||||
#define VIDEO_REPKT_LENGTH(x) UPDATE(x, 29, 16)
|
||||
#define DUAL_LVDS_CYCLE_DIFF(x) UPDATE(x, 13, 4)
|
||||
#define PIXEL_VSYNC_SEL BIT(3)
|
||||
@@ -86,6 +87,7 @@
|
||||
#define DSI_CHANNEL_SWAP UPDATE(2, 31, 30)
|
||||
#define DSI0_SPLIT_MODE UPDATE(0, 31, 30)
|
||||
#define DSI1_SPLIT_MODE UPDATE(3, 31, 30)
|
||||
#define DSI_DST_VPORCH_MASK GENMASK(29, 0)
|
||||
#define DSI_VFP(x) UPDATE(x, 29, 20)
|
||||
#define DSI_VBP(x) UPDATE(x, 19, 10)
|
||||
#define DSI_VSA(x) UPDATE(x, 9, 0)
|
||||
@@ -459,67 +461,93 @@ void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_i
|
||||
serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val);
|
||||
}
|
||||
|
||||
static int rk_serdes_link_tx_ctrl_enable(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route,
|
||||
u8 remote_id)
|
||||
static int rkx110_linktx_ser_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct hwclk *hwclk = serdes->chip[remote_id].hwclk;
|
||||
struct i2c_client *client;
|
||||
struct videomode *vm = &route->vm;
|
||||
u32 ctrl_val, val;
|
||||
u32 rx_src;
|
||||
u32 stream_type;
|
||||
u32 length;
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
client = serdes->chip[DEVICE_LOCAL].client;
|
||||
stream_type = SER_STREAM_DISPLAY;
|
||||
} else {
|
||||
client = serdes->chip[remote_id].client;
|
||||
stream_type = SER_STREAM_CAMERA;
|
||||
}
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SER_EN, enable ? SER_EN : 0);
|
||||
|
||||
serdes->i2c_read_reg(client, RKLINK_TX_SERDES_CTRL, &ctrl_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl_val &= ~(SER_EN | SERDES_DUAL_LANE_EN | SER_CH1_EN | SERDES_MIRROR_EN |
|
||||
CH1_LVDS_SEL_EN);
|
||||
ctrl_val |= stream_type;
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE)
|
||||
ctrl_val |= SERDES_DUAL_LANE_EN;
|
||||
if (serdes->route_flag & ROUTE_MULTI_CHANNEL)
|
||||
ctrl_val |= SER_CH1_EN;
|
||||
if (serdes->route_flag & ROUTE_MULTI_MIRROR)
|
||||
ctrl_val |= SERDES_MIRROR_EN;
|
||||
if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT)
|
||||
ctrl_val |= CH1_LVDS_SEL_EN;
|
||||
static int rk110_linktx_dual_lane_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val);
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SERDES_DUAL_LANE_EN,
|
||||
enable ? SERDES_DUAL_LANE_EN : 0);
|
||||
|
||||
serdes->i2c_read_reg(client, RKLINK_TX_VIDEO_CTRL, &val);
|
||||
rx_src = rk_serdes_get_stream_source(serdes, route->local_port0);
|
||||
val |= rx_src;
|
||||
if (serdes->version == SERDES_V1) {
|
||||
/*
|
||||
* The serdes v1 have a bug when enable video suspend function, which
|
||||
* is used to enhance the i2c frequency. A workaround ways to do it is
|
||||
* reducing the video packet length:
|
||||
* length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16
|
||||
*/
|
||||
length = vm->hactive * 24 / 32 / 16;
|
||||
length = (length + 15) / 16 * 16;
|
||||
val &= ~VIDEO_REPKT_LENGTH(0xffff);
|
||||
val |= VIDEO_REPKT_LENGTH(length);
|
||||
}
|
||||
serdes->i2c_write_reg(client, RKLINK_TX_VIDEO_CTRL, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) {
|
||||
hwclk_set_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX));
|
||||
}
|
||||
void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
ctrl_val |= SER_EN;
|
||||
serdes->i2c_write_reg(client, RKLINK_TX_SERDES_CTRL, ctrl_val);
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, VIDEO_EN, enable ? VIDEO_EN : 0);
|
||||
}
|
||||
|
||||
int rk110_linktx_dual_channel_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SER_CH1_EN,
|
||||
enable ? SER_CH1_EN : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk110_linktx_config_pkg_length(struct rk_serdes *serdes, u8 dev_id, u32 length)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_VIDEO_CTRL, VIDEO_REPKT_LENGTH_MASK,
|
||||
VIDEO_REPKT_LENGTH(length));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk110_linktx_stream_type_cfg(struct rk_serdes *serdes, u8 dev_id)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
if (serdes->stream_type == STREAM_DISPLAY)
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STREAM_TYPE_MASK,
|
||||
SER_STREAM_DISPLAY);
|
||||
else
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, STREAM_TYPE_MASK,
|
||||
SER_STREAM_CAMERA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk110_linktx_replicate_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, SERDES_MIRROR_EN,
|
||||
enable ? SERDES_MIRROR_EN : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkx110_linktx_dual_input_cfg(struct rk_serdes *serdes, u8 dev_id, bool is_lvds)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, CH1_LVDS_SEL_EN,
|
||||
is_lvds ? CH1_LVDS_SEL_EN : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkx110_linktx_input_port_cfg(struct rk_serdes *serdes, u8 dev_id, u32 port)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 val;
|
||||
|
||||
val = rk_serdes_get_stream_source(serdes, port);
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_VIDEO_CTRL, SOURCE_ID_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -530,22 +558,22 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd
|
||||
struct videomode *vm = &route->vm;
|
||||
struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client;
|
||||
struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk;
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx110_dsi_rx *dsi = &sd_panel->dsi_rx;
|
||||
int delay_length;
|
||||
u32 value, type;
|
||||
|
||||
if (id == 0) {
|
||||
hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX,
|
||||
route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX));
|
||||
} else if (id == 1) {
|
||||
if (id) {
|
||||
hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX,
|
||||
route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_1_REC_RKLINK_TX));
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
hwclk_set_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX,
|
||||
route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX110_CPS_DCLK_D_DSI_0_REC_RKLINK_TX));
|
||||
}
|
||||
|
||||
/* config SER_RKLINK_DSI_REC1 */
|
||||
@@ -558,17 +586,25 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd
|
||||
value = DSI_VFP(vm->vfront_porch);
|
||||
value |= DSI_VBP(vm->vback_porch);
|
||||
value |= DSI_VSA(vm->vsync_len);
|
||||
serdes->i2c_write_reg(client, SER_RKLINK_DSI_REC2(id), value);
|
||||
serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(id), DSI_DST_VPORCH_MASK, value);
|
||||
|
||||
if (id)
|
||||
type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(0) : DSI_0_DST(2);
|
||||
else
|
||||
type = (serdes->route_flag & ROUTE_MULTI_CHANNEL) ? DSI_0_DST(3) : DSI_0_DST(1);
|
||||
if (route->local_port0) {
|
||||
if (serdes->route_nr == 2) {
|
||||
type = id ? DSI_0_DST(2) : DSI_0_DST(1);
|
||||
} else {
|
||||
if (id)
|
||||
type = (serdes->channel_nr == 2) ? DSI_0_DST(0) : DSI_0_DST(2);
|
||||
else
|
||||
type = (serdes->channel_nr == 2) ? DSI_0_DST(3) : DSI_0_DST(1);
|
||||
}
|
||||
} else {
|
||||
type = id ? DSI_0_DST(1) : DSI_0_DST(2);
|
||||
}
|
||||
|
||||
serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC2(0), DSI_0_DST_MASK, type);
|
||||
|
||||
/* config SER_RKLINK_DSI_REC3 */
|
||||
if (serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO)
|
||||
if (dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO)
|
||||
delay_length = vm->hsync_len + vm->hback_porch +
|
||||
vm->hactive + vm->hfront_porch;
|
||||
else
|
||||
@@ -582,7 +618,7 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd
|
||||
|
||||
/* config SER_RKLINK_DSI_REC0 */
|
||||
value = DSI_REC_START;
|
||||
if (!(serdes->dsi_rx.mode_flags & SERDES_MIPI_DSI_MODE_VIDEO))
|
||||
if (!(dsi->mode_flags & SERDES_MIPI_DSI_MODE_VIDEO))
|
||||
value |= DSI_CMD_TYPE;
|
||||
|
||||
value |= DSI_HACT(vm->hactive);
|
||||
@@ -592,27 +628,6 @@ static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serd
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk110_linktx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
u8 remote_id = 0;
|
||||
|
||||
rk_serdes_link_tx_ctrl_enable(serdes, route, remote_id);
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DSI_RX0) {
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 1);
|
||||
}
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DSI_RX1) {
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 1);
|
||||
if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk110_ser_pcs_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 pcs_id)
|
||||
{
|
||||
struct i2c_client *client;
|
||||
@@ -634,12 +649,91 @@ static int rk110_ser_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
static int rkx110_display_linktx_ctrl_enable(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route,
|
||||
u8 dev_id)
|
||||
{
|
||||
rk110_linktx_cfg(serdes, route);
|
||||
struct hwclk *hwclk = serdes->chip[dev_id].hwclk;
|
||||
bool enable;
|
||||
bool is_lvds = false;
|
||||
|
||||
rk110_linktx_stream_type_cfg(serdes, dev_id);
|
||||
|
||||
enable = (serdes->lane_nr == 2) ? true : false;
|
||||
rk110_linktx_dual_lane_enable(serdes, dev_id, enable);
|
||||
|
||||
enable = (serdes->channel_nr == 2) ? true : false;
|
||||
rk110_linktx_dual_channel_enable(serdes, dev_id, enable);
|
||||
|
||||
enable = (route->route_flag & ROUTE_MULTI_MIRROR) ? true : false;
|
||||
rk110_linktx_replicate_enable(serdes, dev_id, enable);
|
||||
|
||||
if (((route->local_port0 == RK_SERDES_LVDS_RX0) ||
|
||||
(route->local_port0 == RK_SERDES_LVDS_RX1) ||
|
||||
(route->local_port1 == RK_SERDES_LVDS_RX0) ||
|
||||
(route->local_port1 == RK_SERDES_LVDS_RX1)) &&
|
||||
(serdes->route_nr == 2))
|
||||
is_lvds = true;
|
||||
rkx110_linktx_dual_input_cfg(serdes, dev_id, is_lvds);
|
||||
|
||||
if (route->local_port0) {
|
||||
rkx110_linktx_input_port_cfg(serdes, dev_id, route->local_port0);
|
||||
} else {
|
||||
if (route->local_port1 == RK_SERDES_LVDS_RX0)
|
||||
rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_LVDS_RX1);
|
||||
else if (route->local_port1 == RK_SERDES_LVDS_RX1)
|
||||
rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_LVDS_RX0);
|
||||
else if (route->local_port1 == RK_SERDES_DSI_RX0)
|
||||
rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_DSI_RX1);
|
||||
else if (route->local_port1 == RK_SERDES_DSI_RX1)
|
||||
rkx110_linktx_input_port_cfg(serdes, dev_id, RK_SERDES_DSI_RX0);
|
||||
|
||||
}
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DUAL_LVDS_RX) {
|
||||
hwclk_set_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX, route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX110_CPS_CLK_2X_LVDS_RKLINK_TX));
|
||||
}
|
||||
|
||||
if (serdes->version == SERDES_V1) {
|
||||
/*
|
||||
* The serdes v1 have a bug when enable video suspend function, which
|
||||
* is used to enhance the i2c frequency. A workaround ways to do it is
|
||||
* reducing the video packet length:
|
||||
* length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16
|
||||
*/
|
||||
u32 length;
|
||||
|
||||
length = route->vm.hactive * 24 / 32 / 16;
|
||||
length = (length + 15) / 16 * 16;
|
||||
rk110_linktx_config_pkg_length(serdes, dev_id, length);
|
||||
}
|
||||
|
||||
rkx110_linktx_ser_enable(serdes, dev_id, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx110_display_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
rkx110_display_linktx_ctrl_enable(serdes, route, DEVICE_LOCAL);
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DSI_RX0)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 0);
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DSI_RX1)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 1);
|
||||
|
||||
if (route->local_port1 & RK_SERDES_DSI_RX0)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 0);
|
||||
|
||||
if (route->local_port1 & RK_SERDES_DSI_RX1)
|
||||
rk_serdes_link_tx_dsi_enable(serdes, route, 1);
|
||||
|
||||
rk110_ser_pcs_cfg(serdes, route, 0);
|
||||
rk110_ser_pma_cfg(serdes, route, 0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE) {
|
||||
if (serdes->lane_nr == 2) {
|
||||
rk110_ser_pcs_cfg(serdes, route, 1);
|
||||
rk110_ser_pma_cfg(serdes, route, 1);
|
||||
}
|
||||
@@ -647,13 +741,6 @@ int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_TX_SERDES_CTRL, VIDEO_EN, enable ? VIDEO_EN : 0);
|
||||
}
|
||||
|
||||
void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
@@ -687,7 +774,7 @@ void rkx110_linktx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32
|
||||
}
|
||||
}
|
||||
|
||||
void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
int rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client;
|
||||
u32 val;
|
||||
@@ -707,6 +794,8 @@ void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
dev_err(&client->dev, "wait link ready timeout: 0x%08x\n", val);
|
||||
else
|
||||
dev_info(&client->dev, "link success: 0x%08x\n", val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rkx110_pma_set_rate(struct rk_serdes *serdes, struct rk_serdes_pma_pll *pll,
|
||||
|
||||
@@ -142,11 +142,14 @@ struct rkx120_combtxphy {
|
||||
|
||||
struct rkx110_combrxphy {
|
||||
enum combrx_phy_mode mode;
|
||||
uint8_t lanes;
|
||||
u64 rate;
|
||||
struct configure_opts_combphy mipi_dphy_cfg;
|
||||
};
|
||||
|
||||
struct rkx120_dsi_tx {
|
||||
struct rkx120_combtxphy *combtxphy;
|
||||
|
||||
int bpp; /* 24/18/16*/
|
||||
enum serdes_dsi_bus_format bus_format;
|
||||
enum serdes_dsi_mode_flags mode_flags;
|
||||
@@ -221,6 +224,7 @@ struct rk_serdes_route {
|
||||
u32 remote0_port1;
|
||||
u32 remote1_port0;
|
||||
u32 remote1_port1;
|
||||
u32 route_flag;
|
||||
};
|
||||
|
||||
struct rk_serdes_chip {
|
||||
@@ -282,12 +286,10 @@ struct rk_serdes {
|
||||
struct videomode *vm;
|
||||
u32 stream_type;
|
||||
u32 version;
|
||||
u32 route_flag;
|
||||
u8 remote_nr;
|
||||
struct rkx110_combrxphy combrxphy;
|
||||
struct rkx110_dsi_rx dsi_rx;
|
||||
struct rkx120_combtxphy combtxphy;
|
||||
struct rkx120_dsi_tx dsi_tx;
|
||||
u8 lane_nr;
|
||||
u8 channel_nr;
|
||||
u8 route_nr;
|
||||
|
||||
int (*i2c_read_reg)(struct i2c_client *client, u32 addr, u32 *value);
|
||||
int (*i2c_write_reg)(struct i2c_client *client, u32 addr, u32 value);
|
||||
@@ -318,13 +320,12 @@ struct panel_cmds {
|
||||
int cmd_cnt;
|
||||
};
|
||||
|
||||
struct rk_serdes_panel;
|
||||
struct rk_serdes_panel {
|
||||
struct drm_panel panel;
|
||||
struct device *dev;
|
||||
struct rk_serdes *parent;
|
||||
struct rk_serdes_route route;
|
||||
unsigned int bus_format;
|
||||
int link_mode;
|
||||
struct rk_serdes_panel *secondary;
|
||||
|
||||
struct panel_cmds *on_cmds;
|
||||
struct panel_cmds *off_cmds;
|
||||
@@ -332,14 +333,25 @@ struct rk_serdes_panel {
|
||||
struct regulator *supply;
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct gpio_desc *reset_gpio;
|
||||
|
||||
struct rk_serdes_route route;
|
||||
struct rkx110_combrxphy combrxphy;
|
||||
struct rkx110_dsi_rx dsi_rx;
|
||||
struct rkx120_combtxphy combtxphy;
|
||||
struct rkx120_dsi_tx dsi_tx;
|
||||
|
||||
unsigned int bus_format;
|
||||
unsigned int id;
|
||||
bool multi_panel;
|
||||
};
|
||||
|
||||
int rkx110_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
int rkx110_display_linktx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
void rkx110_linktx_video_enable(struct rk_serdes *serdes, u8 dev_id, bool enable);
|
||||
void rkx110_linktx_channel_enable(struct rk_serdes *serdes, u8 ch_id, u8 dev_id, bool enable);
|
||||
void rkx120_linkrx_engine_enable(struct rk_serdes *serdes, u8 en_id, u8 dev_id, bool enable);
|
||||
void rkx110_set_stream_source(struct rk_serdes *serdes, int local_port, u8 dev_id);
|
||||
int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id);
|
||||
int rkx120_display_linkrx_enable(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, u8 remote_id);
|
||||
int rkx120_rgb_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id);
|
||||
int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id,
|
||||
u8 phy_id);
|
||||
@@ -357,8 +369,8 @@ void rkx110_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_
|
||||
void rkx120_pcs_enable(struct rk_serdes *serdes, bool enable, u8 pcs_id, u8 dev_id);
|
||||
void rkx110_ser_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id);
|
||||
void rkx120_des_pma_enable(struct rk_serdes *serdes, bool enable, u8 pma_id, u8 remote_id);
|
||||
void rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||
void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||
int rkx110_linktx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||
int rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id);
|
||||
void rkx110_x120_pattern_gen_debugfs_create_file(struct pattern_gen *pattern_gen,
|
||||
struct rk_serdes_chip *chip,
|
||||
struct dentry *dentry);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include "rkx110_x120.h"
|
||||
#include "rkx110_x120_display.h"
|
||||
#include "rkx110_reg.h"
|
||||
#include "rkx110_dsi_rx.h"
|
||||
#include "rkx120_dsi_tx.h"
|
||||
@@ -27,6 +28,10 @@ static const struct mfd_cell rkx110_x120_devs[] = {
|
||||
.name = "rockchip-serdes-panel",
|
||||
.of_compatible = "rockchip,serdes-panel",
|
||||
},
|
||||
{
|
||||
.name = "rockchip-serdes-panel1",
|
||||
.of_compatible = "rockchip,serdes-panel",
|
||||
},
|
||||
{
|
||||
.name = "rkx120-pwm0",
|
||||
.of_compatible = "rockchip,rkx120-pwm",
|
||||
@@ -145,26 +150,40 @@ static bool rk_serdes_debug_mode(struct rk_serdes *serdes)
|
||||
return serdes->rkx110_debug || serdes->rkx120_debug;
|
||||
}
|
||||
|
||||
static void rk_serdes_wait_link_ready(struct rk_serdes *serdes)
|
||||
static int rk_serdes_wait_link_ready(struct rk_serdes *serdes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (serdes->stream_type == STREAM_DISPLAY) {
|
||||
rkx110_linktx_wait_link_ready(serdes, 0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE) {
|
||||
ret = rkx110_linktx_wait_link_ready(serdes, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (serdes->lane_nr == 2) {
|
||||
rkx110_ser_pma_enable(serdes, true, 1, DEVICE_LOCAL);
|
||||
if (!(serdes->route_flag & ROUTE_MULTI_REMOTE))
|
||||
if (!(serdes->remote_nr == 2))
|
||||
rkx120_des_pma_enable(serdes, true, 1, DEVICE_REMOTE0);
|
||||
rkx110_linktx_wait_link_ready(serdes, 1);
|
||||
ret = rkx110_linktx_wait_link_ready(serdes, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
rkx120_linkrx_wait_link_ready(serdes, 0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE) {
|
||||
ret = rkx120_linkrx_wait_link_ready(serdes, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (serdes->lane_nr == 2) {
|
||||
rkx120_des_pma_enable(serdes, true, 1, DEVICE_LOCAL);
|
||||
if (!(serdes->route_flag & ROUTE_MULTI_REMOTE))
|
||||
if (!(serdes->remote_nr == 2))
|
||||
rkx110_ser_pma_enable(serdes, true, 1, DEVICE_REMOTE0);
|
||||
rkx120_linkrx_wait_link_ready(serdes, 1);
|
||||
ret = rkx120_linkrx_wait_link_ready(serdes, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk_serdes_print_rate(struct rk_serdes *serdes, enum rk_serdes_rate rate)
|
||||
@@ -336,9 +355,9 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat
|
||||
if (serdes->stream_type == STREAM_DISPLAY) {
|
||||
rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_LOCAL);
|
||||
rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_REMOTE0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE) {
|
||||
if (serdes->lane_nr == 2) {
|
||||
rkx110_pma_set_rate(serdes, &rkx110_pll, 1, DEVICE_LOCAL);
|
||||
if (serdes->route_flag & ROUTE_MULTI_REMOTE)
|
||||
if (serdes->remote_nr == 2)
|
||||
rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_REMOTE1);
|
||||
else
|
||||
rkx120_pma_set_rate(serdes, &rkx120_pll, 1, DEVICE_REMOTE0);
|
||||
@@ -349,9 +368,9 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat
|
||||
} else {
|
||||
rkx120_pma_set_rate(serdes, &rkx120_pll, 0, DEVICE_LOCAL);
|
||||
rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_REMOTE0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LANE) {
|
||||
if (serdes->lane_nr == 2) {
|
||||
rkx120_pma_set_rate(serdes, &rkx120_pll, 1, DEVICE_LOCAL);
|
||||
if (serdes->route_flag & ROUTE_MULTI_REMOTE)
|
||||
if (serdes->remote_nr == 2)
|
||||
rkx110_pma_set_rate(serdes, &rkx110_pll, 0, DEVICE_REMOTE1);
|
||||
else
|
||||
rkx110_pma_set_rate(serdes, &rkx110_pll, 1, DEVICE_REMOTE0);
|
||||
@@ -366,225 +385,6 @@ static void rk_serdes_set_rate(struct rk_serdes *serdes, enum rk_serdes_rate rat
|
||||
serdes->rate = rate;
|
||||
}
|
||||
|
||||
static int rk_serdes_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
if (rk_serdes_debug_mode(serdes))
|
||||
return 0;
|
||||
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
switch (route->local_port0) {
|
||||
case RK_SERDES_RGB_RX:
|
||||
rkx110_rgb_rx_enable(serdes, route);
|
||||
break;
|
||||
case RK_SERDES_LVDS_RX0:
|
||||
rkx110_lvds_rx_enable(serdes, route, 0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT)
|
||||
rkx110_lvds_rx_enable(serdes, route, 1);
|
||||
break;
|
||||
case RK_SERDES_LVDS_RX1:
|
||||
rkx110_lvds_rx_enable(serdes, route, 1);
|
||||
if (serdes->route_flag & ROUTE_MULTI_LVDS_INPUT)
|
||||
rkx110_lvds_rx_enable(serdes, route, 0);
|
||||
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);
|
||||
if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT)
|
||||
rkx110_dsi_rx_enable(serdes, route, 1);
|
||||
break;
|
||||
case RK_SERDES_DSI_RX1:
|
||||
rkx110_dsi_rx_enable(serdes, route, 1);
|
||||
if (serdes->route_flag & ROUTE_MULTI_DSI_INPUT)
|
||||
rkx110_dsi_rx_enable(serdes, route, 0);
|
||||
break;
|
||||
default:
|
||||
dev_info(serdes->dev, "undefined local port0");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rkx110_linktx_enable(serdes, route);
|
||||
|
||||
rkx120_linkrx_enable(serdes, route, DEVICE_REMOTE0);
|
||||
if (serdes->route_flag & ROUTE_MULTI_REMOTE)
|
||||
rkx120_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);
|
||||
} else {
|
||||
/* for camera stream */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_serdes_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
if (rk_serdes_debug_mode(serdes))
|
||||
return 0;
|
||||
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
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");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (serdes->route_flag & ROUTE_MULTI_REMOTE) {
|
||||
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");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (serdes->route_flag & ROUTE_MULTI_CHANNEL) {
|
||||
if (route->remote0_port1 & RK_SERDES_LVDS_TX0) {
|
||||
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 0);
|
||||
} else if (route->remote0_port1 & RK_SERDES_LVDS_TX1) {
|
||||
rkx120_lvds_tx_enable(serdes, route, DEVICE_REMOTE0, 1);
|
||||
} else {
|
||||
dev_err(serdes->dev, "undefined remote0_port1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (serdes->version == SERDES_V1) {
|
||||
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, true);
|
||||
rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, true);
|
||||
}
|
||||
|
||||
rkx110_linktx_video_enable(serdes, DEVICE_LOCAL, true);
|
||||
} else {
|
||||
/* for camera stream */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_serdes_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
if (route->remote0_port0 & RK_SERDES_DSI_TX0)
|
||||
rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0);
|
||||
|
||||
if (serdes->version == SERDES_V1) {
|
||||
rkx120_linkrx_engine_enable(serdes, 0, DEVICE_REMOTE0, false);
|
||||
rkx110_linktx_channel_enable(serdes, 0, DEVICE_LOCAL, 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;
|
||||
}
|
||||
|
||||
static int rk_serdes_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route)
|
||||
{
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
if (route->remote0_port0 & RK_SERDES_DSI_TX0)
|
||||
rkx120_dsi_tx_post_disable(serdes, route, DEVICE_REMOTE0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int rk_serdes_set_hwpin(struct rk_serdes *serdes, struct i2c_client *client,
|
||||
int pintype, int bank, uint32_t mpins, uint32_t param)
|
||||
{
|
||||
@@ -610,11 +410,17 @@ static void rk_serdes_add_callback(struct rk_serdes *serdes)
|
||||
serdes->i2c_read_reg = rk_serdes_i2c_read;
|
||||
serdes->i2c_write_reg = rk_serdes_i2c_write;
|
||||
serdes->i2c_update_bits = rk_serdes_i2c_update_bits;
|
||||
serdes->route_prepare = rk_serdes_route_prepare;
|
||||
serdes->route_enable = rk_serdes_route_enable;
|
||||
serdes->route_disable = rk_serdes_route_disable;
|
||||
serdes->route_unprepare = rk_serdes_route_unprepare;
|
||||
serdes->set_hwpin = rk_serdes_set_hwpin;
|
||||
|
||||
if (rk_serdes_debug_mode(serdes))
|
||||
return;
|
||||
|
||||
if (serdes->stream_type == STREAM_DISPLAY) {
|
||||
serdes->route_prepare = rk_serdes_display_route_prepare;
|
||||
serdes->route_enable = rk_serdes_display_route_enable;
|
||||
serdes->route_disable = rk_serdes_display_route_disable;
|
||||
serdes->route_unprepare = rk_serdes_display_route_unprepare;
|
||||
}
|
||||
}
|
||||
|
||||
static int rk_serdes_passthrough_init(struct rk_serdes *serdes)
|
||||
@@ -956,6 +762,9 @@ static int rk_serdes_add_remote_i2c_device(struct rk_serdes *serdes)
|
||||
i2c_set_clientdata(client, serdes);
|
||||
}
|
||||
|
||||
if (serdes->remote_nr == 2)
|
||||
serdes->lane_nr = 2;
|
||||
|
||||
if (serdes->remote_nr == 0)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1071,6 +880,7 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
|
||||
struct device_node *disp_np;
|
||||
struct rk_serdes *serdes;
|
||||
int ret;
|
||||
bool dual_lane;
|
||||
|
||||
serdes = devm_kzalloc(dev, sizeof(*serdes), GFP_KERNEL);
|
||||
if (!serdes)
|
||||
@@ -1161,6 +971,11 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (serdes->remote_nr != 2) {
|
||||
dual_lane = device_property_read_bool(dev, "dual-lane");
|
||||
serdes->lane_nr = dual_lane ? 2 : 1;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(dev, -1, rkx110_x120_devs, ARRAY_SIZE(rkx110_x120_devs),
|
||||
NULL, 0, NULL);
|
||||
if (ret) {
|
||||
@@ -1198,6 +1013,9 @@ static int rk_serdes_i2c_probe(struct i2c_client *client, const struct i2c_devic
|
||||
rk_serdes_irq_enable(serdes);
|
||||
enable_irq(serdes->irq);
|
||||
|
||||
if (serdes->stream_type == STREAM_DISPLAY)
|
||||
rk_serdes_display_route_init(serdes);
|
||||
|
||||
out:
|
||||
rk_serdes_debugfs_init(serdes);
|
||||
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
// 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_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;
|
||||
}
|
||||
|
||||
static 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 & RK_SERDES_DSI_TX0)
|
||||
rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE0);
|
||||
|
||||
if (route->remote1_port0 & RK_SERDES_DSI_TX0)
|
||||
rkx120_dsi_tx_disable(serdes, route, DEVICE_REMOTE1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
|
||||
*
|
||||
* Author: Zhang Yubing <yubing.zhang@rock-chips.com>
|
||||
*/
|
||||
|
||||
#ifndef _RKX110_RKX120_DISPLAY_H
|
||||
#define _RKX110_RKX120_DISPLAY_H
|
||||
|
||||
int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
int rk_serdes_display_route_disable(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
int rk_serdes_display_route_unprepare(struct rk_serdes *serdes, struct rk_serdes_route *route);
|
||||
int rk_serdes_display_route_init(struct rk_serdes *serdes);
|
||||
|
||||
#endif
|
||||
@@ -30,12 +30,8 @@ static inline struct rk_serdes_panel *to_serdes_panel(struct drm_panel *panel)
|
||||
return container_of(panel, struct rk_serdes_panel, panel);
|
||||
}
|
||||
|
||||
static int serdes_panel_prepare(struct drm_panel *panel)
|
||||
static int serdes_panel_hw_prepare(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes_route *route = &sd_panel->route;
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
|
||||
if (sd_panel->supply) {
|
||||
int err;
|
||||
|
||||
@@ -58,16 +54,47 @@ static int serdes_panel_prepare(struct drm_panel *panel)
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_dsi_prepare(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
|
||||
if (sd_panel->id == 0 && sd_panel->route.remote0_port0 == RK_SERDES_DSI_TX0 &&
|
||||
!!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE0,
|
||||
sd_panel->on_cmds);
|
||||
|
||||
if (sd_panel->id == 1 && sd_panel->route.remote1_port0 == RK_SERDES_DSI_TX0 &&
|
||||
!!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE1,
|
||||
sd_panel->on_cmds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
int ret;
|
||||
|
||||
ret = serdes_panel_hw_prepare(sd_panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (sd_panel->secondary) {
|
||||
ret = serdes_panel_hw_prepare(sd_panel->secondary);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (serdes->route_prepare)
|
||||
serdes->route_prepare(serdes, &sd_panel->route);
|
||||
|
||||
if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0,
|
||||
sd_panel->on_cmds);
|
||||
|
||||
if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1,
|
||||
sd_panel->on_cmds);
|
||||
serdes_panel_dsi_prepare(sd_panel);
|
||||
if (sd_panel->secondary)
|
||||
serdes_panel_dsi_prepare(sd_panel->secondary);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -76,10 +103,19 @@ static int serdes_panel_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
int ret;
|
||||
|
||||
if (serdes->route_enable)
|
||||
serdes->route_enable(serdes, &sd_panel->route);
|
||||
|
||||
if (sd_panel->secondary) {
|
||||
ret = backlight_enable(sd_panel->secondary->panel.backlight);
|
||||
if (ret < 0) {
|
||||
dev_err(sd_panel->dev, "failed to enable backlight: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -87,7 +123,15 @@ static int serdes_panel_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
int ret;
|
||||
|
||||
if (sd_panel->secondary) {
|
||||
ret = backlight_disable(sd_panel->secondary->panel.backlight);
|
||||
if (ret < 0) {
|
||||
dev_err(sd_panel->dev, "failed to disable backlight: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (serdes->route_disable)
|
||||
serdes->route_disable(serdes, &sd_panel->route);
|
||||
@@ -95,22 +139,8 @@ static int serdes_panel_disable(struct drm_panel *panel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_unprepare(struct drm_panel *panel)
|
||||
static int serdes_panel_hw_unprepare(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes_route *route = &sd_panel->route;
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
|
||||
if (route->remote0_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE0,
|
||||
sd_panel->off_cmds);
|
||||
|
||||
if (route->remote1_port0 == RK_SERDES_DSI_TX0 && !!(sd_panel->on_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, DEVICE_REMOTE1,
|
||||
sd_panel->off_cmds);
|
||||
if (serdes->route_unprepare)
|
||||
serdes->route_unprepare(serdes, &sd_panel->route);
|
||||
|
||||
if (sd_panel->reset_gpio) {
|
||||
gpiod_set_value_cansleep(sd_panel->reset_gpio, 0);
|
||||
mdelay(20);
|
||||
@@ -127,6 +157,42 @@ static int serdes_panel_unprepare(struct drm_panel *panel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_dsi_unprepare(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
|
||||
if (sd_panel->id == 0 && sd_panel->route.remote0_port0 == RK_SERDES_DSI_TX0 &&
|
||||
!!(sd_panel->off_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE0,
|
||||
sd_panel->off_cmds);
|
||||
|
||||
if (sd_panel->id == 1 && sd_panel->route.remote1_port0 == RK_SERDES_DSI_TX0 &&
|
||||
!!(sd_panel->off_cmds))
|
||||
rkx120_dsi_tx_cmd_seq_xfer(serdes, &sd_panel->dsi_tx, DEVICE_REMOTE1,
|
||||
sd_panel->off_cmds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = to_serdes_panel(panel);
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
|
||||
serdes_panel_dsi_unprepare(sd_panel);
|
||||
if (sd_panel->secondary)
|
||||
serdes_panel_dsi_unprepare(sd_panel->secondary);
|
||||
|
||||
if (serdes->route_unprepare)
|
||||
serdes->route_unprepare(serdes, &sd_panel->route);
|
||||
|
||||
serdes_panel_hw_unprepare(sd_panel);
|
||||
if (sd_panel->secondary)
|
||||
serdes_panel_hw_unprepare(sd_panel->secondary);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_of_get_native_mode(struct rk_serdes_panel *sd_panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
@@ -336,11 +402,10 @@ static struct mipi_dsi_device *serdes_attach_dsi(struct rk_serdes_panel *sd_pane
|
||||
return dsi;
|
||||
}
|
||||
|
||||
static int rkx120_dsi_rx_parse(struct rk_serdes_panel *sd_panel)
|
||||
static int rkx110_dsi_rx_parse(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct device_node *np = sd_panel->dev->of_node;
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
struct rkx110_dsi_rx *dsi_rx = &serdes->dsi_rx;
|
||||
struct rkx110_dsi_rx *dsi_rx = &sd_panel->dsi_rx;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct device_node *dsi_node;
|
||||
u32 val;
|
||||
@@ -370,12 +435,13 @@ static int rkx120_dsi_rx_parse(struct rk_serdes_panel *sd_panel)
|
||||
static int rkx120_dsi_tx_parse(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct device_node *np = sd_panel->dev->of_node;
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
struct rkx120_dsi_tx *dsi_tx = &serdes->dsi_tx;
|
||||
struct rkx120_dsi_tx *dsi_tx = &sd_panel->dsi_tx;
|
||||
const char *string;
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
dsi_tx->combtxphy = &sd_panel->combtxphy;
|
||||
|
||||
if (of_property_read_u32(np, "dsi-tx,lanes", &val))
|
||||
dsi_tx->lanes = 4;
|
||||
else
|
||||
@@ -418,12 +484,9 @@ static int rkx120_dsi_tx_parse(struct rk_serdes_panel *sd_panel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel)
|
||||
static int serdes_panel_parse_route(struct rk_serdes_panel *sd_panel)
|
||||
{
|
||||
struct rk_serdes_route *route = &sd_panel->route;
|
||||
struct rk_serdes *serdes = sd_panel->parent;
|
||||
u32 lanes;
|
||||
int ret;
|
||||
|
||||
device_property_read_u32(sd_panel->dev, "local-port0", &route->local_port0);
|
||||
device_property_read_u32(sd_panel->dev, "local-port1", &route->local_port1);
|
||||
@@ -431,68 +494,50 @@ static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel)
|
||||
device_property_read_u32(sd_panel->dev, "remote0-port1", &route->remote0_port1);
|
||||
device_property_read_u32(sd_panel->dev, "remote1-port0", &route->remote1_port0);
|
||||
device_property_read_u32(sd_panel->dev, "remote1-port1", &route->remote1_port1);
|
||||
device_property_read_u32(sd_panel->dev, "num-lanes", &lanes);
|
||||
|
||||
serdes->route_flag = 0;
|
||||
|
||||
if (!route->local_port0) {
|
||||
dev_err(sd_panel->dev, "local_port0 should set\n");
|
||||
if (!route->local_port0 && !route->local_port1) {
|
||||
dev_err(sd_panel->dev, "local port should set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!route->remote0_port0) {
|
||||
if (route->local_port0 && !route->remote0_port0) {
|
||||
dev_err(sd_panel->dev, "remote0_port0 should set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (route->local_port1 && !route->remote1_port0) {
|
||||
dev_err(sd_panel->dev, "remote1_port0 should set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (route->remote1_port0 && route->remote0_port1) {
|
||||
dev_err(sd_panel->dev, "too many output\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
route->frame_mode = SERDES_FRAME_NORMAL_MODE;
|
||||
route->route_flag = 0;
|
||||
|
||||
/* 2 video stream output */
|
||||
if (route->remote1_port0 || route->remote0_port1) {
|
||||
/* 2 video stream output in a route */
|
||||
if (route->local_port0 && (route->remote1_port0 || route->remote0_port1)) {
|
||||
if (route->remote1_port0)
|
||||
serdes->route_flag |= ROUTE_MULTI_REMOTE | ROUTE_MULTI_CHANNEL |
|
||||
route->route_flag |= ROUTE_MULTI_REMOTE | ROUTE_MULTI_CHANNEL|
|
||||
ROUTE_MULTI_LANE;
|
||||
|
||||
if (route->remote0_port1) {
|
||||
if ((route->remote0_port0 == RK_SERDES_LVDS_TX0) &&
|
||||
(route->remote0_port1 == RK_SERDES_LVDS_TX1)) {
|
||||
serdes->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||
route->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||
} else if ((route->remote0_port0 == RK_SERDES_LVDS_TX1) &&
|
||||
(route->remote0_port1 == RK_SERDES_LVDS_TX0)) {
|
||||
serdes->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||
route->route_flag |= ROUTE_MULTI_CHANNEL;
|
||||
} else {
|
||||
dev_err(sd_panel->dev, "invalid multi output type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lanes == 2)
|
||||
serdes->route_flag |= ROUTE_MULTI_LANE;
|
||||
}
|
||||
|
||||
if (route->local_port1) {
|
||||
if ((route->local_port0 == RK_SERDES_DSI_RX0) &&
|
||||
(route->local_port1 == RK_SERDES_DSI_RX1))
|
||||
serdes->route_flag |= ROUTE_MULTI_DSI_INPUT;
|
||||
else if ((route->local_port0 == RK_SERDES_DSI_RX1) &&
|
||||
(route->local_port1 == RK_SERDES_DSI_RX0))
|
||||
serdes->route_flag |= ROUTE_MULTI_DSI_INPUT;
|
||||
else if ((route->local_port0 == RK_SERDES_LVDS_RX0) &&
|
||||
(route->local_port1 == RK_SERDES_LVDS_RX1))
|
||||
serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT;
|
||||
else if ((route->local_port0 == RK_SERDES_LVDS_RX1) &&
|
||||
(route->local_port1 == RK_SERDES_LVDS_RX0))
|
||||
serdes->route_flag |= ROUTE_MULTI_LVDS_INPUT;
|
||||
else {
|
||||
dev_err(sd_panel->dev, "invalid multi input type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
serdes->route_flag |= ROUTE_MULTI_SOURCE;
|
||||
} else {
|
||||
if (route->local_port0) {
|
||||
if (device_property_read_bool(sd_panel->dev, "split-mode")) {
|
||||
/* only dsi input support split mode */
|
||||
if ((route->local_port0 != RK_SERDES_DSI_RX0) &&
|
||||
@@ -510,41 +555,43 @@ static int serdes_panel_parse_dt(struct rk_serdes_panel *sd_panel)
|
||||
else
|
||||
route->frame_mode = SERDES_SP_LEFT_RIGHT_SPLIT;
|
||||
|
||||
serdes->route_flag |= ROUTE_MULTI_SPLIT;
|
||||
route->route_flag |= ROUTE_MULTI_SPLIT;
|
||||
|
||||
} else {
|
||||
serdes->route_flag |= ROUTE_MULTI_MIRROR;
|
||||
route->route_flag |= ROUTE_MULTI_MIRROR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (lanes == 2)
|
||||
serdes->route_flag |= ROUTE_MULTI_LANE;
|
||||
}
|
||||
|
||||
if (route->remote0_port0 & RK_SERDES_DSI_TX0 ||
|
||||
route->remote1_port0 & RK_SERDES_DSI_TX0) {
|
||||
ret = rkx120_dsi_tx_parse(sd_panel);
|
||||
if (ret) {
|
||||
dev_err(sd_panel->dev, "failed to get cmds\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (route->local_port0 & RK_SERDES_DSI_RX0 ||
|
||||
route->local_port0 & RK_SERDES_DSI_TX1) {
|
||||
ret = rkx120_dsi_rx_parse(sd_panel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serdes_panel_match_by_id(struct device *dev, const void *data)
|
||||
{
|
||||
struct rk_serdes_panel *sd_panel = dev_get_drvdata(dev);
|
||||
unsigned int *id = (unsigned int *)data;
|
||||
|
||||
return sd_panel->id == *id;
|
||||
}
|
||||
|
||||
static struct rk_serdes_panel *serdes_panel_find_by_id(struct device_driver *drv,
|
||||
unsigned int id)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = driver_find_device(drv, NULL, &id, serdes_panel_match_by_id);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
return dev_get_drvdata(dev);
|
||||
}
|
||||
|
||||
static int serdes_panel_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rk_serdes *serdes = dev_get_drvdata(pdev->dev.parent);
|
||||
struct rk_serdes_panel *sd_panel;
|
||||
struct rk_serdes_panel *sd_panel, *secondary;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
sd_panel = devm_kzalloc(&pdev->dev, sizeof(*sd_panel), GFP_KERNEL);
|
||||
if (!sd_panel)
|
||||
@@ -553,7 +600,20 @@ static int serdes_panel_probe(struct platform_device *pdev)
|
||||
sd_panel->dev = &pdev->dev;
|
||||
sd_panel->parent = serdes;
|
||||
sd_panel->route.stream_type = STREAM_DISPLAY;
|
||||
serdes->vm = &sd_panel->route.vm;
|
||||
|
||||
ret = of_property_read_u32(sd_panel->dev->of_node, "reg", ®);
|
||||
if (ret)
|
||||
sd_panel->id = 0;
|
||||
sd_panel->id = reg;
|
||||
|
||||
sd_panel->multi_panel = device_property_read_bool(sd_panel->dev, "multi-panel");
|
||||
if (sd_panel->multi_panel) {
|
||||
secondary = serdes_panel_find_by_id(sd_panel->dev->driver, 1);
|
||||
if (!secondary)
|
||||
return -EPROBE_DEFER;
|
||||
sd_panel->secondary = secondary;
|
||||
dev_info(sd_panel->dev, "%s get secondary panel\n", __func__);
|
||||
}
|
||||
|
||||
sd_panel->supply = devm_regulator_get_optional(sd_panel->dev, "power");
|
||||
if (IS_ERR(sd_panel->supply)) {
|
||||
@@ -588,6 +648,19 @@ static int serdes_panel_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = serdes_panel_parse_route(sd_panel);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (sd_panel->route.remote0_port0 & RK_SERDES_DSI_TX0 ||
|
||||
sd_panel->route.remote1_port0 & RK_SERDES_DSI_TX0) {
|
||||
ret = rkx120_dsi_tx_parse(sd_panel);
|
||||
if (ret) {
|
||||
dev_err(sd_panel->dev, "failed to get cmds\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register the panel. */
|
||||
drm_panel_init(&sd_panel->panel, sd_panel->dev, &serdes_panel_funcs, 0);
|
||||
|
||||
@@ -597,13 +670,37 @@ static int serdes_panel_probe(struct platform_device *pdev)
|
||||
|
||||
drm_panel_add(&sd_panel->panel);
|
||||
|
||||
if ((sd_panel->route.local_port0 & RK_SERDES_DSI_RX0 ||
|
||||
sd_panel->route.local_port0 & RK_SERDES_DSI_RX1) && sd_panel->id == 0) {
|
||||
ret = rkx110_dsi_rx_parse(sd_panel);
|
||||
if (ret < 0) {
|
||||
drm_panel_remove(&sd_panel->panel);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((sd_panel->route.local_port1 & RK_SERDES_DSI_RX0 ||
|
||||
sd_panel->route.local_port1 & RK_SERDES_DSI_RX1) && sd_panel->id == 1) {
|
||||
ret = rkx110_dsi_rx_parse(sd_panel);
|
||||
if (ret < 0) {
|
||||
drm_panel_remove(&sd_panel->panel);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
dev_set_drvdata(sd_panel->dev, sd_panel);
|
||||
|
||||
ret = serdes_panel_parse_dt(sd_panel);
|
||||
if (ret < 0) {
|
||||
drm_panel_remove(&sd_panel->panel);
|
||||
return ret;
|
||||
}
|
||||
if (sd_panel->route.route_flag & ROUTE_MULTI_CHANNEL)
|
||||
serdes->channel_nr = 2;
|
||||
|
||||
if (sd_panel->route.local_port0 && sd_panel->id == 0)
|
||||
serdes->route_nr++;
|
||||
|
||||
if (sd_panel->route.local_port1 && sd_panel->id == 1)
|
||||
serdes->route_nr++;
|
||||
|
||||
if (serdes->route_nr == 2)
|
||||
serdes->channel_nr = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -294,6 +294,8 @@ int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *rout
|
||||
u8 phy_id)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[remote_id].client;
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx120_combtxphy *combtxphy = &sd_panel->combtxphy;
|
||||
|
||||
if (phy_id) {
|
||||
serdes->i2c_write_reg(client, DES_GRF_SOC_CON7, 0xfff00630);
|
||||
@@ -303,12 +305,12 @@ int rkx120_lvds_tx_enable(struct rk_serdes *serdes, struct rk_serdes_route *rout
|
||||
serdes->i2c_write_reg(client, DES_GRF_SOC_CON2, 0x00040004);
|
||||
}
|
||||
|
||||
rkx120_combtxphy_set_mode(serdes, COMBTX_PHY_MODE_VIDEO_LVDS);
|
||||
rkx120_combtxphy_set_mode(combtxphy, COMBTX_PHY_MODE_VIDEO_LVDS);
|
||||
if (route->remote0_port0 & RK_SERDES_DUAL_LVDS_TX)
|
||||
rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7 / 2);
|
||||
rkx120_combtxphy_set_rate(combtxphy, route->vm.pixelclock * 7 / 2);
|
||||
else
|
||||
rkx120_combtxphy_set_rate(serdes, route->vm.pixelclock * 7);
|
||||
rkx120_combtxphy_power_on(serdes, remote_id, phy_id);
|
||||
rkx120_combtxphy_set_rate(combtxphy, route->vm.pixelclock * 7);
|
||||
rkx120_combtxphy_power_on(serdes, combtxphy, remote_id, phy_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,9 +111,10 @@
|
||||
#define GRF_MIPI_STATUS 0x0080
|
||||
#define PHYLOCK BIT(0)
|
||||
|
||||
static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id)
|
||||
static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des,
|
||||
struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
const struct configure_opts_combphy cfg = combtxphy->mipi_dphy_cfg;
|
||||
u32 byte_clk = DIV_ROUND_CLOSEST_ULL(combtxphy->rate, 8);
|
||||
u32 esc_div = DIV_ROUND_UP(byte_clk, 20 * USEC_PER_SEC);
|
||||
@@ -123,30 +124,30 @@ static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id
|
||||
u32 t_tago, t_tasure, t_taget;
|
||||
u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE;
|
||||
|
||||
serdes_combphy_write(des, remote_id, base + INTERFACE_PARA,
|
||||
serdes_combphy_write(des, dev_id, base + INTERFACE_PARA,
|
||||
TXREADYESC_VLD(esc_div - 2) |
|
||||
RXVALIDESC_VLD(esc_div - 2));
|
||||
serdes_combphy_write(des, remote_id, base + COMMON_PARA0, esc_div);
|
||||
serdes_combphy_update_bits(des, remote_id, base + TEST_PARA0, FSET_EN, FSET_EN);
|
||||
serdes_combphy_write(des, dev_id, base + COMMON_PARA0, esc_div);
|
||||
serdes_combphy_update_bits(des, dev_id, base + TEST_PARA0, FSET_EN, FSET_EN);
|
||||
|
||||
t_init = DIV_ROUND_UP(cfg.init, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + CLANE_PARA1, T_INITTIME_C(t_init));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE0_PARA1, T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(1), T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(2), T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA1(3), T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, dev_id, base + CLANE_PARA1, T_INITTIME_C(t_init));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE0_PARA1, T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA1(1), T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA1(2), T_INITTIME_D(t_init));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA1(3), T_INITTIME_D(t_init));
|
||||
|
||||
t_clkprepare = DIV_ROUND_UP(cfg.clk_prepare, t_byte_clk) - 1;
|
||||
t_clkzero = DIV_ROUND_UP(cfg.clk_zero, t_byte_clk) - 1;
|
||||
t_clkpre = DIV_ROUND_UP(cfg.clk_pre, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + CLANE_PARA2,
|
||||
serdes_combphy_write(des, dev_id, base + CLANE_PARA2,
|
||||
T_CLKPREPARE_C(t_clkprepare) |
|
||||
T_CLKZERO_C(t_clkzero) | T_CLKPRE_C(t_clkpre));
|
||||
|
||||
t_clkpost = DIV_ROUND_UP(cfg.clk_post, t_byte_clk) - 1;
|
||||
t_clktrail = DIV_ROUND_UP(cfg.clk_trail, t_byte_clk) - 1;
|
||||
t_hsexit = DIV_ROUND_UP(cfg.hs_exit, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + CLANE_PARA3,
|
||||
serdes_combphy_write(des, dev_id, base + CLANE_PARA3,
|
||||
T_CLKPOST_C(t_clkpost) |
|
||||
T_CLKTRAIL_C(t_clktrail) |
|
||||
T_HSEXIT_C(t_hsexit));
|
||||
@@ -154,62 +155,63 @@ static void rkx120_combtxphy_dsi_timing_init(struct rk_serdes *des, u8 remote_id
|
||||
t_hsprepare = DIV_ROUND_UP(cfg.hs_prepare, t_byte_clk) - 1;
|
||||
t_hszero = DIV_ROUND_UP(cfg.hs_zero, t_byte_clk) - 1;
|
||||
t_hstrail = DIV_ROUND_UP(cfg.hs_trail, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + DLANE0_PARA2,
|
||||
serdes_combphy_write(des, dev_id, base + DLANE0_PARA2,
|
||||
T_HSPREPARE_D(t_hsprepare) |
|
||||
T_HSZERO_D(t_hszero) |
|
||||
T_HSTRAIL_D(t_hstrail) |
|
||||
T_HSEXIT_D(t_hsexit));
|
||||
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(1),
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA2(1),
|
||||
T_HSPREPARE_D(t_hsprepare) |
|
||||
T_HSZERO_D(t_hszero) |
|
||||
T_HSTRAIL_D(t_hstrail) |
|
||||
T_HSEXIT_D(t_hsexit));
|
||||
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(2),
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA2(2),
|
||||
T_HSPREPARE_D(t_hsprepare) |
|
||||
T_HSZERO_D(t_hszero) |
|
||||
T_HSTRAIL_D(t_hstrail) |
|
||||
T_HSEXIT_D(t_hsexit));
|
||||
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA2(3),
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA2(3),
|
||||
T_HSPREPARE_D(t_hsprepare) |
|
||||
T_HSZERO_D(t_hszero) |
|
||||
T_HSTRAIL_D(t_hstrail) |
|
||||
T_HSEXIT_D(t_hsexit));
|
||||
|
||||
t_wakeup = DIV_ROUND_UP(cfg.wakeup, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + DLANE0_PARA3, T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(1), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(2), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, remote_id, base + DLANE_PARA3(3), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, remote_id, base + CLANE_PARA4, T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE0_PARA3, T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA3(1), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA3(2), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, dev_id, base + DLANE_PARA3(3), T_WAKEUP_D(t_wakeup));
|
||||
serdes_combphy_write(des, dev_id, base + CLANE_PARA4, T_WAKEUP_D(t_wakeup));
|
||||
|
||||
t_tago = DIV_ROUND_UP(cfg.ta_go, t_byte_clk) - 1;
|
||||
t_tasure = DIV_ROUND_UP(cfg.ta_sure, t_byte_clk) - 1;
|
||||
t_taget = DIV_ROUND_UP(cfg.ta_get, t_byte_clk) - 1;
|
||||
serdes_combphy_write(des, remote_id, base + DLANE0_PARA4,
|
||||
serdes_combphy_write(des, dev_id, base + DLANE0_PARA4,
|
||||
T_TAGO_D0(t_tago) |
|
||||
T_TASURE_D0(t_tasure) |
|
||||
T_TAGET_D0(t_taget));
|
||||
}
|
||||
|
||||
static void rkx120_combtxphy_dsi_pll_set(struct rk_serdes *des, u8 remote_id)
|
||||
static void rkx120_combtxphy_dsi_pll_set(struct rk_serdes *des,
|
||||
struct rkx120_combtxphy *combtxphy, u8 dev_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
u32 base = RKX120_MIPI_LVDS_TX_PHY0_BASE;
|
||||
|
||||
serdes_combphy_update_bits(des, remote_id, base + PLL_CTRL_PARA0,
|
||||
serdes_combphy_update_bits(des, dev_id, base + PLL_CTRL_PARA0,
|
||||
RATE_MASK | REFCLK_DIV_MASK | PLL_DIV_MASK,
|
||||
RATE(combtxphy->rate_factor) |
|
||||
REFCLK_DIV(combtxphy->ref_div - 1) |
|
||||
PLL_DIV(combtxphy->fb_div));
|
||||
}
|
||||
|
||||
static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id)
|
||||
static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des,
|
||||
struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
struct i2c_client *client = des->chip[remote_id].client;
|
||||
struct i2c_client *client = des->chip[dev_id].client;
|
||||
u32 grf_base = RKX120_GRF_MIPI0_BASE;
|
||||
u32 val;
|
||||
int ret;
|
||||
@@ -218,8 +220,8 @@ static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id)
|
||||
PHY_MODE(COMBTX_PHY_MODE_VIDEO_MIPI));
|
||||
|
||||
serdes_combphy_get_default_config(combtxphy->rate, &combtxphy->mipi_dphy_cfg);
|
||||
rkx120_combtxphy_dsi_timing_init(des, remote_id);
|
||||
rkx120_combtxphy_dsi_pll_set(des, remote_id);
|
||||
rkx120_combtxphy_dsi_timing_init(des, combtxphy, dev_id);
|
||||
rkx120_combtxphy_dsi_pll_set(des, combtxphy, dev_id);
|
||||
|
||||
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(1));
|
||||
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(1));
|
||||
@@ -233,19 +235,20 @@ static void rkx120_combtxphy_dsi_power_on(struct rk_serdes *des, u8 remote_id)
|
||||
dev_err(des->dev, "PLL is not locked\n");
|
||||
}
|
||||
|
||||
static void rkx120_combtxphy_dsi_power_off(struct rk_serdes *des, u8 remote_id)
|
||||
static void rkx120_combtxphy_dsi_power_off(struct rk_serdes *des, u8 dev_id)
|
||||
{
|
||||
struct i2c_client *client = des->chip[remote_id].client;
|
||||
struct i2c_client *client = des->chip[dev_id].client;
|
||||
u32 grf_base = RKX120_GRF_MIPI0_BASE;
|
||||
|
||||
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON0, PHYSHUTDWN(0));
|
||||
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON1, PWON_PLL(0));
|
||||
}
|
||||
|
||||
static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id)
|
||||
static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des,
|
||||
struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id, u8 phy_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
struct i2c_client *client = des->chip[remote_id].client;
|
||||
struct i2c_client *client = des->chip[dev_id].client;
|
||||
u32 grf_base = (phy_id == 0) ?
|
||||
RKX120_GRF_MIPI0_BASE : RKX120_GRF_MIPI1_BASE;
|
||||
const struct {
|
||||
@@ -304,29 +307,27 @@ static void rkx120_combtxphy_lvds_power_on(struct rk_serdes *des, u8 remote_id,
|
||||
des->i2c_write_reg(client, grf_base + GRF_MIPITX_CON13, TX_IDLE(0));
|
||||
}
|
||||
|
||||
void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id)
|
||||
void rkx120_combtxphy_power_on(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id, u8 phy_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
|
||||
switch (combtxphy->mode) {
|
||||
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||
rkx120_combtxphy_dsi_power_on(des, remote_id);
|
||||
rkx120_combtxphy_dsi_power_on(des, combtxphy, dev_id);
|
||||
break;
|
||||
case COMBTX_PHY_MODE_VIDEO_LVDS:
|
||||
rkx120_combtxphy_lvds_power_on(des, remote_id, phy_id);
|
||||
rkx120_combtxphy_lvds_power_on(des, combtxphy, dev_id, phy_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id)
|
||||
void rkx120_combtxphy_power_off(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id, u8 phy_id)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
|
||||
switch (combtxphy->mode) {
|
||||
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||
rkx120_combtxphy_dsi_power_off(des, remote_id);
|
||||
rkx120_combtxphy_dsi_power_off(des, dev_id);
|
||||
break;
|
||||
case COMBTX_PHY_MODE_VIDEO_LVDS:
|
||||
break;
|
||||
@@ -385,10 +386,8 @@ static void rkx120_combtxphy_lvds_pll_calc_rate(struct rkx120_combtxphy *combtxp
|
||||
{
|
||||
}
|
||||
|
||||
void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate)
|
||||
void rkx120_combtxphy_set_rate(struct rkx120_combtxphy *combtxphy, u64 rate)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
|
||||
switch (combtxphy->mode) {
|
||||
case COMBTX_PHY_MODE_VIDEO_MIPI:
|
||||
rkx120_combtxphy_dsi_pll_calc_rate(combtxphy, rate);
|
||||
@@ -403,14 +402,12 @@ void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate)
|
||||
combtxphy->rate = rate;
|
||||
}
|
||||
|
||||
u64 rkx120_combtxphy_get_rate(struct rk_serdes *des)
|
||||
u64 rkx120_combtxphy_get_rate(struct rkx120_combtxphy *combtxphy)
|
||||
{
|
||||
return des->combtxphy.rate;
|
||||
return combtxphy->rate;
|
||||
}
|
||||
|
||||
void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode)
|
||||
void rkx120_combtxphy_set_mode(struct rkx120_combtxphy *combtxphy, enum combtx_phy_mode mode)
|
||||
{
|
||||
struct rkx120_combtxphy *combtxphy = &des->combtxphy;
|
||||
|
||||
combtxphy->mode = mode;
|
||||
}
|
||||
|
||||
@@ -751,10 +751,9 @@ static int rkx120_dsi_tx_transfer(struct rk_serdes *des, u8 remote_id,
|
||||
return msg->tx_len;
|
||||
}
|
||||
|
||||
static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, u8 remote_id,
|
||||
const void *payload, size_t size)
|
||||
static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, struct rkx120_dsi_tx *dsi,
|
||||
u8 remote_id, const void *payload, size_t size)
|
||||
{
|
||||
const struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
@@ -785,10 +784,9 @@ static int rkx120_mipi_dsi_generic_write(struct rk_serdes *des, u8 remote_id,
|
||||
return rkx120_dsi_tx_transfer(des, remote_id, dsi, &msg);
|
||||
}
|
||||
|
||||
static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, u8 remote_id,
|
||||
const void *data, size_t len)
|
||||
static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi,
|
||||
u8 remote_id, const void *data, size_t len)
|
||||
{
|
||||
const struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
@@ -818,10 +816,9 @@ static int rkx120_mipi_dsi_dcs_write_buffer(struct rk_serdes *des, u8 remote_id,
|
||||
}
|
||||
|
||||
static __maybe_unused int
|
||||
rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, u8 remote_id,
|
||||
rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id,
|
||||
u8 cmd, void *data, size_t len)
|
||||
{
|
||||
const struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
@@ -835,7 +832,7 @@ rkx120_mipi_dsi_dcs_read(struct rk_serdes *des, u8 remote_id,
|
||||
return rkx120_dsi_tx_transfer(des, remote_id, dsi, &msg);
|
||||
}
|
||||
|
||||
int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id,
|
||||
int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id,
|
||||
struct panel_cmds *cmds)
|
||||
{
|
||||
u16 i;
|
||||
@@ -852,13 +849,13 @@ int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id,
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
err = rkx120_mipi_dsi_generic_write(des, remote_id, cmd->payload,
|
||||
err = rkx120_mipi_dsi_generic_write(des, dsi, remote_id, cmd->payload,
|
||||
cmd->dchdr.dlen);
|
||||
break;
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
err = rkx120_mipi_dsi_dcs_write_buffer(des, remote_id, cmd->payload,
|
||||
err = rkx120_mipi_dsi_dcs_write_buffer(des, dsi, remote_id, cmd->payload,
|
||||
cmd->dchdr.dlen);
|
||||
break;
|
||||
default:
|
||||
@@ -901,7 +898,8 @@ static u64 rkx120_dsi_tx_get_lane_rate(const struct rkx120_dsi_tx *dsi)
|
||||
}
|
||||
|
||||
static void
|
||||
mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi, u8 remote_id)
|
||||
mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi,
|
||||
u8 remote_id)
|
||||
{
|
||||
struct i2c_client *client = des->chip[remote_id].client;
|
||||
u32 val, mask;
|
||||
@@ -920,7 +918,7 @@ mipi_dphy_power_on(struct rk_serdes *des, const struct rkx120_dsi_tx *dsi, u8 re
|
||||
dsi_update_bits(des, remote_id, DSI_PHY_RSTZ, PHY_RSTZ, PHY_RSTZ);
|
||||
usleep_range(1500, 2000);
|
||||
|
||||
rkx120_combtxphy_power_on(des, remote_id, 0);
|
||||
rkx120_combtxphy_power_on(des, dsi->combtxphy, remote_id, 0);
|
||||
|
||||
ret = read_poll_timeout(des->i2c_read_reg, ret,
|
||||
!(ret < 0) && (val & PHY_LOCK),
|
||||
@@ -954,9 +952,9 @@ static void rkx120_dsi_tx_reset_control_deassert(struct rk_serdes *des, u8 remot
|
||||
//dsi_i2c_write(des, remote_id, CRU_SOFTRST_CON02, 0x400000);
|
||||
}
|
||||
|
||||
static void rkx120_dsi_tx_bridge_pre_enable(struct rk_serdes *des, u8 remote_id)
|
||||
static void rkx120_dsi_tx_bridge_pre_enable(struct rk_serdes *des, struct rkx120_dsi_tx *dsi,
|
||||
u8 remote_id)
|
||||
{
|
||||
struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
u32 val;
|
||||
|
||||
dsi_write(des, remote_id, DSI_PWR_UP, RESET);
|
||||
@@ -1064,9 +1062,8 @@ static void rkx120_dsi_tx_set_cmd_mode(struct rk_serdes *des, u8 remote_id,
|
||||
}
|
||||
|
||||
static void
|
||||
rkx120_dsi_tx_bridge_enable(struct rk_serdes *des, u8 remote_id)
|
||||
rkx120_dsi_tx_bridge_enable(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id)
|
||||
{
|
||||
struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
const struct videomode *vm = dsi->vm;
|
||||
u32 val;
|
||||
|
||||
@@ -1117,15 +1114,16 @@ void rkx120_dsi_tx_pre_enable(struct rk_serdes *des,
|
||||
struct rk_serdes_route *route,
|
||||
u8 remote_id)
|
||||
{
|
||||
struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx;
|
||||
u64 rate;
|
||||
|
||||
dsi->vm = &route->vm;
|
||||
rate = rkx120_dsi_tx_get_lane_rate(dsi);
|
||||
|
||||
rkx120_combtxphy_set_mode(des, COMBTX_PHY_MODE_VIDEO_MIPI);
|
||||
rkx120_combtxphy_set_rate(des, rate);
|
||||
lane_kbps = rkx120_combtxphy_get_rate(des) / MSEC_PER_SEC;
|
||||
rkx120_combtxphy_set_mode(dsi->combtxphy, COMBTX_PHY_MODE_VIDEO_MIPI);
|
||||
rkx120_combtxphy_set_rate(dsi->combtxphy, rate);
|
||||
lane_kbps = rkx120_combtxphy_get_rate(dsi->combtxphy) / MSEC_PER_SEC;
|
||||
|
||||
/* rst for dsi */
|
||||
rkx120_dsi_tx_reset_control_assert(des, remote_id);
|
||||
@@ -1133,12 +1131,11 @@ void rkx120_dsi_tx_pre_enable(struct rk_serdes *des,
|
||||
rkx120_dsi_tx_reset_control_deassert(des, remote_id);
|
||||
usleep_range(20, 40);
|
||||
|
||||
rkx120_dsi_tx_bridge_pre_enable(des, remote_id);
|
||||
|
||||
rkx120_dsi_tx_bridge_pre_enable(des, dsi, remote_id);
|
||||
#ifdef DSI_READ_POWER_MODE
|
||||
u8 mode;
|
||||
|
||||
rkx120_mipi_dsi_dcs_read(des, remote_id, MIPI_DCS_GET_POWER_MODE,
|
||||
rkx120_mipi_dsi_dcs_read(des, dsi, remote_id, MIPI_DCS_GET_POWER_MODE,
|
||||
&mode, sizeof(mode));
|
||||
|
||||
dev_info(rkx120->dev, "dsi: mode: 0x%x\n", mode);
|
||||
@@ -1149,17 +1146,18 @@ void rkx120_dsi_tx_enable(struct rk_serdes *des,
|
||||
struct rk_serdes_route *route,
|
||||
u8 remote_id)
|
||||
{
|
||||
struct rkx120_dsi_tx *dsi = &des->dsi_tx;
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx;
|
||||
|
||||
#ifdef DSI_READ_POWER_MODE
|
||||
u8 mode;
|
||||
|
||||
rkx120_mipi_dsi_dcs_read(des, remote_id, MIPI_DCS_GET_POWER_MODE,
|
||||
rkx120_mipi_dsi_dcs_read(des, dsi, remote_id, MIPI_DCS_GET_POWER_MODE,
|
||||
&mode, sizeof(mode));
|
||||
|
||||
dev_info(rkx120->dev, "dsi: mode: 0x%x\n", mode);
|
||||
#endif
|
||||
rkx120_dsi_tx_bridge_enable(des, remote_id);
|
||||
rkx120_dsi_tx_bridge_enable(des, dsi, remote_id);
|
||||
|
||||
dev_info(des->dev, "rkx120_dsi_tx final DSI-Link bandwidth: %llu Kbps x %d lanes\n",
|
||||
lane_kbps, dsi->lanes);
|
||||
@@ -1169,7 +1167,10 @@ void rkx120_dsi_tx_post_disable(struct rk_serdes *des,
|
||||
struct rk_serdes_route *route,
|
||||
u8 remote_id)
|
||||
{
|
||||
rkx120_combtxphy_power_off(des, remote_id);
|
||||
struct rk_serdes_panel *sd_panel = container_of(route, struct rk_serdes_panel, route);
|
||||
struct rkx120_dsi_tx *dsi = &sd_panel->dsi_tx;
|
||||
|
||||
rkx120_combtxphy_power_off(des, dsi->combtxphy, remote_id, 0);
|
||||
}
|
||||
|
||||
void rkx120_dsi_tx_disable(struct rk_serdes *des, struct rk_serdes_route *route, u8 remote_id)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "rkx110_x120.h"
|
||||
|
||||
int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, u8 remote_id,
|
||||
int rkx120_dsi_tx_cmd_seq_xfer(struct rk_serdes *des, struct rkx120_dsi_tx *dsi, u8 remote_id,
|
||||
struct panel_cmds *cmds);
|
||||
void rkx120_dsi_tx_pre_enable(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, u8 remote_id);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define TRAIN_CLK_SEL_I2S UPDATE(2, 31, 30)
|
||||
#define DUAL_LVDS_CHANNEL_SWAP BIT(29)
|
||||
#define VIDEO_FREQ_AUTO_EN BIT(28)
|
||||
#define ENGINE_CFG_MASK GENMASK(23, 20)
|
||||
#define ENGINE1_2_LANE BIT(23)
|
||||
#define ENGINE1_EN BIT(22)
|
||||
#define ENGINE0_2_LANE BIT(21)
|
||||
@@ -38,6 +39,7 @@
|
||||
#define LANE0_DATA_WIDTH_32BIT UPDATE(3, 13, 12)
|
||||
#define LANE1_PKT_LOSE_NUM_CLR BIT(9)
|
||||
#define LANE0_PKT_LOSE_NUM_CLR BIT(8)
|
||||
#define LANE_CFG_MASK GENMASK(5, 4)
|
||||
#define LANE0_EN BIT(4)
|
||||
#define LANE1_EN BIT(5)
|
||||
#define DES_EN BIT(0)
|
||||
@@ -79,6 +81,7 @@
|
||||
#define ORDER_FIFO0_WR_ID(x) UPDATE(x, 2, 0)
|
||||
|
||||
#define RKLINK_DES_SOURCE_CFG LINK_REG(0x0024)
|
||||
#define E1_STREAM_CFG_MASK GENMASK(23, 20)
|
||||
#define E1_CAMERA_SRC_CSI UPDATE(0, 23, 21)
|
||||
#define E1_CAMERA_SRC_LVDS UPDATE(1, 23, 21)
|
||||
#define E1_CAMERA_SRC_DVP UPDATE(2, 23, 21)
|
||||
@@ -89,6 +92,7 @@
|
||||
#define E1_DISPLAY_SRC_RGB UPDATE(5, 23, 21)
|
||||
#define E1_STREAM_CAMERA UPDATE(0, 20, 20)
|
||||
#define E1_STREAM_DISPLAY UPDATE(1, 20, 20)
|
||||
#define E0_STREAM_CFG_MASK GENMASK(19, 16)
|
||||
#define E0_CAMERA_SRC_CSI UPDATE(0, 19, 17)
|
||||
#define E0_CAMERA_SRC_LVDS UPDATE(1, 19, 17)
|
||||
#define E0_CAMERA_SRC_DVP UPDATE(2, 19, 17)
|
||||
@@ -99,6 +103,7 @@
|
||||
#define E0_DISPLAY_SRC_RGB UPDATE(5, 19, 17)
|
||||
#define E0_STREAM_CAMERA UPDATE(0, 16, 16)
|
||||
#define E0_STREAM_DISPLAY UPDATE(1, 16, 16)
|
||||
#define LANE_ID_CFG_MASK GENMASK(7, 0)
|
||||
#define LANE1_ENGINE_ID(x) UPDATE(x, 7, 6)
|
||||
#define LANE1_LANE_ID(x) UPDATE(x, 5, 5)
|
||||
#define LNAE1_ID_SEL(x) UPDATE(x, 4, 4)
|
||||
@@ -464,9 +469,9 @@ static const struct rk_serdes_pt des_pt[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static int rk_des_get_stream_source(struct rk_serdes_route *route, u32 port, u8 engine_id)
|
||||
static int rk_des_get_stream_source(u32 stream_type, u32 port, u8 engine_id)
|
||||
{
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
if (stream_type == STREAM_DISPLAY) {
|
||||
if (port & RK_SERDES_RGB_TX)
|
||||
return engine_id ? E1_DISPLAY_SRC_RGB : E0_DISPLAY_SRC_RGB;
|
||||
else if (port & RK_SERDES_LVDS_TX0)
|
||||
@@ -527,66 +532,252 @@ static void rk_serdes_link_rx_dsi_enable(struct rk_serdes *serdes,
|
||||
E1_FIRST_FRAME_DEL | E0_FIRST_FRAME_DEL);
|
||||
}
|
||||
|
||||
static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id)
|
||||
static int rk120_linkrx_des_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct hwclk *hwclk = serdes->chip[remote_id].hwclk;
|
||||
struct i2c_client *client;
|
||||
struct videomode *vm = &route->vm;
|
||||
u32 stream_type;
|
||||
u32 rx_src;
|
||||
u32 ctrl_val, mask, val;
|
||||
u32 lane0_dsource_id, lane1_dsource_id;
|
||||
bool is_rx_dual_lanes;
|
||||
bool is_rx_dual_channels;
|
||||
u32 length;
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
if (route->stream_type == STREAM_DISPLAY) {
|
||||
client = serdes->chip[remote_id].client;
|
||||
stream_type = E0_STREAM_DISPLAY;
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, DES_EN, enable ? DES_EN : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_video_fm_enable(struct rk_serdes *serdes, u8 dev_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, VIDEO_FREQ_AUTO_EN,
|
||||
enable ? VIDEO_FREQ_AUTO_EN : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_engine_lane_enable(struct rk_serdes *serdes, u8 dev_id,
|
||||
bool dual_channels, bool dual_lanes)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 val = 0;
|
||||
|
||||
/*
|
||||
* config engine and lane as fallow:
|
||||
* 1.linkrx receive 1 channel data in 1 lane, enable engine0 and engine0 use 1 lane.
|
||||
* 2.linkrx receive 1 channel data in 2 lane, enable engine0 and engine0 user 2 lanes.
|
||||
* 3.linkrx receive 2 channel data in 1 lane, enable engine0, enagine1. engine0 use
|
||||
* 1 lane, engine1 use 1 lane.
|
||||
* 4.linkrx receive 2 channel data in 2 lane, enable engine0, enagine1. engine0 use
|
||||
* 1 lane, engine1 use 1 lane.
|
||||
*/
|
||||
if (dual_channels) {
|
||||
val |= ENGINE0_EN | ENGINE1_EN;
|
||||
} else {
|
||||
client = serdes->chip[DEVICE_LOCAL].client;
|
||||
stream_type = E0_STREAM_CAMERA;
|
||||
val |= ENGINE0_EN;
|
||||
if (dual_lanes)
|
||||
val |= ENGINE0_2_LANE;
|
||||
}
|
||||
|
||||
is_rx_dual_lanes = (serdes->route_flag & ROUTE_MULTI_LANE) &&
|
||||
!(serdes->route_flag & ROUTE_MULTI_REMOTE);
|
||||
is_rx_dual_channels = (serdes->route_flag & ROUTE_MULTI_CHANNEL) &&
|
||||
!(serdes->route_flag & ROUTE_MULTI_REMOTE);
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, ENGINE_CFG_MASK, val);
|
||||
|
||||
serdes->i2c_read_reg(client, RKLINK_DES_LANE_ENGINE_CFG, &ctrl_val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl_val &= ~LANE1_EN;
|
||||
ctrl_val |= LANE0_EN;
|
||||
ctrl_val |= ENGINE0_EN;
|
||||
if (is_rx_dual_lanes) {
|
||||
ctrl_val |= LANE1_EN;
|
||||
if (is_rx_dual_channels)
|
||||
ctrl_val |= ENGINE1_EN;
|
||||
else
|
||||
ctrl_val |= ENGINE0_2_LANE;
|
||||
} else {
|
||||
if (is_rx_dual_channels)
|
||||
ctrl_val |= ENGINE1_EN;
|
||||
}
|
||||
serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val);
|
||||
static int rk120_linkrx_lane_enable(struct rk_serdes *serdes, u8 dev_id, u32 lanes)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 val;
|
||||
|
||||
mask = LANE0_ENGINE_CFG_MASK;
|
||||
val = LANE0_ENGINE0;
|
||||
if (is_rx_dual_lanes) {
|
||||
if (is_rx_dual_channels) {
|
||||
mask |= LANE1_ENGINE_CFG_MASK;
|
||||
val |= LANE1_ENGINE1;
|
||||
/*
|
||||
* when 1 lane connect to linkrx, enable lane0;
|
||||
* when 2 lane connect to linkrx, enable lane0 and lane1;
|
||||
*/
|
||||
|
||||
if (lanes == 1)
|
||||
val = LANE0_EN;
|
||||
else if (lanes == 2)
|
||||
val = LANE0_EN | LANE1_EN;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_CFG, LANE_CFG_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_lane_engine_dst_cfg(struct rk_serdes *serdes, u8 dev_id,
|
||||
bool dual_channels, bool dual_lanes)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 mask, val;
|
||||
|
||||
/*
|
||||
* config lane dst engine as fallow:
|
||||
* 1. 1 channel 1 lane: lane0 data send to engine0
|
||||
* 2. 1 channel 2 lane: lane0 data send to engine0, lane1 data send to engine0
|
||||
* 3. 2 channel 1 lane: lane0 data send to engine0, lane0 data send to engine1
|
||||
* 4. 2 channel 2 lane: lane0 data send to engine0, lane1 data send to engine1
|
||||
*/
|
||||
if (dual_channels) {
|
||||
if (dual_lanes) {
|
||||
mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK;
|
||||
val = LANE0_ENGINE0 | LANE1_ENGINE1;
|
||||
} else {
|
||||
mask |= LANE1_ENGINE_CFG_MASK;
|
||||
val |= LANE1_ENGINE0;
|
||||
mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK;
|
||||
val = LANE0_ENGINE0 | LANE0_ENGINE1;
|
||||
}
|
||||
} else {
|
||||
if (is_rx_dual_channels)
|
||||
val |= LANE0_ENGINE1;
|
||||
}
|
||||
|
||||
if (dual_lanes) {
|
||||
mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK;
|
||||
val = LANE0_ENGINE0 | LANE1_ENGINE0;
|
||||
} else {
|
||||
mask = LANE0_ENGINE_CFG_MASK | LANE1_ENGINE_CFG_MASK;
|
||||
val = LANE0_ENGINE0 | LANE1_ENGINE1;
|
||||
}
|
||||
}
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_LANE_ENGINE_DST, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_config_pkt_length(struct rk_serdes *serdes, u8 dev_id, u32 length)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) |
|
||||
E1_REPKT_LENGTH(length));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_lane_id_cfg(struct rk_serdes *serdes, u8 dev_id,
|
||||
bool dual_channels, bool dual_lanes)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 val;
|
||||
|
||||
if (dual_channels) {
|
||||
if (dual_lanes) {
|
||||
val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LNAE0_ID_SEL(1) |
|
||||
LANE1_ENGINE_ID(1) | LANE1_LANE_ID(0) | LNAE1_ID_SEL(1);
|
||||
} else {
|
||||
val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LANE1_ENGINE_ID(1) |
|
||||
LANE1_LANE_ID(0);
|
||||
}
|
||||
} else {
|
||||
if (dual_lanes) {
|
||||
val = LANE0_ENGINE_ID(0) | LANE0_LANE_ID(0) | LNAE0_ID_SEL(1) |
|
||||
LANE1_ENGINE_ID(0) | LANE1_LANE_ID(1) | LNAE1_ID_SEL(1);
|
||||
} else {
|
||||
val = LNAE0_ID_SEL(1);
|
||||
}
|
||||
}
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_SOURCE_CFG, LANE_ID_CFG_MASK, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_stream_type_cfg(struct rk_serdes *serdes, u32 stream_type,
|
||||
u8 dev_id, u32 port, u32 engine_id)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 val, mask, rx_src;
|
||||
|
||||
mask = engine_id ? E1_STREAM_CFG_MASK : E0_STREAM_CFG_MASK;
|
||||
if (stream_type == STREAM_DISPLAY)
|
||||
val = engine_id ? E1_STREAM_DISPLAY : E0_STREAM_DISPLAY;
|
||||
else
|
||||
val = engine_id ? E1_STREAM_CAMERA : E0_STREAM_CAMERA;
|
||||
|
||||
rx_src = rk_des_get_stream_source(stream_type, port, engine_id);
|
||||
val |= rx_src;
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_SOURCE_CFG, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_linkrx_data_and_order_id_cfg(struct rk_serdes *serdes, u8 dev_id,
|
||||
bool dual_channels, bool dual_lanes)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
u32 lane0_dsource_id, lane1_dsource_id;
|
||||
u32 data_id_mask;
|
||||
u32 order_id_mask;
|
||||
u32 val;
|
||||
|
||||
data_id_mask = DATA_FIFO0_WR_ID_MASK | DATA_FIFO1_WR_ID_MASK |
|
||||
DATA_FIFO2_WR_ID_MASK | DATA_FIFO3_WR_ID_MASK |
|
||||
DATA_FIFO0_RD_ID_MASK | DATA_FIFO1_RD_ID_MASK |
|
||||
DATA_FIFO2_RD_ID_MASK | DATA_FIFO3_RD_ID_MASK;
|
||||
order_id_mask = ORDER_FIFO0_WR_ID_MASK | ORDER_FIFO1_WR_ID_MASK |
|
||||
ORDER_FIFO0_RD_ID_MASK | ORDER_FIFO1_RD_ID_MASK;
|
||||
|
||||
if (dual_channels) {
|
||||
lane0_dsource_id = (0 << 1) | 0;
|
||||
lane1_dsource_id = (1 << 1) | 0;
|
||||
} else {
|
||||
if (dual_lanes) {
|
||||
lane0_dsource_id = (0 << 1) | 0;
|
||||
lane1_dsource_id = (0 << 1) | 1;
|
||||
} else {
|
||||
lane0_dsource_id = (0 << 1) | 0;
|
||||
lane1_dsource_id = (1 << 1) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
val = DATA_FIFO0_WR_ID(lane0_dsource_id) | DATA_FIFO1_WR_ID(lane0_dsource_id) |
|
||||
DATA_FIFO0_RD_ID(lane0_dsource_id) | DATA_FIFO1_RD_ID(lane0_dsource_id) |
|
||||
DATA_FIFO2_WR_ID(lane1_dsource_id) | DATA_FIFO3_WR_ID(lane1_dsource_id) |
|
||||
DATA_FIFO2_RD_ID(lane1_dsource_id) | DATA_FIFO3_RD_ID(lane1_dsource_id);
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_DATA_ID_CFG, data_id_mask, val);
|
||||
|
||||
val = ORDER_FIFO0_WR_ID(lane0_dsource_id) | ORDER_FIFO1_WR_ID(lane1_dsource_id) |
|
||||
ORDER_FIFO0_RD_ID(lane0_dsource_id) | ORDER_FIFO1_RD_ID(lane1_dsource_id);
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_ORDER_ID_CFG, order_id_mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk120_display_linkrx_cfg(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, u8 dev_id)
|
||||
{
|
||||
struct hwclk *hwclk = serdes->chip[dev_id].hwclk;
|
||||
bool is_rx_dual_lanes = false;
|
||||
bool is_rx_dual_channels = false;
|
||||
|
||||
if (serdes->route_nr == 1) {
|
||||
is_rx_dual_lanes = (serdes->lane_nr == 2) &&
|
||||
!(route->route_flag & ROUTE_MULTI_REMOTE);
|
||||
is_rx_dual_channels = (route->route_flag & ROUTE_MULTI_CHANNEL) &&
|
||||
!(route->route_flag & ROUTE_MULTI_REMOTE);
|
||||
} else {
|
||||
is_rx_dual_lanes = (serdes->lane_nr == 2) && (serdes->remote_nr == 1);
|
||||
is_rx_dual_channels = (serdes->channel_nr == 2) && (serdes->remote_nr == 1);
|
||||
}
|
||||
|
||||
rk120_linkrx_video_fm_enable(serdes, dev_id, true);
|
||||
rk120_linkrx_engine_lane_enable(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes);
|
||||
rk120_linkrx_lane_enable(serdes, dev_id, is_rx_dual_lanes ? 2 : 1);
|
||||
|
||||
rk120_linkrx_lane_engine_dst_cfg(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes);
|
||||
rk120_linkrx_lane_id_cfg(serdes, dev_id, is_rx_dual_channels, is_rx_dual_lanes);
|
||||
if (route->local_port0) {
|
||||
if (dev_id == DEVICE_REMOTE0) {
|
||||
rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id,
|
||||
route->remote0_port0, 0);
|
||||
if (is_rx_dual_channels)
|
||||
rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id,
|
||||
route->remote0_port1, 1);
|
||||
} else {
|
||||
rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id,
|
||||
route->remote1_port0, 0);
|
||||
}
|
||||
} else {
|
||||
rk120_linkrx_stream_type_cfg(serdes, route->stream_type, dev_id,
|
||||
route->remote1_port0, 0);
|
||||
}
|
||||
|
||||
rk120_linkrx_data_and_order_id_cfg(serdes, dev_id, is_rx_dual_channels,
|
||||
is_rx_dual_lanes);
|
||||
if (serdes->version == SERDES_V1) {
|
||||
/*
|
||||
* The serdes v1 have a bug when enable video suspend function, which
|
||||
@@ -594,87 +785,14 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
|
||||
* reducing the video packet length:
|
||||
* length = ((hactive x 24 / 32 / 16) + 15) / 16 * 16
|
||||
*/
|
||||
length = vm->hactive * 24 / 32 / 16;
|
||||
u32 length;
|
||||
|
||||
length = route->vm.hactive * 24 / 32 / 16;
|
||||
length = (length + 15) / 16 * 16;
|
||||
serdes->i2c_write_reg(client, DES_RKLINK_REC01_PKT_LENGTH, E0_REPKT_LENGTH(length) |
|
||||
E1_REPKT_LENGTH(length));
|
||||
rk120_linkrx_config_pkt_length(serdes, dev_id, length);
|
||||
}
|
||||
|
||||
serdes->i2c_read_reg(client, RKLINK_DES_SOURCE_CFG, &val);
|
||||
|
||||
val &= ~(LANE0_ENGINE_ID(1) | LANE0_LANE_ID(1) | LANE1_ENGINE_ID(1) |
|
||||
LANE1_LANE_ID(1) | LNAE0_ID_SEL(1) | LNAE1_ID_SEL(1));
|
||||
|
||||
if (is_rx_dual_lanes) {
|
||||
if (is_rx_dual_channels) {
|
||||
val |= LANE0_ENGINE_ID(0);
|
||||
val |= LANE0_LANE_ID(0);
|
||||
val |= LNAE0_ID_SEL(1);
|
||||
val |= LANE1_ENGINE_ID(1);
|
||||
val |= LANE1_LANE_ID(0);
|
||||
val |= LNAE1_ID_SEL(1);
|
||||
stream_type |= E1_STREAM_DISPLAY;
|
||||
} else {
|
||||
val |= LANE0_ENGINE_ID(0);
|
||||
val |= LANE0_LANE_ID(0);
|
||||
val |= LNAE0_ID_SEL(1);
|
||||
val |= LANE1_ENGINE_ID(0);
|
||||
val |= LANE1_LANE_ID(1);
|
||||
val |= LNAE0_ID_SEL(1);
|
||||
}
|
||||
} else {
|
||||
if (is_rx_dual_channels) {
|
||||
val |= LANE0_ENGINE_ID(0);
|
||||
val |= LANE0_LANE_ID(0);
|
||||
val |= LANE1_ENGINE_ID(1);
|
||||
val |= LANE1_LANE_ID(0);
|
||||
stream_type |= E1_STREAM_DISPLAY;
|
||||
} else {
|
||||
val |= LNAE0_ID_SEL(1);
|
||||
}
|
||||
}
|
||||
val |= stream_type;
|
||||
if (remote_id == DEVICE_REMOTE0)
|
||||
rx_src = rk_des_get_stream_source(route, route->remote0_port0, 0);
|
||||
else
|
||||
rx_src = rk_des_get_stream_source(route, route->remote1_port0, 0);
|
||||
val |= rx_src;
|
||||
if (is_rx_dual_channels) {
|
||||
rx_src = rk_des_get_stream_source(route, route->remote0_port1, 1);
|
||||
val |= rx_src;
|
||||
}
|
||||
serdes->i2c_write_reg(client, RKLINK_DES_SOURCE_CFG, val);
|
||||
|
||||
if (is_rx_dual_lanes || is_rx_dual_channels) {
|
||||
mask = DATA_FIFO0_WR_ID_MASK | DATA_FIFO1_WR_ID_MASK | DATA_FIFO2_WR_ID_MASK |
|
||||
DATA_FIFO3_WR_ID_MASK;
|
||||
mask |= DATA_FIFO0_RD_ID_MASK | DATA_FIFO1_RD_ID_MASK | DATA_FIFO2_RD_ID_MASK |
|
||||
DATA_FIFO3_RD_ID_MASK;
|
||||
if (is_rx_dual_channels) {
|
||||
lane0_dsource_id = (0 << 1) | 0;
|
||||
lane1_dsource_id = (1 << 1) | 0;
|
||||
} else {
|
||||
lane0_dsource_id = (0 << 1) | 0;
|
||||
lane1_dsource_id = (0 << 1) | 1;
|
||||
}
|
||||
val = DATA_FIFO0_WR_ID(lane0_dsource_id) | DATA_FIFO1_WR_ID(lane0_dsource_id);
|
||||
val |= DATA_FIFO0_RD_ID(lane0_dsource_id) | DATA_FIFO1_RD_ID(lane0_dsource_id);
|
||||
|
||||
val |= DATA_FIFO2_WR_ID(lane1_dsource_id) | DATA_FIFO3_WR_ID(lane1_dsource_id);
|
||||
val |= DATA_FIFO2_RD_ID(lane1_dsource_id) | DATA_FIFO3_RD_ID(lane1_dsource_id);
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_DATA_ID_CFG, mask, val);
|
||||
|
||||
mask = ORDER_FIFO0_WR_ID_MASK | ORDER_FIFO1_WR_ID_MASK |
|
||||
ORDER_FIFO0_RD_ID_MASK | ORDER_FIFO1_RD_ID_MASK;
|
||||
val = ORDER_FIFO0_WR_ID(lane0_dsource_id) | ORDER_FIFO1_WR_ID(lane1_dsource_id) |
|
||||
ORDER_FIFO0_RD_ID(lane0_dsource_id) | ORDER_FIFO1_RD_ID(lane1_dsource_id);
|
||||
|
||||
serdes->i2c_update_bits(client, RKLINK_DES_ORDER_ID_CFG, mask, val);
|
||||
}
|
||||
|
||||
ctrl_val |= DES_EN;
|
||||
serdes->i2c_write_reg(client, RKLINK_DES_LANE_ENGINE_CFG, ctrl_val);
|
||||
rk120_linkrx_des_enable(serdes, dev_id, true);
|
||||
|
||||
hwclk_set_rate(hwclk, RKX120_CPS_E0_CLK_RKLINK_RX_PRE, route->vm.pixelclock);
|
||||
dev_info(serdes->dev, "RKX120_CPS_E0_CLK_RKLINK_RX_PRE:%d\n",
|
||||
@@ -686,17 +804,17 @@ static int rk120_link_rx_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
|
||||
}
|
||||
|
||||
if (route->remote0_port0 == RK_SERDES_RGB_TX || route->remote1_port0 == RK_SERDES_RGB_TX)
|
||||
rk_serdes_link_rx_rgb_enable(serdes, route, remote_id);
|
||||
rk_serdes_link_rx_rgb_enable(serdes, route, dev_id);
|
||||
|
||||
if (route->remote0_port0 == RK_SERDES_LVDS_TX0 ||
|
||||
route->remote1_port0 == RK_SERDES_LVDS_TX0 ||
|
||||
route->remote0_port0 == RK_SERDES_LVDS_TX1 ||
|
||||
route->remote1_port0 == RK_SERDES_LVDS_TX1 ||
|
||||
route->remote0_port0 == RK_SERDES_DUAL_LVDS_TX)
|
||||
rk_serdes_link_rx_lvds_enable(serdes, route, remote_id);
|
||||
rk_serdes_link_rx_lvds_enable(serdes, route, dev_id);
|
||||
|
||||
if (route->remote0_port0 == RK_SERDES_DSI_TX0 || route->remote1_port0 == RK_SERDES_DSI_TX0)
|
||||
rk_serdes_link_rx_dsi_enable(serdes, route, remote_id);
|
||||
rk_serdes_link_rx_dsi_enable(serdes, route, dev_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -713,18 +831,19 @@ static int rk120_des_pma_cfg(struct rk_serdes *serdes, struct rk_serdes_route *r
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx120_linkrx_enable(struct rk_serdes *serdes, struct rk_serdes_route *route, u8 remote_id)
|
||||
int rkx120_display_linkrx_enable(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, u8 dev_id)
|
||||
{
|
||||
rk120_link_rx_cfg(serdes, route, remote_id);
|
||||
rk120_display_linkrx_cfg(serdes, route, dev_id);
|
||||
|
||||
rk120_des_pcs_cfg(serdes, route, remote_id, 0);
|
||||
rk120_des_pma_cfg(serdes, route, remote_id, 0);
|
||||
if ((serdes->route_flag & ROUTE_MULTI_LANE) &&
|
||||
!(serdes->route_flag & ROUTE_MULTI_REMOTE)) {
|
||||
rk120_des_pcs_cfg(serdes, route, remote_id, 1);
|
||||
rk120_des_pma_cfg(serdes, route, remote_id, 1);
|
||||
rk120_des_pcs_cfg(serdes, route, dev_id, 0);
|
||||
rk120_des_pma_cfg(serdes, route, dev_id, 0);
|
||||
if ((serdes->lane_nr == 2) && (serdes->remote_nr == 1)) {
|
||||
rk120_des_pcs_cfg(serdes, route, dev_id, 1);
|
||||
rk120_des_pma_cfg(serdes, route, dev_id, 1);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -761,7 +880,7 @@ void rkx120_linkrx_passthrough_cfg(struct rk_serdes *serdes, u32 client_id, u32
|
||||
}
|
||||
}
|
||||
|
||||
void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
int rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[DEVICE_LOCAL].client;
|
||||
u32 val;
|
||||
@@ -781,6 +900,8 @@ void rkx120_linkrx_wait_link_ready(struct rk_serdes *serdes, u8 id)
|
||||
dev_err(&client->dev, "wait link ready timeout: 0x%08x\n", val);
|
||||
else
|
||||
dev_info(&client->dev, "link success: 0x%08x\n", val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rkx120_pma_link_config(struct rk_serdes *serdes, u8 pcs_id, u8 dev_id)
|
||||
|
||||
@@ -14,15 +14,20 @@ int serdes_combphy_update_bits(struct rk_serdes *serdes, u8 remote_id,
|
||||
void serdes_combphy_get_default_config(u64 hs_clk_rate,
|
||||
struct configure_opts_combphy *cfg);
|
||||
|
||||
void rkx110_combrxphy_set_mode(struct rk_serdes *ser, enum combrx_phy_mode mode);
|
||||
void rkx110_combrxphy_set_rate(struct rk_serdes *ser, u64 rate);
|
||||
void rkx110_combrxphy_power_on(struct rk_serdes *ser, enum comb_phy_id id);
|
||||
void rkx110_combrxphy_power_off(struct rk_serdes *ser, enum comb_phy_id id);
|
||||
void rkx110_combrxphy_set_mode(struct rkx110_combrxphy *combrxphy, enum combrx_phy_mode mode);
|
||||
void rkx110_combrxphy_set_rate(struct rkx110_combrxphy *combrxphy, u64 rate);
|
||||
void rkx110_combrxphy_set_lanes(struct rkx110_combrxphy *combrxphy, uint8_t lanes);
|
||||
void rkx110_combrxphy_power_on(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id);
|
||||
void rkx110_combrxphy_power_off(struct rk_serdes *ser, struct rkx110_combrxphy *combrxphy,
|
||||
u8 dev_id, enum comb_phy_id id);
|
||||
|
||||
void rkx120_combtxphy_set_mode(struct rk_serdes *des, enum combtx_phy_mode mode);
|
||||
void rkx120_combtxphy_set_rate(struct rk_serdes *des, u64 rate);
|
||||
u64 rkx120_combtxphy_get_rate(struct rk_serdes *des);
|
||||
void rkx120_combtxphy_power_on(struct rk_serdes *des, u8 remote_id, u8 phy_id);
|
||||
void rkx120_combtxphy_power_off(struct rk_serdes *des, u8 remote_id);
|
||||
void rkx120_combtxphy_set_mode(struct rkx120_combtxphy *combtxphy, enum combtx_phy_mode mode);
|
||||
void rkx120_combtxphy_set_rate(struct rkx120_combtxphy *combtxphy, u64 rate);
|
||||
u64 rkx120_combtxphy_get_rate(struct rkx120_combtxphy *combtxphy);
|
||||
void rkx120_combtxphy_power_on(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id, u8 phy_id);
|
||||
void rkx120_combtxphy_power_off(struct rk_serdes *des, struct rkx120_combtxphy *combtxphy,
|
||||
u8 dev_id, u8 phy_id);
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user