/* * Copyright (C) 2020-2024, ArtInChip Technology Co., Ltd * Authors: Ning Fang * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include "artinchip_fb.h" #include "aic_hal_disp_reg_util.h" #include "aic_hal_de.h" #define CSC_COEFFS_NUM 12 #define CCM_COEF_NUM 12 #define GAMMA_COEF_NUM 16 static int yuv2rgb_bt601_limit[3][4] = { {1192, 0, 1634, -3269}, {1192, -401, -833, 2467}, {1192, 2066, 0, -4131} }; static int yuv2rgb_bt709_limit[3][4] = { {1192, 0, 1836, -3970}, {1192, -218, -546, 1230}, {1192, 2163, 0, -4624} }; static int yuv2rgb_bt601_full[3][4] = { {1024, 0, 1436, -2871}, {1024, -352, -731, 2167}, {1024, 1815, 0, -3629} }; static int yuv2rgb_bt709_full[3][4] = { {1024, 0, 1613, -3225}, {1024, -192, -479, 1342}, {1024, 1900, 0, -3800} }; static int rgb2yuv_bt709_full[4][4] = { {218, 732, 74, 0}, {-116, -394, 512, 128 * 1024}, {512, -464, -46, 128 * 1024}, {0, 0, 0, 1024}, }; static int sin_table[60] = { -1985, -1922, -1859, -1795, -1731, -1665, -1600, -1534, -1467, -1400, -1333, -1265, -1197, -1129, -1060, -990, -921, -851, -781, -711, -640, -570, -499, -428, -356, -285, -214, -142, -71, 0, 71, 142, 214, 285, 356, 428, 499, 570, 640, 711, 781, 851, 921, 990, 1060, 1129, 1197, 1265, 1333, 1400, 1467, 1534, 1600, 1665, 1731, 1795, 1859, 1922, 1985, 2047, }; static int cos_table[60] = { 3582, 3616, 3649, 3681, 3712, 3741, 3770, 3797, 3823, 3848, 3872, 3895, 3917, 3937, 3956, 3974, 3991, 4006, 4020, 4033, 4045, 4056, 4065, 4073, 4080, 4086, 4090, 4093, 4095, 4096, 4095, 4093, 4090, 4086, 4080, 4073, 4065, 4056, 4045, 4033, 4020, 4006, 3991, 3974, 3956, 3937, 3917, 3895, 3872, 3848, 3823, 3797, 3770, 3741, 3712, 3681, 3649, 3616, 3582, 3547, }; /* * Layout of factors in table: * [green red hight low] */ static int qos_cfg[4][4] = { [QOS_V_P0_CFG] = { 0x0d, 0x0d, 0x20, 0x10, }, [QOS_V_P1_CFG] = { 0x0d, 0x0d, 0x20, 0x10, }, [QOS_V_P2_CFG] = { 0x0d, 0x0d, 0x20, 0x10, }, [QOS_UI_CFG] = { 0x0d, 0x0d, 0x60, 0x40, }, }; #define QOS_OUTSTANDING 0x1f #define QOS_DMAR_URGENT_TH 0x40 #if defined(AIC_DE_DRV_V10) || defined(AIC_DE_V10) static const unsigned int scaling_coeffs[4][32] = { [0] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0f001000, 0x0d000e00, 0x0b000c00, 0x09000a00, 0x07000800, 0x05000600, 0x03000400, 0x01000200, 0x01000000, 0x03000200, 0x05000400, 0x07000600, 0x09000800, 0x0b000a00, 0x0d000c00, 0x0f000e00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, [1] = { 0x03a10405, 0x02f80352, 0x023f0299, 0x019701e9, 0x0103014a, 0x008400c1, 0x001b004d, 0x00000000, 0x07ed07f6, 0x07bd07d9, 0x07660795, 0x06f60731, 0x067006b6, 0x05d70625, 0x05300585, 0x047204d5, 0x04720405, 0x053004d5, 0x05d70585, 0x06700625, 0x06f606b6, 0x07660731, 0x07bd0795, 0x07ed07d9, 0x00000000, 0x001b0000, 0x0084004d, 0x010300c1, 0x0197014a, 0x023f01e9, 0x02f80299, 0x03a10352, }, [2] = { 0x0420045e, 0x03a703e3, 0x0333036d, 0x02c502fb, 0x025b028f, 0x01f80229, 0x019a01c8, 0x0141016d, 0x061a062c, 0x05f10606, 0x05c205da, 0x058d05a8, 0x05530571, 0x05130534, 0x04ce04f1, 0x048504aa, 0x0485045e, 0x04ce04aa, 0x051304f1, 0x05530534, 0x058d0571, 0x05c205a8, 0x05f105da, 0x061a0606, 0x01410118, 0x019a016d, 0x01f801c8, 0x025b0229, 0x02c5028f, 0x033302fb, 0x03a7036d, 0x042003e3, }, [3] = { 0x04240444, 0x03e40404, 0x03a603c5, 0x03690387, 0x032d034b, 0x02f30310, 0x02ba02d6, 0x0281029d, 0x05070511, 0x04f104fc, 0x04da04e6, 0x04c204ce, 0x04a804b5, 0x048d049b, 0x0471047f, 0x04540463, 0x04540445, 0x04710463, 0x048d047f, 0x04a8049b, 0x04c204b5, 0x04da04ce, 0x04f104e6, 0x050704fc, 0x02810266, 0x02ba029d, 0x02f302d6, 0x032d0310, 0x0369034b, 0x03a60387, 0x03e403c5, 0x04240404, }, }; #endif void de_config_prefetch_line_set(void *base_addr, u32 line) { reg_set_bits(base_addr + TIMING_LINE_SET, TIMING_LINE_SET_PREFETCH_LINE_MASK, TIMING_LINE_SET_PREFETCH_LINE(line)); } void de_config_tearing_effect(void *base_addr, u32 mode, u32 pulse_width) { reg_set_bits(base_addr + TIMING_CTRL, TIMING_DE_MODE_MASK, TIMING_DE_MODE(mode)); reg_set_bits(base_addr + TIMING_CTRL, TIMING_TE_PULSE_WIDTH_MASK, TIMING_TE_PULSE_WIDTH(pulse_width)); } void de_soft_reset_ctrl(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + WB_BASE, DE_SOFT_RESET_EN); else reg_clr_bit(base_addr + WB_BASE, DE_SOFT_RESET_EN); } void de_config_update_enable(void *base_addr, u32 enable) { reg_write(base_addr + DE_CONFIG_UPDATE, enable); } void de_set_dither(void *base_addr, u32 r_depth, u32 g_depth, u32 b_depth, u32 enable) { reg_write(base_addr + OUTPUT_COLOR_DEPTH, OUTPUT_COLOR_DEPTH_SET(r_depth, g_depth, b_depth)); if (enable) { reg_set_bit(base_addr + DITHER_RAND_SEED, DE_RAND_DITHER_EN); reg_set_bit(base_addr + DE_CTRL, DE_CTRL_DITHER_EN); } else { reg_clr_bit(base_addr + DE_CTRL, DE_CTRL_DITHER_EN); } } void de_set_mode(void *base_addr, u32 mode) { reg_set_bits(base_addr + TIMING_CTRL, TIMING_DE_MODE_MASK, TIMING_DE_MODE(mode)); } void de_set_te_pulse_width(void *base_addr, u32 width) { reg_set_bits(base_addr + TIMING_CTRL, TIMING_TE_PULSE_WIDTH_MASK, TIMING_TE_PULSE_WIDTH(width)); } u32 de_set_te_pinmux(const char *name) { #if defined(AIC_DE_DRV_V10) || defined(AIC_DE_V10) char *pins[] = { "PC.6", "PD.2", "PF.15" }; unsigned int func[] = { 4, 4, 2 }; #elif defined(AIC_DE_DRV_V11) || defined(AIC_DE_V11) char *pins[] = { "PA.1", "PC.6" }; unsigned int func[] = { 8, 6 }; #elif defined(AIC_DE_DRV_V12) || defined(AIC_DE_V12) char *pins[] = { "PA.1", "PC.6" }; unsigned int func[] = { 8, 6 }; #endif unsigned int g, p, i; long pin = 0; for (i = 0; i < ARRAY_SIZE(pins); i++) { if (strncasecmp(name, pins[i], strlen(pins[i])) == 0) { pin = hal_gpio_name2pin(pins[i]); if (pin < 0) return -1; g = GPIO_GROUP(pin); p = GPIO_GROUP_PIN(pin); hal_gpio_set_func(g, p, func[i]); hal_gpio_set_bias_pull(g, p, PIN_PULL_DIS); hal_gpio_set_drive_strength(g, p, 3); return 0; } } return -1; } void de_qos_config(void *base_addr, int *value) { reg_set_bits(base_addr, DMAR_QOS_GREEN_MASK | DMAR_QOS_HIGH_MASK | DMAR_QOS_RED_MASK | DMAR_QOS_LOW_MASK, DMAR_QOS_GREEN(value[0]) | DMAR_QOS_HIGH(value[2]) | DMAR_QOS_RED(value[1]) | DMAR_QOS_LOW(value[3])); } void de_qos_urgent_config(void *base_addr, u32 only_active_en, u32 urgent_en, u32 urgent_th, u32 outstanding) { if (urgent_en) reg_set_bit(base_addr + QOS_V_URGENT, DMAR_URGENT_EN); #ifdef AIC_DE_DRV_V11 if (only_active_en) reg_set_bit(base_addr + QOS_V_URGENT, ONLY_ACTIVE_REGION_EN); reg_set_bits(base_addr + QOS_V_URGENT, DMAR_URGENT_TH_MASK, DMAR_URGENT_TH(urgent_th)); #else reg_set_bits(base_addr + QOS_V_URGENT, OUTSTANDING_MASK | DMAR_URGENT_TH_MASK, OUTSTANDING(outstanding) | DMAR_URGENT_TH(urgent_th)); #endif } void de_set_qos(void *base_addr) { void *base_reg; int i; de_qos_urgent_config(base_addr, 1, 1, QOS_DMAR_URGENT_TH, QOS_OUTSTANDING); for (i = 0; i < 4; i++) { base_reg = base_addr + QOS_V_P0 + i * 0x4; de_qos_config(base_reg, qos_cfg[i]); } } void de_colorbar_ctrl(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + DE_MODE_SELECT, DE_MODE_SELECT_COLOR_BAR); else reg_clr_bit(base_addr + DE_MODE_SELECT, DE_MODE_SELECT_COLOR_BAR); } u32 de_get_version_id(void *base_addr) { return reg_read(base_addr + DE_VERSION_ID); } void de_set_video_layer_info(void *base_addr, u32 w, u32 h, enum mpp_pixel_format format, u32 stride0, u32 stride1, u32 addr0, u32 addr1, u32 addr2, u32 x_offset, u32 y_offset) { reg_set_bits(base_addr + VIDEO_LAYER_CTRL, VIDEO_LAYER_CTRL_INPUT_FORMAT_MASK, VIDEO_LAYER_CTRL_INPUT_FORMAT(format)); reg_write(base_addr + VIDEO_LAYER_INPUT_SIZE, VIDEO_LAYER_INPUT_SIZE_SET(w, h)); reg_write(base_addr + VIDEO_LAYER_STRIDE, VIDEO_LAYER_STRIDE_SET(stride0, stride1)); reg_write(base_addr + VIDEO_LAYER_ADDR0, addr0); reg_write(base_addr + VIDEO_LAYER_ADDR1, addr1); reg_write(base_addr + VIDEO_LAYER_ADDR2, addr2); reg_write(base_addr + VIDEO_LAYER_OFFSET, VIDEO_LAYER_OFFSET_SET(x_offset, y_offset)); } void de_set_video_layer_tile_offset(void *base_addr, u32 p0_x_offset, u32 p0_y_offset, u32 p1_x_offset, u32 p1_y_offset) { reg_write(base_addr + VIDEO_LAYER_TILE_OFFSET0, VIDEO_LAYER_TILE_OFFSET0_SET(p0_x_offset, p0_y_offset)); reg_write(base_addr + VIDEO_LAYER_TILE_OFFSET1, VIDEO_LAYER_TILE_OFFSET1_SET(p1_x_offset, p1_y_offset)); } void de_video_layer_enable(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + VIDEO_LAYER_CTRL, VIDEO_LAYER_CTRL_EN); else reg_clr_bit(base_addr + VIDEO_LAYER_CTRL, VIDEO_LAYER_CTRL_EN); } void de_set_csc0_coefs(void *base_addr, int color_space) { const int *coefs; int i; switch (color_space) { case MPP_COLOR_SPACE_BT601: coefs = &yuv2rgb_bt601_limit[0][0]; break; case MPP_COLOR_SPACE_BT709: coefs = &yuv2rgb_bt709_limit[0][0]; break; case MPP_COLOR_SPACE_BT601_FULL_RANGE: coefs = &yuv2rgb_bt601_full[0][0]; break; case MPP_COLOR_SPACE_BT709_FULL_RANGE: coefs = &yuv2rgb_bt709_full[0][0]; break; default: coefs = &yuv2rgb_bt601_limit[0][0]; break; } for (i = 0; i < CSC_COEFFS_NUM; i++) { if (i == 3 || i == 7 || i == 11) reg_write(base_addr + VIDEO_LAYER_CSC0_COEF(i), CSC0_COEF_OFFSET_SET(coefs[i])); else reg_write(base_addr + VIDEO_LAYER_CSC0_COEF(i), CSC0_COEF_SET(coefs[i])); } } static int get_hsbc_coefs(int bright, int contrast, int sat, int hue, int coef[][4]) { int sinv = sin_table[hue + 29]; int cosv = cos_table[hue + 29]; sat = sat + 128; contrast = contrast + 128; coef[0][0] = contrast << 3; coef[0][1] = 0; coef[0][2] = 0; coef[0][3] = ((bright << 3) << 8) + ((1024 - (contrast << 3)) << 4); coef[1][0] = 0; coef[1][1] = (contrast * sat * cosv) >> 16; coef[1][2] = (contrast * sat * sinv) >> 16; coef[1][3] = (1024 - (coef[1][1] + coef[1][2])) << 7; coef[2][0] = 0; coef[2][1] = (-contrast * sat * sinv) >> 16; coef[2][2] = (contrast * sat * cosv) >> 16; coef[2][3] = (1024 - (coef[2][1] + coef[2][2])) << 7; coef[3][0] = 0; coef[3][1] = 0; coef[3][2] = 0; coef[3][3] = 1024; return 0; } static void matrix_4x4_multi(int a[][4], int b[][4], int out[][4]) { int i, j; int c; for (j = 0; j < 4; j++) { for (i = 0; i < 4; i++) { for (c = 0; c < 4; c++) out[j][i] += (a[j][c] * b[c][i]) >> 10; } } } static int get_csc_coefs_for_hsbc(int is_rgb, int color_space, int bright, int contrast, int saturation, int hue, u32 *csc_coef) { int(*y2r)[4]; int(*r2y)[4]; int(*cur_coef)[4]; int i, j, c, k; int hsv_coef[4][4] = {0}; int out_coef[4][4] = {0}; bright = bright > 100 ? 100 : bright; contrast = contrast > 100 ? 100 : contrast; saturation = saturation > 100 ? 100 : saturation; hue = hue > 100 ? 100 : hue; bright = bright * 128 / 100 - 64; contrast = contrast * 180 / 100 - 90; saturation = saturation * 128 / 100 - 64; hue = hue * 58 / 100 - 29; if (color_space == 0) y2r = yuv2rgb_bt601_limit; else if (color_space == 1) y2r = yuv2rgb_bt709_limit; else if (color_space == 2) y2r = yuv2rgb_bt601_full; else if (color_space == 3) y2r = yuv2rgb_bt709_full; else y2r = yuv2rgb_bt601_limit; get_hsbc_coefs(bright, contrast, saturation, hue, hsv_coef); if (is_rgb) { r2y = rgb2yuv_bt709_full; matrix_4x4_multi(hsv_coef, r2y, out_coef); cur_coef = out_coef; } else { cur_coef = hsv_coef; } k = 0; for (j = 0; j < 3; j++) { for (i = 0; i < 4; i++) { unsigned int value; int accum; accum = 0; for (c = 0; c < 4; c++) { int cur_value = y2r[j][c]; if (c == 3) cur_value = cur_value << 6; accum += cur_value * cur_coef[c][i]; } if (i == 3) { accum = accum >> 16; accum = accum > 8091 ? 8091 : accum; accum = accum < -8092 ? -8092 : accum; value = (unsigned int)accum; value = CSC0_COEF_OFFSET_SET(value); } else { accum = accum >> 10; accum = accum > 4095 ? 4095 : accum; accum = accum < -4096 ? -4096 : accum; value = (unsigned int)accum; value = CSC0_COEF_SET(value); } csc_coef[k++] = value; } } return 0; } int de_set_hsbc_with_csc_coefs(void *base_addr, int color_space, int bright, int contrast, int saturation, int hue) { int i; u32 csc_coef[CSC_COEFFS_NUM]; get_csc_coefs_for_hsbc(0, color_space, bright, contrast, saturation, hue, csc_coef); for (i = 0; i < CSC_COEFFS_NUM; i++) reg_write(base_addr + VIDEO_LAYER_CSC0_COEF(i), csc_coef[i]); return 0; } int get_rgb_hsbc_csc_coefs(int bright, int contrast, int saturation, int hue, u32 *csc_coef) { get_csc_coefs_for_hsbc(1, 3, bright, contrast, saturation, hue, csc_coef); return 0; } void de_set_ui_layer_size(void *base_addr, u32 w, u32 h, u32 x_offset, u32 y_offset) { reg_write(base_addr + UI_LAYER_SIZE, UI_LAYER_SIZE_SET(w, h)); reg_write(base_addr + UI_LAYER_OFFSET, UI_LAYER_OFFSET_SET(x_offset, y_offset)); } void de_ui_alpha_blending_enable(void *base_addr, u32 g_alpha, u32 alpha_mode, u32 enable) { if (enable) reg_set_bits(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_G_ALPHA_MASK | UI_LAYER_CTRL_ALPHA_MODE_MASK | UI_LAYER_CTRL_ALPHA_EN, UI_LAYER_CTRL_G_ALPHA(g_alpha) | UI_LAYER_CTRL_ALPHA_MODE(alpha_mode) | UI_LAYER_CTRL_ALPHA_EN); else reg_clr_bit(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_ALPHA_EN); } void de_set_ui_layer_format(void *base_addr, enum mpp_pixel_format format) { reg_set_bits(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_INPUT_FORMAT_MASK, UI_LAYER_CTRL_INPUT_FORMAT(format)); } void de_ui_layer_color_key_enable(void *base_addr, u32 color_key, u32 ck_en) { if (ck_en) { reg_write(base_addr + UI_LAYER_COLOER_KEY, UI_LAYER_COLOER_KEY_SET(color_key)); reg_set_bit(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_COLOR_KEY_EN); } else { reg_clr_bit(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_COLOR_KEY_EN); } } void de_ui_layer_set_rect(void *base_addr, u32 w, u32 h, u32 x_offset, u32 y_offset, u32 stride, u32 addr, u32 id) { reg_write(base_addr + UI_RECT_INPUT_SIZE(id), UI_RECT_INPUT_SIZE_SET(w, h)); reg_write(base_addr + UI_RECT_OFFSET(id), UI_RECT_OFFSET_SET(x_offset, y_offset)); reg_write(base_addr + UI_RECT_STRIDE(id), UI_RECT_STRIDE_SET(stride)); reg_write(base_addr + UI_RECT_ADDR(id), addr); } void de_ui_layer_enable(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_EN); else reg_clr_bit(base_addr + UI_LAYER_CTRL, UI_LAYER_CTRL_EN); } void de_ui_layer_rect_enable(void *base_addr, u32 index, u32 enable) { if (enable) reg_set_bit(base_addr + UI_LAYER_RECT_CTRL, UI_LAYER_RECT_CTRL_EN(index)); else reg_clr_bit(base_addr + UI_LAYER_RECT_CTRL, UI_LAYER_RECT_CTRL_EN(index)); } void de_scaler0_active_handle(void *base_addr, u32 index) { #if defined(AIC_DE_DRV_V10) || defined(AIC_DE_V10) const unsigned int *table; int i; table = scaling_coeffs[index]; reg_set_bit(base_addr + SCALER0_CTRL, SCALER0_CTRL_CH0_V_COEF_LUT_EN); reg_set_bit(base_addr + SCALER0_CTRL, SCALER0_CTRL_CH1_V_COEF_LUT_EN); for (i = 0; i < 32; i++) { reg_write(base_addr + SCALER0_CH0_V_COEF(i), table[i]); reg_write(base_addr + SCALER0_CH1_V_COEF(i), table[i]); } #endif } /** *@ channel: scaler channel * 0: y channel * 1: c channel */ void de_set_scaler0_channel(void *base_addr, u32 input_w, u32 input_h, u32 output_w, u32 output_h, u32 channel) { u32 dx, dy, h_phase, v_phase; dx = (input_w << 16) / output_w; dy = (input_h << 16) / output_h; h_phase = (dx >= 65536) ? ((dx >> 1) - 32768) : (dx >> 1); v_phase = (dy >= 65536) ? ((dy >> 1) - 32768) : (dy >> 1); reg_write(base_addr + SCALER0_INPUT_SIZE(channel), SCALER0_INPUT_SIZE_SET(input_w, input_h)); reg_write(base_addr + SCALER0_OUTPUT_SIZE(channel), SCALER0_OUTPUT_SIZE_SET(output_w, output_h)); reg_write(base_addr + SCALER0_H_INIT_PHASE(channel), SCALER0_H_INIT_PHASE_SET(h_phase)); reg_write(base_addr + SCALER0_H_RATIO(channel), SCALER0_H_RATIO_SET(dx)); reg_write(base_addr + SCALER0_V_INIT_PHASE(channel), SCALER0_V_INIT_PHASE_SET(v_phase)); reg_write(base_addr + SCALER0_V_RATIO(channel), SCALER0_V_RATIO_SET(dy)); } void de_scaler0_enable(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + SCALER0_CTRL, SCALER0_CTRL_EN); else reg_clr_bit(base_addr + SCALER0_CTRL, SCALER0_CTRL_EN); } void de_timing_enable_interrupt(void *base_addr, u32 enable, u32 mask) { if (enable) reg_set_bit(base_addr + TIMING_INIT, mask); else reg_clr_bits(base_addr + TIMING_INIT, mask); } u32 de_timing_interrupt_status(void *base_addr) { return reg_read(base_addr + TIMING_STATUS); } void de_timing_interrupt_clean_status(void *base_addr, u32 status) { reg_write(base_addr + TIMING_STATUS, status); } void de_timing_enable(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + TIMING_CTRL, TIMING_CTRL_EN); else reg_clr_bit(base_addr + TIMING_CTRL, TIMING_CTRL_EN); } void de_config_timing(void *base_addr, u32 active_w, u32 active_h, u32 hfp, u32 hbp, u32 vfp, u32 vbp, u32 hsync, u32 vsync, u32 h_pol, u32 v_pol) { reg_write(base_addr + TIMING_ACTIVE_SIZE, TIMING_ACTIVE_SIZE_SET(active_w, active_h)); reg_write(base_addr + TIMING_H_PORCH, TIMING_H_PORCH_SET(hfp, hbp)); reg_write(base_addr + TIMING_V_PORCH, TIMING_V_PORCH_SET(vfp, vbp)); reg_write(base_addr + TIMING_SYNC_PLUSE, TIMING_SYNC_PLUSE_SET_H_V(hsync, vsync)); reg_write(base_addr + TIMING_POL_SET, TIMING_POL_SET_H_V(h_pol, v_pol)); } void de_set_blending_size(void *base_addr, u32 active_w, u32 active_h) { reg_write(base_addr + BLENDING_OUTPUT_SIZE, BLENDING_OUTPUT_SIZE_SET(active_w, active_h)); } void de_ccm_ctrl(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + DE_CTRL, DE_CTRL_CCM_EN); else reg_clr_bit(base_addr + DE_CTRL, DE_CTRL_CCM_EN); } void de_gamma_ctrl(void *base_addr, u32 enable) { if (enable) reg_set_bit(base_addr + DE_CTRL, DE_CTRL_GAMMA_EN); else reg_clr_bit(base_addr + DE_CTRL, DE_CTRL_GAMMA_EN); } void de_config_ccm(void *base_addr, const int *ccm_table) { unsigned int i; for (i = 0; i < CCM_COEF_NUM; i++) reg_write(base_addr + CCM_COEF(i), ccm_table[i]); } void de_config_gamma_lut(void *base_addr, const u32 *gamma_table, int channel) { int i, value; for (i = 0; i < GAMMA_COEF_NUM; i++) { value = gamma_table[i]; switch (channel) { case GAMMA_RED: reg_write(base_addr + GAMMA_RED_LUT(i), value); break; case GAMMA_GREEN: reg_write(base_addr + GAMMA_GREEN_LUT(i), value); break; case GAMMA_BLUE: reg_write(base_addr + GAMMA_BLUE_LUT(i), value); break; default: break; } } }