static void program_overscan( struct dce_transform *xfm_dce, const struct scaler_data *data) { int overscan_right = data->h_active - data->recout.x - data->recout.width; int overscan_bottom = data->v_active - data->recout.y - data->recout.height; if (xfm_dce->base.ctx->dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) { overscan_bottom += 2; overscan_right += 2; } if (overscan_right < 0) { BREAK_TO_DEBUGGER(); overscan_right = 0; } if (overscan_bottom < 0) { BREAK_TO_DEBUGGER(); overscan_bottom = 0; } REG_SET_2(EXT_OVERSCAN_LEFT_RIGHT, 0, EXT_OVERSCAN_LEFT, data->recout.x, EXT_OVERSCAN_RIGHT, overscan_right); REG_SET_2(EXT_OVERSCAN_TOP_BOTTOM, 0, EXT_OVERSCAN_TOP, data->recout.y, EXT_OVERSCAN_BOTTOM, overscan_bottom); }
static void hubp1_set_vm_context0_settings(struct hubp *hubp, const struct vm_context0_param *vm0) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); /* pte base */ REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, 0, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, vm0->pte_base.high_part); REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, 0, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, vm0->pte_base.low_part); /* pte start */ REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, 0, VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, vm0->pte_start.high_part); REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, 0, VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, vm0->pte_start.low_part); /* pte end */ REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, 0, VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, vm0->pte_end.high_part); REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, 0, VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, vm0->pte_end.low_part); /* fault handling */ REG_SET_2(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, vm0->fault_default.high_part, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_SYSTEM, context0_default_system); REG_SET(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, vm0->fault_default.low_part); /* control: enable VM PTE*/ REG_SET_2(DCN_VM_MX_L1_TLB_CNTL, 0, ENABLE_L1_TLB, 1, SYSTEM_ACCESS_MODE, 3); }
static void program_viewport( struct dce_transform *xfm_dce, const struct rect *view_port) { REG_SET_2(VIEWPORT_START, 0, VIEWPORT_X_START, view_port->x, VIEWPORT_Y_START, view_port->y); REG_SET_2(VIEWPORT_SIZE, 0, VIEWPORT_HEIGHT, view_port->height, VIEWPORT_WIDTH, view_port->width); /* TODO: add stereo support */ }
static void dce110_stream_encoder_set_mst_bandwidth( struct stream_encoder *enc, struct fixed31_32 avg_time_slots_per_mtp) { struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); uint32_t x = dal_fixed31_32_floor( avg_time_slots_per_mtp); uint32_t y = dal_fixed31_32_ceil( dal_fixed31_32_shl( dal_fixed31_32_sub_int( avg_time_slots_per_mtp, x), 26)); { REG_SET_2(DP_MSE_RATE_CNTL, 0, DP_MSE_RATE_X, x, DP_MSE_RATE_Y, y); } /* wait for update to be completed on the link */ /* i.e. DP_MSE_RATE_UPDATE_PENDING field (read only) */ /* is reset to 0 (not pending) */ REG_WAIT(DP_MSE_RATE_UPDATE, DP_MSE_RATE_UPDATE_PENDING, 0, 10, DP_MST_UPDATE_MAX_RETRY); }
static bool setup_scaling_configuration( struct dce_transform *xfm_dce, const struct scaler_data *data) { REG_SET(SCL_BYPASS_CONTROL, 0, SCL_BYPASS_MODE, 0); if (data->taps.h_taps + data->taps.v_taps <= 2) { /* Set bypass */ if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0) REG_UPDATE_2(SCL_MODE, SCL_MODE, 0, SCL_PSCL_EN, 0); else REG_UPDATE(SCL_MODE, SCL_MODE, 0); return false; } REG_SET_2(SCL_TAP_CONTROL, 0, SCL_H_NUM_OF_TAPS, data->taps.h_taps - 1, SCL_V_NUM_OF_TAPS, data->taps.v_taps - 1); if (data->format <= PIXEL_FORMAT_GRPH_END) REG_UPDATE(SCL_MODE, SCL_MODE, 1); else REG_UPDATE(SCL_MODE, SCL_MODE, 2); if (xfm_dce->xfm_mask->SCL_PSCL_EN != 0) REG_UPDATE(SCL_MODE, SCL_PSCL_EN, 1); /* 1 - Replace out of bound pixels with edge */ REG_SET(SCL_CONTROL, 0, SCL_BOUNDARY_MODE, 1); return true; }
static void hubp1_set_vm_system_aperture_settings(struct hubp *hubp, struct vm_system_aperture_param *apt) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); PHYSICAL_ADDRESS_LOC mc_vm_apt_default; PHYSICAL_ADDRESS_LOC mc_vm_apt_low; PHYSICAL_ADDRESS_LOC mc_vm_apt_high; mc_vm_apt_default.quad_part = apt->sys_default.quad_part >> 12; mc_vm_apt_low.quad_part = apt->sys_low.quad_part >> 12; mc_vm_apt_high.quad_part = apt->sys_high.quad_part >> 12; REG_SET_2(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, aperture_default_system, /* 1 = system physical memory */ MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mc_vm_apt_default.high_part); REG_SET(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mc_vm_apt_default.low_part); REG_SET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, MC_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, mc_vm_apt_low.high_part); REG_SET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, MC_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, mc_vm_apt_low.low_part); REG_SET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, mc_vm_apt_high.high_part); REG_SET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, mc_vm_apt_high.low_part); }
void hubp1_cursor_set_attributes( struct hubp *hubp, const struct dc_cursor_attributes *attr) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch); enum cursor_lines_per_chunk lpc = hubp1_get_lines_per_chunk( attr->width, attr->color_format); hubp->curs_attr = *attr; REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part); REG_UPDATE(CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, attr->address.low_part); REG_UPDATE_2(CURSOR_SIZE, CURSOR_WIDTH, attr->width, CURSOR_HEIGHT, attr->height); REG_UPDATE_3(CURSOR_CONTROL, CURSOR_MODE, attr->color_format, CURSOR_PITCH, hw_pitch, CURSOR_LINES_PER_CHUNK, lpc); REG_SET_2(CURSOR_SETTINS, 0, /* no shift of the cursor HDL schedule */ CURSOR0_DST_Y_OFFSET, 0, /* used to shift the cursor chunk request deadline */ CURSOR0_CHUNK_HDL_ADJUST, 3); }
/***************************************************************************** * set_clamp * * @param depth : bit depth to set the clamp to (should match denorm) * * @brief * Programs clamp according to panel bit depth. * *******************************************************************************/ static void set_clamp( struct dce_transform *xfm_dce, enum dc_color_depth depth) { int clamp_max = 0; /* At the clamp block the data will be MSB aligned, so we set the max * clamp accordingly. * For example, the max value for 6 bits MSB aligned (14 bit bus) would * be "11 1111 0000 0000" in binary, so 0x3F00. */ switch (depth) { case COLOR_DEPTH_666: /* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */ clamp_max = 0x3F00; break; case COLOR_DEPTH_888: /* 8bit MSB aligned on 14 bit bus '11 1111 1100 0000' */ clamp_max = 0x3FC0; break; case COLOR_DEPTH_101010: /* 10bit MSB aligned on 14 bit bus '11 1111 1111 1100' */ clamp_max = 0x3FFC; break; case COLOR_DEPTH_121212: /* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */ clamp_max = 0x3FFF; break; default: clamp_max = 0x3FC0; BREAK_TO_DEBUGGER(); /* Invalid clamp bit depth */ } REG_SET_2(OUT_CLAMP_CONTROL_B_CB, 0, OUT_CLAMP_MIN_B_CB, 0, OUT_CLAMP_MAX_B_CB, clamp_max); REG_SET_2(OUT_CLAMP_CONTROL_G_Y, 0, OUT_CLAMP_MIN_G_Y, 0, OUT_CLAMP_MAX_G_Y, clamp_max); REG_SET_2(OUT_CLAMP_CONTROL_R_CR, 0, OUT_CLAMP_MIN_R_CR, 0, OUT_CLAMP_MAX_R_CR, clamp_max); }
static void hubp1_setup_interdependent( struct hubp *hubp, struct _vcs_dpi_display_dlg_regs_st *dlg_attr, struct _vcs_dpi_display_ttu_regs_st *ttu_attr) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); REG_SET_2(PREFETCH_SETTINS, 0, DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, VRATIO_PREFETCH, dlg_attr->vratio_prefetch); REG_SET(PREFETCH_SETTINS_C, 0, VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); REG_SET_2(VBLANK_PARAMETERS_0, 0, DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); REG_SET(VBLANK_PARAMETERS_3, 0, REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); REG_SET(VBLANK_PARAMETERS_4, 0, REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); REG_SET_2(PER_LINE_DELIVERY_PRE, 0, REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); REG_SET(DCN_SURF0_TTU_CNTL1, 0, REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_l); REG_SET(DCN_SURF1_TTU_CNTL1, 0, REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_c); REG_SET(DCN_CUR0_TTU_CNTL1, 0, REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); }
static void program_scl_ratios_inits( struct dce_transform *xfm_dce, struct scl_ratios_inits *inits) { REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, SCL_H_SCALE_RATIO, inits->h_int_scale_ratio); REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, SCL_V_SCALE_RATIO, inits->v_int_scale_ratio); REG_SET_2(SCL_HORZ_FILTER_INIT, 0, SCL_H_INIT_INT, inits->h_init.integer, SCL_H_INIT_FRAC, inits->h_init.fraction); REG_SET_2(SCL_VERT_FILTER_INIT, 0, SCL_V_INIT_INT, inits->v_init.integer, SCL_V_INIT_FRAC, inits->v_init.fraction); REG_WRITE(SCL_AUTOMATIC_MODE_CONTROL, 0); }
void dce_pipe_control_lock(struct dc *dc, struct pipe_ctx *pipe, bool lock) { uint32_t lock_val = lock ? 1 : 0; uint32_t dcp_grph, scl, blnd, update_lock_mode, val; struct dce_hwseq *hws = dc->hwseq; /* Not lock pipe when blank */ if (lock && pipe->stream_res.tg->funcs->is_blanked && pipe->stream_res.tg->funcs->is_blanked(pipe->stream_res.tg)) return; val = REG_GET_4(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], BLND_DCP_GRPH_V_UPDATE_LOCK, &dcp_grph, BLND_SCL_V_UPDATE_LOCK, &scl, BLND_BLND_V_UPDATE_LOCK, &blnd, BLND_V_UPDATE_LOCK_MODE, &update_lock_mode); dcp_grph = lock_val; scl = lock_val; blnd = lock_val; update_lock_mode = lock_val; REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_DCP_GRPH_V_UPDATE_LOCK, dcp_grph, BLND_SCL_V_UPDATE_LOCK, scl); if (hws->masks->BLND_BLND_V_UPDATE_LOCK != 0) REG_SET_2(BLND_V_UPDATE_LOCK[pipe->stream_res.tg->inst], val, BLND_BLND_V_UPDATE_LOCK, blnd, BLND_V_UPDATE_LOCK_MODE, update_lock_mode); if (hws->wa.blnd_crtc_trigger) { if (!lock) { uint32_t value = REG_READ(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst]); REG_WRITE(CRTC_H_BLANK_START_END[pipe->stream_res.tg->inst], value); } } }
void min_set_viewport( struct hubp *hubp, const struct rect *viewport, const struct rect *viewport_c) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION, 0, PRI_VIEWPORT_WIDTH, viewport->width, PRI_VIEWPORT_HEIGHT, viewport->height); REG_SET_2(DCSURF_PRI_VIEWPORT_START, 0, PRI_VIEWPORT_X_START, viewport->x, PRI_VIEWPORT_Y_START, viewport->y); /*for stereo*/ REG_SET_2(DCSURF_SEC_VIEWPORT_DIMENSION, 0, SEC_VIEWPORT_WIDTH, viewport->width, SEC_VIEWPORT_HEIGHT, viewport->height); REG_SET_2(DCSURF_SEC_VIEWPORT_START, 0, SEC_VIEWPORT_X_START, viewport->x, SEC_VIEWPORT_Y_START, viewport->y); /* DC supports NV12 only at the moment */ REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION_C, 0, PRI_VIEWPORT_WIDTH_C, viewport_c->width, PRI_VIEWPORT_HEIGHT_C, viewport_c->height); REG_SET_2(DCSURF_PRI_VIEWPORT_START_C, 0, PRI_VIEWPORT_X_START_C, viewport_c->x, PRI_VIEWPORT_Y_START_C, viewport_c->y); }
static void program_gamut_remap( struct dce_transform *xfm_dce, const uint16_t *reg_val) { if (reg_val) { REG_SET_2(GAMUT_REMAP_C11_C12, 0, GAMUT_REMAP_C11, reg_val[0], GAMUT_REMAP_C12, reg_val[1]); REG_SET_2(GAMUT_REMAP_C13_C14, 0, GAMUT_REMAP_C13, reg_val[2], GAMUT_REMAP_C14, reg_val[3]); REG_SET_2(GAMUT_REMAP_C21_C22, 0, GAMUT_REMAP_C21, reg_val[4], GAMUT_REMAP_C22, reg_val[5]); REG_SET_2(GAMUT_REMAP_C23_C24, 0, GAMUT_REMAP_C23, reg_val[6], GAMUT_REMAP_C24, reg_val[7]); REG_SET_2(GAMUT_REMAP_C31_C32, 0, GAMUT_REMAP_C31, reg_val[8], GAMUT_REMAP_C32, reg_val[9]); REG_SET_2(GAMUT_REMAP_C33_C34, 0, GAMUT_REMAP_C33, reg_val[10], GAMUT_REMAP_C34, reg_val[11]); REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 1); } else REG_SET(GAMUT_REMAP_CONTROL, 0, GRPH_GAMUT_REMAP_MODE, 0); }
static void program_color_matrix( struct dce_transform *xfm_dce, const struct out_csc_color_matrix *tbl_entry, enum grph_color_adjust_option options) { { REG_SET_2(OUTPUT_CSC_C11_C12, 0, OUTPUT_CSC_C11, tbl_entry->regval[0], OUTPUT_CSC_C12, tbl_entry->regval[1]); } { REG_SET_2(OUTPUT_CSC_C13_C14, 0, OUTPUT_CSC_C11, tbl_entry->regval[2], OUTPUT_CSC_C12, tbl_entry->regval[3]); } { REG_SET_2(OUTPUT_CSC_C21_C22, 0, OUTPUT_CSC_C11, tbl_entry->regval[4], OUTPUT_CSC_C12, tbl_entry->regval[5]); } { REG_SET_2(OUTPUT_CSC_C23_C24, 0, OUTPUT_CSC_C11, tbl_entry->regval[6], OUTPUT_CSC_C12, tbl_entry->regval[7]); } { REG_SET_2(OUTPUT_CSC_C31_C32, 0, OUTPUT_CSC_C11, tbl_entry->regval[8], OUTPUT_CSC_C12, tbl_entry->regval[9]); } { REG_SET_2(OUTPUT_CSC_C33_C34, 0, OUTPUT_CSC_C11, tbl_entry->regval[10], OUTPUT_CSC_C12, tbl_entry->regval[11]); } }
/* setup stream encoder in dp mode */ static void dce110_stream_encoder_dp_set_stream_attribute( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space) { #if defined(CONFIG_DRM_AMD_DC_DCN1_0) uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; uint32_t misc1 = 0; uint32_t h_blank; uint32_t h_back_porch; uint8_t synchronous_clock = 0; /* asynchronous mode */ uint8_t colorimetry_bpc; #endif struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_DB_CNTL)) REG_UPDATE(DP_DB_CNTL, DP_DB_DISABLE, 1); #endif /* set pixel encoding */ switch (crtc_timing->pixel_encoding) { case PIXEL_ENCODING_YCBCR422: REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_YCBCR422); break; case PIXEL_ENCODING_YCBCR444: REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_YCBCR444); if (crtc_timing->flags.Y_ONLY) if (crtc_timing->display_color_depth != COLOR_DEPTH_666) /* HW testing only, no use case yet. * Color depth of Y-only could be * 8, 10, 12, 16 bits */ REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_Y_ONLY); /* Note: DP_MSA_MISC1 bit 7 is the indicator * of Y-only mode. * This bit is set in HW if register * DP_PIXEL_ENCODING is programmed to 0x4 */ break; case PIXEL_ENCODING_YCBCR420: REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_YCBCR420); if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN) REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (enc110->se_mask->DP_VID_N_MUL) REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); #endif break; default: REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_RGB444); break; } #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); #endif /* set color depth */ switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, 0); break; case COLOR_DEPTH_888: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_DEPTH_8BPC); break; case COLOR_DEPTH_101010: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_DEPTH_10BPC); break; case COLOR_DEPTH_121212: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_DEPTH_12BPC); break; default: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, DP_COMPONENT_DEPTH_6BPC); break; } /* set dynamic range and YCbCr range */ if (enc110->se_mask->DP_DYN_RANGE && enc110->se_mask->DP_YCBCR_RANGE) REG_UPDATE_2( DP_PIXEL_FORMAT, DP_DYN_RANGE, 0, DP_YCBCR_RANGE, 0); #if defined(CONFIG_DRM_AMD_DC_DCN1_0) switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; break; case COLOR_DEPTH_888: colorimetry_bpc = 1; break; case COLOR_DEPTH_101010: colorimetry_bpc = 2; break; case COLOR_DEPTH_121212: colorimetry_bpc = 3; break; default: colorimetry_bpc = 0; break; } misc0 = misc0 | synchronous_clock; misc0 = colorimetry_bpc << 5; if (REG(DP_MSA_TIMING_PARAM1)) { switch (output_color_space) { case COLOR_SPACE_SRGB: misc0 = misc0 | 0x0; misc1 = misc1 & ~0x80; /* bit7 = 0*/ break; case COLOR_SPACE_SRGB_LIMITED: misc0 = misc0 | 0x8; /* bit3=1 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ break; case COLOR_SPACE_YCBCR601: misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_YCBCR709: misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_2020_RGB_FULLRANGE: case COLOR_SPACE_2020_RGB_LIMITEDRANGE: case COLOR_SPACE_2020_YCBCR: case COLOR_SPACE_ADOBERGB: case COLOR_SPACE_UNKNOWN: case COLOR_SPACE_YCBCR601_LIMITED: case COLOR_SPACE_YCBCR709_LIMITED: /* do nothing */ break; } #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_COLORIMETRY)) REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0); if (REG(DP_MSA_MISC)) REG_WRITE(DP_MSA_MISC, misc1); /* MSA_MISC1 */ /* dcn new register * dc_crtc_timing is vesa dmt struct. data from edid */ if (REG(DP_MSA_TIMING_PARAM1)) REG_SET_2(DP_MSA_TIMING_PARAM1, 0, DP_MSA_HTOTAL, crtc_timing->h_total, DP_MSA_VTOTAL, crtc_timing->v_total); #endif /* calcuate from vesa timing parameters * h_active_start related to leading edge of sync */ h_blank = crtc_timing->h_total - crtc_timing->h_border_left - crtc_timing->h_addressable - crtc_timing->h_border_right; h_back_porch = h_blank - crtc_timing->h_front_porch - crtc_timing->h_sync_width; /* start at begining of left border */ h_active_start = crtc_timing->h_sync_width + h_back_porch; v_active_start = crtc_timing->v_total - crtc_timing->v_border_top - crtc_timing->v_addressable - crtc_timing->v_border_bottom - crtc_timing->v_front_porch; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2)) REG_SET_2(DP_MSA_TIMING_PARAM2, 0, DP_MSA_HSTART, h_active_start, DP_MSA_VSTART, v_active_start); if (REG(DP_MSA_TIMING_PARAM3)) REG_SET_4(DP_MSA_TIMING_PARAM3, 0, DP_MSA_HSYNCWIDTH, crtc_timing->h_sync_width, DP_MSA_HSYNCPOLARITY, !crtc_timing->flags.HSYNC_POSITIVE_POLARITY, DP_MSA_VSYNCWIDTH, crtc_timing->v_sync_width, DP_MSA_VSYNCPOLARITY, !crtc_timing->flags.VSYNC_POSITIVE_POLARITY); /* HWDITH include border or overscan */ if (REG(DP_MSA_TIMING_PARAM4)) REG_SET_2(DP_MSA_TIMING_PARAM4, 0, DP_MSA_HWIDTH, crtc_timing->h_border_left + crtc_timing->h_addressable + crtc_timing->h_border_right, DP_MSA_VHEIGHT, crtc_timing->v_border_top + crtc_timing->v_addressable + crtc_timing->v_border_bottom); #endif } #endif }
static void regamma_config_regions_and_segments(struct dce_transform *xfm_dce, const struct pwl_params *params) { const struct gamma_curve *curve; REG_SET_2(REGAMMA_CNTLA_START_CNTL, 0, REGAMMA_CNTLA_EXP_REGION_START, params->arr_points[0].custom_float_x, REGAMMA_CNTLA_EXP_REGION_START_SEGMENT, 0); REG_SET(REGAMMA_CNTLA_SLOPE_CNTL, 0, REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE, params->arr_points[0].custom_float_slope); REG_SET(REGAMMA_CNTLA_END_CNTL1, 0, REGAMMA_CNTLA_EXP_REGION_END, params->arr_points[1].custom_float_x); REG_SET_2(REGAMMA_CNTLA_END_CNTL2, 0, REGAMMA_CNTLA_EXP_REGION_END_BASE, params->arr_points[1].custom_float_y, REGAMMA_CNTLA_EXP_REGION_END_SLOPE, params->arr_points[1].custom_float_slope); curve = params->arr_curve_points; REG_SET_4(REGAMMA_CNTLA_REGION_0_1, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_2_3, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_4_5, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_6_7, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_8_9, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_10_11, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_12_13, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); curve += 2; REG_SET_4(REGAMMA_CNTLA_REGION_14_15, 0, REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET, curve[0].offset, REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET, curve[1].offset, REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); }
void hubp1_program_deadline( struct hubp *hubp, struct _vcs_dpi_display_dlg_regs_st *dlg_attr, struct _vcs_dpi_display_ttu_regs_st *ttu_attr) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); /* DLG - Per hubp */ REG_SET_2(BLANK_OFFSET_0, 0, REFCYC_H_BLANK_END, dlg_attr->refcyc_h_blank_end, DLG_V_BLANK_END, dlg_attr->dlg_vblank_end); REG_SET(BLANK_OFFSET_1, 0, MIN_DST_Y_NEXT_START, dlg_attr->min_dst_y_next_start); REG_SET(DST_DIMENSIONS, 0, REFCYC_PER_HTOTAL, dlg_attr->refcyc_per_htotal); REG_SET_2(DST_AFTER_SCALER, 0, REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); REG_SET(REF_FREQ_TO_PIX_FREQ, 0, REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); /* DLG - Per luma/chroma */ REG_SET(VBLANK_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); if (REG(NOM_PARAMETERS_0)) REG_SET(NOM_PARAMETERS_0, 0, DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); if (REG(NOM_PARAMETERS_1)) REG_SET(NOM_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_NOM_L, dlg_attr->refcyc_per_pte_group_nom_l); REG_SET(NOM_PARAMETERS_4, 0, DST_Y_PER_META_ROW_NOM_L, dlg_attr->dst_y_per_meta_row_nom_l); REG_SET(NOM_PARAMETERS_5, 0, REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); REG_SET_2(PER_LINE_DELIVERY, 0, REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); REG_SET(VBLANK_PARAMETERS_2, 0, REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); if (REG(NOM_PARAMETERS_2)) REG_SET(NOM_PARAMETERS_2, 0, DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); if (REG(NOM_PARAMETERS_3)) REG_SET(NOM_PARAMETERS_3, 0, REFCYC_PER_PTE_GROUP_NOM_C, dlg_attr->refcyc_per_pte_group_nom_c); REG_SET(NOM_PARAMETERS_6, 0, DST_Y_PER_META_ROW_NOM_C, dlg_attr->dst_y_per_meta_row_nom_c); REG_SET(NOM_PARAMETERS_7, 0, REFCYC_PER_META_CHUNK_NOM_C, dlg_attr->refcyc_per_meta_chunk_nom_c); /* TTU - per hubp */ REG_SET_2(DCN_TTU_QOS_WM, 0, QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); /* TTU - per luma/chroma */ /* Assumed surf0 is luma and 1 is chroma */ REG_SET_3(DCN_SURF0_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_l, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); REG_SET_3(DCN_CUR0_TTU_CNTL0, 0, REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0, QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0, QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0); }
static void dce_transform_set_scaler( struct transform *xfm, const struct scaler_data *data) { struct dce_transform *xfm_dce = TO_DCE_TRANSFORM(xfm); bool is_scaling_required; bool filter_updated = false; const uint16_t *coeffs_v, *coeffs_h; /*Use all three pieces of memory always*/ REG_SET_2(LB_MEMORY_CTRL, 0, LB_MEMORY_CONFIG, 0, LB_MEMORY_SIZE, xfm_dce->lb_memory_size); /* Clear SCL_F_SHARP_CONTROL value to 0 */ REG_WRITE(SCL_F_SHARP_CONTROL, 0); /* 1. Program overscan */ program_overscan(xfm_dce, data); /* 2. Program taps and configuration */ is_scaling_required = setup_scaling_configuration(xfm_dce, data); if (is_scaling_required) { /* 3. Calculate and program ratio, filter initialization */ struct scl_ratios_inits inits = { 0 }; calculate_inits(xfm_dce, data, &inits); program_scl_ratios_inits(xfm_dce, &inits); coeffs_v = get_filter_coeffs_16p(data->taps.v_taps, data->ratios.vert); coeffs_h = get_filter_coeffs_16p(data->taps.h_taps, data->ratios.horz); if (coeffs_v != xfm_dce->filter_v || coeffs_h != xfm_dce->filter_h) { /* 4. Program vertical filters */ if (xfm_dce->filter_v == NULL) REG_SET(SCL_VERT_FILTER_CONTROL, 0, SCL_V_2TAP_HARDCODE_COEF_EN, 0); program_multi_taps_filter( xfm_dce, data->taps.v_taps, coeffs_v, FILTER_TYPE_RGB_Y_VERTICAL); program_multi_taps_filter( xfm_dce, data->taps.v_taps, coeffs_v, FILTER_TYPE_ALPHA_VERTICAL); /* 5. Program horizontal filters */ if (xfm_dce->filter_h == NULL) REG_SET(SCL_HORZ_FILTER_CONTROL, 0, SCL_H_2TAP_HARDCODE_COEF_EN, 0); program_multi_taps_filter( xfm_dce, data->taps.h_taps, coeffs_h, FILTER_TYPE_RGB_Y_HORIZONTAL); program_multi_taps_filter( xfm_dce, data->taps.h_taps, coeffs_h, FILTER_TYPE_ALPHA_HORIZONTAL); xfm_dce->filter_v = coeffs_v; xfm_dce->filter_h = coeffs_h; filter_updated = true; } } /* 6. Program the viewport */ program_viewport(xfm_dce, &data->viewport); /* 7. Set bit to flip to new coefficient memory */ if (filter_updated) REG_UPDATE(SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE, 1); REG_UPDATE(LB_DATA_FORMAT, ALPHA_EN, data->lb_params.alpha_en); }
void hubp1_cursor_set_position( struct hubp *hubp, const struct dc_cursor_position *pos, const struct dc_cursor_mi_param *param) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y; int x_hotspot = pos->x_hotspot; int y_hotspot = pos->y_hotspot; uint32_t dst_x_offset; uint32_t cur_en = pos->enable ? 1 : 0; /* * Guard aganst cursor_set_position() from being called with invalid * attributes * * TODO: Look at combining cursor_set_position() and * cursor_set_attributes() into cursor_update() */ if (hubp->curs_attr.address.quad_part == 0) return; if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) { src_x_offset = pos->y - pos->y_hotspot - param->viewport.x; y_hotspot = pos->x_hotspot; x_hotspot = pos->y_hotspot; } if (param->mirror) { x_hotspot = param->viewport.width - x_hotspot; src_x_offset = param->viewport.x + param->viewport.width - src_x_offset; } dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; dst_x_offset *= param->ref_clk_khz; dst_x_offset /= param->pixel_clk_khz; ASSERT(param->h_scale_ratio.value); if (param->h_scale_ratio.value) dst_x_offset = dc_fixpt_floor(dc_fixpt_div( dc_fixpt_from_int(dst_x_offset), param->h_scale_ratio)); if (src_x_offset >= (int)param->viewport.width) cur_en = 0; /* not visible beyond right edge*/ if (src_x_offset + (int)hubp->curs_attr.width <= 0) cur_en = 0; /* not visible beyond left edge*/ if (src_y_offset >= (int)param->viewport.height) cur_en = 0; /* not visible beyond bottom edge*/ if (src_y_offset < 0) //+ (int)hubp->curs_attr.height cur_en = 0; /* not visible beyond top edge*/ if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr); REG_UPDATE(CURSOR_CONTROL, CURSOR_ENABLE, cur_en); REG_SET_2(CURSOR_POSITION, 0, CURSOR_X_POSITION, pos->x, CURSOR_Y_POSITION, pos->y); REG_SET_2(CURSOR_HOT_SPOT, 0, CURSOR_HOT_SPOT_X, x_hotspot, CURSOR_HOT_SPOT_Y, y_hotspot); REG_SET(CURSOR_DST_OFFSET, 0, CURSOR_DST_X_OFFSET, dst_x_offset); /* TODO Handle surface pixel formats other than 4:4:4 */ }
static bool process_transaction( struct dce_i2c_hw *dce_i2c_hw, struct i2c_request_transaction_data *request) { uint32_t length = request->length; uint8_t *buffer = request->data; bool last_transaction = false; uint32_t value = 0; last_transaction = ((dce_i2c_hw->transaction_count == 3) || (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)); switch (dce_i2c_hw->transaction_count) { case 0: REG_UPDATE_5(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 1: REG_UPDATE_5(DC_I2C_TRANSACTION1, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 2: REG_UPDATE_5(DC_I2C_TRANSACTION2, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; case 3: REG_UPDATE_5(DC_I2C_TRANSACTION3, DC_I2C_STOP_ON_NACK0, 1, DC_I2C_START0, 1, DC_I2C_RW0, 0 != (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ), DC_I2C_COUNT0, length, DC_I2C_STOP0, last_transaction ? 1 : 0); break; default: /* TODO Warning ? */ break; } /* Write the I2C address and I2C data * into the hardware circular buffer, one byte per entry. * As an example, the 7-bit I2C slave address for CRT monitor * for reading DDC/EDID information is 0b1010001. * For an I2C send operation, the LSB must be programmed to 0; * for I2C receive operation, the LSB must be programmed to 1. */ if (dce_i2c_hw->transaction_count == 0) { value = REG_SET_4(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address, DC_I2C_INDEX, 0, DC_I2C_INDEX_WRITE, 1); dce_i2c_hw->buffer_used_write = 0; } else value = REG_SET_2(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address); dce_i2c_hw->buffer_used_write++; if (!(request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)) { while (length) { REG_SET_2(DC_I2C_DATA, value, DC_I2C_INDEX_WRITE, 0, DC_I2C_DATA, *buffer++); dce_i2c_hw->buffer_used_write++; --length; } } ++dce_i2c_hw->transaction_count; dce_i2c_hw->buffer_used_bytes += length + 1; return last_transaction; }
static bool process_transaction( struct i2c_hw_engine_dce110 *hw_engine, struct i2c_request_transaction_data *request) { uint32_t length = request->length; uint8_t *buffer = request->data; uint32_t value = 0; bool last_transaction = false; struct dc_context *ctx = NULL; ctx = hw_engine->base.base.base.ctx; switch (hw_engine->transaction_count) { case 0: SET_I2C_TRANSACTION(0); break; case 1: SET_I2C_TRANSACTION(1); break; case 2: SET_I2C_TRANSACTION(2); break; case 3: SET_I2C_TRANSACTION(3); break; default: /* TODO Warning ? */ break; } /* Write the I2C address and I2C data * into the hardware circular buffer, one byte per entry. * As an example, the 7-bit I2C slave address for CRT monitor * for reading DDC/EDID information is 0b1010001. * For an I2C send operation, the LSB must be programmed to 0; * for I2C receive operation, the LSB must be programmed to 1. */ if (hw_engine->transaction_count == 0) { value = REG_SET_4(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address, DC_I2C_INDEX, 0, DC_I2C_INDEX_WRITE, 1); hw_engine->buffer_used_write = 0; } else value = REG_SET_2(DC_I2C_DATA, 0, DC_I2C_DATA_RW, false, DC_I2C_DATA, request->address); hw_engine->buffer_used_write++; if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) { while (length) { REG_SET_2(DC_I2C_DATA, value, DC_I2C_INDEX_WRITE, 0, DC_I2C_DATA, *buffer++); hw_engine->buffer_used_write++; --length; } } ++hw_engine->transaction_count; hw_engine->buffer_used_bytes += length + 1; return last_transaction; }