diff options
Diffstat (limited to 'drivers/gpu/drm/mediatek/mtk_dpi.c')
-rw-r--r-- | drivers/gpu/drm/mediatek/mtk_dpi.c | 261 |
1 files changed, 201 insertions, 60 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index e61cd67b978f..630a4e301ef6 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -8,6 +8,7 @@ #include <linux/component.h> #include <linux/interrupt.h> #include <linux/kernel.h> +#include <linux/media-bus-format.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> @@ -22,6 +23,7 @@ #include <drm/drm_bridge.h> #include <drm/drm_bridge_connector.h> #include <drm/drm_crtc.h> +#include <drm/drm_edid.h> #include <drm/drm_of.h> #include <drm/drm_simple_kms_helper.h> @@ -55,12 +57,7 @@ enum mtk_dpi_out_channel_swap { enum mtk_dpi_out_color_format { MTK_DPI_COLOR_FORMAT_RGB, - MTK_DPI_COLOR_FORMAT_RGB_FULL, - MTK_DPI_COLOR_FORMAT_YCBCR_444, - MTK_DPI_COLOR_FORMAT_YCBCR_422, - MTK_DPI_COLOR_FORMAT_XV_YCC, - MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL, - MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL + MTK_DPI_COLOR_FORMAT_YCBCR_422 }; struct mtk_dpi { @@ -118,6 +115,27 @@ struct mtk_dpi_yc_limit { u16 c_bottom; }; +/** + * struct mtk_dpi_conf - Configuration of mediatek dpi. + * @cal_factor: Callback function to calculate factor value. + * @reg_h_fre_con: Register address of frequency control. + * @max_clock_khz: Max clock frequency supported for this SoCs in khz units. + * @edge_sel_en: Enable of edge selection. + * @output_fmts: Array of supported output formats. + * @num_output_fmts: Quantity of supported output formats. + * @is_ck_de_pol: Support CK/DE polarity. + * @swap_input_support: Support input swap function. + * @support_direct_pin: IP supports direct connection to dpi panels. + * @input_2pixel: Input pixel of dp_intf is 2 pixel per round, so enable this + * config to enable this feature. + * @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH + * (no shift). + * @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift). + * @channel_swap_shift: Shift value of channel swap. + * @yuv422_en_bit: Enable bit of yuv422. + * @csc_enable_bit: Enable bit of CSC. + * @pixels_per_iter: Quantity of transferred pixels per iteration. + */ struct mtk_dpi_conf { unsigned int (*cal_factor)(int clock); u32 reg_h_fre_con; @@ -125,6 +143,16 @@ struct mtk_dpi_conf { bool edge_sel_en; const u32 *output_fmts; u32 num_output_fmts; + bool is_ck_de_pol; + bool swap_input_support; + bool support_direct_pin; + bool input_2pixel; + u32 dimension_mask; + u32 hvsize_mask; + u32 channel_swap_shift; + u32 yuv422_en_bit; + u32 csc_enable_bit; + u32 pixels_per_iter; }; static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) @@ -153,12 +181,12 @@ static void mtk_dpi_disable(struct mtk_dpi *dpi) static void mtk_dpi_config_hsync(struct mtk_dpi *dpi, struct mtk_dpi_sync_param *sync) { - mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, - sync->sync_width << HPW, HPW_MASK); - mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, - sync->back_porch << HBP, HBP_MASK); + mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, sync->sync_width << HPW, + dpi->conf->dimension_mask << HPW); + mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->back_porch << HBP, + dpi->conf->dimension_mask << HBP); mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP, - HFP_MASK); + dpi->conf->dimension_mask << HFP); } static void mtk_dpi_config_vsync(struct mtk_dpi *dpi, @@ -166,17 +194,17 @@ static void mtk_dpi_config_vsync(struct mtk_dpi *dpi, u32 width_addr, u32 porch_addr) { mtk_dpi_mask(dpi, width_addr, - sync->sync_width << VSYNC_WIDTH_SHIFT, - VSYNC_WIDTH_MASK); - mtk_dpi_mask(dpi, width_addr, sync->shift_half_line << VSYNC_HALF_LINE_SHIFT, VSYNC_HALF_LINE_MASK); + mtk_dpi_mask(dpi, width_addr, + sync->sync_width << VSYNC_WIDTH_SHIFT, + dpi->conf->dimension_mask << VSYNC_WIDTH_SHIFT); mtk_dpi_mask(dpi, porch_addr, sync->back_porch << VSYNC_BACK_PORCH_SHIFT, - VSYNC_BACK_PORCH_MASK); + dpi->conf->dimension_mask << VSYNC_BACK_PORCH_SHIFT); mtk_dpi_mask(dpi, porch_addr, sync->front_porch << VSYNC_FRONT_PORCH_SHIFT, - VSYNC_FRONT_PORCH_MASK); + dpi->conf->dimension_mask << VSYNC_FRONT_PORCH_SHIFT); } static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi, @@ -210,13 +238,20 @@ static void mtk_dpi_config_pol(struct mtk_dpi *dpi, struct mtk_dpi_polarities *dpi_pol) { unsigned int pol; + unsigned int mask; - pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) | - (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) | - (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) | + mask = HSYNC_POL | VSYNC_POL; + pol = (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) | (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL); - mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, - CK_POL | DE_POL | HSYNC_POL | VSYNC_POL); + if (dpi->conf->is_ck_de_pol) { + mask |= CK_POL | DE_POL; + pol |= (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? + 0 : CK_POL) | + (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? + 0 : DE_POL); + } + + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, mask); } static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d) @@ -231,20 +266,36 @@ static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter) static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height) { - mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK); - mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK); + mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, + dpi->conf->hvsize_mask << HSIZE); + mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, + dpi->conf->hvsize_mask << VSIZE); } -static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi, - struct mtk_dpi_yc_limit *limit) +static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi) { - mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT, + struct mtk_dpi_yc_limit limit; + + if (drm_default_rgb_quant_range(&dpi->mode) == + HDMI_QUANTIZATION_RANGE_LIMITED) { + limit.y_bottom = 0x10; + limit.y_top = 0xfe0; + limit.c_bottom = 0x10; + limit.c_top = 0xfe0; + } else { + limit.y_bottom = 0; + limit.y_top = 0xfff; + limit.c_bottom = 0; + limit.c_top = 0xfff; + } + + mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_bottom << Y_LIMINT_BOT, Y_LIMINT_BOT_MASK); - mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP, + mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_top << Y_LIMINT_TOP, Y_LIMINT_TOP_MASK); - mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT, + mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_bottom << C_LIMIT_BOT, C_LIMIT_BOT_MASK); - mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP, + mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_top << C_LIMIT_TOP, C_LIMIT_TOP_MASK); } @@ -332,17 +383,21 @@ static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi, break; } - mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK); + mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, + val << dpi->conf->channel_swap_shift, + CH_SWAP_MASK << dpi->conf->channel_swap_shift); } static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable) { - mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN); + mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->yuv422_en_bit : 0, + dpi->conf->yuv422_en_bit); } static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable) { - mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE); + mtk_dpi_mask(dpi, DPI_CON, enable ? dpi->conf->csc_enable_bit : 0, + dpi->conf->csc_enable_bit); } static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) @@ -364,23 +419,24 @@ static void mtk_dpi_config_disable_edge(struct mtk_dpi *dpi) static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, enum mtk_dpi_out_color_format format) { - if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) || - (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) { - mtk_dpi_config_yuv422_enable(dpi, false); - mtk_dpi_config_csc_enable(dpi, true); - mtk_dpi_config_swap_input(dpi, false); - mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR); - } else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) || - (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) { + mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); + + if (format == MTK_DPI_COLOR_FORMAT_YCBCR_422) { mtk_dpi_config_yuv422_enable(dpi, true); mtk_dpi_config_csc_enable(dpi, true); - mtk_dpi_config_swap_input(dpi, true); - mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); + + /* + * If height is smaller than 720, we need to use RGB_TO_BT601 + * to transfer to yuv422. Otherwise, we use RGB_TO_JPEG. + */ + mtk_dpi_mask(dpi, DPI_MATRIX_SET, dpi->mode.hdisplay <= 720 ? + MATRIX_SEL_RGB_TO_BT601 : MATRIX_SEL_RGB_TO_JPEG, + INT_MATRIX_SEL_MASK); } else { mtk_dpi_config_yuv422_enable(dpi, false); mtk_dpi_config_csc_enable(dpi, false); - mtk_dpi_config_swap_input(dpi, false); - mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); + if (dpi->conf->swap_input_support) + mtk_dpi_config_swap_input(dpi, false); } } @@ -436,7 +492,6 @@ static int mtk_dpi_power_on(struct mtk_dpi *dpi) if (dpi->pinctrl && dpi->pins_dpi) pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi); - mtk_dpi_enable(dpi); return 0; err_pixel: @@ -449,7 +504,6 @@ err_refcount: static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct drm_display_mode *mode) { - struct mtk_dpi_yc_limit limit; struct mtk_dpi_polarities dpi_pol; struct mtk_dpi_sync_param hsync; struct mtk_dpi_sync_param vsync_lodd = { 0 }; @@ -471,7 +525,14 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, clk_set_rate(dpi->tvd_clk, pll_rate); pll_rate = clk_get_rate(dpi->tvd_clk); + /* + * Depending on the IP version, we may output a different amount of + * pixels for each iteration: divide the clock by this number and + * adjust the display porches accordingly. + */ vm.pixelclock = pll_rate / factor; + vm.pixelclock /= dpi->conf->pixels_per_iter; + if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) || (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE)) clk_set_rate(dpi->pixel_clk, vm.pixelclock * 2); @@ -484,20 +545,22 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n", pll_rate, vm.pixelclock); - limit.c_bottom = 0x0010; - limit.c_top = 0x0FE0; - limit.y_bottom = 0x0010; - limit.y_top = 0x0FE0; - dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING; dpi_pol.de_pol = MTK_DPI_POLARITY_RISING; dpi_pol.hsync_pol = vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; - hsync.sync_width = vm.hsync_len; - hsync.back_porch = vm.hback_porch; - hsync.front_porch = vm.hfront_porch; + + /* + * Depending on the IP version, we may output a different amount of + * pixels for each iteration: divide the clock by this number and + * adjust the display porches accordingly. + */ + hsync.sync_width = vm.hsync_len / dpi->conf->pixels_per_iter; + hsync.back_porch = vm.hback_porch / dpi->conf->pixels_per_iter; + hsync.front_porch = vm.hfront_porch / dpi->conf->pixels_per_iter; + hsync.shift_half_line = false; vsync_lodd.sync_width = vm.vsync_len; vsync_lodd.back_porch = vm.vback_porch; @@ -536,14 +599,20 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, else mtk_dpi_config_fb_size(dpi, vm.hactive, vm.vactive); - mtk_dpi_config_channel_limit(dpi, &limit); + mtk_dpi_config_channel_limit(dpi); mtk_dpi_config_bit_num(dpi, dpi->bit_num); mtk_dpi_config_channel_swap(dpi, dpi->channel_swap); - mtk_dpi_config_yc_map(dpi, dpi->yc_map); mtk_dpi_config_color_format(dpi, dpi->color_format); - mtk_dpi_config_2n_h_fre(dpi); - mtk_dpi_dual_edge(dpi); - mtk_dpi_config_disable_edge(dpi); + if (dpi->conf->support_direct_pin) { + mtk_dpi_config_yc_map(dpi, dpi->yc_map); + mtk_dpi_config_2n_h_fre(dpi); + mtk_dpi_dual_edge(dpi); + mtk_dpi_config_disable_edge(dpi); + } + if (dpi->conf->input_2pixel) { + mtk_dpi_mask(dpi, DPI_CON, DPINTF_INPUT_2P_EN, + DPINTF_INPUT_2P_EN); + } mtk_dpi_sw_reset(dpi, false); return 0; @@ -622,7 +691,10 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge, dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS; dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB; dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB; - dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB; + if (out_bus_format == MEDIA_BUS_FMT_YUYV8_1X16) + dpi->color_format = MTK_DPI_COLOR_FORMAT_YCBCR_422; + else + dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB; return 0; } @@ -658,6 +730,7 @@ static void mtk_dpi_bridge_enable(struct drm_bridge *bridge) mtk_dpi_power_on(dpi); mtk_dpi_set_display_mode(dpi, &dpi->mode); + mtk_dpi_enable(dpi); } static enum drm_mode_status @@ -781,6 +854,16 @@ static unsigned int mt8183_calculate_factor(int clock) return 2; } +static unsigned int mt8195_dpintf_calculate_factor(int clock) +{ + if (clock < 70000) + return 4; + else if (clock < 200000) + return 2; + else + return 1; +} + static const u32 mt8173_output_fmts[] = { MEDIA_BUS_FMT_RGB888_1X24, }; @@ -790,12 +873,26 @@ static const u32 mt8183_output_fmts[] = { MEDIA_BUS_FMT_RGB888_2X12_BE, }; +static const u32 mt8195_output_fmts[] = { + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_YUYV8_1X16, +}; + static const struct mtk_dpi_conf mt8173_conf = { .cal_factor = mt8173_calculate_factor, .reg_h_fre_con = 0xe0, .max_clock_khz = 300000, .output_fmts = mt8173_output_fmts, .num_output_fmts = ARRAY_SIZE(mt8173_output_fmts), + .pixels_per_iter = 1, + .is_ck_de_pol = true, + .swap_input_support = true, + .support_direct_pin = true, + .dimension_mask = HPW_MASK, + .hvsize_mask = HSIZE_MASK, + .channel_swap_shift = CH_SWAP, + .yuv422_en_bit = YUV422_EN, + .csc_enable_bit = CSC_ENABLE, }; static const struct mtk_dpi_conf mt2701_conf = { @@ -805,6 +902,15 @@ static const struct mtk_dpi_conf mt2701_conf = { .max_clock_khz = 150000, .output_fmts = mt8173_output_fmts, .num_output_fmts = ARRAY_SIZE(mt8173_output_fmts), + .pixels_per_iter = 1, + .is_ck_de_pol = true, + .swap_input_support = true, + .support_direct_pin = true, + .dimension_mask = HPW_MASK, + .hvsize_mask = HSIZE_MASK, + .channel_swap_shift = CH_SWAP, + .yuv422_en_bit = YUV422_EN, + .csc_enable_bit = CSC_ENABLE, }; static const struct mtk_dpi_conf mt8183_conf = { @@ -813,6 +919,15 @@ static const struct mtk_dpi_conf mt8183_conf = { .max_clock_khz = 100000, .output_fmts = mt8183_output_fmts, .num_output_fmts = ARRAY_SIZE(mt8183_output_fmts), + .pixels_per_iter = 1, + .is_ck_de_pol = true, + .swap_input_support = true, + .support_direct_pin = true, + .dimension_mask = HPW_MASK, + .hvsize_mask = HSIZE_MASK, + .channel_swap_shift = CH_SWAP, + .yuv422_en_bit = YUV422_EN, + .csc_enable_bit = CSC_ENABLE, }; static const struct mtk_dpi_conf mt8192_conf = { @@ -821,6 +936,29 @@ static const struct mtk_dpi_conf mt8192_conf = { .max_clock_khz = 150000, .output_fmts = mt8183_output_fmts, .num_output_fmts = ARRAY_SIZE(mt8183_output_fmts), + .pixels_per_iter = 1, + .is_ck_de_pol = true, + .swap_input_support = true, + .support_direct_pin = true, + .dimension_mask = HPW_MASK, + .hvsize_mask = HSIZE_MASK, + .channel_swap_shift = CH_SWAP, + .yuv422_en_bit = YUV422_EN, + .csc_enable_bit = CSC_ENABLE, +}; + +static const struct mtk_dpi_conf mt8195_dpintf_conf = { + .cal_factor = mt8195_dpintf_calculate_factor, + .max_clock_khz = 600000, + .output_fmts = mt8195_output_fmts, + .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts), + .pixels_per_iter = 4, + .input_2pixel = true, + .dimension_mask = DPINTF_HPW_MASK, + .hvsize_mask = DPINTF_HSIZE_MASK, + .channel_swap_shift = DPINTF_CH_SWAP, + .yuv422_en_bit = DPINTF_YUV422_EN, + .csc_enable_bit = DPINTF_CSC_ENABLE, }; static int mtk_dpi_probe(struct platform_device *pdev) @@ -945,6 +1083,9 @@ static const struct of_device_id mtk_dpi_of_ids[] = { { .compatible = "mediatek,mt8192-dpi", .data = &mt8192_conf, }, + { .compatible = "mediatek,mt8195-dp-intf", + .data = &mt8195_dpintf_conf, + }, { }, }; MODULE_DEVICE_TABLE(of, mtk_dpi_of_ids); |