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:
Zhang Yubing
2023-09-08 15:28:59 +08:00
committed by 张玉炳
parent 339c882a12
commit e0a3fc8778
16 changed files with 1169 additions and 715 deletions
+1
View File
@@ -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 \
+4 -2
View File
@@ -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;
}
+44 -32
View File
@@ -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;
}
+11 -5
View File
@@ -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);
}
+188 -99
View File
@@ -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,
+24 -12
View File
@@ -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);
+54 -236
View File
@@ -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
+194 -97
View File
@@ -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", &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;
}
+6 -4
View File
@@ -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;
}
+49 -52
View File
@@ -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;
}
+29 -28
View File
@@ -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)
+1 -1
View File
@@ -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);
+259 -138
View File
@@ -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 -9
View File
@@ -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