/* TODO store/restore FP was here*/ bool dal_clock_source_adjust_pxl_clk_by_pix_amount( struct clock_source *clk_src, struct pixel_clk_params *pix_clk_params, int32_t pix_num) { bool success = false; uint32_t requested_pix_rate_hz; uint32_t cur_pix_rate_hz = retrieve_raw_pix_rate_hz( clk_src, pix_clk_params); requested_pix_rate_hz = cur_pix_rate_hz + pix_num; if (pix_clk_params == NULL) return false; dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "%s[start]: Current(Raw): %u,%03u,%03uHz, Requested(Raw): %u,%03u,%03uHz\n", __func__, (cur_pix_rate_hz / 1000000), (cur_pix_rate_hz / 1000) % 1000, (cur_pix_rate_hz % 1000), (requested_pix_rate_hz / 1000000), (requested_pix_rate_hz / 1000) % 1000, (requested_pix_rate_hz % 1000)); if (dal_is_dp_signal(pix_clk_params->signal_type)) success = clk_src->funcs->adjust_dto_pixel_rate( clk_src, pix_clk_params, requested_pix_rate_hz); else success = clk_src->funcs->adjust_pll_pixel_rate( clk_src, pix_clk_params, requested_pix_rate_hz); cur_pix_rate_hz = retrieve_raw_pix_rate_hz(clk_src, pix_clk_params); dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "%s[end]: Current(Raw): %u,%03u,%03uHz,Requested(Raw): %u,%03u,%03uHz\n\n", __func__, (cur_pix_rate_hz / 1000000), (cur_pix_rate_hz / 1000) % 1000, (cur_pix_rate_hz % 1000), (requested_pix_rate_hz / 1000000), (requested_pix_rate_hz / 1000) % 1000, (requested_pix_rate_hz % 1000)); return success; }
/* audio_dce110 is derived from audio directly, not via dce80 */ struct hw_ctx_audio *dal_hw_ctx_audio_dce110_create( struct dal_context *dal_context, uint32_t azalia_stream_id) { /* allocate memory for struc hw_ctx_audio_dce110 */ struct hw_ctx_audio_dce110 *hw_ctx_dce110 = dal_alloc(sizeof(struct hw_ctx_audio_dce110)); if (!hw_ctx_dce110) { ASSERT_CRITICAL(hw_ctx_dce110); return NULL; } /*return pointer to hw_ctx_audio back to caller -- audio object */ if (construct( hw_ctx_dce110, azalia_stream_id, dal_context)) return &hw_ctx_dce110->base; dal_logger_write( dal_context->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_AUDIO, "Failed to create hw_ctx_audio for DCE11\n"); dal_free(hw_ctx_dce110); return NULL; }
static enum clocks_state get_required_clocks_state( struct display_clock *dc, struct state_dependent_clocks *req_clocks) { int32_t i; struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc); enum clocks_state low_req_clk = disp_clk->max_clks_state; if (!req_clocks) { /* NULL pointer*/ dal_logger_write(dc->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "%s: Invalid parameter", __func__); return CLOCKS_STATE_INVALID; } /* Iterate from highest supported to lowest valid state, and update * lowest RequiredState with the lowest state that satisfies * all required clocks */ for (i = disp_clk->max_clks_state; i >= CLOCKS_STATE_ULTRA_LOW; --i) { if ((req_clocks->display_clk_khz <= max_clks_by_state[i].display_clk_khz) && (req_clocks->pixel_clk_khz <= max_clks_by_state[i].pixel_clk_khz)) low_req_clk = i; } return low_req_clk; }
/** * Calculate PLL Dividers for given Clock Value. * First will call VBIOS Adjust Exec table to check if requested Pixel clock * will be Adjusted based on usage. * Then it will calculate PLL Dividers for this Adjusted clock using preferred * method (Maximum VCO frequency). * * \return * Calculation error in units of 0.01% */ static uint32_t dce112_get_pix_clk_dividers( struct clock_source *cs, struct pixel_clk_params *pix_clk_params, struct pll_settings *pll_settings) { struct dce112_clk_src *clk_src = TO_DCE112_CLK_SRC(cs); uint32_t actualPixelClockInKHz; if (pix_clk_params == NULL || pll_settings == NULL || pix_clk_params->requested_pix_clk == 0) { dal_logger_write(cs->ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_GPU, "%s: Invalid parameters!!\n", __func__); return 0; } memset(pll_settings, 0, sizeof(*pll_settings)); if (clk_src->base.id == CLOCK_SOURCE_ID_DP_DTO) { pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz; pll_settings->calculated_pix_clk = clk_src->ext_clk_khz; pll_settings->actual_pix_clk = pix_clk_params->requested_pix_clk; return 0; } /* PLL only after this point */ actualPixelClockInKHz = pix_clk_params->requested_pix_clk; /* Calculate Dividers */ if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) { switch (pix_clk_params->color_depth) { case COLOR_DEPTH_101010: actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2; break; case COLOR_DEPTH_121212: actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2; break; case COLOR_DEPTH_161616: actualPixelClockInKHz = actualPixelClockInKHz * 2; break; default: break; } } pll_settings->actual_pix_clk = actualPixelClockInKHz; pll_settings->adjusted_pix_clk = actualPixelClockInKHz; pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk; return 0; }
static bool dummy_ack( struct irq_service *irq_service, const struct irq_source_info *info) { dal_logger_write( irq_service->ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_IRQ_SERVICE, "%s: called for non-implemented irq source\n", __func__); return false; }
static bool set_pixel_storage_depth( struct line_buffer *base, enum lb_pixel_depth depth) { bool ret = true; struct line_buffer_dce110 *lb = LB110_FROM_BASE(base); uint32_t value; value = dal_read_reg( base->dal_context, lb->lbx_data_format); switch (depth) { case LB_PIXEL_DEPTH_18BPP: set_reg_field_value(value, 2, LB_DATA_FORMAT, PIXEL_DEPTH); set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); break; case LB_PIXEL_DEPTH_24BPP: set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_DEPTH); set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); break; case LB_PIXEL_DEPTH_30BPP: set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_DEPTH); set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); break; case LB_PIXEL_DEPTH_36BPP: set_reg_field_value(value, 3, LB_DATA_FORMAT, PIXEL_DEPTH); set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_EXPAN_MODE); break; default: ret = false; break; } if (ret == true) { set_reg_field_value(value, 0, LB_DATA_FORMAT, ALPHA_EN); dal_write_reg( base->dal_context, lb->lbx_data_format, value); if (!(lb->caps & depth)) { /*we should use unsupported capabilities * unless it is required by w/a*/ dal_logger_write(base->dal_context->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "%s: Capability not supported", __func__); } } return ret; }
bool dce110_transform_get_max_num_of_supported_lines( struct dce110_transform *xfm110, enum lb_pixel_depth depth, uint32_t pixel_width, uint32_t *lines) { uint32_t pixels_per_entries = 0; uint32_t max_pixels_supports = 0; if (pixel_width == 0) return false; /* Find number of pixels that can fit into a single LB entry and * take floor of the value since we cannot store a single pixel * across multiple entries. */ switch (depth) { case LB_PIXEL_DEPTH_18BPP: pixels_per_entries = LB_BITS_PER_ENTRY / 18; break; case LB_PIXEL_DEPTH_24BPP: pixels_per_entries = LB_BITS_PER_ENTRY / 24; break; case LB_PIXEL_DEPTH_30BPP: pixels_per_entries = LB_BITS_PER_ENTRY / 30; break; case LB_PIXEL_DEPTH_36BPP: pixels_per_entries = LB_BITS_PER_ENTRY / 36; break; default: dal_logger_write(xfm110->base.ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "%s: Invalid LB pixel depth", __func__); break; } if (pixels_per_entries == 0) return false; max_pixels_supports = pixels_per_entries * LB_TOTAL_NUMBER_OF_ENTRIES; *lines = max_pixels_supports / pixel_width; return true; }
static void dce80_link_encoder_enable_tmds_output( struct link_encoder *enc, enum clock_source_id clock_source, enum dc_color_depth color_depth, bool hdmi, bool dual_link, uint32_t pixel_clock) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; /* Enable the PHY */ cntl.action = TRANSMITTER_CONTROL_ENABLE; cntl.engine_id = enc->preferred_engine; cntl.transmitter = enc110->base.transmitter; cntl.pll_id = clock_source; if (hdmi) { cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A; cntl.lanes_number = 4; } else if (dual_link) { cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK; cntl.lanes_number = 8; } else { cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK; cntl.lanes_number = 4; } cntl.hpd_sel = enc110->base.hpd_source; cntl.pixel_clock = pixel_clock; cntl.color_depth = color_depth; result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { dal_logger_write(ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_ENCODER, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); } }
struct clock_source *dal_clock_source_create( struct clock_source_init_data *clk_src_init_data) { enum dce_version dce_ver = dal_adapter_service_get_dce_version(clk_src_init_data->as); enum clock_source_id clk_src_id = dal_graphics_object_id_get_clock_source_id( clk_src_init_data->clk_src_id); switch (dce_ver) { #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) break; case DCE_VERSION_11_0: { switch (clk_src_id) { case CLOCK_SOURCE_ID_PLL0: /* fall through */ case CLOCK_SOURCE_ID_PLL1: /* fall through */ case CLOCK_SOURCE_ID_PLL2: return dal_pll_clock_source_dce110_create( clk_src_init_data); case CLOCK_SOURCE_ID_EXTERNAL: return dal_ext_clock_source_dce110_create( clk_src_init_data); case CLOCK_SOURCE_ID_VCE: return dal_vce_clock_source_dce110_create( clk_src_init_data); default: return NULL; } } break; #endif default: dal_logger_write(clk_src_init_data->dal_ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_GPU, "Clock Source: not supported DCE version %d", dce_ver); ASSERT_CRITICAL(false); break; } return NULL; }
/* enables DP PHY output */ static void dce80_link_encoder_enable_dp_output( struct link_encoder *enc, const struct dc_link_settings *link_settings, enum clock_source_id clock_source) { struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc); struct dc_context *ctx = enc110->base.ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result result; /* Enable the PHY */ /* number_of_lanes is used for pixel clock adjust, * but it's not passed to asic_control. * We need to set number of lanes manually. */ configure_encoder(enc110, link_settings); cntl.action = TRANSMITTER_CONTROL_ENABLE; cntl.engine_id = enc->preferred_engine; cntl.transmitter = enc110->base.transmitter; cntl.pll_id = clock_source; cntl.signal = SIGNAL_TYPE_DISPLAY_PORT; cntl.lanes_number = link_settings->lane_count; cntl.hpd_sel = enc110->base.hpd_source; cntl.pixel_clock = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ; /* TODO: check if undefined works */ cntl.color_depth = COLOR_DEPTH_UNDEFINED; result = link_transmitter_control(enc110, &cntl); if (result != BP_RESULT_OK) { dal_logger_write(ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_ENCODER, "%s: Failed to execute VBIOS command table!\n", __func__); BREAK_TO_DEBUGGER(); } }
static uint32_t read_indirect_azalia_reg( const struct hw_ctx_audio *hw_ctx, uint32_t reg_index) { uint32_t ret_val = 0; uint32_t addr = 0; uint32_t value = 0; /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */ { addr = FROM_BASE(hw_ctx)->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_index; set_reg_field_value(value, reg_index, AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX); dal_write_reg(hw_ctx->ctx, addr, value); } /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */ { addr = FROM_BASE(hw_ctx)->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_data; value = dal_read_reg(hw_ctx->ctx, addr); ret_val = value; } dal_logger_write( hw_ctx->ctx->logger, LOG_MAJOR_HW_TRACE, LOG_MINOR_HW_TRACE_AUDIO, "AUDIO:read_indirect_azalia_reg: index: %u data: %u\n", reg_index, ret_val); return ret_val; }
/* Assign GTC group and enable GTC value embedding */ static void enable_gtc_embedding_with_group( const struct hw_ctx_audio *hw_ctx, uint32_t group_num, uint32_t audio_latency) { /*need to replace the static number with variable */ if (group_num <= 6) { uint32_t value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING); set_reg_field_value( value, group_num, AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING, PRESENTATION_TIME_EMBEDDING_GROUP); set_reg_field_value( value, 1, AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING, PRESENTATION_TIME_EMBEDDING_ENABLE); write_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING, value); /*update audio latency to LIPSYNC*/ set_audio_latency(hw_ctx, audio_latency); } else { dal_logger_write( hw_ctx->ctx->logger, LOG_MAJOR_HW_TRACE, LOG_MINOR_COMPONENT_AUDIO, "GTC group number %d is too big", group_num); } }
static bool get_current_pixel_storage_depth( struct line_buffer *base, enum lb_pixel_depth *depth) { struct line_buffer_dce110 *lb = LB110_FROM_BASE(base); uint32_t value = 0; if (depth == NULL) return false; value = dal_read_reg( base->dal_context, lb->lbx_data_format); switch (get_reg_field_value(value, LB_DATA_FORMAT, PIXEL_DEPTH)) { case 0: *depth = LB_PIXEL_DEPTH_30BPP; break; case 1: *depth = LB_PIXEL_DEPTH_24BPP; break; case 2: *depth = LB_PIXEL_DEPTH_18BPP; break; case 3: *depth = LB_PIXEL_DEPTH_36BPP; break; default: dal_logger_write(base->dal_context->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "%s: Invalid LB pixel depth", __func__); *depth = LB_PIXEL_DEPTH_30BPP; break; } return true; }
bool dal_line_buffer_construct_base( struct line_buffer *lb, struct line_buffer_init_data *init_data ) { struct dal_context *dal_context = init_data->dal_context; if (init_data == NULL || init_data->as == NULL) return false; lb->dal_context = init_data->dal_context; lb->size = dal_adapter_service_get_line_buffer_size(init_data->as); lb->power_gating = dal_adapter_service_is_feature_supported( FEATURE_POWER_GATING_LB_PORTION); dal_logger_write(dal_context->logger, LOG_MAJOR_LINE_BUFFER, LOG_MINOR_LINE_BUFFER_POWERGATING, "LB Partial Power Gating option: %s\n", (lb->power_gating == true ? "Enabled" : "Disabled")); return true; }
static uint32_t get_validation_clock(struct display_clock *dc) { uint32_t clk = 0; struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc); switch (disp_clk->max_clks_state) { case CLOCKS_STATE_ULTRA_LOW: /*Currently not supported, it has 0 in table entry*/ case CLOCKS_STATE_LOW: clk = max_clks_by_state[CLOCKS_STATE_LOW]. display_clk_khz; break; case CLOCKS_STATE_NOMINAL: clk = max_clks_by_state[CLOCKS_STATE_NOMINAL]. display_clk_khz; break; case CLOCKS_STATE_PERFORMANCE: clk = max_clks_by_state[CLOCKS_STATE_PERFORMANCE]. display_clk_khz; break; case CLOCKS_STATE_INVALID: default: /*Invalid Clocks State*/ dal_logger_write(dc->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Invalid clock state"); /* just return the display engine clock for * lowest supported state*/ clk = max_clks_by_state[CLOCKS_STATE_LOW]. display_clk_khz; break; } return clk; }
static bool set_min_clocks_state( struct display_clock *base, enum clocks_state clocks_state) { struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base); if (clocks_state > dc->max_clks_state) { /*Requested state exceeds max supported state.*/ dal_logger_write(base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Requested state exceeds max supported state"); return false; } else if (clocks_state == base->cur_min_clks_state) { /*if we're trying to set the same state, we can just return * since nothing needs to be done*/ return true; } base->cur_min_clks_state = clocks_state; return true; }
/** * prepare_scratch_active_and_requested * * @brief * prepare and update VBIOS scratch pad registers about active and requested * displays * * @param * data - helper's shared data * enum controller_ild - controller Id * enum signal_type - signal type used on display * const struct connector_device_tag_info* - pointer to display type and enum id */ static void prepare_scratch_active_and_requested( struct dal_context *dal_context, struct vbios_helper_data *data, enum controller_id id, enum signal_type s, const struct connector_device_tag_info *dev_tag) { switch (s) { case SIGNAL_TYPE_DVI_SINGLE_LINK: case SIGNAL_TYPE_DVI_SINGLE_LINK1: case SIGNAL_TYPE_DVI_DUAL_LINK: case SIGNAL_TYPE_HDMI_TYPE_A: case SIGNAL_TYPE_DISPLAY_PORT: case SIGNAL_TYPE_DISPLAY_PORT_MST: if (dev_tag->dev_id.device_type == DEVICE_TYPE_DFP) switch (dev_tag->dev_id.enum_id) { case 1: data->requested |= ATOM_S6_ACC_REQ_DFP1; data->active |= ATOM_S3_DFP1_ACTIVE; break; case 2: data->requested |= ATOM_S6_ACC_REQ_DFP2; data->active |= ATOM_S3_DFP2_ACTIVE; break; case 3: data->requested |= ATOM_S6_ACC_REQ_DFP3; data->active |= ATOM_S3_DFP3_ACTIVE; break; case 4: data->requested |= ATOM_S6_ACC_REQ_DFP4; data->active |= ATOM_S3_DFP4_ACTIVE; break; case 5: data->requested |= ATOM_S6_ACC_REQ_DFP5; data->active |= ATOM_S3_DFP5_ACTIVE; break; case 6: data->requested |= ATOM_S6_ACC_REQ_DFP6; data->active |= ATOM_S3_DFP6_ACTIVE; break; default: break; } break; case SIGNAL_TYPE_LVDS: case SIGNAL_TYPE_EDP: data->requested |= ATOM_S6_ACC_REQ_LCD1; data->active |= ATOM_S3_LCD1_ACTIVE; break; case SIGNAL_TYPE_RGB: if (dev_tag->dev_id.device_type == DEVICE_TYPE_CRT) switch (dev_tag->dev_id.enum_id) { case 1: data->requested |= ATOM_S6_ACC_REQ_CRT1; data->active |= ATOM_S3_CRT1_ACTIVE; break; case 2: dal_logger_write(dal_context->logger, LOG_MAJOR_BIOS, LOG_MINOR_COMPONENT_BIOS, "%s: DAL does not support DAC2!\n", __func__); break; default: break; } break; case SIGNAL_TYPE_DVO: dal_logger_write(dal_context->logger, LOG_MAJOR_BIOS, LOG_MINOR_COMPONENT_BIOS, "%s: Passing unsupported Signal!\n", __func__); break; default: dal_logger_write(dal_context->logger, LOG_MAJOR_BIOS, LOG_MINOR_COMPONENT_BIOS, "%s: No such signal!\n", __func__); break; } }
/* get current channel spliting */ static bool get_channel_splitting_mapping( const struct hw_ctx_audio *hw_ctx, enum engine_id engine_id, struct audio_channel_associate_info *audio_mapping) { uint32_t value = 0; if (audio_mapping == NULL) return false; value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO); /*0xFFFFFFFF*/ if (get_reg_field_value(value, AZALIA_F0_CODEC_PIN_ASSOCIATION_INFO, ASSOCIATION_INFO) != MULTI_CHANNEL_SPLIT_NO_ASSO_INFO) { uint32_t multi_channel01_enable = 0; uint32_t multi_channel23_enable = 0; uint32_t multi_channel45_enable = 0; uint32_t multi_channel67_enable = 0; /* get the one we set.*/ audio_mapping->u32all = value; /* check each enable status*/ value = read_indirect_azalia_reg( hw_ctx, ixAZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE); multi_channel01_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL01_ENABLE); multi_channel23_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL23_ENABLE); multi_channel45_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL45_ENABLE); multi_channel67_enable = get_reg_field_value(value, AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE, MULTICHANNEL67_ENABLE); if (multi_channel01_enable == 0 && multi_channel23_enable == 0 && multi_channel45_enable == 0 && multi_channel67_enable == 0) dal_logger_write(hw_ctx->ctx->logger, LOG_MAJOR_HW_TRACE, LOG_MINOR_COMPONENT_AUDIO, "Audio driver did not enable multi-channel\n"); return true; } return false; }
static void dce80_update_hdmi_info_packet( struct dce110_stream_encoder *enc110, uint32_t packet_index, const struct encoder_info_packet *info_packet) { struct dc_context *ctx = enc110->base.ctx; uint32_t cont, send, line; uint32_t addr = 0; uint32_t regval; if (info_packet->valid) { dce80_update_generic_info_packet( enc110, packet_index, info_packet); /* enable transmission of packet(s) - * packet transmission begins on the next frame */ cont = 1; /* send packet(s) every frame */ send = 1; /* select line number to send packets on */ line = 2; } else { cont = 0; send = 0; line = 0; } /* choose which generic packet control to use */ switch (packet_index) { case 0: case 1: addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL0); break; case 2: case 3: addr = LINK_REG(HDMI_GENERIC_PACKET_CONTROL1); break; default: /* invalid HW packet index */ dal_logger_write( ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_ENCODER, "Invalid HW packet index: %s()\n", __func__); break; } regval = dm_read_reg(ctx, addr); switch (packet_index) { case 0: case 2: set_reg_field_value( regval, cont, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT); set_reg_field_value( regval, send, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND); set_reg_field_value( regval, line, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_LINE); break; case 1: case 3: set_reg_field_value( regval, cont, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT); set_reg_field_value( regval, send, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND); set_reg_field_value( regval, line, HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_LINE); break; default: /* invalid HW packet index */ dal_logger_write( ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_ENCODER, "Invalid HW packet index: %s()\n", __func__); break; } dm_write_reg(ctx, addr, regval); }
static bool dal_display_clock_dce110_construct( struct display_clock_dce110 *dc110, struct dc_context *ctx, struct adapter_service *as) { struct display_clock *dc_base = &dc110->disp_clk_base; if (NULL == as) return false; if (!dal_display_clock_construct_base(dc_base, ctx, as)) return false; dc_base->funcs = &funcs; dc110->dfs_bypass_disp_clk = 0; if (!display_clock_integrated_info_construct(dc110, as)) dal_logger_write(dc_base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Cannot obtain VBIOS integrated info\n"); dc110->gpu_pll_ss_percentage = 0; dc110->gpu_pll_ss_divider = 1000; dc110->ss_on_gpu_pll = false; dc_base->id = CLOCK_SOURCE_ID_DFS; /* Initially set max clocks state to nominal. This should be updated by * via a pplib call to DAL IRI eventually calling a * DisplayEngineClock_Dce110::StoreMaxClocksState(). This call will come in * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/ dc110->max_clks_state = CLOCKS_STATE_NOMINAL; dal_divider_range_construct( ÷r_ranges[DIVIDER_RANGE_01], DIVIDER_RANGE_01_START, DIVIDER_RANGE_01_STEP_SIZE, DIVIDER_RANGE_01_BASE_DIVIDER_ID, DIVIDER_RANGE_02_BASE_DIVIDER_ID); dal_divider_range_construct( ÷r_ranges[DIVIDER_RANGE_02], DIVIDER_RANGE_02_START, DIVIDER_RANGE_02_STEP_SIZE, DIVIDER_RANGE_02_BASE_DIVIDER_ID, DIVIDER_RANGE_03_BASE_DIVIDER_ID); dal_divider_range_construct( ÷r_ranges[DIVIDER_RANGE_03], DIVIDER_RANGE_03_START, DIVIDER_RANGE_03_STEP_SIZE, DIVIDER_RANGE_03_BASE_DIVIDER_ID, DIVIDER_RANGE_MAX_DIVIDER_ID); { uint32_t ss_info_num = dal_adapter_service_get_ss_info_num( as, AS_SIGNAL_TYPE_GPU_PLL); if (ss_info_num) { struct spread_spectrum_info info; bool result; memset(&info, 0, sizeof(info)); result = dal_adapter_service_get_ss_info( as, AS_SIGNAL_TYPE_GPU_PLL, 0, &info); /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS * even if SS not enabled and in that case * SSInfo.spreadSpectrumPercentage !=0 would be sign * that SS is enabled */ if (result && info.spread_spectrum_percentage != 0) { dc110->ss_on_gpu_pll = true; dc110->gpu_pll_ss_divider = info.spread_percentage_divider; if (info.type.CENTER_MODE == 0) { /* Currently for DP Reference clock we * need only SS percentage for * downspread */ dc110->gpu_pll_ss_percentage = info.spread_spectrum_percentage; } } } } return true; }
bool dce80_link_encoder_construct( struct dce110_link_encoder *enc110, const struct encoder_init_data *init_data, const struct dce110_link_enc_registers *link_regs, const struct dce110_link_enc_aux_registers *aux_regs, const struct dce110_link_enc_bl_registers *bl_regs) { struct graphics_object_encoder_cap_info enc_cap_info = {0}; enc110->base.funcs = &dce80_lnk_enc_funcs; enc110->base.ctx = init_data->ctx; enc110->base.id = init_data->encoder; enc110->base.hpd_source = init_data->hpd_source; enc110->base.connector = init_data->connector; enc110->base.input_signals = SIGNAL_TYPE_ALL; enc110->base.adapter_service = init_data->adapter_service; enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; enc110->base.features.flags.raw = 0; enc110->base.transmitter = init_data->transmitter; enc110->base.features.flags.bits.IS_AUDIO_CAPABLE = true; enc110->base.features.max_pixel_clock = DCE8_UNIPHY_MAX_PIXEL_CLK_IN_KHZ; enc110->base.features.max_hdmi_pixel_clock = DCE8_UNIPHY_MAX_PIXEL_CLK_IN_KHZ; enc110->base.features.max_deep_color = COLOR_DEPTH_121212; enc110->base.features.max_hdmi_deep_color = COLOR_DEPTH_121212; /* set the flag to indicate whether driver poll the I2C data pin * while doing the DP sink detect */ if (dal_adapter_service_is_feature_supported( FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) enc110->base.features.flags.bits. DP_SINK_DETECT_POLL_DATA_PIN = true; enc110->base.output_signals = SIGNAL_TYPE_DVI_SINGLE_LINK | SIGNAL_TYPE_DVI_DUAL_LINK | SIGNAL_TYPE_LVDS | SIGNAL_TYPE_DISPLAY_PORT | SIGNAL_TYPE_DISPLAY_PORT_MST | SIGNAL_TYPE_EDP | SIGNAL_TYPE_HDMI_TYPE_A; /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. * Prefer DIG assignment is decided by board design. * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design * and VBIOS will filter out 7 UNIPHY for DCE 8.0. * By this, adding DIGG should not hurt DCE 8.0. * This will let DCE 8.1 share DCE 8.0 as much as possible */ enc110->link_regs = link_regs; enc110->aux_regs = aux_regs; enc110->bl_regs = bl_regs; switch (enc110->base.transmitter) { case TRANSMITTER_UNIPHY_A: enc110->base.preferred_engine = ENGINE_ID_DIGA; break; case TRANSMITTER_UNIPHY_B: enc110->base.preferred_engine = ENGINE_ID_DIGB; break; case TRANSMITTER_UNIPHY_C: enc110->base.preferred_engine = ENGINE_ID_DIGC; break; case TRANSMITTER_UNIPHY_D: enc110->base.preferred_engine = ENGINE_ID_DIGD; break; case TRANSMITTER_UNIPHY_E: enc110->base.preferred_engine = ENGINE_ID_DIGE; break; case TRANSMITTER_UNIPHY_F: enc110->base.preferred_engine = ENGINE_ID_DIGF; break; default: ASSERT_CRITICAL(false); enc110->base.preferred_engine = ENGINE_ID_UNKNOWN; break; } dal_logger_write(init_data->ctx->logger, LOG_MAJOR_I2C_AUX, LOG_MINOR_I2C_AUX_CFG, "Using channel: %s [%d]\n", DECODE_CHANNEL_ID(init_data->channel), init_data->channel); /* Override features with DCE-specific values */ if (dal_adapter_service_get_encoder_cap_info( enc110->base.adapter_service, enc110->base.id, &enc_cap_info)) enc110->base.features.flags.bits.IS_HBR2_CAPABLE = enc_cap_info.dp_hbr2_cap; /* test pattern 3 support */ enc110->base.features.flags.bits.IS_TPS3_CAPABLE = true; enc110->base.features.max_deep_color = COLOR_DEPTH_121212; enc110->base.features.flags.bits.IS_Y_ONLY_CAPABLE = dal_adapter_service_is_feature_supported( FEATURE_SUPPORT_DP_Y_ONLY); enc110->base.features.flags.bits.IS_YCBCR_CAPABLE = dal_adapter_service_is_feature_supported( FEATURE_SUPPORT_DP_YUV); return true; }
static uint32_t calc_single_display_min_clks( struct display_clock *base, struct min_clock_params *params, bool set_clk) { struct fixed32_32 h_scale_ratio = dal_fixed32_32_one; struct fixed32_32 v_scale_ratio = dal_fixed32_32_one; uint32_t pix_clk_khz = 0; uint32_t lb_source_width = 0; struct fixed32_32 deep_color_factor; struct fixed32_32 scaler_efficiency; struct fixed32_32 v_filter_init; uint32_t v_filter_init_trunc; uint32_t num_lines_at_frame_start = 3; struct fixed32_32 v_filter_init_ceil; struct fixed32_32 lines_per_lines_out_at_frame_start; struct fixed32_32 lb_lines_in_per_line_out; /* in middle of the frame*/ uint32_t src_wdth_rnd_to_chunks; struct fixed32_32 scaling_coeff; struct fixed32_32 h_blank_granularity_factor = dal_fixed32_32_one; struct fixed32_32 fx_disp_clk_mhz; struct fixed32_32 line_time; struct fixed32_32 disp_pipe_pix_throughput; struct fixed32_32 fx_alt_disp_clk_mhz; uint32_t disp_clk_khz; uint32_t alt_disp_clk_khz; struct display_clock_dce110 *disp_clk_110 = DCLCK110_FROM_BASE(base); uint32_t max_clk_khz = get_validation_clock(base); bool panning_allowed = false; /* TODO: receive this value from AS */ if (params == NULL) { dal_logger_write(base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Invalid input parameter in %s", __func__); return 0; } deep_color_factor = get_deep_color_factor(params); scaler_efficiency = get_scaler_efficiency(base->ctx, params); pix_clk_khz = params->requested_pixel_clock; lb_source_width = params->source_view.width; if (0 != params->dest_view.height && 0 != params->dest_view.width) { h_scale_ratio = dal_fixed32_32_from_fraction( params->source_view.width, params->dest_view.width); v_scale_ratio = dal_fixed32_32_from_fraction( params->source_view.height, params->dest_view.height); } else { dal_logger_write(base->ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_GPU, "Destination height or width is 0!\n"); } v_filter_init = dal_fixed32_32_add( v_scale_ratio, dal_fixed32_32_add_int( dal_fixed32_32_div_int( dal_fixed32_32_mul_int( v_scale_ratio, params->timing_info.INTERLACED), 2), params->scaling_info.v_taps + 1)); v_filter_init = dal_fixed32_32_div_int(v_filter_init, 2); v_filter_init_trunc = dal_fixed32_32_floor(v_filter_init); v_filter_init_ceil = dal_fixed32_32_from_fraction( v_filter_init_trunc, 2); v_filter_init_ceil = dal_fixed32_32_from_int( dal_fixed32_32_ceil(v_filter_init_ceil)); v_filter_init_ceil = dal_fixed32_32_mul_int(v_filter_init_ceil, 2); lines_per_lines_out_at_frame_start = dal_fixed32_32_div_int(v_filter_init_ceil, num_lines_at_frame_start); lb_lines_in_per_line_out = get_lb_lines_in_per_line_out(params, v_scale_ratio); if (panning_allowed) src_wdth_rnd_to_chunks = ((lb_source_width - 1) / 128) * 128 + 256; else src_wdth_rnd_to_chunks = ((lb_source_width + 127) / 128) * 128; scaling_coeff = dal_fixed32_32_div( dal_fixed32_32_from_int(params->scaling_info.v_taps), scaler_efficiency); if (dal_fixed32_32_le(h_scale_ratio, dal_fixed32_32_one)) scaling_coeff = dal_fixed32_32_max( dal_fixed32_32_from_int( dal_fixed32_32_ceil( dal_fixed32_32_from_fraction( params->scaling_info.h_taps, 4))), dal_fixed32_32_max( dal_fixed32_32_mul( scaling_coeff, h_scale_ratio), dal_fixed32_32_one)); if (!params->line_buffer_prefetch_enabled && dal_fixed32_32_floor(lb_lines_in_per_line_out) != 2 && dal_fixed32_32_floor(lb_lines_in_per_line_out) != 4) { uint32_t line_total_pixel = params->timing_info.h_total + lb_source_width - 256; h_blank_granularity_factor = dal_fixed32_32_div( dal_fixed32_32_from_int(params->timing_info.h_total), dal_fixed32_32_div( dal_fixed32_32_from_fraction( line_total_pixel, 2), h_scale_ratio)); } /* Calculate display clock with ramping. Ramping factor is 1.1*/ fx_disp_clk_mhz = dal_fixed32_32_div_int( dal_fixed32_32_mul_int(scaling_coeff, 11), 10); line_time = dal_fixed32_32_from_fraction( params->timing_info.h_total * 1000, pix_clk_khz); disp_pipe_pix_throughput = dal_fixed32_32_mul( lb_lines_in_per_line_out, h_blank_granularity_factor); disp_pipe_pix_throughput = dal_fixed32_32_max( disp_pipe_pix_throughput, lines_per_lines_out_at_frame_start); disp_pipe_pix_throughput = dal_fixed32_32_div(dal_fixed32_32_mul_int( disp_pipe_pix_throughput, src_wdth_rnd_to_chunks), line_time); if (0 != params->timing_info.h_total) { fx_disp_clk_mhz = dal_fixed32_32_max( dal_fixed32_32_div_int( dal_fixed32_32_mul_int( scaling_coeff, pix_clk_khz), 1000), disp_pipe_pix_throughput); fx_disp_clk_mhz = dal_fixed32_32_mul( fx_disp_clk_mhz, dal_fixed32_32_from_fraction(11, 10)); } fx_disp_clk_mhz = dal_fixed32_32_max(fx_disp_clk_mhz, dal_fixed32_32_mul(deep_color_factor, dal_fixed32_32_from_fraction(11, 10))); /* Calculate display clock without ramping */ fx_alt_disp_clk_mhz = scaling_coeff; if (0 != params->timing_info.h_total) { fx_alt_disp_clk_mhz = dal_fixed32_32_max( dal_fixed32_32_div_int(dal_fixed32_32_mul_int( scaling_coeff, pix_clk_khz), 1000), dal_fixed32_32_div_int(dal_fixed32_32_mul_int( disp_pipe_pix_throughput, 105), 100)); } if (set_clk && disp_clk_110->ss_on_gpu_pll && disp_clk_110->gpu_pll_ss_divider) fx_alt_disp_clk_mhz = dal_fixed32_32_mul(fx_alt_disp_clk_mhz, dal_fixed32_32_add_int( dal_fixed32_32_div_int( dal_fixed32_32_div_int( dal_fixed32_32_from_fraction( disp_clk_110->gpu_pll_ss_percentage, disp_clk_110->gpu_pll_ss_divider), 100), 2), 1)); /* convert to integer */ disp_clk_khz = dal_fixed32_32_round( dal_fixed32_32_mul_int(fx_disp_clk_mhz, 1000)); alt_disp_clk_khz = dal_fixed32_32_round( dal_fixed32_32_mul_int(fx_alt_disp_clk_mhz, 1000)); if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz)) disp_clk_khz = alt_disp_clk_khz; if (set_clk) { /* only compensate clock if we are going to set it.*/ disp_clk_khz = get_actual_required_display_clk( disp_clk_110, disp_clk_khz); } disp_clk_khz = disp_clk_khz > max_clk_khz ? max_clk_khz : disp_clk_khz; return disp_clk_khz; }
void dal_clock_source_get_ss_info_from_atombios( struct clock_source *clk_src, enum as_signal_type as_signal, struct spread_spectrum_data *spread_spectrum_data[], uint32_t *ss_entries_num) { enum bp_result bp_result = BP_RESULT_FAILURE; struct spread_spectrum_info *ss_info; struct spread_spectrum_data *ss_data; struct spread_spectrum_info *ss_info_cur; struct spread_spectrum_data *ss_data_cur; uint32_t i; if (ss_entries_num == NULL) { dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "Invalid entry !!!\n"); return; } if (spread_spectrum_data == NULL) { dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "Invalid array pointer!!!\n"); return; } spread_spectrum_data[0] = NULL; *ss_entries_num = 0; *ss_entries_num = dal_bios_parser_get_ss_entry_number( clk_src->bios_parser, as_signal); if (*ss_entries_num == 0) return; ss_info = dal_alloc(sizeof(struct spread_spectrum_info) * (*ss_entries_num)); ss_info_cur = ss_info; if (ss_info == NULL) return; ss_data = dal_alloc(sizeof(struct spread_spectrum_data) * (*ss_entries_num)); if (ss_data == NULL) goto out_free_info; for (i = 0, ss_info_cur = ss_info; i < (*ss_entries_num); ++i, ++ss_info_cur) { bp_result = dal_bios_parser_get_spread_spectrum_info( clk_src->bios_parser, as_signal, i, ss_info_cur); if (bp_result != BP_RESULT_OK) goto out_free_data; } for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data; i < (*ss_entries_num); ++i, ++ss_info_cur, ++ss_data_cur) { if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) { dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "Invalid ATOMBIOS SS Table!!!\n"); goto out_free_data; } /* for HDMI check SS percentage, * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/ if (as_signal == AS_SIGNAL_TYPE_HDMI && ss_info_cur->spread_spectrum_percentage > 6){ /* invalid input, do nothing */ dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "Invalid SS percentage "); dal_logger_write(clk_src->dal_ctx->logger, LOG_MAJOR_SYNC, LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "for HDMI in ATOMBIOS info Table!!!\n"); continue; } if (ss_info_cur->spread_percentage_divider == 1000) { /* Keep previous precision from ATOMBIOS for these * in case new precision set by ATOMBIOS for these * (otherwise all code in DCE specific classes * for all previous ASICs would need * to be updated for SS calculations, * Audio SS compensation and DP DTO SS compensation * which assumes fixed SS percentage Divider = 100)*/ ss_info_cur->spread_spectrum_percentage /= 10; ss_info_cur->spread_percentage_divider = 100; } ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range; ss_data_cur->percentage = ss_info_cur->spread_spectrum_percentage; ss_data_cur->percentage_divider = ss_info_cur->spread_percentage_divider; ss_data_cur->modulation_freq_hz = ss_info_cur->spread_spectrum_range; if (ss_info_cur->type.CENTER_MODE) ss_data_cur->flags.CENTER_SPREAD = 1; if (ss_info_cur->type.EXTERNAL) ss_data_cur->flags.EXTERNAL_SS = 1; } *spread_spectrum_data = ss_data; dal_free(ss_info); return; out_free_data: dal_free(ss_data); *ss_entries_num = 0; out_free_info: dal_free(ss_info); }
static bool dce110_transform_v_set_scaler( struct transform *xfm, const struct scaler_data *data) { struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm); bool is_scaling_required = false; bool filter_updated = false; struct rect luma_viewport = {0}; struct rect chroma_viewport = {0}; struct dc_context *ctx = xfm->ctx; /* 1. Calculate viewport, viewport programming should happen after init * calculations as they may require an adjustment in the viewport. */ calculate_viewport(data, &luma_viewport, &chroma_viewport); /* 2. Program overscan */ program_overscan(xfm110, &data->overscan); /* 3. Program taps and configuration */ is_scaling_required = setup_scaling_configuration(xfm110, data); if (is_scaling_required) { /* 4. Calculate and program ratio, filter initialization */ struct sclv_ratios_inits inits = { 0 }; calculate_inits( xfm110, data, &inits, &luma_viewport, &chroma_viewport); program_scl_ratios_inits(xfm110, &inits); /*scaler coeff of 2-TAPS use hardware auto calculated value*/ /* 5. Program vertical filters */ if (data->taps.v_taps > 2) { program_two_taps_filter_vert(xfm110, false); if (!program_multi_taps_filter(xfm110, data, false)) { dal_logger_write(ctx->logger, LOG_MAJOR_DCP, LOG_MINOR_DCP_SCALER, "Failed vertical taps programming\n"); return false; } filter_updated = true; } else program_two_taps_filter_vert(xfm110, true); /* 6. Program horizontal filters */ if (data->taps.h_taps > 2) { program_two_taps_filter_horz(xfm110, false); if (!program_multi_taps_filter(xfm110, data, true)) { dal_logger_write(ctx->logger, LOG_MAJOR_DCP, LOG_MINOR_DCP_SCALER, "Failed horizontal taps programming\n"); return false; } filter_updated = true; } else program_two_taps_filter_horz(xfm110, true); } /* 7. Program the viewport */ program_viewport(xfm110, &luma_viewport, &chroma_viewport); /* 8. Set bit to flip to new coefficient memory */ if (filter_updated) set_coeff_update_complete(xfm110); return true; }
static bool construct( struct hw_ctx_audio_dce110 *hw_ctx, uint8_t azalia_stream_id, struct dal_context *dal_context) { struct hw_ctx_audio *base = &hw_ctx->base; if (!dal_audio_construct_hw_ctx_audio(base)) return false; base->funcs = &funcs; /* save audio endpoint or dig front for current dce110 audio object */ hw_ctx->azalia_stream_id = azalia_stream_id; hw_ctx->base.ctx = dal_context; /* azalia audio endpoints register offsets. azalia is associated with DIG front. save AUDIO register offset */ switch (azalia_stream_id) { case 1: { hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_index = mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX; hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_data = mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA; } break; case 2: { hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_index = mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX; hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_data = mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA; } break; case 3: { hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_index = mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX; hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_data = mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA; } break; case 4: { hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_index = mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX; hw_ctx->az_mm_reg_offsets. azf0endpointx_azalia_f0_codec_endpoint_data = mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA; } break; default: dal_logger_write( hw_ctx->base.ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_AUDIO, "Invalid Azalia stream ID!"); break; } return true; }
static bool construct( struct i2c_hw_engine_dce110 *engine_dce110, const struct i2c_hw_engine_dce110_create_arg *arg) { uint32_t xtal_ref_div = 0; uint32_t value = 0; /*ddc_setup_offset of dce80 and dce110 have the same register name * but different offset. Do not need different array*/ if (arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t)) return false; if (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t)) return false; if (!arg->reference_frequency) return false; if (!dal_i2c_hw_engine_construct(&engine_dce110->base, arg->ctx)) return false; engine_dce110->base.base.base.funcs = &engine_funcs; engine_dce110->base.base.funcs = &i2c_engine_funcs; engine_dce110->base.funcs = &i2c_hw_engine_funcs; engine_dce110->base.default_speed = arg->default_speed; engine_dce110->engine_id = arg->engine_id; engine_dce110->buffer_used_bytes = 0; engine_dce110->transaction_count = 0; engine_dce110->engine_keep_power_up_count = 1; /*values which are not included by arg*/ engine_dce110->addr.DC_I2C_DDCX_SETUP = mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id]; engine_dce110->addr.DC_I2C_DDCX_SPEED = mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id]; value = dal_read_reg( engine_dce110->base.base.base.ctx, mmMICROSECOND_TIME_BASE_DIV); xtal_ref_div = get_reg_field_value( value, MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV); if (xtal_ref_div == 0) { dal_logger_write( engine_dce110->base.base.base.ctx->logger, LOG_MAJOR_WARNING, LOG_MINOR_COMPONENT_I2C_AUX, "Invalid base timer divider\n", __func__); xtal_ref_div = 2; } /*Calculating Reference Clock by divding original frequency by * XTAL_REF_DIV. * At upper level, uint32_t reference_frequency = * dal_i2caux_get_reference_clock(as) >> 1 * which already divided by 2. So we need x2 to get original * reference clock from ppll_info */ engine_dce110->reference_frequency = (arg->reference_frequency * 2) / xtal_ref_div; return true; }
/* * Initializes asic_capability instance. */ static bool construct( struct asic_capability *cap, struct hw_asic_id *init, struct dc_context *ctx) { bool asic_supported = false; cap->ctx = ctx; memset(cap->data, 0, sizeof(cap->data)); /* ASIC data */ cap->data[ASIC_DATA_VRAM_TYPE] = init->vram_type; cap->data[ASIC_DATA_VRAM_BITWIDTH] = init->vram_width; cap->data[ASIC_DATA_FEATURE_FLAGS] = init->feature_flags; cap->runtime_flags = init->runtime_flags; cap->data[ASIC_DATA_REVISION_ID] = init->hw_internal_rev; cap->data[ASIC_DATA_MAX_UNDERSCAN_PERCENTAGE] = 10; cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 4; cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 1; cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES] = 0; cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 25; /* ASIC basic capability */ cap->caps.UNDERSCAN_FOR_HDMI_ONLY = true; cap->caps.SUPPORT_CEA861E_FINAL = true; cap->caps.MIRABILIS_SUPPORTED = false; cap->caps.MIRABILIS_ENABLED_BY_DEFAULT = false; cap->caps.WIRELESS_LIMIT_TO_720P = false; cap->caps.WIRELESS_FULL_TIMING_ADJUSTMENT = false; cap->caps.WIRELESS_TIMING_ADJUSTMENT = true; cap->caps.WIRELESS_COMPRESSED_AUDIO = false; cap->caps.VCE_SUPPORTED = false; cap->caps.HPD_CHECK_FOR_EDID = false; cap->caps.NO_VCC_OFF_HPD_POLLING = false; cap->caps.NEED_MC_TUNING = false; cap->caps.SUPPORT_8BPP = true; /* ASIC stereo 3D capability */ cap->stereo_3d_caps.SUPPORTED = true; switch (init->chip_family) { case FAMILY_CI: #if defined(CONFIG_DRM_AMD_DAL_DCE8_0) dal_hawaii_asic_capability_create(cap, init); asic_supported = true; #endif break; case FAMILY_KV: if (ASIC_REV_IS_KALINDI(init->hw_internal_rev) || ASIC_REV_IS_BHAVANI(init->hw_internal_rev)) { } else { } break; case FAMILY_CZ: #if defined(CONFIG_DRM_AMD_DAL_DCE11_0) carrizo_asic_capability_create(cap, init); asic_supported = true; #endif break; case FAMILY_VI: #if defined(CONFIG_DRM_AMD_DAL_DCE10_0) if (ASIC_REV_IS_TONGA_P(init->hw_internal_rev) || ASIC_REV_IS_FIJI_P(init->hw_internal_rev)) { tonga_asic_capability_create(cap, init); asic_supported = true; break; } #endif #if defined(CONFIG_DRM_AMD_DAL_DCE11_2) if (ASIC_REV_IS_POLARIS10_P(init->hw_internal_rev) || ASIC_REV_IS_POLARIS11_M(init->hw_internal_rev)) { polaris10_asic_capability_create(cap, init); asic_supported = true; } #endif break; default: /* unsupported "chip_family" */ break; } if (false == asic_supported) { dal_logger_write(ctx->logger, LOG_MAJOR_ERROR, LOG_MINOR_MASK_ALL, "%s: ASIC not supported!\n", __func__); } return asic_supported; }