From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 03 Jan 2024 09:43:39 +0000 Subject: [PATCH] update kernel to 5.10.198 --- kernel/drivers/mfd/rkx110_x120/pattern_gen.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 299 insertions(+), 11 deletions(-) diff --git a/kernel/drivers/mfd/rkx110_x120/pattern_gen.c b/kernel/drivers/mfd/rkx110_x120/pattern_gen.c index 488d372..8ad2574 100644 --- a/kernel/drivers/mfd/rkx110_x120/pattern_gen.c +++ b/kernel/drivers/mfd/rkx110_x120/pattern_gen.c @@ -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 @@ 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, -- Gitblit v1.6.2