// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2020 Rockchip Electronics Co., Ltd. * * Author: Guochun Huang */ #include #include "rk628.h" #include "rk628_cru.h" #include "rk628_config.h" #include "panel.h" #include "rk628_rgb.h" int rk628_rgb_parse(struct rk628 *rk628, struct device_node *rgb_np) { int ret = 0; /* input/output: rgb/bt1120 */ rk628->rgb.vccio_rgb = devm_regulator_get_optional(rk628->dev, "vccio-rgb"); if (IS_ERR(rk628->rgb.vccio_rgb)) rk628->rgb.vccio_rgb = NULL; /* input/output: bt1120 */ if ((rk628_input_is_bt1120(rk628) || rk628_output_is_bt1120(rk628))) { if (of_property_read_bool(rk628->dev->of_node, "bt1120-dual-edge")) rk628->rgb.bt1120_dual_edge = true; if (of_property_read_bool(rk628->dev->of_node, "bt1120-yc-swap")) rk628->rgb.bt1120_yc_swap = true; if (of_property_read_bool(rk628->dev->of_node, "bt1120-uv-swap")) rk628->rgb.bt1120_uv_swap = true; } /* output: rgb/bt1120 */ if (rk628_output_is_bt1120(rk628) || rk628_output_is_rgb(rk628)) ret = rk628_panel_info_get(rk628, rgb_np); return ret; } static int rk628_rgb_resolution_show(struct seq_file *s, void *data) { struct rk628 *rk628 = s->private; u16 width = 0, height = 0; u32 rgb_rx_eval_time, rgb_rx_clkrate; u64 ref_clk, pixel_clk; u32 val; rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS0, &val); rgb_rx_eval_time = (val & RGB_RX_EVAL_TIME_MASK) >> 16; rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS2, &val); rgb_rx_clkrate = val & RGB_RX_CLKRATE_MASK; ref_clk = rk628_cru_clk_get_rate(rk628, CGU_CLK_IMODET); pixel_clk = ref_clk * rgb_rx_clkrate; do_div(pixel_clk, rgb_rx_eval_time + 1); if (rk628_input_is_rgb(rk628)) { rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS4, &val); height = (val >> 16) & 0xffff; width = val & 0xffff; } else if (rk628_input_is_bt1120(rk628)) { rk628_i2c_read(rk628, GRF_SYSTEM_STATUS3, &val); height = val & DECODER_1120_LAST_LINE_NUM_MASK; rk628_i2c_read(rk628, GRF_SYSTEM_STATUS4, &val); width = val & DECODER_1120_LAST_PIX_NUM_MASK; } seq_printf(s, "%dx%d pclk:%llu\n", width, height, pixel_clk); return 0; } static int rk628_rgb_resolution_open(struct inode *inode, struct file *file) { return single_open(file, rk628_rgb_resolution_show, inode->i_private); } static const struct file_operations rk628_rgb_resolution_fops = { .owner = THIS_MODULE, .open = rk628_rgb_resolution_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; void rk628_rgb_decoder_create_debugfs_file(struct rk628 *rk628) { if (rk628->version == RK628D_VERSION) return; if (rk628_input_is_rgb(rk628) || rk628_input_is_bt1120(rk628)) debugfs_create_file("rgb_resolution", 0400, rk628->debug_dir, rk628, &rk628_rgb_resolution_fops); } static void rk628_rgb_decoder_enable(struct rk628 *rk628) { /* config sw_input_mode RGB */ rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK, SW_INPUT_MODE(INPUT_MODE_RGB)); if (rk628->version == RK628F_VERSION) { rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS0, RGB_RX_MODET_EN | RGB_RX_DCLK_EN, RGB_RX_MODET_EN | RGB_RX_DCLK_EN); rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS3, RGB_RX_CNT_EN_MASK, RGB_RX_CNT_EN(1)); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0); } /* pinctrl for vop pin */ rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff); rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555); rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b); } static void rk628_rgb_encoder_enable(struct rk628 *rk628) { int voltage = 0; u32 d_strength, clk_strength; u64 dclk_delay; rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_BT_DATA_OEN_MASK | SW_OUTPUT_RGB_MODE_MASK, SW_OUTPUT_RGB_MODE(OUTPUT_MODE_RGB >> 3)); if (rk628->version != RK628F_VERSION) rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN); /* pinctrl for vop pin */ rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff); rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555); rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b); /* * Under the same drive strength and DCLK delay, the signal behaves * differently under different voltage power domains. In order to * center the eye diagram of the signal, have sufficient signal setup * and hold time, and ensure that the signal does not overshoot, the * drive strength and DCLK delay need to be set for the power domains * of different voltages. */ if (rk628->rgb.vccio_rgb) voltage = regulator_get_voltage(rk628->rgb.vccio_rgb); switch (voltage) { case 1800000: d_strength = 3; clk_strength = 3; dclk_delay = 0x10000000; break; case 3300000: d_strength = 1; clk_strength = 2; dclk_delay = 0x100000000; break; default: d_strength = 1; clk_strength = 2; dclk_delay = 0x100000000; } /* rk628: modify IO drive strength for RGB */ if (rk628->version == RK628F_VERSION) d_strength = d_strength * 0x1111 | 0xffff0000; else { d_strength = 0xffff7777; clk_strength = 7; } rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, d_strength); rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, d_strength & 0xf0fff0ff); rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, clk_strength | 0x000f0000); /* rk628: modify DCLK delay for RGB */ if (rk628->version == RK628F_VERSION) { rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, dclk_delay & 0xffffffff); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, dclk_delay >> 32); } } static void rk628_rgb_encoder_disable(struct rk628 *rk628) { } void rk628_rgb_rx_enable(struct rk628 *rk628) { rk628_rgb_decoder_enable(rk628); } void rk628_rgb_tx_enable(struct rk628 *rk628) { rk628_rgb_encoder_enable(rk628); rk628_panel_prepare(rk628); rk628_panel_enable(rk628); } void rk628_rgb_tx_disable(struct rk628 *rk628) { rk628_panel_disable(rk628); rk628_panel_unprepare(rk628); rk628_rgb_encoder_disable(rk628); } static void rk628_bt1120_decoder_timing_cfg(struct rk628 *rk628) { u32 src_hsync_len, src_hback_porch, src_hfront_porch, src_hactive; u32 src_vsync_len, src_vback_porch, src_vfront_porch, src_vactive; u32 dsp_htotal, dsp_hs_end, dsp_hact_st; u32 dsp_vtotal, dsp_vs_end, dsp_vact_st; u32 dsp_hbor_st, dsp_vbor_st; u16 bor_left = 0, bor_up = 0; struct rk628_display_mode *src = &rk628->src_mode; src_hactive = src->hdisplay; src_hsync_len = src->hsync_end - src->hsync_start; src_hback_porch = src->htotal - src->hsync_end; src_hfront_porch = src->hsync_start - src->hdisplay; src_vsync_len = src->vsync_end - src->vsync_start; src_vback_porch = src->vtotal - src->vsync_end; src_vfront_porch = src->vsync_start - src->vdisplay; src_vactive = src->vdisplay; dsp_htotal = src_hsync_len + src_hback_porch + src_hactive + src_hfront_porch; dsp_vtotal = src_vsync_len + src_vback_porch + src_vactive + src_vfront_porch; dsp_hs_end = src_hsync_len; dsp_vs_end = src_vsync_len; dsp_hbor_st = src_hsync_len + src_hback_porch; dsp_vbor_st = src_vsync_len + src_vback_porch; dsp_hact_st = dsp_hbor_st + bor_left; dsp_vact_st = dsp_vbor_st + bor_up; if (rk628->version == RK628F_VERSION) rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS0, RGB_RX_MODET_EN | RGB_RX_DCLK_EN, RGB_RX_MODET_EN | RGB_RX_DCLK_EN); rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL0, BT1120_DSP_HS_END(dsp_hs_end) | BT1120_DSP_HTOTAL(dsp_htotal)); rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL1, BT1120_DSP_HACT_ST(dsp_hact_st)); rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL2, BT1120_DSP_VS_END(dsp_vs_end) | BT1120_DSP_VTOTAL(dsp_vtotal)); rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL3, BT1120_DSP_VACT_ST(dsp_vact_st)); } static void rk628_bt1120_decoder_enable(struct rk628 *rk628) { struct rk628_display_mode *mode = rk628_display_get_src_mode(rk628); rk628_set_input_bus_format(rk628, BUS_FMT_YUV422); /* pinctrl for vop pin */ rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff); rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555); rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b); /* config sw_input_mode bt1120 */ rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK, SW_INPUT_MODE(INPUT_MODE_BT1120)); if (rk628->version == RK628F_VERSION) rk628_bt1120_decoder_timing_cfg(rk628); /* operation resetn_bt1120dec */ rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10001000); rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10000000); if (rk628->rgb.bt1120_dual_edge) { rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0, DEC_DUALEDGE_EN, DEC_DUALEDGE_EN); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0); } else { if (rk628->version == RK628F_VERSION) { rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x08000000); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0); } } rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON1, SW_SET_X_MASK, SW_SET_X(mode->hdisplay)); rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON2, SW_SET_Y_MASK, SW_SET_Y(mode->vdisplay)); rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_BT_DATA_OEN_MASK | SW_INPUT_MODE_MASK, SW_BT_DATA_OEN | SW_INPUT_MODE(INPUT_MODE_BT1120)); rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0, SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN | SW_BT1120_YC_SWAP | SW_BT1120_UV_SWAP, SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN | (rk628->rgb.bt1120_yc_swap ? SW_BT1120_YC_SWAP : 0) | (rk628->rgb.bt1120_uv_swap ? SW_BT1120_UV_SWAP : 0)); } static void rk628_bt1120_encoder_enable(struct rk628 *rk628) { u32 val = 0; int voltage = 0; u32 strength; u64 dclk_delay; rk628_set_output_bus_format(rk628, BUS_FMT_YUV422); /* pinctrl for vop pin */ rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff); rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555); rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b); rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_BT_DATA_OEN_MASK | SW_OUTPUT_RGB_MODE_MASK, SW_OUTPUT_RGB_MODE(OUTPUT_MODE_BT1120 >> 3)); if (rk628->version != RK628F_VERSION) rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN); /* * Under the same drive strength and DCLK delay, the signal behaves * differently under different voltage power domains. In order to * center the eye diagram of the signal, have sufficient signal setup * and hold time, and ensure that the signal does not overshoot, the * drive strength and DCLK delay need to be set for the power domains * of different voltages. */ if (rk628->rgb.vccio_rgb) voltage = regulator_get_voltage(rk628->rgb.vccio_rgb); switch (voltage) { case 1800000: strength = 3; dclk_delay = 0x100000000; break; case 3300000: strength = 1; dclk_delay = 0x1000000000; break; default: strength = 1; dclk_delay = 0x1000000000; } /* rk628: modify IO drive strength for BT1120 */ if (rk628->version == RK628F_VERSION) strength = strength * 0x1111 | 0xffff0000; else strength = 0xffff1111; rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, strength); rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, strength); rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, strength); rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, strength); rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, strength); rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, strength); rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, strength & 0xf0fff0ff); rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, strength & 0x000f000f); /* rk628: modify DCLK delay for BT1120 */ if (rk628->rgb.bt1120_dual_edge) { val |= ENC_DUALEDGE_EN(1); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0); } else { if (rk628->version == RK628F_VERSION) { rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, dclk_delay & 0xffffffff); rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, dclk_delay >> 32); } } val |= rk628->rgb.bt1120_yc_swap ? BT1120_YC_SWAP(1) : BT1120_YC_SWAP(0); val |= rk628->rgb.bt1120_uv_swap ? BT1120_UV_SWAP(1) : BT1120_UV_SWAP(0); rk628_i2c_write(rk628, GRF_RGB_ENC_CON, val); } void rk628_bt1120_rx_enable(struct rk628 *rk628) { rk628_bt1120_decoder_enable(rk628); } void rk628_bt1120_tx_enable(struct rk628 *rk628) { rk628_bt1120_encoder_enable(rk628); }