mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
mfd: rkx110_x120: support pattern generator for V1
Signed-off-by: Zhang Yubing <yubing.zhang@rock-chips.com> Change-Id: I0fef8a64dd5602ac8642142b247b4198baef56cb
This commit is contained in:
@@ -341,6 +341,8 @@ static HAL_Status RKX11x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName
|
||||
/* link(dclk): Allowed to change PLL rate if need ! */
|
||||
case RKX111_CPS_DCLK_D_DSI_0_REC:
|
||||
case RKX111_CPS_DCLK_D_DSI_1_REC:
|
||||
case RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:
|
||||
case RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:
|
||||
case RKX110_CPS_CLK_2X_LVDS_RKLINK_TX:
|
||||
/* i2s */
|
||||
case RKX110_CPS_CLK_I2S_SRC_RKLINK_TX:
|
||||
@@ -384,9 +386,6 @@ static HAL_Status RKX11x_HAL_CRU_ClkSetFreq(struct hwclk *hw, uint32_t clockName
|
||||
/* bus */
|
||||
case RKX110_CPS_DCLK_RX_PRE:
|
||||
case RKX111_CPS_DCLK_RX_PRE_200M:
|
||||
/* lvds */
|
||||
case RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:
|
||||
case RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:
|
||||
/* camera */
|
||||
case RKX110_CPS_CLK_CAM0_OUT2IO:
|
||||
case RKX110_CPS_CLK_CAM1_OUT2IO:
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "rkx110_x120.h"
|
||||
#include "rkx110_x120_display.h"
|
||||
#include "hal/cru_api.h"
|
||||
|
||||
#define PATTERN_GEN_PATTERN_CTRL 0x0000
|
||||
#define PATTERN_START_PCLK BIT(31)
|
||||
@@ -29,11 +31,10 @@
|
||||
#define PATTERN_GEN_VALUE0 0x0014
|
||||
#define PATTERN_GEN_VALUE1 0x0018
|
||||
|
||||
static void pattern_gen_enable(struct pattern_gen *pattern_gen)
|
||||
static void pattern_gen_config(struct i2c_client *client, struct pattern_gen *pattern_gen,
|
||||
struct videomode *vm)
|
||||
{
|
||||
struct i2c_client *client = pattern_gen->chip->client;
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
const struct videomode *vm = serdes->vm;
|
||||
|
||||
serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
|
||||
PATTERN_RECTANGLE_H | PATTERN_RECTANGLE_V,
|
||||
@@ -53,24 +54,311 @@ static void pattern_gen_enable(struct pattern_gen *pattern_gen)
|
||||
serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG3,
|
||||
FIELD_PREP(PATTERN_HSA, vm->hsync_len));
|
||||
|
||||
serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
|
||||
PATTERN_START_PCLK,
|
||||
FIELD_PREP(PATTERN_START_PCLK, 1));
|
||||
serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
|
||||
BIT(pattern_gen->link_src_offset + 16) |
|
||||
BIT(pattern_gen->link_src_offset));
|
||||
}
|
||||
|
||||
static void pattern_stop_stream(struct pattern_gen *pattern_gen)
|
||||
{
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
|
||||
if (serdes->version != SERDES_V1)
|
||||
return;
|
||||
|
||||
if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
|
||||
return;
|
||||
|
||||
rk_serdes_display_video_start(serdes, pattern_gen->route, false);
|
||||
|
||||
if (!strcmp(pattern_gen->name, "lvds0")) {
|
||||
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
|
||||
RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
|
||||
} else if (!strcmp(pattern_gen->name, "lvds1")) {
|
||||
hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
|
||||
RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
|
||||
} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
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);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi0")) {
|
||||
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);
|
||||
rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 0, false);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi1")) {
|
||||
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);
|
||||
rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 1, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void pattern_start_stream(struct pattern_gen *pattern_gen, bool is_pattern_stream)
|
||||
{
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
struct videomode *vm = &pattern_gen->route->vm;
|
||||
u32 delay_length;
|
||||
|
||||
if (serdes->version != SERDES_V1)
|
||||
return;
|
||||
|
||||
if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
|
||||
return;
|
||||
|
||||
if (!strcmp(pattern_gen->name, "lvds0")) {
|
||||
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
|
||||
RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
|
||||
} else if (!strcmp(pattern_gen->name, "lvds1")) {
|
||||
hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
|
||||
RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
|
||||
} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
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);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi0")) {
|
||||
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);
|
||||
|
||||
rkx110_linktx_dsi_type_select(serdes, DEVICE_LOCAL, 0,
|
||||
is_pattern_stream ? false : true);
|
||||
if (is_pattern_stream)
|
||||
delay_length = vm->hsync_len + vm->hback_porch +
|
||||
vm->hactive + vm->hfront_porch;
|
||||
else
|
||||
delay_length = (vm->vfront_porch + 1) * (vm->hsync_len +
|
||||
vm->hback_porch + vm->hactive + vm->hfront_porch);
|
||||
rkx110_linktx_dsi_deley_length_config(serdes, DEVICE_LOCAL, 0, delay_length);
|
||||
rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 0, true);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi1")) {
|
||||
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);
|
||||
|
||||
rkx110_linktx_dsi_type_select(serdes, DEVICE_LOCAL, 1,
|
||||
is_pattern_stream ? false : true);
|
||||
if (is_pattern_stream)
|
||||
delay_length = vm->hsync_len + vm->hback_porch +
|
||||
vm->hactive + vm->hfront_porch;
|
||||
else
|
||||
delay_length = (vm->vfront_porch + 1) * (vm->hsync_len +
|
||||
vm->hback_porch + vm->hactive + vm->hfront_porch);
|
||||
rkx110_linktx_dsi_deley_length_config(serdes, DEVICE_LOCAL, 1, delay_length);
|
||||
rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 1, true);
|
||||
}
|
||||
|
||||
rk_serdes_display_video_start(serdes, pattern_gen->route, true);
|
||||
}
|
||||
|
||||
static void pattern_switch_clk_to_pattern(struct pattern_gen *pattern_gen, struct videomode *vm)
|
||||
{
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk;
|
||||
|
||||
if (serdes->version != SERDES_V1)
|
||||
return;
|
||||
|
||||
if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
|
||||
return;
|
||||
|
||||
if (!strcmp(pattern_gen->name, "lvds0")) {
|
||||
hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, vm->pixelclock);
|
||||
dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN));
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_PATTERN_GEN);
|
||||
} else if (!strcmp(pattern_gen->name, "lvds1")) {
|
||||
hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, vm->pixelclock);
|
||||
dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN));
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_PATTERN_GEN);
|
||||
} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, vm->pixelclock);
|
||||
dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN));
|
||||
hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, vm->pixelclock);
|
||||
dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:%d\n",
|
||||
hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN));
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_PATTERN_GEN);
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_PATTERN_GEN);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi0")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_PATTERN_GEN);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi1")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_PATTERN_GEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void pattern_switch_clk_to_stream(struct pattern_gen *pattern_gen)
|
||||
{
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk;
|
||||
|
||||
if (serdes->version != SERDES_V1)
|
||||
return;
|
||||
|
||||
if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
|
||||
return;
|
||||
|
||||
if (!strcmp(pattern_gen->name, "lvds0")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_RKLINK_TX_PRE);
|
||||
} else if (!strcmp(pattern_gen->name, "lvds1")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_RKLINK_TX_PRE);
|
||||
} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_RKLINK_TX_PRE);
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_RKLINK_TX_PRE);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi0")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_0_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_RKLINK_TX_PRE);
|
||||
} else if (!strcmp(pattern_gen->name, "dsi1")) {
|
||||
hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_1_RKLINK_TX_SEL,
|
||||
RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_RKLINK_TX_PRE);
|
||||
}
|
||||
}
|
||||
|
||||
static int pattern_get_route(struct pattern_gen *pattern_gen)
|
||||
{
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
struct rk_serdes_route *route;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < serdes->route_nr; i++) {
|
||||
route = serdes->route[i];
|
||||
|
||||
if (pattern_gen->chip == &serdes->chip[DEVICE_LOCAL]) {
|
||||
if ((pattern_gen->type == route->local_port0) ||
|
||||
(pattern_gen->type == route->local_port1)) {
|
||||
pattern_gen->route = route;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pattern_gen->chip == &serdes->chip[DEVICE_REMOTE0]) {
|
||||
if ((pattern_gen->type == route->remote0_port0) ||
|
||||
(pattern_gen->type == route->remote0_port1)) {
|
||||
pattern_gen->route = route;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern_gen->chip == &serdes->chip[DEVICE_REMOTE1]) {
|
||||
if ((pattern_gen->type == route->remote1_port0) ||
|
||||
(pattern_gen->type == route->remote1_port1)) {
|
||||
pattern_gen->route = route;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= serdes->route_nr) {
|
||||
dev_info(serdes->dev, "can't find the %s in route\n", pattern_gen->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pattern_gen_enable(struct pattern_gen *pattern_gen)
|
||||
{
|
||||
struct i2c_client *client = pattern_gen->chip->client;
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
struct videomode vm;
|
||||
int ret;
|
||||
|
||||
ret = pattern_get_route(pattern_gen);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
memcpy(&vm, &pattern_gen->route->vm, sizeof(vm));
|
||||
|
||||
pattern_stop_stream(pattern_gen);
|
||||
if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
struct pattern_gen *lvds0_pat = pattern_gen + 1;
|
||||
struct pattern_gen *lvds1_pat = pattern_gen + 2;
|
||||
|
||||
vm.hactive /= 2;
|
||||
vm.hfront_porch /= 2;
|
||||
vm.hback_porch /= 2;
|
||||
vm.hsync_len /= 2;
|
||||
vm.pixelclock /= 2;
|
||||
|
||||
pattern_switch_clk_to_pattern(pattern_gen, &vm);
|
||||
pattern_gen_config(client, lvds0_pat, &vm);
|
||||
pattern_gen_config(client, lvds1_pat, &vm);
|
||||
serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
|
||||
BIT(pattern_gen->link_src_offset + 16) |
|
||||
BIT(pattern_gen->link_src_offset));
|
||||
} else {
|
||||
pattern_switch_clk_to_pattern(pattern_gen, &vm);
|
||||
pattern_gen_config(client, pattern_gen, &vm);
|
||||
serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
|
||||
PATTERN_START_PCLK,
|
||||
FIELD_PREP(PATTERN_START_PCLK, 1));
|
||||
}
|
||||
|
||||
pattern_start_stream(pattern_gen, true);
|
||||
}
|
||||
|
||||
static void pattern_gen_disable(struct pattern_gen *pattern_gen)
|
||||
{
|
||||
struct i2c_client *client = pattern_gen->chip->client;
|
||||
struct rk_serdes *serdes = pattern_gen->chip->serdes;
|
||||
int ret;
|
||||
|
||||
serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
|
||||
BIT(pattern_gen->link_src_offset + 16));
|
||||
serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
|
||||
PATTERN_START_PCLK,
|
||||
FIELD_PREP(PATTERN_START_PCLK, 0));
|
||||
ret = pattern_get_route(pattern_gen);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
pattern_stop_stream(pattern_gen);
|
||||
if (!strcmp(pattern_gen->name, "dual-lvds")) {
|
||||
struct pattern_gen *lvds0_pat = pattern_gen + 1;
|
||||
struct pattern_gen *lvds1_pat = pattern_gen + 2;
|
||||
|
||||
serdes->i2c_write_reg(client, lvds0_pat->link_src_reg,
|
||||
BIT(lvds0_pat->link_src_offset + 16));
|
||||
serdes->i2c_write_reg(client, lvds1_pat->link_src_reg,
|
||||
BIT(lvds1_pat->link_src_offset + 16));
|
||||
serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
|
||||
BIT(pattern_gen->link_src_offset + 16));
|
||||
} else {
|
||||
serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
|
||||
BIT(pattern_gen->link_src_offset + 16));
|
||||
serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
|
||||
PATTERN_START_PCLK,
|
||||
FIELD_PREP(PATTERN_START_PCLK, 0));
|
||||
}
|
||||
|
||||
pattern_switch_clk_to_stream(pattern_gen);
|
||||
pattern_start_stream(pattern_gen, false);
|
||||
}
|
||||
|
||||
static ssize_t pattern_gen_write(struct file *file, const char __user *ubuf,
|
||||
|
||||
@@ -15,21 +15,30 @@ static struct pattern_gen rkx110_pattern_gen[] = {
|
||||
.base = RKX110_PATTERN_GEN_DSI0_BASE,
|
||||
.link_src_reg = SER_GRF_SOC_CON4,
|
||||
.link_src_offset = 12,
|
||||
.type = RK_SERDES_DSI_RX0,
|
||||
}, {
|
||||
.name = "dsi1",
|
||||
.base = RKX110_PATTERN_GEN_DSI1_BASE,
|
||||
.link_src_reg = SER_GRF_SOC_CON4,
|
||||
.link_src_offset = 13,
|
||||
.type = RK_SERDES_DSI_RX1,
|
||||
}, {
|
||||
.name = "dual-lvds",
|
||||
.link_src_reg = SER_GRF_SOC_CON1,
|
||||
.link_src_offset = 14,
|
||||
.type = RK_SERDES_DUAL_LVDS_RX,
|
||||
}, {
|
||||
.name = "lvds0",
|
||||
.base = RKX110_PATTERN_GEN_LVDS0_BASE,
|
||||
.link_src_reg = SER_GRF_SOC_CON4,
|
||||
.link_src_offset = 14,
|
||||
.type = RK_SERDES_LVDS_RX0,
|
||||
}, {
|
||||
.name = "lvds1",
|
||||
.base = RKX110_PATTERN_GEN_LVDS1_BASE,
|
||||
.link_src_reg = SER_GRF_SOC_CON4,
|
||||
.link_src_offset = 15,
|
||||
.type = RK_SERDES_LVDS_RX1,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
#define DSI_VSA(x) UPDATE(x, 9, 0)
|
||||
|
||||
#define SER_RKLINK_DSI_REC3(x) LINK_REG(0x0014 + 0x10 * x)
|
||||
#define DSI_DELAY_LENGTH_MASK GENMASK(31, 12)
|
||||
#define DSI_DELAY_LENGTH(x) UPDATE(x, 31, 12)
|
||||
#define DSI_HSA(x) UPDATE(x, 11, 0)
|
||||
|
||||
@@ -552,6 +553,37 @@ static int rkx110_linktx_input_port_cfg(struct rk_serdes *serdes, u8 dev_id, u32
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx110_linktx_dsi_rec_start(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool enable)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC0(dsi_id), DSI_REC_START,
|
||||
enable ? DSI_REC_START : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx110_linktx_dsi_type_select(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool is_cmd)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC0(dsi_id), DSI_CMD_TYPE,
|
||||
is_cmd ? DSI_CMD_TYPE : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rkx110_linktx_dsi_deley_length_config(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id,
|
||||
u32 length)
|
||||
{
|
||||
struct i2c_client *client = serdes->chip[dev_id].client;
|
||||
|
||||
serdes->i2c_update_bits(client, SER_RKLINK_DSI_REC3(dsi_id), DSI_DELAY_LENGTH_MASK,
|
||||
DSI_DELAY_LENGTH(length));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_serdes_link_tx_dsi_enable(struct rk_serdes *serdes, struct rk_serdes_route *route,
|
||||
int id)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <video/videomode.h>
|
||||
|
||||
#define MAX_PANEL 2
|
||||
#define RK_SERDES_MAX_ROUTE 2
|
||||
#define RK_SERDES_PASSTHROUGH_CNT 11
|
||||
|
||||
#define SERDES_VERSION_V0(type) 0x2201
|
||||
@@ -237,9 +237,11 @@ struct rk_serdes_chip {
|
||||
struct pattern_gen {
|
||||
const char *name;
|
||||
struct rk_serdes_chip *chip;
|
||||
struct rk_serdes_route *route;
|
||||
u32 base;
|
||||
u32 link_src_reg;
|
||||
u8 link_src_offset;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
struct rk_serdes_pt_pin {
|
||||
@@ -283,7 +285,7 @@ struct rk_serdes {
|
||||
struct dentry *debugfs_remote1;
|
||||
struct dentry *debugfs_rate;
|
||||
|
||||
struct videomode *vm;
|
||||
struct rk_serdes_route *route[RK_SERDES_MAX_ROUTE];
|
||||
u32 stream_type;
|
||||
u32 version;
|
||||
u8 remote_nr;
|
||||
@@ -384,4 +386,9 @@ int rkx110_irq_handler(struct rk_serdes *serdes, u8 dev_id);
|
||||
void rkx120_irq_enable(struct rk_serdes *serdes, u8 dev_id);
|
||||
void rkx120_irq_disable(struct rk_serdes *serdes, u8 dev_id);
|
||||
int rkx120_irq_handler(struct rk_serdes *serdes, u8 dev_id);
|
||||
|
||||
int rkx110_linktx_dsi_rec_start(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool enable);
|
||||
int rkx110_linktx_dsi_type_select(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id, bool is_cmd);
|
||||
int rkx110_linktx_dsi_deley_length_config(struct rk_serdes *serdes, u8 dev_id, u8 dsi_id,
|
||||
u32 length);
|
||||
#endif
|
||||
|
||||
@@ -67,7 +67,7 @@ int rk_serdes_display_route_prepare(struct rk_serdes *serdes, struct rk_serdes_r
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rk_serdes_display_video_start(struct rk_serdes *serdes,
|
||||
int rk_serdes_display_video_start(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, bool enable)
|
||||
{
|
||||
if (route->local_port0) {
|
||||
|
||||
@@ -13,5 +13,7 @@ int rk_serdes_display_route_enable(struct rk_serdes *serdes, struct rk_serdes_ro
|
||||
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);
|
||||
int rk_serdes_display_video_start(struct rk_serdes *serdes,
|
||||
struct rk_serdes_route *route, bool enable);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -693,11 +693,15 @@ static int serdes_panel_probe(struct platform_device *pdev)
|
||||
if (sd_panel->route.route_flag & ROUTE_MULTI_CHANNEL)
|
||||
serdes->channel_nr = 2;
|
||||
|
||||
if (sd_panel->route.local_port0 && sd_panel->id == 0)
|
||||
if (sd_panel->route.local_port0 && sd_panel->id == 0) {
|
||||
serdes->route[0] = &sd_panel->route;
|
||||
serdes->route_nr++;
|
||||
}
|
||||
|
||||
if (sd_panel->route.local_port1 && sd_panel->id == 1)
|
||||
if (sd_panel->route.local_port1 && sd_panel->id == 1) {
|
||||
serdes->route[1] = &sd_panel->route;
|
||||
serdes->route_nr++;
|
||||
}
|
||||
|
||||
if (serdes->route_nr == 2)
|
||||
serdes->channel_nr = 2;
|
||||
|
||||
@@ -21,16 +21,24 @@ static struct pattern_gen rkx120_pattern_gen[] = {
|
||||
.base = RKX120_PATTERN_GEN_DSI_BASE,
|
||||
.link_src_reg = DES_GRF_SOC_CON2,
|
||||
.link_src_offset = 12,
|
||||
.type = RK_SERDES_DSI_TX0,
|
||||
}, {
|
||||
.name = "dual-lvds",
|
||||
.link_src_reg = DES_GRF_SOC_CON1,
|
||||
.link_src_offset = 14,
|
||||
.type = RK_SERDES_DUAL_LVDS_TX,
|
||||
}, {
|
||||
.name = "lvds0",
|
||||
.base = RKX120_PATTERN_GEN_LVDS0_BASE,
|
||||
.link_src_reg = DES_GRF_SOC_CON2,
|
||||
.link_src_offset = 13,
|
||||
.type = RK_SERDES_LVDS_TX0,
|
||||
}, {
|
||||
.name = "lvds1",
|
||||
.base = RKX120_PATTERN_GEN_LVDS1_BASE,
|
||||
.link_src_reg = DES_GRF_SOC_CON2,
|
||||
.link_src_offset = 14,
|
||||
.type = RK_SERDES_LVDS_TX1,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
@@ -236,9 +244,14 @@ static const struct file_operations rkx120_reg_fops = {
|
||||
void rkx120_debugfs_init(struct rk_serdes_chip *chip, struct dentry *dentry)
|
||||
{
|
||||
const struct rk_serdes_reg *regs = rkx120_regs;
|
||||
struct pattern_gen *pattern_gen = rkx120_pattern_gen;
|
||||
struct pattern_gen *pattern_gen;
|
||||
struct dentry *dir;
|
||||
|
||||
pattern_gen = devm_kmemdup(chip->serdes->dev, &rkx120_pattern_gen,
|
||||
sizeof(rkx120_pattern_gen), GFP_KERNEL);
|
||||
if (!pattern_gen)
|
||||
return;
|
||||
|
||||
dir = debugfs_create_dir("registers", dentry);
|
||||
if (!IS_ERR(dir)) {
|
||||
while (regs->name) {
|
||||
|
||||
Reference in New Issue
Block a user