diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display')
145 files changed, 4019 insertions, 10591 deletions
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 8a626d16e8e3..ad31d7b9912f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1760,7 +1760,7 @@ static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) + caps.min_input_signal * 0x101; if (dc_link_set_backlight_level(dm->backlight_link, - brightness, 0, 0)) + brightness, 0)) return 0; else return 1; @@ -2284,6 +2284,71 @@ static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb, return r; } +static inline uint64_t get_dcc_address(uint64_t address, uint64_t tiling_flags) +{ + uint32_t offset = AMDGPU_TILING_GET(tiling_flags, DCC_OFFSET_256B); + + return offset ? (address + offset * 256) : 0; +} + +static bool fill_plane_dcc_attributes(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + struct dc_plane_state *plane_state, + uint64_t info) +{ + struct dc *dc = adev->dm.dc; + struct dc_dcc_surface_param input; + struct dc_surface_dcc_cap output; + uint32_t offset = AMDGPU_TILING_GET(info, DCC_OFFSET_256B); + uint32_t i64b = AMDGPU_TILING_GET(info, DCC_INDEPENDENT_64B) != 0; + uint64_t dcc_address; + + memset(&input, 0, sizeof(input)); + memset(&output, 0, sizeof(output)); + + if (!offset) + return false; + + if (!dc->cap_funcs.get_dcc_compression_cap) + return false; + + input.format = plane_state->format; + input.surface_size.width = + plane_state->plane_size.grph.surface_size.width; + input.surface_size.height = + plane_state->plane_size.grph.surface_size.height; + input.swizzle_mode = plane_state->tiling_info.gfx9.swizzle; + + if (plane_state->rotation == ROTATION_ANGLE_0 || + plane_state->rotation == ROTATION_ANGLE_180) + input.scan = SCAN_DIRECTION_HORIZONTAL; + else if (plane_state->rotation == ROTATION_ANGLE_90 || + plane_state->rotation == ROTATION_ANGLE_270) + input.scan = SCAN_DIRECTION_VERTICAL; + + if (!dc->cap_funcs.get_dcc_compression_cap(dc, &input, &output)) + return false; + + if (!output.capable) + return false; + + if (i64b == 0 && output.grph.rgb.independent_64b_blks != 0) + return false; + + plane_state->dcc.enable = 1; + plane_state->dcc.grph.meta_pitch = + AMDGPU_TILING_GET(info, DCC_PITCH_MAX) + 1; + plane_state->dcc.grph.independent_64b_blks = i64b; + + dcc_address = get_dcc_address(afb->address, info); + plane_state->address.grph.meta_addr.low_part = + lower_32_bits(dcc_address); + plane_state->address.grph.meta_addr.high_part = + upper_32_bits(dcc_address); + + return true; +} + static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, struct dc_plane_state *plane_state, const struct amdgpu_framebuffer *amdgpu_fb) @@ -2336,6 +2401,10 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, return -EINVAL; } + memset(&plane_state->address, 0, sizeof(plane_state->address)); + memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info)); + memset(&plane_state->dcc, 0, sizeof(plane_state->dcc)); + if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { plane_state->address.type = PLN_ADDR_TYPE_GRAPHICS; plane_state->plane_size.grph.surface_size.x = 0; @@ -2367,8 +2436,6 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, plane_state->color_space = COLOR_SPACE_YCBCR709; } - memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info)); - /* Fill GFX8 params */ if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) { unsigned int bankw, bankh, mtaspect, tile_split, num_banks; @@ -2417,6 +2484,9 @@ static int fill_plane_attributes_from_fb(struct amdgpu_device *adev, plane_state->tiling_info.gfx9.swizzle = AMDGPU_TILING_GET(tiling_flags, SWIZZLE_MODE); plane_state->tiling_info.gfx9.shaderEnable = 1; + + fill_plane_dcc_attributes(adev, amdgpu_fb, plane_state, + tiling_flags); } plane_state->visible = true; @@ -2580,7 +2650,7 @@ get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing) * according to HDMI spec, we use YCbCr709 and YCbCr601 * respectively */ - if (dc_crtc_timing->pix_clk_khz > 27030) { + if (dc_crtc_timing->pix_clk_100hz > 270300) { if (dc_crtc_timing->flags.Y_ONLY) color_space = COLOR_SPACE_YCBCR709_LIMITED; @@ -2623,7 +2693,7 @@ static void adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_ if (timing_out->display_color_depth <= COLOR_DEPTH_888) return; do { - normalized_clk = timing_out->pix_clk_khz; + normalized_clk = timing_out->pix_clk_100hz / 10; /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) normalized_clk /= 2; @@ -2666,10 +2736,10 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, timing_out->v_border_bottom = 0; /* TODO: un-hardcode */ if (drm_mode_is_420_only(info, mode_in) - && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) - && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; else timing_out->pixel_encoding = PIXEL_ENCODING_RGB; @@ -2704,14 +2774,14 @@ fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream, mode_in->crtc_vsync_start - mode_in->crtc_vdisplay; timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start; - timing_out->pix_clk_khz = mode_in->crtc_clock; + timing_out->pix_clk_100hz = mode_in->crtc_clock * 10; timing_out->aspect_ratio = get_aspect_ratio(mode_in); stream->output_color_space = get_output_color_space(timing_out); stream->out_transfer_func->type = TF_TYPE_PREDEFINED; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - if (stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) adjust_colour_depth_from_display_info(timing_out, info); } @@ -2832,7 +2902,7 @@ static void set_master_stream(struct dc_stream_state *stream_set[], if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) { int refresh_rate = 0; - refresh_rate = (stream_set[j]->timing.pix_clk_khz*1000)/ + refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/ (stream_set[j]->timing.h_total*stream_set[j]->timing.v_total); if (refresh_rate > highest_rfr) { highest_rfr = refresh_rate; @@ -2889,11 +2959,9 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_connector = &aconnector->base; if (!aconnector->dc_sink) { - if (!aconnector->mst_port) { - sink = create_fake_sink(aconnector); - if (!sink) - return stream; - } + sink = create_fake_sink(aconnector); + if (!sink) + return stream; } else { sink = aconnector->dc_sink; } @@ -2905,6 +2973,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, goto finish; } + stream->dm_stream_context = aconnector; + list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { /* Search for preferred mode */ if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) { @@ -2956,10 +3026,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, drm_connector, sink); - update_stream_signal(stream); - - if (dm_state && dm_state->freesync_capable) - stream->ignore_msa_timing_param = true; + update_stream_signal(stream, sink); finish: if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON) @@ -3532,6 +3599,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, struct amdgpu_bo *rbo; uint64_t chroma_addr = 0; struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old; + uint64_t tiling_flags, dcc_address; unsigned int awidth; uint32_t domain; int r; @@ -3572,6 +3640,9 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, DRM_ERROR("%p bind failed\n", rbo); return r; } + + amdgpu_bo_get_tiling_flags(rbo, &tiling_flags); + amdgpu_bo_unreserve(rbo); afb->address = amdgpu_bo_gpu_offset(rbo); @@ -3585,6 +3656,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { plane_state->address.grph.addr.low_part = lower_32_bits(afb->address); plane_state->address.grph.addr.high_part = upper_32_bits(afb->address); + + dcc_address = + get_dcc_address(afb->address, tiling_flags); + plane_state->address.grph.meta_addr.low_part = + lower_32_bits(dcc_address); + plane_state->address.grph.meta_addr.high_part = + upper_32_bits(dcc_address); } else { awidth = ALIGN(new_state->fb->width, 64); plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; @@ -4456,20 +4534,6 @@ static void prepare_flip_isr(struct amdgpu_crtc *acrtc) acrtc->crtc_id); } -struct dc_stream_status *dc_state_get_stream_status( - struct dc_state *state, - struct dc_stream_state *stream) -{ - uint8_t i; - - for (i = 0; i < state->stream_count; i++) { - if (stream == state->streams[i]) - return &state->stream_status[i]; - } - - return NULL; -} - static void update_freesync_state_on_stream( struct amdgpu_display_manager *dm, struct dm_crtc_state *new_crtc_state, @@ -4523,12 +4587,12 @@ static void update_freesync_state_on_stream( TRANSFER_FUNC_UNKNOWN, &vrr_infopacket); - new_crtc_state->freesync_timing_changed = + new_crtc_state->freesync_timing_changed |= (memcmp(&new_crtc_state->vrr_params.adjust, &vrr_params.adjust, sizeof(vrr_params.adjust)) != 0); - new_crtc_state->freesync_vrr_info_changed = + new_crtc_state->freesync_vrr_info_changed |= (memcmp(&new_crtc_state->vrr_infopacket, &vrr_infopacket, sizeof(vrr_infopacket)) != 0); @@ -4544,254 +4608,6 @@ static void update_freesync_state_on_stream( new_crtc_state->base.crtc->base.id, (int)new_crtc_state->base.vrr_enabled, (int)vrr_params.state); - - if (new_crtc_state->freesync_timing_changed) - DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n", - new_crtc_state->base.crtc->base.id, - vrr_params.adjust.v_total_min, - vrr_params.adjust.v_total_max); -} - -/* - * Executes flip - * - * Waits on all BO's fences and for proper vblank count - */ -static void amdgpu_dm_do_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - uint32_t target, - struct dc_state *state) -{ - unsigned long flags; - uint64_t timestamp_ns; - uint32_t target_vblank; - int r, vpos, hpos; - struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb); - struct amdgpu_bo *abo = gem_to_amdgpu_bo(fb->obj[0]); - struct amdgpu_device *adev = crtc->dev->dev_private; - bool async_flip = (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; - struct dc_flip_addrs addr = { {0} }; - /* TODO eliminate or rename surface_update */ - struct dc_surface_update surface_updates[1] = { {0} }; - struct dc_stream_update stream_update = {0}; - struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); - struct dc_stream_status *stream_status; - struct dc_plane_state *surface; - - - /* Prepare wait for target vblank early - before the fence-waits */ - target_vblank = target - (uint32_t)drm_crtc_vblank_count(crtc) + - amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id); - - /* - * TODO This might fail and hence better not used, wait - * explicitly on fences instead - * and in general should be called for - * blocking commit to as per framework helpers - */ - r = amdgpu_bo_reserve(abo, true); - if (unlikely(r != 0)) { - DRM_ERROR("failed to reserve buffer before flip\n"); - WARN_ON(1); - } - - /* Wait for all fences on this FB */ - WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false, - MAX_SCHEDULE_TIMEOUT) < 0); - - amdgpu_bo_unreserve(abo); - - /* - * Wait until we're out of the vertical blank period before the one - * targeted by the flip - */ - while ((acrtc->enabled && - (amdgpu_display_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, - 0, &vpos, &hpos, NULL, - NULL, &crtc->hwmode) - & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == - (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && - (int)(target_vblank - - amdgpu_get_vblank_counter_kms(adev->ddev, acrtc->crtc_id)) > 0)) { - usleep_range(1000, 1100); - } - - /* Flip */ - spin_lock_irqsave(&crtc->dev->event_lock, flags); - - WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE); - WARN_ON(!acrtc_state->stream); - - addr.address.grph.addr.low_part = lower_32_bits(afb->address); - addr.address.grph.addr.high_part = upper_32_bits(afb->address); - addr.flip_immediate = async_flip; - - timestamp_ns = ktime_get_ns(); - addr.flip_timestamp_in_us = div_u64(timestamp_ns, 1000); - - - if (acrtc->base.state->event) - prepare_flip_isr(acrtc); - - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - - stream_status = dc_stream_get_status(acrtc_state->stream); - if (!stream_status) { - DRM_ERROR("No stream status for CRTC: id=%d\n", - acrtc->crtc_id); - return; - } - - surface = stream_status->plane_states[0]; - surface_updates->surface = surface; - - if (!surface) { - DRM_ERROR("No surface for CRTC: id=%d\n", - acrtc->crtc_id); - return; - } - surface_updates->flip_addr = &addr; - - if (acrtc_state->stream) { - update_freesync_state_on_stream( - &adev->dm, - acrtc_state, - acrtc_state->stream, - surface, - addr.flip_timestamp_in_us); - - if (acrtc_state->freesync_timing_changed) - stream_update.adjust = - &acrtc_state->stream->adjust; - - if (acrtc_state->freesync_vrr_info_changed) - stream_update.vrr_infopacket = - &acrtc_state->stream->vrr_infopacket; - } - - /* Update surface timing information. */ - surface->time.time_elapsed_in_us[surface->time.index] = - addr.flip_timestamp_in_us - surface->time.prev_update_time_in_us; - surface->time.prev_update_time_in_us = addr.flip_timestamp_in_us; - surface->time.index++; - if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX) - surface->time.index = 0; - - mutex_lock(&adev->dm.dc_lock); - - dc_commit_updates_for_stream(adev->dm.dc, - surface_updates, - 1, - acrtc_state->stream, - &stream_update, - &surface_updates->surface, - state); - mutex_unlock(&adev->dm.dc_lock); - - DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n", - __func__, - addr.address.grph.addr.high_part, - addr.address.grph.addr.low_part); -} - -/* - * TODO this whole function needs to go - * - * dc_surface_update is needlessly complex. See if we can just replace this - * with a dc_plane_state and follow the atomic model a bit more closely here. - */ -static bool commit_planes_to_stream( - struct amdgpu_display_manager *dm, - struct dc *dc, - struct dc_plane_state **plane_states, - uint8_t new_plane_count, - struct dm_crtc_state *dm_new_crtc_state, - struct dm_crtc_state *dm_old_crtc_state, - struct dc_state *state) -{ - /* no need to dynamically allocate this. it's pretty small */ - struct dc_surface_update updates[MAX_SURFACES]; - struct dc_flip_addrs *flip_addr; - struct dc_plane_info *plane_info; - struct dc_scaling_info *scaling_info; - int i; - struct dc_stream_state *dc_stream = dm_new_crtc_state->stream; - struct dc_stream_update *stream_update = - kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL); - unsigned int abm_level; - - if (!stream_update) { - BREAK_TO_DEBUGGER(); - return false; - } - - flip_addr = kcalloc(MAX_SURFACES, sizeof(struct dc_flip_addrs), - GFP_KERNEL); - plane_info = kcalloc(MAX_SURFACES, sizeof(struct dc_plane_info), - GFP_KERNEL); - scaling_info = kcalloc(MAX_SURFACES, sizeof(struct dc_scaling_info), - GFP_KERNEL); - - if (!flip_addr || !plane_info || !scaling_info) { - kfree(flip_addr); - kfree(plane_info); - kfree(scaling_info); - kfree(stream_update); - return false; - } - - memset(updates, 0, sizeof(updates)); - - stream_update->src = dc_stream->src; - stream_update->dst = dc_stream->dst; - stream_update->out_transfer_func = dc_stream->out_transfer_func; - - if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) { - abm_level = dm_new_crtc_state->abm_level; - stream_update->abm_level = &abm_level; - } - - for (i = 0; i < new_plane_count; i++) { - updates[i].surface = plane_states[i]; - updates[i].gamma = - (struct dc_gamma *)plane_states[i]->gamma_correction; - updates[i].in_transfer_func = plane_states[i]->in_transfer_func; - flip_addr[i].address = plane_states[i]->address; - flip_addr[i].flip_immediate = plane_states[i]->flip_immediate; - plane_info[i].color_space = plane_states[i]->color_space; - plane_info[i].format = plane_states[i]->format; - plane_info[i].plane_size = plane_states[i]->plane_size; - plane_info[i].rotation = plane_states[i]->rotation; - plane_info[i].horizontal_mirror = plane_states[i]->horizontal_mirror; - plane_info[i].stereo_format = plane_states[i]->stereo_format; - plane_info[i].tiling_info = plane_states[i]->tiling_info; - plane_info[i].visible = plane_states[i]->visible; - plane_info[i].per_pixel_alpha = plane_states[i]->per_pixel_alpha; - plane_info[i].dcc = plane_states[i]->dcc; - scaling_info[i].scaling_quality = plane_states[i]->scaling_quality; - scaling_info[i].src_rect = plane_states[i]->src_rect; - scaling_info[i].dst_rect = plane_states[i]->dst_rect; - scaling_info[i].clip_rect = plane_states[i]->clip_rect; - - updates[i].flip_addr = &flip_addr[i]; - updates[i].plane_info = &plane_info[i]; - updates[i].scaling_info = &scaling_info[i]; - } - - mutex_lock(&dm->dc_lock); - dc_commit_updates_for_stream( - dc, - updates, - new_plane_count, - dc_stream, stream_update, plane_states, state); - mutex_unlock(&dm->dc_lock); - - kfree(flip_addr); - kfree(plane_info); - kfree(scaling_info); - kfree(stream_update); - return true; } static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, @@ -4801,26 +4617,51 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, struct drm_crtc *pcrtc, bool *wait_for_vblank) { - uint32_t i; + uint32_t i, r; + uint64_t timestamp_ns; struct drm_plane *plane; struct drm_plane_state *old_plane_state, *new_plane_state; - struct dc_stream_state *dc_stream_attach; - struct dc_plane_state *plane_states_constructed[MAX_SURFACES]; struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc); struct drm_crtc_state *new_pcrtc_state = drm_atomic_get_new_crtc_state(state, pcrtc); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state); struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc)); - int planes_count = 0; + int flip_count = 0, planes_count = 0, vpos, hpos; unsigned long flags; + struct amdgpu_bo *abo; + uint64_t tiling_flags, dcc_address; + uint32_t target, target_vblank; + + struct { + struct dc_surface_update surface_updates[MAX_SURFACES]; + struct dc_flip_addrs flip_addrs[MAX_SURFACES]; + struct dc_stream_update stream_update; + } *flip; + + struct { + struct dc_surface_update surface_updates[MAX_SURFACES]; + struct dc_plane_info plane_infos[MAX_SURFACES]; + struct dc_scaling_info scaling_infos[MAX_SURFACES]; + struct dc_stream_update stream_update; + } *full; + + flip = kzalloc(sizeof(*flip), GFP_KERNEL); + full = kzalloc(sizeof(*full), GFP_KERNEL); + + if (!flip || !full) { + dm_error("Failed to allocate update bundles\n"); + goto cleanup; + } /* update planes when needed */ for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) { struct drm_crtc *crtc = new_plane_state->crtc; struct drm_crtc_state *new_crtc_state; struct drm_framebuffer *fb = new_plane_state->fb; + struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb); bool pflip_needed; + struct dc_plane_state *dc_plane; struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state); if (plane->type == DRM_PLANE_TYPE_CURSOR) { @@ -4835,73 +4676,193 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, if (!new_crtc_state->active) continue; - pflip_needed = !state->allow_modeset; - - spin_lock_irqsave(&crtc->dev->event_lock, flags); - if (acrtc_attach->pflip_status != AMDGPU_FLIP_NONE) { - DRM_ERROR("%s: acrtc %d, already busy\n", - __func__, - acrtc_attach->crtc_id); - /* In commit tail framework this cannot happen */ - WARN_ON(1); - } - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); - - if (!pflip_needed || plane->type == DRM_PLANE_TYPE_OVERLAY) { - WARN_ON(!dm_new_plane_state->dc_state); - - plane_states_constructed[planes_count] = dm_new_plane_state->dc_state; + pflip_needed = old_plane_state->fb && + old_plane_state->fb != new_plane_state->fb; - dc_stream_attach = acrtc_state->stream; - planes_count++; + dc_plane = dm_new_plane_state->dc_state; - } else if (new_crtc_state->planes_changed) { - /* Assume even ONE crtc with immediate flip means + if (pflip_needed) { + /* + * Assume even ONE crtc with immediate flip means * entire can't wait for VBLANK * TODO Check if it's correct */ - *wait_for_vblank = - new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC ? - false : true; - - /* TODO: Needs rework for multiplane flip */ - if (plane->type == DRM_PLANE_TYPE_PRIMARY) - drm_crtc_vblank_get(crtc); - - amdgpu_dm_do_flip( - crtc, - fb, - (uint32_t)drm_crtc_vblank_count(crtc) + *wait_for_vblank, - dc_state); + if (new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) + *wait_for_vblank = false; + + /* + * TODO This might fail and hence better not used, wait + * explicitly on fences instead + * and in general should be called for + * blocking commit to as per framework helpers + */ + abo = gem_to_amdgpu_bo(fb->obj[0]); + r = amdgpu_bo_reserve(abo, true); + if (unlikely(r != 0)) { + DRM_ERROR("failed to reserve buffer before flip\n"); + WARN_ON(1); + } + + /* Wait for all fences on this FB */ + WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false, + MAX_SCHEDULE_TIMEOUT) < 0); + + amdgpu_bo_get_tiling_flags(abo, &tiling_flags); + + amdgpu_bo_unreserve(abo); + + flip->flip_addrs[flip_count].address.grph.addr.low_part = lower_32_bits(afb->address); + flip->flip_addrs[flip_count].address.grph.addr.high_part = upper_32_bits(afb->address); + + dcc_address = get_dcc_address(afb->address, tiling_flags); + flip->flip_addrs[flip_count].address.grph.meta_addr.low_part = lower_32_bits(dcc_address); + flip->flip_addrs[flip_count].address.grph.meta_addr.high_part = upper_32_bits(dcc_address); + + flip->flip_addrs[flip_count].flip_immediate = + (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; + + timestamp_ns = ktime_get_ns(); + flip->flip_addrs[flip_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); + flip->surface_updates[flip_count].flip_addr = &flip->flip_addrs[flip_count]; + flip->surface_updates[flip_count].surface = dc_plane; + + if (!flip->surface_updates[flip_count].surface) { + DRM_ERROR("No surface for CRTC: id=%d\n", + acrtc_attach->crtc_id); + continue; + } + + if (plane == pcrtc->primary) + update_freesync_state_on_stream( + dm, + acrtc_state, + acrtc_state->stream, + dc_plane, + flip->flip_addrs[flip_count].flip_timestamp_in_us); + + DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x\n", + __func__, + flip->flip_addrs[flip_count].address.grph.addr.high_part, + flip->flip_addrs[flip_count].address.grph.addr.low_part); + + flip_count += 1; } + full->surface_updates[planes_count].surface = dc_plane; + if (new_pcrtc_state->color_mgmt_changed) { + full->surface_updates[planes_count].gamma = dc_plane->gamma_correction; + full->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; + } + + + full->scaling_infos[planes_count].scaling_quality = dc_plane->scaling_quality; + full->scaling_infos[planes_count].src_rect = dc_plane->src_rect; + full->scaling_infos[planes_count].dst_rect = dc_plane->dst_rect; + full->scaling_infos[planes_count].clip_rect = dc_plane->clip_rect; + full->surface_updates[planes_count].scaling_info = &full->scaling_infos[planes_count]; + + + full->plane_infos[planes_count].color_space = dc_plane->color_space; + full->plane_infos[planes_count].format = dc_plane->format; + full->plane_infos[planes_count].plane_size = dc_plane->plane_size; + full->plane_infos[planes_count].rotation = dc_plane->rotation; + full->plane_infos[planes_count].horizontal_mirror = dc_plane->horizontal_mirror; + full->plane_infos[planes_count].stereo_format = dc_plane->stereo_format; + full->plane_infos[planes_count].tiling_info = dc_plane->tiling_info; + full->plane_infos[planes_count].visible = dc_plane->visible; + full->plane_infos[planes_count].per_pixel_alpha = dc_plane->per_pixel_alpha; + full->plane_infos[planes_count].dcc = dc_plane->dcc; + full->surface_updates[planes_count].plane_info = &full->plane_infos[planes_count]; + + planes_count += 1; + } - if (planes_count) { - unsigned long flags; + /* + * TODO: For proper atomic behaviour, we should be calling into DC once with + * all the changes. However, DC refuses to do pageflips and non-pageflip + * changes in the same call. Change DC to respect atomic behaviour, + * hopefully eliminating dc_*_update structs in their entirety. + */ + if (flip_count) { + target = (uint32_t)drm_crtc_vblank_count(pcrtc) + *wait_for_vblank; + /* Prepare wait for target vblank early - before the fence-waits */ + target_vblank = target - (uint32_t)drm_crtc_vblank_count(pcrtc) + + amdgpu_get_vblank_counter_kms(pcrtc->dev, acrtc_attach->crtc_id); - if (new_pcrtc_state->event) { + /* + * Wait until we're out of the vertical blank period before the one + * targeted by the flip + */ + while ((acrtc_attach->enabled && + (amdgpu_display_get_crtc_scanoutpos(dm->ddev, acrtc_attach->crtc_id, + 0, &vpos, &hpos, NULL, + NULL, &pcrtc->hwmode) + & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && + (int)(target_vblank - + amdgpu_get_vblank_counter_kms(dm->ddev, acrtc_attach->crtc_id)) > 0)) { + usleep_range(1000, 1100); + } + if (acrtc_attach->base.state->event) { drm_crtc_vblank_get(pcrtc); spin_lock_irqsave(&pcrtc->dev->event_lock, flags); + + WARN_ON(acrtc_attach->pflip_status != AMDGPU_FLIP_NONE); prepare_flip_isr(acrtc_attach); + spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); } - dc_stream_attach->abm_level = acrtc_state->abm_level; + if (acrtc_state->stream) { - if (false == commit_planes_to_stream(dm, - dm->dc, - plane_states_constructed, - planes_count, - acrtc_state, - dm_old_crtc_state, - dc_state)) - dm_error("%s: Failed to attach plane!\n", __func__); - } else { - /*TODO BUG Here should go disable planes on CRTC. */ + if (acrtc_state->freesync_timing_changed) + flip->stream_update.adjust = + &acrtc_state->stream->adjust; + + if (acrtc_state->freesync_vrr_info_changed) + flip->stream_update.vrr_infopacket = + &acrtc_state->stream->vrr_infopacket; + } + + mutex_lock(&dm->dc_lock); + dc_commit_updates_for_stream(dm->dc, + flip->surface_updates, + flip_count, + acrtc_state->stream, + &flip->stream_update, + dc_state); + mutex_unlock(&dm->dc_lock); } + + if (planes_count) { + if (new_pcrtc_state->mode_changed) { + full->stream_update.src = acrtc_state->stream->src; + full->stream_update.dst = acrtc_state->stream->dst; + } + + if (new_pcrtc_state->color_mgmt_changed) + full->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func; + + acrtc_state->stream->abm_level = acrtc_state->abm_level; + if (acrtc_state->abm_level != dm_old_crtc_state->abm_level) + full->stream_update.abm_level = &acrtc_state->abm_level; + + mutex_lock(&dm->dc_lock); + dc_commit_updates_for_stream(dm->dc, + full->surface_updates, + planes_count, + acrtc_state->stream, + &full->stream_update, + dc_state); + mutex_unlock(&dm->dc_lock); + } + +cleanup: + kfree(flip); + kfree(full); } /* @@ -4915,7 +4876,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_state, struct dc_stream_state *stream_state) { - stream_state->mode_changed = crtc_state->mode_changed; + stream_state->mode_changed = + crtc_state->mode_changed || crtc_state->active_changed; } static int amdgpu_dm_atomic_commit(struct drm_device *dev, @@ -4936,10 +4898,25 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, */ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); - if (drm_atomic_crtc_needs_modeset(new_crtc_state) && dm_old_crtc_state->stream) + if (drm_atomic_crtc_needs_modeset(new_crtc_state) + && dm_old_crtc_state->stream) { + /* + * If the stream is removed and CRC capture was + * enabled on the CRTC the extra vblank reference + * needs to be dropped since CRC capture will be + * disabled. + */ + if (!dm_new_crtc_state->stream + && dm_new_crtc_state->crc_enabled) { + drm_crtc_vblank_put(crtc); + dm_new_crtc_state->crc_enabled = false; + } + manage_dm_interrupts(adev, acrtc, false); + } } /* * Add check here for SoC's that support hardware cursor plane, to @@ -5077,8 +5054,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) dc_stream_get_status(dm_new_crtc_state->stream); if (!status) - status = dc_state_get_stream_status(dc_state, - dm_new_crtc_state->stream); + status = dc_stream_get_status_from_state(dc_state, + dm_new_crtc_state->stream); if (!status) DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc); @@ -5087,13 +5064,18 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) } } - /* Handle scaling, underscan, and abm changes*/ + /* Handle connector state changes */ for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); + struct dc_surface_update dummy_updates[MAX_SURFACES]; + struct dc_stream_update stream_update; struct dc_stream_status *status = NULL; + memset(&dummy_updates, 0, sizeof(dummy_updates)); + memset(&stream_update, 0, sizeof(stream_update)); + if (acrtc) { new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); @@ -5103,37 +5085,48 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; - dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - /* Skip anything that is not scaling or underscan changes */ if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) && (dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level)) continue; - update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, - dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); + if (is_scaling_state_different(dm_new_con_state, dm_old_con_state)) { + update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode, + dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream); - if (!dm_new_crtc_state->stream) - continue; + stream_update.src = dm_new_crtc_state->stream->src; + stream_update.dst = dm_new_crtc_state->stream->dst; + } + + if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) { + dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level; + + stream_update.abm_level = &dm_new_crtc_state->abm_level; + } status = dc_stream_get_status(dm_new_crtc_state->stream); WARN_ON(!status); WARN_ON(!status->plane_count); - dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level; + /* + * TODO: DC refuses to perform stream updates without a dc_surface_update. + * Here we create an empty update on each plane. + * To fix this, DC should permit updating only stream properties. + */ + for (j = 0; j < status->plane_count; j++) + dummy_updates[j].surface = status->plane_states[0]; - /*TODO How it works with MPO ?*/ - if (!commit_planes_to_stream( - dm, - dm->dc, - status->plane_states, - status->plane_count, - dm_new_crtc_state, - to_dm_crtc_state(old_crtc_state), - dc_state)) - dm_error("%s: Failed to update stream scaling!\n", __func__); + + mutex_lock(&dm->dc_lock); + dc_commit_updates_for_stream(dm->dc, + dummy_updates, + status->plane_count, + dm_new_crtc_state->stream, + &stream_update, + dc_state); + mutex_unlock(&dm->dc_lock); } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, @@ -5158,6 +5151,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) continue; manage_dm_interrupts(adev, acrtc, true); + +#ifdef CONFIG_DEBUG_FS + /* The stream has changed so CRC capture needs to re-enabled. */ + if (dm_new_crtc_state->crc_enabled) + amdgpu_dm_crtc_set_crc_source(crtc, "auto"); +#endif } /* update planes when needed per crtc*/ @@ -5184,18 +5183,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) } spin_unlock_irqrestore(&adev->ddev->event_lock, flags); + /* Signal HW programming completion */ + drm_atomic_helper_commit_hw_done(state); if (wait_for_vblank) drm_atomic_helper_wait_for_flip_done(dev, state); - /* - * FIXME: - * Delay hw_done() until flip_done() is signaled. This is to block - * another commit from freeing the CRTC state while we're still - * waiting on flip_done. - */ - drm_atomic_helper_commit_hw_done(state); - drm_atomic_helper_cleanup_planes(dev, state); /* @@ -5359,10 +5352,13 @@ static void get_freesync_config_for_crtc( struct mod_freesync_config config = {0}; struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); + struct drm_display_mode *mode = &new_crtc_state->base.mode; - new_crtc_state->vrr_supported = new_con_state->freesync_capable; + new_crtc_state->vrr_supported = new_con_state->freesync_capable && + aconnector->min_vfreq <= drm_mode_vrefresh(mode); - if (new_con_state->freesync_capable) { + if (new_crtc_state->vrr_supported) { + new_crtc_state->stream->ignore_msa_timing_param = true; config.state = new_crtc_state->base.vrr_enabled ? VRR_STATE_ACTIVE_VARIABLE : VRR_STATE_INACTIVE; @@ -5388,15 +5384,15 @@ static void reset_freesync_config_for_crtc( sizeof(new_crtc_state->vrr_infopacket)); } -static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, - struct drm_atomic_state *state, - bool enable, - bool *lock_and_validation_needed) +static int dm_update_crtc_state(struct amdgpu_display_manager *dm, + struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state, + struct drm_crtc_state *new_crtc_state, + bool enable, + bool *lock_and_validation_needed) { struct dm_atomic_state *dm_state = NULL; - struct drm_crtc *crtc; - struct drm_crtc_state *old_crtc_state, *new_crtc_state; - int i; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; struct dc_stream_state *new_stream; int ret = 0; @@ -5405,200 +5401,203 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, * TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set * update changed items */ - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - struct amdgpu_crtc *acrtc = NULL; - struct amdgpu_dm_connector *aconnector = NULL; - struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL; - struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL; - struct drm_plane_state *new_plane_state = NULL; + struct amdgpu_crtc *acrtc = NULL; + struct amdgpu_dm_connector *aconnector = NULL; + struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL; + struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL; + struct drm_plane_state *new_plane_state = NULL; - new_stream = NULL; + new_stream = NULL; - dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); - acrtc = to_amdgpu_crtc(crtc); + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + acrtc = to_amdgpu_crtc(crtc); - new_plane_state = drm_atomic_get_new_plane_state(state, new_crtc_state->crtc->primary); + new_plane_state = drm_atomic_get_new_plane_state(state, new_crtc_state->crtc->primary); - if (new_crtc_state->enable && new_plane_state && !new_plane_state->fb) { - ret = -EINVAL; - goto fail; - } + if (new_crtc_state->enable && new_plane_state && !new_plane_state->fb) { + ret = -EINVAL; + goto fail; + } - aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); + aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); - /* TODO This hack should go away */ - if (aconnector && enable) { - /* Make sure fake sink is created in plug-in scenario */ - drm_new_conn_state = drm_atomic_get_new_connector_state(state, - &aconnector->base); - drm_old_conn_state = drm_atomic_get_old_connector_state(state, - &aconnector->base); + /* TODO This hack should go away */ + if (aconnector && enable) { + /* Make sure fake sink is created in plug-in scenario */ + drm_new_conn_state = drm_atomic_get_new_connector_state(state, + &aconnector->base); + drm_old_conn_state = drm_atomic_get_old_connector_state(state, + &aconnector->base); - if (IS_ERR(drm_new_conn_state)) { - ret = PTR_ERR_OR_ZERO(drm_new_conn_state); - break; - } - - dm_new_conn_state = to_dm_connector_state(drm_new_conn_state); - dm_old_conn_state = to_dm_connector_state(drm_old_conn_state); + if (IS_ERR(drm_new_conn_state)) { + ret = PTR_ERR_OR_ZERO(drm_new_conn_state); + goto fail; + } - new_stream = create_stream_for_sink(aconnector, - &new_crtc_state->mode, - dm_new_conn_state, - dm_old_crtc_state->stream); + dm_new_conn_state = to_dm_connector_state(drm_new_conn_state); + dm_old_conn_state = to_dm_connector_state(drm_old_conn_state); - /* - * we can have no stream on ACTION_SET if a display - * was disconnected during S3, in this case it is not an - * error, the OS will be updated after detection, and - * will do the right thing on next atomic commit - */ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + goto skip_modeset; - if (!new_stream) { - DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n", - __func__, acrtc->base.base.id); - break; - } + new_stream = create_stream_for_sink(aconnector, + &new_crtc_state->mode, + dm_new_conn_state, + dm_old_crtc_state->stream); - dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level; + /* + * we can have no stream on ACTION_SET if a display + * was disconnected during S3, in this case it is not an + * error, the OS will be updated after detection, and + * will do the right thing on next atomic commit + */ - if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && - dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) { - new_crtc_state->mode_changed = false; - DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d", - new_crtc_state->mode_changed); - } + if (!new_stream) { + DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n", + __func__, acrtc->base.base.id); + ret = -ENOMEM; + goto fail; } - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) - goto next_crtc; + dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level; - DRM_DEBUG_DRIVER( - "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, " - "planes_changed:%d, mode_changed:%d,active_changed:%d," - "connectors_changed:%d\n", - acrtc->crtc_id, - new_crtc_state->enable, - new_crtc_state->active, - new_crtc_state->planes_changed, - new_crtc_state->mode_changed, - new_crtc_state->active_changed, - new_crtc_state->connectors_changed); + if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && + dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) { + new_crtc_state->mode_changed = false; + DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d", + new_crtc_state->mode_changed); + } + } - /* Remove stream for any changed/disabled CRTC */ - if (!enable) { + /* mode_changed flag may get updated above, need to check again */ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + goto skip_modeset; - if (!dm_old_crtc_state->stream) - goto next_crtc; + DRM_DEBUG_DRIVER( + "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, " + "planes_changed:%d, mode_changed:%d,active_changed:%d," + "connectors_changed:%d\n", + acrtc->crtc_id, + new_crtc_state->enable, + new_crtc_state->active, + new_crtc_state->planes_changed, + new_crtc_state->mode_changed, + new_crtc_state->active_changed, + new_crtc_state->connectors_changed); - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - goto fail; + /* Remove stream for any changed/disabled CRTC */ + if (!enable) { - DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n", - crtc->base.id); + if (!dm_old_crtc_state->stream) + goto skip_modeset; - /* i.e. reset mode */ - if (dc_remove_stream_from_ctx( - dm->dc, - dm_state->context, - dm_old_crtc_state->stream) != DC_OK) { - ret = -EINVAL; - goto fail; - } + ret = dm_atomic_get_state(state, &dm_state); + if (ret) + goto fail; - dc_stream_release(dm_old_crtc_state->stream); - dm_new_crtc_state->stream = NULL; + DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n", + crtc->base.id); + + /* i.e. reset mode */ + if (dc_remove_stream_from_ctx( + dm->dc, + dm_state->context, + dm_old_crtc_state->stream) != DC_OK) { + ret = -EINVAL; + goto fail; + } - reset_freesync_config_for_crtc(dm_new_crtc_state); + dc_stream_release(dm_old_crtc_state->stream); + dm_new_crtc_state->stream = NULL; - *lock_and_validation_needed = true; + reset_freesync_config_for_crtc(dm_new_crtc_state); - } else {/* Add stream for any updated/enabled CRTC */ - /* - * Quick fix to prevent NULL pointer on new_stream when - * added MST connectors not found in existing crtc_state in the chained mode - * TODO: need to dig out the root cause of that - */ - if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port)) - goto next_crtc; + *lock_and_validation_needed = true; - if (modereset_required(new_crtc_state)) - goto next_crtc; + } else {/* Add stream for any updated/enabled CRTC */ + /* + * Quick fix to prevent NULL pointer on new_stream when + * added MST connectors not found in existing crtc_state in the chained mode + * TODO: need to dig out the root cause of that + */ + if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port)) + goto skip_modeset; - if (modeset_required(new_crtc_state, new_stream, - dm_old_crtc_state->stream)) { + if (modereset_required(new_crtc_state)) + goto skip_modeset; - WARN_ON(dm_new_crtc_state->stream); + if (modeset_required(new_crtc_state, new_stream, + dm_old_crtc_state->stream)) { - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - goto fail; + WARN_ON(dm_new_crtc_state->stream); - dm_new_crtc_state->stream = new_stream; + ret = dm_atomic_get_state(state, &dm_state); + if (ret) + goto fail; - dc_stream_retain(new_stream); + dm_new_crtc_state->stream = new_stream; - DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n", - crtc->base.id); + dc_stream_retain(new_stream); - if (dc_add_stream_to_ctx( - dm->dc, - dm_state->context, - dm_new_crtc_state->stream) != DC_OK) { - ret = -EINVAL; - goto fail; - } + DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n", + crtc->base.id); - *lock_and_validation_needed = true; + if (dc_add_stream_to_ctx( + dm->dc, + dm_state->context, + dm_new_crtc_state->stream) != DC_OK) { + ret = -EINVAL; + goto fail; } - } -next_crtc: - /* Release extra reference */ - if (new_stream) - dc_stream_release(new_stream); + *lock_and_validation_needed = true; + } + } - /* - * We want to do dc stream updates that do not require a - * full modeset below. - */ - if (!(enable && aconnector && new_crtc_state->enable && - new_crtc_state->active)) - continue; - /* - * Given above conditions, the dc state cannot be NULL because: - * 1. We're in the process of enabling CRTCs (just been added - * to the dc context, or already is on the context) - * 2. Has a valid connector attached, and - * 3. Is currently active and enabled. - * => The dc stream state currently exists. - */ - BUG_ON(dm_new_crtc_state->stream == NULL); +skip_modeset: + /* Release extra reference */ + if (new_stream) + dc_stream_release(new_stream); - /* Scaling or underscan settings */ - if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state)) - update_stream_scaling_settings( - &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); + /* + * We want to do dc stream updates that do not require a + * full modeset below. + */ + if (!(enable && aconnector && new_crtc_state->enable && + new_crtc_state->active)) + return 0; + /* + * Given above conditions, the dc state cannot be NULL because: + * 1. We're in the process of enabling CRTCs (just been added + * to the dc context, or already is on the context) + * 2. Has a valid connector attached, and + * 3. Is currently active and enabled. + * => The dc stream state currently exists. + */ + BUG_ON(dm_new_crtc_state->stream == NULL); - /* - * Color management settings. We also update color properties - * when a modeset is needed, to ensure it gets reprogrammed. - */ - if (dm_new_crtc_state->base.color_mgmt_changed || - drm_atomic_crtc_needs_modeset(new_crtc_state)) { - ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state); - if (ret) - goto fail; - amdgpu_dm_set_ctm(dm_new_crtc_state); - } + /* Scaling or underscan settings */ + if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state)) + update_stream_scaling_settings( + &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); - /* Update Freesync settings. */ - get_freesync_config_for_crtc(dm_new_crtc_state, - dm_new_conn_state); + /* + * Color management settings. We also update color properties + * when a modeset is needed, to ensure it gets reprogrammed. + */ + if (dm_new_crtc_state->base.color_mgmt_changed || + drm_atomic_crtc_needs_modeset(new_crtc_state)) { + ret = amdgpu_dm_set_regamma_lut(dm_new_crtc_state); + if (ret) + goto fail; + amdgpu_dm_set_ctm(dm_new_crtc_state); } + /* Update Freesync settings. */ + get_freesync_config_for_crtc(dm_new_crtc_state, + dm_new_conn_state); + return ret; fail: @@ -5607,145 +5606,141 @@ fail: return ret; } -static int dm_update_planes_state(struct dc *dc, - struct drm_atomic_state *state, - bool enable, - bool *lock_and_validation_needed) +static int dm_update_plane_state(struct dc *dc, + struct drm_atomic_state *state, + struct drm_plane *plane, + struct drm_plane_state *old_plane_state, + struct drm_plane_state *new_plane_state, + bool enable, + bool *lock_and_validation_needed) { struct dm_atomic_state *dm_state = NULL; struct drm_crtc *new_plane_crtc, *old_plane_crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; - struct drm_plane *plane; - struct drm_plane_state *old_plane_state, *new_plane_state; struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state; struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state; - int i ; /* TODO return page_flip_needed() function */ bool pflip_needed = !state->allow_modeset; int ret = 0; - /* Add new planes, in reverse order as DC expectation */ - for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { - new_plane_crtc = new_plane_state->crtc; - old_plane_crtc = old_plane_state->crtc; - dm_new_plane_state = to_dm_plane_state(new_plane_state); - dm_old_plane_state = to_dm_plane_state(old_plane_state); + new_plane_crtc = new_plane_state->crtc; + old_plane_crtc = old_plane_state->crtc; + dm_new_plane_state = to_dm_plane_state(new_plane_state); + dm_old_plane_state = to_dm_plane_state(old_plane_state); - /*TODO Implement atomic check for cursor plane */ - if (plane->type == DRM_PLANE_TYPE_CURSOR) - continue; + /*TODO Implement atomic check for cursor plane */ + if (plane->type == DRM_PLANE_TYPE_CURSOR) + return 0; - /* Remove any changed/removed planes */ - if (!enable) { - if (pflip_needed && - plane->type != DRM_PLANE_TYPE_OVERLAY) - continue; + /* Remove any changed/removed planes */ + if (!enable) { + if (pflip_needed && + plane->type != DRM_PLANE_TYPE_OVERLAY) + return 0; - if (!old_plane_crtc) - continue; + if (!old_plane_crtc) + return 0; - old_crtc_state = drm_atomic_get_old_crtc_state( - state, old_plane_crtc); - dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + old_crtc_state = drm_atomic_get_old_crtc_state( + state, old_plane_crtc); + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - if (!dm_old_crtc_state->stream) - continue; + if (!dm_old_crtc_state->stream) + return 0; - DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n", - plane->base.id, old_plane_crtc->base.id); + DRM_DEBUG_ATOMIC("Disabling DRM plane: %d on DRM crtc %d\n", + plane->base.id, old_plane_crtc->base.id); - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - return ret; + ret = dm_atomic_get_state(state, &dm_state); + if (ret) + return ret; - if (!dc_remove_plane_from_context( - dc, - dm_old_crtc_state->stream, - dm_old_plane_state->dc_state, - dm_state->context)) { + if (!dc_remove_plane_from_context( + dc, + dm_old_crtc_state->stream, + dm_old_plane_state->dc_state, + dm_state->context)) { - ret = EINVAL; - return ret; - } + ret = EINVAL; + return ret; + } - dc_plane_state_release(dm_old_plane_state->dc_state); - dm_new_plane_state->dc_state = NULL; + dc_plane_state_release(dm_old_plane_state->dc_state); + dm_new_plane_state->dc_state = NULL; - *lock_and_validation_needed = true; + *lock_and_validation_needed = true; - } else { /* Add new planes */ - struct dc_plane_state *dc_new_plane_state; + } else { /* Add new planes */ + struct dc_plane_state *dc_new_plane_state; - if (drm_atomic_plane_disabling(plane->state, new_plane_state)) - continue; + if (drm_atomic_plane_disabling(plane->state, new_plane_state)) + return 0; - if (!new_plane_crtc) - continue; + if (!new_plane_crtc) + return 0; - new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc); - dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_crtc); + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); - if (!dm_new_crtc_state->stream) - continue; + if (!dm_new_crtc_state->stream) + return 0; - if (pflip_needed && - plane->type != DRM_PLANE_TYPE_OVERLAY) - continue; + if (pflip_needed && plane->type != DRM_PLANE_TYPE_OVERLAY) + return 0; - WARN_ON(dm_new_plane_state->dc_state); + WARN_ON(dm_new_plane_state->dc_state); - dc_new_plane_state = dc_create_plane_state(dc); - if (!dc_new_plane_state) - return -ENOMEM; + dc_new_plane_state = dc_create_plane_state(dc); + if (!dc_new_plane_state) + return -ENOMEM; - DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", - plane->base.id, new_plane_crtc->base.id); + DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n", + plane->base.id, new_plane_crtc->base.id); - ret = fill_plane_attributes( - new_plane_crtc->dev->dev_private, - dc_new_plane_state, - new_plane_state, - new_crtc_state); - if (ret) { - dc_plane_state_release(dc_new_plane_state); - return ret; - } + ret = fill_plane_attributes( + new_plane_crtc->dev->dev_private, + dc_new_plane_state, + new_plane_state, + new_crtc_state); + if (ret) { + dc_plane_state_release(dc_new_plane_state); + return ret; + } - ret = dm_atomic_get_state(state, &dm_state); - if (ret) { - dc_plane_state_release(dc_new_plane_state); - return ret; - } + ret = dm_atomic_get_state(state, &dm_state); + if (ret) { + dc_plane_state_release(dc_new_plane_state); + return ret; + } - /* - * Any atomic check errors that occur after this will - * not need a release. The plane state will be attached - * to the stream, and therefore part of the atomic - * state. It'll be released when the atomic state is - * cleaned. - */ - if (!dc_add_plane_to_context( - dc, - dm_new_crtc_state->stream, - dc_new_plane_state, - dm_state->context)) { - - dc_plane_state_release(dc_new_plane_state); - return -EINVAL; - } + /* + * Any atomic check errors that occur after this will + * not need a release. The plane state will be attached + * to the stream, and therefore part of the atomic + * state. It'll be released when the atomic state is + * cleaned. + */ + if (!dc_add_plane_to_context( + dc, + dm_new_crtc_state->stream, + dc_new_plane_state, + dm_state->context)) { - dm_new_plane_state->dc_state = dc_new_plane_state; + dc_plane_state_release(dc_new_plane_state); + return -EINVAL; + } - /* Tell DC to do a full surface update every time there - * is a plane change. Inefficient, but works for now. - */ - dm_new_plane_state->dc_state->update_flags.bits.full_update = 1; + dm_new_plane_state->dc_state = dc_new_plane_state; - *lock_and_validation_needed = true; - } + /* Tell DC to do a full surface update every time there + * is a plane change. Inefficient, but works for now. + */ + dm_new_plane_state->dc_state->update_flags.bits.full_update = 1; + + *lock_and_validation_needed = true; } @@ -5769,11 +5764,13 @@ dm_determine_update_type_for_commit(struct dc *dc, struct dm_crtc_state *new_dm_crtc_state, *old_dm_crtc_state; struct dc_stream_status *status = NULL; - struct dc_surface_update *updates = kzalloc(MAX_SURFACES * sizeof(struct dc_surface_update), GFP_KERNEL); - struct dc_plane_state *surface = kzalloc(MAX_SURFACES * sizeof(struct dc_plane_state), GFP_KERNEL); - struct dc_stream_update stream_update; + struct dc_surface_update *updates; + struct dc_plane_state *surface; enum surface_update_type update_type = UPDATE_TYPE_FAST; + updates = kcalloc(MAX_SURFACES, sizeof(*updates), GFP_KERNEL); + surface = kcalloc(MAX_SURFACES, sizeof(*surface), GFP_KERNEL); + if (!updates || !surface) { DRM_ERROR("Plane or surface update failed to allocate"); /* Set type to FULL to avoid crashing in DC*/ @@ -5782,79 +5779,85 @@ dm_determine_update_type_for_commit(struct dc *dc, } for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct dc_stream_update stream_update = { 0 }; + new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); old_dm_crtc_state = to_dm_crtc_state(old_crtc_state); num_plane = 0; - if (new_dm_crtc_state->stream) { - - for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { - new_plane_crtc = new_plane_state->crtc; - old_plane_crtc = old_plane_state->crtc; - new_dm_plane_state = to_dm_plane_state(new_plane_state); - old_dm_plane_state = to_dm_plane_state(old_plane_state); - - if (plane->type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (!state->allow_modeset) - continue; - - if (crtc == new_plane_crtc) { - updates[num_plane].surface = &surface[num_plane]; - - if (new_crtc_state->mode_changed) { - updates[num_plane].surface->src_rect = - new_dm_plane_state->dc_state->src_rect; - updates[num_plane].surface->dst_rect = - new_dm_plane_state->dc_state->dst_rect; - updates[num_plane].surface->rotation = - new_dm_plane_state->dc_state->rotation; - updates[num_plane].surface->in_transfer_func = - new_dm_plane_state->dc_state->in_transfer_func; - stream_update.dst = new_dm_crtc_state->stream->dst; - stream_update.src = new_dm_crtc_state->stream->src; - } - - if (new_crtc_state->color_mgmt_changed) { - updates[num_plane].gamma = - new_dm_plane_state->dc_state->gamma_correction; - updates[num_plane].in_transfer_func = - new_dm_plane_state->dc_state->in_transfer_func; - stream_update.gamut_remap = - &new_dm_crtc_state->stream->gamut_remap_matrix; - stream_update.out_transfer_func = - new_dm_crtc_state->stream->out_transfer_func; - } - - num_plane++; - } + if (!new_dm_crtc_state->stream) { + if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) { + update_type = UPDATE_TYPE_FULL; + goto cleanup; } - if (num_plane > 0) { - ret = dm_atomic_get_state(state, &dm_state); - if (ret) - goto cleanup; + continue; + } - old_dm_state = dm_atomic_get_old_state(state); - if (!old_dm_state) { - ret = -EINVAL; - goto cleanup; - } + for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { + new_plane_crtc = new_plane_state->crtc; + old_plane_crtc = old_plane_state->crtc; + new_dm_plane_state = to_dm_plane_state(new_plane_state); + old_dm_plane_state = to_dm_plane_state(old_plane_state); - status = dc_state_get_stream_status(old_dm_state->context, - new_dm_crtc_state->stream); + if (plane->type == DRM_PLANE_TYPE_CURSOR) + continue; - update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane, - &stream_update, status); + if (!state->allow_modeset) + continue; - if (update_type > UPDATE_TYPE_MED) { - update_type = UPDATE_TYPE_FULL; - goto cleanup; - } + if (crtc != new_plane_crtc) + continue; + + updates[num_plane].surface = &surface[num_plane]; + + if (new_crtc_state->mode_changed) { + updates[num_plane].surface->src_rect = + new_dm_plane_state->dc_state->src_rect; + updates[num_plane].surface->dst_rect = + new_dm_plane_state->dc_state->dst_rect; + updates[num_plane].surface->rotation = + new_dm_plane_state->dc_state->rotation; + updates[num_plane].surface->in_transfer_func = + new_dm_plane_state->dc_state->in_transfer_func; + stream_update.dst = new_dm_crtc_state->stream->dst; + stream_update.src = new_dm_crtc_state->stream->src; } - } else if (!new_dm_crtc_state->stream && old_dm_crtc_state->stream) { + if (new_crtc_state->color_mgmt_changed) { + updates[num_plane].gamma = + new_dm_plane_state->dc_state->gamma_correction; + updates[num_plane].in_transfer_func = + new_dm_plane_state->dc_state->in_transfer_func; + stream_update.gamut_remap = + &new_dm_crtc_state->stream->gamut_remap_matrix; + stream_update.out_transfer_func = + new_dm_crtc_state->stream->out_transfer_func; + } + + num_plane++; + } + + if (num_plane == 0) + continue; + + ret = dm_atomic_get_state(state, &dm_state); + if (ret) + goto cleanup; + + old_dm_state = dm_atomic_get_old_state(state); + if (!old_dm_state) { + ret = -EINVAL; + goto cleanup; + } + + status = dc_stream_get_status_from_state(old_dm_state->context, + new_dm_crtc_state->stream); + + update_type = dc_check_update_surfaces_for_stream(dc, updates, num_plane, + &stream_update, status); + + if (update_type > UPDATE_TYPE_MED) { update_type = UPDATE_TYPE_FULL; goto cleanup; } @@ -5903,6 +5906,8 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_connector_state *old_con_state, *new_con_state; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; + struct drm_plane *plane; + struct drm_plane_state *old_plane_state, *new_plane_state; enum surface_update_type update_type = UPDATE_TYPE_FAST; enum surface_update_type overall_update_type = UPDATE_TYPE_FAST; @@ -5921,7 +5926,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && !new_crtc_state->color_mgmt_changed && - !new_crtc_state->vrr_enabled) + old_crtc_state->vrr_enabled == new_crtc_state->vrr_enabled) continue; if (!new_crtc_state->enable) @@ -5937,27 +5942,47 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, } /* Remove exiting planes if they are modified */ - ret = dm_update_planes_state(dc, state, false, &lock_and_validation_needed); - if (ret) { - goto fail; + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { + ret = dm_update_plane_state(dc, state, plane, + old_plane_state, + new_plane_state, + false, + &lock_and_validation_needed); + if (ret) + goto fail; } /* Disable all crtcs which require disable */ - ret = dm_update_crtcs_state(&adev->dm, state, false, &lock_and_validation_needed); - if (ret) { - goto fail; + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + ret = dm_update_crtc_state(&adev->dm, state, crtc, + old_crtc_state, + new_crtc_state, + false, + &lock_and_validation_needed); + if (ret) + goto fail; } /* Enable all crtcs which require enable */ - ret = dm_update_crtcs_state(&adev->dm, state, true, &lock_and_validation_needed); - if (ret) { - goto fail; + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + ret = dm_update_crtc_state(&adev->dm, state, crtc, + old_crtc_state, + new_crtc_state, + true, + &lock_and_validation_needed); + if (ret) + goto fail; } /* Add new/modified planes */ - ret = dm_update_planes_state(dc, state, true, &lock_and_validation_needed); - if (ret) { - goto fail; + for_each_oldnew_plane_in_state_reverse(state, plane, old_plane_state, new_plane_state, i) { + ret = dm_update_plane_state(dc, state, plane, + old_plane_state, + new_plane_state, + true, + &lock_and_validation_needed); + if (ret) + goto fail; } /* Run this here since we want to validate the streams we created */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index f088ac585978..a10e3a50d9ef 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -64,8 +64,10 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) { + struct amdgpu_device *adev = crtc->dev->dev_private; struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); struct dc_stream_state *stream_state = crtc_state->stream; + bool enable; enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); @@ -80,29 +82,33 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) return -EINVAL; } - /* When enabling CRC, we should also disable dithering. */ - if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) { - if (dc_stream_configure_crc(stream_state->ctx->dc, - stream_state, - true, true)) { - crtc_state->crc_enabled = true; - dc_stream_set_dither_option(stream_state, - DITHER_OPTION_TRUN8); - } - else - return -EINVAL; - } else { - if (dc_stream_configure_crc(stream_state->ctx->dc, - stream_state, - false, false)) { - crtc_state->crc_enabled = false; - dc_stream_set_dither_option(stream_state, - DITHER_OPTION_DEFAULT); - } - else - return -EINVAL; + enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO); + + mutex_lock(&adev->dm.dc_lock); + if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state, + enable, enable)) { + mutex_unlock(&adev->dm.dc_lock); + return -EINVAL; } + /* When enabling CRC, we should also disable dithering. */ + dc_stream_set_dither_option(stream_state, + enable ? DITHER_OPTION_TRUN8 + : DITHER_OPTION_DEFAULT); + + mutex_unlock(&adev->dm.dc_lock); + + /* + * Reading the CRC requires the vblank interrupt handler to be + * enabled. Keep a reference until CRC capture stops. + */ + if (!crtc_state->crc_enabled && enable) + drm_crtc_vblank_get(crtc); + else if (crtc_state->crc_enabled && !enable) + drm_crtc_vblank_put(crtc); + + crtc_state->crc_enabled = enable; + /* Reset crc_skipped on dm state */ crtc_state->crc_skip_count = 0; return 0; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 9a7ac58eb18e..cca3e16cda4f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -783,6 +783,45 @@ static ssize_t dtn_log_write( return size; } +/* + * Backlight at this moment. Read only. + * As written to display, taking ABM and backlight lut into account. + * Ranges from 0x0 to 0x10000 (= 100% PWM) + */ +static int current_backlight_read(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct amdgpu_device *adev = dev->dev_private; + struct dc *dc = adev->dm.dc; + unsigned int backlight = dc_get_current_backlight_pwm(dc); + + seq_printf(m, "0x%x\n", backlight); + return 0; +} + +/* + * Backlight value that is being approached. Read only. + * As written to display, taking ABM and backlight lut into account. + * Ranges from 0x0 to 0x10000 (= 100% PWM) + */ +static int target_backlight_read(struct seq_file *m, void *data) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct amdgpu_device *adev = dev->dev_private; + struct dc *dc = adev->dm.dc; + unsigned int backlight = dc_get_target_backlight_pwm(dc); + + seq_printf(m, "0x%x\n", backlight); + return 0; +} + +static const struct drm_info_list amdgpu_dm_debugfs_list[] = { + {"amdgpu_current_backlight_pwm", ¤t_backlight_read}, + {"amdgpu_target_backlight_pwm", &target_backlight_read}, +}; + int dtn_debugfs_init(struct amdgpu_device *adev) { static const struct file_operations dtn_log_fops = { @@ -793,9 +832,15 @@ int dtn_debugfs_init(struct amdgpu_device *adev) }; struct drm_minor *minor = adev->ddev->primary; - struct dentry *root = minor->debugfs_root; + struct dentry *ent, *root = minor->debugfs_root; + int ret; + + ret = amdgpu_debugfs_add_files(adev, amdgpu_dm_debugfs_list, + ARRAY_SIZE(amdgpu_dm_debugfs_list)); + if (ret) + return ret; - struct dentry *ent = debugfs_create_file( + ent = debugfs_create_file( "amdgpu_dm_dtn_log", 0644, root, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index 78173311f718..b39766bd2840 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -192,7 +192,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( int bpp = 0; int pbn = 0; - aconnector = stream->sink->priv; + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; if (!aconnector || !aconnector->mst_port) return false; @@ -205,7 +205,7 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( mst_port = aconnector->port; if (enable) { - clock = stream->timing.pix_clk_khz; + clock = stream->timing.pix_clk_100hz / 10; switch (stream->timing.display_color_depth) { @@ -263,6 +263,13 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( return true; } +/* + * poll pending down reply before clear payload allocation table + */ +void dm_helpers_dp_mst_poll_pending_down_reply( + struct dc_context *ctx, + const struct dc_link *link) +{} /* * Clear payload allocation table before enable MST DP link. @@ -284,7 +291,7 @@ bool dm_helpers_dp_mst_poll_for_allocation_change_trigger( struct drm_dp_mst_topology_mgr *mst_mgr; int ret; - aconnector = stream->sink->priv; + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; if (!aconnector || !aconnector->mst_port) return false; @@ -312,7 +319,7 @@ bool dm_helpers_dp_mst_send_payload_allocation( struct drm_dp_mst_port *mst_port; int ret; - aconnector = stream->sink->priv; + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; if (!aconnector || !aconnector->mst_port) return false; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 24632727e127..f51d52eb52e6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -35,6 +35,8 @@ #include "dc_link_ddc.h" +#include "i2caux_interface.h" + /* #define TRACE_DPCD */ #ifdef TRACE_DPCD @@ -81,80 +83,24 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { ssize_t result = 0; - enum i2caux_transaction_action action; - enum aux_transaction_type type; + struct aux_payload payload; if (WARN_ON(msg->size > 16)) return -E2BIG; - switch (msg->request & ~DP_AUX_I2C_MOT) { - case DP_AUX_NATIVE_READ: - type = AUX_TRANSACTION_TYPE_DP; - action = I2CAUX_TRANSACTION_ACTION_DP_READ; - - result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, - msg->address, - &msg->reply, - msg->buffer, - msg->size, - type, - action); - break; - case DP_AUX_NATIVE_WRITE: - type = AUX_TRANSACTION_TYPE_DP; - action = I2CAUX_TRANSACTION_ACTION_DP_WRITE; - - dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, - msg->address, - &msg->reply, - msg->buffer, - msg->size, - type, - action); - result = msg->size; - break; - case DP_AUX_I2C_READ: - type = AUX_TRANSACTION_TYPE_I2C; - if (msg->request & DP_AUX_I2C_MOT) - action = I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; - else - action = I2CAUX_TRANSACTION_ACTION_I2C_READ; - - result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, - msg->address, - &msg->reply, - msg->buffer, - msg->size, - type, - action); - break; - case DP_AUX_I2C_WRITE: - type = AUX_TRANSACTION_TYPE_I2C; - if (msg->request & DP_AUX_I2C_MOT) - action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; - else - action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - - dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, - msg->address, - &msg->reply, - msg->buffer, - msg->size, - type, - action); - result = msg->size; - break; - default: - return -EINVAL; - } + payload.address = msg->address; + payload.data = msg->buffer; + payload.length = msg->size; + payload.reply = &msg->reply; + payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0; + payload.write = (msg->request & DP_AUX_I2C_READ) == 0; + payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0; + payload.defer_delay = 0; -#ifdef TRACE_DPCD - log_dpcd(msg->request, - msg->address, - msg->buffer, - msg->size, - r == DDC_RESULT_SUCESSFULL); -#endif + result = dc_link_aux_transfer(TO_DM_AUX(aux)->ddc_service, &payload); + + if (payload.write) + result = msg->size; if (result < 0) /* DC doesn't know about kernel error codes */ result = -EIO; @@ -228,6 +174,11 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) aconnector->edid = edid; } + if (aconnector->dc_sink && aconnector->dc_sink->sink_signal == SIGNAL_TYPE_VIRTUAL) { + dc_sink_release(aconnector->dc_sink); + aconnector->dc_sink = NULL; + } + if (!aconnector->dc_sink) { struct dc_sink *dc_sink; struct dc_sink_init_data init_params = { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 7ef99037167a..a114954d6a5b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -559,6 +559,58 @@ void pp_rv_set_pme_wa_enable(struct pp_smu *pp) pp_funcs->notify_smu_enable_pwe(pp_handle); } +void pp_rv_set_active_display_count(struct pp_smu *pp, int count) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->set_active_display_count) + return; + + pp_funcs->set_active_display_count(pp_handle, count); +} + +void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->set_min_deep_sleep_dcefclk) + return; + + pp_funcs->set_min_deep_sleep_dcefclk(pp_handle, clock); +} + +void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->set_hard_min_dcefclk_by_freq) + return; + + pp_funcs->set_hard_min_dcefclk_by_freq(pp_handle, clock); +} + +void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs || !pp_funcs->set_hard_min_fclk_by_freq) + return; + + pp_funcs->set_hard_min_fclk_by_freq(pp_handle, mhz); +} + void dm_pp_get_funcs_rv( struct dc_context *ctx, struct pp_smu_funcs_rv *funcs) @@ -567,4 +619,9 @@ void dm_pp_get_funcs_rv( funcs->set_display_requirement = pp_rv_set_display_requirement; funcs->set_wm_ranges = pp_rv_set_wm_ranges; funcs->set_pme_wa_enable = pp_rv_set_pme_wa_enable; + funcs->set_display_count = pp_rv_set_active_display_count; + funcs->set_min_deep_sleep_dcfclk = pp_rv_set_min_deep_sleep_dcfclk; + funcs->set_hard_min_dcfclk_by_freq = pp_rv_set_hard_min_dcefclk_by_freq; + funcs->set_hard_min_fclk_by_freq = pp_rv_set_hard_min_fclk_by_freq; } + diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index aed538a4d1ba..b8ddb4acccdb 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -23,7 +23,7 @@ # Makefile for Display Core (dc) component. # -DC_LIBS = basics bios calcs dce gpio i2caux irq virtual +DC_LIBS = basics bios calcs dce gpio irq virtual ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml @@ -41,7 +41,8 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI include $(AMD_DC) DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \ -dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o +dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \ +dc_vm_helper.o AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE)) diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index c2ab026aee91..a4c97d32e751 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -835,18 +835,6 @@ static enum bp_result bios_parser_enable_crtc( return bp->cmd_tbl.enable_crtc(bp, id, enable); } -static enum bp_result bios_parser_crtc_source_select( - struct dc_bios *dcb, - struct bp_crtc_source_select *bp_params) -{ - struct bios_parser *bp = BP_FROM_DCB(dcb); - - if (!bp->cmd_tbl.select_crtc_source) - return BP_RESULT_FAILURE; - - return bp->cmd_tbl.select_crtc_source(bp, bp_params); -} - static enum bp_result bios_parser_enable_disp_power_gating( struct dc_bios *dcb, enum controller_id controller_id, @@ -2842,8 +2830,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .program_crtc_timing = bios_parser_program_crtc_timing, /* still use. should probably retire and program directly */ - .crtc_source_select = bios_parser_crtc_source_select, /* still use. should probably retire and program directly */ - .program_display_engine_pll = bios_parser_program_display_engine_pll, .enable_disp_power_gating = bios_parser_enable_disp_power_gating, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c index c513ab6f3843..a1c56f29cfeb 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1083,18 +1083,6 @@ static enum bp_result bios_parser_enable_crtc( return bp->cmd_tbl.enable_crtc(bp, id, enable); } -static enum bp_result bios_parser_crtc_source_select( - struct dc_bios *dcb, - struct bp_crtc_source_select *bp_params) -{ - struct bios_parser *bp = BP_FROM_DCB(dcb); - - if (!bp->cmd_tbl.select_crtc_source) - return BP_RESULT_FAILURE; - - return bp->cmd_tbl.select_crtc_source(bp, bp_params); -} - static enum bp_result bios_parser_enable_disp_power_gating( struct dc_bios *dcb, enum controller_id controller_id, @@ -1899,8 +1887,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .is_accelerated_mode = bios_parser_is_accelerated_mode, - .is_active_display = bios_is_active_display, - .set_scratch_critical_state = bios_parser_set_scratch_critical_state, @@ -1917,8 +1903,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .program_crtc_timing = bios_parser_program_crtc_timing, - .crtc_source_select = bios_parser_crtc_source_select, - .enable_disp_power_gating = bios_parser_enable_disp_power_gating, .bios_parser_destroy = firmware_parser_destroy, diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c index fdda8aa8e303..fce46ab54c54 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c @@ -83,101 +83,7 @@ uint32_t bios_get_vga_enabled_displays( { uint32_t active_disp = 1; - if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/ - active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF; + active_disp = REG_READ(BIOS_SCRATCH_3) & 0XFFFF; return active_disp; } -bool bios_is_active_display( - struct dc_bios *bios, - enum signal_type signal, - const struct connector_device_tag_info *device_tag) -{ - uint32_t active = 0; - uint32_t connected = 0; - uint32_t bios_scratch_0 = 0; - uint32_t bios_scratch_3 = 0; - - switch (signal) { - case SIGNAL_TYPE_DVI_SINGLE_LINK: - case SIGNAL_TYPE_DVI_DUAL_LINK: - case SIGNAL_TYPE_HDMI_TYPE_A: - case SIGNAL_TYPE_DISPLAY_PORT: - case SIGNAL_TYPE_DISPLAY_PORT_MST: - { - if (device_tag->dev_id.device_type == DEVICE_TYPE_DFP) { - switch (device_tag->dev_id.enum_id) { - case 1: - { - active = ATOM_S3_DFP1_ACTIVE; - connected = 0x0008; //ATOM_DISPLAY_DFP1_CONNECT - } - break; - - case 2: - { - active = ATOM_S3_DFP2_ACTIVE; - connected = 0x0080; //ATOM_DISPLAY_DFP2_CONNECT - } - break; - - case 3: - { - active = ATOM_S3_DFP3_ACTIVE; - connected = 0x0200; //ATOM_DISPLAY_DFP3_CONNECT - } - break; - - case 4: - { - active = ATOM_S3_DFP4_ACTIVE; - connected = 0x0400; //ATOM_DISPLAY_DFP4_CONNECT - } - break; - - case 5: - { - active = ATOM_S3_DFP5_ACTIVE; - connected = 0x0800; //ATOM_DISPLAY_DFP5_CONNECT - } - break; - - case 6: - { - active = ATOM_S3_DFP6_ACTIVE; - connected = 0x0040; //ATOM_DISPLAY_DFP6_CONNECT - } - break; - - default: - break; - } - } - } - break; - - case SIGNAL_TYPE_LVDS: - case SIGNAL_TYPE_EDP: - { - active = ATOM_S3_LCD1_ACTIVE; - connected = 0x0002; //ATOM_DISPLAY_LCD1_CONNECT - } - break; - - default: - break; - } - - - if (bios->regs->BIOS_SCRATCH_0) /*follow up with other asic, todo*/ - bios_scratch_0 = REG_READ(BIOS_SCRATCH_0); - if (bios->regs->BIOS_SCRATCH_3) /*follow up with other asic, todo*/ - bios_scratch_3 = REG_READ(BIOS_SCRATCH_3); - - bios_scratch_3 &= ATOM_S3_DEVICE_ACTIVE_MASK; - if ((active & bios_scratch_3) && (connected & bios_scratch_0)) - return true; - - return false; -} - diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h index f33cac2147e3..75a29e68fb27 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h @@ -35,10 +35,6 @@ bool bios_is_accelerated_mode(struct dc_bios *bios); void bios_set_scratch_acc_mode_change(struct dc_bios *bios); void bios_set_scratch_critical_state(struct dc_bios *bios, bool state); uint32_t bios_get_vga_enabled_displays(struct dc_bios *bios); -bool bios_is_active_display( - struct dc_bios *bios, - enum signal_type signal, - const struct connector_device_tag_info *device_tag); #define GET_IMAGE(type, offset) ((type *) bios_get_image(&bp->base, offset, sizeof(type))) diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c index 2bd7cd97e00d..5815983caaf8 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c @@ -55,7 +55,6 @@ static void init_adjust_display_pll(struct bios_parser *bp); static void init_dac_encoder_control(struct bios_parser *bp); static void init_dac_output_control(struct bios_parser *bp); static void init_set_crtc_timing(struct bios_parser *bp); -static void init_select_crtc_source(struct bios_parser *bp); static void init_enable_crtc(struct bios_parser *bp); static void init_enable_crtc_mem_req(struct bios_parser *bp); static void init_external_encoder_control(struct bios_parser *bp); @@ -73,7 +72,6 @@ void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp) init_dac_encoder_control(bp); init_dac_output_control(bp); init_set_crtc_timing(bp); - init_select_crtc_source(bp); init_enable_crtc(bp); init_enable_crtc_mem_req(bp); init_program_clock(bp); @@ -964,9 +962,9 @@ static enum bp_result set_pixel_clock_v3( allocation.sPCLKInput.ucPostDiv = (uint8_t)bp_params->pixel_clock_post_divider; - /* We need to convert from KHz units into 10KHz units */ + /* We need to convert from 100Hz units into 10KHz units */ allocation.sPCLKInput.usPixelClock = - cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10)); + cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100)); params = (PIXEL_CLOCK_PARAMETERS_V3 *)&allocation.sPCLKInput; params->ucTransmitterId = @@ -1042,9 +1040,9 @@ static enum bp_result set_pixel_clock_v5( (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( bp_params->signal_type, false); - /* We need to convert from KHz units into 10KHz units */ + /* We need to convert from 100Hz units into 10KHz units */ clk.sPCLKInput.usPixelClock = - cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10)); + cpu_to_le16((uint16_t)(bp_params->target_pixel_clock_100hz / 100)); if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) clk.sPCLKInput.ucMiscInfo |= @@ -1118,9 +1116,9 @@ static enum bp_result set_pixel_clock_v6( (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom( bp_params->signal_type, false); - /* We need to convert from KHz units into 10KHz units */ + /* We need to convert from 100 Hz units into 10KHz units */ clk.sPCLKInput.ulCrtcPclkFreq.ulPixelClock = - cpu_to_le32(bp_params->target_pixel_clock / 10); + cpu_to_le32(bp_params->target_pixel_clock_100hz / 100); if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) { clk.sPCLKInput.ucMiscInfo |= @@ -1182,8 +1180,7 @@ static enum bp_result set_pixel_clock_v7( clk.ucTransmitterID = bp->cmd_helper->encoder_id_to_atom(dal_graphics_object_id_get_encoder_id(bp_params->encoder_object_id)); clk.ucEncoderMode = (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom(bp_params->signal_type, false); - /* We need to convert from KHz units into 10KHz units */ - clk.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock * 10); + clk.ulPixelClock = cpu_to_le32(bp_params->target_pixel_clock_100hz); clk.ucDeepColorRatio = (uint8_t) bp->cmd_helper->transmitter_color_depth_to_atom(bp_params->color_depth); @@ -1899,120 +1896,6 @@ static enum bp_result set_crtc_using_dtd_timing_v3( /******************************************************************************* ******************************************************************************** ** - ** SELECT CRTC SOURCE - ** - ******************************************************************************** - *******************************************************************************/ - -static enum bp_result select_crtc_source_v2( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params); -static enum bp_result select_crtc_source_v3( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params); - -static void init_select_crtc_source(struct bios_parser *bp) -{ - switch (BIOS_CMD_TABLE_PARA_REVISION(SelectCRTC_Source)) { - case 2: - bp->cmd_tbl.select_crtc_source = select_crtc_source_v2; - break; - case 3: - bp->cmd_tbl.select_crtc_source = select_crtc_source_v3; - break; - default: - dm_output_to_console("Don't select_crtc_source enable_crtc for v%d\n", - BIOS_CMD_TABLE_PARA_REVISION(SelectCRTC_Source)); - bp->cmd_tbl.select_crtc_source = NULL; - break; - } -} - -static enum bp_result select_crtc_source_v2( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params) -{ - enum bp_result result = BP_RESULT_FAILURE; - SELECT_CRTC_SOURCE_PARAMETERS_V2 params; - uint8_t atom_controller_id; - uint32_t atom_engine_id; - enum signal_type s = bp_params->signal; - - memset(¶ms, 0, sizeof(params)); - - /* set controller id */ - if (bp->cmd_helper->controller_id_to_atom( - bp_params->controller_id, &atom_controller_id)) - params.ucCRTC = atom_controller_id; - else - return BP_RESULT_FAILURE; - - /* set encoder id */ - if (bp->cmd_helper->engine_bp_to_atom( - bp_params->engine_id, &atom_engine_id)) - params.ucEncoderID = (uint8_t)atom_engine_id; - else - return BP_RESULT_FAILURE; - - if (SIGNAL_TYPE_EDP == s || - (SIGNAL_TYPE_DISPLAY_PORT == s && - SIGNAL_TYPE_LVDS == bp_params->sink_signal)) - s = SIGNAL_TYPE_LVDS; - - params.ucEncodeMode = - (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom( - s, bp_params->enable_dp_audio); - - if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params)) - result = BP_RESULT_OK; - - return result; -} - -static enum bp_result select_crtc_source_v3( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params) -{ - bool result = BP_RESULT_FAILURE; - SELECT_CRTC_SOURCE_PARAMETERS_V3 params; - uint8_t atom_controller_id; - uint32_t atom_engine_id; - enum signal_type s = bp_params->signal; - - memset(¶ms, 0, sizeof(params)); - - if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id, - &atom_controller_id)) - params.ucCRTC = atom_controller_id; - else - return result; - - if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id, - &atom_engine_id)) - params.ucEncoderID = (uint8_t)atom_engine_id; - else - return result; - - if (SIGNAL_TYPE_EDP == s || - (SIGNAL_TYPE_DISPLAY_PORT == s && - SIGNAL_TYPE_LVDS == bp_params->sink_signal)) - s = SIGNAL_TYPE_LVDS; - - params.ucEncodeMode = - bp->cmd_helper->encoder_mode_bp_to_atom( - s, bp_params->enable_dp_audio); - /* Needed for VBIOS Random Spatial Dithering feature */ - params.ucDstBpc = (uint8_t)(bp_params->display_output_bit_depth); - - if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params)) - result = BP_RESULT_OK; - - return result; -} - -/******************************************************************************* - ******************************************************************************** - ** ** ENABLE CRTC ** ******************************************************************************** @@ -2164,7 +2047,7 @@ static enum bp_result program_clock_v5( /* We need to convert from KHz units into 10KHz units */ params.sPCLKInput.ucPpll = (uint8_t) atom_pll_id; params.sPCLKInput.usPixelClock = - cpu_to_le16((uint16_t) (bp_params->target_pixel_clock / 10)); + cpu_to_le16((uint16_t) (bp_params->target_pixel_clock_100hz / 100)); params.sPCLKInput.ucCRTC = (uint8_t) ATOM_CRTC_INVALID; if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) @@ -2196,7 +2079,7 @@ static enum bp_result program_clock_v6( /* We need to convert from KHz units into 10KHz units */ params.sPCLKInput.ucPpll = (uint8_t)atom_pll_id; params.sPCLKInput.ulDispEngClkFreq = - cpu_to_le32(bp_params->target_pixel_clock / 10); + cpu_to_le32(bp_params->target_pixel_clock_100hz / 100); if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.h b/drivers/gpu/drm/amd/display/dc/bios/command_table.h index 94f3d43a7471..ad533775e724 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.h @@ -71,9 +71,6 @@ struct cmd_tbl { enum bp_result (*set_crtc_timing)( struct bios_parser *bp, struct bp_hw_crtc_timing_parameters *bp_params); - enum bp_result (*select_crtc_source)( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params); enum bp_result (*enable_crtc)( struct bios_parser *bp, enum controller_id controller_id, diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c index 2b5dc499a35e..bb2e8105e6ab 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -301,17 +301,17 @@ static enum bp_result set_pixel_clock_v7( cmd_helper->encoder_mode_bp_to_atom( bp_params->signal_type, false); - /* We need to convert from KHz units into 10KHz units */ - clk.pixclk_100hz = cpu_to_le32(bp_params->target_pixel_clock * - 10); + clk.pixclk_100hz = cpu_to_le32(bp_params->target_pixel_clock_100hz); clk.deep_color_ratio = (uint8_t) bp->cmd_helper-> transmitter_color_depth_to_atom( bp_params->color_depth); - DC_LOG_BIOS("%s:program display clock = %d"\ - "colorDepth = %d\n", __func__,\ - bp_params->target_pixel_clock, bp_params->color_depth); + + DC_LOG_BIOS("%s:program display clock = %d, tg = %d, pll = %d, "\ + "colorDepth = %d\n", __func__, + bp_params->target_pixel_clock_100hz, (int)controller_id, + pll_id, bp_params->color_depth); if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) clk.miscinfo |= PIXEL_CLOCK_V7_MISC_FORCE_PROG_PPLL; @@ -463,75 +463,6 @@ static enum bp_result set_crtc_using_dtd_timing_v3( /****************************************************************************** ****************************************************************************** ** - ** SELECT CRTC SOURCE - ** - ****************************************************************************** - *****************************************************************************/ - - -static enum bp_result select_crtc_source_v3( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params); - -static void init_select_crtc_source(struct bios_parser *bp) -{ - switch (BIOS_CMD_TABLE_PARA_REVISION(selectcrtc_source)) { - case 3: - bp->cmd_tbl.select_crtc_source = select_crtc_source_v3; - break; - default: - dm_output_to_console("Don't select_crtc_source enable_crtc for v%d\n", - BIOS_CMD_TABLE_PARA_REVISION(selectcrtc_source)); - bp->cmd_tbl.select_crtc_source = NULL; - break; - } -} - - -static enum bp_result select_crtc_source_v3( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params) -{ - bool result = BP_RESULT_FAILURE; - struct select_crtc_source_parameters_v2_3 params; - uint8_t atom_controller_id; - uint32_t atom_engine_id; - enum signal_type s = bp_params->signal; - - memset(¶ms, 0, sizeof(params)); - - if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id, - &atom_controller_id)) - params.crtc_id = atom_controller_id; - else - return result; - - if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id, - &atom_engine_id)) - params.encoder_id = (uint8_t)atom_engine_id; - else - return result; - - if (s == SIGNAL_TYPE_EDP || - (s == SIGNAL_TYPE_DISPLAY_PORT && bp_params->sink_signal == - SIGNAL_TYPE_LVDS)) - s = SIGNAL_TYPE_LVDS; - - params.encode_mode = - bp->cmd_helper->encoder_mode_bp_to_atom( - s, bp_params->enable_dp_audio); - /* Needed for VBIOS Random Spatial Dithering feature */ - params.dst_bpc = (uint8_t)(bp_params->display_output_bit_depth); - - if (EXEC_BIOS_CMD_TABLE(selectcrtc_source, params)) - result = BP_RESULT_OK; - - return result; -} - -/****************************************************************************** - ****************************************************************************** - ** ** ENABLE CRTC ** ****************************************************************************** @@ -808,7 +739,6 @@ void dal_firmware_parser_init_cmd_tbl(struct bios_parser *bp) init_set_crtc_timing(bp); - init_select_crtc_source(bp); init_enable_crtc(bp); init_external_encoder_control(bp); diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h index ec1c0c9f3f1d..7a2af24dfe60 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.h +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.h @@ -71,9 +71,6 @@ struct cmd_tbl { enum bp_result (*set_crtc_timing)( struct bios_parser *bp, struct bp_hw_crtc_timing_parameters *bp_params); - enum bp_result (*select_crtc_source)( - struct bios_parser *bp, - struct bp_crtc_source_select *bp_params); enum bp_result (*enable_crtc)( struct bios_parser *bp, enum controller_id controller_id, diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 9ebe30ba4dab..f3aa7b53d2aa 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -2792,7 +2792,7 @@ static void populate_initial_data( data->lpt_en[num_displays + 4] = false; data->h_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.h_total); data->v_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.v_total); - data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pipe[i].stream->timing.pix_clk_khz, 1000); + data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pipe[i].stream->timing.pix_clk_100hz, 10000); data->src_width[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.width); data->pitch_in_pixels[num_displays + 4] = data->src_width[num_displays + 4]; data->src_height[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.height); @@ -2881,7 +2881,7 @@ static void populate_initial_data( /* Pipes without underlay after */ for (i = 0; i < pipe_count; i++) { - unsigned int pixel_clock_khz; + unsigned int pixel_clock_100hz; if (!pipe[i].stream || pipe[i].bottom_pipe) continue; @@ -2890,10 +2890,10 @@ static void populate_initial_data( data->lpt_en[num_displays + 4] = false; data->h_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.h_total); data->v_total[num_displays + 4] = bw_int_to_fixed(pipe[i].stream->timing.v_total); - pixel_clock_khz = pipe[i].stream->timing.pix_clk_khz; + pixel_clock_100hz = pipe[i].stream->timing.pix_clk_100hz; if (pipe[i].stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clock_khz *= 2; - data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pixel_clock_khz, 1000); + pixel_clock_100hz *= 2; + data->pixel_rate[num_displays + 4] = bw_frc_to_fixed(pixel_clock_100hz, 10000); if (pipe[i].plane_state) { data->src_width[num_displays + 4] = bw_int_to_fixed(pipe[i].plane_res.scl_data.viewport.width); data->pitch_in_pixels[num_displays + 4] = data->src_width[num_displays + 4]; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c index d0fc54f8fb1c..1ef0074302c5 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c @@ -63,7 +63,7 @@ void scaler_settings_calculation(struct dcn_bw_internal_vars *v) if (v->interlace_output[k] == 1.0) { v->v_ratio[k] = 2.0 * v->v_ratio[k]; } - if ((v->underscan_output[k] == 1.0)) { + if (v->underscan_output[k] == 1.0) { v->h_ratio[k] = v->h_ratio[k] * v->under_scan_factor; v->v_ratio[k] = v->v_ratio[k] * v->under_scan_factor; } @@ -797,9 +797,40 @@ void mode_support_and_system_configuration(struct dcn_bw_internal_vars *v) else { v->maximum_vstartup = v->v_sync_plus_back_porch[k] - 1.0; } - v->line_times_for_prefetch[k] = v->maximum_vstartup - v->urgent_latency / (v->htotal[k] / v->pixel_clock[k]) - (v->time_calc + v->time_setup) / (v->htotal[k] / v->pixel_clock[k]) - (v->dst_y_after_scaler + v->dst_x_after_scaler / v->htotal[k]); - v->line_times_for_prefetch[k] =dcn_bw_floor2(4.0 * (v->line_times_for_prefetch[k] + 0.125), 1.0) / 4; - v->prefetch_bw[k] = (v->meta_pte_bytes_per_frame[k] + 2.0 * v->meta_row_bytes[k] + 2.0 * v->dpte_bytes_per_row[k] + v->prefetch_lines_y[k] * v->swath_width_yper_state[i][j][k] *dcn_bw_ceil2(v->byte_per_pixel_in_dety[k], 1.0) + v->prefetch_lines_c[k] * v->swath_width_yper_state[i][j][k] / 2.0 *dcn_bw_ceil2(v->byte_per_pixel_in_detc[k], 2.0)) / (v->line_times_for_prefetch[k] * v->htotal[k] / v->pixel_clock[k]); + + do { + v->line_times_for_prefetch[k] = v->maximum_vstartup - v->urgent_latency / (v->htotal[k] / v->pixel_clock[k]) - (v->time_calc + v->time_setup) / (v->htotal[k] / v->pixel_clock[k]) - (v->dst_y_after_scaler + v->dst_x_after_scaler / v->htotal[k]); + v->line_times_for_prefetch[k] =dcn_bw_floor2(4.0 * (v->line_times_for_prefetch[k] + 0.125), 1.0) / 4; + v->prefetch_bw[k] = (v->meta_pte_bytes_per_frame[k] + 2.0 * v->meta_row_bytes[k] + 2.0 * v->dpte_bytes_per_row[k] + v->prefetch_lines_y[k] * v->swath_width_yper_state[i][j][k] *dcn_bw_ceil2(v->byte_per_pixel_in_dety[k], 1.0) + v->prefetch_lines_c[k] * v->swath_width_yper_state[i][j][k] / 2.0 *dcn_bw_ceil2(v->byte_per_pixel_in_detc[k], 2.0)) / (v->line_times_for_prefetch[k] * v->htotal[k] / v->pixel_clock[k]); + + if (v->pte_enable == dcn_bw_yes && v->dcc_enable[k] == dcn_bw_yes) { + v->time_for_meta_pte_without_immediate_flip = dcn_bw_max3( + v->meta_pte_bytes_frame[k] / v->prefetch_bandwidth[k], + v->extra_latency, + v->htotal[k] / v->pixel_clock[k] / 4.0); + } else { + v->time_for_meta_pte_without_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0; + } + + if (v->pte_enable == dcn_bw_yes || v->dcc_enable[k] == dcn_bw_yes) { + v->time_for_meta_and_dpte_row_without_immediate_flip = dcn_bw_max3(( + v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bandwidth[k], + v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, + v->extra_latency); + } else { + v->time_for_meta_and_dpte_row_without_immediate_flip = dcn_bw_max2( + v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, + v->extra_latency - v->time_for_meta_pte_with_immediate_flip); + } + + v->lines_for_meta_pte_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; + v->lines_for_meta_and_dpte_row_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; + v->maximum_vstartup = v->maximum_vstartup - 1; + + if (v->lines_for_meta_pte_without_immediate_flip[k] < 8.0 && v->lines_for_meta_and_dpte_row_without_immediate_flip[k] < 16.0) + break; + + } while(1); } v->bw_available_for_immediate_flip = v->return_bw_per_state[i]; for (k = 0; k <= v->number_of_active_planes - 1; k++) { @@ -814,24 +845,18 @@ void mode_support_and_system_configuration(struct dcn_bw_internal_vars *v) for (k = 0; k <= v->number_of_active_planes - 1; k++) { if (v->pte_enable == dcn_bw_yes && v->dcc_enable[k] == dcn_bw_yes) { v->time_for_meta_pte_with_immediate_flip =dcn_bw_max5(v->meta_pte_bytes_per_frame[k] / v->prefetch_bw[k], v->meta_pte_bytes_per_frame[k] * v->total_immediate_flip_bytes[k] / (v->bw_available_for_immediate_flip * (v->meta_pte_bytes_per_frame[k] + v->meta_row_bytes[k] + v->dpte_bytes_per_row[k])), v->extra_latency, v->urgent_latency, v->htotal[k] / v->pixel_clock[k] / 4.0); - v->time_for_meta_pte_without_immediate_flip =dcn_bw_max3(v->meta_pte_bytes_per_frame[k] / v->prefetch_bw[k], v->extra_latency, v->htotal[k] / v->pixel_clock[k] / 4.0); } else { v->time_for_meta_pte_with_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0; - v->time_for_meta_pte_without_immediate_flip = v->htotal[k] / v->pixel_clock[k] / 4.0; } if (v->pte_enable == dcn_bw_yes || v->dcc_enable[k] == dcn_bw_yes) { v->time_for_meta_and_dpte_row_with_immediate_flip =dcn_bw_max5((v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bw[k], (v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) * v->total_immediate_flip_bytes[k] / (v->bw_available_for_immediate_flip * (v->meta_pte_bytes_per_frame[k] + v->meta_row_bytes[k] + v->dpte_bytes_per_row[k])), v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_with_immediate_flip, v->extra_latency, 2.0 * v->urgent_latency); - v->time_for_meta_and_dpte_row_without_immediate_flip =dcn_bw_max3((v->meta_row_bytes[k] + v->dpte_bytes_per_row[k]) / v->prefetch_bw[k], v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, v->extra_latency); } else { v->time_for_meta_and_dpte_row_with_immediate_flip =dcn_bw_max2(v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_with_immediate_flip, v->extra_latency - v->time_for_meta_pte_with_immediate_flip); - v->time_for_meta_and_dpte_row_without_immediate_flip =dcn_bw_max2(v->htotal[k] / v->pixel_clock[k] - v->time_for_meta_pte_without_immediate_flip, v->extra_latency - v->time_for_meta_pte_without_immediate_flip); } v->lines_for_meta_pte_with_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_with_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; - v->lines_for_meta_pte_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_pte_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; v->lines_for_meta_and_dpte_row_with_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_with_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; - v->lines_for_meta_and_dpte_row_without_immediate_flip[k] =dcn_bw_floor2(4.0 * (v->time_for_meta_and_dpte_row_without_immediate_flip / (v->htotal[k] / v->pixel_clock[k]) + 0.125), 1.0) / 4; v->line_times_to_request_prefetch_pixel_data_with_immediate_flip = v->line_times_for_prefetch[k] - v->lines_for_meta_pte_with_immediate_flip[k] - v->lines_for_meta_and_dpte_row_with_immediate_flip[k]; v->line_times_to_request_prefetch_pixel_data_without_immediate_flip = v->line_times_for_prefetch[k] - v->lines_for_meta_pte_without_immediate_flip[k] - v->lines_for_meta_and_dpte_row_without_immediate_flip[k]; if (v->line_times_to_request_prefetch_pixel_data_with_immediate_flip > 0.0) { diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c index 43e4a2be0fa6..12d1842079ae 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -290,41 +290,34 @@ static void pipe_ctx_to_e2e_pipe_params ( switch (pipe->plane_state->tiling_info.gfx9.swizzle) { /* for 4/8/16 high tiles */ case DC_SW_LINEAR: - input->src.is_display_sw = 1; input->src.macro_tile_size = dm_4k_tile; break; case DC_SW_4KB_S: case DC_SW_4KB_S_X: - input->src.is_display_sw = 0; input->src.macro_tile_size = dm_4k_tile; break; case DC_SW_64KB_S: case DC_SW_64KB_S_X: case DC_SW_64KB_S_T: - input->src.is_display_sw = 0; input->src.macro_tile_size = dm_64k_tile; break; case DC_SW_VAR_S: case DC_SW_VAR_S_X: - input->src.is_display_sw = 0; input->src.macro_tile_size = dm_256k_tile; break; /* For 64bpp 2 high tiles */ case DC_SW_4KB_D: case DC_SW_4KB_D_X: - input->src.is_display_sw = 1; input->src.macro_tile_size = dm_4k_tile; break; case DC_SW_64KB_D: case DC_SW_64KB_D_X: case DC_SW_64KB_D_T: - input->src.is_display_sw = 1; input->src.macro_tile_size = dm_64k_tile; break; case DC_SW_VAR_D: case DC_SW_VAR_D_X: - input->src.is_display_sw = 1; input->src.macro_tile_size = dm_256k_tile; break; @@ -423,7 +416,7 @@ static void pipe_ctx_to_e2e_pipe_params ( - pipe->stream->timing.v_addressable - pipe->stream->timing.v_border_bottom - pipe->stream->timing.v_border_top; - input->dest.pixel_rate_mhz = pipe->stream->timing.pix_clk_khz/1000.0; + input->dest.pixel_rate_mhz = pipe->stream->timing.pix_clk_100hz/10000.0; input->dest.vstartup_start = pipe->pipe_dlg_param.vstartup_start; input->dest.vupdate_offset = pipe->pipe_dlg_param.vupdate_offset; input->dest.vupdate_offset = pipe->pipe_dlg_param.vupdate_offset; @@ -670,9 +663,9 @@ static void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v) } static void hack_force_pipe_split(struct dcn_bw_internal_vars *v, - unsigned int pixel_rate_khz) + unsigned int pixel_rate_100hz) { - float pixel_rate_mhz = pixel_rate_khz / 1000; + float pixel_rate_mhz = pixel_rate_100hz / 10000; /* * force enabling pipe split by lower dpp clock for DPM0 to just @@ -695,7 +688,7 @@ static void hack_bounding_box(struct dcn_bw_internal_vars *v, if (context->stream_count == 1 && dbg->force_single_disp_pipe_split) - hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_khz); + hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_100hz); } bool dcn_validate_bandwidth( @@ -852,7 +845,7 @@ bool dcn_validate_bandwidth( v->v_sync_plus_back_porch[input_idx] = pipe->stream->timing.v_total - v->vactive[input_idx] - pipe->stream->timing.v_front_porch; - v->pixel_clock[input_idx] = pipe->stream->timing.pix_clk_khz/1000.0; + v->pixel_clock[input_idx] = pipe->stream->timing.pix_clk_100hz/10000.0; if (pipe->stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) v->pixel_clock[input_idx] *= 2; if (!pipe->plane_state) { @@ -961,7 +954,7 @@ bool dcn_validate_bandwidth( v->dcc_rate[input_idx] = 1; /*TODO: Worst case? does this change?*/ v->output_format[input_idx] = pipe->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420 ? dcn_bw_420 : dcn_bw_444; - v->output[input_idx] = pipe->stream->sink->sink_signal == + v->output[input_idx] = pipe->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ? dcn_bw_hdmi : dcn_bw_dp; v->output_deep_color[input_idx] = dcn_bw_encoder_8bpc; if (v->output[input_idx] == dcn_bw_hdmi) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 5fd52094d459..52f838442e21 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -384,7 +384,7 @@ void dc_stream_set_dither_option(struct dc_stream_state *stream, enum dc_dither_option option) { struct bit_depth_reduction_params params; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct pipe_ctx *pipes = NULL; int i; @@ -451,7 +451,7 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream) pipes, stream->output_color_space, stream->csc_color_matrix.matrix, - pipes->plane_res.hubp->opp_id); + pipes->plane_res.hubp ? pipes->plane_res.hubp->opp_id : 0); ret = true; } } @@ -526,9 +526,8 @@ void dc_link_set_preferred_link_settings(struct dc *dc, for (i = 0; i < MAX_PIPES; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->stream->sink - && pipe->stream->sink->link) { - if (pipe->stream->sink->link == link) + if (pipe->stream && pipe->stream->link) { + if (pipe->stream->link == link) break; } } @@ -586,9 +585,6 @@ static void destruct(struct dc *dc) if (dc->ctx->gpio_service) dal_gpio_service_destroy(&dc->ctx->gpio_service); - if (dc->ctx->i2caux) - dal_i2caux_destroy(&dc->ctx->i2caux); - if (dc->ctx->created_bios) dal_bios_parser_destroy(&dc->ctx->dc_bios); @@ -625,7 +621,6 @@ static bool construct(struct dc *dc, #endif enum dce_version dc_version = DCE_VERSION_UNKNOWN; - dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL); if (!dc_dceip) { dm_error("%s: failed to create dceip\n", __func__); @@ -670,6 +665,7 @@ static bool construct(struct dc *dc, dc_ctx->dc = dc; dc_ctx->asic_id = init_params->asic_id; dc_ctx->dc_sink_id_count = 0; + dc_ctx->dc_stream_id_count = 0; dc->ctx = dc_ctx; dc->current_state = dc_create_state(); @@ -709,14 +705,6 @@ static bool construct(struct dc *dc, dc_ctx->created_bios = true; } - /* Create I2C AUX */ - dc_ctx->i2caux = dal_i2caux_create(dc_ctx); - - if (!dc_ctx->i2caux) { - ASSERT_CRITICAL(false); - goto fail; - } - dc_ctx->perf_trace = dc_perf_trace_create(); if (!dc_ctx->perf_trace) { ASSERT_CRITICAL(false); @@ -840,6 +828,11 @@ alloc_fail: return NULL; } +void dc_init_callbacks(struct dc *dc, + const struct dc_callback_init *init_params) +{ +} + void dc_destroy(struct dc **dc) { destruct(*dc); @@ -875,8 +868,9 @@ static void program_timing_sync( struct dc *dc, struct dc_state *ctx) { - int i, j; + int i, j, k; int group_index = 0; + int num_group = 0; int pipe_count = dc->res_pool->pipe_count; struct pipe_ctx *unsynced_pipes[MAX_PIPES] = { NULL }; @@ -913,11 +907,11 @@ static void program_timing_sync( } } - /* set first unblanked pipe as master */ + /* set first pipe with plane as master */ for (j = 0; j < group_size; j++) { struct pipe_ctx *temp; - if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) { + if (pipe_set[j]->plane_state) { if (j == 0) break; @@ -928,9 +922,21 @@ static void program_timing_sync( } } - /* remove any other unblanked pipes as they have already been synced */ + + for (k = 0; k < group_size; k++) { + struct dc_stream_status *status = dc_stream_get_status_from_state(ctx, pipe_set[k]->stream); + + status->timing_sync_info.group_id = num_group; + status->timing_sync_info.group_size = group_size; + if (k == 0) + status->timing_sync_info.master = true; + else + status->timing_sync_info.master = false; + + } + /* remove any other pipes with plane as they have already been synced */ for (j = j + 1; j < group_size; j++) { - if (pipe_set[j]->stream_res.tg->funcs->is_blanked && !pipe_set[j]->stream_res.tg->funcs->is_blanked(pipe_set[j]->stream_res.tg)) { + if (pipe_set[j]->plane_state) { group_size--; pipe_set[j] = pipe_set[group_size]; j--; @@ -942,6 +948,7 @@ static void program_timing_sync( dc, group_index, group_size, pipe_set); group_index++; } + num_group++; } } @@ -962,6 +969,52 @@ static bool context_changed( return false; } +bool dc_validate_seamless_boot_timing(struct dc *dc, + const struct dc_sink *sink, + struct dc_crtc_timing *crtc_timing) +{ + struct timing_generator *tg; + struct dc_link *link = sink->link; + unsigned int inst; + + /* Check for enabled DIG to identify enabled display */ + if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) + return false; + + /* Check for which front end is used by this encoder. + * Note the inst is 1 indexed, where 0 is undefined. + * Note that DIG_FE can source from different OTG but our + * current implementation always map 1-to-1, so this code makes + * the same assumption and doesn't check OTG source. + */ + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + + /* Instance should be within the range of the pool */ + if (inst >= dc->res_pool->pipe_count) + return false; + + tg = dc->res_pool->timing_generators[inst]; + + if (!tg->funcs->is_matching_timing) + return false; + + if (!tg->funcs->is_matching_timing(tg, crtc_timing)) + return false; + + if (dc_is_dp_signal(link->connector_signal)) { + unsigned int pix_clk_100hz; + + dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( + dc->res_pool->dp_clock_source, + inst, &pix_clk_100hz); + + if (crtc_timing->pix_clk_100hz != pix_clk_100hz) + return false; + } + + return true; +} + bool dc_enable_stereo( struct dc *dc, struct dc_state *context, @@ -1040,7 +1093,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c /* Program all planes within new context*/ for (i = 0; i < context->stream_count; i++) { - const struct dc_sink *sink = context->streams[i]->sink; + const struct dc_link *link = context->streams[i]->link; + struct dc_stream_status *status; + + if (context->streams[i]->apply_seamless_boot_optimization) + context->streams[i]->apply_seamless_boot_optimization = false; if (!context->streams[i]->mode_changed) continue; @@ -1065,12 +1122,15 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c } } - CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}", + status = dc_stream_get_status_from_state(context, context->streams[i]); + context->streams[i]->out.otg_offset = status->primary_otg_inst; + + CONN_MSG_MODE(link, "{%dx%d, %dx%d@%dKhz}", context->streams[i]->timing.h_addressable, context->streams[i]->timing.v_addressable, context->streams[i]->timing.h_total, context->streams[i]->timing.v_total, - context->streams[i]->timing.pix_clk_khz); + context->streams[i]->timing.pix_clk_100hz / 10); } dc_enable_stereo(dc, context, dc_streams, context->stream_count); @@ -1114,6 +1174,9 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) int i; struct dc_state *context = dc->current_state; + if (dc->optimized_required == false) + return true; + post_surface_trace(dc); for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -1215,6 +1278,12 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa */ update_flags->bits.bpp_change = 1; + if (u->plane_info->plane_size.grph.surface_pitch != u->surface->plane_size.grph.surface_pitch + || u->plane_info->plane_size.video.luma_pitch != u->surface->plane_size.video.luma_pitch + || u->plane_info->plane_size.video.chroma_pitch != u->surface->plane_size.video.chroma_pitch) + update_flags->bits.plane_size_change = 1; + + if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info, sizeof(union dc_tiling_info)) != 0) { update_flags->bits.swizzle_change = 1; @@ -1236,7 +1305,7 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa || update_flags->bits.output_tf_change) return UPDATE_TYPE_FULL; - return UPDATE_TYPE_MED; + return update_flags->raw ? UPDATE_TYPE_MED : UPDATE_TYPE_FAST; } static enum surface_update_type get_scaling_info_update_type( @@ -1436,6 +1505,101 @@ static struct dc_stream_status *stream_get_status( static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL; +static void copy_surface_update_to_plane( + struct dc_plane_state *surface, + struct dc_surface_update *srf_update) +{ + if (srf_update->flip_addr) { + surface->address = srf_update->flip_addr->address; + surface->flip_immediate = + srf_update->flip_addr->flip_immediate; + surface->time.time_elapsed_in_us[surface->time.index] = + srf_update->flip_addr->flip_timestamp_in_us - + surface->time.prev_update_time_in_us; + surface->time.prev_update_time_in_us = + srf_update->flip_addr->flip_timestamp_in_us; + surface->time.index++; + if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX) + surface->time.index = 0; + } + + if (srf_update->scaling_info) { + surface->scaling_quality = + srf_update->scaling_info->scaling_quality; + surface->dst_rect = + srf_update->scaling_info->dst_rect; + surface->src_rect = + srf_update->scaling_info->src_rect; + surface->clip_rect = + srf_update->scaling_info->clip_rect; + } + + if (srf_update->plane_info) { + surface->color_space = + srf_update->plane_info->color_space; + surface->format = + srf_update->plane_info->format; + surface->plane_size = + srf_update->plane_info->plane_size; + surface->rotation = + srf_update->plane_info->rotation; + surface->horizontal_mirror = + srf_update->plane_info->horizontal_mirror; + surface->stereo_format = + srf_update->plane_info->stereo_format; + surface->tiling_info = + srf_update->plane_info->tiling_info; + surface->visible = + srf_update->plane_info->visible; + surface->per_pixel_alpha = + srf_update->plane_info->per_pixel_alpha; + surface->global_alpha = + srf_update->plane_info->global_alpha; + surface->global_alpha_value = + srf_update->plane_info->global_alpha_value; + surface->dcc = + srf_update->plane_info->dcc; + surface->sdr_white_level = + srf_update->plane_info->sdr_white_level; + } + + if (srf_update->gamma && + (surface->gamma_correction != + srf_update->gamma)) { + memcpy(&surface->gamma_correction->entries, + &srf_update->gamma->entries, + sizeof(struct dc_gamma_entries)); + surface->gamma_correction->is_identity = + srf_update->gamma->is_identity; + surface->gamma_correction->num_entries = + srf_update->gamma->num_entries; + surface->gamma_correction->type = + srf_update->gamma->type; + } + + if (srf_update->in_transfer_func && + (surface->in_transfer_func != + srf_update->in_transfer_func)) { + surface->in_transfer_func->sdr_ref_white_level = + srf_update->in_transfer_func->sdr_ref_white_level; + surface->in_transfer_func->tf = + srf_update->in_transfer_func->tf; + surface->in_transfer_func->type = + srf_update->in_transfer_func->type; + memcpy(&surface->in_transfer_func->tf_pts, + &srf_update->in_transfer_func->tf_pts, + sizeof(struct dc_transfer_func_distributed_points)); + } + + if (srf_update->input_csc_color_matrix) + surface->input_csc_color_matrix = + *srf_update->input_csc_color_matrix; + + if (srf_update->coeff_reduction_factor) + surface->coeff_reduction_factor = + *srf_update->coeff_reduction_factor; +} + static void commit_planes_do_stream_update(struct dc *dc, struct dc_stream_state *stream, struct dc_stream_update *stream_update, @@ -1459,11 +1623,13 @@ static void commit_planes_do_stream_update(struct dc *dc, stream_update->adjust->v_total_min, stream_update->adjust->v_total_max); - if (stream_update->periodic_fn_vsync_delta && - pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) + if (stream_update->periodic_vsync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( - pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, - pipe_ctx->stream->periodic_fn_vsync_delta); + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE0, &stream->periodic_vsync_config); + + if (stream_update->enhanced_sync_config && pipe_ctx->stream_res.tg->funcs->program_vline_interrupt) + pipe_ctx->stream_res.tg->funcs->program_vline_interrupt( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing, VLINE1, &stream->enhanced_sync_config); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || stream_update->vrr_infopacket || @@ -1605,7 +1771,6 @@ void dc_commit_updates_for_stream(struct dc *dc, int surface_count, struct dc_stream_state *stream, struct dc_stream_update *stream_update, - struct dc_plane_state **plane_states, struct dc_state *state) { const struct dc_stream_status *stream_status; @@ -1640,14 +1805,7 @@ void dc_commit_updates_for_stream(struct dc *dc, for (i = 0; i < surface_count; i++) { struct dc_plane_state *surface = srf_updates[i].surface; - /* TODO: On flip we don't build the state, so it still has the - * old address. Which is why we are updating the address here - */ - if (srf_updates[i].flip_addr) { - surface->address = srf_updates[i].flip_addr->address; - surface->flip_immediate = srf_updates[i].flip_addr->flip_immediate; - - } + copy_surface_update_to_plane(surface, &srf_updates[i]); if (update_type >= UPDATE_TYPE_MED) { for (j = 0; j < dc->res_pool->pipe_count; j++) { @@ -1764,6 +1922,26 @@ void dc_resume(struct dc *dc) core_link_resume(dc->links[i]); } +unsigned int dc_get_current_backlight_pwm(struct dc *dc) +{ + struct abm *abm = dc->res_pool->abm; + + if (abm) + return abm->funcs->get_current_backlight(abm); + + return 0; +} + +unsigned int dc_get_target_backlight_pwm(struct dc *dc) +{ + struct abm *abm = dc->res_pool->abm; + + if (abm) + return abm->funcs->get_target_backlight(abm); + + return 0; +} + bool dc_is_dmcu_initialized(struct dc *dc) { struct dmcu *dmcu = dc->res_pool->dmcu; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 52deacf39841..7f5a947ad31d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -43,10 +43,6 @@ #include "dpcd_defs.h" #include "dmcu.h" -#include "dce/dce_11_0_d.h" -#include "dce/dce_11_0_enum.h" -#include "dce/dce_11_0_sh_mask.h" - #define DC_LOGGER_INIT(logger) @@ -80,6 +76,12 @@ static void destruct(struct dc_link *link) { int i; + if (link->hpd_gpio != NULL) { + dal_gpio_close(link->hpd_gpio); + dal_gpio_destroy_irq(&link->hpd_gpio); + link->hpd_gpio = NULL; + } + if (link->ddc) dal_ddc_service_destroy(&link->ddc); @@ -789,7 +791,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) return false; } - sink->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock; + sink->link->dongle_max_pix_clk = sink_caps.max_hdmi_pixel_clock; sink->converter_disable_audio = converter_disable_audio; link->local_sink = sink; @@ -935,18 +937,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) bool dc_link_get_hpd_state(struct dc_link *dc_link) { - struct gpio *hpd_pin; uint32_t state; - hpd_pin = get_hpd_gpio(dc_link->ctx->dc_bios, - dc_link->link_id, dc_link->ctx->gpio_service); - if (hpd_pin == NULL) - ASSERT(false); - - dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT); - dal_gpio_get_value(hpd_pin, &state); - dal_gpio_close(hpd_pin); - dal_gpio_destroy_irq(&hpd_pin); + dal_gpio_lock_pin(dc_link->hpd_gpio); + dal_gpio_get_value(dc_link->hpd_gpio, &state); + dal_gpio_unlock_pin(dc_link->hpd_gpio); return state; } @@ -1102,7 +1097,6 @@ static bool construct( const struct link_init_data *init_params) { uint8_t i; - struct gpio *hpd_gpio = NULL; struct ddc_service_init_data ddc_service_init_data = { { 0 } }; struct dc_context *dc_ctx = init_params->ctx; struct encoder_init_data enc_init_data = { 0 }; @@ -1132,10 +1126,12 @@ static bool construct( if (link->dc->res_pool->funcs->link_init) link->dc->res_pool->funcs->link_init(link); - hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); - - if (hpd_gpio != NULL) - link->irq_source_hpd = dal_irq_get_source(hpd_gpio); + link->hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); + if (link->hpd_gpio != NULL) { + dal_gpio_open(link->hpd_gpio, GPIO_MODE_INTERRUPT); + dal_gpio_unlock_pin(link->hpd_gpio); + link->irq_source_hpd = dal_irq_get_source(link->hpd_gpio); + } switch (link->link_id.id) { case CONNECTOR_ID_HDMI_TYPE_A: @@ -1153,18 +1149,18 @@ static bool construct( case CONNECTOR_ID_DISPLAY_PORT: link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; - if (hpd_gpio != NULL) + if (link->hpd_gpio != NULL) link->irq_source_hpd_rx = - dal_irq_get_rx_source(hpd_gpio); + dal_irq_get_rx_source(link->hpd_gpio); break; case CONNECTOR_ID_EDP: link->connector_signal = SIGNAL_TYPE_EDP; - if (hpd_gpio != NULL) { + if (link->hpd_gpio != NULL) { link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; link->irq_source_hpd_rx = - dal_irq_get_rx_source(hpd_gpio); + dal_irq_get_rx_source(link->hpd_gpio); } break; case CONNECTOR_ID_LVDS: @@ -1175,10 +1171,7 @@ static bool construct( goto create_fail; } - if (hpd_gpio != NULL) { - dal_gpio_destroy_irq(&hpd_gpio); - hpd_gpio = NULL; - } + /* TODO: #DAL3 Implement id to str function.*/ LINK_INFO("Connector[%d] description:" @@ -1281,8 +1274,9 @@ link_enc_create_fail: ddc_create_fail: create_fail: - if (hpd_gpio != NULL) { - dal_gpio_destroy_irq(&hpd_gpio); + if (link->hpd_gpio != NULL) { + dal_gpio_destroy_irq(&link->hpd_gpio); + link->hpd_gpio = NULL; } return false; @@ -1372,7 +1366,7 @@ static void dpcd_configure_panel_mode( static void enable_stream_features(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; union down_spread_ctrl old_downspread; union down_spread_ctrl new_downspread; @@ -1397,7 +1391,7 @@ static enum dc_status enable_link_dp( struct dc_stream_state *stream = pipe_ctx->stream; enum dc_status status; bool skip_video_pattern; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct dc_link_settings link_settings = {0}; enum dp_panel_mode panel_mode; @@ -1414,8 +1408,8 @@ static enum dc_status enable_link_dp( pipe_ctx->clock_source->id, &link_settings); - if (stream->sink->edid_caps.panel_patch.dppowerup_delay > 0) { - int delay_dp_power_up_in_ms = stream->sink->edid_caps.panel_patch.dppowerup_delay; + if (stream->sink_patches.dppowerup_delay > 0) { + int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay; msleep(delay_dp_power_up_in_ms); } @@ -1448,7 +1442,7 @@ static enum dc_status enable_link_edp( { enum dc_status status; struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; /*in case it is not on*/ link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); @@ -1463,7 +1457,7 @@ static enum dc_status enable_link_dp_mst( struct dc_state *state, struct pipe_ctx *pipe_ctx) { - struct dc_link *link = pipe_ctx->stream->sink->link; + struct dc_link *link = pipe_ctx->stream->link; /* sink signal type after MST branch is MST. Multiple MST sinks * share one link. Link DP PHY is enable or training only once. @@ -1471,6 +1465,11 @@ static enum dc_status enable_link_dp_mst( if (link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) return DC_OK; + /* to make sure the pending down rep can be processed + * before clear payload table + */ + dm_helpers_dp_mst_poll_pending_down_reply(link->ctx, link); + /* clear payload table */ dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link); @@ -1597,7 +1596,7 @@ static bool i2c_write(struct pipe_ctx *pipe_ctx, cmd.payloads = &payload; if (dm_helpers_submit_i2c(pipe_ctx->stream->ctx, - pipe_ctx->stream->sink->link, &cmd)) + pipe_ctx->stream->link, &cmd)) return true; return false; @@ -1651,7 +1650,7 @@ static void write_i2c_retimer_setting( else { i2c_success = dal_ddc_service_query_ddc_data( - pipe_ctx->stream->sink->link->ddc, + pipe_ctx->stream->link->ddc, slave_address, &offset, 1, &value, 1); if (!i2c_success) /* Write failure */ @@ -1704,7 +1703,7 @@ static void write_i2c_retimer_setting( else { i2c_success = dal_ddc_service_query_ddc_data( - pipe_ctx->stream->sink->link->ddc, + pipe_ctx->stream->link->ddc, slave_address, &offset, 1, &value, 1); if (!i2c_success) /* Write failure */ @@ -1929,7 +1928,7 @@ static void write_i2c_redriver_setting( static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; enum dc_color_depth display_color_depth; enum engine_id eng_id; struct ext_hdmi_settings settings = {0}; @@ -1938,12 +1937,12 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) && (stream->timing.v_addressable == 480); if (stream->phy_pix_clk == 0) - stream->phy_pix_clk = stream->timing.pix_clk_khz; + stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10; if (stream->phy_pix_clk > 340000) is_over_340mhz = true; if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) { - unsigned short masked_chip_caps = pipe_ctx->stream->sink->link->chip_caps & + unsigned short masked_chip_caps = pipe_ctx->stream->link->chip_caps & EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK; if (masked_chip_caps == EXT_DISPLAY_PATH_CAPS__HDMI20_TISN65DP159RSBT) { /* DP159, Retimer settings */ @@ -1964,11 +1963,11 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) dal_ddc_service_write_scdc_data( - stream->sink->link->ddc, + stream->link->ddc, stream->phy_pix_clk, stream->timing.flags.LTE_340MCSC_SCRAMBLE); - memset(&stream->sink->link->cur_link_settings, 0, + memset(&stream->link->cur_link_settings, 0, sizeof(struct dc_link_settings)); display_color_depth = stream->timing.display_color_depth; @@ -1989,12 +1988,12 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx) static void enable_link_lvds(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; if (stream->phy_pix_clk == 0) - stream->phy_pix_clk = stream->timing.pix_clk_khz; + stream->phy_pix_clk = stream->timing.pix_clk_100hz / 10; - memset(&stream->sink->link->cur_link_settings, 0, + memset(&stream->link->cur_link_settings, 0, sizeof(struct dc_link_settings)); link->link_enc->funcs->enable_lvds_output( @@ -2067,7 +2066,7 @@ static bool dp_active_dongle_validate_timing( const struct dc_crtc_timing *timing, const struct dpcd_caps *dpcd_caps) { - unsigned int required_pix_clk = timing->pix_clk_khz; + unsigned int required_pix_clk_100hz = timing->pix_clk_100hz; const struct dc_dongle_caps *dongle_caps = &dpcd_caps->dongle_caps; switch (dpcd_caps->dongle_type) { @@ -2107,9 +2106,9 @@ static bool dp_active_dongle_validate_timing( /* Check Color Depth and Pixel Clock */ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) - required_pix_clk /= 2; + required_pix_clk_100hz /= 2; else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) - required_pix_clk = required_pix_clk * 2 / 3; + required_pix_clk_100hz = required_pix_clk_100hz * 2 / 3; switch (timing->display_color_depth) { case COLOR_DEPTH_666: @@ -2119,12 +2118,12 @@ static bool dp_active_dongle_validate_timing( case COLOR_DEPTH_101010: if (dongle_caps->dp_hdmi_max_bpc < 10) return false; - required_pix_clk = required_pix_clk * 10 / 8; + required_pix_clk_100hz = required_pix_clk_100hz * 10 / 8; break; case COLOR_DEPTH_121212: if (dongle_caps->dp_hdmi_max_bpc < 12) return false; - required_pix_clk = required_pix_clk * 12 / 8; + required_pix_clk_100hz = required_pix_clk_100hz * 12 / 8; break; case COLOR_DEPTH_141414: @@ -2134,7 +2133,7 @@ static bool dp_active_dongle_validate_timing( return false; } - if (required_pix_clk > dongle_caps->dp_hdmi_max_pixel_clk) + if (required_pix_clk_100hz > (dongle_caps->dp_hdmi_max_pixel_clk * 10)) return false; return true; @@ -2145,7 +2144,7 @@ enum dc_status dc_link_validate_mode_timing( struct dc_link *link, const struct dc_crtc_timing *timing) { - uint32_t max_pix_clk = stream->sink->dongle_max_pix_clk; + uint32_t max_pix_clk = stream->link->dongle_max_pix_clk * 10; struct dpcd_caps *dpcd_caps = &link->dpcd_caps; /* A hack to avoid failing any modes for EDID override feature on @@ -2155,7 +2154,7 @@ enum dc_status dc_link_validate_mode_timing( return DC_OK; /* Passive Dongle */ - if (0 != max_pix_clk && timing->pix_clk_khz > max_pix_clk) + if (0 != max_pix_clk && timing->pix_clk_100hz > max_pix_clk) return DC_EXCEED_DONGLE_CAP; /* Active Dongle*/ @@ -2190,8 +2189,7 @@ int dc_link_get_backlight_level(const struct dc_link *link) bool dc_link_set_backlight_level(const struct dc_link *link, uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp, - const struct dc_stream_state *stream) + uint32_t frame_ramp) { struct dc *core_dc = link->ctx->dc; struct abm *abm = core_dc->res_pool->abm; @@ -2206,10 +2204,6 @@ bool dc_link_set_backlight_level(const struct dc_link *link, (abm->funcs->set_backlight_level_pwm == NULL)) return false; - if (stream) - ((struct dc_stream_state *)stream)->bl_pwm_level = - backlight_pwm_u16_16; - use_smooth_brightness = dmcu->funcs->is_dmcu_initialized(dmcu); DC_LOG_BACKLIGHT("New Backlight level: %d (0x%X)\n", @@ -2219,7 +2213,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, for (i = 0; i < MAX_PIPES; i++) { if (core_dc->current_state->res_ctx.pipe_ctx[i].stream) { if (core_dc->current_state->res_ctx. - pipe_ctx[i].stream->sink->link + pipe_ctx[i].stream->link == link) /* DMCU -1 for all controller id values, * therefore +1 here @@ -2279,7 +2273,7 @@ void core_link_resume(struct dc_link *link) static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream) { struct dc_link_settings *link_settings = - &stream->sink->link->cur_link_settings; + &stream->link->cur_link_settings; uint32_t link_rate_in_mbps = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_MHZ; struct fixed31_32 mbps = dc_fixpt_from_int( @@ -2310,7 +2304,7 @@ static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx) uint32_t denominator; bpc = get_color_depth(pipe_ctx->stream_res.pix_clk_params.color_depth); - kbps = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk * bpc * 3; + kbps = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 * bpc * 3; /* * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 @@ -2386,7 +2380,7 @@ static void update_mst_stream_alloc_table( static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct link_encoder *link_encoder = link->link_enc; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -2466,7 +2460,7 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct link_encoder *link_encoder = link->link_enc; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -2551,8 +2545,8 @@ void core_link_enable_stream( DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL) { - stream->sink->link->link_enc->funcs->setup( - stream->sink->link->link_enc, + stream->link->link_enc->funcs->setup( + stream->link->link_enc, pipe_ctx->stream->signal); pipe_ctx->stream_res.stream_enc->funcs->setup_stereo_sync( pipe_ctx->stream_res.stream_enc, @@ -2586,13 +2580,23 @@ void core_link_enable_stream( &stream->timing); if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + bool apply_edp_fast_boot_optimization = + pipe_ctx->stream->apply_edp_fast_boot_optimization; + + pipe_ctx->stream->apply_edp_fast_boot_optimization = false; + resource_build_info_frame(pipe_ctx); core_dc->hwss.update_info_frame(pipe_ctx); + /* Do not touch link on seamless boot optimization. */ + if (pipe_ctx->stream->apply_seamless_boot_optimization) { + pipe_ctx->stream->dpms_off = false; + return; + } + /* eDP lit up by bios already, no need to enable again. */ if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP && - pipe_ctx->stream->apply_edp_fast_boot_optimization) { - pipe_ctx->stream->apply_edp_fast_boot_optimization = false; + apply_edp_fast_boot_optimization) { pipe_ctx->stream->dpms_off = false; return; } @@ -2604,7 +2608,7 @@ void core_link_enable_stream( if (status != DC_OK) { DC_LOG_WARNING("enabling link %u failed: %d\n", - pipe_ctx->stream->sink->link->link_index, + pipe_ctx->stream->link->link_index, status); /* Abort stream enable *unless* the failure was due to @@ -2619,6 +2623,8 @@ void core_link_enable_stream( } } + stream->link->link_status.link_active = true; + core_dc->hwss.enable_audio_stream(pipe_ctx); /* turn off otg test pattern if enable */ @@ -2633,15 +2639,10 @@ void core_link_enable_stream( allocate_mst_payload(pipe_ctx); core_dc->hwss.unblank_stream(pipe_ctx, - &pipe_ctx->stream->sink->link->cur_link_settings); + &pipe_ctx->stream->link->cur_link_settings); if (dc_is_dp_signal(pipe_ctx->stream->signal)) enable_stream_features(pipe_ctx); - - dc_link_set_backlight_level(pipe_ctx->stream->sink->link, - pipe_ctx->stream->bl_pwm_level, - 0, - pipe_ctx->stream); } } @@ -2657,7 +2658,9 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) core_dc->hwss.disable_stream(pipe_ctx, option); - disable_link(pipe_ctx->stream->sink->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + + pipe_ctx->stream->link->link_status.link_active = false; } void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c index 506a97e16956..b7ee63cd8dc7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c @@ -33,7 +33,7 @@ #include "include/vector.h" #include "core_types.h" #include "dc_link_ddc.h" -#include "aux_engine.h" +#include "dce/dce_aux.h" #define AUX_POWER_UP_WA_DELAY 500 #define I2C_OVER_AUX_DEFER_WA_DELAY 70 @@ -42,7 +42,6 @@ #define CV_SMART_DONGLE_ADDRESS 0x20 /* DVI-HDMI dongle slave address for retrieving dongle signature*/ #define DVI_HDMI_DONGLE_ADDRESS 0x68 -static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G"; struct dvi_hdmi_dongle_signature_data { int8_t vendor[3];/* "AMD" */ uint8_t version[2]; @@ -165,43 +164,6 @@ static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p) } -static struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count) -{ - struct aux_payloads *payloads; - - payloads = kzalloc(sizeof(struct aux_payloads), GFP_KERNEL); - - if (!payloads) - return NULL; - - if (dal_vector_construct( - &payloads->payloads, ctx, count, sizeof(struct aux_payload))) - return payloads; - - kfree(payloads); - return NULL; -} - -static struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p) -{ - return (struct aux_payload *)p->payloads.container; -} - -static uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p) -{ - return p->payloads.count; -} - -static void dal_ddc_aux_payloads_destroy(struct aux_payloads **p) -{ - if (!p || !*p) - return; - - dal_vector_destruct(&(*p)->payloads); - kfree(*p); - *p = NULL; -} - #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) void dal_ddc_i2c_payloads_add( @@ -225,27 +187,6 @@ void dal_ddc_i2c_payloads_add( } -void dal_ddc_aux_payloads_add( - struct aux_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write) -{ - uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; - uint32_t pos; - - for (pos = 0; pos < len; pos += payload_size) { - struct aux_payload payload = { - .i2c_over_aux = true, - .write = write, - .address = address, - .length = DDC_MIN(payload_size, len - pos), - .data = data + pos }; - dal_vector_append(&payloads->payloads, &payload); - } -} - static void construct( struct ddc_service *ddc_service, struct ddc_service_init_data *init_data) @@ -574,32 +515,34 @@ bool dal_ddc_service_query_ddc_data( /*TODO: len of payload data for i2c and aux is uint8!!!!, * but we want to read 256 over i2c!!!!*/ if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { - - struct aux_payloads *payloads = - dal_ddc_aux_payloads_create(ddc->ctx, payloads_num); - - struct aux_command command = { - .payloads = dal_ddc_aux_payloads_get(payloads), - .number_of_payloads = 0, + struct aux_payload write_payload = { + .i2c_over_aux = true, + .write = true, + .mot = true, + .address = address, + .length = write_size, + .data = write_buf, + .reply = NULL, .defer_delay = get_defer_delay(ddc), - .max_defer_write_retry = 0 }; + }; - dal_ddc_aux_payloads_add( - payloads, address, write_size, write_buf, true); - - dal_ddc_aux_payloads_add( - payloads, address, read_size, read_buf, false); - - command.number_of_payloads = - dal_ddc_aux_payloads_get_count(payloads); + struct aux_payload read_payload = { + .i2c_over_aux = true, + .write = false, + .mot = false, + .address = address, + .length = read_size, + .data = read_buf, + .reply = NULL, + .defer_delay = get_defer_delay(ddc), + }; - ret = dal_i2caux_submit_aux_command( - ddc->ctx->i2caux, - ddc->ddc_pin, - &command); + ret = dc_link_aux_transfer_with_retries(ddc, &write_payload); - dal_ddc_aux_payloads_destroy(&payloads); + if (!ret) + return false; + ret = dc_link_aux_transfer_with_retries(ddc, &read_payload); } else { struct i2c_payloads *payloads = dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num); @@ -631,56 +574,15 @@ bool dal_ddc_service_query_ddc_data( } int dc_link_aux_transfer(struct ddc_service *ddc, - unsigned int address, - uint8_t *reply, - void *buffer, - unsigned int size, - enum aux_transaction_type type, - enum i2caux_transaction_action action) + struct aux_payload *payload) { - struct ddc *ddc_pin = ddc->ddc_pin; - struct aux_engine *aux_engine; - enum aux_channel_operation_result operation_result; - struct aux_request_transaction_data aux_req; - struct aux_reply_transaction_data aux_rep; - uint8_t returned_bytes = 0; - int res = -1; - uint32_t status; - - memset(&aux_req, 0, sizeof(aux_req)); - memset(&aux_rep, 0, sizeof(aux_rep)); - - aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; - aux_engine->funcs->acquire(aux_engine, ddc_pin); - - aux_req.type = type; - aux_req.action = action; - - aux_req.address = address; - aux_req.delay = 0; - aux_req.length = size; - aux_req.data = buffer; - - aux_engine->funcs->submit_channel_request(aux_engine, &aux_req); - operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - res = aux_engine->funcs->read_channel_reply(aux_engine, size, - buffer, reply, - &status); - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - res = 0; - break; - case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - res = -1; - break; - } - aux_engine->funcs->release_engine(aux_engine); - return res; + return dce_aux_transfer(ddc, payload); +} + +bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, + struct aux_payload *payload) +{ + return dce_aux_transfer_with_retries(ddc, payload); } /*test only function*/ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 0caacb60b02f..09d301216076 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -49,6 +49,8 @@ static void wait_for_training_aux_rd_interval( { union training_aux_rd_interval training_rd_interval; + memset(&training_rd_interval, 0, sizeof(training_rd_interval)); + /* overwrite the delay if rev > 1.1*/ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { /* DP 1.2 or later - retrieve delay through @@ -117,6 +119,13 @@ static void dpcd_set_link_settings( core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && + (link->dpcd_caps.link_rate_set >= 1 && + link->dpcd_caps.link_rate_set <= 8)) { + core_link_write_dpcd(link, DP_LINK_RATE_SET, + &link->dpcd_caps.link_rate_set, 1); + } + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", __func__, DP_LINK_BW_SET, @@ -1542,7 +1551,7 @@ static uint32_t bandwidth_in_kbps_from_timing( ASSERT(bits_per_channel != 0); - kbps = timing->pix_clk_khz; + kbps = timing->pix_clk_100hz / 10; kbps *= bits_per_channel; if (timing->flags.Y_ONLY != 1) { @@ -1584,7 +1593,7 @@ bool dp_validate_mode_timing( const struct dc_link_settings *link_setting; /*always DP fail safe mode*/ - if (timing->pix_clk_khz == (uint32_t) 25175 && + if ((timing->pix_clk_100hz / 10) == (uint32_t) 25175 && timing->h_addressable == (uint32_t) 640 && timing->v_addressable == (uint32_t) 480) return true; @@ -1634,7 +1643,7 @@ void decide_link_settings(struct dc_stream_state *stream, req_bw = bandwidth_in_kbps_from_timing(&stream->timing); - link = stream->sink->link; + link = stream->link; /* if preferred is specified through AMDDP, use it, if it's enough * to drive the mode @@ -1656,7 +1665,7 @@ void decide_link_settings(struct dc_stream_state *stream, } /* EDP use the link cap setting */ - if (stream->sink->sink_signal == SIGNAL_TYPE_EDP) { + if (link->connector_signal == SIGNAL_TYPE_EDP) { *link_setting = link->verified_link_cap; return; } @@ -2002,11 +2011,7 @@ static void handle_automated_test(struct dc_link *link) dp_test_send_phy_test_pattern(link); test_response.bits.ACK = 1; } - if (!test_request.raw) - /* no requests, revert all test signals - * TODO: revert all test signals - */ - test_response.bits.ACK = 1; + /* send request acknowledgment */ if (test_response.bits.ACK) core_link_write_dpcd( @@ -2493,13 +2498,72 @@ bool detect_dp_sink_caps(struct dc_link *link) /* TODO save sink caps in link->sink */ } +enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz) +{ + enum dc_link_rate link_rate; + // LinkRate is normally stored as a multiplier of 0.27 Gbps per lane. Do the translation. + switch (link_rate_in_khz) { + case 1620000: + link_rate = LINK_RATE_LOW; // Rate_1 (RBR) - 1.62 Gbps/Lane + break; + case 2160000: + link_rate = LINK_RATE_RATE_2; // Rate_2 - 2.16 Gbps/Lane + break; + case 2430000: + link_rate = LINK_RATE_RATE_3; // Rate_3 - 2.43 Gbps/Lane + break; + case 2700000: + link_rate = LINK_RATE_HIGH; // Rate_4 (HBR) - 2.70 Gbps/Lane + break; + case 3240000: + link_rate = LINK_RATE_RBR2; // Rate_5 (RBR2) - 3.24 Gbps/Lane + break; + case 4320000: + link_rate = LINK_RATE_RATE_6; // Rate_6 - 4.32 Gbps/Lane + break; + case 5400000: + link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2) - 5.40 Gbps/Lane + break; + case 8100000: + link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3) - 8.10 Gbps/Lane + break; + default: + link_rate = LINK_RATE_UNKNOWN; + break; + } + return link_rate; +} + void detect_edp_sink_caps(struct dc_link *link) { - retrieve_link_cap(link); + uint8_t supported_link_rates[16] = {0}; + uint32_t entry; + uint32_t link_rate_in_khz; + enum dc_link_rate link_rate = LINK_RATE_UNKNOWN; - if (link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN) - link->reported_link_cap.link_rate = LINK_RATE_HIGH2; + retrieve_link_cap(link); + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { + // Read DPCD 00010h - 0001Fh 16 bytes at one shot + core_link_read_dpcd(link, DP_SUPPORTED_LINK_RATES, + supported_link_rates, sizeof(supported_link_rates)); + + link->dpcd_caps.link_rate_set = 0; + for (entry = 0; entry < 16; entry += 2) { + // DPCD register reports per-lane link rate = 16-bit link rate capability + // value X 200 kHz. Need multipler to find link rate in kHz. + link_rate_in_khz = (supported_link_rates[entry+1] * 0x100 + + supported_link_rates[entry]) * 200; + + if (link_rate_in_khz != 0) { + link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); + if (link->reported_link_cap.link_rate < link_rate) { + link->reported_link_cap.link_rate = link_rate; + link->dpcd_caps.link_rate_set = entry; + } + } + } + } link->verified_link_cap = link->reported_link_cap; } @@ -2621,7 +2685,7 @@ bool dc_link_dp_set_test_pattern( memset(&training_pattern, 0, sizeof(training_pattern)); for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream->sink->link == link) { + if (pipes[i].stream->link == link) { pipe_ctx = &pipes[i]; break; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index 0065ec7d5330..f7f7515f65f4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -70,13 +70,12 @@ void dp_enable_link_phy( */ for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && - pipes[i].stream->sink != NULL && - pipes[i].stream->sink->link == link) { + pipes[i].stream->link == link) { if (pipes[i].clock_source != NULL && pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { pipes[i].clock_source = dp_cs; - pipes[i].stream_res.pix_clk_params.requested_pix_clk = - pipes[i].stream->timing.pix_clk_khz; + pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz = + pipes[i].stream->timing.pix_clk_100hz; pipes[i].clock_source->funcs->program_pix_clk( pipes[i].clock_source, &pipes[i].stream_res.pix_clk_params, @@ -120,6 +119,10 @@ bool edp_receiver_ready_T9(struct dc_link *link) break; udelay(100); //MAx T9 } while (++tries < 50); + + if (link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0) + udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000); + return result; } bool edp_receiver_ready_T7(struct dc_link *link) @@ -279,10 +282,8 @@ void dp_retrain_link_dp_test(struct dc_link *link, for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && !pipes[i].top_pipe && - pipes[i].stream->sink != NULL && - pipes[i].stream->sink->link != NULL && - pipes[i].stream_res.stream_enc != NULL && - pipes[i].stream->sink->link == link) { + pipes[i].stream->link != NULL && + pipes[i].stream_res.stream_enc != NULL) { udelay(100); pipes[i].stream_res.stream_enc->funcs->dp_blank( diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 76137df74a53..349ab8017776 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -355,8 +355,8 @@ bool resource_are_streams_timing_synchronizable( != stream2->timing.v_addressable) return false; - if (stream1->timing.pix_clk_khz - != stream2->timing.pix_clk_khz) + if (stream1->timing.pix_clk_100hz + != stream2->timing.pix_clk_100hz) return false; if (stream1->clamping.c_depth != stream2->clamping.c_depth) @@ -1559,7 +1559,7 @@ static struct stream_encoder *find_first_free_match_stream_enc_for_link( { int i; int j = -1; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; for (i = 0; i < pool->stream_enc_count; i++) { if (!res_ctx->is_stream_enc_acquired[i] && @@ -1748,7 +1748,7 @@ static struct dc_stream_state *find_pll_sharable_stream( if (resource_are_streams_timing_synchronizable( stream_needs_pll, stream_has_pll) && !dc_is_dp_signal(stream_has_pll->signal) - && stream_has_pll->sink->link->connector_signal + && stream_has_pll->link->connector_signal != SIGNAL_TYPE_VIRTUAL) return stream_has_pll; @@ -1759,7 +1759,7 @@ static struct dc_stream_state *find_pll_sharable_stream( static int get_norm_pix_clk(const struct dc_crtc_timing *timing) { - uint32_t pix_clk = timing->pix_clk_khz; + uint32_t pix_clk = timing->pix_clk_100hz; uint32_t normalized_pix_clk = pix_clk; if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) @@ -1791,15 +1791,60 @@ static void calculate_phy_pix_clks(struct dc_stream_state *stream) /* update actual pixel clock on all streams */ if (dc_is_hdmi_signal(stream->signal)) stream->phy_pix_clk = get_norm_pix_clk( - &stream->timing); + &stream->timing) / 10; else stream->phy_pix_clk = - stream->timing.pix_clk_khz; + stream->timing.pix_clk_100hz / 10; if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) stream->phy_pix_clk *= 2; } +static int acquire_resource_from_hw_enabled_state( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct dc_link *link = stream->link; + unsigned int inst; + + /* Check for enabled DIG to identify enabled display */ + if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) + return -1; + + /* Check for which front end is used by this encoder. + * Note the inst is 1 indexed, where 0 is undefined. + * Note that DIG_FE can source from different OTG but our + * current implementation always map 1-to-1, so this code makes + * the same assumption and doesn't check OTG source. + */ + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + + /* Instance should be within the range of the pool */ + if (inst >= pool->pipe_count) + return -1; + + if (!res_ctx->pipe_ctx[inst].stream) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst]; + + pipe_ctx->stream_res.tg = pool->timing_generators[inst]; + pipe_ctx->plane_res.mi = pool->mis[inst]; + pipe_ctx->plane_res.hubp = pool->hubps[inst]; + pipe_ctx->plane_res.ipp = pool->ipps[inst]; + pipe_ctx->plane_res.xfm = pool->transforms[inst]; + pipe_ctx->plane_res.dpp = pool->dpps[inst]; + pipe_ctx->stream_res.opp = pool->opps[inst]; + if (pool->dpps[inst]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst; + pipe_ctx->pipe_idx = inst; + + pipe_ctx->stream = stream; + return inst; + } + + return -1; +} + enum dc_status resource_map_pool_resources( const struct dc *dc, struct dc_state *context, @@ -1824,8 +1869,15 @@ enum dc_status resource_map_pool_resources( calculate_phy_pix_clks(stream); - /* acquire new resources */ - pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); + if (stream->apply_seamless_boot_optimization) + pipe_idx = acquire_resource_from_hw_enabled_state( + &context->res_ctx, + pool, + stream); + + if (pipe_idx < 0) + /* acquire new resources */ + pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); #ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (pipe_idx < 0) @@ -1842,7 +1894,7 @@ enum dc_status resource_map_pool_resources( &context->res_ctx, pool, stream); if (!pipe_ctx->stream_res.stream_enc) - return DC_NO_STREAM_ENG_RESOURCE; + return DC_NO_STREAM_ENC_RESOURCE; update_stream_engine_usage( &context->res_ctx, pool, @@ -1850,7 +1902,7 @@ enum dc_status resource_map_pool_resources( true); /* TODO: Add check if ASIC support and EDID audio */ - if (!stream->sink->converter_disable_audio && + if (!stream->converter_disable_audio && dc_is_audio_capable_signal(pipe_ctx->stream->signal) && stream->audio_info.mode_count) { pipe_ctx->stream_res.audio = find_first_free_audio( @@ -2112,7 +2164,7 @@ static void set_avi_info_frame( itc = true; itc_value = 1; - support = stream->sink->edid_caps.content_support; + support = stream->content_support; if (itc) { if (!support.bits.valid_content_type) { @@ -2151,8 +2203,8 @@ static void set_avi_info_frame( /* TODO : We should handle YCC quantization */ /* but we do not have matrix calculation */ - if (stream->sink->edid_caps.qs_bit == 1 && - stream->sink->edid_caps.qy_bit == 1) { + if (stream->qs_bit == 1 && + stream->qy_bit == 1) { if (color_space == COLOR_SPACE_SRGB || color_space == COLOR_SPACE_2020_RGB_FULLRANGE) { hdmi_info.bits.Q0_Q1 = RGB_QUANTIZATION_FULL_RANGE; @@ -2596,7 +2648,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream) { struct dc *core_dc = dc; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct timing_generator *tg = core_dc->res_pool->timing_generators[0]; enum dc_status res = DC_OK; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c index 66e5c4623a49..996298c35f42 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -35,20 +35,17 @@ /******************************************************************************* * Private functions ******************************************************************************/ -void update_stream_signal(struct dc_stream_state *stream) +void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) { - - struct dc_sink *dc_sink = stream->sink; - - if (dc_sink->sink_signal == SIGNAL_TYPE_NONE) - stream->signal = stream->sink->link->connector_signal; + if (sink->sink_signal == SIGNAL_TYPE_NONE) + stream->signal = stream->link->connector_signal; else - stream->signal = dc_sink->sink_signal; + stream->signal = sink->sink_signal; if (dc_is_dvi_signal(stream->signal)) { if (stream->ctx->dc->caps.dual_link_dvi && - stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK && - stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) + (stream->timing.pix_clk_100hz / 10) > TMDS_MAX_PIXEL_CLOCK && + sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK) stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK; else stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK; @@ -61,10 +58,15 @@ static void construct(struct dc_stream_state *stream, uint32_t i = 0; stream->sink = dc_sink_data; - stream->ctx = stream->sink->ctx; - dc_sink_retain(dc_sink_data); + stream->ctx = dc_sink_data->ctx; + stream->link = dc_sink_data->link; + stream->sink_patches = dc_sink_data->edid_caps.panel_patch; + stream->converter_disable_audio = dc_sink_data->converter_disable_audio; + stream->qs_bit = dc_sink_data->edid_caps.qs_bit; + stream->qy_bit = dc_sink_data->edid_caps.qy_bit; + /* Copy audio modes */ /* TODO - Remove this translation */ for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++) @@ -100,11 +102,14 @@ static void construct(struct dc_stream_state *stream, /* EDID CAP translation for HDMI 2.0 */ stream->timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble; - update_stream_signal(stream); + update_stream_signal(stream, dc_sink_data); stream->out_transfer_func = dc_create_transfer_func(); stream->out_transfer_func->type = TF_TYPE_BYPASS; stream->out_transfer_func->ctx = stream->ctx; + + stream->stream_id = stream->ctx->dc_stream_id_count; + stream->ctx->dc_stream_id_count++; } static void destruct(struct dc_stream_state *stream) @@ -155,21 +160,43 @@ struct dc_stream_state *dc_create_stream_for_sink( return stream; } -struct dc_stream_status *dc_stream_get_status( +/** + * dc_stream_get_status_from_state - Get stream status from given dc state + * @state: DC state to find the stream status in + * @stream: The stream to get the stream status for + * + * The given stream is expected to exist in the given dc state. Otherwise, NULL + * will be returned. + */ +struct dc_stream_status *dc_stream_get_status_from_state( + struct dc_state *state, struct dc_stream_state *stream) { uint8_t i; - struct dc *dc = stream->ctx->dc; - for (i = 0; i < dc->current_state->stream_count; i++) { - if (stream == dc->current_state->streams[i]) - return &dc->current_state->stream_status[i]; + for (i = 0; i < state->stream_count; i++) { + if (stream == state->streams[i]) + return &state->stream_status[i]; } return NULL; } /** + * dc_stream_get_status() - Get current stream status of the given stream state + * @stream: The stream to get the stream status for. + * + * The given stream is expected to exist in dc->current_state. Otherwise, NULL + * will be returned. + */ +struct dc_stream_status *dc_stream_get_status( + struct dc_stream_state *stream) +{ + struct dc *dc = stream->ctx->dc; + return dc_stream_get_status_from_state(dc->current_state, stream); +} + +/** * dc_stream_set_cursor_attributes() - Update cursor attributes and set cursor surface address */ bool dc_stream_set_cursor_attributes( @@ -334,16 +361,12 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) stream->output_color_space); DC_LOG_DC( "\tpix_clk_khz: %d, h_total: %d, v_total: %d, pixelencoder:%d, displaycolorDepth:%d\n", - stream->timing.pix_clk_khz, + stream->timing.pix_clk_100hz / 10, stream->timing.h_total, stream->timing.v_total, stream->timing.pixel_encoding, stream->timing.display_color_depth); DC_LOG_DC( - "\tsink name: %s, serial: %d\n", - stream->sink->edid_caps.display_name, - stream->sink->edid_caps.serial_number); - DC_LOG_DC( "\tlink: %d\n", - stream->sink->link->link_index); + stream->link->link_index); } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index c60c9b4c3075..ee6bd50f60b8 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -40,11 +40,14 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state plane_state->ctx = ctx; plane_state->gamma_correction = dc_create_gamma(); - plane_state->gamma_correction->is_identity = true; + if (plane_state->gamma_correction != NULL) + plane_state->gamma_correction->is_identity = true; plane_state->in_transfer_func = dc_create_transfer_func(); - plane_state->in_transfer_func->type = TF_TYPE_BYPASS; - plane_state->in_transfer_func->ctx = ctx; + if (plane_state->in_transfer_func != NULL) { + plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + plane_state->in_transfer_func->ctx = ctx; + } } static void destruct(struct dc_plane_state *plane_state) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c new file mode 100644 index 000000000000..6ce87b682a32 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c @@ -0,0 +1,123 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "vm_helper.h" + +static void mark_vmid_used(struct vm_helper *vm_helper, unsigned int pos, uint8_t hubp_idx) +{ + struct vmid_usage vmids = vm_helper->hubp_vmid_usage[hubp_idx]; + + vmids.vmid_usage[0] = vmids.vmid_usage[1]; + vmids.vmid_usage[1] = 1 << pos; +} + +static void add_ptb_to_table(struct vm_helper *vm_helper, unsigned int vmid, uint64_t ptb) +{ + vm_helper->ptb_assigned_to_vmid[vmid] = ptb; + vm_helper->num_vmids_available--; +} + +static void clear_entry_from_vmid_table(struct vm_helper *vm_helper, unsigned int vmid) +{ + vm_helper->ptb_assigned_to_vmid[vmid] = 0; + vm_helper->num_vmids_available++; +} + +static void evict_vmids(struct vm_helper *vm_helper) +{ + int i; + uint16_t ord = 0; + + for (i = 0; i < vm_helper->num_vmid; i++) + ord |= vm_helper->hubp_vmid_usage[i].vmid_usage[0] | vm_helper->hubp_vmid_usage[i].vmid_usage[1]; + + // At this point any positions with value 0 are unused vmids, evict them + for (i = 1; i < vm_helper->num_vmid; i++) { + if (ord & (1u << i)) + clear_entry_from_vmid_table(vm_helper, i); + } +} + +// Return value of -1 indicates vmid table unitialized or ptb dne in the table +static int get_existing_vmid_for_ptb(struct vm_helper *vm_helper, uint64_t ptb) +{ + int i; + + for (i = 0; i < vm_helper->num_vmid; i++) { + if (vm_helper->ptb_assigned_to_vmid[i] == ptb) + return i; + } + + return -1; +} + +// Expected to be called only when there's an available vmid +static int get_next_available_vmid(struct vm_helper *vm_helper) +{ + int i; + + for (i = 1; i < vm_helper->num_vmid; i++) { + if (vm_helper->ptb_assigned_to_vmid[i] == 0) + return i; + } + + return -1; +} + +uint8_t get_vmid_for_ptb(struct vm_helper *vm_helper, int64_t ptb, uint8_t hubp_idx) +{ + unsigned int vmid = 0; + int vmid_exists = -1; + + // Physical address gets vmid 0 + if (ptb == 0) + return 0; + + vmid_exists = get_existing_vmid_for_ptb(vm_helper, ptb); + + if (vmid_exists != -1) { + mark_vmid_used(vm_helper, vmid_exists, hubp_idx); + vmid = vmid_exists; + } else { + if (vm_helper->num_vmids_available == 0) + evict_vmids(vm_helper); + + vmid = get_next_available_vmid(vm_helper); + mark_vmid_used(vm_helper, vmid, hubp_idx); + add_ptb_to_table(vm_helper, vmid, ptb); + } + + return vmid; +} + +void init_vm_helper(struct vm_helper *vm_helper, unsigned int num_vmid, unsigned int num_hubp) +{ + vm_helper->num_vmid = num_vmid; + vm_helper->num_hubp = num_hubp; + vm_helper->num_vmids_available = num_vmid - 1; + + memset(vm_helper->hubp_vmid_usage, 0, sizeof(vm_helper->hubp_vmid_usage[0]) * MAX_HUBP); + memset(vm_helper->ptb_assigned_to_vmid, 0, sizeof(vm_helper->ptb_assigned_to_vmid[0]) * MAX_VMID); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 4b5bbb13ce7f..1a7fd6aa77eb 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -39,7 +39,7 @@ #include "inc/hw/dmcu.h" #include "dml/display_mode_lib.h" -#define DC_VER "3.2.08" +#define DC_VER "3.2.17" #define MAX_SURFACES 3 #define MAX_STREAMS 6 @@ -255,6 +255,8 @@ struct dc_debug_options { bool scl_reset_length10; bool hdmi20_disable; bool skip_detection_link_training; + unsigned int force_odm_combine; //bit vector based on otg inst + unsigned int force_fclk_khz; }; struct dc_debug_data { @@ -263,7 +265,6 @@ struct dc_debug_data { uint32_t auxErrorCount; }; - struct dc_state; struct resource_pool; struct dce_hwseq; @@ -339,8 +340,13 @@ struct dc_init_data { uint32_t log_mask; }; -struct dc *dc_create(const struct dc_init_data *init_params); +struct dc_callback_init { + uint8_t reserved; +}; +struct dc *dc_create(const struct dc_init_data *init_params); +void dc_init_callbacks(struct dc *dc, + const struct dc_callback_init *init_params); void dc_destroy(struct dc **dc); /******************************************************************************* @@ -440,6 +446,7 @@ union surface_update_flags { uint32_t coeff_reduction_change:1; uint32_t output_tf_change:1; uint32_t pixel_format_change:1; + uint32_t plane_size_change:1; /* Full updates */ uint32_t new_plane:1; @@ -587,6 +594,10 @@ struct dc_validation_set { uint8_t plane_count; }; +bool dc_validate_seamless_boot_timing(struct dc *dc, + const struct dc_sink *sink, + struct dc_crtc_timing *crtc_timing); + enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state); void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info); @@ -652,6 +663,7 @@ struct dpcd_caps { int8_t branch_dev_name[6]; int8_t branch_hw_revision; int8_t branch_fw_revision[2]; + uint8_t link_rate_set; bool allow_invalid_MSA_timing_param; bool panel_mode_edp; @@ -742,6 +754,9 @@ void dc_set_power_state( struct dc *dc, enum dc_acpi_cm_power_state power_state); void dc_resume(struct dc *dc); +unsigned int dc_get_current_backlight_pwm(struct dc *dc); +unsigned int dc_get_target_backlight_pwm(struct dc *dc); + bool dc_is_dmcu_initialized(struct dc *dc); #endif /* DC_INTERFACE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index a8b3cedf9431..78c3b300ec45 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -86,10 +86,6 @@ struct dc_vbios_funcs { bool (*is_accelerated_mode)( struct dc_bios *bios); - bool (*is_active_display)( - struct dc_bios *bios, - enum signal_type signal, - const struct connector_device_tag_info *device_tag); void (*set_scratch_critical_state)( struct dc_bios *bios, bool state); @@ -125,10 +121,6 @@ struct dc_vbios_funcs { enum bp_result (*program_crtc_timing)( struct dc_bios *bios, struct bp_hw_crtc_timing_parameters *bp_params); - - enum bp_result (*crtc_source_select)( - struct dc_bios *bios, - struct bp_crtc_source_select *bp_params); enum bp_result (*program_display_engine_pll)( struct dc_bios *bios, struct bp_pixel_clock_parameters *bp_params); @@ -145,7 +137,6 @@ struct dc_vbios_funcs { }; struct bios_registers { - uint32_t BIOS_SCRATCH_0; uint32_t BIOS_SCRATCH_3; uint32_t BIOS_SCRATCH_6; }; diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index da93ab43f2d8..d4eab33c453b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -46,11 +46,14 @@ enum dc_lane_count { */ enum dc_link_rate { LINK_RATE_UNKNOWN = 0, - LINK_RATE_LOW = 0x06, - LINK_RATE_HIGH = 0x0A, - LINK_RATE_RBR2 = 0x0C, - LINK_RATE_HIGH2 = 0x14, - LINK_RATE_HIGH3 = 0x1E + LINK_RATE_LOW = 0x06, // Rate_1 (RBR) - 1.62 Gbps/Lane + LINK_RATE_RATE_2 = 0x08, // Rate_2 - 2.16 Gbps/Lane + LINK_RATE_RATE_3 = 0x09, // Rate_3 - 2.43 Gbps/Lane + LINK_RATE_HIGH = 0x0A, // Rate_4 (HBR) - 2.70 Gbps/Lane + LINK_RATE_RBR2 = 0x0C, // Rate_5 (RBR2)- 3.24 Gbps/Lane + LINK_RATE_RATE_6 = 0x10, // Rate_6 - 4.32 Gbps/Lane + LINK_RATE_HIGH2 = 0x14, // Rate_7 (HBR2)- 5.40 Gbps/Lane + LINK_RATE_HIGH3 = 0x1E // Rate_8 (HBR3)- 8.10 Gbps/Lane }; enum dc_link_spread { diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 4842d2378bbf..597d38393379 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -29,31 +29,59 @@ #include "dm_services.h" #include <stdarg.h> +struct dc_reg_value_masks { + uint32_t value; + uint32_t mask; +}; + +struct dc_reg_sequence { + uint32_t addr; + struct dc_reg_value_masks value_masks; +}; + +static inline void set_reg_field_value_masks( + struct dc_reg_value_masks *field_value_mask, + uint32_t value, + uint32_t mask, + uint8_t shift) +{ + ASSERT(mask != 0); + + field_value_mask->value = (field_value_mask->value & ~mask) | (mask & (value << shift)); + field_value_mask->mask = field_value_mask->mask | mask; +} + uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, uint32_t reg_val, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...) { + struct dc_reg_value_masks field_value_mask = {0}; uint32_t shift, mask, field_value; int i = 1; va_list ap; va_start(ap, field_value1); - reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1); + /* gather all bits value/mask getting updated in this register */ + set_reg_field_value_masks(&field_value_mask, + field_value1, mask1, shift1); while (i < n) { shift = va_arg(ap, uint32_t); mask = va_arg(ap, uint32_t); field_value = va_arg(ap, uint32_t); - reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift); + set_reg_field_value_masks(&field_value_mask, + field_value, mask, shift); i++; } - - dm_write_reg(ctx, addr, reg_val); va_end(ap); + + /* mmio write directly */ + reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + dm_write_reg(ctx, addr, reg_val); return reg_val; } diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h index e72fce4eca65..da55d623647a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -97,6 +97,8 @@ struct dc_plane_address { union large_integer chroma_dcc_const_color; } video_progressive; }; + + union large_integer page_table_base; }; struct dc_size { @@ -730,7 +732,7 @@ struct dc_crtc_timing { uint32_t v_front_porch; uint32_t v_sync_width; - uint32_t pix_clk_khz; + uint32_t pix_clk_100hz; uint32_t vic; uint32_t hdmi_vic; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 29f19d57ff7a..8fc223defed4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -30,6 +30,7 @@ #include "grph_object_defs.h" struct dc_link_status { + bool link_active; struct dpcd_caps *dpcd_caps; }; @@ -110,6 +111,7 @@ struct dc_link { union ddi_channel_mapping ddi_channel_mapping; struct connector_device_tag_info device_tag; struct dpcd_caps dpcd_caps; + uint32_t dongle_max_pix_clk; unsigned short chip_caps; unsigned int dpcd_sink_count; enum edp_revision edp_revision; @@ -124,6 +126,7 @@ struct dc_link { struct dc_link_status link_status; struct link_trace link_trace; + struct gpio *hpd_gpio; }; const struct dc_link_status *dc_link_get_status(const struct dc_link *dc_link); @@ -146,8 +149,7 @@ static inline struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_ */ bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t backlight_pwm_u16_16, - uint32_t frame_ramp, - const struct dc_stream_state *stream); + uint32_t frame_ramp); int dc_link_get_backlight_level(const struct dc_link *dc_link); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index be34d638e15d..a798694992b9 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -32,17 +32,18 @@ /******************************************************************************* * Stream Interfaces ******************************************************************************/ +struct timing_sync_info { + int group_id; + int group_size; + bool master; +}; struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; int plane_count; + struct timing_sync_info timing_sync_info; struct dc_plane_state *plane_states[MAX_SURFACE_NUM]; - - /* - * link this stream passes through - */ - struct dc_link *link; }; // TODO: References to this needs to be removed.. @@ -50,8 +51,20 @@ struct freesync_context { bool dummy; }; +union vline_config { + unsigned int line_number; + unsigned long long delta_in_ns; +}; + + struct dc_stream_state { + // sink is deprecated, new code should not reference + // this pointer struct dc_sink *sink; + + struct dc_link *link; + struct dc_panel_patch sink_patches; + union display_content_support content_support; struct dc_crtc_timing timing; struct dc_crtc_timing_adjust adjust; struct dc_info_packet vrr_infopacket; @@ -80,8 +93,9 @@ struct dc_stream_state { enum view_3d_format view_format; bool ignore_msa_timing_param; - - unsigned long long periodic_fn_vsync_delta; + bool converter_disable_audio; + uint8_t qs_bit; + uint8_t qy_bit; /* TODO: custom INFO packets */ /* TODO: ABM info (DMCU) */ @@ -91,7 +105,9 @@ struct dc_stream_state { /* DMCU info */ unsigned int abm_level; - unsigned int bl_pwm_level; + + union vline_config periodic_vsync_config; + union vline_config enhanced_sync_config; /* from core_stream struct */ struct dc_context *ctx; @@ -103,7 +119,8 @@ struct dc_stream_state { int phy_pix_clk; enum signal_type signal; bool dpms_off; - bool apply_edp_fast_boot_optimization; + + void *dm_stream_context; struct dc_cursor_attributes cursor_attributes; struct dc_cursor_position cursor_position; @@ -117,6 +134,21 @@ struct dc_stream_state { /* Computed state bits */ bool mode_changed : 1; + /* Output from DC when stream state is committed or altered + * DC may only access these values during: + * dc_commit_state, dc_commit_state_no_check, dc_commit_streams + * values may not change outside of those calls + */ + struct { + // For interrupt management, some hardware instance + // offsets need to be exposed to DM + uint8_t otg_offset; + } out; + + bool apply_edp_fast_boot_optimization; + bool apply_seamless_boot_optimization; + + uint32_t stream_id; }; struct dc_stream_update { @@ -126,7 +158,9 @@ struct dc_stream_update { struct dc_info_packet *hdr_static_metadata; unsigned int *abm_level; - unsigned long long *periodic_fn_vsync_delta; + union vline_config *periodic_vsync_config; + union vline_config *enhanced_sync_config; + struct dc_crtc_timing_adjust *adjust; struct dc_info_packet *vrr_infopacket; struct dc_info_packet *vsc_infopacket; @@ -163,7 +197,6 @@ void dc_commit_updates_for_stream(struct dc *dc, int surface_count, struct dc_stream_state *stream, struct dc_stream_update *stream_update, - struct dc_plane_state **plane_states, struct dc_state *state); /* * Log the current stream state. @@ -256,11 +289,14 @@ enum surface_update_type dc_check_update_surfaces_for_stream( */ struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink); -void update_stream_signal(struct dc_stream_state *stream); +void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink); void dc_stream_retain(struct dc_stream_state *dc_stream); void dc_stream_release(struct dc_stream_state *dc_stream); +struct dc_stream_status *dc_stream_get_status_from_state( + struct dc_state *state, + struct dc_stream_state *stream); struct dc_stream_status *dc_stream_get_status( struct dc_stream_state *dc_stream); diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 0b20ae23f169..da2009a108cf 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -97,8 +97,8 @@ struct dc_context { struct dc_bios *dc_bios; bool created_bios; struct gpio_service *gpio_service; - struct i2caux *i2caux; uint32_t dc_sink_id_count; + uint32_t dc_stream_id_count; uint64_t fbc_gpu_addr; }; @@ -201,6 +201,7 @@ union display_content_support { struct dc_panel_patch { unsigned int dppowerup_delay; unsigned int extra_t12_ms; + unsigned int extra_delay_backlight_off; }; struct dc_edid_caps { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 2a342eae80fd..01e56f1a9f34 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -314,8 +314,8 @@ static bool dce_abm_immediate_disable(struct abm *abm) /* setDMCUParam_ABMLevel */ REG_UPDATE_2(MASTER_COMM_CMD_REG, - MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_LEVEL_SET, - MASTER_COMM_CMD_REG_BYTE2, MCP_DISABLE_ABM_IMMEDIATELY); + MASTER_COMM_CMD_REG_BYTE0, MCP_ABM_PIPE_SET, + MASTER_COMM_CMD_REG_BYTE1, MCP_DISABLE_ABM_IMMEDIATELY); /* notifyDMCUMsg */ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index aaeb7faac0c4..4febf4ef7240 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -24,6 +24,7 @@ */ #include "dm_services.h" +#include "core_types.h" #include "dce_aux.h" #include "dce/dce_11_0_sh_mask.h" @@ -41,17 +42,17 @@ container_of((ptr), struct aux_engine_dce110, base) #define FROM_ENGINE(ptr) \ - FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base)) + FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base)) #define FROM_AUX_ENGINE_ENGINE(ptr) \ - container_of((ptr), struct aux_engine, base) + container_of((ptr), struct dce_aux, base) enum { AUX_INVALID_REPLY_RETRY_COUNTER = 1, AUX_TIMED_OUT_RETRY_COUNTER = 2, AUX_DEFER_RETRY_COUNTER = 6 }; static void release_engine( - struct aux_engine *engine) + struct dce_aux *engine) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); @@ -66,7 +67,7 @@ static void release_engine( #define DMCU_CAN_ACCESS_AUX 2 static bool is_engine_available( - struct aux_engine *engine) + struct dce_aux *engine) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); @@ -79,7 +80,7 @@ static bool is_engine_available( return (field != DMCU_CAN_ACCESS_AUX); } static bool acquire_engine( - struct aux_engine *engine) + struct dce_aux *engine) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); @@ -155,7 +156,7 @@ static bool acquire_engine( (0xFF & (address)) static void submit_channel_request( - struct aux_engine *engine, + struct dce_aux *engine, struct aux_request_transaction_data *request) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); @@ -247,7 +248,7 @@ static void submit_channel_request( REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); } -static int read_channel_reply(struct aux_engine *engine, uint32_t size, +static int read_channel_reply(struct dce_aux *engine, uint32_t size, uint8_t *buffer, uint8_t *reply_result, uint32_t *sw_status) { @@ -273,7 +274,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size, REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); reply_result_32 = reply_result_32 >> 4; - *reply_result = (uint8_t)reply_result_32; + if (reply_result != NULL) + *reply_result = (uint8_t)reply_result_32; if (reply_result_32 == 0) { /* ACK */ uint32_t i = 0; @@ -299,61 +301,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size, return 0; } -static void process_channel_reply( - struct aux_engine *engine, - struct aux_reply_transaction_data *reply) -{ - int bytes_replied; - uint8_t reply_result; - uint32_t sw_status; - - bytes_replied = read_channel_reply(engine, reply->length, reply->data, - &reply_result, &sw_status); - - /* in case HPD is LOW, exit AUX transaction */ - if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON; - return; - } - - if (bytes_replied < 0) { - /* Need to handle an error case... - * Hopefully, upper layer function won't call this function if - * the number of bytes in the reply was 0, because there was - * surely an error that was asserted that should have been - * handled for hot plug case, this could happens - */ - if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_INVALID; - ASSERT_CRITICAL(false); - return; - } - } else { - - switch (reply_result) { - case 0: /* ACK */ - reply->status = AUX_TRANSACTION_REPLY_AUX_ACK; - break; - case 1: /* NACK */ - reply->status = AUX_TRANSACTION_REPLY_AUX_NACK; - break; - case 2: /* DEFER */ - reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER; - break; - case 4: /* AUX ACK / I2C NACK */ - reply->status = AUX_TRANSACTION_REPLY_I2C_NACK; - break; - case 8: /* AUX ACK / I2C DEFER */ - reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER; - break; - default: - reply->status = AUX_TRANSACTION_REPLY_INVALID; - } - } -} - static enum aux_channel_operation_result get_channel_status( - struct aux_engine *engine, + struct dce_aux *engine, uint8_t *returned_bytes) { struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); @@ -414,469 +363,22 @@ static enum aux_channel_operation_result get_channel_status( return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; } } -static void process_read_reply( - struct aux_engine *engine, - struct read_command_context *ctx) -{ - engine->funcs->process_channel_reply(engine, &ctx->reply); - - switch (ctx->reply.status) { - case AUX_TRANSACTION_REPLY_AUX_ACK: - ctx->defer_retry_aux = 0; - if (ctx->returned_byte > ctx->current_read_length) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else if (ctx->returned_byte < ctx->current_read_length) { - ctx->current_read_length -= ctx->returned_byte; - - ctx->offset += ctx->returned_byte; - - ++ctx->invalid_reply_retry_aux_on_ack; - - if (ctx->invalid_reply_retry_aux_on_ack > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } - } else { - ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - ctx->transaction_complete = true; - ctx->operation_succeeded = true; - } - break; - case AUX_TRANSACTION_REPLY_AUX_NACK: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - ctx->operation_succeeded = false; - break; - case AUX_TRANSACTION_REPLY_AUX_DEFER: - ++ctx->defer_retry_aux; - - if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_I2C_DEFER: - ctx->defer_retry_aux = 0; - - ++ctx->defer_retry_i2c; - - if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} -static void process_read_request( - struct aux_engine *engine, - struct read_command_context *ctx) -{ - enum aux_channel_operation_result operation_result; - engine->funcs->submit_channel_request(engine, &ctx->request); - - operation_result = engine->funcs->get_channel_status( - engine, &ctx->returned_byte); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - if (ctx->returned_byte > ctx->current_read_length) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else { - ctx->timed_out_retry_aux = 0; - ctx->invalid_reply_retry_aux = 0; - - ctx->reply.length = ctx->returned_byte; - ctx->reply.data = ctx->buffer; - - process_read_reply(engine, ctx); - } - break; - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - ++ctx->invalid_reply_retry_aux; - - if (ctx->invalid_reply_retry_aux > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else - udelay(400); - break; - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - ++ctx->timed_out_retry_aux; - - if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else { - /* DP 1.2a, table 2-58: - * "S3: AUX Request CMD PENDING: - * retry 3 times, with 400usec wait on each" - * The HW timeout is set to 550usec, - * so we should not wait here - */ - } - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} -static bool read_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - struct read_command_context ctx; - - ctx.buffer = request->payload.data; - ctx.current_read_length = request->payload.length; - ctx.offset = 0; - ctx.timed_out_retry_aux = 0; - ctx.invalid_reply_retry_aux = 0; - ctx.defer_retry_aux = 0; - ctx.defer_retry_i2c = 0; - ctx.invalid_reply_retry_aux_on_ack = 0; - ctx.transaction_complete = false; - ctx.operation_succeeded = true; - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - ctx.request.type = AUX_TRANSACTION_TYPE_DP; - ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ; - ctx.request.address = request->payload.address; - } else if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { - ctx.request.type = AUX_TRANSACTION_TYPE_I2C; - ctx.request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_READ; - ctx.request.address = request->payload.address >> 1; - } else { - /* in DAL2, there was no return in such case */ - BREAK_TO_DEBUGGER(); - return false; - } - - ctx.request.delay = 0; - - do { - memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length); - - ctx.request.data = ctx.buffer + ctx.offset; - ctx.request.length = ctx.current_read_length; - - process_read_request(engine, &ctx); - - request->status = ctx.status; - - if (ctx.operation_succeeded && !ctx.transaction_complete) - if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) - msleep(engine->delay); - } while (ctx.operation_succeeded && !ctx.transaction_complete); - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d", - request->payload.address, - request->payload.data[0], - ctx.operation_succeeded); - } - - return ctx.operation_succeeded; -} - -static void process_write_reply( - struct aux_engine *engine, - struct write_command_context *ctx) -{ - engine->funcs->process_channel_reply(engine, &ctx->reply); - - switch (ctx->reply.status) { - case AUX_TRANSACTION_REPLY_AUX_ACK: - ctx->operation_succeeded = true; - - if (ctx->returned_byte) { - ctx->request.action = ctx->mot ? - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; - - ctx->current_write_length = 0; - - ++ctx->ack_m_retry; - - if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else - udelay(300); - } else { - ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - ctx->defer_retry_aux = 0; - ctx->ack_m_retry = 0; - ctx->transaction_complete = true; - } - break; - case AUX_TRANSACTION_REPLY_AUX_NACK: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - ctx->operation_succeeded = false; - break; - case AUX_TRANSACTION_REPLY_AUX_DEFER: - ++ctx->defer_retry_aux; - - if (ctx->defer_retry_aux > ctx->max_defer_retry) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_I2C_DEFER: - ctx->defer_retry_aux = 0; - ctx->current_write_length = 0; - - ctx->request.action = ctx->mot ? - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; - - ++ctx->defer_retry_i2c; - - if (ctx->defer_retry_i2c > ctx->max_defer_retry) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} -static void process_write_request( - struct aux_engine *engine, - struct write_command_context *ctx) -{ - enum aux_channel_operation_result operation_result; - - engine->funcs->submit_channel_request(engine, &ctx->request); - - operation_result = engine->funcs->get_channel_status( - engine, &ctx->returned_byte); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - ctx->timed_out_retry_aux = 0; - ctx->invalid_reply_retry_aux = 0; - - ctx->reply.length = ctx->returned_byte; - ctx->reply.data = ctx->reply_data; - - process_write_reply(engine, ctx); - break; - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - ++ctx->invalid_reply_retry_aux; - - if (ctx->invalid_reply_retry_aux > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else - udelay(400); - break; - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - ++ctx->timed_out_retry_aux; - - if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else { - /* DP 1.2a, table 2-58: - * "S3: AUX Request CMD PENDING: - * retry 3 times, with 400usec wait on each" - * The HW timeout is set to 550usec, - * so we should not wait here - */ - } - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} -static bool write_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - struct write_command_context ctx; - - ctx.mot = middle_of_transaction; - ctx.buffer = request->payload.data; - ctx.current_write_length = request->payload.length; - ctx.timed_out_retry_aux = 0; - ctx.invalid_reply_retry_aux = 0; - ctx.defer_retry_aux = 0; - ctx.defer_retry_i2c = 0; - ctx.ack_m_retry = 0; - ctx.transaction_complete = false; - ctx.operation_succeeded = true; - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - ctx.request.type = AUX_TRANSACTION_TYPE_DP; - ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE; - ctx.request.address = request->payload.address; - } else if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { - ctx.request.type = AUX_TRANSACTION_TYPE_I2C; - ctx.request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - ctx.request.address = request->payload.address >> 1; - } else { - /* in DAL2, there was no return in such case */ - BREAK_TO_DEBUGGER(); - return false; - } - - ctx.request.delay = 0; - - ctx.max_defer_retry = - (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ? - engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER; - - do { - ctx.request.data = ctx.buffer; - ctx.request.length = ctx.current_write_length; - - process_write_request(engine, &ctx); - - request->status = ctx.status; - - if (ctx.operation_succeeded && !ctx.transaction_complete) - if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) - msleep(engine->delay); - } while (ctx.operation_succeeded && !ctx.transaction_complete); - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d", - request->payload.address, - request->payload.data[0], - ctx.operation_succeeded); - } - - return ctx.operation_succeeded; -} -static bool end_of_transaction_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request) -{ - struct i2caux_transaction_request dummy_request; - uint8_t dummy_data; - - /* [tcheng] We only need to send the stop (read with MOT = 0) - * for I2C-over-Aux, not native AUX - */ - - if (request->payload.address_space != - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) - return false; - - dummy_request.operation = request->operation; - dummy_request.payload.address_space = request->payload.address_space; - dummy_request.payload.address = request->payload.address; - - /* - * Add a dummy byte due to some receiver quirk - * where one byte is sent along with MOT = 0. - * Ideally this should be 0. - */ - - dummy_request.payload.length = 0; - dummy_request.payload.data = &dummy_data; - - if (request->operation == I2CAUX_TRANSACTION_READ) - return read_command(engine, &dummy_request, false); - else - return write_command(engine, &dummy_request, false); - - /* according Syed, it does not need now DoDummyMOT */ -} -static bool submit_request( - struct aux_engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - - bool result; - bool mot_used = true; - - switch (request->operation) { - case I2CAUX_TRANSACTION_READ: - result = read_command(engine, request, mot_used); - break; - case I2CAUX_TRANSACTION_WRITE: - result = write_command(engine, request, mot_used); - break; - default: - result = false; - } - - /* [tcheng] - * need to send stop for the last transaction to free up the AUX - * if the above command fails, this would be the last transaction - */ - - if (!middle_of_transaction || !result) - end_of_transaction_command(engine, request); - - /* mask AUX interrupt */ - - return result; -} enum i2caux_engine_type get_engine_type( - const struct aux_engine *engine) + const struct dce_aux *engine) { return I2CAUX_ENGINE_TYPE_AUX; } static bool acquire( - struct aux_engine *engine, + struct dce_aux *engine, struct ddc *ddc) { enum gpio_result result; - if (engine->funcs->is_engine_available) { - /*check whether SW could use the engine*/ - if (!engine->funcs->is_engine_available(engine)) - return false; - } + if (!is_engine_available(engine)) + return false; result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, GPIO_DDC_CONFIG_TYPE_MODE_AUX); @@ -884,7 +386,7 @@ static bool acquire( if (result != GPIO_RESULT_OK) return false; - if (!engine->funcs->acquire_engine(engine)) { + if (!acquire_engine(engine)) { dal_ddc_close(ddc); return false; } @@ -894,21 +396,7 @@ static bool acquire( return true; } -static const struct aux_engine_funcs aux_engine_funcs = { - .acquire_engine = acquire_engine, - .submit_channel_request = submit_channel_request, - .process_channel_reply = process_channel_reply, - .read_channel_reply = read_channel_reply, - .get_channel_status = get_channel_status, - .is_engine_available = is_engine_available, - .release_engine = release_engine, - .destroy_engine = dce110_engine_destroy, - .submit_request = submit_request, - .get_engine_type = get_engine_type, - .acquire = acquire, -}; - -void dce110_engine_destroy(struct aux_engine **engine) +void dce110_engine_destroy(struct dce_aux **engine) { struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine); @@ -917,7 +405,7 @@ void dce110_engine_destroy(struct aux_engine **engine) *engine = NULL; } -struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, +struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110, struct dc_context *ctx, uint32_t inst, uint32_t timeout_period, @@ -927,7 +415,6 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng aux_engine110->base.ctx = ctx; aux_engine110->base.delay = 0; aux_engine110->base.max_defer_write_retry = 0; - aux_engine110->base.funcs = &aux_engine_funcs; aux_engine110->base.inst = inst; aux_engine110->timeout_period = timeout_period; aux_engine110->regs = regs; @@ -935,3 +422,101 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng return &aux_engine110->base; } +static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload) +{ + if (payload->i2c_over_aux) { + if (payload->write) { + if (payload->mot) + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT; + return I2CAUX_TRANSACTION_ACTION_I2C_WRITE; + } + if (payload->mot) + return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT; + return I2CAUX_TRANSACTION_ACTION_I2C_READ; + } + if (payload->write) + return I2CAUX_TRANSACTION_ACTION_DP_WRITE; + return I2CAUX_TRANSACTION_ACTION_DP_READ; +} + +int dce_aux_transfer(struct ddc_service *ddc, + struct aux_payload *payload) +{ + struct ddc *ddc_pin = ddc->ddc_pin; + struct dce_aux *aux_engine; + enum aux_channel_operation_result operation_result; + struct aux_request_transaction_data aux_req; + struct aux_reply_transaction_data aux_rep; + uint8_t returned_bytes = 0; + int res = -1; + uint32_t status; + + memset(&aux_req, 0, sizeof(aux_req)); + memset(&aux_rep, 0, sizeof(aux_rep)); + + aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; + acquire(aux_engine, ddc_pin); + + if (payload->i2c_over_aux) + aux_req.type = AUX_TRANSACTION_TYPE_I2C; + else + aux_req.type = AUX_TRANSACTION_TYPE_DP; + + aux_req.action = i2caux_action_from_payload(payload); + + aux_req.address = payload->address; + aux_req.delay = payload->defer_delay * 10; + aux_req.length = payload->length; + aux_req.data = payload->data; + + submit_channel_request(aux_engine, &aux_req); + operation_result = get_channel_status(aux_engine, &returned_bytes); + + switch (operation_result) { + case AUX_CHANNEL_OPERATION_SUCCEEDED: + res = read_channel_reply(aux_engine, payload->length, + payload->data, payload->reply, + &status); + break; + case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: + res = 0; + break; + case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: + case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: + case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: + res = -1; + break; + } + release_engine(aux_engine); + return res; +} + +#define AUX_RETRY_MAX 7 + +bool dce_aux_transfer_with_retries(struct ddc_service *ddc, + struct aux_payload *payload) +{ + int i, ret = 0; + uint8_t reply; + bool payload_reply = true; + + if (!payload->reply) { + payload_reply = false; + payload->reply = &reply; + } + + for (i = 0; i < AUX_RETRY_MAX; i++) { + ret = dce_aux_transfer(ddc, payload); + + if (ret >= 0) { + if (*payload->reply == 0) { + if (!payload_reply) + payload->reply = NULL; + return true; + } + } + + udelay(1000); + } + return false; +} diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h index f7caab85dc80..d27f22c05e4b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -25,7 +25,9 @@ #ifndef __DAL_AUX_ENGINE_DCE110_H__ #define __DAL_AUX_ENGINE_DCE110_H__ -#include "aux_engine.h" + +#include "i2caux_interface.h" +#include "inc/hw/aux_engine.h" #define AUX_COMMON_REG_LIST(id)\ SRI(AUX_CONTROL, DP_AUX, id), \ @@ -75,8 +77,20 @@ enum { /* This is the timeout as defined in DP 1.2a, */ SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4 }; + +struct dce_aux { + uint32_t inst; + struct ddc *ddc; + struct dc_context *ctx; + /* following values are expressed in milliseconds */ + uint32_t delay; + uint32_t max_defer_write_retry; + + bool acquire_reset; +}; + struct aux_engine_dce110 { - struct aux_engine base; + struct dce_aux base; const struct dce110_aux_registers *regs; struct { uint32_t aux_control; @@ -96,16 +110,22 @@ struct aux_engine_dce110_init_data { const struct dce110_aux_registers *regs; }; -struct aux_engine *dce110_aux_engine_construct( +struct dce_aux *dce110_aux_engine_construct( struct aux_engine_dce110 *aux_engine110, struct dc_context *ctx, uint32_t inst, uint32_t timeout_period, const struct dce110_aux_registers *regs); -void dce110_engine_destroy(struct aux_engine **engine); +void dce110_engine_destroy(struct dce_aux **engine); bool dce110_aux_engine_acquire( - struct aux_engine *aux_engine, + struct dce_aux *aux_engine, struct ddc *ddc); + +int dce_aux_transfer(struct ddc_service *ddc, + struct aux_payload *cmd); + +bool dce_aux_transfer_with_retries(struct ddc_service *ddc, + struct aux_payload *cmd); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c index afd287f08bc9..3c52a4fc921d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c @@ -194,8 +194,8 @@ static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context) if (pipe_ctx->top_pipe) continue; - if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk) - max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 > max_pix_clk) + max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10; /* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS * logic for HBR3 still needs Nominal (0.8V) on VDDC rail @@ -257,7 +257,7 @@ static int dce_set_clock( clk_mgr_dce->dentist_vco_freq_khz / 64); /* Prepare to program display clock*/ - pxl_clk_params.target_pixel_clock = requested_clk_khz; + pxl_clk_params.target_pixel_clock_100hz = requested_clk_khz * 10; pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS; if (clk_mgr_dce->dfs_bypass_active) @@ -450,6 +450,42 @@ void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce) } } +/** + * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info + * @clk_mgr: clock manager base structure + * + * Reads from VBIOS the XGMI spread spectrum info and saves it within + * the dce clock manager. This operation will overwrite the existing dprefclk + * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also + * sets the ->xgmi_enabled flag. + */ +void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr) +{ + struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); + enum bp_result result; + struct spread_spectrum_info info = { { 0 } }; + struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios; + + clk_mgr_dce->xgmi_enabled = false; + + result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI, + 0, &info); + if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) { + clk_mgr_dce->xgmi_enabled = true; + clk_mgr_dce->ss_on_dprefclk = true; + clk_mgr_dce->dprefclk_ss_divider = + info.spread_percentage_divider; + + if (info.type.CENTER_MODE == 0) { + /* Currently for DP Reference clock we + * need only SS percentage for + * downspread */ + clk_mgr_dce->dprefclk_ss_percentage = + info.spread_spectrum_percentage; + } + } +} + void dce110_fill_display_configs( const struct dc_state *context, struct dm_pp_display_configuration *pp_display_cfg) @@ -483,18 +519,18 @@ void dce110_fill_display_configs( cfg->src_height = stream->src.height; cfg->src_width = stream->src.width; cfg->ddi_channel_mapping = - stream->sink->link->ddi_channel_mapping.raw; + stream->link->ddi_channel_mapping.raw; cfg->transmitter = - stream->sink->link->link_enc->transmitter; + stream->link->link_enc->transmitter; cfg->link_settings.lane_count = - stream->sink->link->cur_link_settings.lane_count; + stream->link->cur_link_settings.lane_count; cfg->link_settings.link_rate = - stream->sink->link->cur_link_settings.link_rate; + stream->link->cur_link_settings.link_rate; cfg->link_settings.link_spread = - stream->sink->link->cur_link_settings.link_spread; + stream->link->cur_link_settings.link_spread; cfg->sym_clock = stream->phy_pix_clk; /* Round v_refresh*/ - cfg->v_refresh = stream->timing.pix_clk_khz * 1000; + cfg->v_refresh = stream->timing.pix_clk_100hz * 100; cfg->v_refresh /= stream->timing.h_total; cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2) / stream->timing.v_total; @@ -518,7 +554,7 @@ static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context) - stream->timing.v_addressable); vertical_blank_time = vertical_blank_in_pixels - * 1000 / stream->timing.pix_clk_khz; + * 10000 / stream->timing.pix_clk_100hz; if (min_vertical_blank_time > vertical_blank_time) min_vertical_blank_time = vertical_blank_time; @@ -612,7 +648,7 @@ static void dce11_pplib_apply_display_requirements( pp_display_cfg->crtc_index = pp_display_cfg->disp_configs[0].pipe_idx; - pp_display_cfg->line_time_in_us = timing->h_total * 1000 / timing->pix_clk_khz; + pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz; } if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0) @@ -625,11 +661,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr, { struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); struct dm_pp_power_level_change_request level_change_req; - int unpatched_disp_clk = context->bw.dce.dispclk_khz; + int patched_disp_clk = context->bw.dce.dispclk_khz; /*TODO: W/A for dal3 linux, investigate why this works */ if (!clk_mgr_dce->dfs_bypass_active) - context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + patched_disp_clk = patched_disp_clk * 115 / 100; level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context); /* get max clock state from PPLIB */ @@ -639,13 +675,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr, clk_mgr_dce->cur_min_clks_state = level_change_req.power_level; } - if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) { - context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz); - clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz; + if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) { + patched_disp_clk = dce_set_clock(clk_mgr, patched_disp_clk); + clk_mgr->clks.dispclk_khz = patched_disp_clk; } dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context); - - context->bw.dce.dispclk_khz = unpatched_disp_clk; } static void dce11_update_clocks(struct clk_mgr *clk_mgr, @@ -676,11 +710,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr, { struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); struct dm_pp_power_level_change_request level_change_req; - int unpatched_disp_clk = context->bw.dce.dispclk_khz; + int patched_disp_clk = context->bw.dce.dispclk_khz; /*TODO: W/A for dal3 linux, investigate why this works */ if (!clk_mgr_dce->dfs_bypass_active) - context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + patched_disp_clk = patched_disp_clk * 115 / 100; level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context); /* get max clock state from PPLIB */ @@ -690,13 +724,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr, clk_mgr_dce->cur_min_clks_state = level_change_req.power_level; } - if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) { - context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz); - clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz; + if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) { + patched_disp_clk = dce112_set_clock(clk_mgr, patched_disp_clk); + clk_mgr->clks.dispclk_khz = patched_disp_clk; } dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context); - - context->bw.dce.dispclk_khz = unpatched_disp_clk; } static void dce12_update_clocks(struct clk_mgr *clk_mgr, @@ -706,17 +738,23 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr, struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr); struct dm_pp_clock_for_voltage_req clock_voltage_req = {0}; int max_pix_clk = get_max_pixel_clock_for_all_paths(context); - int unpatched_disp_clk = context->bw.dce.dispclk_khz; + int patched_disp_clk = context->bw.dce.dispclk_khz; /*TODO: W/A for dal3 linux, investigate why this works */ if (!clk_mgr_dce->dfs_bypass_active) - context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100; + patched_disp_clk = patched_disp_clk * 115 / 100; - if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) { + if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) { clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK; - clock_voltage_req.clocks_in_khz = context->bw.dce.dispclk_khz; - context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz); - clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz; + /* + * When xGMI is enabled, the display clk needs to be adjusted + * with the WAFL link's SS percentage. + */ + if (clk_mgr_dce->xgmi_enabled) + patched_disp_clk = clk_mgr_adjust_dp_ref_freq_for_ss( + clk_mgr_dce, patched_disp_clk); + clock_voltage_req.clocks_in_khz = patched_disp_clk; + clk_mgr->clks.dispclk_khz = dce112_set_clock(clk_mgr, patched_disp_clk); dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req); } @@ -729,8 +767,6 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr, dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req); } dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context); - - context->bw.dce.dispclk_khz = unpatched_disp_clk; } static const struct clk_mgr_funcs dce120_funcs = { @@ -882,6 +918,27 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx) return &clk_mgr_dce->base; } +struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx) +{ + struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce), + GFP_KERNEL); + + if (clk_mgr_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + memcpy(clk_mgr_dce->max_clks_by_state, dce120_max_clks_by_state, + sizeof(dce120_max_clks_by_state)); + + dce_clk_mgr_construct(clk_mgr_dce, ctx, NULL, NULL, NULL); + + clk_mgr_dce->dprefclk_khz = 625000; + clk_mgr_dce->base.funcs = &dce120_funcs; + + return &clk_mgr_dce->base; +} + void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr) { struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h index 3bceb31d910d..c8f8c442142a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h @@ -94,11 +94,37 @@ struct dce_clk_mgr { * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */ int dfs_bypass_disp_clk; - /* Flag for Enabled SS on DPREFCLK */ + /** + * @ss_on_dprefclk: + * + * True if spread spectrum is enabled on the DP ref clock. + */ bool ss_on_dprefclk; - /* DPREFCLK SS percentage (if down-spread enabled) */ + + /** + * @xgmi_enabled: + * + * True if xGMI is enabled. On VG20, both audio and display clocks need + * to be adjusted with the WAFL link's SS info if xGMI is enabled. + */ + bool xgmi_enabled; + + /** + * @dprefclk_ss_percentage: + * + * DPREFCLK SS percentage (if down-spread enabled). + * + * Note that if XGMI is enabled, the SS info (percentage and divider) + * from the WAFL link is used instead. This is decided during + * dce_clk_mgr initialization. + */ int dprefclk_ss_percentage; - /* DPREFCLK SS percentage Divider (100 or 1000) */ + + /** + * @dprefclk_ss_divider: + * + * DPREFCLK SS percentage Divider (100 or 1000). + */ int dprefclk_ss_divider; int dprefclk_khz; @@ -163,6 +189,9 @@ struct clk_mgr *dce112_clk_mgr_create( struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx); +struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx); +void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr); + void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr); int dentist_get_divider_from_did(int did); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 723ce80ed89c..71d5777de961 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -108,28 +108,28 @@ static const struct spread_spectrum_data *get_ss_data_entry( } /** -* Function: calculate_fb_and_fractional_fb_divider -* -* * DESCRIPTION: Calculates feedback and fractional feedback dividers values -* -*PARAMETERS: -* targetPixelClock Desired frequency in 10 KHz -* ref_divider Reference divider (already known) -* postDivider Post Divider (already known) -* feedback_divider_param Pointer where to store -* calculated feedback divider value -* fract_feedback_divider_param Pointer where to store -* calculated fract feedback divider value -* -*RETURNS: -* It fills the locations pointed by feedback_divider_param -* and fract_feedback_divider_param -* It returns - true if feedback divider not 0 -* - false should never happen) -*/ + * Function: calculate_fb_and_fractional_fb_divider + * + * * DESCRIPTION: Calculates feedback and fractional feedback dividers values + * + *PARAMETERS: + * targetPixelClock Desired frequency in 100 Hz + * ref_divider Reference divider (already known) + * postDivider Post Divider (already known) + * feedback_divider_param Pointer where to store + * calculated feedback divider value + * fract_feedback_divider_param Pointer where to store + * calculated fract feedback divider value + * + *RETURNS: + * It fills the locations pointed by feedback_divider_param + * and fract_feedback_divider_param + * It returns - true if feedback divider not 0 + * - false should never happen) + */ static bool calculate_fb_and_fractional_fb_divider( struct calc_pll_clock_source *calc_pll_cs, - uint32_t target_pix_clk_khz, + uint32_t target_pix_clk_100hz, uint32_t ref_divider, uint32_t post_divider, uint32_t *feedback_divider_param, @@ -138,11 +138,11 @@ static bool calculate_fb_and_fractional_fb_divider( uint64_t feedback_divider; feedback_divider = - (uint64_t)target_pix_clk_khz * ref_divider * post_divider; + (uint64_t)target_pix_clk_100hz * ref_divider * post_divider; feedback_divider *= 10; /* additional factor, since we divide by 10 afterwards */ feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor); - feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz); + feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull); /*Round to the number of precision * The following code replace the old code (ullfeedbackDivider + 5)/10 @@ -195,36 +195,36 @@ static bool calc_fb_divider_checking_tolerance( { uint32_t feedback_divider; uint32_t fract_feedback_divider; - uint32_t actual_calculated_clock_khz; + uint32_t actual_calculated_clock_100hz; uint32_t abs_err; - uint64_t actual_calc_clk_khz; + uint64_t actual_calc_clk_100hz; calculate_fb_and_fractional_fb_divider( calc_pll_cs, - pll_settings->adjusted_pix_clk, + pll_settings->adjusted_pix_clk_100hz, ref_divider, post_divider, &feedback_divider, &fract_feedback_divider); /*Actual calculated value*/ - actual_calc_clk_khz = (uint64_t)feedback_divider * + actual_calc_clk_100hz = (uint64_t)feedback_divider * calc_pll_cs->fract_fb_divider_factor + fract_feedback_divider; - actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz; - actual_calc_clk_khz = - div_u64(actual_calc_clk_khz, + actual_calc_clk_100hz *= calc_pll_cs->ref_freq_khz * 10; + actual_calc_clk_100hz = + div_u64(actual_calc_clk_100hz, ref_divider * post_divider * calc_pll_cs->fract_fb_divider_factor); - actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz); + actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz); - abs_err = (actual_calculated_clock_khz > - pll_settings->adjusted_pix_clk) - ? actual_calculated_clock_khz - - pll_settings->adjusted_pix_clk - : pll_settings->adjusted_pix_clk - - actual_calculated_clock_khz; + abs_err = (actual_calculated_clock_100hz > + pll_settings->adjusted_pix_clk_100hz) + ? actual_calculated_clock_100hz - + pll_settings->adjusted_pix_clk_100hz + : pll_settings->adjusted_pix_clk_100hz - + actual_calculated_clock_100hz; if (abs_err <= tolerance) { /*found good values*/ @@ -233,10 +233,10 @@ static bool calc_fb_divider_checking_tolerance( pll_settings->feedback_divider = feedback_divider; pll_settings->fract_feedback_divider = fract_feedback_divider; pll_settings->pix_clk_post_divider = post_divider; - pll_settings->calculated_pix_clk = - actual_calculated_clock_khz; + pll_settings->calculated_pix_clk_100hz = + actual_calculated_clock_100hz; pll_settings->vco_freq = - actual_calculated_clock_khz * post_divider; + actual_calculated_clock_100hz * post_divider / 10; return true; } return false; @@ -257,8 +257,8 @@ static bool calc_pll_dividers_in_range( /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25% * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/ - tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) / - 10000; + tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) / + 100000; if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE) tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE; @@ -294,7 +294,7 @@ static uint32_t calculate_pixel_clock_pll_dividers( uint32_t min_ref_divider; uint32_t max_ref_divider; - if (pll_settings->adjusted_pix_clk == 0) { + if (pll_settings->adjusted_pix_clk_100hz == 0) { DC_LOG_ERROR( "%s Bad requested pixel clock", __func__); return MAX_PLL_CALC_ERROR; @@ -306,21 +306,21 @@ static uint32_t calculate_pixel_clock_pll_dividers( max_post_divider = pll_settings->pix_clk_post_divider; } else { min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider; - if (min_post_divider * pll_settings->adjusted_pix_clk < - calc_pll_cs->min_vco_khz) { - min_post_divider = calc_pll_cs->min_vco_khz / - pll_settings->adjusted_pix_clk; + if (min_post_divider * pll_settings->adjusted_pix_clk_100hz < + calc_pll_cs->min_vco_khz * 10) { + min_post_divider = calc_pll_cs->min_vco_khz * 10 / + pll_settings->adjusted_pix_clk_100hz; if ((min_post_divider * - pll_settings->adjusted_pix_clk) < - calc_pll_cs->min_vco_khz) + pll_settings->adjusted_pix_clk_100hz) < + calc_pll_cs->min_vco_khz * 10) min_post_divider++; } max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider; - if (max_post_divider * pll_settings->adjusted_pix_clk - > calc_pll_cs->max_vco_khz) - max_post_divider = calc_pll_cs->max_vco_khz / - pll_settings->adjusted_pix_clk; + if (max_post_divider * pll_settings->adjusted_pix_clk_100hz + > calc_pll_cs->max_vco_khz * 10) + max_post_divider = calc_pll_cs->max_vco_khz * 10 / + pll_settings->adjusted_pix_clk_100hz; } /* 2) Find Reference divider ranges @@ -392,47 +392,47 @@ static bool pll_adjust_pix_clk( struct pixel_clk_params *pix_clk_params, struct pll_settings *pll_settings) { - uint32_t actual_pix_clk_khz = 0; - uint32_t requested_clk_khz = 0; + uint32_t actual_pix_clk_100hz = 0; + uint32_t requested_clk_100hz = 0; struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = { 0 }; enum bp_result bp_result; switch (pix_clk_params->signal_type) { case SIGNAL_TYPE_HDMI_TYPE_A: { - requested_clk_khz = pix_clk_params->requested_pix_clk; + requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz; if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) { switch (pix_clk_params->color_depth) { case COLOR_DEPTH_101010: - requested_clk_khz = (requested_clk_khz * 5) >> 2; + requested_clk_100hz = (requested_clk_100hz * 5) >> 2; break; /* x1.25*/ case COLOR_DEPTH_121212: - requested_clk_khz = (requested_clk_khz * 6) >> 2; + requested_clk_100hz = (requested_clk_100hz * 6) >> 2; break; /* x1.5*/ case COLOR_DEPTH_161616: - requested_clk_khz = requested_clk_khz * 2; + requested_clk_100hz = requested_clk_100hz * 2; break; /* x2.0*/ default: break; } } - actual_pix_clk_khz = requested_clk_khz; + actual_pix_clk_100hz = requested_clk_100hz; } break; case SIGNAL_TYPE_DISPLAY_PORT: case SIGNAL_TYPE_DISPLAY_PORT_MST: case SIGNAL_TYPE_EDP: - requested_clk_khz = pix_clk_params->requested_sym_clk; - actual_pix_clk_khz = pix_clk_params->requested_pix_clk; + requested_clk_100hz = pix_clk_params->requested_sym_clk * 10; + actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz; break; default: - requested_clk_khz = pix_clk_params->requested_pix_clk; - actual_pix_clk_khz = pix_clk_params->requested_pix_clk; + requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz; + actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz; break; } - bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz; + bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10; bp_adjust_pixel_clock_params. encoder_object_id = pix_clk_params->encoder_object_id; bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type; @@ -441,9 +441,9 @@ static bool pll_adjust_pix_clk( bp_result = clk_src->bios->funcs->adjust_pixel_clock( clk_src->bios, &bp_adjust_pixel_clock_params); if (bp_result == BP_RESULT_OK) { - pll_settings->actual_pix_clk = actual_pix_clk_khz; - pll_settings->adjusted_pix_clk = - bp_adjust_pixel_clock_params.adjusted_pixel_clock; + pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz; + pll_settings->adjusted_pix_clk_100hz = + bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10; pll_settings->reference_divider = bp_adjust_pixel_clock_params.reference_divider; pll_settings->pix_clk_post_divider = @@ -490,7 +490,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper ( const struct spread_spectrum_data *ss_data = get_ss_data_entry( clk_src, pix_clk_params->signal_type, - pll_settings->adjusted_pix_clk); + pll_settings->adjusted_pix_clk_100hz / 10); if (NULL != ss_data) pll_settings->ss_percentage = ss_data->percentage; @@ -502,13 +502,13 @@ static uint32_t dce110_get_pix_clk_dividers_helper ( * to continue. */ DC_LOG_ERROR( "%s: Failed to adjust pixel clock!!", __func__); - pll_settings->actual_pix_clk = - pix_clk_params->requested_pix_clk; - pll_settings->adjusted_pix_clk = - pix_clk_params->requested_pix_clk; + pll_settings->actual_pix_clk_100hz = + pix_clk_params->requested_pix_clk_100hz; + pll_settings->adjusted_pix_clk_100hz = + pix_clk_params->requested_pix_clk_100hz; if (dc_is_dp_signal(pix_clk_params->signal_type)) - pll_settings->adjusted_pix_clk = 100000; + pll_settings->adjusted_pix_clk_100hz = 1000000; } /* Calculate Dividers */ @@ -533,28 +533,28 @@ static void dce112_get_pix_clk_dividers_helper ( struct pll_settings *pll_settings, struct pixel_clk_params *pix_clk_params) { - uint32_t actualPixelClockInKHz; + uint32_t actual_pixel_clock_100hz; - actualPixelClockInKHz = pix_clk_params->requested_pix_clk; + actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz; /* 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; + actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2; break; case COLOR_DEPTH_121212: - actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2; + actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2; break; case COLOR_DEPTH_161616: - actualPixelClockInKHz = actualPixelClockInKHz * 2; + actual_pixel_clock_100hz = actual_pixel_clock_100hz * 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; + pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz; + pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz; + pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz; } static uint32_t dce110_get_pix_clk_dividers( @@ -567,7 +567,7 @@ static uint32_t dce110_get_pix_clk_dividers( DC_LOGGER_INIT(); if (pix_clk_params == NULL || pll_settings == NULL - || pix_clk_params->requested_pix_clk == 0) { + || pix_clk_params->requested_pix_clk_100hz == 0) { DC_LOG_ERROR( "%s: Invalid parameters!!\n", __func__); return pll_calc_error; @@ -577,10 +577,10 @@ static uint32_t dce110_get_pix_clk_dividers( if (cs->id == CLOCK_SOURCE_ID_DP_DTO || cs->id == CLOCK_SOURCE_ID_EXTERNAL) { - 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; + pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10; + pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10; + pll_settings->actual_pix_clk_100hz = + pix_clk_params->requested_pix_clk_100hz; return 0; } @@ -599,7 +599,7 @@ static uint32_t dce112_get_pix_clk_dividers( DC_LOGGER_INIT(); if (pix_clk_params == NULL || pll_settings == NULL - || pix_clk_params->requested_pix_clk == 0) { + || pix_clk_params->requested_pix_clk_100hz == 0) { DC_LOG_ERROR( "%s: Invalid parameters!!\n", __func__); return -1; @@ -609,10 +609,10 @@ static uint32_t dce112_get_pix_clk_dividers( if (cs->id == CLOCK_SOURCE_ID_DP_DTO || cs->id == CLOCK_SOURCE_ID_EXTERNAL) { - 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; + pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10; + pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10; + pll_settings->actual_pix_clk_100hz = + pix_clk_params->requested_pix_clk_100hz; return -1; } @@ -714,7 +714,7 @@ static bool enable_spread_spectrum( ss_data = get_ss_data_entry( clk_src, signal, - pll_settings->calculated_pix_clk); + pll_settings->calculated_pix_clk_100hz / 10); /* Pixel clock PLL has been programmed to generate desired pixel clock, * now enable SS on pixel clock */ @@ -853,7 +853,7 @@ static bool dce110_program_pix_clk( /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/ bp_pc_params.controller_id = pix_clk_params->controller_id; bp_pc_params.pll_id = clock_source->id; - bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk; + bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz; bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id; bp_pc_params.signal_type = pix_clk_params->signal_type; @@ -903,12 +903,12 @@ static bool dce112_program_pix_clk( #if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; - unsigned dp_dto_ref_kHz = 700000; - unsigned clock_kHz = pll_settings->actual_pix_clk; + unsigned dp_dto_ref_100hz = 7000000; + unsigned clock_100hz = pll_settings->actual_pix_clk_100hz; /* Set DTO values: phase = target clock, modulo = reference clock */ - REG_WRITE(PHASE[inst], clock_kHz); - REG_WRITE(MODULO[inst], dp_dto_ref_kHz); + REG_WRITE(PHASE[inst], clock_100hz); + REG_WRITE(MODULO[inst], dp_dto_ref_100hz); /* Enable DTO */ REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1); @@ -927,7 +927,7 @@ static bool dce112_program_pix_clk( /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/ bp_pc_params.controller_id = pix_clk_params->controller_id; bp_pc_params.pll_id = clock_source->id; - bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk; + bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz; bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id; bp_pc_params.signal_type = pix_clk_params->signal_type; @@ -977,6 +977,28 @@ static bool dce110_clock_source_power_down( return bp_result == BP_RESULT_OK; } +static bool get_pixel_clk_frequency_100hz( + struct clock_source *clock_source, + unsigned int inst, + unsigned int *pixel_clk_khz) +{ + struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); + unsigned int clock_hz = 0; + + if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) { + clock_hz = REG_READ(PHASE[inst]); + + /* NOTE: There is agreement with VBIOS here that MODULO is + * programmed equal to DPREFCLK, in which case PHASE will be + * equivalent to pixel clock. + */ + *pixel_clk_khz = clock_hz / 100; + return true; + } + + return false; +} + /*****************************************/ /* Constructor */ /*****************************************/ @@ -984,12 +1006,14 @@ static bool dce110_clock_source_power_down( static const struct clock_source_funcs dce112_clk_src_funcs = { .cs_power_down = dce110_clock_source_power_down, .program_pix_clk = dce112_program_pix_clk, - .get_pix_clk_dividers = dce112_get_pix_clk_dividers + .get_pix_clk_dividers = dce112_get_pix_clk_dividers, + .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; static const struct clock_source_funcs dce110_clk_src_funcs = { .cs_power_down = dce110_clock_source_power_down, .program_pix_clk = dce110_program_pix_clk, - .get_pix_clk_dividers = dce110_get_pix_clk_dividers + .get_pix_clk_dividers = dce110_get_pix_clk_dividers, + .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index dea40b322191..c2926cf19dee 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -51,7 +51,6 @@ #define PSR_SET_WAITLOOP 0x31 #define MCP_INIT_DMCU 0x88 #define MCP_INIT_IRAM 0x89 -#define MCP_DMCU_VERSION 0x90 #define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L static bool dce_dmcu_init(struct dmcu *dmcu) @@ -317,38 +316,11 @@ static void dce_get_psr_wait_loop( } #if defined(CONFIG_DRM_AMD_DC_DCN1_0) -static void dcn10_get_dmcu_state(struct dmcu *dmcu) -{ - struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); - uint32_t dmcu_state_offset = 0xf6; - - /* Enable write access to IRAM */ - REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, - IRAM_HOST_ACCESS_EN, 1, - IRAM_RD_ADDR_AUTO_INC, 1); - - REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10); - - /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */ - REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_state_offset); - - /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/ - dmcu->dmcu_state = REG_READ(DMCU_IRAM_RD_DATA); - - /* Disable write access to IRAM to allow dynamic sleep state */ - REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, - IRAM_HOST_ACCESS_EN, 0, - IRAM_RD_ADDR_AUTO_INC, 0); -} - static void dcn10_get_dmcu_version(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); uint32_t dmcu_version_offset = 0xf1; - /* Clear scratch */ - REG_WRITE(DC_DMCU_SCRATCH, 0); - /* Enable write access to IRAM */ REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 1, @@ -359,85 +331,74 @@ static void dcn10_get_dmcu_version(struct dmcu *dmcu) /* Write address to IRAM_RD_ADDR and read from DATA register */ REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset); dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA); - dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) | + dmcu->dmcu_version.abm_version = REG_READ(DMCU_IRAM_RD_DATA); + dmcu->dmcu_version.psr_version = REG_READ(DMCU_IRAM_RD_DATA); + dmcu->dmcu_version.build_version = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) | REG_READ(DMCU_IRAM_RD_DATA)); - dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA); - dmcu->dmcu_version.date = REG_READ(DMCU_IRAM_RD_DATA); /* Disable write access to IRAM to allow dynamic sleep state */ REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL, IRAM_HOST_ACCESS_EN, 0, IRAM_RD_ADDR_AUTO_INC, 0); - - /* Send MCP command message to DMCU to get version reply from FW. - * We expect this version should match the one in IRAM, otherwise - * something is wrong with DMCU and we should fail and disable UC. - */ - REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); - - /* Set command to get DMCU version from microcontroller */ - REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, - MCP_DMCU_VERSION); - - /* Notify microcontroller of new command */ - REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); - - /* Ensure command has been executed before continuing */ - REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); - - /* Somehow version does not match, so fail and return version 0 */ - if (dmcu->dmcu_version.interface_version != REG_READ(DC_DMCU_SCRATCH)) - dmcu->dmcu_version.interface_version = 0; } static bool dcn10_dmcu_init(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); + bool status = false; - /* DMCU FW should populate the scratch register if running */ - if (REG_READ(DC_DMCU_SCRATCH) == 0) - return false; - - /* Check state is uninitialized */ - dcn10_get_dmcu_state(dmcu); - - /* If microcontroller is already initialized, do nothing */ - if (dmcu->dmcu_state == DMCU_RUNNING) - return true; - - /* Retrieve and cache the DMCU firmware version. */ - dcn10_get_dmcu_version(dmcu); - - /* Check interface version to confirm firmware is loaded and running */ - if (dmcu->dmcu_version.interface_version == 0) - return false; + /* Definition of DC_DMCU_SCRATCH + * 0 : firmare not loaded + * 1 : PSP load DMCU FW but not initialized + * 2 : Firmware already initialized + */ + dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH); - /* Wait until microcontroller is ready to process interrupt */ - REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); + switch (dmcu->dmcu_state) { + case DMCU_UNLOADED: + status = false; + break; + case DMCU_LOADED_UNINITIALIZED: + /* Wait until microcontroller is ready to process interrupt */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); - /* Set initialized ramping boundary value */ - REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF); + /* Set initialized ramping boundary value */ + REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF); - /* Set command to initialize microcontroller */ - REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, + /* Set command to initialize microcontroller */ + REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_INIT_DMCU); - /* Notify microcontroller of new command */ - REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + /* Notify microcontroller of new command */ + REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); - /* Ensure command has been executed before continuing */ - REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); + /* Ensure command has been executed before continuing */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800); - // Check state is initialized - dcn10_get_dmcu_state(dmcu); + // Check state is initialized + dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH); - // If microcontroller is not in running state, fail - if (dmcu->dmcu_state != DMCU_RUNNING) - return false; + // If microcontroller is not in running state, fail + if (dmcu->dmcu_state == DMCU_RUNNING) { + /* Retrieve and cache the DMCU firmware version. */ + dcn10_get_dmcu_version(dmcu); + status = true; + } else + status = false; - return true; + break; + case DMCU_RUNNING: + status = true; + break; + default: + status = false; + break; + } + + return status; } + static bool dcn10_dmcu_load_iram(struct dmcu *dmcu, unsigned int start_offset, const char *src, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h index c83a7f05f14c..956bdf14503f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -133,6 +133,10 @@ SR(DCHUB_AGP_TOP), \ BL_REG_LIST() +#define HWSEQ_VG20_REG_LIST() \ + HWSEQ_DCE120_REG_LIST(),\ + MMHUB_SR(MC_VM_XGMI_LFB_CNTL) + #define HWSEQ_DCE112_REG_LIST() \ HWSEQ_DCE10_REG_LIST(), \ HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \ @@ -298,6 +302,7 @@ struct dce_hwseq_registers { uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR; uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR; + uint32_t MC_VM_XGMI_LFB_CNTL; uint32_t AZALIA_AUDIO_DTO; uint32_t AZALIA_CONTROLLER_CLOCK_GATING; }; @@ -382,6 +387,11 @@ struct dce_hwseq_registers { HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) +#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\ + HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\ + HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh) + #define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\ HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \ @@ -470,6 +480,8 @@ struct dce_hwseq_registers { type PHYSICAL_PAGE_NUMBER_MSB;\ type PHYSICAL_PAGE_NUMBER_LSB;\ type LOGICAL_ADDR; \ + type PF_LFB_REGION;\ + type PF_MAX_REGION;\ type ENABLE_L1_TLB;\ type SYSTEM_ACCESS_MODE;\ type LVTMA_BLON;\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c index 3e18ea84b1f9..314c04a915d2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c @@ -599,12 +599,12 @@ bool dce110_link_encoder_validate_dvi_output( if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK || connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) && signal != SIGNAL_TYPE_HDMI_TYPE_A && - crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK) + crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK * 10)) return false; - if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK) + if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10)) return false; - if (crtc_timing->pix_clk_khz > max_pixel_clock) + if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10)) return false; /* DVI supports 6/8bpp single-link and 10/16bpp dual-link */ @@ -788,7 +788,7 @@ bool dce110_link_encoder_validate_output_with_stream( case SIGNAL_TYPE_DVI_DUAL_LINK: is_valid = dce110_link_encoder_validate_dvi_output( enc110, - stream->sink->link->connector_signal, + stream->link->connector_signal, stream->signal, &stream->timing); break; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index cce0d18f91da..1fa2d4fd7a35 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -288,9 +288,18 @@ static void dce110_stream_encoder_dp_set_stream_attribute( #endif struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); - + struct dc_crtc_timing hw_crtc_timing = *crtc_timing; + if (hw_crtc_timing.flags.INTERLACE) { + /*the input timing is in VESA spec format with Interlace flag =1*/ + hw_crtc_timing.v_total /= 2; + hw_crtc_timing.v_border_top /= 2; + hw_crtc_timing.v_addressable /= 2; + hw_crtc_timing.v_border_bottom /= 2; + hw_crtc_timing.v_front_porch /= 2; + hw_crtc_timing.v_sync_width /= 2; + } /* set pixel encoding */ - switch (crtc_timing->pixel_encoding) { + switch (hw_crtc_timing.pixel_encoding) { case PIXEL_ENCODING_YCBCR422: REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_TYPE_YCBCR422); @@ -299,8 +308,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute( REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING, DP_PIXEL_ENCODING_TYPE_YCBCR444); - if (crtc_timing->flags.Y_ONLY) - if (crtc_timing->display_color_depth != COLOR_DEPTH_666) + if (hw_crtc_timing.flags.Y_ONLY) + if (hw_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 */ @@ -335,7 +344,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( /* set color depth */ - switch (crtc_timing->display_color_depth) { + switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666: REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH, 0); @@ -363,7 +372,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( #if defined(CONFIG_DRM_AMD_DC_DCN1_0) - switch (crtc_timing->display_color_depth) { + switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; break; @@ -401,9 +410,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute( misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ dynamic_range_ycbcr = 0; /*bt601*/ - if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ - else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) + else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_YCBCR709: @@ -411,9 +420,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute( misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ dynamic_range_ycbcr = 1; /*bt709*/ - if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ - else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) + else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_2020_RGB_LIMITEDRANGE: @@ -453,27 +462,27 @@ static void dce110_stream_encoder_dp_set_stream_attribute( */ 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); + DP_MSA_HTOTAL, hw_crtc_timing.h_total, + DP_MSA_VTOTAL, hw_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_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left - + hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right; - h_back_porch = h_blank - crtc_timing->h_front_porch - - crtc_timing->h_sync_width; + h_back_porch = h_blank - hw_crtc_timing.h_front_porch - + hw_crtc_timing.h_sync_width; /* start at begining of left border */ - h_active_start = crtc_timing->h_sync_width + h_back_porch; + h_active_start = hw_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; + v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top - + hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom - + hw_crtc_timing.v_front_porch; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) @@ -486,21 +495,21 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (REG(DP_MSA_TIMING_PARAM3)) REG_SET_4(DP_MSA_TIMING_PARAM3, 0, DP_MSA_HSYNCWIDTH, - crtc_timing->h_sync_width, + hw_crtc_timing.h_sync_width, DP_MSA_HSYNCPOLARITY, - !crtc_timing->flags.HSYNC_POSITIVE_POLARITY, + !hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY, DP_MSA_VSYNCWIDTH, - crtc_timing->v_sync_width, + hw_crtc_timing.v_sync_width, DP_MSA_VSYNCPOLARITY, - !crtc_timing->flags.VSYNC_POSITIVE_POLARITY); + !hw_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); + DP_MSA_HWIDTH, hw_crtc_timing.h_border_left + + hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right, + DP_MSA_VHEIGHT, hw_crtc_timing.v_border_top + + hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom); #endif } #endif @@ -662,7 +671,7 @@ static void dce110_stream_encoder_dvi_set_stream_attribute( cntl.signal = is_dual_link ? SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK; cntl.enable_dp_audio = false; - cntl.pixel_clock = crtc_timing->pix_clk_khz; + cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10; cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR; if (enc110->base.bp->funcs->encoder_control( @@ -686,7 +695,7 @@ static void dce110_stream_encoder_lvds_set_stream_attribute( cntl.engine_id = enc110->base.id; cntl.signal = SIGNAL_TYPE_LVDS; cntl.enable_dp_audio = false; - cntl.pixel_clock = crtc_timing->pix_clk_khz; + cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10; cntl.lanes_number = LANE_COUNT_FOUR; if (enc110->base.bp->funcs->encoder_control( @@ -1575,6 +1584,14 @@ static void setup_stereo_sync( REG_UPDATE(DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, !enable); } +static void dig_connect_to_otg( + struct stream_encoder *enc, + int tg_inst) +{ + struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); + + REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst); +} static const struct stream_encoder_funcs dce110_str_enc_funcs = { .dp_set_stream_attribute = @@ -1609,7 +1626,7 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = { .hdmi_audio_disable = dce110_se_hdmi_audio_disable, .setup_stereo_sync = setup_stereo_sync, .set_avmute = dce110_stream_encoder_set_avmute, - + .dig_connect_to_otg = dig_connect_to_otg, }; void dce110_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h index 6c28229c76eb..f9cdf2b5242c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h @@ -199,7 +199,8 @@ SE_SF(DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\ SE_SF(DP_SEC_CNTL, DP_SEC_AIP_ENABLE, mask_sh),\ SE_SF(DP_SEC_CNTL, DP_SEC_ACM_ENABLE, mask_sh),\ - SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh) + SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh),\ + SE_SF(DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh) #define SE_COMMON_MASK_SH_LIST_DCE_COMMON(mask_sh)\ SE_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) @@ -284,7 +285,8 @@ SE_SF(DIG0_DIG_FE_CNTL, TMDS_PIXEL_ENCODING, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, TMDS_COLOR_FORMAT, mask_sh),\ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\ - SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh) + SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\ + SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh) #define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\ SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh) @@ -494,6 +496,7 @@ struct dce_stream_encoder_shift { uint8_t HDMI_DB_DISABLE; uint8_t DP_VID_N_MUL; uint8_t DP_VID_M_DOUBLE_VALUE_EN; + uint8_t DIG_SOURCE_SELECT; }; struct dce_stream_encoder_mask { @@ -624,6 +627,7 @@ struct dce_stream_encoder_mask { uint32_t HDMI_DB_DISABLE; uint32_t DP_VID_N_MUL; uint32_t DP_VID_M_DOUBLE_VALUE_EN; + uint32_t DIG_SOURCE_SELECT; }; struct dce110_stream_enc_registers { diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 6ae51a5dfc04..23044e6723e8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -76,6 +76,7 @@ #ifndef mmBIOS_SCRATCH_2 #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC #define mmBIOS_SCRATCH_6 0x05CF #endif @@ -365,6 +366,7 @@ static const struct dce_abm_mask abm_mask = { #define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03 static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 }; @@ -587,7 +589,7 @@ struct output_pixel_processor *dce100_opp_create( return &opp->base; } -struct aux_engine *dce100_aux_engine_create( +struct dce_aux *dce100_aux_engine_create( struct dc_context *ctx, uint32_t inst) { diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index 52d50e24a995..7b23239d33fe 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -62,8 +62,6 @@ static const struct dce110_compressor_reg_offsets reg_offsets[] = { } }; -static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600; - static uint32_t align_to_chunks_number_per_line(uint32_t pixels) { return 256 * ((pixels + 255) / 256); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 4bf24758217f..e1b285ea01ac 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -614,55 +614,6 @@ dce110_set_output_transfer_func(struct pipe_ctx *pipe_ctx, return true; } -static enum dc_status bios_parser_crtc_source_select( - struct pipe_ctx *pipe_ctx) -{ - struct dc_bios *dcb; - /* call VBIOS table to set CRTC source for the HW - * encoder block - * note: video bios clears all FMT setting here. */ - struct bp_crtc_source_select crtc_source_select = {0}; - const struct dc_sink *sink = pipe_ctx->stream->sink; - - crtc_source_select.engine_id = pipe_ctx->stream_res.stream_enc->id; - crtc_source_select.controller_id = pipe_ctx->stream_res.tg->inst + 1; - /*TODO: Need to un-hardcode color depth, dp_audio and account for - * the case where signal and sink signal is different (translator - * encoder)*/ - crtc_source_select.signal = pipe_ctx->stream->signal; - crtc_source_select.enable_dp_audio = false; - crtc_source_select.sink_signal = pipe_ctx->stream->signal; - - switch (pipe_ctx->stream->timing.display_color_depth) { - case COLOR_DEPTH_666: - crtc_source_select.display_output_bit_depth = PANEL_6BIT_COLOR; - break; - case COLOR_DEPTH_888: - crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR; - break; - case COLOR_DEPTH_101010: - crtc_source_select.display_output_bit_depth = PANEL_10BIT_COLOR; - break; - case COLOR_DEPTH_121212: - crtc_source_select.display_output_bit_depth = PANEL_12BIT_COLOR; - break; - default: - BREAK_TO_DEBUGGER(); - crtc_source_select.display_output_bit_depth = PANEL_8BIT_COLOR; - break; - } - - dcb = sink->ctx->dc_bios; - - if (BP_RESULT_OK != dcb->funcs->crtc_source_select( - dcb, - &crtc_source_select)) { - return DC_ERROR_UNEXPECTED; - } - - return DC_OK; -} - void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) { bool is_hdmi; @@ -692,10 +643,10 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx) void dce110_enable_stream(struct pipe_ctx *pipe_ctx) { enum dc_lane_count lane_count = - pipe_ctx->stream->sink->link->cur_link_settings.lane_count; + pipe_ctx->stream->link->cur_link_settings.lane_count; struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; - struct dc_link *link = pipe_ctx->stream->sink->link; + struct dc_link *link = pipe_ctx->stream->link; uint32_t active_total_with_borders; @@ -1000,7 +951,7 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.audio->funcs->az_enable(pipe_ctx->stream_res.audio); - if (num_audio == 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + if (num_audio >= 1 && pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* un-mute audio */ @@ -1017,6 +968,8 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( pipe_ctx->stream_res.stream_enc, true); if (pipe_ctx->stream_res.audio) { + struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; + if (option != KEEP_ACQUIRED_RESOURCE || !dc->debug.az_endpoint_mute_only) { /*only disalbe az_endpoint if power down or free*/ @@ -1036,6 +989,9 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); pipe_ctx->stream_res.audio = NULL; } + if (pp_smu != NULL && pp_smu->set_pme_wa_enable != NULL) + /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); /* TODO: notify audio driver for if audio modes list changed * add audio mode list change flag */ @@ -1048,7 +1004,7 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; struct dc *dc = pipe_ctx->stream->ctx->dc; if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) @@ -1073,11 +1029,10 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, { struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; /* only 3 items below are used by unblank */ - params.pixel_clk_khz = - pipe_ctx->stream->timing.pix_clk_khz; + params.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10; params.link_settings.link_rate = link_settings->link_rate; if (dc_is_dp_signal(pipe_ctx->stream->signal)) @@ -1087,10 +1042,11 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, link->dc->hwss.edp_backlight_control(link, true); } } + void dce110_blank_stream(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; - struct dc_link *link = stream->sink->link; + struct dc_link *link = stream->link; if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { link->dc->hwss.edp_backlight_control(link, false); @@ -1163,27 +1119,27 @@ static void build_audio_output( stream->timing.flags.INTERLACE; audio_output->crtc_info.refresh_rate = - (stream->timing.pix_clk_khz*1000)/ + (stream->timing.pix_clk_100hz*10000)/ (stream->timing.h_total*stream->timing.v_total); audio_output->crtc_info.color_depth = stream->timing.display_color_depth; audio_output->crtc_info.requested_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10; audio_output->crtc_info.calculated_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk; + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10; /*for HDMI, audio ACR is with deep color ratio factor*/ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && audio_output->crtc_info.requested_pixel_clock == - stream->timing.pix_clk_khz) { + (stream->timing.pix_clk_100hz / 10)) { if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) { audio_output->crtc_info.requested_pixel_clock = audio_output->crtc_info.requested_pixel_clock/2; audio_output->crtc_info.calculated_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk/2; + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/20; } } @@ -1294,8 +1250,6 @@ static enum dc_status dce110_enable_stream_timing( struct pipe_ctx *pipe_ctx_old = &dc->current_state->res_ctx. pipe_ctx[pipe_ctx->pipe_idx]; struct tg_color black_color = {0}; - struct drr_params params = {0}; - unsigned int event_triggers = 0; if (!pipe_ctx_old->stream) { @@ -1324,20 +1278,6 @@ static enum dc_status dce110_enable_stream_timing( pipe_ctx->stream_res.tg, &stream->timing, true); - - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && - stream->adjust.v_total_max != 0) - event_triggers = 0x80; - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers); } if (!pipe_ctx_old->stream) { @@ -1357,6 +1297,8 @@ static enum dc_status apply_single_controller_ctx_to_hw( struct dc *dc) { struct dc_stream_state *stream = pipe_ctx->stream; + struct drr_params params = {0}; + unsigned int event_triggers = 0; if (pipe_ctx->stream_res.audio != NULL) { struct audio_output audio_output; @@ -1383,14 +1325,32 @@ static enum dc_status apply_single_controller_ctx_to_hw( } /* */ - dc->hwss.enable_stream_timing(pipe_ctx, context, dc); + /* Do not touch stream timing on seamless boot optimization. */ + if (!pipe_ctx->stream->apply_seamless_boot_optimization) + dc->hwss.enable_stream_timing(pipe_ctx, context, dc); + + if (pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt) + pipe_ctx->stream_res.tg->funcs->program_vupdate_interrupt( + pipe_ctx->stream_res.tg, + &stream->timing); + + params.vertical_total_min = stream->adjust.v_total_min; + params.vertical_total_max = stream->adjust.v_total_max; + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, ¶ms); + + // DRR should set trigger event to monitor surface update event + if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) + event_triggers = 0x80; + if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) + pipe_ctx->stream_res.tg->funcs->set_static_screen_control( + pipe_ctx->stream_res.tg, event_triggers); - /* TODO: move to stream encoder */ if (pipe_ctx->stream->signal != SIGNAL_TYPE_VIRTUAL) - if (DC_OK != bios_parser_crtc_source_select(pipe_ctx)) { - BREAK_TO_DEBUGGER(); - return DC_ERROR_UNEXPECTED; - } + pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( + pipe_ctx->stream_res.stream_enc, + pipe_ctx->stream_res.tg->inst); pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion( pipe_ctx->stream_res.opp, @@ -1408,7 +1368,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0; - pipe_ctx->stream->sink->link->psr_enabled = false; + pipe_ctx->stream->link->psr_enabled = false; return DC_OK; } @@ -1518,7 +1478,7 @@ static struct dc_link *get_link_for_edp(struct dc *dc) return NULL; } -static struct dc_link *get_link_for_edp_not_in_use( +static struct dc_link *get_link_for_edp_to_turn_off( struct dc *dc, struct dc_state *context) { @@ -1527,8 +1487,12 @@ static struct dc_link *get_link_for_edp_not_in_use( /* check if eDP panel is suppose to be set mode, if yes, no need to disable */ for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->signal == SIGNAL_TYPE_EDP) - return NULL; + if (context->streams[i]->signal == SIGNAL_TYPE_EDP) { + if (context->streams[i]->dpms_off == true) + return context->streams[i]->sink->link; + else + return NULL; + } } /* check if there is an eDP panel not in use */ @@ -1555,7 +1519,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) int i; struct dc_link *edp_link_to_turnoff = NULL; struct dc_link *edp_link = get_link_for_edp(dc); - struct dc_bios *bios = dc->ctx->dc_bios; bool can_edp_fast_boot_optimize = false; bool apply_edp_fast_boot_optimization = false; @@ -1571,7 +1534,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) } if (can_edp_fast_boot_optimize) - edp_link_to_turnoff = get_link_for_edp_not_in_use(dc, context); + edp_link_to_turnoff = get_link_for_edp_to_turn_off(dc, context); /* if OS doesn't light up eDP and eDP link is available, we want to disable * If resume from S4/S5, should optimization. @@ -1582,20 +1545,6 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) if (context->streams[i]->signal == SIGNAL_TYPE_EDP) { context->streams[i]->apply_edp_fast_boot_optimization = true; apply_edp_fast_boot_optimization = true; - - /* When after S4 and S5, vbios may post edp and previous dpms_off - * doesn't make sense. - * Update dpms_off state to align hw and sw state via check - * vBios scratch register. - */ - if (bios->funcs->is_active_display) { - const struct connector_device_tag_info *device_tag = &(edp_link->device_tag); - - if (bios->funcs->is_active_display(bios, - context->streams[i]->signal, - device_tag)) - context->streams[i]->dpms_off = false; - } } } } @@ -1624,8 +1573,8 @@ static uint32_t compute_pstate_blackout_duration( pstate_blackout_duration_ns = 1000 * blackout_duration.value >> 24; total_dest_line_time_ns = 1000000UL * - stream->timing.h_total / - stream->timing.pix_clk_khz + + (stream->timing.h_total * 10) / + stream->timing.pix_clk_100hz + pstate_blackout_duration_ns; return total_dest_line_time_ns; @@ -1813,18 +1762,15 @@ static bool should_enable_fbc(struct dc *dc, if (i == dc->res_pool->pipe_count) return false; - if (!pipe_ctx->stream->sink) - return false; - - if (!pipe_ctx->stream->sink->link) + if (!pipe_ctx->stream->link) return false; /* Only supports eDP */ - if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP) + if (pipe_ctx->stream->link->connector_signal != SIGNAL_TYPE_EDP) return false; /* PSR should not be enabled */ - if (pipe_ctx->stream->sink->link->psr_enabled) + if (pipe_ctx->stream->link->psr_enabled) return false; /* Nothing to compress */ @@ -2329,6 +2275,11 @@ static void dce110_enable_per_frame_crtc_position_reset( } +static void init_pipes(struct dc *dc, struct dc_state *context) +{ + // Do nothing +} + static void init_hw(struct dc *dc) { int i; @@ -2573,7 +2524,7 @@ static void dce110_apply_ctx_for_surface( pipe_ctx->plane_res.mi, pipe_ctx->stream->timing.h_total, pipe_ctx->stream->timing.v_total, - pipe_ctx->stream->timing.pix_clk_khz, + pipe_ctx->stream->timing.pix_clk_100hz / 10, context->stream_count); dce110_program_front_end_for_pipe(dc, pipe_ctx); @@ -2595,7 +2546,7 @@ static void dce110_apply_ctx_for_surface( } if (dc->fbc_compressor) - enable_fbc(dc, dc->current_state); + enable_fbc(dc, context); } static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) @@ -2622,13 +2573,35 @@ static void dce110_wait_for_mpcc_disconnect( /* do nothing*/ } +static void program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + int i; + struct out_csc_color_matrix tbl_entry; + + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + enum dc_color_space color_space = pipe_ctx->stream->output_color_space; + + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = pipe_ctx->stream->csc_color_matrix.matrix[i]; + + tbl_entry.color_space = color_space; + + pipe_ctx->plane_res.xfm->funcs->opp_set_csc_adjustment( + pipe_ctx->plane_res.xfm, &tbl_entry); + } +} + void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx) { struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position; struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp; struct mem_input *mi = pipe_ctx->plane_res.mi; struct dc_cursor_mi_param param = { - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, .viewport = pipe_ctx->plane_res.scl_data.viewport, .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, @@ -2672,7 +2645,9 @@ void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx) static const struct hw_sequencer_funcs dce110_funcs = { .program_gamut_remap = program_gamut_remap, + .program_output_csc = program_output_csc, .init_hw = init_hw, + .init_pipes = init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dce110_apply_ctx_for_surface, .update_plane_addr = update_plane_addr, diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index e33d11785b1f..7549adaa1542 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -84,6 +84,7 @@ #ifndef mmBIOS_SCRATCH_2 #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC #define mmBIOS_SCRATCH_6 0x05CF #endif @@ -369,6 +370,7 @@ static const struct dce110_clk_src_mask cs_mask = { }; static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 }; @@ -606,7 +608,7 @@ static struct output_pixel_processor *dce110_opp_create( return &opp->base; } -struct aux_engine *dce110_aux_engine_create( +struct dce_aux *dce110_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -779,8 +781,8 @@ static void get_pixel_clock_parameters( * the pixel clock normalization for hdmi up to here instead of doing it * in pll_adjust_pix_clk */ - pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz; - pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id; + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + pixel_clk_params->encoder_object_id = stream->link->link_enc->id; pixel_clk_params->signal_type = pipe_ctx->stream->signal; pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; /* TODO: un-hardcode*/ @@ -797,10 +799,10 @@ static void get_pixel_clock_parameters( pixel_clk_params->color_depth = COLOR_DEPTH_888; } if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { - pixel_clk_params->requested_pix_clk = pixel_clk_params->requested_pix_clk / 2; + pixel_clk_params->requested_pix_clk_100hz = pixel_clk_params->requested_pix_clk_100hz / 2; } if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clk_params->requested_pix_clk *= 2; + pixel_clk_params->requested_pix_clk_100hz *= 2; } @@ -874,7 +876,7 @@ static bool dce110_validate_bandwidth( __func__, context->streams[0]->timing.h_addressable, context->streams[0]->timing.v_addressable, - context->streams[0]->timing.pix_clk_khz); + context->streams[0]->timing.pix_clk_100hz / 10); if (memcmp(&dc->current_state->bw.dce, &context->bw.dce, sizeof(context->bw.dce))) { @@ -1055,7 +1057,7 @@ static struct pipe_ctx *dce110_acquire_underlay( pipe_ctx->plane_res.mi->funcs->allocate_mem_input(pipe_ctx->plane_res.mi, stream->timing.h_total, stream->timing.v_total, - stream->timing.pix_clk_khz, + stream->timing.pix_clk_100hz / 10, context->stream_count); color_space_to_black_color(dc, diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index 969d4e72dc94..ea3065d63372 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -76,6 +76,7 @@ #ifndef mmBIOS_SCRATCH_2 #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC #define mmBIOS_SCRATCH_6 0x05CF #endif @@ -376,6 +377,7 @@ static const struct dce110_clk_src_mask cs_mask = { }; static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 }; @@ -607,7 +609,7 @@ struct output_pixel_processor *dce112_opp_create( return &opp->base; } -struct aux_engine *dce112_aux_engine_create( +struct dce_aux *dce112_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -763,7 +765,7 @@ static struct clock_source *find_matching_pll( const struct resource_pool *pool, const struct dc_stream_state *const stream) { - switch (stream->sink->link->link_enc->transmitter) { + switch (stream->link->link_enc->transmitter) { case TRANSMITTER_UNIPHY_A: return pool->clock_sources[DCE112_CLK_SRC_PLL0]; case TRANSMITTER_UNIPHY_B: diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c index eb0f5f9a973b..1ca30928025e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c @@ -244,6 +244,21 @@ static void dce120_update_dchub( dh_data->dchub_info_valid = false; } +/** + * dce121_xgmi_enabled() - Check if xGMI is enabled + * @hws: DCE hardware sequencer object + * + * Return true if xGMI is enabled. False otherwise. + */ +bool dce121_xgmi_enabled(struct dce_hwseq *hws) +{ + uint32_t pf_max_region; + + REG_GET(MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, &pf_max_region); + /* PF_MAX_REGION == 0 means xgmi is disabled */ + return !!pf_max_region; +} + void dce120_hw_sequencer_construct(struct dc *dc) { /* All registers used by dce11.2 match those in dce11 in offset and diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h index 77a6b86d7606..c51afbd0b012 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h @@ -30,6 +30,7 @@ struct dc; +bool dce121_xgmi_enabled(struct dce_hwseq *hws); void dce120_hw_sequencer_construct(struct dc *dc); #endif /* __DC_HWSS_DCE112_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c index f12696674eb0..312a0aebf91f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -62,6 +62,8 @@ #include "soc15_hw_ip.h" #include "vega10_ip_offset.h" #include "nbio/nbio_6_1_offset.h" +#include "mmhub/mmhub_9_4_0_offset.h" +#include "mmhub/mmhub_9_4_0_sh_mask.h" #include "reg_helper.h" #include "dce100/dce100_resource.h" @@ -139,6 +141,17 @@ static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = { .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ mm ## block ## id ## _ ## reg_name +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + /* macros to expend register list macro defined in HW object header file * end *********************/ @@ -378,7 +391,7 @@ struct output_pixel_processor *dce120_opp_create( ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); return &opp->base; } -struct aux_engine *dce120_aux_engine_create( +struct dce_aux *dce120_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -429,6 +442,7 @@ struct dce_i2c_hw *dce120_i2c_hw_create( return dce_i2c_hw; } static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3 + NBIO_BASE(mmBIOS_SCRATCH_3_BASE_IDX), .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX) }; @@ -681,6 +695,19 @@ static const struct dce_hwseq_mask hwseq_mask = { HWSEQ_DCE12_MASK_SH_LIST(_MASK) }; +/* HWSEQ regs for VG20 */ +static const struct dce_hwseq_registers dce121_hwseq_reg = { + HWSEQ_VG20_REG_LIST() +}; + +static const struct dce_hwseq_shift dce121_hwseq_shift = { + HWSEQ_VG20_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask dce121_hwseq_mask = { + HWSEQ_VG20_MASK_SH_LIST(_MASK) +}; + static struct dce_hwseq *dce120_hwseq_create( struct dc_context *ctx) { @@ -695,6 +722,20 @@ static struct dce_hwseq *dce120_hwseq_create( return hws; } +static struct dce_hwseq *dce121_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &dce121_hwseq_reg; + hws->shifts = &dce121_hwseq_shift; + hws->masks = &dce121_hwseq_mask; + } + return hws; +} + static const struct resource_create_funcs res_create_funcs = { .read_dce_straps = read_dce_straps, .create_audio = create_audio, @@ -702,6 +743,14 @@ static const struct resource_create_funcs res_create_funcs = { .create_hwseq = dce120_hwseq_create, }; +static const struct resource_create_funcs dce121_res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce120_stream_encoder_create, + .create_hwseq = dce121_hwseq_create, +}; + + #define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) } static const struct dce_mem_input_registers mi_regs[] = { mi_inst_regs(0), @@ -911,7 +960,8 @@ static bool construct( int j; struct dc_context *ctx = dc->ctx; struct irq_service_init_data irq_init_data; - bool harvest_enabled = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); + static const struct resource_create_funcs *res_funcs; + bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); uint32_t pipe_fuses; ctx->dc_bios->regs = &bios_regs; @@ -975,7 +1025,11 @@ static bool construct( } } - pool->base.clk_mgr = dce120_clk_mgr_create(ctx); + if (is_vg20) + pool->base.clk_mgr = dce121_clk_mgr_create(ctx); + else + pool->base.clk_mgr = dce120_clk_mgr_create(ctx); + if (pool->base.clk_mgr == NULL) { dm_error("DC: failed to create display clock!\n"); BREAK_TO_DEBUGGER(); @@ -1008,14 +1062,14 @@ static bool construct( if (!pool->base.irqs) goto irqs_create_fail; - /* retrieve valid pipe fuses */ - if (harvest_enabled) + /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */ + if (is_vg20) pipe_fuses = read_pipe_fuses(ctx); /* index to valid pipe resource */ j = 0; for (i = 0; i < pool->base.pipe_count; i++) { - if (harvest_enabled) { + if (is_vg20) { if ((pipe_fuses & (1 << i)) != 0) { dm_error("DC: skip invalid pipe %d!\n", i); continue; @@ -1093,10 +1147,24 @@ static bool construct( pool->base.pipe_count = j; pool->base.timing_generator_count = j; - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) + if (is_vg20) + res_funcs = &dce121_res_create_funcs; + else + res_funcs = &res_create_funcs; + + if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs)) goto res_create_fail; + /* + * This is a bit of a hack. The xGMI enabled info is used to determine + * if audio and display clocks need to be adjusted with the WAFL link's + * SS info. This is a responsiblity of the clk_mgr. But since MMHUB is + * under hwseq, and the relevant register is in MMHUB, we have to do it + * here. + */ + if (is_vg20 && dce121_xgmi_enabled(dc->hwseq)) + dce121_clock_patch_xgmi_ss_info(pool->base.clk_mgr); + /* Create hardware sequencer */ if (!dce120_hw_sequencer_create(dc)) goto controller_create_fail; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index cdd1d6b7b9f2..2eca81b5cf2f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -77,6 +77,7 @@ #ifndef mmBIOS_SCRATCH_2 #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC #define mmBIOS_SCRATCH_6 0x05CF #endif @@ -358,6 +359,7 @@ static const struct dce110_clk_src_mask cs_mask = { }; static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 }; @@ -467,7 +469,7 @@ static struct output_pixel_processor *dce80_opp_create( return &opp->base; } -struct aux_engine *dce80_aux_engine_create( +struct dce_aux *dce80_aux_engine_create( struct dc_context *ctx, uint32_t inst) { diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c index 3ba4712a35ab..8b5ce557ee71 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c @@ -84,17 +84,17 @@ static const struct dce110_timing_generator_offsets reg_offsets[] = { #define DCP_REG(reg) (reg + tg110->offsets.dcp) #define DMIF_REG(reg) (reg + tg110->offsets.dmif) -static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_khz) +static void program_pix_dur(struct timing_generator *tg, uint32_t pix_clk_100hz) { uint64_t pix_dur; uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1 + DCE110TG_FROM_TG(tg)->offsets.dmif; uint32_t value = dm_read_reg(tg->ctx, addr); - if (pix_clk_khz == 0) + if (pix_clk_100hz == 0) return; - pix_dur = 1000000000 / pix_clk_khz; + pix_dur = div_u64(10000000000ull, pix_clk_100hz); set_reg_field_value( value, @@ -110,7 +110,7 @@ static void program_timing(struct timing_generator *tg, bool use_vbios) { if (!use_vbios) - program_pix_dur(tg, timing->pix_clk_khz); + program_pix_dur(tg, timing->pix_clk_100hz); dce110_tg_program_timing(tg, timing, use_vbios); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c index 54abedbf1b43..afe8c42211cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_clk_mgr.c @@ -161,69 +161,17 @@ static int get_active_display_cnt( return display_count; } -static void notify_deep_sleep_dcfclk_to_smu( - struct pp_smu_funcs_rv *pp_smu, int min_dcef_deep_sleep_clk_khz) -{ - int min_dcef_deep_sleep_clk_mhz; //minimum required DCEF Deep Sleep clock in mhz - /* - * if function pointer not set up, this message is - * sent as part of pplib_apply_display_requirements. - * So just return. - */ - if (!pp_smu || !pp_smu->set_min_deep_sleep_dcfclk) - return; - - min_dcef_deep_sleep_clk_mhz = (min_dcef_deep_sleep_clk_khz + 999) / 1000; //Round up - pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, min_dcef_deep_sleep_clk_mhz); -} - -static void notify_hard_min_dcfclk_to_smu( - struct pp_smu_funcs_rv *pp_smu, int min_dcf_clk_khz) -{ - int min_dcf_clk_mhz; //minimum required DCF clock in mhz - - /* - * if function pointer not set up, this message is - * sent as part of pplib_apply_display_requirements. - * So just return. - */ - if (!pp_smu || !pp_smu->set_hard_min_dcfclk_by_freq) - return; - - min_dcf_clk_mhz = min_dcf_clk_khz / 1000; - - pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, min_dcf_clk_mhz); -} - -static void notify_hard_min_fclk_to_smu( - struct pp_smu_funcs_rv *pp_smu, int min_f_clk_khz) -{ - int min_f_clk_mhz; //minimum required F clock in mhz - - /* - * if function pointer not set up, this message is - * sent as part of pplib_apply_display_requirements. - * So just return. - */ - if (!pp_smu || !pp_smu->set_hard_min_fclk_by_freq) - return; - - min_f_clk_mhz = min_f_clk_khz / 1000; - - pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, min_f_clk_mhz); -} - static void dcn1_update_clocks(struct clk_mgr *clk_mgr, struct dc_state *context, bool safe_to_lower) { struct dc *dc = clk_mgr->ctx->dc; + struct dc_debug_options *debug = &dc->debug; struct dc_clocks *new_clocks = &context->bw.dcn.clk; struct pp_smu_display_requirement_rv *smu_req_cur = &dc->res_pool->pp_smu_req; struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; - uint32_t requested_dcf_clock_in_khz = 0; bool send_request_to_increase = false; bool send_request_to_lower = false; int display_count; @@ -243,9 +191,8 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, */ if (pp_smu->set_display_count) pp_smu->set_display_count(&pp_smu->pp_smu, display_count); - else - smu_req.display_count = display_count; + smu_req.display_count = display_count; } if (new_clocks->dispclk_khz > clk_mgr->clks.dispclk_khz @@ -261,12 +208,13 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, } // F Clock + if (debug->force_fclk_khz != 0) + new_clocks->fclk_khz = debug->force_fclk_khz; + if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr->clks.fclk_khz)) { clk_mgr->clks.fclk_khz = new_clocks->fclk_khz; smu_req.hard_min_fclk_mhz = new_clocks->fclk_khz / 1000; - notify_hard_min_fclk_to_smu(pp_smu, new_clocks->fclk_khz); - send_request_to_lower = true; } @@ -281,7 +229,7 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) { clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; - smu_req.min_deep_sleep_dcefclk_mhz = new_clocks->dcfclk_deep_sleep_khz / 1000; + smu_req.min_deep_sleep_dcefclk_mhz = (new_clocks->dcfclk_deep_sleep_khz + 999) / 1000; send_request_to_lower = true; } @@ -291,15 +239,18 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, */ if (send_request_to_increase) { /*use dcfclk to request voltage*/ - requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - - notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); - - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); - - notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz); - dcn1_pplib_apply_display_requirements(dc, context); + if (pp_smu->set_hard_min_fclk_by_freq && + pp_smu->set_hard_min_dcfclk_by_freq && + pp_smu->set_min_deep_sleep_dcfclk) { + + pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_fclk_mhz); + pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_dcefclk_mhz); + pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, smu_req.min_deep_sleep_dcefclk_mhz); + } else { + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + dcn1_pplib_apply_display_requirements(dc, context); + } } /* dcn1 dppclk is tied to dispclk */ @@ -314,18 +265,20 @@ static void dcn1_update_clocks(struct clk_mgr *clk_mgr, if (!send_request_to_increase && send_request_to_lower) { /*use dcfclk to request voltage*/ - requested_dcf_clock_in_khz = dcn_find_dcfclk_suits_all(dc, new_clocks); - - notify_hard_min_dcfclk_to_smu(pp_smu, requested_dcf_clock_in_khz); - - if (pp_smu->set_display_requirement) - pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); - - notify_deep_sleep_dcfclk_to_smu(pp_smu, clk_mgr->clks.dcfclk_deep_sleep_khz); - dcn1_pplib_apply_display_requirements(dc, context); + if (pp_smu->set_hard_min_fclk_by_freq && + pp_smu->set_hard_min_dcfclk_by_freq && + pp_smu->set_min_deep_sleep_dcfclk) { + + pp_smu->set_hard_min_fclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_fclk_mhz); + pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, smu_req.hard_min_dcefclk_mhz); + pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, smu_req.min_deep_sleep_dcefclk_mhz); + } else { + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + dcn1_pplib_apply_display_requirements(dc, context); + } } - *smu_req_cur = smu_req; } static const struct clk_mgr_funcs dcn1_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c index dcb3c5530236..cd1ebe57ed59 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -463,7 +463,7 @@ void dpp1_set_cursor_position( if (src_y_offset >= (int)param->viewport.height) cur_en = 0; /* not visible beyond bottom edge*/ - if (src_y_offset < 0) + if (src_y_offset + (int)height <= 0) cur_en = 0; /* not visible beyond top edge*/ REG_UPDATE(CURSOR0_CONTROL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c index 116977eb24e2..41f0f4c912e7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -51,10 +51,6 @@ #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) -struct dcn10_input_csc_matrix { - enum dc_color_space color_space; - uint16_t regval[12]; -}; enum dcn10_coef_filter_type_sel { SCL_COEF_LUMA_VERT_FILTER = 0, @@ -99,7 +95,7 @@ enum gamut_remap_select { GAMUT_REMAP_COMB_COEFF }; -static const struct dcn10_input_csc_matrix dcn10_input_csc_matrix[] = { +static const struct dpp_input_csc_matrix dpp_input_csc_matrix[] = { {COLOR_SPACE_SRGB, {0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, {COLOR_SPACE_SRGB_LIMITED, @@ -454,7 +450,7 @@ void dpp1_program_input_csc( { struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); int i; - int arr_size = sizeof(dcn10_input_csc_matrix)/sizeof(struct dcn10_input_csc_matrix); + int arr_size = sizeof(dpp_input_csc_matrix)/sizeof(struct dpp_input_csc_matrix); const uint16_t *regval = NULL; uint32_t cur_select = 0; enum dcn10_input_csc_select select; @@ -467,8 +463,8 @@ void dpp1_program_input_csc( if (tbl_entry == NULL) { for (i = 0; i < arr_size; i++) - if (dcn10_input_csc_matrix[i].color_space == color_space) { - regval = dcn10_input_csc_matrix[i].regval; + if (dpp_input_csc_matrix[i].color_space == color_space) { + regval = dpp_input_csc_matrix[i].regval; break; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c index 4a863a5dab41..c7642e748297 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -597,11 +597,13 @@ static void dpp1_dscl_set_manual_ratio_init( SCL_V_INIT_FRAC, init_frac, SCL_V_INIT_INT, init_int); - init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5; - init_int = dc_fixpt_floor(data->inits.v_bot); - REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, - SCL_V_INIT_FRAC_BOT, init_frac, - SCL_V_INIT_INT_BOT, init_int); + if (REG(SCL_VERT_FILTER_INIT_BOT)) { + init_frac = dc_fixpt_u0d19(data->inits.v_bot) << 5; + init_int = dc_fixpt_floor(data->inits.v_bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, + SCL_V_INIT_FRAC_BOT, init_frac, + SCL_V_INIT_INT_BOT, init_int); + } init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5; init_int = dc_fixpt_floor(data->inits.v_c); @@ -609,11 +611,13 @@ static void dpp1_dscl_set_manual_ratio_init( SCL_V_INIT_FRAC_C, init_frac, SCL_V_INIT_INT_C, init_int); - init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5; - init_int = dc_fixpt_floor(data->inits.v_c_bot); - REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, - SCL_V_INIT_FRAC_BOT_C, init_frac, - SCL_V_INIT_INT_BOT_C, init_int); + if (REG(SCL_VERT_FILTER_INIT_BOT_C)) { + init_frac = dc_fixpt_u0d19(data->inits.v_c_bot) << 5; + init_int = dc_fixpt_floor(data->inits.v_c_bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, + SCL_V_INIT_FRAC_BOT_C, init_frac, + SCL_V_INIT_INT_BOT_C, init_int); + } } @@ -688,15 +692,17 @@ void dpp1_dscl_set_scaler_manual_scale( return; /* Black offsets */ - if (ycbcr) - REG_SET_2(SCL_BLACK_OFFSET, 0, - SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, - SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR); - else + if (REG(SCL_BLACK_OFFSET)) { + if (ycbcr) + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR); + else - REG_SET_2(SCL_BLACK_OFFSET, 0, - SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, - SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y); + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y); + } /* Manually calculate scale ratio and init values */ dpp1_dscl_set_manual_ratio_init(dpp, scl_data); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c index c7d1e678ebf5..e161ad836812 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -29,19 +29,20 @@ #include "reg_helper.h" #define CTX \ - hubbub->ctx + hubbub1->base.ctx #define DC_LOGGER \ - hubbub->ctx->logger + hubbub1->base.ctx->logger #define REG(reg)\ - hubbub->regs->reg + hubbub1->regs->reg #undef FN #define FN(reg_name, field_name) \ - hubbub->shifts->field_name, hubbub->masks->field_name + hubbub1->shifts->field_name, hubbub1->masks->field_name void hubbub1_wm_read_state(struct hubbub *hubbub, struct dcn_hubbub_wm *wm) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); struct dcn_hubbub_wm_set *s; memset(wm, 0, sizeof(struct dcn_hubbub_wm)); @@ -87,14 +88,23 @@ void hubbub1_wm_read_state(struct hubbub *hubbub, s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); } -void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub) +void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow) { - REG_UPDATE(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, 0); + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + + /* + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 1 means do not allow stutter + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 means allow stutter + */ + + REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); } bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); uint32_t enable = 0; REG_GET(DCHUBBUB_ARB_DRAM_STATE_CNTL, @@ -107,6 +117,8 @@ bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) bool hubbub1_verify_allow_pstate_change_high( struct hubbub *hubbub) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + /* pstate latency is ~20us so if we wait over 40us and pstate allow * still not asserted, we are probably stuck and going to hang * @@ -193,7 +205,7 @@ bool hubbub1_verify_allow_pstate_change_high( * 31: SOC pstate change request */ - REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub->debug_test_index_pstate); + REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub1->debug_test_index_pstate); for (i = 0; i < pstate_wait_timeout_us; i++) { debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); @@ -244,6 +256,8 @@ static uint32_t convert_and_clamp( void hubbub1_wm_change_req_wa(struct hubbub *hubbub) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + REG_UPDATE_SEQ(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0, 1); } @@ -254,7 +268,7 @@ void hubbub1_program_watermarks( unsigned int refclk_mhz, bool safe_to_lower) { - uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0; + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); /* * Need to clamp to max of the register values (i.e. no wrap) * for dcn1, all wm registers are 21-bit wide @@ -264,8 +278,8 @@ void hubbub1_program_watermarks( /* Repeat for water mark set A, B, C and D. */ /* clock state A */ - if (safe_to_lower || watermarks->a.urgent_ns > hubbub->watermarks.a.urgent_ns) { - hubbub->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) { + hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns; prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); @@ -275,20 +289,22 @@ void hubbub1_program_watermarks( watermarks->a.urgent_ns, prog_wm_value); } - if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub->watermarks.a.pte_meta_urgent_ns) { - hubbub->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->a.pte_meta_urgent_ns, prog_wm_value); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) { + if (safe_to_lower || watermarks->a.pte_meta_urgent_ns > hubbub1->watermarks.a.pte_meta_urgent_ns) { + hubbub1->watermarks.a.pte_meta_urgent_ns = watermarks->a.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.pte_meta_urgent_ns, prog_wm_value); + } } if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; prog_wm_value = convert_and_clamp( watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, @@ -300,8 +316,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns - > hubbub->watermarks.a.cstate_pstate.cstate_exit_ns) { - hubbub->watermarks.a.cstate_pstate.cstate_exit_ns = + > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns = watermarks->a.cstate_pstate.cstate_exit_ns; prog_wm_value = convert_and_clamp( watermarks->a.cstate_pstate.cstate_exit_ns, @@ -314,8 +330,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns - > hubbub->watermarks.a.cstate_pstate.pstate_change_ns) { - hubbub->watermarks.a.cstate_pstate.pstate_change_ns = + > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.a.cstate_pstate.pstate_change_ns = watermarks->a.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( watermarks->a.cstate_pstate.pstate_change_ns, @@ -327,8 +343,8 @@ void hubbub1_program_watermarks( } /* clock state B */ - if (safe_to_lower || watermarks->b.urgent_ns > hubbub->watermarks.b.urgent_ns) { - hubbub->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) { + hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns; prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); @@ -338,20 +354,22 @@ void hubbub1_program_watermarks( watermarks->b.urgent_ns, prog_wm_value); } - if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub->watermarks.b.pte_meta_urgent_ns) { - hubbub->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->b.pte_meta_urgent_ns, prog_wm_value); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) { + if (safe_to_lower || watermarks->b.pte_meta_urgent_ns > hubbub1->watermarks.b.pte_meta_urgent_ns) { + hubbub1->watermarks.b.pte_meta_urgent_ns = watermarks->b.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.pte_meta_urgent_ns, prog_wm_value); + } } if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; prog_wm_value = convert_and_clamp( watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, @@ -363,8 +381,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns - > hubbub->watermarks.b.cstate_pstate.cstate_exit_ns) { - hubbub->watermarks.b.cstate_pstate.cstate_exit_ns = + > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns = watermarks->b.cstate_pstate.cstate_exit_ns; prog_wm_value = convert_and_clamp( watermarks->b.cstate_pstate.cstate_exit_ns, @@ -377,8 +395,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns - > hubbub->watermarks.b.cstate_pstate.pstate_change_ns) { - hubbub->watermarks.b.cstate_pstate.pstate_change_ns = + > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.b.cstate_pstate.pstate_change_ns = watermarks->b.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( watermarks->b.cstate_pstate.pstate_change_ns, @@ -390,8 +408,8 @@ void hubbub1_program_watermarks( } /* clock state C */ - if (safe_to_lower || watermarks->c.urgent_ns > hubbub->watermarks.c.urgent_ns) { - hubbub->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) { + hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns; prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); @@ -401,20 +419,22 @@ void hubbub1_program_watermarks( watermarks->c.urgent_ns, prog_wm_value); } - if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub->watermarks.c.pte_meta_urgent_ns) { - hubbub->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->c.pte_meta_urgent_ns, prog_wm_value); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) { + if (safe_to_lower || watermarks->c.pte_meta_urgent_ns > hubbub1->watermarks.c.pte_meta_urgent_ns) { + hubbub1->watermarks.c.pte_meta_urgent_ns = watermarks->c.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.pte_meta_urgent_ns, prog_wm_value); + } } if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; prog_wm_value = convert_and_clamp( watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, @@ -426,8 +446,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns - > hubbub->watermarks.c.cstate_pstate.cstate_exit_ns) { - hubbub->watermarks.c.cstate_pstate.cstate_exit_ns = + > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns = watermarks->c.cstate_pstate.cstate_exit_ns; prog_wm_value = convert_and_clamp( watermarks->c.cstate_pstate.cstate_exit_ns, @@ -440,8 +460,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns - > hubbub->watermarks.c.cstate_pstate.pstate_change_ns) { - hubbub->watermarks.c.cstate_pstate.pstate_change_ns = + > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.c.cstate_pstate.pstate_change_ns = watermarks->c.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( watermarks->c.cstate_pstate.pstate_change_ns, @@ -453,8 +473,8 @@ void hubbub1_program_watermarks( } /* clock state D */ - if (safe_to_lower || watermarks->d.urgent_ns > hubbub->watermarks.d.urgent_ns) { - hubbub->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) { + hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns; prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); @@ -464,20 +484,22 @@ void hubbub1_program_watermarks( watermarks->d.urgent_ns, prog_wm_value); } - if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub->watermarks.d.pte_meta_urgent_ns) { - hubbub->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; - prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, - refclk_mhz, 0x1fffff); - REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); - DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" - "HW register value = 0x%x\n", - watermarks->d.pte_meta_urgent_ns, prog_wm_value); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) { + if (safe_to_lower || watermarks->d.pte_meta_urgent_ns > hubbub1->watermarks.d.pte_meta_urgent_ns) { + hubbub1->watermarks.d.pte_meta_urgent_ns = watermarks->d.pte_meta_urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("PTE_META_URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.pte_meta_urgent_ns, prog_wm_value); + } } if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns - > hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { - hubbub->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; prog_wm_value = convert_and_clamp( watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, @@ -489,8 +511,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns - > hubbub->watermarks.d.cstate_pstate.cstate_exit_ns) { - hubbub->watermarks.d.cstate_pstate.cstate_exit_ns = + > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns = watermarks->d.cstate_pstate.cstate_exit_ns; prog_wm_value = convert_and_clamp( watermarks->d.cstate_pstate.cstate_exit_ns, @@ -503,8 +525,8 @@ void hubbub1_program_watermarks( } if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns - > hubbub->watermarks.d.cstate_pstate.pstate_change_ns) { - hubbub->watermarks.d.cstate_pstate.pstate_change_ns = + > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.d.cstate_pstate.pstate_change_ns = watermarks->d.cstate_pstate.pstate_change_ns; prog_wm_value = convert_and_clamp( watermarks->d.cstate_pstate.pstate_change_ns, @@ -520,9 +542,7 @@ void hubbub1_program_watermarks( REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68); - REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, - DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en); + hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); #if 0 REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, @@ -535,6 +555,8 @@ void hubbub1_update_dchub( struct hubbub *hubbub, struct dchub_init_data *dh_data) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { ASSERT(false); /*should not come here*/ @@ -594,6 +616,8 @@ void hubbub1_update_dchub( void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + uint32_t watermark_change_req; REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, @@ -610,6 +634,8 @@ void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub) void hubbub1_soft_reset(struct hubbub *hubbub, bool reset) { + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + uint32_t reset_en = reset ? 1 : 0; REG_UPDATE(DCHUBBUB_SOFT_RESET, @@ -752,7 +778,9 @@ static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub, const struct dc_dcc_surface_param *input, struct dc_surface_dcc_cap *output) { - struct dc *dc = hubbub->ctx->dc; + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + struct dc *dc = hubbub1->base.ctx->dc; + /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */ enum dcc_control dcc_control; unsigned int bpe; @@ -764,10 +792,10 @@ static bool hubbub1_get_dcc_compression_cap(struct hubbub *hubbub, if (dc->debug.disable_dcc == DCC_DISABLE) return false; - if (!hubbub->funcs->dcc_support_pixel_format(input->format, &bpe)) + if (!hubbub1->base.funcs->dcc_support_pixel_format(input->format, &bpe)) return false; - if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, + if (!hubbub1->base.funcs->dcc_support_swizzle(input->swizzle_mode, bpe, &segment_order_horz, &segment_order_vert)) return false; @@ -837,6 +865,7 @@ static const struct hubbub_funcs hubbub1_funcs = { .dcc_support_swizzle = hubbub1_dcc_support_swizzle, .dcc_support_pixel_format = hubbub1_dcc_support_pixel_format, .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap, + .wm_read_state = hubbub1_wm_read_state, }; void hubbub1_construct(struct hubbub *hubbub, @@ -845,18 +874,20 @@ void hubbub1_construct(struct hubbub *hubbub, const struct dcn_hubbub_shift *hubbub_shift, const struct dcn_hubbub_mask *hubbub_mask) { - hubbub->ctx = ctx; + struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); + + hubbub1->base.ctx = ctx; - hubbub->funcs = &hubbub1_funcs; + hubbub1->base.funcs = &hubbub1_funcs; - hubbub->regs = hubbub_regs; - hubbub->shifts = hubbub_shift; - hubbub->masks = hubbub_mask; + hubbub1->regs = hubbub_regs; + hubbub1->shifts = hubbub_shift; + hubbub1->masks = hubbub_mask; - hubbub->debug_test_index_pstate = 0x7; + hubbub1->debug_test_index_pstate = 0x7; #if defined(CONFIG_DRM_AMD_DC_DCN1_01) if (ctx->dce_version == DCN_VERSION_1_01) - hubbub->debug_test_index_pstate = 0xB; + hubbub1->debug_test_index_pstate = 0xB; #endif } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index d0f03d152913..9cd4a5194154 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -29,6 +29,9 @@ #include "core_types.h" #include "dchubbub.h" +#define TO_DCN10_HUBBUB(hubbub)\ + container_of(hubbub, struct dcn10_hubbub, base) + #define HUBHUB_REG_LIST_DCN()\ SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A),\ SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A),\ @@ -107,6 +110,12 @@ struct dcn_hubbub_registers { uint32_t DCHUBBUB_SDPIF_AGP_TOP; uint32_t DCHUBBUB_CRC_CTRL; uint32_t DCHUBBUB_SOFT_RESET; + uint32_t DCN_VM_FB_LOCATION_BASE; + uint32_t DCN_VM_FB_LOCATION_TOP; + uint32_t DCN_VM_FB_OFFSET; + uint32_t DCN_VM_AGP_BOT; + uint32_t DCN_VM_AGP_TOP; + uint32_t DCN_VM_AGP_BASE; }; /* set field name */ @@ -152,7 +161,13 @@ struct dcn_hubbub_registers { type SDPIF_FB_OFFSET;\ type SDPIF_AGP_BASE;\ type SDPIF_AGP_BOT;\ - type SDPIF_AGP_TOP + type SDPIF_AGP_TOP;\ + type FB_BASE;\ + type FB_TOP;\ + type FB_OFFSET;\ + type AGP_BOT;\ + type AGP_TOP;\ + type AGP_BASE struct dcn_hubbub_shift { @@ -165,22 +180,8 @@ struct dcn_hubbub_mask { struct dc; -struct dcn_hubbub_wm_set { - uint32_t wm_set; - uint32_t data_urgent; - uint32_t pte_meta_urgent; - uint32_t sr_enter; - uint32_t sr_exit; - uint32_t dram_clk_chanage; -}; - -struct dcn_hubbub_wm { - struct dcn_hubbub_wm_set sets[4]; -}; - -struct hubbub { - const struct hubbub_funcs *funcs; - struct dc_context *ctx; +struct dcn10_hubbub { + struct hubbub base; const struct dcn_hubbub_registers *regs; const struct dcn_hubbub_shift *shifts; const struct dcn_hubbub_mask *masks; @@ -203,7 +204,7 @@ void hubbub1_program_watermarks( unsigned int refclk_mhz, bool safe_to_lower); -void hubbub1_disable_allow_self_refresh(struct hubbub *hubbub); +void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow); bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubub); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c index 345af015d061..683829466a44 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -115,7 +115,7 @@ static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) REG_UPDATE(DCHUBP_CNTL, HUBP_BLANK_EN, blank_en); } -static void hubp1_vready_workaround(struct hubp *hubp, +void hubp1_vready_workaround(struct hubp *hubp, struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest) { uint32_t value = 0; @@ -317,7 +317,8 @@ void hubp1_program_pixel_format( bool hubp1_program_surface_flip_and_addr( struct hubp *hubp, const struct dc_plane_address *address, - bool flip_immediate) + bool flip_immediate, + uint8_t vmid) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -1140,7 +1141,7 @@ void hubp1_cursor_set_position( 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 + if (src_y_offset + (int)hubp->curs_attr.height <= 0) cur_en = 0; /* not visible beyond top edge*/ if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) @@ -1149,9 +1150,28 @@ void hubp1_cursor_set_position( REG_UPDATE(CURSOR_CONTROL, CURSOR_ENABLE, cur_en); - REG_SET_2(CURSOR_POSITION, 0, - CURSOR_X_POSITION, pos->x, + //account for cases where we see negative offset relative to overlay plane + if (src_x_offset < 0 && src_y_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, 0, + CURSOR_Y_POSITION, 0); + x_hotspot -= src_x_offset; + y_hotspot -= src_y_offset; + } else if (src_x_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, 0, CURSOR_Y_POSITION, pos->y); + x_hotspot -= src_x_offset; + } else if (src_y_offset < 0) { + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, 0); + y_hotspot -= src_y_offset; + } else { + 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, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h index 62d4232e7796..a6d6dfe00617 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -707,11 +707,6 @@ void hubp1_dcc_control(struct hubp *hubp, bool enable, bool independent_64b_blks); -bool hubp1_program_surface_flip_and_addr( - struct hubp *hubp, - const struct dc_plane_address *address, - bool flip_immediate); - bool hubp1_is_flip_pending(struct hubp *hubp); void hubp1_cursor_set_attributes( @@ -745,5 +740,7 @@ void hubp1_clear_underflow(struct hubp *hubp); enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch); +void hubp1_vready_workaround(struct hubp *hubp, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 91e015e14355..117d9d8227f7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -40,7 +40,6 @@ #include "ipp.h" #include "mpc.h" #include "reg_helper.h" -#include "custom_float.h" #include "dcn10_hubp.h" #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" @@ -92,10 +91,11 @@ static void log_mpc_crc(struct dc *dc, void dcn10_log_hubbub_state(struct dc *dc, struct dc_log_buffer_ctx *log_ctx) { struct dc_context *dc_ctx = dc->ctx; - struct dcn_hubbub_wm wm = {0}; + struct dcn_hubbub_wm wm; int i; - hubbub1_wm_read_state(dc->res_pool->hubbub, &wm); + memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); + dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); DTN_INFO("HUBBUB WM: data_urgent pte_meta_urgent" " sr_enter sr_exit dram_clk_change\n"); @@ -636,8 +636,6 @@ static enum dc_status dcn10_enable_stream_timing( struct dc_stream_state *stream = pipe_ctx->stream; enum dc_color_space color_space; struct tg_color black_color = {0}; - struct drr_params params = {0}; - unsigned int event_triggers = 0; /* by upper caller loop, pipe0 is parent pipe and be called first. * back end is set up by for pipe0. Other children pipe share back end @@ -705,19 +703,6 @@ static enum dc_status dcn10_enable_stream_timing( return DC_ERROR_UNEXPECTED; } - params.vertical_total_min = stream->adjust.v_total_min; - params.vertical_total_max = stream->adjust.v_total_max; - if (pipe_ctx->stream_res.tg->funcs->set_drr) - pipe_ctx->stream_res.tg->funcs->set_drr( - pipe_ctx->stream_res.tg, ¶ms); - - // DRR should set trigger event to monitor surface update event - if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) - event_triggers = 0x80; - if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control) - pipe_ctx->stream_res.tg->funcs->set_static_screen_control( - pipe_ctx->stream_res.tg, event_triggers); - /* TODO program crtc source select for non-virtual signal*/ /* TODO program FMT */ /* TODO setup link_enc */ @@ -971,92 +956,34 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->pipe_idx); } -static void dcn10_init_hw(struct dc *dc) +static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) { int i; - struct abm *abm = dc->res_pool->abm; - struct dmcu *dmcu = dc->res_pool->dmcu; - struct dce_hwseq *hws = dc->hwseq; - struct dc_bios *dcb = dc->ctx->dc_bios; - struct dc_state *context = dc->current_state; - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - REG_WRITE(REFCLK_CNTL, 0); - REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); - REG_WRITE(DIO_MEM_PWR_CTRL, 0); - - if (!dc->debug.disable_clock_gate) { - /* enable all DCN clock gating */ - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); - } - - enable_power_gating_plane(dc->hwseq, true); - } else { - - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bool allow_self_fresh_force_enable = - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub); - - bios_golden_init(dc); - - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - if (allow_self_fresh_force_enable == false && - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - hubbub1_disable_allow_self_refresh(dc->res_pool->hubbub); - - disable_vga(dc->hwseq); - } - - for (i = 0; i < dc->link_count; i++) { - /* Power up AND update implementation according to the - * required signal (which may be different from the - * default signal on connector). - */ - struct dc_link *link = dc->links[i]; - - if (link->link_enc->connector.id == CONNECTOR_ID_EDP) - dc->hwss.edp_power_control(link, true); - - link->link_enc->funcs->hw_init(link->link_enc); - } - } for (i = 0; i < dc->res_pool->pipe_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; if (tg->funcs->is_tg_enabled(tg)) tg->funcs->lock(tg); - } - - /* Blank controller using driver code instead of - * command table. - */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; + /* Blank controller using driver code instead of + * command table. + */ if (tg->funcs->is_tg_enabled(tg)) { tg->funcs->set_blank(tg, true); hwss_wait_for_blank_complete(tg); } } - /* Reset all MPCC muxes */ dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); - for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = dc->res_pool->hubps[i]; struct dpp *dpp = dc->res_pool->dpps[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dpp->funcs->dpp_reset(dpp); pipe_ctx->stream_res.tg = tg; pipe_ctx->pipe_idx = i; @@ -1074,18 +1001,9 @@ static void dcn10_init_hw(struct dc *dc) pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; hwss1_plane_atomic_disconnect(dc, pipe_ctx); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct timing_generator *tg = dc->res_pool->timing_generators[i]; - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; dcn10_disable_plane(dc, pipe_ctx); @@ -1094,10 +1012,73 @@ static void dcn10_init_hw(struct dc *dc) tg->funcs->tg_init(tg); } +} - /* end of FPGA. Below if real ASIC */ - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) +static void dcn10_init_hw(struct dc *dc) +{ + int i; + struct abm *abm = dc->res_pool->abm; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(REFCLK_CNTL, 0); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + enable_power_gating_plane(dc->hwseq, true); + + /* end of FPGA. Below if real ASIC */ return; + } + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bool allow_self_fresh_force_enable = + hububu1_is_allow_self_refresh_enabled( + dc->res_pool->hubbub); + + bios_golden_init(dc); + + /* WA for making DF sleep when idle after resume from S0i3. + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 + * before calling command table and it changed to 1 after, + * it should be set back to 0. + */ + if (allow_self_fresh_force_enable == false && + hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); + + disable_vga(dc->hwseq); + } + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (link->link_enc->connector.id == CONNECTOR_ID_EDP) + dc->hwss.edp_power_control(link, true); + + link->link_enc->funcs->hw_init(link->link_enc); + + /* Check for enabled DIG to identify enabled display */ + if (link->link_enc->funcs->is_dig_enabled && + link->link_enc->funcs->is_dig_enabled(link->link_enc)) + link->link_status.link_active = true; + } for (i = 0; i < dc->res_pool->audio_count; i++) { struct audio *audio = dc->res_pool->audios[i]; @@ -1128,6 +1109,9 @@ static void dcn10_init_hw(struct dc *dc) enable_power_gating_plane(dc->hwseq, true); memset(&dc->res_pool->clk_mgr->clks, 0, sizeof(dc->res_pool->clk_mgr->clks)); + + if (dc->hwss.init_pipes) + dc->hwss.init_pipes(dc, dc->current_state); } static void reset_hw_ctx_wrap( @@ -1202,7 +1186,8 @@ static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_c pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( pipe_ctx->plane_res.hubp, &plane_state->address, - plane_state->flip_immediate); + plane_state->flip_immediate, + 0); plane_state->status.requested_address = plane_state->address; @@ -2048,7 +2033,7 @@ void update_dchubp_dpp( dc->res_pool->dccg->funcs->update_dpp_dto( dc->res_pool->dccg, dpp->inst, - pipe_ctx->plane_res.bw.calc.dppclk_khz); + pipe_ctx->plane_res.bw.dppclk_khz); else dc->res_pool->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? dc->res_pool->clk_mgr->clks.dispclk_khz / 2 : @@ -2125,7 +2110,8 @@ void update_dchubp_dpp( plane_state->update_flags.bits.swizzle_change || plane_state->update_flags.bits.dcc_change || plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change) { + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.plane_size_change) { hubp->funcs->hubp_program_surface_config( hubp, plane_state->format, @@ -2252,13 +2238,11 @@ static void program_all_pipe_in_tree( } - if (pipe_ctx->plane_state != NULL) { + if (pipe_ctx->plane_state != NULL) dcn10_program_pipe(dc, pipe_ctx, context); - } - if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) { + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); - } } struct pipe_ctx *find_top_pipe_for_stream( @@ -2334,9 +2318,10 @@ static void dcn10_apply_ctx_for_surface( } } - if (!pipe_ctx->plane_state && - old_pipe_ctx->plane_state && - old_pipe_ctx->stream_res.tg == tg) { + if ((!pipe_ctx->plane_state || + pipe_ctx->stream_res.tg != old_pipe_ctx->stream_res.tg) && + old_pipe_ctx->plane_state && + old_pipe_ctx->stream_res.tg == tg) { dc->hwss.plane_atomic_disconnect(dc, old_pipe_ctx); removed_pipe[i] = true; @@ -2355,29 +2340,22 @@ static void dcn10_apply_ctx_for_surface( top_pipe_to_program->plane_state->update_flags.bits.full_update) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - + tg = pipe_ctx->stream_res.tg; /* Skip inactive pipes and ones already updated */ if (!pipe_ctx->stream || pipe_ctx->stream == stream - || !pipe_ctx->plane_state) + || !pipe_ctx->plane_state + || !tg->funcs->is_tg_enabled(tg)) continue; - pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + tg->funcs->lock(tg); pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( pipe_ctx->plane_res.hubp, &pipe_ctx->dlg_regs, &pipe_ctx->ttu_regs); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - - if (!pipe_ctx->stream || pipe_ctx->stream == stream - || !pipe_ctx->plane_state) - continue; - dcn10_pipe_control_lock(dc, pipe_ctx, false); - } + tg->funcs->unlock(tg); + } if (num_planes == 0) false_optc_underflow_wa(dc, stream, tg); @@ -2390,6 +2368,22 @@ static void dcn10_apply_ctx_for_surface( hubbub1_wm_change_req_wa(dc->res_pool->hubbub); } +static void dcn10_stereo_hw_frame_pack_wa(struct dc *dc, struct dc_state *context) +{ + uint8_t i; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->timing.timing_3d_format + == TIMING_3D_FORMAT_HW_FRAME_PACKING) { + /* + * Disable stutter + */ + hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, false); + break; + } + } +} + static void dcn10_prepare_bandwidth( struct dc *dc, struct dc_state *context) @@ -2411,6 +2405,7 @@ static void dcn10_prepare_bandwidth( &context->bw.dcn.watermarks, dc->res_pool->ref_clock_inKhz / 1000, true); + dcn10_stereo_hw_frame_pack_wa(dc, context); if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) dcn_bw_notify_pplib_of_wm_ranges(dc); @@ -2440,6 +2435,7 @@ static void dcn10_optimize_bandwidth( &context->bw.dcn.watermarks, dc->res_pool->ref_clock_inKhz / 1000, true); + dcn10_stereo_hw_frame_pack_wa(dc, context); if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) dcn_bw_notify_pplib_of_wm_ranges(dc); @@ -2525,7 +2521,7 @@ static void dcn10_config_stereo_parameters( timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { enum display_dongle_type dongle = \ - stream->sink->link->ddc->dongle_type; + stream->link->ddc->dongle_type; if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) @@ -2656,7 +2652,7 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_cursor_mi_param param = { - .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz, + .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10, .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz, .viewport = pipe_ctx->plane_res.scl_data.viewport, .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz, @@ -2716,6 +2712,7 @@ static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) static const struct hw_sequencer_funcs dcn10_funcs = { .program_gamut_remap = program_gamut_remap, .init_hw = dcn10_init_hw, + .init_pipes = dcn10_init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, .update_plane_addr = dcn10_update_plane_addr, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index cd469014baa3..98f41d250978 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -40,7 +40,6 @@ #include "ipp.h" #include "mpc.h" #include "reg_helper.h" -#include "custom_float.h" #include "dcn10_hubp.h" #include "dcn10_hubbub.h" #include "dcn10_cm_common.h" @@ -72,7 +71,7 @@ static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, static unsigned int dcn10_get_hubbub_state(struct dc *dc, char *pBuf, unsigned int bufSize) { struct dc_context *dc_ctx = dc->ctx; - struct dcn_hubbub_wm wm = {0}; + struct dcn_hubbub_wm wm; int i; unsigned int chars_printed = 0; @@ -81,7 +80,8 @@ static unsigned int dcn10_get_hubbub_state(struct dc *dc, char *pBuf, unsigned i const uint32_t ref_clk_mhz = dc_ctx->dc->res_pool->ref_clock_inKhz / 1000; static const unsigned int frac = 1000; - hubbub1_wm_read_state(dc->res_pool->hubbub, &wm); + memset(&wm, 0, sizeof(struct dcn_hubbub_wm)); + dc->res_pool->hubbub->funcs->wm_read_state(dc->res_pool->hubbub, &wm); chars_printed = snprintf_count(pBuf, remaining_buffer, "wm_set_index,data_urgent,pte_meta_urgent,sr_enter,sr_exit,dram_clk_chanage\n"); remaining_buffer -= chars_printed; @@ -419,20 +419,22 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int unsigned int remaining_buffer = bufSize; chars_printed = snprintf_count(pBuf, remaining_buffer, "instance,v_bs,v_be,v_ss,v_se,vpol,vmax,vmin,vmax_sel,vmin_sel," - "h_bs,h_be,h_ss,h_se,hpol,htot,vtot,underflow\n"); + "h_bs,h_be,h_ss,h_se,hpol,htot,vtot,underflow,pixelclk[khz]\n"); remaining_buffer -= chars_printed; pBuf += chars_printed; for (i = 0; i < pool->timing_generator_count; i++) { struct timing_generator *tg = pool->timing_generators[i]; struct dcn_otg_state s = {0}; + int pix_clk = 0; optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + pix_clk = dc->current_state->res_ctx.pipe_ctx[i].stream_res.pix_clk_params.requested_pix_clk_100hz / 10; //only print if OTG master is enabled if (s.otg_enabled & 1) { chars_printed = snprintf_count(pBuf, remaining_buffer, "%x,%d,%d,%d,%d,%d,%d,%d,%d,%d," - "%d,%d,%d,%d,%d,%d,%d,%d" + "%d,%d,%d,%d,%d,%d,%d,%d,%d" "\n", tg->inst, s.v_blank_start, @@ -451,7 +453,8 @@ static unsigned int dcn10_get_otg_states(struct dc *dc, char *pBuf, unsigned int s.h_sync_a_pol, s.h_total, s.v_total, - s.underflow_occurred_status); + s.underflow_occurred_status, + pix_clk); remaining_buffer -= chars_printed; pBuf += chars_printed; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 477ab9222216..a9db372688ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c @@ -85,6 +85,7 @@ static const struct link_encoder_funcs dcn10_lnk_enc_funcs = { .enable_hpd = dcn10_link_encoder_enable_hpd, .disable_hpd = dcn10_link_encoder_disable_hpd, .is_dig_enabled = dcn10_is_dig_enabled, + .get_dig_frontend = dcn10_get_dig_frontend, .destroy = dcn10_link_encoder_destroy }; @@ -440,7 +441,7 @@ static uint8_t get_frontend_source( } } -void configure_encoder( +void enc1_configure_encoder( struct dcn10_link_encoder *enc10, const struct dc_link_settings *link_settings) { @@ -495,6 +496,15 @@ bool dcn10_is_dig_enabled(struct link_encoder *enc) return value; } +unsigned int dcn10_get_dig_frontend(struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + uint32_t value; + + REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value); + return value; +} + static void link_encoder_disable(struct dcn10_link_encoder *enc10) { /* reset training pattern */ @@ -543,12 +553,12 @@ bool dcn10_link_encoder_validate_dvi_output( if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK || connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) && signal != SIGNAL_TYPE_HDMI_TYPE_A && - crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK) + crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK * 10)) return false; - if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK) + if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10)) return false; - if (crtc_timing->pix_clk_khz > max_pixel_clock) + if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10)) return false; /* DVI supports 6/8bpp single-link and 10/16bpp dual-link */ @@ -571,7 +581,7 @@ bool dcn10_link_encoder_validate_dvi_output( static bool dcn10_link_encoder_validate_hdmi_output( const struct dcn10_link_encoder *enc10, const struct dc_crtc_timing *crtc_timing, - int adjusted_pix_clk_khz) + int adjusted_pix_clk_100hz) { enum dc_color_depth max_deep_color = enc10->base.features.max_hdmi_deep_color; @@ -581,11 +591,11 @@ static bool dcn10_link_encoder_validate_hdmi_output( if (crtc_timing->display_color_depth < COLOR_DEPTH_888) return false; - if (adjusted_pix_clk_khz < TMDS_MIN_PIXEL_CLOCK) + if (adjusted_pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10)) return false; - if ((adjusted_pix_clk_khz == 0) || - (adjusted_pix_clk_khz > enc10->base.features.max_hdmi_pixel_clock)) + if ((adjusted_pix_clk_100hz == 0) || + (adjusted_pix_clk_100hz > (enc10->base.features.max_hdmi_pixel_clock * 10))) return false; /* DCE11 HW does not support 420 */ @@ -594,7 +604,7 @@ static bool dcn10_link_encoder_validate_hdmi_output( return false; if (!enc10->base.features.flags.bits.HDMI_6GB_EN && - adjusted_pix_clk_khz >= 300000) + adjusted_pix_clk_100hz >= 3000000) return false; if (enc10->base.ctx->dc->debug.hdmi20_disable && crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) @@ -738,7 +748,7 @@ bool dcn10_link_encoder_validate_output_with_stream( case SIGNAL_TYPE_DVI_DUAL_LINK: is_valid = dcn10_link_encoder_validate_dvi_output( enc10, - stream->sink->link->connector_signal, + stream->link->connector_signal, stream->signal, &stream->timing); break; @@ -746,7 +756,7 @@ bool dcn10_link_encoder_validate_output_with_stream( is_valid = dcn10_link_encoder_validate_hdmi_output( enc10, &stream->timing, - stream->phy_pix_clk); + stream->phy_pix_clk * 10); break; case SIGNAL_TYPE_DISPLAY_PORT: case SIGNAL_TYPE_DISPLAY_PORT_MST: @@ -910,7 +920,7 @@ void dcn10_link_encoder_enable_dp_output( * but it's not passed to asic_control. * We need to set number of lanes manually. */ - configure_encoder(enc10, link_settings); + enc1_configure_encoder(enc10, link_settings); cntl.action = TRANSMITTER_CONTROL_ENABLE; cntl.engine_id = enc->preferred_engine; @@ -949,7 +959,7 @@ void dcn10_link_encoder_enable_dp_mst_output( * but it's not passed to asic_control. * We need to set number of lanes manually. */ - configure_encoder(enc10, link_settings); + enc1_configure_encoder(enc10, link_settings); cntl.action = TRANSMITTER_CONTROL_ENABLE; cntl.engine_id = ENGINE_ID_UNKNOWN; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h index 49ead12b2532..b74b80a247ec 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h @@ -271,7 +271,7 @@ void dcn10_link_encoder_setup( struct link_encoder *enc, enum signal_type signal); -void configure_encoder( +void enc1_configure_encoder( struct dcn10_link_encoder *enc10, const struct dc_link_settings *link_settings); @@ -336,6 +336,8 @@ void dcn10_psr_program_secondary_packet(struct link_encoder *enc, bool dcn10_is_dig_enabled(struct link_encoder *enc); +unsigned int dcn10_get_dig_frontend(struct link_encoder *enc); + void dcn10_aux_initialize(struct dcn10_link_encoder *enc10); #endif /* __DC_LINK_ENCODER__DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c index 7c138615f17d..2f78a84f0dcb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -97,6 +97,7 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c struct dc_crtc_timing patched_crtc_timing; int vesa_sync_start; int asic_blank_end; + int interlace_factor; int vertical_line_start; patched_crtc_timing = *dc_crtc_timing; @@ -110,13 +111,16 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c vesa_sync_start - patched_crtc_timing.h_border_left; + interlace_factor = patched_crtc_timing.flags.INTERLACE ? 2 : 1; + vesa_sync_start = patched_crtc_timing.v_addressable + patched_crtc_timing.v_border_bottom + patched_crtc_timing.v_front_porch; asic_blank_end = (patched_crtc_timing.v_total - vesa_sync_start - - patched_crtc_timing.v_border_top); + patched_crtc_timing.v_border_top) + * interlace_factor; vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; if (vertical_line_start < 0) { @@ -127,40 +131,95 @@ static uint32_t get_start_vline(struct timing_generator *optc, const struct dc_c return vertical_line_start; } -void optc1_program_vline_interrupt( +static void calc_vline_position( struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing, - unsigned long long vsync_delta) + unsigned long long vsync_delta, + uint32_t *start_line, + uint32_t *end_line) { - - struct optc *optc1 = DCN10TG_FROM_TG(optc); - unsigned long long req_delta_tens_of_usec = div64_u64((vsync_delta + 9999), 10000); - unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_khz + 99), 100); + unsigned long long pix_clk_hundreds_khz = div64_u64((dc_crtc_timing->pix_clk_100hz + 999), 1000); uint32_t req_delta_lines = (uint32_t) div64_u64( (req_delta_tens_of_usec * pix_clk_hundreds_khz + dc_crtc_timing->h_total - 1), dc_crtc_timing->h_total); uint32_t vsync_line = get_start_vline(optc, dc_crtc_timing); - uint32_t start_line = 0; - uint32_t endLine = 0; if (req_delta_lines != 0) - req_delta_lines--; + req_delta_lines--; - if (req_delta_lines > vsync_line) - start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) + 2; - else - start_line = vsync_line - req_delta_lines; + if (req_delta_lines > vsync_line) + *start_line = dc_crtc_timing->v_total - (req_delta_lines - vsync_line) - 1; + else + *start_line = vsync_line - req_delta_lines; + + *end_line = *start_line + 2; + + if (*end_line >= dc_crtc_timing->v_total) + *end_line = 2; +} + +void optc1_program_vline_interrupt( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, + enum vline_select vline, + const union vline_config *vline_config) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t start_line = 0; + uint32_t end_line = 0; + + switch (vline) { + case VLINE0: + calc_vline_position(optc, dc_crtc_timing, vline_config->delta_in_ns, &start_line, &end_line); + REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, + OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, + OTG_VERTICAL_INTERRUPT0_LINE_END, end_line); + break; + case VLINE1: + REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, + OTG_VERTICAL_INTERRUPT1_LINE_START, vline_config->line_number); + break; + default: + break; + } +} + +void optc1_program_vupdate_interrupt( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int32_t vertical_line_start; + uint32_t asic_blank_end; + uint32_t vesa_sync_start; + struct dc_crtc_timing patched_crtc_timing; + + patched_crtc_timing = *dc_crtc_timing; + optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); + + /* asic_h_blank_end = HsyncWidth + HbackPorch = + * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - + * vesa.h_left_border + */ + vesa_sync_start = patched_crtc_timing.h_addressable + + patched_crtc_timing.h_border_right + + patched_crtc_timing.h_front_porch; - endLine = start_line + 2; + asic_blank_end = patched_crtc_timing.h_total - + vesa_sync_start - + patched_crtc_timing.h_border_left; - if (endLine >= dc_crtc_timing->v_total) - endLine = 2; + /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, + * program the reg for interrupt postition. + */ + vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; + if (vertical_line_start < 0) + vertical_line_start = 0; - REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, - OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, - OTG_VERTICAL_INTERRUPT0_LINE_END, endLine); + REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, + OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); } /** @@ -265,22 +324,14 @@ void optc1_program_timing( patched_crtc_timing.v_addressable + patched_crtc_timing.v_border_bottom); - REG_UPDATE_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, asic_blank_start, - OTG_V_BLANK_END, asic_blank_end); - - /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, - * program the reg for interrupt postition. - */ vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; v_fp2 = 0; if (vertical_line_start < 0) v_fp2 = -vertical_line_start; - if (vertical_line_start < 0) - vertical_line_start = 0; - REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, - OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); + REG_UPDATE_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, asic_blank_start, + OTG_V_BLANK_END, asic_blank_end); /* v_sync polarity */ v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? @@ -299,16 +350,17 @@ void optc1_program_timing( } /* Interlace */ - if (patched_crtc_timing.flags.INTERLACE == 1) { - REG_UPDATE(OTG_INTERLACE_CONTROL, - OTG_INTERLACE_ENABLE, 1); - v_init = v_init / 2; - if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) - v_fp2 = v_fp2 / 2; - } else - REG_UPDATE(OTG_INTERLACE_CONTROL, - OTG_INTERLACE_ENABLE, 0); - + if (REG(OTG_INTERLACE_CONTROL)) { + if (patched_crtc_timing.flags.INTERLACE == 1) { + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 1); + v_init = v_init / 2; + if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) + v_fp2 = v_fp2 / 2; + } else + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 0); + } /* VTG enable set to 0 first VInit */ REG_UPDATE(CONTROL, @@ -338,7 +390,7 @@ void optc1_program_timing( h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_BY2, h_div_2); + OTG_H_TIMING_DIV_BY2, h_div_2 || optc1->comb_opp_id != 0xf); } @@ -1184,6 +1236,64 @@ bool optc1_is_stereo_left_eye(struct timing_generator *optc) return ret; } +bool optc1_is_matching_timing(struct timing_generator *tg, + const struct dc_crtc_timing *otg_timing) +{ + struct dc_crtc_timing hw_crtc_timing = {0}; + struct dcn_otg_state s = {0}; + + if (tg == NULL || otg_timing == NULL) + return false; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + hw_crtc_timing.h_total = s.h_total + 1; + hw_crtc_timing.h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); + hw_crtc_timing.h_front_porch = s.h_total + 1 - s.h_blank_start; + hw_crtc_timing.h_sync_width = s.h_sync_a_end - s.h_sync_a_start; + + hw_crtc_timing.v_total = s.v_total + 1; + hw_crtc_timing.v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); + hw_crtc_timing.v_front_porch = s.v_total + 1 - s.v_blank_start; + hw_crtc_timing.v_sync_width = s.v_sync_a_end - s.v_sync_a_start; + + if (otg_timing->h_total != hw_crtc_timing.h_total) + return false; + + if (otg_timing->h_border_left != hw_crtc_timing.h_border_left) + return false; + + if (otg_timing->h_addressable != hw_crtc_timing.h_addressable) + return false; + + if (otg_timing->h_border_right != hw_crtc_timing.h_border_right) + return false; + + if (otg_timing->h_front_porch != hw_crtc_timing.h_front_porch) + return false; + + if (otg_timing->h_sync_width != hw_crtc_timing.h_sync_width) + return false; + + if (otg_timing->v_total != hw_crtc_timing.v_total) + return false; + + if (otg_timing->v_border_top != hw_crtc_timing.v_border_top) + return false; + + if (otg_timing->v_addressable != hw_crtc_timing.v_addressable) + return false; + + if (otg_timing->v_border_bottom != hw_crtc_timing.v_border_bottom) + return false; + + if (otg_timing->v_sync_width != hw_crtc_timing.v_sync_width) + return false; + + return true; +} + + void optc1_read_otg_state(struct optc *optc1, struct dcn_otg_state *s) { @@ -1371,6 +1481,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, .program_vline_interrupt = optc1_program_vline_interrupt, + .program_vupdate_interrupt = optc1_program_vupdate_interrupt, .program_global_sync = optc1_program_global_sync, .enable_crtc = optc1_enable_crtc, .disable_crtc = optc1_disable_crtc, @@ -1380,6 +1491,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .get_frame_count = optc1_get_vblank_counter, .get_scanoutpos = optc1_get_crtc_scanoutpos, .get_otg_active_size = optc1_get_otg_active_size, + .is_matching_timing = optc1_is_matching_timing, .set_early_control = optc1_set_early_control, /* used by enable_timing_synchronization. Not need for FPGA */ .wait_for_state = optc1_wait_for_state, @@ -1419,10 +1531,13 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_v_blank_interlace = 5; optc1->min_h_sync_width = 8; optc1->min_v_sync_width = 1; + optc1->comb_opp_id = 0xf; } bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) { - return timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + + return two_pix; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h index 8bacf0b6e27e..24452f11c598 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -67,6 +67,8 @@ SRI(OTG_CLOCK_CONTROL, OTG, inst),\ SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ @@ -135,6 +137,8 @@ struct dcn_optc_registers { uint32_t OTG_CLOCK_CONTROL; uint32_t OTG_VERTICAL_INTERRUPT0_CONTROL; uint32_t OTG_VERTICAL_INTERRUPT0_POSITION; + uint32_t OTG_VERTICAL_INTERRUPT1_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT1_POSITION; uint32_t OTG_VERTICAL_INTERRUPT2_CONTROL; uint32_t OTG_VERTICAL_INTERRUPT2_POSITION; uint32_t OPTC_INPUT_CLOCK_CONTROL; @@ -227,6 +231,8 @@ struct dcn_optc_registers { SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ @@ -361,6 +367,8 @@ struct dcn_optc_registers { type OTG_VERTICAL_INTERRUPT0_INT_ENABLE;\ type OTG_VERTICAL_INTERRUPT0_LINE_START;\ type OTG_VERTICAL_INTERRUPT0_LINE_END;\ + type OTG_VERTICAL_INTERRUPT1_INT_ENABLE;\ + type OTG_VERTICAL_INTERRUPT1_LINE_START;\ type OTG_VERTICAL_INTERRUPT2_INT_ENABLE;\ type OTG_VERTICAL_INTERRUPT2_LINE_START;\ type OPTC_INPUT_CLK_EN;\ @@ -427,7 +435,7 @@ struct optc { const struct dcn_optc_shift *tg_shift; const struct dcn_optc_mask *tg_mask; - enum controller_id controller_id; + int comb_opp_id; uint32_t max_h_total; uint32_t max_v_total; @@ -475,9 +483,11 @@ void optc1_program_timing( const struct dc_crtc_timing *dc_crtc_timing, bool use_vbios); -void optc1_program_vline_interrupt(struct timing_generator *optc, +void optc1_program_vline_interrupt( + struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing, - unsigned long long vsync_delta); + enum vline_select vline, + const union vline_config *vline_config); void optc1_program_global_sync( struct timing_generator *optc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c index 5d4772dec0ba..09d74070a49b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -70,7 +70,7 @@ const struct _vcs_dpi_ip_params_st dcn1_0_ip = { .rob_buffer_size_kbytes = 64, .det_buffer_size_kbytes = 164, - .dpte_buffer_size_in_pte_reqs = 42, + .dpte_buffer_size_in_pte_reqs_luma = 42, .dpp_output_buffer_pixels = 2560, .opp_output_buffer_lines = 1, .pixel_chunk_size_kbytes = 8, @@ -436,7 +436,6 @@ static const struct dcn_optc_mask tg_mask = { }; static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_0), NBIO_SR(BIOS_SCRATCH_3), NBIO_SR(BIOS_SCRATCH_6) }; @@ -609,7 +608,7 @@ static struct output_pixel_processor *dcn10_opp_create( return &opp->base; } -struct aux_engine *dcn10_aux_engine_create( +struct dce_aux *dcn10_aux_engine_create( struct dc_context *ctx, uint32_t inst) { @@ -678,18 +677,18 @@ static struct mpc *dcn10_mpc_create(struct dc_context *ctx) static struct hubbub *dcn10_hubbub_create(struct dc_context *ctx) { - struct hubbub *hubbub = kzalloc(sizeof(struct hubbub), + struct dcn10_hubbub *dcn10_hubbub = kzalloc(sizeof(struct dcn10_hubbub), GFP_KERNEL); - if (!hubbub) + if (!dcn10_hubbub) return NULL; - hubbub1_construct(hubbub, ctx, + hubbub1_construct(&dcn10_hubbub->base, ctx, &hubbub_reg, &hubbub_shift, &hubbub_mask); - return hubbub; + return &dcn10_hubbub->base; } static struct timing_generator *dcn10_timing_generator_create( @@ -911,7 +910,7 @@ static void destruct(struct dcn10_resource_pool *pool) for (i = 0; i < pool->base.res_cap->num_ddc; i++) { if (pool->base.engines[i] != NULL) - pool->base.engines[i]->funcs->destroy_engine(&pool->base.engines[i]); + dce110_engine_destroy(&pool->base.engines[i]); if (pool->base.hw_i2cs[i] != NULL) { kfree(pool->base.hw_i2cs[i]); pool->base.hw_i2cs[i] = NULL; @@ -974,8 +973,8 @@ static void get_pixel_clock_parameters( struct pixel_clk_params *pixel_clk_params) { const struct dc_stream_state *stream = pipe_ctx->stream; - pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz; - pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id; + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + pixel_clk_params->encoder_object_id = stream->link->link_enc->id; pixel_clk_params->signal_type = pipe_ctx->stream->signal; pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; /* TODO: un-hardcode*/ @@ -991,9 +990,9 @@ static void get_pixel_clock_parameters( pixel_clk_params->color_depth = COLOR_DEPTH_888; if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - pixel_clk_params->requested_pix_clk /= 2; + pixel_clk_params->requested_pix_clk_100hz /= 2; if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clk_params->requested_pix_clk *= 2; + pixel_clk_params->requested_pix_clk_100hz *= 2; } @@ -1131,6 +1130,56 @@ static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_st return DC_OK; } +static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *context) +{ + int i, j; + bool video_down_scaled = false; + bool video_large = false; + bool desktop_large = false; + bool dcc_disabled = false; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 2) + return false; + + for (j = 0; j < context->stream_status[i].plane_count; j++) { + struct dc_plane_state *plane = + context->stream_status[i].plane_states[j]; + + + if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + + if (plane->src_rect.width > plane->dst_rect.width || + plane->src_rect.height > plane->dst_rect.height) + video_down_scaled = true; + + if (plane->src_rect.width >= 3840) + video_large = true; + + } else { + if (plane->src_rect.width >= 3840) + desktop_large = true; + if (!plane->dcc.enable) + dcc_disabled = true; + } + } + } + + /* + * Workaround: On DCN10 there is UMC issue that causes underflow when + * playing 4k video on 4k desktop with video downscaled and single channel + * memory + */ + if (video_large && desktop_large && video_down_scaled && dcc_disabled && + dc->dcn_soc->number_of_channels == 1) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + static enum dc_status dcn10_get_default_swizzle_mode(struct dc_plane_state *plane_state) { enum dc_status result = DC_OK; @@ -1159,6 +1208,7 @@ static const struct resource_funcs dcn10_res_pool_funcs = { .validate_bandwidth = dcn_validate_bandwidth, .acquire_idle_pipe_for_layer = dcn10_acquire_idle_pipe_for_layer, .validate_plane = dcn10_validate_plane, + .validate_global = dcn10_validate_global, .add_stream_to_ctx = dcn10_add_stream_to_ctx, .get_default_swizzle_mode = dcn10_get_default_swizzle_mode }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index b8b5525a389a..b08254121251 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -261,17 +261,29 @@ void enc1_stream_encoder_dp_set_stream_attribute( uint8_t dp_component_depth = 0; struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + struct dc_crtc_timing hw_crtc_timing = *crtc_timing; + + if (hw_crtc_timing.flags.INTERLACE) { + /*the input timing is in VESA spec format with Interlace flag =1*/ + hw_crtc_timing.v_total /= 2; + hw_crtc_timing.v_border_top /= 2; + hw_crtc_timing.v_addressable /= 2; + hw_crtc_timing.v_border_bottom /= 2; + hw_crtc_timing.v_front_porch /= 2; + hw_crtc_timing.v_sync_width /= 2; + } + /* set pixel encoding */ - switch (crtc_timing->pixel_encoding) { + switch (hw_crtc_timing.pixel_encoding) { case PIXEL_ENCODING_YCBCR422: dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR422; break; case PIXEL_ENCODING_YCBCR444: dp_pixel_encoding = DP_PIXEL_ENCODING_TYPE_YCBCR444; - if (crtc_timing->flags.Y_ONLY) - if (crtc_timing->display_color_depth != COLOR_DEPTH_666) + if (hw_crtc_timing.flags.Y_ONLY) + if (hw_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 @@ -299,7 +311,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care"). */ - if ((crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) || + if ((hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) || (output_color_space == COLOR_SPACE_2020_YCBCR) || (output_color_space == COLOR_SPACE_2020_RGB_FULLRANGE) || (output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE)) @@ -308,7 +320,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( misc1 = misc1 & ~0x40; /* set color depth */ - switch (crtc_timing->display_color_depth) { + switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666: dp_component_depth = DP_COMPONENT_PIXEL_DEPTH_6BPC; break; @@ -336,7 +348,7 @@ void enc1_stream_encoder_dp_set_stream_attribute( /* set dynamic range and YCbCr range */ - switch (crtc_timing->display_color_depth) { + switch (hw_crtc_timing.display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; break; @@ -372,9 +384,9 @@ void enc1_stream_encoder_dp_set_stream_attribute( misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ dynamic_range_ycbcr = 0; /*bt601*/ - if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ - else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) + else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_YCBCR709: @@ -382,9 +394,9 @@ void enc1_stream_encoder_dp_set_stream_attribute( misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */ misc1 = misc1 & ~0x80; /* bit7 = 0*/ dynamic_range_ycbcr = 1; /*bt709*/ - if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */ - else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) + else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444) misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */ break; case COLOR_SPACE_2020_RGB_LIMITEDRANGE: @@ -414,26 +426,26 @@ void enc1_stream_encoder_dp_set_stream_attribute( * dc_crtc_timing is vesa dmt struct. data from edid */ REG_SET_2(DP_MSA_TIMING_PARAM1, 0, - DP_MSA_HTOTAL, crtc_timing->h_total, - DP_MSA_VTOTAL, crtc_timing->v_total); + DP_MSA_HTOTAL, hw_crtc_timing.h_total, + DP_MSA_VTOTAL, hw_crtc_timing.v_total); /* calculate 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_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left - + hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right; - h_back_porch = h_blank - crtc_timing->h_front_porch - - crtc_timing->h_sync_width; + h_back_porch = h_blank - hw_crtc_timing.h_front_porch - + hw_crtc_timing.h_sync_width; /* start at beginning of left border */ - h_active_start = crtc_timing->h_sync_width + h_back_porch; + h_active_start = hw_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; + v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top - + hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom - + hw_crtc_timing.v_front_porch; /* start at beginning of left border */ @@ -443,20 +455,20 @@ void enc1_stream_encoder_dp_set_stream_attribute( REG_SET_4(DP_MSA_TIMING_PARAM3, 0, DP_MSA_HSYNCWIDTH, - crtc_timing->h_sync_width, + hw_crtc_timing.h_sync_width, DP_MSA_HSYNCPOLARITY, - !crtc_timing->flags.HSYNC_POSITIVE_POLARITY, + !hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY, DP_MSA_VSYNCWIDTH, - crtc_timing->v_sync_width, + hw_crtc_timing.v_sync_width, DP_MSA_VSYNCPOLARITY, - !crtc_timing->flags.VSYNC_POSITIVE_POLARITY); + !hw_crtc_timing.flags.VSYNC_POSITIVE_POLARITY); /* HWDITH include border or overscan */ 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); + DP_MSA_HWIDTH, hw_crtc_timing.h_border_left + + hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right, + DP_MSA_VHEIGHT, hw_crtc_timing.v_border_top + + hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom); } static void enc1_stream_encoder_set_stream_attribute_helper( @@ -594,7 +606,7 @@ void enc1_stream_encoder_dvi_set_stream_attribute( cntl.signal = is_dual_link ? SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK; cntl.enable_dp_audio = false; - cntl.pixel_clock = crtc_timing->pix_clk_khz; + cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10; cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR; if (enc1->base.bp->funcs->encoder_control( @@ -1413,6 +1425,14 @@ void enc1_setup_stereo_sync( REG_UPDATE(DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, !enable); } +void enc1_dig_connect_to_otg( + struct stream_encoder *enc, + int tg_inst) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst); +} static const struct stream_encoder_funcs dcn10_str_enc_funcs = { .dp_set_stream_attribute = @@ -1445,6 +1465,7 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = { .hdmi_audio_disable = enc1_se_hdmi_audio_disable, .setup_stereo_sync = enc1_setup_stereo_sync, .set_avmute = enc1_stream_encoder_set_avmute, + .dig_connect_to_otg = enc1_dig_connect_to_otg, }; void dcn10_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index 67f3e4dd95c1..b7c800e10a32 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h @@ -274,7 +274,8 @@ struct dcn10_stream_enc_registers { SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_HWIDTH, mask_sh),\ SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_VHEIGHT, mask_sh),\ SE_SF(DIG0_HDMI_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\ - SE_SF(DP0_DP_VID_TIMING, DP_VID_N_MUL, mask_sh) + SE_SF(DP0_DP_VID_TIMING, DP_VID_N_MUL, mask_sh),\ + SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh) #define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\ SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh) @@ -426,7 +427,8 @@ struct dcn10_stream_enc_registers { type DP_MSA_VHEIGHT;\ type HDMI_DB_DISABLE;\ type DP_VID_N_MUL;\ - type DP_VID_M_DOUBLE_VALUE_EN + type DP_VID_M_DOUBLE_VALUE_EN;\ + type DIG_SOURCE_SELECT struct dcn10_stream_encoder_shift { SE_REG_FIELD_LIST_DCN1_0(uint8_t); @@ -523,4 +525,8 @@ void enc1_se_hdmi_audio_setup( void enc1_se_hdmi_audio_disable( struct stream_encoder *enc); +void enc1_dig_connect_to_otg( + struct stream_encoder *enc, + int tg_inst); + #endif /* __DC_STREAM_ENCODER_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 5d4527d03045..e81b24374bcb 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -58,6 +58,13 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( bool enable); /* + * poll pending down reply before clear payload allocation table + */ +void dm_helpers_dp_mst_poll_pending_down_reply( + struct dc_context *ctx, + const struct dc_link *link); + +/* * Clear payload allocation table before enable MST DP link. */ void dm_helpers_dp_mst_clear_payload_allocation_table( diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index 0029a39efb1c..14bed5b1fa97 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -38,7 +38,8 @@ enum pp_smu_ver { * of interface sharing between families of ASIcs. */ PP_SMU_UNSUPPORTED, - PP_SMU_VER_RV + PP_SMU_VER_RV, + PP_SMU_VER_MAX }; struct pp_smu { diff --git a/drivers/gpu/drm/amd/display/dc/dm_services_types.h b/drivers/gpu/drm/amd/display/dc/dm_services_types.h index 1af8c777b3ac..77200711abbe 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h @@ -82,9 +82,17 @@ enum dm_pp_clock_type { #define DC_DECODE_PP_CLOCK_TYPE(clk_type) \ (clk_type) == DM_PP_CLOCK_TYPE_DISPLAY_CLK ? "Display" : \ (clk_type) == DM_PP_CLOCK_TYPE_ENGINE_CLK ? "Engine" : \ - (clk_type) == DM_PP_CLOCK_TYPE_MEMORY_CLK ? "Memory" : "Invalid" - -#define DM_PP_MAX_CLOCK_LEVELS 8 + (clk_type) == DM_PP_CLOCK_TYPE_MEMORY_CLK ? "Memory" : \ + (clk_type) == DM_PP_CLOCK_TYPE_DCFCLK ? "DCF" : \ + (clk_type) == DM_PP_CLOCK_TYPE_DCEFCLK ? "DCEF" : \ + (clk_type) == DM_PP_CLOCK_TYPE_SOCCLK ? "SoC" : \ + (clk_type) == DM_PP_CLOCK_TYPE_PIXELCLK ? "Pixel" : \ + (clk_type) == DM_PP_CLOCK_TYPE_DISPLAYPHYCLK ? "Display PHY" : \ + (clk_type) == DM_PP_CLOCK_TYPE_DPPCLK ? "DPP" : \ + (clk_type) == DM_PP_CLOCK_TYPE_FCLK ? "F" : \ + "Invalid" + +#define DM_PP_MAX_CLOCK_LEVELS 16 struct dm_pp_clock_levels { uint32_t num_levels; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h index bea4e61b94c7..c59e582c1f40 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h @@ -121,4 +121,30 @@ enum self_refresh_affinity { dm_neither_self_refresh_nor_mclk_switch }; +enum dm_validation_status { + DML_VALIDATION_OK, + DML_FAIL_SCALE_RATIO_TAP, + DML_FAIL_SOURCE_PIXEL_FORMAT, + DML_FAIL_VIEWPORT_SIZE, + DML_FAIL_TOTAL_V_ACTIVE_BW, + DML_FAIL_DIO_SUPPORT, + DML_FAIL_NOT_ENOUGH_DSC, + DML_FAIL_DSC_CLK_REQUIRED, + DML_FAIL_URGENT_LATENCY, + DML_FAIL_REORDERING_BUFFER, + DML_FAIL_DISPCLK_DPPCLK, + DML_FAIL_TOTAL_AVAILABLE_PIPES, + DML_FAIL_NUM_OTG, + DML_FAIL_WRITEBACK_MODE, + DML_FAIL_WRITEBACK_LATENCY, + DML_FAIL_WRITEBACK_SCALE_RATIO_TAP, + DML_FAIL_CURSOR_SUPPORT, + DML_FAIL_PITCH_SUPPORT, + DML_FAIL_PTE_BUFFER_SIZE, + DML_FAIL_HOST_VM_IMMEDIATE_FLIP, + DML_FAIL_DSC_INPUT_BPC, + DML_FAIL_PREFETCH_SUPPORT, + DML_FAIL_V_RATIO_PREFETCH, +}; + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index dddeb0d4db8f..d303b789adfe 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c @@ -62,3 +62,31 @@ void dml_init_instance(struct display_mode_lib *lib, enum dml_project project) } } +const char *dml_get_status_message(enum dm_validation_status status) +{ + switch (status) { + case DML_VALIDATION_OK: return "Validation OK"; + case DML_FAIL_SCALE_RATIO_TAP: return "Scale ratio/tap"; + case DML_FAIL_SOURCE_PIXEL_FORMAT: return "Source pixel format"; + case DML_FAIL_VIEWPORT_SIZE: return "Viewport size"; + case DML_FAIL_TOTAL_V_ACTIVE_BW: return "Total vertical active bandwidth"; + case DML_FAIL_DIO_SUPPORT: return "DIO support"; + case DML_FAIL_NOT_ENOUGH_DSC: return "Not enough DSC Units"; + case DML_FAIL_DSC_CLK_REQUIRED: return "DSC clock required"; + case DML_FAIL_URGENT_LATENCY: return "Urgent latency"; + case DML_FAIL_REORDERING_BUFFER: return "Re-ordering buffer"; + case DML_FAIL_DISPCLK_DPPCLK: return "Dispclk and Dppclk"; + case DML_FAIL_TOTAL_AVAILABLE_PIPES: return "Total available pipes"; + case DML_FAIL_NUM_OTG: return "Number of OTG"; + case DML_FAIL_WRITEBACK_MODE: return "Writeback mode"; + case DML_FAIL_WRITEBACK_LATENCY: return "Writeback latency"; + case DML_FAIL_WRITEBACK_SCALE_RATIO_TAP: return "Writeback scale ratio/tap"; + case DML_FAIL_CURSOR_SUPPORT: return "Cursor support"; + case DML_FAIL_PITCH_SUPPORT: return "Pitch support"; + case DML_FAIL_PTE_BUFFER_SIZE: return "PTE buffer size"; + case DML_FAIL_DSC_INPUT_BPC: return "DSC input bpc"; + case DML_FAIL_PREFETCH_SUPPORT: return "Prefetch support"; + case DML_FAIL_V_RATIO_PREFETCH: return "Vertical ratio prefetch"; + default: return "Unknown Status"; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h index 635206248889..a730e0209c05 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h @@ -43,4 +43,6 @@ struct display_mode_lib { void dml_init_instance(struct display_mode_lib *lib, enum dml_project project); +const char *dml_get_status_message(enum dm_validation_status status); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 5dd04520ceca..391183e3428f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h @@ -30,22 +30,15 @@ typedef struct _vcs_dpi_soc_bounding_box_st soc_bounding_box_st; typedef struct _vcs_dpi_ip_params_st ip_params_st; typedef struct _vcs_dpi_display_pipe_source_params_st display_pipe_source_params_st; typedef struct _vcs_dpi_display_output_params_st display_output_params_st; -typedef struct _vcs_dpi_display_bandwidth_st display_bandwidth_st; typedef struct _vcs_dpi_scaler_ratio_depth_st scaler_ratio_depth_st; typedef struct _vcs_dpi_scaler_taps_st scaler_taps_st; typedef struct _vcs_dpi_display_pipe_dest_params_st display_pipe_dest_params_st; typedef struct _vcs_dpi_display_pipe_params_st display_pipe_params_st; typedef struct _vcs_dpi_display_clocks_and_cfg_st display_clocks_and_cfg_st; typedef struct _vcs_dpi_display_e2e_pipe_params_st display_e2e_pipe_params_st; -typedef struct _vcs_dpi_dchub_buffer_sizing_st dchub_buffer_sizing_st; -typedef struct _vcs_dpi_watermarks_perf_st watermarks_perf_st; -typedef struct _vcs_dpi_cstate_pstate_watermarks_st cstate_pstate_watermarks_st; -typedef struct _vcs_dpi_wm_calc_pipe_params_st wm_calc_pipe_params_st; -typedef struct _vcs_dpi_vratio_pre_st vratio_pre_st; typedef struct _vcs_dpi_display_data_rq_misc_params_st display_data_rq_misc_params_st; typedef struct _vcs_dpi_display_data_rq_sizing_params_st display_data_rq_sizing_params_st; typedef struct _vcs_dpi_display_data_rq_dlg_params_st display_data_rq_dlg_params_st; -typedef struct _vcs_dpi_display_cur_rq_dlg_params_st display_cur_rq_dlg_params_st; typedef struct _vcs_dpi_display_rq_dlg_params_st display_rq_dlg_params_st; typedef struct _vcs_dpi_display_rq_sizing_params_st display_rq_sizing_params_st; typedef struct _vcs_dpi_display_rq_misc_params_st display_rq_misc_params_st; @@ -55,8 +48,6 @@ typedef struct _vcs_dpi_display_ttu_regs_st display_ttu_regs_st; typedef struct _vcs_dpi_display_data_rq_regs_st display_data_rq_regs_st; typedef struct _vcs_dpi_display_rq_regs_st display_rq_regs_st; typedef struct _vcs_dpi_display_dlg_sys_params_st display_dlg_sys_params_st; -typedef struct _vcs_dpi_display_dlg_prefetch_param_st display_dlg_prefetch_param_st; -typedef struct _vcs_dpi_display_pipe_clock_st display_pipe_clock_st; typedef struct _vcs_dpi_display_arb_params_st display_arb_params_st; struct _vcs_dpi_voltage_scaling_st { @@ -111,8 +102,6 @@ struct _vcs_dpi_soc_bounding_box_st { double xfc_bus_transport_time_us; double xfc_xbuf_latency_tolerance_us; int use_urgent_burst_bw; - double max_hscl_ratio; - double max_vscl_ratio; unsigned int num_states; struct _vcs_dpi_voltage_scaling_st clock_limits[8]; }; @@ -129,7 +118,8 @@ struct _vcs_dpi_ip_params_st { unsigned int odm_capable; unsigned int rob_buffer_size_kbytes; unsigned int det_buffer_size_kbytes; - unsigned int dpte_buffer_size_in_pte_reqs; + unsigned int dpte_buffer_size_in_pte_reqs_luma; + unsigned int dpte_buffer_size_in_pte_reqs_chroma; unsigned int pde_proc_buffer_size_64k_reqs; unsigned int dpp_output_buffer_pixels; unsigned int opp_output_buffer_lines; @@ -192,7 +182,6 @@ struct _vcs_dpi_display_xfc_params_st { struct _vcs_dpi_display_pipe_source_params_st { int source_format; unsigned char dcc; - unsigned int dcc_override; unsigned int dcc_rate; unsigned char dcc_use_global; unsigned char vm; @@ -205,7 +194,6 @@ struct _vcs_dpi_display_pipe_source_params_st { int source_scan; int sw_mode; int macro_tile_size; - unsigned char is_display_sw; unsigned int viewport_width; unsigned int viewport_height; unsigned int viewport_y_y; @@ -252,16 +240,10 @@ struct _vcs_dpi_display_output_params_st { int output_bpc; int output_type; int output_format; - int output_standard; int dsc_slices; struct writeback_st wb; }; -struct _vcs_dpi_display_bandwidth_st { - double total_bw_consumed_gbps; - double guaranteed_urgent_return_bw_gbps; -}; - struct _vcs_dpi_scaler_ratio_depth_st { double hscl_ratio; double vscl_ratio; @@ -300,11 +282,9 @@ struct _vcs_dpi_display_pipe_dest_params_st { unsigned int vupdate_width; unsigned int vready_offset; unsigned char interlaced; - unsigned char underscan; double pixel_rate_mhz; unsigned char synchronized_vblank_all_planes; unsigned char otg_inst; - unsigned char odm_split_cnt; unsigned char odm_combine; unsigned char use_maximum_vstartup; }; @@ -331,65 +311,6 @@ struct _vcs_dpi_display_e2e_pipe_params_st { display_clocks_and_cfg_st clks_cfg; }; -struct _vcs_dpi_dchub_buffer_sizing_st { - unsigned int swath_width_y; - unsigned int swath_height_y; - unsigned int swath_height_c; - unsigned int detail_buffer_size_y; -}; - -struct _vcs_dpi_watermarks_perf_st { - double stutter_eff_in_active_region_percent; - double urgent_latency_supported_us; - double non_urgent_latency_supported_us; - double dram_clock_change_margin_us; - double dram_access_eff_percent; -}; - -struct _vcs_dpi_cstate_pstate_watermarks_st { - double cstate_exit_us; - double cstate_enter_plus_exit_us; - double pstate_change_us; -}; - -struct _vcs_dpi_wm_calc_pipe_params_st { - unsigned int num_dpp; - int voltage; - int output_type; - double dcfclk_mhz; - double socclk_mhz; - double dppclk_mhz; - double pixclk_mhz; - unsigned char interlace_en; - unsigned char pte_enable; - unsigned char dcc_enable; - double dcc_rate; - double bytes_per_pixel_c; - double bytes_per_pixel_y; - unsigned int swath_width_y; - unsigned int swath_height_y; - unsigned int swath_height_c; - unsigned int det_buffer_size_y; - double h_ratio; - double v_ratio; - unsigned int h_taps; - unsigned int h_total; - unsigned int v_total; - unsigned int v_active; - unsigned int e2e_index; - double display_pipe_line_delivery_time; - double read_bw; - unsigned int lines_in_det_y; - unsigned int lines_in_det_y_rounded_down_to_swath; - double full_det_buffering_time; - double dcfclk_deepsleep_mhz_per_plane; -}; - -struct _vcs_dpi_vratio_pre_st { - double vratio_pre_l; - double vratio_pre_c; -}; - struct _vcs_dpi_display_data_rq_misc_params_st { unsigned int full_swath_bytes; unsigned int stored_swath_bytes; @@ -423,16 +344,9 @@ struct _vcs_dpi_display_data_rq_dlg_params_st { unsigned int meta_bytes_per_row_ub; }; -struct _vcs_dpi_display_cur_rq_dlg_params_st { - unsigned char enable; - unsigned int swath_height; - unsigned int req_per_line; -}; - struct _vcs_dpi_display_rq_dlg_params_st { display_data_rq_dlg_params_st rq_l; display_data_rq_dlg_params_st rq_c; - display_cur_rq_dlg_params_st rq_cur0; }; struct _vcs_dpi_display_rq_sizing_params_st { @@ -498,6 +412,10 @@ struct _vcs_dpi_display_dlg_regs_st { unsigned int xfc_reg_remote_surface_flip_latency; unsigned int xfc_reg_prefetch_margin; unsigned int dst_y_delta_drq_limit; + unsigned int refcyc_per_vm_group_vblank; + unsigned int refcyc_per_vm_group_flip; + unsigned int refcyc_per_vm_req_vblank; + unsigned int refcyc_per_vm_req_flip; }; struct _vcs_dpi_display_ttu_regs_st { @@ -556,19 +474,6 @@ struct _vcs_dpi_display_dlg_sys_params_st { unsigned int total_flip_bytes; }; -struct _vcs_dpi_display_dlg_prefetch_param_st { - double prefetch_bw; - unsigned int flip_bytes; -}; - -struct _vcs_dpi_display_pipe_clock_st { - double dcfclk_mhz; - double dispclk_mhz; - double socclk_mhz; - double dscclk_mhz[6]; - double dppclk_mhz[6]; -}; - struct _vcs_dpi_display_arb_params_st { int max_req_outstanding; int min_req_outstanding; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c index c2037daa8e66..ad8571f5a142 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c @@ -459,7 +459,7 @@ static void dml1_rq_dlg_get_row_heights( /* dpte */ /* ------ */ log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes); - dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs; + dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma; log2_vmpg_height = 0; log2_vmpg_width = 0; @@ -776,7 +776,7 @@ static void get_surf_rq_param( /* dpte */ /* ------ */ log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes); - dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs; + dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma; log2_vmpg_height = 0; log2_vmpg_width = 0; @@ -881,7 +881,7 @@ static void get_surf_rq_param( /* the dpte_group_bytes is reduced for the specific case of vertical * access of a tile surface that has dpte request of 8x1 ptes. */ - if (!surf_linear & (log2_dpte_req_height_ptes == 0) & surf_vert) /*reduced, in this case, will have page fault within a group */ + if (!surf_linear && (log2_dpte_req_height_ptes == 0) && surf_vert) /*reduced, in this case, will have page fault within a group */ rq_sizing_param->dpte_group_bytes = 512; else /*full size */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c index 1d1efd72b291..cf76ea2d9f5a 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c @@ -101,6 +101,18 @@ enum gpio_mode dal_gpio_get_mode( return gpio->mode; } +enum gpio_result dal_gpio_lock_pin( + struct gpio *gpio) +{ + return dal_gpio_service_lock(gpio->service, gpio->id, gpio->en); +} + +enum gpio_result dal_gpio_unlock_pin( + struct gpio *gpio) +{ + return dal_gpio_service_unlock(gpio->service, gpio->id, gpio->en); +} + enum gpio_result dal_gpio_change_mode( struct gpio *gpio, enum gpio_mode mode) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index dada04296025..3c63a3c04dbb 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -192,6 +192,34 @@ static void set_pin_free( service->busyness[id][en] = false; } +enum gpio_result dal_gpio_service_lock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en) +{ + if (!service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } + + set_pin_busy(service, id, en); + return GPIO_RESULT_OK; +} + +enum gpio_result dal_gpio_service_unlock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en) +{ + if (!service->busyness[id]) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_OPEN_FAILED; + } + + set_pin_free(service, id, en); + return GPIO_RESULT_OK; +} + enum gpio_result dal_gpio_service_open( struct gpio_service *service, enum gpio_id id, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h index 1d501a43d13b..0c678af75331 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h @@ -52,4 +52,14 @@ void dal_gpio_service_close( struct gpio_service *service, struct hw_gpio_pin **ptr); +enum gpio_result dal_gpio_service_lock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en); + +enum gpio_result dal_gpio_service_unlock( + struct gpio_service *service, + enum gpio_id id, + uint32_t en); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile deleted file mode 100644 index 352885cb4d07..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile +++ /dev/null @@ -1,99 +0,0 @@ -# -# Copyright 2017 Advanced Micro Devices, Inc. -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# -# Makefile for the 'i2c' sub-component of DAL. -# It provides the control and status of HW i2c engine of the adapter. - -I2CAUX = aux_engine.o engine_base.o i2caux.o i2c_engine.o \ - i2c_generic_hw_engine.o i2c_hw_engine.o i2c_sw_engine.o - -AMD_DAL_I2CAUX = $(addprefix $(AMDDALPATH)/dc/i2caux/,$(I2CAUX)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX) - -############################################################################### -# DCE 8x family -############################################################################### -I2CAUX_DCE80 = i2caux_dce80.o i2c_hw_engine_dce80.o \ - i2c_sw_engine_dce80.o - -AMD_DAL_I2CAUX_DCE80 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce80/,$(I2CAUX_DCE80)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE80) - -############################################################################### -# DCE 100 family -############################################################################### -I2CAUX_DCE100 = i2caux_dce100.o - -AMD_DAL_I2CAUX_DCE100 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce100/,$(I2CAUX_DCE100)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE100) - -############################################################################### -# DCE 110 family -############################################################################### -I2CAUX_DCE110 = i2caux_dce110.o i2c_sw_engine_dce110.o i2c_hw_engine_dce110.o \ - aux_engine_dce110.o - -AMD_DAL_I2CAUX_DCE110 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce110/,$(I2CAUX_DCE110)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE110) - -############################################################################### -# DCE 112 family -############################################################################### -I2CAUX_DCE112 = i2caux_dce112.o - -AMD_DAL_I2CAUX_DCE112 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce112/,$(I2CAUX_DCE112)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE112) - -############################################################################### -# DCN 1.0 family -############################################################################### -ifdef CONFIG_DRM_AMD_DC_DCN1_0 -I2CAUX_DCN1 = i2caux_dcn10.o - -AMD_DAL_I2CAUX_DCN1 = $(addprefix $(AMDDALPATH)/dc/i2caux/dcn10/,$(I2CAUX_DCN1)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCN1) -endif - -############################################################################### -# DCE 120 family -############################################################################### -I2CAUX_DCE120 = i2caux_dce120.o - -AMD_DAL_I2CAUX_DCE120 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce120/,$(I2CAUX_DCE120)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE120) - -############################################################################### -# Diagnostics on FPGA -############################################################################### -I2CAUX_DIAG = i2caux_diag.o - -AMD_DAL_I2CAUX_DIAG = $(addprefix $(AMDDALPATH)/dc/i2caux/diagnostics/,$(I2CAUX_DIAG)) - -AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DIAG) - diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c deleted file mode 100644 index 8cbf38b2470d..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dm_event_log.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "engine.h" - -/* - * Header of this unit - */ - -#include "aux_engine.h" - -/* - * Post-requisites: headers required by this unit - */ - -#include "include/link_service_types.h" - -/* - * This unit - */ - -enum { - AUX_INVALID_REPLY_RETRY_COUNTER = 1, - AUX_TIMED_OUT_RETRY_COUNTER = 2, - AUX_DEFER_RETRY_COUNTER = 6 -}; - -#define FROM_ENGINE(ptr) \ - container_of((ptr), struct aux_engine, base) -#define DC_LOGGER \ - engine->base.ctx->logger - -enum i2caux_engine_type dal_aux_engine_get_engine_type( - const struct engine *engine) -{ - return I2CAUX_ENGINE_TYPE_AUX; -} - -bool dal_aux_engine_acquire( - struct engine *engine, - struct ddc *ddc) -{ - struct aux_engine *aux_engine = FROM_ENGINE(engine); - - enum gpio_result result; - if (aux_engine->funcs->is_engine_available) { - /*check whether SW could use the engine*/ - if (!aux_engine->funcs->is_engine_available(aux_engine)) { - return false; - } - } - - result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, - GPIO_DDC_CONFIG_TYPE_MODE_AUX); - - if (result != GPIO_RESULT_OK) - return false; - - if (!aux_engine->funcs->acquire_engine(aux_engine)) { - dal_ddc_close(ddc); - return false; - } - - engine->ddc = ddc; - - return true; -} - -struct read_command_context { - uint8_t *buffer; - uint32_t current_read_length; - uint32_t offset; - enum i2caux_transaction_status status; - - struct aux_request_transaction_data request; - struct aux_reply_transaction_data reply; - - uint8_t returned_byte; - - uint32_t timed_out_retry_aux; - uint32_t invalid_reply_retry_aux; - uint32_t defer_retry_aux; - uint32_t defer_retry_i2c; - uint32_t invalid_reply_retry_aux_on_ack; - - bool transaction_complete; - bool operation_succeeded; -}; - -static void process_read_reply( - struct aux_engine *engine, - struct read_command_context *ctx) -{ - engine->funcs->process_channel_reply(engine, &ctx->reply); - - switch (ctx->reply.status) { - case AUX_TRANSACTION_REPLY_AUX_ACK: - ctx->defer_retry_aux = 0; - if (ctx->returned_byte > ctx->current_read_length) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else if (ctx->returned_byte < ctx->current_read_length) { - ctx->current_read_length -= ctx->returned_byte; - - ctx->offset += ctx->returned_byte; - - ++ctx->invalid_reply_retry_aux_on_ack; - - if (ctx->invalid_reply_retry_aux_on_ack > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } - } else { - ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - ctx->transaction_complete = true; - ctx->operation_succeeded = true; - } - break; - case AUX_TRANSACTION_REPLY_AUX_NACK: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - ctx->operation_succeeded = false; - break; - case AUX_TRANSACTION_REPLY_AUX_DEFER: - ++ctx->defer_retry_aux; - - if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_I2C_DEFER: - ctx->defer_retry_aux = 0; - - ++ctx->defer_retry_i2c; - - if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} - -static void process_read_request( - struct aux_engine *engine, - struct read_command_context *ctx) -{ - enum aux_channel_operation_result operation_result; - - engine->funcs->submit_channel_request(engine, &ctx->request); - - operation_result = engine->funcs->get_channel_status( - engine, &ctx->returned_byte); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - if (ctx->returned_byte > ctx->current_read_length) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else { - ctx->timed_out_retry_aux = 0; - ctx->invalid_reply_retry_aux = 0; - - ctx->reply.length = ctx->returned_byte; - ctx->reply.data = ctx->buffer; - - process_read_reply(engine, ctx); - } - break; - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - ++ctx->invalid_reply_retry_aux; - - if (ctx->invalid_reply_retry_aux > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else - udelay(400); - break; - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - ++ctx->timed_out_retry_aux; - - if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else { - /* DP 1.2a, table 2-58: - * "S3: AUX Request CMD PENDING: - * retry 3 times, with 400usec wait on each" - * The HW timeout is set to 550usec, - * so we should not wait here */ - } - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} - -static bool read_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - struct read_command_context ctx; - - ctx.buffer = request->payload.data; - ctx.current_read_length = request->payload.length; - ctx.offset = 0; - ctx.timed_out_retry_aux = 0; - ctx.invalid_reply_retry_aux = 0; - ctx.defer_retry_aux = 0; - ctx.defer_retry_i2c = 0; - ctx.invalid_reply_retry_aux_on_ack = 0; - ctx.transaction_complete = false; - ctx.operation_succeeded = true; - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - ctx.request.type = AUX_TRANSACTION_TYPE_DP; - ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ; - ctx.request.address = request->payload.address; - } else if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { - ctx.request.type = AUX_TRANSACTION_TYPE_I2C; - ctx.request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_READ; - ctx.request.address = request->payload.address >> 1; - } else { - /* in DAL2, there was no return in such case */ - BREAK_TO_DEBUGGER(); - return false; - } - - ctx.request.delay = 0; - - do { - memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length); - - ctx.request.data = ctx.buffer + ctx.offset; - ctx.request.length = ctx.current_read_length; - - process_read_request(engine, &ctx); - - request->status = ctx.status; - - if (ctx.operation_succeeded && !ctx.transaction_complete) - if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) - msleep(engine->delay); - } while (ctx.operation_succeeded && !ctx.transaction_complete); - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d", - request->payload.address, - request->payload.data[0], - ctx.operation_succeeded); - } - - return ctx.operation_succeeded; -} - -struct write_command_context { - bool mot; - - uint8_t *buffer; - uint32_t current_write_length; - enum i2caux_transaction_status status; - - struct aux_request_transaction_data request; - struct aux_reply_transaction_data reply; - - uint8_t returned_byte; - - uint32_t timed_out_retry_aux; - uint32_t invalid_reply_retry_aux; - uint32_t defer_retry_aux; - uint32_t defer_retry_i2c; - uint32_t max_defer_retry; - uint32_t ack_m_retry; - - uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE]; - - bool transaction_complete; - bool operation_succeeded; -}; - -static void process_write_reply( - struct aux_engine *engine, - struct write_command_context *ctx) -{ - engine->funcs->process_channel_reply(engine, &ctx->reply); - - switch (ctx->reply.status) { - case AUX_TRANSACTION_REPLY_AUX_ACK: - ctx->operation_succeeded = true; - - if (ctx->returned_byte) { - ctx->request.action = ctx->mot ? - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; - - ctx->current_write_length = 0; - - ++ctx->ack_m_retry; - - if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else - udelay(300); - } else { - ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - ctx->defer_retry_aux = 0; - ctx->ack_m_retry = 0; - ctx->transaction_complete = true; - } - break; - case AUX_TRANSACTION_REPLY_AUX_NACK: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - ctx->operation_succeeded = false; - break; - case AUX_TRANSACTION_REPLY_AUX_DEFER: - ++ctx->defer_retry_aux; - - if (ctx->defer_retry_aux > ctx->max_defer_retry) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_I2C_DEFER: - ctx->defer_retry_aux = 0; - ctx->current_write_length = 0; - - ctx->request.action = ctx->mot ? - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST; - - ++ctx->defer_retry_i2c; - - if (ctx->defer_retry_i2c > ctx->max_defer_retry) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } - break; - case AUX_TRANSACTION_REPLY_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} - -static void process_write_request( - struct aux_engine *engine, - struct write_command_context *ctx) -{ - enum aux_channel_operation_result operation_result; - - engine->funcs->submit_channel_request(engine, &ctx->request); - - operation_result = engine->funcs->get_channel_status( - engine, &ctx->returned_byte); - - switch (operation_result) { - case AUX_CHANNEL_OPERATION_SUCCEEDED: - ctx->timed_out_retry_aux = 0; - ctx->invalid_reply_retry_aux = 0; - - ctx->reply.length = ctx->returned_byte; - ctx->reply.data = ctx->reply_data; - - process_write_reply(engine, ctx); - break; - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: - ++ctx->invalid_reply_retry_aux; - - if (ctx->invalid_reply_retry_aux > - AUX_INVALID_REPLY_RETRY_COUNTER) { - ctx->status = - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR; - ctx->operation_succeeded = false; - } else - udelay(400); - break; - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: - ++ctx->timed_out_retry_aux; - - if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) { - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - ctx->operation_succeeded = false; - } else { - /* DP 1.2a, table 2-58: - * "S3: AUX Request CMD PENDING: - * retry 3 times, with 400usec wait on each" - * The HW timeout is set to 550usec, - * so we should not wait here */ - } - break; - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: - ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON; - ctx->operation_succeeded = false; - break; - default: - ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN; - ctx->operation_succeeded = false; - } -} - -static bool write_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - struct write_command_context ctx; - - ctx.mot = middle_of_transaction; - ctx.buffer = request->payload.data; - ctx.current_write_length = request->payload.length; - ctx.timed_out_retry_aux = 0; - ctx.invalid_reply_retry_aux = 0; - ctx.defer_retry_aux = 0; - ctx.defer_retry_i2c = 0; - ctx.ack_m_retry = 0; - ctx.transaction_complete = false; - ctx.operation_succeeded = true; - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - ctx.request.type = AUX_TRANSACTION_TYPE_DP; - ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE; - ctx.request.address = request->payload.address; - } else if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) { - ctx.request.type = AUX_TRANSACTION_TYPE_I2C; - ctx.request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - ctx.request.address = request->payload.address >> 1; - } else { - /* in DAL2, there was no return in such case */ - BREAK_TO_DEBUGGER(); - return false; - } - - ctx.request.delay = 0; - - ctx.max_defer_retry = - (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ? - engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER; - - do { - ctx.request.data = ctx.buffer; - ctx.request.length = ctx.current_write_length; - - process_write_request(engine, &ctx); - - request->status = ctx.status; - - if (ctx.operation_succeeded && !ctx.transaction_complete) - if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C) - msleep(engine->delay); - } while (ctx.operation_succeeded && !ctx.transaction_complete); - - if (request->payload.address_space == - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) { - DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d", - request->payload.address, - request->payload.data[0], - ctx.operation_succeeded); - } - - return ctx.operation_succeeded; -} - -static bool end_of_transaction_command( - struct aux_engine *engine, - struct i2caux_transaction_request *request) -{ - struct i2caux_transaction_request dummy_request; - uint8_t dummy_data; - - /* [tcheng] We only need to send the stop (read with MOT = 0) - * for I2C-over-Aux, not native AUX */ - - if (request->payload.address_space != - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) - return false; - - dummy_request.operation = request->operation; - dummy_request.payload.address_space = request->payload.address_space; - dummy_request.payload.address = request->payload.address; - - /* - * Add a dummy byte due to some receiver quirk - * where one byte is sent along with MOT = 0. - * Ideally this should be 0. - */ - - dummy_request.payload.length = 0; - dummy_request.payload.data = &dummy_data; - - if (request->operation == I2CAUX_TRANSACTION_READ) - return read_command(engine, &dummy_request, false); - else - return write_command(engine, &dummy_request, false); - - /* according Syed, it does not need now DoDummyMOT */ -} - -bool dal_aux_engine_submit_request( - struct engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction) -{ - struct aux_engine *aux_engine = FROM_ENGINE(engine); - - bool result; - bool mot_used = true; - - switch (request->operation) { - case I2CAUX_TRANSACTION_READ: - result = read_command(aux_engine, request, mot_used); - break; - case I2CAUX_TRANSACTION_WRITE: - result = write_command(aux_engine, request, mot_used); - break; - default: - result = false; - } - - /* [tcheng] - * need to send stop for the last transaction to free up the AUX - * if the above command fails, this would be the last transaction */ - - if (!middle_of_transaction || !result) - end_of_transaction_command(aux_engine, request); - - /* mask AUX interrupt */ - - return result; -} - -void dal_aux_engine_construct( - struct aux_engine *engine, - struct dc_context *ctx) -{ - dal_i2caux_construct_engine(&engine->base, ctx); - engine->delay = 0; - engine->max_defer_write_retry = 0; -} - -void dal_aux_engine_destruct( - struct aux_engine *engine) -{ - dal_i2caux_destruct_engine(&engine->base); -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h deleted file mode 100644 index c33a2898d967..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_AUX_ENGINE_H__ -#define __DAL_AUX_ENGINE_H__ - -#include "dc_ddc_types.h" - -struct aux_engine; - -struct aux_engine_funcs { - void (*destroy)( - struct aux_engine **ptr); - bool (*acquire_engine)( - struct aux_engine *engine); - void (*configure)( - struct aux_engine *engine, - union aux_config cfg); - void (*submit_channel_request)( - struct aux_engine *engine, - struct aux_request_transaction_data *request); - void (*process_channel_reply)( - struct aux_engine *engine, - struct aux_reply_transaction_data *reply); - int (*read_channel_reply)( - struct aux_engine *engine, - uint32_t size, - uint8_t *buffer, - uint8_t *reply_result, - uint32_t *sw_status); - enum aux_channel_operation_result (*get_channel_status)( - struct aux_engine *engine, - uint8_t *returned_bytes); - bool (*is_engine_available) ( - struct aux_engine *engine); -}; - -struct aux_engine { - struct engine base; - const struct aux_engine_funcs *funcs; - /* following values are expressed in milliseconds */ - uint32_t delay; - uint32_t max_defer_write_retry; - - bool acquire_reset; -}; - -void dal_aux_engine_construct( - struct aux_engine *engine, - struct dc_context *ctx); - -void dal_aux_engine_destruct( - struct aux_engine *engine); -bool dal_aux_engine_submit_request( - struct engine *ptr, - struct i2caux_transaction_request *request, - bool middle_of_transaction); -bool dal_aux_engine_acquire( - struct engine *ptr, - struct ddc *ddc); -enum i2caux_engine_type dal_aux_engine_get_engine_type( - const struct engine *engine); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c deleted file mode 100644 index 8b704ab0471c..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -#include "../dce110/aux_engine_dce110.h" -#include "../dce110/i2c_hw_engine_dce110.h" -#include "../dce110/i2caux_dce110.h" - -#include "dce/dce_10_0_d.h" -#include "dce/dce_10_0_sh_mask.h" - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -#define hw_engine_regs(id)\ -{\ - I2C_HW_ENGINE_COMMON_REG_LIST(id) \ -} - -static const struct dce110_aux_registers dce100_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5), -}; - -static const struct dce110_i2c_hw_engine_registers dce100_hw_engine_regs[] = { - hw_engine_regs(1), - hw_engine_regs(2), - hw_engine_regs(3), - hw_engine_regs(4), - hw_engine_regs(5), - hw_engine_regs(6) -}; - -static const struct dce110_i2c_hw_engine_shift i2c_shift = { - I2C_COMMON_MASK_SH_LIST_DCE100(__SHIFT) -}; - -static const struct dce110_i2c_hw_engine_mask i2c_mask = { - I2C_COMMON_MASK_SH_LIST_DCE100(_MASK) -}; - -struct i2caux *dal_i2caux_dce100_create( - struct dc_context *ctx) -{ - struct i2caux_dce110 *i2caux_dce110 = - kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL); - - if (!i2caux_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - dal_i2caux_dce110_construct(i2caux_dce110, - ctx, - ARRAY_SIZE(dce100_aux_regs), - dce100_aux_regs, - dce100_hw_engine_regs, - &i2c_shift, - &i2c_mask); - return &i2caux_dce110->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h deleted file mode 100644 index 2b508d3e0ef4..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCE100_H__ -#define __DAL_I2C_AUX_DCE100_H__ - -struct i2caux *dal_i2caux_dce100_create( - struct dc_context *ctx); - -#endif /* __DAL_I2C_AUX_DCE100_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c deleted file mode 100644 index 59c3ed43d609..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dm_event_log.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../engine.h" -#include "../aux_engine.h" - -/* - * Header of this unit - */ - -#include "aux_engine_dce110.h" - -/* - * Post-requisites: headers required by this unit - */ -#include "dce/dce_11_0_sh_mask.h" - -#define CTX \ - aux110->base.base.ctx -#define REG(reg_name)\ - (aux110->regs->reg_name) -#include "reg_helper.h" - -/* - * This unit - */ - -/* - * @brief - * Cast 'struct aux_engine *' - * to 'struct aux_engine_dce110 *' - */ -#define FROM_AUX_ENGINE(ptr) \ - container_of((ptr), struct aux_engine_dce110, base) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct aux_engine_dce110 *' - */ -#define FROM_ENGINE(ptr) \ - FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base)) - -static void release_engine( - struct engine *engine) -{ - struct aux_engine_dce110 *aux110 = FROM_ENGINE(engine); - - REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1); -} - -static void destruct( - struct aux_engine_dce110 *engine); - -static void destroy( - struct aux_engine **aux_engine) -{ - struct aux_engine_dce110 *engine = FROM_AUX_ENGINE(*aux_engine); - - destruct(engine); - - kfree(engine); - - *aux_engine = NULL; -} - -#define SW_CAN_ACCESS_AUX 1 -#define DMCU_CAN_ACCESS_AUX 2 - -static bool is_engine_available( - struct aux_engine *engine) -{ - struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); - - uint32_t value = REG_READ(AUX_ARB_CONTROL); - uint32_t field = get_reg_field_value( - value, - AUX_ARB_CONTROL, - AUX_REG_RW_CNTL_STATUS); - - return (field != DMCU_CAN_ACCESS_AUX); -} -static bool acquire_engine( - struct aux_engine *engine) -{ - struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); - - uint32_t value = REG_READ(AUX_ARB_CONTROL); - uint32_t field = get_reg_field_value( - value, - AUX_ARB_CONTROL, - AUX_REG_RW_CNTL_STATUS); - if (field == DMCU_CAN_ACCESS_AUX) - return false; - /* enable AUX before request SW to access AUX */ - value = REG_READ(AUX_CONTROL); - field = get_reg_field_value(value, - AUX_CONTROL, - AUX_EN); - - if (field == 0) { - set_reg_field_value( - value, - 1, - AUX_CONTROL, - AUX_EN); - - if (REG(AUX_RESET_MASK)) { - /*DP_AUX block as part of the enable sequence*/ - set_reg_field_value( - value, - 1, - AUX_CONTROL, - AUX_RESET); - } - - REG_WRITE(AUX_CONTROL, value); - - if (REG(AUX_RESET_MASK)) { - /*poll HW to make sure reset it done*/ - - REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 1, - 1, 11); - - set_reg_field_value( - value, - 0, - AUX_CONTROL, - AUX_RESET); - - REG_WRITE(AUX_CONTROL, value); - - REG_WAIT(AUX_CONTROL, AUX_RESET_DONE, 0, - 1, 11); - } - } /*if (field)*/ - - /* request SW to access AUX */ - REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_USE_AUX_REG_REQ, 1); - - value = REG_READ(AUX_ARB_CONTROL); - field = get_reg_field_value( - value, - AUX_ARB_CONTROL, - AUX_REG_RW_CNTL_STATUS); - - return (field == SW_CAN_ACCESS_AUX); -} - -#define COMPOSE_AUX_SW_DATA_16_20(command, address) \ - ((command) | ((0xF0000 & (address)) >> 16)) - -#define COMPOSE_AUX_SW_DATA_8_15(address) \ - ((0xFF00 & (address)) >> 8) - -#define COMPOSE_AUX_SW_DATA_0_7(address) \ - (0xFF & (address)) - -static void submit_channel_request( - struct aux_engine *engine, - struct aux_request_transaction_data *request) -{ - struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); - uint32_t value; - uint32_t length; - - bool is_write = - ((request->type == AUX_TRANSACTION_TYPE_DP) && - (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) || - ((request->type == AUX_TRANSACTION_TYPE_I2C) && - ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || - (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT))); - if (REG(AUXN_IMPCAL)) { - /* clear_aux_error */ - REG_UPDATE_SEQ(AUXN_IMPCAL, AUXN_CALOUT_ERROR_AK, - 1, - 0); - - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_CALOUT_ERROR_AK, - 1, - 0); - - /* force_default_calibrate */ - REG_UPDATE_1BY1_2(AUXN_IMPCAL, - AUXN_IMPCAL_ENABLE, 1, - AUXN_IMPCAL_OVERRIDE_ENABLE, 0); - - /* bug? why AUXN update EN and OVERRIDE_EN 1 by 1 while AUX P toggles OVERRIDE? */ - - REG_UPDATE_SEQ(AUXP_IMPCAL, AUXP_IMPCAL_OVERRIDE_ENABLE, - 1, - 0); - } - /* set the delay and the number of bytes to write */ - - /* The length include - * the 4 bit header and the 20 bit address - * (that is 3 byte). - * If the requested length is non zero this means - * an addition byte specifying the length is required. */ - - length = request->length ? 4 : 3; - if (is_write) - length += request->length; - - REG_UPDATE_2(AUX_SW_CONTROL, - AUX_SW_START_DELAY, request->delay, - AUX_SW_WR_BYTES, length); - - /* program action and address and payload data (if 'is_write') */ - value = REG_UPDATE_4(AUX_SW_DATA, - AUX_SW_INDEX, 0, - AUX_SW_DATA_RW, 0, - AUX_SW_AUTOINCREMENT_DISABLE, 1, - AUX_SW_DATA, COMPOSE_AUX_SW_DATA_16_20(request->action, request->address)); - - value = REG_SET_2(AUX_SW_DATA, value, - AUX_SW_AUTOINCREMENT_DISABLE, 0, - AUX_SW_DATA, COMPOSE_AUX_SW_DATA_8_15(request->address)); - - value = REG_SET(AUX_SW_DATA, value, - AUX_SW_DATA, COMPOSE_AUX_SW_DATA_0_7(request->address)); - - if (request->length) { - value = REG_SET(AUX_SW_DATA, value, - AUX_SW_DATA, request->length - 1); - } - - if (is_write) { - /* Load the HW buffer with the Data to be sent. - * This is relevant for write operation. - * For read, the data recived data will be - * processed in process_channel_reply(). */ - uint32_t i = 0; - - while (i < request->length) { - value = REG_SET(AUX_SW_DATA, value, - AUX_SW_DATA, request->data[i]); - - ++i; - } - } - - REG_UPDATE(AUX_INTERRUPT_CONTROL, AUX_SW_DONE_ACK, 1); - REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 0, - 10, aux110->timeout_period/10); - REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); - EVENT_LOG_AUX_REQ(engine->base.ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE, - request->action, request->address, request->length, request->data); -} - -static int read_channel_reply(struct aux_engine *engine, uint32_t size, - uint8_t *buffer, uint8_t *reply_result, - uint32_t *sw_status) -{ - struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); - uint32_t bytes_replied; - uint32_t reply_result_32; - - *sw_status = REG_GET(AUX_SW_STATUS, AUX_SW_REPLY_BYTE_COUNT, - &bytes_replied); - - /* In case HPD is LOW, exit AUX transaction */ - if ((*sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) - return -1; - - /* Need at least the status byte */ - if (!bytes_replied) - return -1; - - REG_UPDATE_1BY1_3(AUX_SW_DATA, - AUX_SW_INDEX, 0, - AUX_SW_AUTOINCREMENT_DISABLE, 1, - AUX_SW_DATA_RW, 1); - - REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32); - reply_result_32 = reply_result_32 >> 4; - *reply_result = (uint8_t)reply_result_32; - - if (reply_result_32 == 0) { /* ACK */ - uint32_t i = 0; - - /* First byte was already used to get the command status */ - --bytes_replied; - - /* Do not overflow buffer */ - if (bytes_replied > size) - return -1; - - while (i < bytes_replied) { - uint32_t aux_sw_data_val; - - REG_GET(AUX_SW_DATA, AUX_SW_DATA, &aux_sw_data_val); - buffer[i] = aux_sw_data_val; - ++i; - } - - return i; - } - - return 0; -} - -static void process_channel_reply( - struct aux_engine *engine, - struct aux_reply_transaction_data *reply) -{ - int bytes_replied; - uint8_t reply_result; - uint32_t sw_status; - - bytes_replied = read_channel_reply(engine, reply->length, reply->data, - &reply_result, &sw_status); - EVENT_LOG_AUX_REP(engine->base.ddc->pin_data->en, - EVENT_LOG_AUX_ORIGIN_NATIVE, reply_result, - bytes_replied, reply->data); - - /* in case HPD is LOW, exit AUX transaction */ - if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON; - return; - } - - if (bytes_replied < 0) { - /* Need to handle an error case... - * Hopefully, upper layer function won't call this function if - * the number of bytes in the reply was 0, because there was - * surely an error that was asserted that should have been - * handled for hot plug case, this could happens - */ - if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) { - reply->status = AUX_TRANSACTION_REPLY_INVALID; - ASSERT_CRITICAL(false); - return; - } - } else { - - switch (reply_result) { - case 0: /* ACK */ - reply->status = AUX_TRANSACTION_REPLY_AUX_ACK; - break; - case 1: /* NACK */ - reply->status = AUX_TRANSACTION_REPLY_AUX_NACK; - break; - case 2: /* DEFER */ - reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER; - break; - case 4: /* AUX ACK / I2C NACK */ - reply->status = AUX_TRANSACTION_REPLY_I2C_NACK; - break; - case 8: /* AUX ACK / I2C DEFER */ - reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER; - break; - default: - reply->status = AUX_TRANSACTION_REPLY_INVALID; - } - } -} - -static enum aux_channel_operation_result get_channel_status( - struct aux_engine *engine, - uint8_t *returned_bytes) -{ - struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine); - - uint32_t value; - - if (returned_bytes == NULL) { - /*caller pass NULL pointer*/ - ASSERT_CRITICAL(false); - return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN; - } - *returned_bytes = 0; - - /* poll to make sure that SW_DONE is asserted */ - value = REG_WAIT(AUX_SW_STATUS, AUX_SW_DONE, 1, - 10, aux110->timeout_period/10); - - /* in case HPD is LOW, exit AUX transaction */ - if ((value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) - return AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON; - - /* Note that the following bits are set in 'status.bits' - * during CTS 4.2.1.2 (FW 3.3.1): - * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP, - * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H. - * - * AUX_SW_RX_MIN_COUNT_VIOL is an internal, - * HW debugging bit and should be ignored. */ - if (value & AUX_SW_STATUS__AUX_SW_DONE_MASK) { - if ((value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_STATE_MASK) || - (value & AUX_SW_STATUS__AUX_SW_RX_TIMEOUT_MASK)) - return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; - - else if ((value & AUX_SW_STATUS__AUX_SW_RX_INVALID_STOP_MASK) || - (value & AUX_SW_STATUS__AUX_SW_RX_RECV_NO_DET_MASK) || - (value & - AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_H_MASK) || - (value & AUX_SW_STATUS__AUX_SW_RX_RECV_INVALID_L_MASK)) - return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; - - *returned_bytes = get_reg_field_value(value, - AUX_SW_STATUS, - AUX_SW_REPLY_BYTE_COUNT); - - if (*returned_bytes == 0) - return - AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY; - else { - *returned_bytes -= 1; - return AUX_CHANNEL_OPERATION_SUCCEEDED; - } - } else { - /*time_elapsed >= aux_engine->timeout_period - * AUX_SW_STATUS__AUX_SW_HPD_DISCON = at this point - */ - ASSERT_CRITICAL(false); - return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT; - } -} - -static const struct aux_engine_funcs aux_engine_funcs = { - .destroy = destroy, - .acquire_engine = acquire_engine, - .submit_channel_request = submit_channel_request, - .process_channel_reply = process_channel_reply, - .read_channel_reply = read_channel_reply, - .get_channel_status = get_channel_status, - .is_engine_available = is_engine_available, -}; - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .submit_request = dal_aux_engine_submit_request, - .get_engine_type = dal_aux_engine_get_engine_type, - .acquire = dal_aux_engine_acquire, -}; - -static void construct( - struct aux_engine_dce110 *engine, - const struct aux_engine_dce110_init_data *aux_init_data) -{ - dal_aux_engine_construct(&engine->base, aux_init_data->ctx); - engine->base.base.funcs = &engine_funcs; - engine->base.funcs = &aux_engine_funcs; - - engine->timeout_period = aux_init_data->timeout_period; - engine->regs = aux_init_data->regs; -} - -static void destruct( - struct aux_engine_dce110 *engine) -{ - dal_aux_engine_destruct(&engine->base); -} - -struct aux_engine *dal_aux_engine_dce110_create( - const struct aux_engine_dce110_init_data *aux_init_data) -{ - struct aux_engine_dce110 *engine; - - if (!aux_init_data) { - ASSERT_CRITICAL(false); - return NULL; - } - - engine = kzalloc(sizeof(*engine), GFP_KERNEL); - - if (!engine) { - ASSERT_CRITICAL(false); - return NULL; - } - - construct(engine, aux_init_data); - return &engine->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h deleted file mode 100644 index 85ee82162590..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_AUX_ENGINE_DCE110_H__ -#define __DAL_AUX_ENGINE_DCE110_H__ - -#include "../aux_engine.h" - -#define AUX_COMMON_REG_LIST(id)\ - SRI(AUX_CONTROL, DP_AUX, id), \ - SRI(AUX_ARB_CONTROL, DP_AUX, id), \ - SRI(AUX_SW_DATA, DP_AUX, id), \ - SRI(AUX_SW_CONTROL, DP_AUX, id), \ - SRI(AUX_INTERRUPT_CONTROL, DP_AUX, id), \ - SRI(AUX_SW_STATUS, DP_AUX, id), \ - SR(AUXN_IMPCAL), \ - SR(AUXP_IMPCAL) - -struct dce110_aux_registers { - uint32_t AUX_CONTROL; - uint32_t AUX_ARB_CONTROL; - uint32_t AUX_SW_DATA; - uint32_t AUX_SW_CONTROL; - uint32_t AUX_INTERRUPT_CONTROL; - uint32_t AUX_SW_STATUS; - uint32_t AUXN_IMPCAL; - uint32_t AUXP_IMPCAL; - - uint32_t AUX_RESET_MASK; -}; - -struct aux_engine_dce110 { - struct aux_engine base; - const struct dce110_aux_registers *regs; - struct { - uint32_t aux_control; - uint32_t aux_arb_control; - uint32_t aux_sw_data; - uint32_t aux_sw_control; - uint32_t aux_interrupt_control; - uint32_t aux_sw_status; - } addr; - uint32_t timeout_period; -}; - -struct aux_engine_dce110_init_data { - uint32_t engine_id; - uint32_t timeout_period; - struct dc_context *ctx; - const struct dce110_aux_registers *regs; -}; - -struct aux_engine *dal_aux_engine_dce110_create( - const struct aux_engine_dce110_init_data *aux_init_data); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c deleted file mode 100644 index 9cbe1a7a6bcb..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "include/logger_interface.h" -/* - * Pre-requisites: headers required by header of this unit - */ - -#include "include/i2caux_interface.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_hw_engine.h" -#include "../i2c_generic_hw_engine.h" -/* - * Header of this unit - */ - -#include "i2c_hw_engine_dce110.h" - -/* - * Post-requisites: headers required by this unit - */ -#include "reg_helper.h" - -/* - * This unit - */ -#define DC_LOGGER \ - hw_engine->base.base.base.ctx->logger - -enum dc_i2c_status { - DC_I2C_STATUS__DC_I2C_STATUS_IDLE, - DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW, - DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW -}; - -enum dc_i2c_arbitration { - DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, - DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH -}; - - - -/* - * @brief - * Cast pointer to 'struct i2c_hw_engine *' - * to pointer 'struct i2c_hw_engine_dce110 *' - */ -#define FROM_I2C_HW_ENGINE(ptr) \ - container_of((ptr), struct i2c_hw_engine_dce110, base) -/* - * @brief - * Cast pointer to 'struct i2c_engine *' - * to pointer to 'struct i2c_hw_engine_dce110 *' - */ -#define FROM_I2C_ENGINE(ptr) \ - FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base)) - -/* - * @brief - * Cast pointer to 'struct engine *' - * to 'pointer to struct i2c_hw_engine_dce110 *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -#define CTX \ - hw_engine->base.base.base.ctx - -#define REG(reg_name)\ - (hw_engine->regs->reg_name) - -#undef FN -#define FN(reg_name, field_name) \ - hw_engine->i2c_shift->field_name, hw_engine->i2c_mask->field_name - -#include "reg_helper.h" - -static void disable_i2c_hw_engine( - struct i2c_hw_engine_dce110 *hw_engine) -{ - REG_UPDATE_N(SETUP, 1, FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 0); -} - -static void release_engine( - struct engine *engine) -{ - struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); - - struct i2c_engine *base = NULL; - bool safe_to_reset; - - base = &hw_engine->base.base; - - /* Restore original HW engine speed */ - - base->funcs->set_speed(base, hw_engine->base.original_speed); - - /* Release I2C */ - REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, 1); - - /* Reset HW engine */ - { - uint32_t i2c_sw_status = 0; - REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); - /* if used by SW, safe to reset */ - safe_to_reset = (i2c_sw_status == 1); - } - - if (safe_to_reset) - REG_UPDATE_2( - DC_I2C_CONTROL, - DC_I2C_SOFT_RESET, 1, - DC_I2C_SW_STATUS_RESET, 1); - else - REG_UPDATE(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, 1); - - /* HW I2c engine - clock gating feature */ - if (!hw_engine->engine_keep_power_up_count) - disable_i2c_hw_engine(hw_engine); -} - -static bool setup_engine( - struct i2c_engine *i2c_engine) -{ - struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); - uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; - uint32_t reset_length = 0; - - if (hw_engine->base.base.setup_limit != 0) - i2c_setup_limit = hw_engine->base.base.setup_limit; - - /* Program pin select */ - REG_UPDATE_6( - DC_I2C_CONTROL, - DC_I2C_GO, 0, - DC_I2C_SOFT_RESET, 0, - DC_I2C_SEND_RESET, 0, - DC_I2C_SW_STATUS_RESET, 1, - DC_I2C_TRANSACTION_COUNT, 0, - DC_I2C_DDC_SELECT, hw_engine->engine_id); - - /* Program time limit */ - if (hw_engine->base.base.send_reset_length == 0) { - /*pre-dcn*/ - REG_UPDATE_N( - SETUP, 2, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); - } else { - reset_length = hw_engine->base.base.send_reset_length; - } - /* Program HW priority - * set to High - interrupt software I2C at any time - * Enable restart of SW I2C that was interrupted by HW - * disable queuing of software while I2C is in use by HW */ - REG_UPDATE_2( - DC_I2C_ARBITRATION, - DC_I2C_NO_QUEUED_SW_GO, 0, - DC_I2C_SW_PRIORITY, DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL); - - return true; -} - -static uint32_t get_speed( - const struct i2c_engine *i2c_engine) -{ - const struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); - uint32_t pre_scale = 0; - - REG_GET(SPEED, DC_I2C_DDC1_PRESCALE, &pre_scale); - - /* [anaumov] it seems following is unnecessary */ - /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ - return pre_scale ? - hw_engine->reference_frequency / pre_scale : - hw_engine->base.default_speed; -} - -static void set_speed( - struct i2c_engine *i2c_engine, - uint32_t speed) -{ - struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); - - if (speed) { - if (hw_engine->i2c_mask->DC_I2C_DDC1_START_STOP_TIMING_CNTL) - REG_UPDATE_N( - SPEED, 3, - FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, - FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2, - FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL), speed > 50 ? 2:1); - else - REG_UPDATE_N( - SPEED, 2, - FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE), hw_engine->reference_frequency / speed, - FN(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD), 2); - } -} - -static inline void reset_hw_engine(struct engine *engine) -{ - struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); - - REG_UPDATE_2( - DC_I2C_CONTROL, - DC_I2C_SW_STATUS_RESET, 1, - DC_I2C_SW_STATUS_RESET, 1); -} - -static bool is_hw_busy(struct engine *engine) -{ - struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine); - uint32_t i2c_sw_status = 0; - - REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); - if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) - return false; - - reset_hw_engine(engine); - - REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); - return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; -} - - -#define STOP_TRANS_PREDICAT \ - ((hw_engine->transaction_count == 3) || \ - (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || \ - (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) - -#define SET_I2C_TRANSACTION(id) \ - do { \ - REG_UPDATE_N(DC_I2C_TRANSACTION##id, 5, \ - FN(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0), 1, \ - FN(DC_I2C_TRANSACTION0, DC_I2C_START0), 1, \ - FN(DC_I2C_TRANSACTION0, DC_I2C_STOP0), STOP_TRANS_PREDICAT ? 1:0, \ - FN(DC_I2C_TRANSACTION0, DC_I2C_RW0), (0 != (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)), \ - FN(DC_I2C_TRANSACTION0, DC_I2C_COUNT0), length); \ - if (STOP_TRANS_PREDICAT) \ - last_transaction = true; \ - } while (false) - - -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; -} - -static void execute_transaction( - struct i2c_hw_engine_dce110 *hw_engine) -{ - REG_UPDATE_N(SETUP, 5, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN), 0, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN), 0, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL), 0, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY), 0, - FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY), 0); - - - REG_UPDATE_5(DC_I2C_CONTROL, - DC_I2C_SOFT_RESET, 0, - DC_I2C_SW_STATUS_RESET, 0, - DC_I2C_SEND_RESET, 0, - DC_I2C_GO, 0, - DC_I2C_TRANSACTION_COUNT, hw_engine->transaction_count - 1); - - /* start I2C transfer */ - REG_UPDATE(DC_I2C_CONTROL, DC_I2C_GO, 1); - - /* all transactions were executed and HW buffer became empty - * (even though it actually happens when status becomes DONE) */ - hw_engine->transaction_count = 0; - hw_engine->buffer_used_bytes = 0; -} - -static void submit_channel_request( - struct i2c_engine *engine, - struct i2c_request_transaction_data *request) -{ - request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; - - if (!process_transaction(FROM_I2C_ENGINE(engine), request)) - return; - - if (is_hw_busy(&engine->base)) { - request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; - return; - } - - execute_transaction(FROM_I2C_ENGINE(engine)); -} - -static void process_channel_reply( - struct i2c_engine *engine, - struct i2c_reply_transaction_data *reply) -{ - uint32_t length = reply->length; - uint8_t *buffer = reply->data; - - struct i2c_hw_engine_dce110 *hw_engine = - FROM_I2C_ENGINE(engine); - - - REG_SET_3(DC_I2C_DATA, 0, - DC_I2C_INDEX, hw_engine->buffer_used_write, - DC_I2C_DATA_RW, 1, - DC_I2C_INDEX_WRITE, 1); - - while (length) { - /* after reading the status, - * if the I2C operation executed successfully - * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller - * should read data bytes from I2C circular data buffer */ - - uint32_t i2c_data; - - REG_GET(DC_I2C_DATA, DC_I2C_DATA, &i2c_data); - *buffer++ = i2c_data; - - --length; - } -} - -static enum i2c_channel_operation_result get_channel_status( - struct i2c_engine *i2c_engine, - uint8_t *returned_bytes) -{ - uint32_t i2c_sw_status = 0; - struct i2c_hw_engine_dce110 *hw_engine = FROM_I2C_ENGINE(i2c_engine); - uint32_t value = - REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); - - if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) - return I2C_CHANNEL_OPERATION_ENGINE_BUSY; - else if (value & hw_engine->i2c_mask->DC_I2C_SW_STOPPED_ON_NACK) - return I2C_CHANNEL_OPERATION_NO_RESPONSE; - else if (value & hw_engine->i2c_mask->DC_I2C_SW_TIMEOUT) - return I2C_CHANNEL_OPERATION_TIMEOUT; - else if (value & hw_engine->i2c_mask->DC_I2C_SW_ABORTED) - return I2C_CHANNEL_OPERATION_FAILED; - else if (value & hw_engine->i2c_mask->DC_I2C_SW_DONE) - return I2C_CHANNEL_OPERATION_SUCCEEDED; - - /* - * this is the case when HW used for communication, I2C_SW_STATUS - * could be zero - */ - return I2C_CHANNEL_OPERATION_SUCCEEDED; -} - -static uint32_t get_hw_buffer_available_size( - const struct i2c_hw_engine *engine) -{ - return I2C_HW_BUFFER_SIZE - - FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes; -} - -static uint32_t get_transaction_timeout( - const struct i2c_hw_engine *engine, - uint32_t length) -{ - uint32_t speed = engine->base.funcs->get_speed(&engine->base); - - uint32_t period_timeout; - uint32_t num_of_clock_stretches; - - if (!speed) - return 0; - - period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed; - - num_of_clock_stretches = 1 + (length << 3) + 1; - num_of_clock_stretches += - (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) + - (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1); - - return period_timeout * num_of_clock_stretches; -} - -static void destroy( - struct i2c_engine **i2c_engine) -{ - struct i2c_hw_engine_dce110 *engine_dce110 = - FROM_I2C_ENGINE(*i2c_engine); - - dal_i2c_hw_engine_destruct(&engine_dce110->base); - - kfree(engine_dce110); - - *i2c_engine = NULL; -} - -static const struct i2c_engine_funcs i2c_engine_funcs = { - .destroy = destroy, - .get_speed = get_speed, - .set_speed = set_speed, - .setup_engine = setup_engine, - .submit_channel_request = submit_channel_request, - .process_channel_reply = process_channel_reply, - .get_channel_status = get_channel_status, - .acquire_engine = dal_i2c_hw_engine_acquire_engine, -}; - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .get_engine_type = dal_i2c_hw_engine_get_engine_type, - .acquire = dal_i2c_engine_acquire, - .submit_request = dal_i2c_hw_engine_submit_request, -}; - -static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = { - .get_hw_buffer_available_size = get_hw_buffer_available_size, - .get_transaction_timeout = get_transaction_timeout, - .wait_on_operation_result = dal_i2c_hw_engine_wait_on_operation_result, -}; - -static void construct( - struct i2c_hw_engine_dce110 *hw_engine, - const struct i2c_hw_engine_dce110_create_arg *arg) -{ - uint32_t xtal_ref_div = 0; - - dal_i2c_hw_engine_construct(&hw_engine->base, arg->ctx); - - hw_engine->base.base.base.funcs = &engine_funcs; - hw_engine->base.base.funcs = &i2c_engine_funcs; - hw_engine->base.funcs = &i2c_hw_engine_funcs; - hw_engine->base.default_speed = arg->default_speed; - - hw_engine->regs = arg->regs; - hw_engine->i2c_shift = arg->i2c_shift; - hw_engine->i2c_mask = arg->i2c_mask; - - hw_engine->engine_id = arg->engine_id; - - hw_engine->buffer_used_bytes = 0; - hw_engine->transaction_count = 0; - hw_engine->engine_keep_power_up_count = 1; - - - REG_GET(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, &xtal_ref_div); - - if (xtal_ref_div == 0) { - DC_LOG_WARNING("Invalid base timer divider [%s]\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 - */ - hw_engine->reference_frequency = - (arg->reference_frequency * 2) / xtal_ref_div; -} - -struct i2c_engine *dal_i2c_hw_engine_dce110_create( - const struct i2c_hw_engine_dce110_create_arg *arg) -{ - struct i2c_hw_engine_dce110 *engine_dce10; - - if (!arg) { - ASSERT_CRITICAL(false); - return NULL; - } - if (!arg->reference_frequency) { - ASSERT_CRITICAL(false); - return NULL; - } - - engine_dce10 = kzalloc(sizeof(struct i2c_hw_engine_dce110), - GFP_KERNEL); - - if (!engine_dce10) { - ASSERT_CRITICAL(false); - return NULL; - } - - construct(engine_dce10, arg); - return &engine_dce10->base.base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h deleted file mode 100644 index fea2946906ed..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_HW_ENGINE_DCE110_H__ -#define __DAL_I2C_HW_ENGINE_DCE110_H__ - -#define I2C_HW_ENGINE_COMMON_REG_LIST(id)\ - SRI(SETUP, DC_I2C_DDC, id),\ - SRI(SPEED, DC_I2C_DDC, id),\ - SR(DC_I2C_ARBITRATION),\ - SR(DC_I2C_CONTROL),\ - SR(DC_I2C_SW_STATUS),\ - SR(DC_I2C_TRANSACTION0),\ - SR(DC_I2C_TRANSACTION1),\ - SR(DC_I2C_TRANSACTION2),\ - SR(DC_I2C_TRANSACTION3),\ - SR(DC_I2C_DATA),\ - SR(MICROSECOND_TIME_BASE_DIV) - -#define I2C_SF(reg_name, field_name, post_fix)\ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh)\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_EN, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_CLK_DRIVE_EN, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_DATA_DRIVE_SEL, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_TRANSACTION_DELAY, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_INTRA_BYTE_DELAY, mask_sh),\ - I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_DONE_USING_I2C_REG, mask_sh),\ - I2C_SF(DC_I2C_ARBITRATION, DC_I2C_NO_QUEUED_SW_GO, mask_sh),\ - I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_PRIORITY, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_SOFT_RESET, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_SW_STATUS_RESET, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_GO, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_SEND_RESET, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_TRANSACTION_COUNT, mask_sh),\ - I2C_SF(DC_I2C_CONTROL, DC_I2C_DDC_SELECT, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_PRESCALE, mask_sh),\ - I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_THRESHOLD, mask_sh),\ - I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_STOPPED_ON_NACK, mask_sh),\ - I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_TIMEOUT, mask_sh),\ - I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_ABORTED, mask_sh),\ - I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_DONE, mask_sh),\ - I2C_SF(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, mask_sh),\ - I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_STOP_ON_NACK0, mask_sh),\ - I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_START0, mask_sh),\ - I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_RW0, mask_sh),\ - I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_STOP0, mask_sh),\ - I2C_SF(DC_I2C_TRANSACTION0, DC_I2C_COUNT0, mask_sh),\ - I2C_SF(DC_I2C_DATA, DC_I2C_DATA_RW, mask_sh),\ - I2C_SF(DC_I2C_DATA, DC_I2C_DATA, mask_sh),\ - I2C_SF(DC_I2C_DATA, DC_I2C_INDEX, mask_sh),\ - I2C_SF(DC_I2C_DATA, DC_I2C_INDEX_WRITE, mask_sh),\ - I2C_SF(MICROSECOND_TIME_BASE_DIV, XTAL_REF_DIV, mask_sh) - -#define I2C_COMMON_MASK_SH_LIST_DCE100(mask_sh)\ - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh) - -#define I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh)\ - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh),\ - I2C_SF(DC_I2C_DDC1_SPEED, DC_I2C_DDC1_START_STOP_TIMING_CNTL, mask_sh) - -struct dce110_i2c_hw_engine_shift { - uint8_t DC_I2C_DDC1_ENABLE; - uint8_t DC_I2C_DDC1_TIME_LIMIT; - uint8_t DC_I2C_DDC1_DATA_DRIVE_EN; - uint8_t DC_I2C_DDC1_CLK_DRIVE_EN; - uint8_t DC_I2C_DDC1_DATA_DRIVE_SEL; - uint8_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY; - uint8_t DC_I2C_DDC1_INTRA_BYTE_DELAY; - uint8_t DC_I2C_SW_DONE_USING_I2C_REG; - uint8_t DC_I2C_NO_QUEUED_SW_GO; - uint8_t DC_I2C_SW_PRIORITY; - uint8_t DC_I2C_SOFT_RESET; - uint8_t DC_I2C_SW_STATUS_RESET; - uint8_t DC_I2C_GO; - uint8_t DC_I2C_SEND_RESET; - uint8_t DC_I2C_TRANSACTION_COUNT; - uint8_t DC_I2C_DDC_SELECT; - uint8_t DC_I2C_DDC1_PRESCALE; - uint8_t DC_I2C_DDC1_THRESHOLD; - uint8_t DC_I2C_DDC1_START_STOP_TIMING_CNTL; - uint8_t DC_I2C_SW_STOPPED_ON_NACK; - uint8_t DC_I2C_SW_TIMEOUT; - uint8_t DC_I2C_SW_ABORTED; - uint8_t DC_I2C_SW_DONE; - uint8_t DC_I2C_SW_STATUS; - uint8_t DC_I2C_STOP_ON_NACK0; - uint8_t DC_I2C_START0; - uint8_t DC_I2C_RW0; - uint8_t DC_I2C_STOP0; - uint8_t DC_I2C_COUNT0; - uint8_t DC_I2C_DATA_RW; - uint8_t DC_I2C_DATA; - uint8_t DC_I2C_INDEX; - uint8_t DC_I2C_INDEX_WRITE; - uint8_t XTAL_REF_DIV; -}; - -struct dce110_i2c_hw_engine_mask { - uint32_t DC_I2C_DDC1_ENABLE; - uint32_t DC_I2C_DDC1_TIME_LIMIT; - uint32_t DC_I2C_DDC1_DATA_DRIVE_EN; - uint32_t DC_I2C_DDC1_CLK_DRIVE_EN; - uint32_t DC_I2C_DDC1_DATA_DRIVE_SEL; - uint32_t DC_I2C_DDC1_INTRA_TRANSACTION_DELAY; - uint32_t DC_I2C_DDC1_INTRA_BYTE_DELAY; - uint32_t DC_I2C_SW_DONE_USING_I2C_REG; - uint32_t DC_I2C_NO_QUEUED_SW_GO; - uint32_t DC_I2C_SW_PRIORITY; - uint32_t DC_I2C_SOFT_RESET; - uint32_t DC_I2C_SW_STATUS_RESET; - uint32_t DC_I2C_GO; - uint32_t DC_I2C_SEND_RESET; - uint32_t DC_I2C_TRANSACTION_COUNT; - uint32_t DC_I2C_DDC_SELECT; - uint32_t DC_I2C_DDC1_PRESCALE; - uint32_t DC_I2C_DDC1_THRESHOLD; - uint32_t DC_I2C_DDC1_START_STOP_TIMING_CNTL; - uint32_t DC_I2C_SW_STOPPED_ON_NACK; - uint32_t DC_I2C_SW_TIMEOUT; - uint32_t DC_I2C_SW_ABORTED; - uint32_t DC_I2C_SW_DONE; - uint32_t DC_I2C_SW_STATUS; - uint32_t DC_I2C_STOP_ON_NACK0; - uint32_t DC_I2C_START0; - uint32_t DC_I2C_RW0; - uint32_t DC_I2C_STOP0; - uint32_t DC_I2C_COUNT0; - uint32_t DC_I2C_DATA_RW; - uint32_t DC_I2C_DATA; - uint32_t DC_I2C_INDEX; - uint32_t DC_I2C_INDEX_WRITE; - uint32_t XTAL_REF_DIV; -}; - -struct dce110_i2c_hw_engine_registers { - uint32_t SETUP; - uint32_t SPEED; - uint32_t DC_I2C_ARBITRATION; - uint32_t DC_I2C_CONTROL; - uint32_t DC_I2C_SW_STATUS; - uint32_t DC_I2C_TRANSACTION0; - uint32_t DC_I2C_TRANSACTION1; - uint32_t DC_I2C_TRANSACTION2; - uint32_t DC_I2C_TRANSACTION3; - uint32_t DC_I2C_DATA; - uint32_t MICROSECOND_TIME_BASE_DIV; -}; - -struct i2c_hw_engine_dce110 { - struct i2c_hw_engine base; - const struct dce110_i2c_hw_engine_registers *regs; - const struct dce110_i2c_hw_engine_shift *i2c_shift; - const struct dce110_i2c_hw_engine_mask *i2c_mask; - struct { - uint32_t DC_I2C_DDCX_SETUP; - uint32_t DC_I2C_DDCX_SPEED; - } addr; - uint32_t engine_id; - /* expressed in kilohertz */ - uint32_t reference_frequency; - /* number of bytes currently used in HW buffer */ - uint32_t buffer_used_bytes; - /* number of bytes used for write transaction in HW buffer - * - this will be used as the index to read from*/ - uint32_t buffer_used_write; - /* number of pending transactions (before GO) */ - uint32_t transaction_count; - uint32_t engine_keep_power_up_count; - uint32_t i2_setup_time_limit; -}; - -struct i2c_hw_engine_dce110_create_arg { - uint32_t engine_id; - uint32_t reference_frequency; - uint32_t default_speed; - struct dc_context *ctx; - const struct dce110_i2c_hw_engine_registers *regs; - const struct dce110_i2c_hw_engine_shift *i2c_shift; - const struct dce110_i2c_hw_engine_mask *i2c_mask; -}; - -struct i2c_engine *dal_i2c_hw_engine_dce110_create( - const struct i2c_hw_engine_dce110_create_arg *arg); - -enum { - I2C_SETUP_TIME_LIMIT_DCE = 255, - I2C_SETUP_TIME_LIMIT_DCN = 3, - I2C_HW_BUFFER_SIZE = 538, - I2C_SEND_RESET_LENGTH_9 = 9, - I2C_SEND_RESET_LENGTH_10 = 10, -}; -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c deleted file mode 100644 index 3aa7f791e523..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" - -/* - * Header of this unit - */ - -#include "i2c_sw_engine_dce110.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -/* - * @brief - * Cast 'struct i2c_sw_engine *' - * to 'struct i2c_sw_engine_dce110 *' - */ -#define FROM_I2C_SW_ENGINE(ptr) \ - container_of((ptr), struct i2c_sw_engine_dce110, base) -/* - * @brief - * Cast 'struct i2c_engine *' - * to 'struct i2c_sw_engine_dce80 *' - */ -#define FROM_I2C_ENGINE(ptr) \ - FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base)) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct i2c_sw_engine_dce80 *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -static void release_engine( - struct engine *engine) -{ -} - -static void destruct( - struct i2c_sw_engine_dce110 *engine) -{ - dal_i2c_sw_engine_destruct(&engine->base); -} - -static void destroy( - struct i2c_engine **engine) -{ - struct i2c_sw_engine_dce110 *sw_engine = FROM_I2C_ENGINE(*engine); - - destruct(sw_engine); - - kfree(sw_engine); - - *engine = NULL; -} - -static bool acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc_handle) -{ - return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle); -} - -static const struct i2c_engine_funcs i2c_engine_funcs = { - .acquire_engine = acquire_engine, - .destroy = destroy, - .get_speed = dal_i2c_sw_engine_get_speed, - .set_speed = dal_i2c_sw_engine_set_speed, - .setup_engine = dal_i2c_engine_setup_i2c_engine, - .submit_channel_request = dal_i2c_sw_engine_submit_channel_request, - .process_channel_reply = dal_i2c_engine_process_channel_reply, - .get_channel_status = dal_i2c_sw_engine_get_channel_status, -}; - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .get_engine_type = dal_i2c_sw_engine_get_engine_type, - .acquire = dal_i2c_engine_acquire, - .submit_request = dal_i2c_sw_engine_submit_request, -}; - -static void construct( - struct i2c_sw_engine_dce110 *engine_dce110, - const struct i2c_sw_engine_dce110_create_arg *arg_dce110) -{ - struct i2c_sw_engine_create_arg arg_base; - - arg_base.ctx = arg_dce110->ctx; - arg_base.default_speed = arg_dce110->default_speed; - - dal_i2c_sw_engine_construct(&engine_dce110->base, &arg_base); - - /*struct engine struct engine_funcs*/ - engine_dce110->base.base.base.funcs = &engine_funcs; - /*struct i2c_engine struct i2c_engine_funcs*/ - engine_dce110->base.base.funcs = &i2c_engine_funcs; - engine_dce110->base.default_speed = arg_dce110->default_speed; - engine_dce110->engine_id = arg_dce110->engine_id; -} - -struct i2c_engine *dal_i2c_sw_engine_dce110_create( - const struct i2c_sw_engine_dce110_create_arg *arg) -{ - struct i2c_sw_engine_dce110 *engine_dce110; - - if (!arg) { - ASSERT_CRITICAL(false); - return NULL; - } - - engine_dce110 = kzalloc(sizeof(struct i2c_sw_engine_dce110), - GFP_KERNEL); - - if (!engine_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - construct(engine_dce110, arg); - return &engine_dce110->base.base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c deleted file mode 100644 index 1d748ac1d6d6..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -/* - * Header of this unit - */ -#include "i2caux_dce110.h" - -#include "i2c_sw_engine_dce110.h" -#include "i2c_hw_engine_dce110.h" -#include "aux_engine_dce110.h" -#include "../../dc.h" -#include "dc_types.h" - - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ -/*cast pointer to struct i2caux TO pointer to struct i2caux_dce110*/ -#define FROM_I2C_AUX(ptr) \ - container_of((ptr), struct i2caux_dce110, base) - -static void destruct( - struct i2caux_dce110 *i2caux_dce110) -{ - dal_i2caux_destruct(&i2caux_dce110->base); -} - -static void destroy( - struct i2caux **i2c_engine) -{ - struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(*i2c_engine); - - destruct(i2caux_dce110); - - kfree(i2caux_dce110); - - *i2c_engine = NULL; -} - -static struct i2c_engine *acquire_i2c_hw_engine( - struct i2caux *i2caux, - struct ddc *ddc) -{ - struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux); - - struct i2c_engine *engine = NULL; - /* generic hw engine is not used for EDID read - * It may be needed for external i2c device, like thermal chip, - * TODO will be implemented when needed. - * check dce80 bool non_generic for generic hw engine; - */ - - if (!ddc) - return NULL; - - if (ddc->hw_info.hw_supported) { - enum gpio_ddc_line line = dal_ddc_get_line(ddc); - - if (line < GPIO_DDC_LINE_COUNT) - engine = i2caux->i2c_hw_engines[line]; - } - - if (!engine) - return NULL; - - if (!i2caux_dce110->i2c_hw_buffer_in_use && - engine->base.funcs->acquire(&engine->base, ddc)) { - i2caux_dce110->i2c_hw_buffer_in_use = true; - return engine; - } - - return NULL; -} - -static void release_engine( - struct i2caux *i2caux, - struct engine *engine) -{ - struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux); - - if (engine->funcs->get_engine_type(engine) == - I2CAUX_ENGINE_TYPE_I2C_DDC_HW) - i2caux_dce110->i2c_hw_buffer_in_use = false; - - dal_i2caux_release_engine(i2caux, engine); -} - -static const enum gpio_ddc_line hw_ddc_lines[] = { - GPIO_DDC_LINE_DDC1, - GPIO_DDC_LINE_DDC2, - GPIO_DDC_LINE_DDC3, - GPIO_DDC_LINE_DDC4, - GPIO_DDC_LINE_DDC5, - GPIO_DDC_LINE_DDC6, -}; - -static const enum gpio_ddc_line hw_aux_lines[] = { - GPIO_DDC_LINE_DDC1, - GPIO_DDC_LINE_DDC2, - GPIO_DDC_LINE_DDC3, - GPIO_DDC_LINE_DDC4, - GPIO_DDC_LINE_DDC5, - GPIO_DDC_LINE_DDC6, -}; - -/* function table */ -static const struct i2caux_funcs i2caux_funcs = { - .destroy = destroy, - .acquire_i2c_hw_engine = acquire_i2c_hw_engine, - .release_engine = release_engine, - .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine, - .acquire_aux_engine = dal_i2caux_acquire_aux_engine, -}; - -#include "dce/dce_11_0_d.h" -#include "dce/dce_11_0_sh_mask.h" - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = AUX_CONTROL__AUX_RESET_MASK \ -} - -#define hw_engine_regs(id)\ -{\ - I2C_HW_ENGINE_COMMON_REG_LIST(id) \ -} - -static const struct dce110_aux_registers dce110_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -static const struct dce110_i2c_hw_engine_registers i2c_hw_engine_regs[] = { - hw_engine_regs(1), - hw_engine_regs(2), - hw_engine_regs(3), - hw_engine_regs(4), - hw_engine_regs(5), - hw_engine_regs(6) -}; - -static const struct dce110_i2c_hw_engine_shift i2c_shift = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce110_i2c_hw_engine_mask i2c_mask = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -void dal_i2caux_dce110_construct( - struct i2caux_dce110 *i2caux_dce110, - struct dc_context *ctx, - unsigned int num_i2caux_inst, - const struct dce110_aux_registers aux_regs[], - const struct dce110_i2c_hw_engine_registers i2c_hw_engine_regs[], - const struct dce110_i2c_hw_engine_shift *i2c_shift, - const struct dce110_i2c_hw_engine_mask *i2c_mask) -{ - uint32_t i = 0; - uint32_t reference_frequency = 0; - bool use_i2c_sw_engine = false; - struct i2caux *base = NULL; - /*TODO: For CZ bring up, if dal_i2caux_get_reference_clock - * does not return 48KHz, we need hard coded for 48Khz. - * Some BIOS setting incorrect cause this - * For production, we always get value from BIOS*/ - reference_frequency = - dal_i2caux_get_reference_clock(ctx->dc_bios) >> 1; - - base = &i2caux_dce110->base; - - dal_i2caux_construct(base, ctx); - - i2caux_dce110->base.funcs = &i2caux_funcs; - i2caux_dce110->i2c_hw_buffer_in_use = false; - /* Create I2C engines (DDC lines per connector) - * different I2C/AUX usage cases, DDC, Generic GPIO, AUX. - */ - do { - enum gpio_ddc_line line_id = hw_ddc_lines[i]; - - struct i2c_hw_engine_dce110_create_arg hw_arg_dce110; - - if (use_i2c_sw_engine) { - struct i2c_sw_engine_dce110_create_arg sw_arg; - - sw_arg.engine_id = i; - sw_arg.default_speed = base->default_i2c_sw_speed; - sw_arg.ctx = ctx; - base->i2c_sw_engines[line_id] = - dal_i2c_sw_engine_dce110_create(&sw_arg); - } - - hw_arg_dce110.engine_id = i; - hw_arg_dce110.reference_frequency = reference_frequency; - hw_arg_dce110.default_speed = base->default_i2c_hw_speed; - hw_arg_dce110.ctx = ctx; - hw_arg_dce110.regs = &i2c_hw_engine_regs[i]; - hw_arg_dce110.i2c_shift = i2c_shift; - hw_arg_dce110.i2c_mask = i2c_mask; - - base->i2c_hw_engines[line_id] = - dal_i2c_hw_engine_dce110_create(&hw_arg_dce110); - if (base->i2c_hw_engines[line_id] != NULL) { - switch (ctx->dce_version) { - case DCN_VERSION_1_0: - base->i2c_hw_engines[line_id]->setup_limit = - I2C_SETUP_TIME_LIMIT_DCN; - base->i2c_hw_engines[line_id]->send_reset_length = 0; - break; - default: - base->i2c_hw_engines[line_id]->setup_limit = - I2C_SETUP_TIME_LIMIT_DCE; - base->i2c_hw_engines[line_id]->send_reset_length = 0; - break; - } - } - ++i; - } while (i < num_i2caux_inst); - - /* Create AUX engines for all lines which has assisted HW AUX - * 'i' (loop counter) used as DDC/AUX engine_id */ - - i = 0; - - do { - enum gpio_ddc_line line_id = hw_aux_lines[i]; - - struct aux_engine_dce110_init_data aux_init_data; - - aux_init_data.engine_id = i; - aux_init_data.timeout_period = base->aux_timeout_period; - aux_init_data.ctx = ctx; - aux_init_data.regs = &aux_regs[i]; - - base->aux_engines[line_id] = - dal_aux_engine_dce110_create(&aux_init_data); - - ++i; - } while (i < num_i2caux_inst); - - /*TODO Generic I2C SW and HW*/ -} - -/* - * dal_i2caux_dce110_create - * - * @brief - * public interface to allocate memory for DCE11 I2CAUX - * - * @param - * struct adapter_service *as - [in] - * struct dc_context *ctx - [in] - * - * @return - * pointer to the base struct of DCE11 I2CAUX - */ -struct i2caux *dal_i2caux_dce110_create( - struct dc_context *ctx) -{ - struct i2caux_dce110 *i2caux_dce110 = - kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL); - - if (!i2caux_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - dal_i2caux_dce110_construct(i2caux_dce110, - ctx, - ARRAY_SIZE(dce110_aux_regs), - dce110_aux_regs, - i2c_hw_engine_regs, - &i2c_shift, - &i2c_mask); - return &i2caux_dce110->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h deleted file mode 100644 index d3d8cc58666a..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCE110_H__ -#define __DAL_I2C_AUX_DCE110_H__ - -#include "../i2caux.h" - -struct i2caux_dce110 { - struct i2caux base; - /* indicate the I2C HW circular buffer is in use */ - bool i2c_hw_buffer_in_use; -}; - -struct dce110_aux_registers; -struct dce110_i2c_hw_engine_registers; -struct dce110_i2c_hw_engine_shift; -struct dce110_i2c_hw_engine_mask; - -struct i2caux *dal_i2caux_dce110_create( - struct dc_context *ctx); - -void dal_i2caux_dce110_construct( - struct i2caux_dce110 *i2caux_dce110, - struct dc_context *ctx, - unsigned int num_i2caux_inst, - const struct dce110_aux_registers *aux_regs, - const struct dce110_i2c_hw_engine_registers *i2c_hw_engine_regs, - const struct dce110_i2c_hw_engine_shift *i2c_shift, - const struct dce110_i2c_hw_engine_mask *i2c_mask); - -#endif /* __DAL_I2C_AUX_DCE110_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c deleted file mode 100644 index a9db04738724..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -#include "../dce110/i2caux_dce110.h" -#include "i2caux_dce112.h" - -#include "../dce110/aux_engine_dce110.h" - -#include "../dce110/i2c_hw_engine_dce110.h" - -#include "dce/dce_11_2_d.h" -#include "dce/dce_11_2_sh_mask.h" - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = AUX_CONTROL__AUX_RESET_MASK \ -} - -#define hw_engine_regs(id)\ -{\ - I2C_HW_ENGINE_COMMON_REG_LIST(id) \ -} - -static const struct dce110_aux_registers dce112_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5), -}; - -static const struct dce110_i2c_hw_engine_registers dce112_hw_engine_regs[] = { - hw_engine_regs(1), - hw_engine_regs(2), - hw_engine_regs(3), - hw_engine_regs(4), - hw_engine_regs(5), - hw_engine_regs(6) -}; - -static const struct dce110_i2c_hw_engine_shift i2c_shift = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce110_i2c_hw_engine_mask i2c_mask = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static void construct( - struct i2caux_dce110 *i2caux_dce110, - struct dc_context *ctx) -{ - dal_i2caux_dce110_construct(i2caux_dce110, - ctx, - ARRAY_SIZE(dce112_aux_regs), - dce112_aux_regs, - dce112_hw_engine_regs, - &i2c_shift, - &i2c_mask); -} - -/* - * dal_i2caux_dce110_create - * - * @brief - * public interface to allocate memory for DCE11 I2CAUX - * - * @param - * struct adapter_service *as - [in] - * struct dc_context *ctx - [in] - * - * @return - * pointer to the base struct of DCE11 I2CAUX - */ -struct i2caux *dal_i2caux_dce112_create( - struct dc_context *ctx) -{ - struct i2caux_dce110 *i2caux_dce110 = - kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL); - - if (!i2caux_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - construct(i2caux_dce110, ctx); - return &i2caux_dce110->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h deleted file mode 100644 index 8d35453c25b6..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCE112_H__ -#define __DAL_I2C_AUX_DCE112_H__ - -struct i2caux *dal_i2caux_dce112_create( - struct dc_context *ctx); - -#endif /* __DAL_I2C_AUX_DCE112_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c deleted file mode 100644 index 6a4f344c1db4..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2012-16 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -#include "../dce110/i2c_hw_engine_dce110.h" -#include "../dce110/aux_engine_dce110.h" -#include "../dce110/i2caux_dce110.h" - -#include "dce/dce_12_0_offset.h" -#include "dce/dce_12_0_sh_mask.h" -#include "soc15_hw_ip.h" -#include "vega10_ip_offset.h" - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -#define BASE_INNER(seg) \ - DCE_BASE__INST0_SEG ## seg - -/* compile time expand base address. */ -#define BASE(seg) \ - BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name -/* macros to expend register list macro defined in HW object header file - * end *********************/ - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK \ -} - -static const struct dce110_aux_registers dce120_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5), -}; - -#define hw_engine_regs(id)\ -{\ - I2C_HW_ENGINE_COMMON_REG_LIST(id) \ -} - -static const struct dce110_i2c_hw_engine_registers dce120_hw_engine_regs[] = { - hw_engine_regs(1), - hw_engine_regs(2), - hw_engine_regs(3), - hw_engine_regs(4), - hw_engine_regs(5), - hw_engine_regs(6) -}; - -static const struct dce110_i2c_hw_engine_shift i2c_shift = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce110_i2c_hw_engine_mask i2c_mask = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -struct i2caux *dal_i2caux_dce120_create( - struct dc_context *ctx) -{ - struct i2caux_dce110 *i2caux_dce110 = - kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL); - - if (!i2caux_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - dal_i2caux_dce110_construct(i2caux_dce110, - ctx, - ARRAY_SIZE(dce120_aux_regs), - dce120_aux_regs, - dce120_hw_engine_regs, - &i2c_shift, - &i2c_mask); - return &i2caux_dce110->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h deleted file mode 100644 index b6ac47617c70..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-16 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCE120_H__ -#define __DAL_I2C_AUX_DCE120_H__ - -struct i2caux *dal_i2caux_dce120_create( - struct dc_context *ctx); - -#endif /* __DAL_I2C_AUX_DCE120_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c deleted file mode 100644 index fd0832dd2c75..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_hw_engine.h" -#include "../i2c_generic_hw_engine.h" -/* - * Header of this unit - */ - -#include "i2c_hw_engine_dce80.h" - -/* - * Post-requisites: headers required by this unit - */ - -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" -/* - * This unit - */ - -enum dc_i2c_status { - DC_I2C_STATUS__DC_I2C_STATUS_IDLE, - DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW, - DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW -}; - -enum dc_i2c_arbitration { - DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, - DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH -}; - -enum { - /* No timeout in HW - * (timeout implemented in SW by querying status) */ - I2C_SETUP_TIME_LIMIT = 255, - I2C_HW_BUFFER_SIZE = 144 -}; - -/* - * @brief - * Cast 'struct i2c_hw_engine *' - * to 'struct i2c_hw_engine_dce80 *' - */ -#define FROM_I2C_HW_ENGINE(ptr) \ - container_of((ptr), struct i2c_hw_engine_dce80, base) - -/* - * @brief - * Cast pointer to 'struct i2c_engine *' - * to pointer to 'struct i2c_hw_engine_dce80 *' - */ -#define FROM_I2C_ENGINE(ptr) \ - FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base)) - -/* - * @brief - * Cast pointer to 'struct engine *' - * to 'pointer to struct i2c_hw_engine_dce80 *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -static void disable_i2c_hw_engine( - struct i2c_hw_engine_dce80 *engine) -{ - const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; - uint32_t value = 0; - - struct dc_context *ctx = NULL; - - ctx = engine->base.base.base.ctx; - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_ENABLE); - - dm_write_reg(ctx, addr, value); -} - -static void release_engine( - struct engine *engine) -{ - struct i2c_hw_engine_dce80 *hw_engine = FROM_ENGINE(engine); - - struct i2c_engine *base = NULL; - bool safe_to_reset; - uint32_t value = 0; - - base = &hw_engine->base.base; - - /* Restore original HW engine speed */ - - base->funcs->set_speed(base, hw_engine->base.original_speed); - - /* Release I2C */ - { - value = dm_read_reg(engine->ctx, mmDC_I2C_ARBITRATION); - - set_reg_field_value( - value, - 1, - DC_I2C_ARBITRATION, - DC_I2C_SW_DONE_USING_I2C_REG); - - dm_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value); - } - - /* Reset HW engine */ - { - uint32_t i2c_sw_status = 0; - - value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); - - i2c_sw_status = get_reg_field_value( - value, - DC_I2C_SW_STATUS, - DC_I2C_SW_STATUS); - /* if used by SW, safe to reset */ - safe_to_reset = (i2c_sw_status == 1); - } - { - value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL); - - if (safe_to_reset) - set_reg_field_value( - value, - 1, - DC_I2C_CONTROL, - DC_I2C_SOFT_RESET); - - set_reg_field_value( - value, - 1, - DC_I2C_CONTROL, - DC_I2C_SW_STATUS_RESET); - - dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); - } - - /* HW I2c engine - clock gating feature */ - if (!hw_engine->engine_keep_power_up_count) - disable_i2c_hw_engine(hw_engine); -} - -static void destruct( - struct i2c_hw_engine_dce80 *engine) -{ - dal_i2c_hw_engine_destruct(&engine->base); -} - -static void destroy( - struct i2c_engine **i2c_engine) -{ - struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(*i2c_engine); - - destruct(engine); - - kfree(engine); - - *i2c_engine = NULL; -} - -static bool setup_engine( - struct i2c_engine *i2c_engine) -{ - uint32_t value = 0; - struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); - - /* Program pin select */ - { - const uint32_t addr = mmDC_I2C_CONTROL; - - value = dm_read_reg(i2c_engine->base.ctx, addr); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_GO); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SOFT_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SEND_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SW_STATUS_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_TRANSACTION_COUNT); - - set_reg_field_value( - value, - engine->engine_id, - DC_I2C_CONTROL, - DC_I2C_DDC_SELECT); - - dm_write_reg(i2c_engine->base.ctx, addr, value); - } - - /* Program time limit */ - { - const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; - - value = dm_read_reg(i2c_engine->base.ctx, addr); - - set_reg_field_value( - value, - I2C_SETUP_TIME_LIMIT, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_TIME_LIMIT); - - set_reg_field_value( - value, - 1, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_ENABLE); - - dm_write_reg(i2c_engine->base.ctx, addr, value); - } - - /* Program HW priority - * set to High - interrupt software I2C at any time - * Enable restart of SW I2C that was interrupted by HW - * disable queuing of software while I2C is in use by HW */ - { - value = dm_read_reg(i2c_engine->base.ctx, - mmDC_I2C_ARBITRATION); - - set_reg_field_value( - value, - 0, - DC_I2C_ARBITRATION, - DC_I2C_NO_QUEUED_SW_GO); - - set_reg_field_value( - value, - DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL, - DC_I2C_ARBITRATION, - DC_I2C_SW_PRIORITY); - - dm_write_reg(i2c_engine->base.ctx, - mmDC_I2C_ARBITRATION, value); - } - - return true; -} - -static uint32_t get_speed( - const struct i2c_engine *i2c_engine) -{ - const struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); - - const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; - - uint32_t pre_scale = 0; - - uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr); - - pre_scale = get_reg_field_value( - value, - DC_I2C_DDC1_SPEED, - DC_I2C_DDC1_PRESCALE); - - /* [anaumov] it seems following is unnecessary */ - /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/ - - return pre_scale ? - engine->reference_frequency / pre_scale : - engine->base.default_speed; -} - -static void set_speed( - struct i2c_engine *i2c_engine, - uint32_t speed) -{ - struct i2c_hw_engine_dce80 *engine = FROM_I2C_ENGINE(i2c_engine); - - if (speed) { - const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED; - - uint32_t value = dm_read_reg(i2c_engine->base.ctx, addr); - - set_reg_field_value( - value, - engine->reference_frequency / speed, - DC_I2C_DDC1_SPEED, - DC_I2C_DDC1_PRESCALE); - - set_reg_field_value( - value, - 2, - DC_I2C_DDC1_SPEED, - DC_I2C_DDC1_THRESHOLD); - - dm_write_reg(i2c_engine->base.ctx, addr, value); - } -} - -static inline void reset_hw_engine(struct engine *engine) -{ - uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_CONTROL); - - set_reg_field_value( - value, - 1, - DC_I2C_CONTROL, - DC_I2C_SOFT_RESET); - - set_reg_field_value( - value, - 1, - DC_I2C_CONTROL, - DC_I2C_SW_STATUS_RESET); - - dm_write_reg(engine->ctx, mmDC_I2C_CONTROL, value); -} - -static bool is_hw_busy(struct engine *engine) -{ - uint32_t i2c_sw_status = 0; - - uint32_t value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); - - i2c_sw_status = get_reg_field_value( - value, - DC_I2C_SW_STATUS, - DC_I2C_SW_STATUS); - - if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE) - return false; - - reset_hw_engine(engine); - - value = dm_read_reg(engine->ctx, mmDC_I2C_SW_STATUS); - - i2c_sw_status = get_reg_field_value( - value, - DC_I2C_SW_STATUS, - DC_I2C_SW_STATUS); - - return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; -} - -/* - * @brief - * DC_GPIO_DDC MM register offsets - */ -static const uint32_t transaction_addr[] = { - mmDC_I2C_TRANSACTION0, - mmDC_I2C_TRANSACTION1, - mmDC_I2C_TRANSACTION2, - mmDC_I2C_TRANSACTION3 -}; - -static bool process_transaction( - struct i2c_hw_engine_dce80 *engine, - struct i2c_request_transaction_data *request) -{ - uint32_t length = request->length; - uint8_t *buffer = request->data; - - bool last_transaction = false; - uint32_t value = 0; - - struct dc_context *ctx = NULL; - - ctx = engine->base.base.base.ctx; - - { - const uint32_t addr = - transaction_addr[engine->transaction_count]; - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 1, - DC_I2C_TRANSACTION0, - DC_I2C_STOP_ON_NACK0); - - set_reg_field_value( - value, - 1, - DC_I2C_TRANSACTION0, - DC_I2C_START0); - - if ((engine->transaction_count == 3) || - (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || - (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) { - - set_reg_field_value( - value, - 1, - DC_I2C_TRANSACTION0, - DC_I2C_STOP0); - - last_transaction = true; - } else - set_reg_field_value( - value, - 0, - DC_I2C_TRANSACTION0, - DC_I2C_STOP0); - - set_reg_field_value( - value, - (0 != (request->action & - I2CAUX_TRANSACTION_ACTION_I2C_READ)), - DC_I2C_TRANSACTION0, - DC_I2C_RW0); - - set_reg_field_value( - value, - length, - DC_I2C_TRANSACTION0, - DC_I2C_COUNT0); - - dm_write_reg(ctx, addr, value); - } - - /* 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. */ - - { - value = 0; - - set_reg_field_value( - value, - false, - DC_I2C_DATA, - DC_I2C_DATA_RW); - - set_reg_field_value( - value, - request->address, - DC_I2C_DATA, - DC_I2C_DATA); - - if (engine->transaction_count == 0) { - set_reg_field_value( - value, - 0, - DC_I2C_DATA, - DC_I2C_INDEX); - - /*enable index write*/ - set_reg_field_value( - value, - 1, - DC_I2C_DATA, - DC_I2C_INDEX_WRITE); - } - - dm_write_reg(ctx, mmDC_I2C_DATA, value); - - if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) { - - set_reg_field_value( - value, - 0, - DC_I2C_DATA, - DC_I2C_INDEX_WRITE); - - while (length) { - - set_reg_field_value( - value, - *buffer++, - DC_I2C_DATA, - DC_I2C_DATA); - - dm_write_reg(ctx, mmDC_I2C_DATA, value); - --length; - } - } - } - - ++engine->transaction_count; - engine->buffer_used_bytes += length + 1; - - return last_transaction; -} - -static void execute_transaction( - struct i2c_hw_engine_dce80 *engine) -{ - uint32_t value = 0; - struct dc_context *ctx = NULL; - - ctx = engine->base.base.base.ctx; - - { - const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP; - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_DATA_DRIVE_EN); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_CLK_DRIVE_EN); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_DATA_DRIVE_SEL); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_INTRA_TRANSACTION_DELAY); - - set_reg_field_value( - value, - 0, - DC_I2C_DDC1_SETUP, - DC_I2C_DDC1_INTRA_BYTE_DELAY); - - dm_write_reg(ctx, addr, value); - } - - { - const uint32_t addr = mmDC_I2C_CONTROL; - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SOFT_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SW_STATUS_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_SEND_RESET); - - set_reg_field_value( - value, - 0, - DC_I2C_CONTROL, - DC_I2C_GO); - - set_reg_field_value( - value, - engine->transaction_count - 1, - DC_I2C_CONTROL, - DC_I2C_TRANSACTION_COUNT); - - dm_write_reg(ctx, addr, value); - } - - /* start I2C transfer */ - { - const uint32_t addr = mmDC_I2C_CONTROL; - - value = dm_read_reg(ctx, addr); - - set_reg_field_value( - value, - 1, - DC_I2C_CONTROL, - DC_I2C_GO); - - dm_write_reg(ctx, addr, value); - } - - /* all transactions were executed and HW buffer became empty - * (even though it actually happens when status becomes DONE) */ - engine->transaction_count = 0; - engine->buffer_used_bytes = 0; -} - -static void submit_channel_request( - struct i2c_engine *engine, - struct i2c_request_transaction_data *request) -{ - request->status = I2C_CHANNEL_OPERATION_SUCCEEDED; - - if (!process_transaction(FROM_I2C_ENGINE(engine), request)) - return; - - if (is_hw_busy(&engine->base)) { - request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; - return; - } - - execute_transaction(FROM_I2C_ENGINE(engine)); -} - -static void process_channel_reply( - struct i2c_engine *engine, - struct i2c_reply_transaction_data *reply) -{ - uint32_t length = reply->length; - uint8_t *buffer = reply->data; - - uint32_t value = 0; - - /*set index*/ - set_reg_field_value( - value, - length - 1, - DC_I2C_DATA, - DC_I2C_INDEX); - - set_reg_field_value( - value, - 1, - DC_I2C_DATA, - DC_I2C_DATA_RW); - - set_reg_field_value( - value, - 1, - DC_I2C_DATA, - DC_I2C_INDEX_WRITE); - - dm_write_reg(engine->base.ctx, mmDC_I2C_DATA, value); - - while (length) { - /* after reading the status, - * if the I2C operation executed successfully - * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller - * should read data bytes from I2C circular data buffer */ - - value = dm_read_reg(engine->base.ctx, mmDC_I2C_DATA); - - *buffer++ = get_reg_field_value( - value, - DC_I2C_DATA, - DC_I2C_DATA); - - --length; - } -} - -static enum i2c_channel_operation_result get_channel_status( - struct i2c_engine *engine, - uint8_t *returned_bytes) -{ - uint32_t i2c_sw_status = 0; - uint32_t value = dm_read_reg(engine->base.ctx, mmDC_I2C_SW_STATUS); - - i2c_sw_status = get_reg_field_value( - value, - DC_I2C_SW_STATUS, - DC_I2C_SW_STATUS); - - if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW) - return I2C_CHANNEL_OPERATION_ENGINE_BUSY; - else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_STOPPED_ON_NACK_MASK) - return I2C_CHANNEL_OPERATION_NO_RESPONSE; - else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_TIMEOUT_MASK) - return I2C_CHANNEL_OPERATION_TIMEOUT; - else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_ABORTED_MASK) - return I2C_CHANNEL_OPERATION_FAILED; - else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_DONE_MASK) - return I2C_CHANNEL_OPERATION_SUCCEEDED; - - /* - * this is the case when HW used for communication, I2C_SW_STATUS - * could be zero - */ - return I2C_CHANNEL_OPERATION_SUCCEEDED; -} - -static uint32_t get_hw_buffer_available_size( - const struct i2c_hw_engine *engine) -{ - return I2C_HW_BUFFER_SIZE - - FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes; -} - -static uint32_t get_transaction_timeout( - const struct i2c_hw_engine *engine, - uint32_t length) -{ - uint32_t speed = engine->base.funcs->get_speed(&engine->base); - - uint32_t period_timeout; - uint32_t num_of_clock_stretches; - - if (!speed) - return 0; - - period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed; - - num_of_clock_stretches = 1 + (length << 3) + 1; - num_of_clock_stretches += - (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) + - (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1); - - return period_timeout * num_of_clock_stretches; -} - -/* - * @brief - * DC_I2C_DDC1_SETUP MM register offsets - * - * @note - * The indices of this offset array are DDC engine IDs - */ -static const int32_t ddc_setup_offset[] = { - - mmDC_I2C_DDC1_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 1 */ - mmDC_I2C_DDC2_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 2 */ - mmDC_I2C_DDC3_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 3 */ - mmDC_I2C_DDC4_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 4 */ - mmDC_I2C_DDC5_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 5 */ - mmDC_I2C_DDC6_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 6 */ - mmDC_I2C_DDCVGA_SETUP - mmDC_I2C_DDC1_SETUP /* DDC Engine 7 */ -}; - -/* - * @brief - * DC_I2C_DDC1_SPEED MM register offsets - * - * @note - * The indices of this offset array are DDC engine IDs - */ -static const int32_t ddc_speed_offset[] = { - mmDC_I2C_DDC1_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 1 */ - mmDC_I2C_DDC2_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 2 */ - mmDC_I2C_DDC3_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 3 */ - mmDC_I2C_DDC4_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 4 */ - mmDC_I2C_DDC5_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 5 */ - mmDC_I2C_DDC6_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 6 */ - mmDC_I2C_DDCVGA_SPEED - mmDC_I2C_DDC1_SPEED /* DDC Engine 7 */ -}; - -static const struct i2c_engine_funcs i2c_engine_funcs = { - .destroy = destroy, - .get_speed = get_speed, - .set_speed = set_speed, - .setup_engine = setup_engine, - .submit_channel_request = submit_channel_request, - .process_channel_reply = process_channel_reply, - .get_channel_status = get_channel_status, - .acquire_engine = dal_i2c_hw_engine_acquire_engine, -}; - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .get_engine_type = dal_i2c_hw_engine_get_engine_type, - .acquire = dal_i2c_engine_acquire, - .submit_request = dal_i2c_hw_engine_submit_request, -}; - -static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = { - .get_hw_buffer_available_size = - get_hw_buffer_available_size, - .get_transaction_timeout = - get_transaction_timeout, - .wait_on_operation_result = - dal_i2c_hw_engine_wait_on_operation_result, -}; - -static void construct( - struct i2c_hw_engine_dce80 *engine, - const struct i2c_hw_engine_dce80_create_arg *arg) -{ - dal_i2c_hw_engine_construct(&engine->base, arg->ctx); - - engine->base.base.base.funcs = &engine_funcs; - engine->base.base.funcs = &i2c_engine_funcs; - engine->base.funcs = &i2c_hw_engine_funcs; - engine->base.default_speed = arg->default_speed; - engine->addr.DC_I2C_DDCX_SETUP = - mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id]; - engine->addr.DC_I2C_DDCX_SPEED = - mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id]; - - engine->engine_id = arg->engine_id; - engine->reference_frequency = arg->reference_frequency; - engine->buffer_used_bytes = 0; - engine->transaction_count = 0; - engine->engine_keep_power_up_count = 1; -} - -struct i2c_engine *dal_i2c_hw_engine_dce80_create( - const struct i2c_hw_engine_dce80_create_arg *arg) -{ - struct i2c_hw_engine_dce80 *engine; - - if (!arg) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - if ((arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t)) || - (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t)) || - !arg->reference_frequency) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - engine = kzalloc(sizeof(struct i2c_hw_engine_dce80), GFP_KERNEL); - - if (!engine) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - construct(engine, arg); - return &engine->base.base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h deleted file mode 100644 index 5c6116fb5479..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_HW_ENGINE_DCE80_H__ -#define __DAL_I2C_HW_ENGINE_DCE80_H__ - -struct i2c_hw_engine_dce80 { - struct i2c_hw_engine base; - struct { - uint32_t DC_I2C_DDCX_SETUP; - uint32_t DC_I2C_DDCX_SPEED; - } addr; - uint32_t engine_id; - /* expressed in kilohertz */ - uint32_t reference_frequency; - /* number of bytes currently used in HW buffer */ - uint32_t buffer_used_bytes; - /* number of pending transactions (before GO) */ - uint32_t transaction_count; - uint32_t engine_keep_power_up_count; -}; - -struct i2c_hw_engine_dce80_create_arg { - uint32_t engine_id; - uint32_t reference_frequency; - uint32_t default_speed; - struct dc_context *ctx; -}; - -struct i2c_engine *dal_i2c_hw_engine_dce80_create( - const struct i2c_hw_engine_dce80_create_arg *arg); -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c deleted file mode 100644 index 4853ee26096a..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" - -/* - * Header of this unit - */ - -#include "i2c_sw_engine_dce80.h" - -/* - * Post-requisites: headers required by this unit - */ - -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" - -/* - * This unit - */ - -static const uint32_t ddc_hw_status_addr[] = { - mmDC_I2C_DDC1_HW_STATUS, - mmDC_I2C_DDC2_HW_STATUS, - mmDC_I2C_DDC3_HW_STATUS, - mmDC_I2C_DDC4_HW_STATUS, - mmDC_I2C_DDC5_HW_STATUS, - mmDC_I2C_DDC6_HW_STATUS, - mmDC_I2C_DDCVGA_HW_STATUS -}; - -/* - * @brief - * Cast 'struct i2c_sw_engine *' - * to 'struct i2c_sw_engine_dce80 *' - */ -#define FROM_I2C_SW_ENGINE(ptr) \ - container_of((ptr), struct i2c_sw_engine_dce80, base) - -/* - * @brief - * Cast 'struct i2c_engine *' - * to 'struct i2c_sw_engine_dce80 *' - */ -#define FROM_I2C_ENGINE(ptr) \ - FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base)) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct i2c_sw_engine_dce80 *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -static void release_engine( - struct engine *engine) -{ - -} - -static void destruct( - struct i2c_sw_engine_dce80 *engine) -{ - dal_i2c_sw_engine_destruct(&engine->base); -} - -static void destroy( - struct i2c_engine **engine) -{ - struct i2c_sw_engine_dce80 *sw_engine = FROM_I2C_ENGINE(*engine); - - destruct(sw_engine); - - kfree(sw_engine); - - *engine = NULL; -} - -static bool acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc_handle) -{ - return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle); -} - -static const struct i2c_engine_funcs i2c_engine_funcs = { - .acquire_engine = acquire_engine, - .destroy = destroy, - .get_speed = dal_i2c_sw_engine_get_speed, - .set_speed = dal_i2c_sw_engine_set_speed, - .setup_engine = dal_i2c_engine_setup_i2c_engine, - .submit_channel_request = dal_i2c_sw_engine_submit_channel_request, - .process_channel_reply = dal_i2c_engine_process_channel_reply, - .get_channel_status = dal_i2c_sw_engine_get_channel_status, -}; - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .get_engine_type = dal_i2c_sw_engine_get_engine_type, - .acquire = dal_i2c_engine_acquire, - .submit_request = dal_i2c_sw_engine_submit_request, -}; - -static void construct( - struct i2c_sw_engine_dce80 *engine, - const struct i2c_sw_engine_dce80_create_arg *arg) -{ - struct i2c_sw_engine_create_arg arg_base; - - arg_base.ctx = arg->ctx; - arg_base.default_speed = arg->default_speed; - - dal_i2c_sw_engine_construct(&engine->base, &arg_base); - - engine->base.base.base.funcs = &engine_funcs; - engine->base.base.funcs = &i2c_engine_funcs; - engine->base.default_speed = arg->default_speed; - engine->engine_id = arg->engine_id; -} - -struct i2c_engine *dal_i2c_sw_engine_dce80_create( - const struct i2c_sw_engine_dce80_create_arg *arg) -{ - struct i2c_sw_engine_dce80 *engine; - - if (!arg) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - engine = kzalloc(sizeof(struct i2c_sw_engine_dce80), GFP_KERNEL); - - if (!engine) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - construct(engine, arg); - return &engine->base.base; -} - diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c deleted file mode 100644 index ed48596dd2a5..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../i2caux.h" - -/* - * Header of this unit - */ - -#include "i2caux_dce80.h" - -/* - * Post-requisites: headers required by this unit - */ - -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "i2c_sw_engine_dce80.h" -#include "../i2c_hw_engine.h" -#include "i2c_hw_engine_dce80.h" -#include "../i2c_generic_hw_engine.h" -#include "../aux_engine.h" - - -#include "../dce110/aux_engine_dce110.h" -#include "../dce110/i2caux_dce110.h" - -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" - - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers dce80_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -/* - * This unit - */ - -#define FROM_I2C_AUX(ptr) \ - container_of((ptr), struct i2caux_dce80, base) - -static void destruct( - struct i2caux_dce80 *i2caux_dce80) -{ - dal_i2caux_destruct(&i2caux_dce80->base); -} - -static void destroy( - struct i2caux **i2c_engine) -{ - struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(*i2c_engine); - - destruct(i2caux_dce80); - - kfree(i2caux_dce80); - - *i2c_engine = NULL; -} - -static struct i2c_engine *acquire_i2c_hw_engine( - struct i2caux *i2caux, - struct ddc *ddc) -{ - struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(i2caux); - - struct i2c_engine *engine = NULL; - bool non_generic; - - if (!ddc) - return NULL; - - if (ddc->hw_info.hw_supported) { - enum gpio_ddc_line line = dal_ddc_get_line(ddc); - - if (line < GPIO_DDC_LINE_COUNT) { - non_generic = true; - engine = i2caux->i2c_hw_engines[line]; - } - } - - if (!engine) { - non_generic = false; - engine = i2caux->i2c_generic_hw_engine; - } - - if (!engine) - return NULL; - - if (non_generic) { - if (!i2caux_dce80->i2c_hw_buffer_in_use && - engine->base.funcs->acquire(&engine->base, ddc)) { - i2caux_dce80->i2c_hw_buffer_in_use = true; - return engine; - } - } else { - if (engine->base.funcs->acquire(&engine->base, ddc)) - return engine; - } - - return NULL; -} - -static void release_engine( - struct i2caux *i2caux, - struct engine *engine) -{ - if (engine->funcs->get_engine_type(engine) == - I2CAUX_ENGINE_TYPE_I2C_DDC_HW) - FROM_I2C_AUX(i2caux)->i2c_hw_buffer_in_use = false; - - dal_i2caux_release_engine(i2caux, engine); -} - -static const enum gpio_ddc_line hw_ddc_lines[] = { - GPIO_DDC_LINE_DDC1, - GPIO_DDC_LINE_DDC2, - GPIO_DDC_LINE_DDC3, - GPIO_DDC_LINE_DDC4, - GPIO_DDC_LINE_DDC5, - GPIO_DDC_LINE_DDC6, - GPIO_DDC_LINE_DDC_VGA -}; - -static const enum gpio_ddc_line hw_aux_lines[] = { - GPIO_DDC_LINE_DDC1, - GPIO_DDC_LINE_DDC2, - GPIO_DDC_LINE_DDC3, - GPIO_DDC_LINE_DDC4, - GPIO_DDC_LINE_DDC5, - GPIO_DDC_LINE_DDC6 -}; - -static const struct i2caux_funcs i2caux_funcs = { - .destroy = destroy, - .acquire_i2c_hw_engine = acquire_i2c_hw_engine, - .release_engine = release_engine, - .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine, - .acquire_aux_engine = dal_i2caux_acquire_aux_engine, -}; - -static void construct( - struct i2caux_dce80 *i2caux_dce80, - struct dc_context *ctx) -{ - /* Entire family have I2C engine reference clock frequency - * changed from XTALIN (27) to XTALIN/2 (13.5) */ - - struct i2caux *base = &i2caux_dce80->base; - - uint32_t reference_frequency = - dal_i2caux_get_reference_clock(ctx->dc_bios) >> 1; - - /*bool use_i2c_sw_engine = dal_adapter_service_is_feature_supported(as, - FEATURE_RESTORE_USAGE_I2C_SW_ENGINE);*/ - - /* Use SWI2C for dce8 currently, sicne we have bug with hwi2c */ - bool use_i2c_sw_engine = true; - - uint32_t i; - - dal_i2caux_construct(base, ctx); - - i2caux_dce80->base.funcs = &i2caux_funcs; - i2caux_dce80->i2c_hw_buffer_in_use = false; - - /* Create I2C HW engines (HW + SW pairs) - * for all lines which has assisted HW DDC - * 'i' (loop counter) used as DDC/AUX engine_id */ - - i = 0; - - do { - enum gpio_ddc_line line_id = hw_ddc_lines[i]; - - struct i2c_hw_engine_dce80_create_arg hw_arg; - - if (use_i2c_sw_engine) { - struct i2c_sw_engine_dce80_create_arg sw_arg; - - sw_arg.engine_id = i; - sw_arg.default_speed = base->default_i2c_sw_speed; - sw_arg.ctx = ctx; - base->i2c_sw_engines[line_id] = - dal_i2c_sw_engine_dce80_create(&sw_arg); - } - - hw_arg.engine_id = i; - hw_arg.reference_frequency = reference_frequency; - hw_arg.default_speed = base->default_i2c_hw_speed; - hw_arg.ctx = ctx; - - base->i2c_hw_engines[line_id] = - dal_i2c_hw_engine_dce80_create(&hw_arg); - - ++i; - } while (i < ARRAY_SIZE(hw_ddc_lines)); - - /* Create AUX engines for all lines which has assisted HW AUX - * 'i' (loop counter) used as DDC/AUX engine_id */ - - i = 0; - - do { - enum gpio_ddc_line line_id = hw_aux_lines[i]; - - struct aux_engine_dce110_init_data arg; - - arg.engine_id = i; - arg.timeout_period = base->aux_timeout_period; - arg.ctx = ctx; - arg.regs = &dce80_aux_regs[i]; - - base->aux_engines[line_id] = - dal_aux_engine_dce110_create(&arg); - - ++i; - } while (i < ARRAY_SIZE(hw_aux_lines)); - - /* TODO Generic I2C SW and HW */ -} - -struct i2caux *dal_i2caux_dce80_create( - struct dc_context *ctx) -{ - struct i2caux_dce80 *i2caux_dce80 = - kzalloc(sizeof(struct i2caux_dce80), GFP_KERNEL); - - if (!i2caux_dce80) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - construct(i2caux_dce80, ctx); - return &i2caux_dce80->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h b/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h deleted file mode 100644 index 21908629e973..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCE80_H__ -#define __DAL_I2C_AUX_DCE80_H__ - -struct i2caux_dce80 { - struct i2caux base; - /* indicate the I2C HW circular buffer is in use */ - bool i2c_hw_buffer_in_use; -}; - -struct i2caux *dal_i2caux_dce80_create( - struct dc_context *ctx); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c deleted file mode 100644 index a59c1f50c1e8..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -#include "../dce110/aux_engine_dce110.h" -#include "../dce110/i2c_hw_engine_dce110.h" -#include "../dce110/i2caux_dce110.h" - -#include "dcn/dcn_1_0_offset.h" -#include "dcn/dcn_1_0_sh_mask.h" -#include "soc15_hw_ip.h" -#include "vega10_ip_offset.h" - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -#define BASE_INNER(seg) \ - DCE_BASE__INST0_SEG ## seg - -/* compile time expand base address. */ -#define BASE(seg) \ - BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name -/* macros to expend register list macro defined in HW object header file - * end *********************/ - -#define aux_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK \ -} - -#define hw_engine_regs(id)\ -{\ - I2C_HW_ENGINE_COMMON_REG_LIST(id) \ -} - -static const struct dce110_aux_registers dcn10_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5), -}; - -static const struct dce110_i2c_hw_engine_registers dcn10_hw_engine_regs[] = { - hw_engine_regs(1), - hw_engine_regs(2), - hw_engine_regs(3), - hw_engine_regs(4), - hw_engine_regs(5), - hw_engine_regs(6) -}; - -static const struct dce110_i2c_hw_engine_shift i2c_shift = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce110_i2c_hw_engine_mask i2c_mask = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -struct i2caux *dal_i2caux_dcn10_create( - struct dc_context *ctx) -{ - struct i2caux_dce110 *i2caux_dce110 = - kzalloc(sizeof(struct i2caux_dce110), GFP_KERNEL); - - if (!i2caux_dce110) { - ASSERT_CRITICAL(false); - return NULL; - } - - dal_i2caux_dce110_construct(i2caux_dce110, - ctx, - ARRAY_SIZE(dcn10_aux_regs), - dcn10_aux_regs, - dcn10_hw_engine_regs, - &i2c_shift, - &i2c_mask); - return &i2caux_dce110->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h b/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h deleted file mode 100644 index aeb4a86463d4..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DCN10_H__ -#define __DAL_I2C_AUX_DCN10_H__ - -struct i2caux *dal_i2caux_dcn10_create( - struct dc_context *ctx); - -#endif /* __DAL_I2C_AUX_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c b/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c deleted file mode 100644 index e6408f644086..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2012-16 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "../i2caux.h" -#include "../engine.h" -#include "../i2c_engine.h" -#include "../i2c_sw_engine.h" -#include "../i2c_hw_engine.h" - -/* - * Header of this unit - */ -#include "i2caux_diag.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -static void destruct( - struct i2caux *i2caux) -{ - dal_i2caux_destruct(i2caux); -} - -static void destroy( - struct i2caux **i2c_engine) -{ - destruct(*i2c_engine); - - kfree(*i2c_engine); - - *i2c_engine = NULL; -} - -/* function table */ -static const struct i2caux_funcs i2caux_funcs = { - .destroy = destroy, - .acquire_i2c_hw_engine = NULL, - .release_engine = NULL, - .acquire_i2c_sw_engine = NULL, - .acquire_aux_engine = NULL, -}; - -static void construct( - struct i2caux *i2caux, - struct dc_context *ctx) -{ - dal_i2caux_construct(i2caux, ctx); - i2caux->funcs = &i2caux_funcs; -} - -struct i2caux *dal_i2caux_diag_fpga_create( - struct dc_context *ctx) -{ - struct i2caux *i2caux = kzalloc(sizeof(struct i2caux), - GFP_KERNEL); - - if (!i2caux) { - ASSERT_CRITICAL(false); - return NULL; - } - - construct(i2caux, ctx); - return i2caux; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h b/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h deleted file mode 100644 index a83eeb748283..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012-16 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_DIAG_FPGA_H__ -#define __DAL_I2C_AUX_DIAG_FPGA_H__ - -struct i2caux *dal_i2caux_diag_fpga_create( - struct dc_context *ctx); - -#endif /* __DAL_I2C_AUX_DIAG_FPGA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/engine.h deleted file mode 100644 index b16fb1ff687d..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_ENGINE_H__ -#define __DAL_ENGINE_H__ - -#include "dc_ddc_types.h" - -enum i2caux_transaction_operation { - I2CAUX_TRANSACTION_READ, - I2CAUX_TRANSACTION_WRITE -}; - -enum i2caux_transaction_address_space { - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1, - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD -}; - -struct i2caux_transaction_payload { - enum i2caux_transaction_address_space address_space; - uint32_t address; - uint32_t length; - uint8_t *data; -}; - -enum i2caux_transaction_status { - I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L), - I2CAUX_TRANSACTION_STATUS_SUCCEEDED, - I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY, - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT, - I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR, - I2CAUX_TRANSACTION_STATUS_FAILED_NACK, - I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE, - I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION, - I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION, - I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW, - I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON -}; - -struct i2caux_transaction_request { - enum i2caux_transaction_operation operation; - struct i2caux_transaction_payload payload; - enum i2caux_transaction_status status; -}; - -enum i2caux_engine_type { - I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L), - I2CAUX_ENGINE_TYPE_AUX, - I2CAUX_ENGINE_TYPE_I2C_DDC_HW, - I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW, - I2CAUX_ENGINE_TYPE_I2C_SW -}; - -enum i2c_default_speed { - I2CAUX_DEFAULT_I2C_HW_SPEED = 50, - I2CAUX_DEFAULT_I2C_SW_SPEED = 50 -}; - -struct engine; - -struct engine_funcs { - enum i2caux_engine_type (*get_engine_type)( - const struct engine *engine); - bool (*acquire)( - struct engine *engine, - struct ddc *ddc); - bool (*submit_request)( - struct engine *engine, - struct i2caux_transaction_request *request, - bool middle_of_transaction); - void (*release_engine)( - struct engine *engine); -}; - -struct engine { - const struct engine_funcs *funcs; - uint32_t inst; - struct ddc *ddc; - struct dc_context *ctx; -}; - -void dal_i2caux_construct_engine( - struct engine *engine, - struct dc_context *ctx); - -void dal_i2caux_destruct_engine( - struct engine *engine); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c b/drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c deleted file mode 100644 index 5d155d36d353..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" - -/* - * Header of this unit - */ - -#include "engine.h" - -void dal_i2caux_construct_engine( - struct engine *engine, - struct dc_context *ctx) -{ - engine->ddc = NULL; - engine->ctx = ctx; -} - -void dal_i2caux_destruct_engine( - struct engine *engine) -{ - /* nothing to do */ -} - diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c deleted file mode 100644 index 70e20bd47ce4..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "engine.h" - -/* - * Header of this unit - */ - -#include "i2c_engine.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -#define FROM_ENGINE(ptr) \ - container_of((ptr), struct i2c_engine, base) - -bool dal_i2c_engine_acquire( - struct engine *engine, - struct ddc *ddc_handle) -{ - struct i2c_engine *i2c_engine = FROM_ENGINE(engine); - - uint32_t counter = 0; - bool result; - - do { - result = i2c_engine->funcs->acquire_engine( - i2c_engine, ddc_handle); - - if (result) - break; - - /* i2c_engine is busy by VBios, lets wait and retry */ - - udelay(10); - - ++counter; - } while (counter < 2); - - if (result) { - if (!i2c_engine->funcs->setup_engine(i2c_engine)) { - engine->funcs->release_engine(engine); - result = false; - } - } - - return result; -} - -bool dal_i2c_engine_setup_i2c_engine( - struct i2c_engine *engine) -{ - /* Derivative classes do not have to override this */ - - return true; -} - -void dal_i2c_engine_submit_channel_request( - struct i2c_engine *engine, - struct i2c_request_transaction_data *request) -{ - -} - -void dal_i2c_engine_process_channel_reply( - struct i2c_engine *engine, - struct i2c_reply_transaction_data *reply) -{ - -} - -void dal_i2c_engine_construct( - struct i2c_engine *engine, - struct dc_context *ctx) -{ - dal_i2caux_construct_engine(&engine->base, ctx); - engine->timeout_delay = 0; -} - -void dal_i2c_engine_destruct( - struct i2c_engine *engine) -{ - dal_i2caux_destruct_engine(&engine->base); -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h deleted file mode 100644 index ded6ea34b714..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_ENGINE_H__ -#define __DAL_I2C_ENGINE_H__ - -enum i2c_channel_operation_result { - I2C_CHANNEL_OPERATION_SUCCEEDED, - I2C_CHANNEL_OPERATION_FAILED, - I2C_CHANNEL_OPERATION_NOT_GRANTED, - I2C_CHANNEL_OPERATION_IS_BUSY, - I2C_CHANNEL_OPERATION_NO_HANDLE_PROVIDED, - I2C_CHANNEL_OPERATION_CHANNEL_IN_USE, - I2C_CHANNEL_OPERATION_CHANNEL_CLIENT_MAX_ALLOWED, - I2C_CHANNEL_OPERATION_ENGINE_BUSY, - I2C_CHANNEL_OPERATION_TIMEOUT, - I2C_CHANNEL_OPERATION_NO_RESPONSE, - I2C_CHANNEL_OPERATION_HW_REQUEST_I2C_BUS, - I2C_CHANNEL_OPERATION_WRONG_PARAMETER, - I2C_CHANNEL_OPERATION_OUT_NB_OF_RETRIES, - I2C_CHANNEL_OPERATION_NOT_STARTED -}; - -struct i2c_request_transaction_data { - enum i2caux_transaction_action action; - enum i2c_channel_operation_result status; - uint8_t address; - uint32_t length; - uint8_t *data; -}; - -struct i2c_reply_transaction_data { - uint32_t length; - uint8_t *data; -}; - -struct i2c_engine; - -struct i2c_engine_funcs { - void (*destroy)( - struct i2c_engine **ptr); - uint32_t (*get_speed)( - const struct i2c_engine *engine); - void (*set_speed)( - struct i2c_engine *engine, - uint32_t speed); - bool (*acquire_engine)( - struct i2c_engine *engine, - struct ddc *ddc); - bool (*setup_engine)( - struct i2c_engine *engine); - void (*submit_channel_request)( - struct i2c_engine *engine, - struct i2c_request_transaction_data *request); - void (*process_channel_reply)( - struct i2c_engine *engine, - struct i2c_reply_transaction_data *reply); - enum i2c_channel_operation_result (*get_channel_status)( - struct i2c_engine *engine, - uint8_t *returned_bytes); -}; - -struct i2c_engine { - struct engine base; - const struct i2c_engine_funcs *funcs; - uint32_t timeout_delay; - uint32_t setup_limit; - uint32_t send_reset_length; -}; - -void dal_i2c_engine_construct( - struct i2c_engine *engine, - struct dc_context *ctx); - -void dal_i2c_engine_destruct( - struct i2c_engine *engine); - -bool dal_i2c_engine_setup_i2c_engine( - struct i2c_engine *engine); - -void dal_i2c_engine_submit_channel_request( - struct i2c_engine *engine, - struct i2c_request_transaction_data *request); - -void dal_i2c_engine_process_channel_reply( - struct i2c_engine *engine, - struct i2c_reply_transaction_data *reply); - -bool dal_i2c_engine_acquire( - struct engine *ptr, - struct ddc *ddc_handle); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c deleted file mode 100644 index 5a4295e0fae5..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "engine.h" -#include "i2c_engine.h" -#include "i2c_hw_engine.h" - -/* - * Header of this unit - */ - -#include "i2c_generic_hw_engine.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -/* - * @brief - * Cast 'struct i2c_hw_engine *' - * to 'struct i2c_generic_hw_engine *' - */ -#define FROM_I2C_HW_ENGINE(ptr) \ - container_of((ptr), struct i2c_generic_hw_engine, base) - -/* - * @brief - * Cast 'struct i2c_engine *' - * to 'struct i2c_generic_hw_engine *' - */ -#define FROM_I2C_ENGINE(ptr) \ - FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base)) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct i2c_generic_hw_engine *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type( - const struct engine *engine) -{ - return I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW; -} - -/* - * @brief - * Single transaction handling. - * Since transaction may be bigger than HW buffer size, - * it divides transaction to sub-transactions - * and uses batch transaction feature of the engine. - */ -bool dal_i2c_generic_hw_engine_submit_request( - struct engine *engine, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction) -{ - struct i2c_generic_hw_engine *hw_engine = FROM_ENGINE(engine); - - struct i2c_hw_engine *base = &hw_engine->base; - - uint32_t max_payload_size = - base->funcs->get_hw_buffer_available_size(base); - - bool initial_stop_bit = !middle_of_transaction; - - struct i2c_generic_transaction_attributes attributes; - - enum i2c_channel_operation_result operation_result = - I2C_CHANNEL_OPERATION_FAILED; - - bool result = false; - - /* setup transaction initial properties */ - - uint8_t address = i2caux_request->payload.address; - uint8_t *current_payload = i2caux_request->payload.data; - uint32_t remaining_payload_size = i2caux_request->payload.length; - - bool first_iteration = true; - - if (i2caux_request->operation == I2CAUX_TRANSACTION_READ) - attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_READ; - else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE) - attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - else { - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION; - return false; - } - - /* Do batch transaction. - * Divide read/write data into payloads which fit HW buffer size. - * 1. Single transaction: - * start_bit = 1, stop_bit depends on session state, ack_on_read = 0; - * 2. Start of batch transaction: - * start_bit = 1, stop_bit = 0, ack_on_read = 1; - * 3. Middle of batch transaction: - * start_bit = 0, stop_bit = 0, ack_on_read = 1; - * 4. End of batch transaction: - * start_bit = 0, stop_bit depends on session state, ack_on_read = 0. - * Session stop bit is set if 'middle_of_transaction' = 0. */ - - while (remaining_payload_size) { - uint32_t current_transaction_size; - uint32_t current_payload_size; - - bool last_iteration; - bool stop_bit; - - /* Calculate current transaction size and payload size. - * Transaction size = total number of bytes in transaction, - * including slave's address; - * Payload size = number of data bytes in transaction. */ - - if (first_iteration) { - /* In the first sub-transaction we send slave's address - * thus we need to reserve one byte for it */ - current_transaction_size = - (remaining_payload_size > max_payload_size - 1) ? - max_payload_size : - remaining_payload_size + 1; - - current_payload_size = current_transaction_size - 1; - } else { - /* Second and further sub-transactions will have - * entire buffer reserved for data */ - current_transaction_size = - (remaining_payload_size > max_payload_size) ? - max_payload_size : - remaining_payload_size; - - current_payload_size = current_transaction_size; - } - - last_iteration = - (remaining_payload_size == current_payload_size); - - stop_bit = last_iteration ? initial_stop_bit : false; - - /* write slave device address */ - - if (first_iteration) - hw_engine->funcs->write_address(hw_engine, address); - - /* write current portion of data, if requested */ - - if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE) - hw_engine->funcs->write_data( - hw_engine, - current_payload, - current_payload_size); - - /* execute transaction */ - - attributes.start_bit = first_iteration; - attributes.stop_bit = stop_bit; - attributes.last_read = last_iteration; - attributes.transaction_size = current_transaction_size; - - hw_engine->funcs->execute_transaction(hw_engine, &attributes); - - /* wait until transaction is processed; if it fails - quit */ - - operation_result = base->funcs->wait_on_operation_result( - base, - base->funcs->get_transaction_timeout( - base, current_transaction_size), - I2C_CHANNEL_OPERATION_ENGINE_BUSY); - - if (operation_result != I2C_CHANNEL_OPERATION_SUCCEEDED) - break; - - /* read current portion of data, if requested */ - - /* the read offset should be 1 for first sub-transaction, - * and 0 for any next one */ - - if (i2caux_request->operation == I2CAUX_TRANSACTION_READ) - hw_engine->funcs->read_data(hw_engine, current_payload, - current_payload_size, first_iteration ? 1 : 0); - - /* update loop variables */ - - first_iteration = false; - current_payload += current_payload_size; - remaining_payload_size -= current_payload_size; - } - - /* update transaction status */ - - switch (operation_result) { - case I2C_CHANNEL_OPERATION_SUCCEEDED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - result = true; - break; - case I2C_CHANNEL_OPERATION_NO_RESPONSE: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - break; - case I2C_CHANNEL_OPERATION_TIMEOUT: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - break; - case I2C_CHANNEL_OPERATION_FAILED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE; - break; - default: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION; - } - - return result; -} - -/* - * @brief - * Returns number of microseconds to wait until timeout to be considered - */ -uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout( - const struct i2c_hw_engine *engine, - uint32_t length) -{ - const struct i2c_engine *base = &engine->base; - - uint32_t speed = base->funcs->get_speed(base); - - if (!speed) - return 0; - - /* total timeout = period_timeout * (start + data bits count + stop) */ - - return ((1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed) * - (1 + (length << 3) + 1); -} - -void dal_i2c_generic_hw_engine_construct( - struct i2c_generic_hw_engine *engine, - struct dc_context *ctx) -{ - dal_i2c_hw_engine_construct(&engine->base, ctx); -} - -void dal_i2c_generic_hw_engine_destruct( - struct i2c_generic_hw_engine *engine) -{ - dal_i2c_hw_engine_destruct(&engine->base); -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h deleted file mode 100644 index 1da0397b04a2..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_GENERIC_HW_ENGINE_H__ -#define __DAL_I2C_GENERIC_HW_ENGINE_H__ - -struct i2c_generic_transaction_attributes { - enum i2caux_transaction_action action; - uint32_t transaction_size; - bool start_bit; - bool stop_bit; - bool last_read; -}; - -struct i2c_generic_hw_engine; - -struct i2c_generic_hw_engine_funcs { - void (*write_address)( - struct i2c_generic_hw_engine *engine, - uint8_t address); - void (*write_data)( - struct i2c_generic_hw_engine *engine, - const uint8_t *buffer, - uint32_t length); - void (*read_data)( - struct i2c_generic_hw_engine *engine, - uint8_t *buffer, - uint32_t length, - uint32_t offset); - void (*execute_transaction)( - struct i2c_generic_hw_engine *engine, - struct i2c_generic_transaction_attributes *attributes); -}; - -struct i2c_generic_hw_engine { - struct i2c_hw_engine base; - const struct i2c_generic_hw_engine_funcs *funcs; -}; - -void dal_i2c_generic_hw_engine_construct( - struct i2c_generic_hw_engine *engine, - struct dc_context *ctx); - -void dal_i2c_generic_hw_engine_destruct( - struct i2c_generic_hw_engine *engine); -enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type( - const struct engine *engine); -bool dal_i2c_generic_hw_engine_submit_request( - struct engine *ptr, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction); -uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout( - const struct i2c_hw_engine *engine, - uint32_t length); -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c deleted file mode 100644 index 141898533e8e..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" -#include "dm_event_log.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "engine.h" -#include "i2c_engine.h" - -/* - * Header of this unit - */ - -#include "i2c_hw_engine.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -/* - * @brief - * Cast 'struct i2c_engine *' - * to 'struct i2c_hw_engine *' - */ -#define FROM_I2C_ENGINE(ptr) \ - container_of((ptr), struct i2c_hw_engine, base) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct i2c_hw_engine *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type( - const struct engine *engine) -{ - return I2CAUX_ENGINE_TYPE_I2C_DDC_HW; -} - -bool dal_i2c_hw_engine_submit_request( - struct engine *engine, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction) -{ - struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine); - - struct i2c_request_transaction_data request; - - uint32_t transaction_timeout; - - enum i2c_channel_operation_result operation_result; - - bool result = false; - - /* We need following: - * transaction length will not exceed - * the number of free bytes in HW buffer (minus one for address)*/ - - if (i2caux_request->payload.length >= - hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) { - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW; - return false; - } - - if (i2caux_request->operation == I2CAUX_TRANSACTION_READ) - request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_READ; - else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE) - request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - else { - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION; - /* [anaumov] in DAL2, there was no "return false" */ - return false; - } - - request.address = (uint8_t)i2caux_request->payload.address; - request.length = i2caux_request->payload.length; - request.data = i2caux_request->payload.data; - - /* obtain timeout value before submitting request */ - - transaction_timeout = hw_engine->funcs->get_transaction_timeout( - hw_engine, i2caux_request->payload.length + 1); - - hw_engine->base.funcs->submit_channel_request( - &hw_engine->base, &request); - /* EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_I2C, */ - /* request.action, request.address, request.length, request.data); */ - - if ((request.status == I2C_CHANNEL_OPERATION_FAILED) || - (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) { - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY; - return false; - } - - /* wait until transaction proceed */ - - operation_result = hw_engine->funcs->wait_on_operation_result( - hw_engine, - transaction_timeout, - I2C_CHANNEL_OPERATION_ENGINE_BUSY); - - /* update transaction status */ - - switch (operation_result) { - case I2C_CHANNEL_OPERATION_SUCCEEDED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - result = true; - break; - case I2C_CHANNEL_OPERATION_NO_RESPONSE: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - break; - case I2C_CHANNEL_OPERATION_TIMEOUT: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - break; - case I2C_CHANNEL_OPERATION_FAILED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE; - break; - default: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION; - } - - if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) { - struct i2c_reply_transaction_data reply; - - reply.data = i2caux_request->payload.data; - reply.length = i2caux_request->payload.length; - - hw_engine->base.funcs-> - process_channel_reply(&hw_engine->base, &reply); - /* EVENT_LOG_AUX_REP(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_I2C, */ - /* AUX_TRANSACTION_REPLY_I2C_ACK, reply.length, reply.data); */ - } - - - - return result; -} - -bool dal_i2c_hw_engine_acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc) -{ - enum gpio_result result; - uint32_t current_speed; - - result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE, - GPIO_DDC_CONFIG_TYPE_MODE_I2C); - - if (result != GPIO_RESULT_OK) - return false; - - engine->base.ddc = ddc; - - current_speed = engine->funcs->get_speed(engine); - - if (current_speed) - FROM_I2C_ENGINE(engine)->original_speed = current_speed; - - return true; -} -/* - * @brief - * Queries in a loop for current engine status - * until retrieved status matches 'expected_result', or timeout occurs. - * Timeout given in microseconds - * and the status query frequency is also one per microsecond. - */ -enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result( - struct i2c_hw_engine *engine, - uint32_t timeout, - enum i2c_channel_operation_result expected_result) -{ - enum i2c_channel_operation_result result; - uint32_t i = 0; - - if (!timeout) - return I2C_CHANNEL_OPERATION_SUCCEEDED; - - do { - result = engine->base.funcs->get_channel_status( - &engine->base, NULL); - - if (result != expected_result) - break; - - udelay(1); - - ++i; - } while (i < timeout); - - return result; -} - -void dal_i2c_hw_engine_construct( - struct i2c_hw_engine *engine, - struct dc_context *ctx) -{ - dal_i2c_engine_construct(&engine->base, ctx); - engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED; - engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED; -} - -void dal_i2c_hw_engine_destruct( - struct i2c_hw_engine *engine) -{ - dal_i2c_engine_destruct(&engine->base); -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h deleted file mode 100644 index 8936a994804a..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_HW_ENGINE_H__ -#define __DAL_I2C_HW_ENGINE_H__ - -enum { - TRANSACTION_TIMEOUT_IN_I2C_CLOCKS = 32 -}; - -struct i2c_hw_engine; - -struct i2c_hw_engine_funcs { - uint32_t (*get_hw_buffer_available_size)( - const struct i2c_hw_engine *engine); - enum i2c_channel_operation_result (*wait_on_operation_result)( - struct i2c_hw_engine *engine, - uint32_t timeout, - enum i2c_channel_operation_result expected_result); - uint32_t (*get_transaction_timeout)( - const struct i2c_hw_engine *engine, - uint32_t length); -}; - -struct i2c_hw_engine { - struct i2c_engine base; - const struct i2c_hw_engine_funcs *funcs; - - /* Values below are in kilohertz */ - uint32_t original_speed; - uint32_t default_speed; -}; - -void dal_i2c_hw_engine_construct( - struct i2c_hw_engine *engine, - struct dc_context *ctx); - -void dal_i2c_hw_engine_destruct( - struct i2c_hw_engine *engine); - -enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result( - struct i2c_hw_engine *engine, - uint32_t timeout, - enum i2c_channel_operation_result expected_result); - -bool dal_i2c_hw_engine_acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc); - -bool dal_i2c_hw_engine_submit_request( - struct engine *ptr, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction); - -enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type( - const struct engine *engine); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c deleted file mode 100644 index 8e19bb629394..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "engine.h" -#include "i2c_engine.h" - -/* - * Header of this unit - */ - -#include "i2c_sw_engine.h" - -/* - * Post-requisites: headers required by this unit - */ - -/* - * This unit - */ - -#define SCL false -#define SDA true - -static inline bool read_bit_from_ddc( - struct ddc *ddc, - bool data_nor_clock) -{ - uint32_t value = 0; - - if (data_nor_clock) - dal_gpio_get_value(ddc->pin_data, &value); - else - dal_gpio_get_value(ddc->pin_clock, &value); - - return (value != 0); -} - -static inline void write_bit_to_ddc( - struct ddc *ddc, - bool data_nor_clock, - bool bit) -{ - uint32_t value = bit ? 1 : 0; - - if (data_nor_clock) - dal_gpio_set_value(ddc->pin_data, value); - else - dal_gpio_set_value(ddc->pin_clock, value); -} - -static bool wait_for_scl_high( - struct dc_context *ctx, - struct ddc *ddc, - uint16_t clock_delay_div_4) -{ - uint32_t scl_retry = 0; - uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4; - - udelay(clock_delay_div_4); - - /* 3 milliseconds delay - * to wake up some displays from "low power" state. - */ - - do { - if (read_bit_from_ddc(ddc, SCL)) - return true; - - udelay(clock_delay_div_4); - - ++scl_retry; - } while (scl_retry <= scl_retry_max); - - return false; -} - -static bool start_sync( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4) -{ - uint32_t retry = 0; - - /* The I2C communications start signal is: - * the SDA going low from high, while the SCL is high. */ - - write_bit_to_ddc(ddc_handle, SCL, true); - - udelay(clock_delay_div_4); - - do { - write_bit_to_ddc(ddc_handle, SDA, true); - - if (!read_bit_from_ddc(ddc_handle, SDA)) { - ++retry; - continue; - } - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - break; - - write_bit_to_ddc(ddc_handle, SDA, false); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, false); - - udelay(clock_delay_div_4); - - return true; - } while (retry <= I2C_SW_RETRIES); - - return false; -} - -static bool stop_sync( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4) -{ - uint32_t retry = 0; - - /* The I2C communications stop signal is: - * the SDA going high from low, while the SCL is high. */ - - write_bit_to_ddc(ddc_handle, SCL, false); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SDA, false); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - return false; - - write_bit_to_ddc(ddc_handle, SDA, true); - - do { - udelay(clock_delay_div_4); - - if (read_bit_from_ddc(ddc_handle, SDA)) - return true; - - ++retry; - } while (retry <= 2); - - return false; -} - -static bool write_byte( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4, - uint8_t byte) -{ - int32_t shift = 7; - bool ack; - - /* bits are transmitted serially, starting from MSB */ - - do { - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SDA, (byte >> shift) & 1); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - return false; - - write_bit_to_ddc(ddc_handle, SCL, false); - - --shift; - } while (shift >= 0); - - /* The display sends ACK by preventing the SDA from going high - * after the SCL pulse we use to send our last data bit. - * If the SDA goes high after that bit, it's a NACK */ - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SDA, true); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - return false; - - /* read ACK bit */ - - ack = !read_bit_from_ddc(ddc_handle, SDA); - - udelay(clock_delay_div_4 << 1); - - write_bit_to_ddc(ddc_handle, SCL, false); - - udelay(clock_delay_div_4 << 1); - - return ack; -} - -static bool read_byte( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4, - uint8_t *byte, - bool more) -{ - int32_t shift = 7; - - uint8_t data = 0; - - /* The data bits are read from MSB to LSB; - * bit is read while SCL is high */ - - do { - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - return false; - - if (read_bit_from_ddc(ddc_handle, SDA)) - data |= (1 << shift); - - write_bit_to_ddc(ddc_handle, SCL, false); - - udelay(clock_delay_div_4 << 1); - - --shift; - } while (shift >= 0); - - /* read only whole byte */ - - *byte = data; - - udelay(clock_delay_div_4); - - /* send the acknowledge bit: - * SDA low means ACK, SDA high means NACK */ - - write_bit_to_ddc(ddc_handle, SDA, !more); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SCL, true); - - if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4)) - return false; - - write_bit_to_ddc(ddc_handle, SCL, false); - - udelay(clock_delay_div_4); - - write_bit_to_ddc(ddc_handle, SDA, true); - - udelay(clock_delay_div_4); - - return true; -} - -static bool i2c_write( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4, - uint8_t address, - uint32_t length, - const uint8_t *data) -{ - uint32_t i = 0; - - if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address)) - return false; - - while (i < length) { - if (!write_byte(ctx, ddc_handle, clock_delay_div_4, data[i])) - return false; - ++i; - } - - return true; -} - -static bool i2c_read( - struct dc_context *ctx, - struct ddc *ddc_handle, - uint16_t clock_delay_div_4, - uint8_t address, - uint32_t length, - uint8_t *data) -{ - uint32_t i = 0; - - if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address)) - return false; - - while (i < length) { - if (!read_byte(ctx, ddc_handle, clock_delay_div_4, data + i, - i < length - 1)) - return false; - ++i; - } - - return true; -} - -/* - * @brief - * Cast 'struct i2c_engine *' - * to 'struct i2c_sw_engine *' - */ -#define FROM_I2C_ENGINE(ptr) \ - container_of((ptr), struct i2c_sw_engine, base) - -/* - * @brief - * Cast 'struct engine *' - * to 'struct i2c_sw_engine *' - */ -#define FROM_ENGINE(ptr) \ - FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base)) - -enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type( - const struct engine *engine) -{ - return I2CAUX_ENGINE_TYPE_I2C_SW; -} - -bool dal_i2c_sw_engine_submit_request( - struct engine *engine, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction) -{ - struct i2c_sw_engine *sw_engine = FROM_ENGINE(engine); - - struct i2c_engine *base = &sw_engine->base; - - struct i2c_request_transaction_data request; - bool operation_succeeded = false; - - if (i2caux_request->operation == I2CAUX_TRANSACTION_READ) - request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_READ; - else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE) - request.action = middle_of_transaction ? - I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT : - I2CAUX_TRANSACTION_ACTION_I2C_WRITE; - else { - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION; - /* in DAL2, there was no "return false" */ - return false; - } - - request.address = (uint8_t)i2caux_request->payload.address; - request.length = i2caux_request->payload.length; - request.data = i2caux_request->payload.data; - - base->funcs->submit_channel_request(base, &request); - - if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) || - (request.status == I2C_CHANNEL_OPERATION_FAILED)) - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY; - else { - enum i2c_channel_operation_result operation_result; - - do { - operation_result = - base->funcs->get_channel_status(base, NULL); - - switch (operation_result) { - case I2C_CHANNEL_OPERATION_SUCCEEDED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_SUCCEEDED; - operation_succeeded = true; - break; - case I2C_CHANNEL_OPERATION_NO_RESPONSE: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_NACK; - break; - case I2C_CHANNEL_OPERATION_TIMEOUT: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT; - break; - case I2C_CHANNEL_OPERATION_FAILED: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE; - break; - default: - i2caux_request->status = - I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION; - break; - } - } while (operation_result == I2C_CHANNEL_OPERATION_ENGINE_BUSY); - } - - return operation_succeeded; -} - -uint32_t dal_i2c_sw_engine_get_speed( - const struct i2c_engine *engine) -{ - return FROM_I2C_ENGINE(engine)->speed; -} - -void dal_i2c_sw_engine_set_speed( - struct i2c_engine *engine, - uint32_t speed) -{ - struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine); - - ASSERT(speed); - - sw_engine->speed = speed ? speed : I2CAUX_DEFAULT_I2C_SW_SPEED; - - sw_engine->clock_delay = 1000 / sw_engine->speed; - - if (sw_engine->clock_delay < 12) - sw_engine->clock_delay = 12; -} - -bool dal_i2caux_i2c_sw_engine_acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc) -{ - enum gpio_result result; - - result = dal_ddc_open(ddc, GPIO_MODE_FAST_OUTPUT, - GPIO_DDC_CONFIG_TYPE_MODE_I2C); - - if (result != GPIO_RESULT_OK) - return false; - - engine->base.ddc = ddc; - - return true; -} - -void dal_i2c_sw_engine_submit_channel_request( - struct i2c_engine *engine, - struct i2c_request_transaction_data *req) -{ - struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine); - - struct ddc *ddc = engine->base.ddc; - uint16_t clock_delay_div_4 = sw_engine->clock_delay >> 2; - - /* send sync (start / repeated start) */ - - bool result = start_sync(engine->base.ctx, ddc, clock_delay_div_4); - - /* process payload */ - - if (result) { - switch (req->action) { - case I2CAUX_TRANSACTION_ACTION_I2C_WRITE: - case I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT: - result = i2c_write(engine->base.ctx, ddc, clock_delay_div_4, - req->address, req->length, req->data); - break; - case I2CAUX_TRANSACTION_ACTION_I2C_READ: - case I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT: - result = i2c_read(engine->base.ctx, ddc, clock_delay_div_4, - req->address, req->length, req->data); - break; - default: - result = false; - break; - } - } - - /* send stop if not 'mot' or operation failed */ - - if (!result || - (req->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) || - (req->action == I2CAUX_TRANSACTION_ACTION_I2C_READ)) - if (!stop_sync(engine->base.ctx, ddc, clock_delay_div_4)) - result = false; - - req->status = result ? - I2C_CHANNEL_OPERATION_SUCCEEDED : - I2C_CHANNEL_OPERATION_FAILED; -} - -enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status( - struct i2c_engine *engine, - uint8_t *returned_bytes) -{ - /* No arbitration with VBIOS is performed since DCE 6.0 */ - return I2C_CHANNEL_OPERATION_SUCCEEDED; -} - -void dal_i2c_sw_engine_destruct( - struct i2c_sw_engine *engine) -{ - dal_i2c_engine_destruct(&engine->base); -} - -static void destroy( - struct i2c_engine **ptr) -{ - dal_i2c_sw_engine_destruct(FROM_I2C_ENGINE(*ptr)); - - kfree(*ptr); - *ptr = NULL; -} - -static const struct i2c_engine_funcs i2c_engine_funcs = { - .acquire_engine = dal_i2caux_i2c_sw_engine_acquire_engine, - .destroy = destroy, - .get_speed = dal_i2c_sw_engine_get_speed, - .set_speed = dal_i2c_sw_engine_set_speed, - .setup_engine = dal_i2c_engine_setup_i2c_engine, - .submit_channel_request = dal_i2c_sw_engine_submit_channel_request, - .process_channel_reply = dal_i2c_engine_process_channel_reply, - .get_channel_status = dal_i2c_sw_engine_get_channel_status, -}; - -static void release_engine( - struct engine *engine) -{ - -} - -static const struct engine_funcs engine_funcs = { - .release_engine = release_engine, - .get_engine_type = dal_i2c_sw_engine_get_engine_type, - .acquire = dal_i2c_engine_acquire, - .submit_request = dal_i2c_sw_engine_submit_request, -}; - -void dal_i2c_sw_engine_construct( - struct i2c_sw_engine *engine, - const struct i2c_sw_engine_create_arg *arg) -{ - dal_i2c_engine_construct(&engine->base, arg->ctx); - dal_i2c_sw_engine_set_speed(&engine->base, arg->default_speed); - engine->base.funcs = &i2c_engine_funcs; - engine->base.base.funcs = &engine_funcs; -} - -struct i2c_engine *dal_i2c_sw_engine_create( - const struct i2c_sw_engine_create_arg *arg) -{ - struct i2c_sw_engine *engine; - - if (!arg) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - engine = kzalloc(sizeof(struct i2c_sw_engine), GFP_KERNEL); - - if (!engine) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dal_i2c_sw_engine_construct(engine, arg); - return &engine->base; -} diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h deleted file mode 100644 index 546f15b0d3f1..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_SW_ENGINE_H__ -#define __DAL_I2C_SW_ENGINE_H__ - -enum { - I2C_SW_RETRIES = 10, - I2C_SW_SCL_READ_RETRIES = 128, - /* following value is in microseconds */ - I2C_SW_TIMEOUT_DELAY = 3000 -}; - -struct i2c_sw_engine; - -struct i2c_sw_engine { - struct i2c_engine base; - uint32_t clock_delay; - /* Values below are in KHz */ - uint32_t speed; - uint32_t default_speed; -}; - -struct i2c_sw_engine_create_arg { - uint32_t default_speed; - struct dc_context *ctx; -}; - -void dal_i2c_sw_engine_construct( - struct i2c_sw_engine *engine, - const struct i2c_sw_engine_create_arg *arg); - -bool dal_i2caux_i2c_sw_engine_acquire_engine( - struct i2c_engine *engine, - struct ddc *ddc_handle); - -void dal_i2c_sw_engine_destruct( - struct i2c_sw_engine *engine); - -struct i2c_engine *dal_i2c_sw_engine_create( - const struct i2c_sw_engine_create_arg *arg); -enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type( - const struct engine *engine); -bool dal_i2c_sw_engine_submit_request( - struct engine *ptr, - struct i2caux_transaction_request *i2caux_request, - bool middle_of_transaction); -uint32_t dal_i2c_sw_engine_get_speed( - const struct i2c_engine *engine); -void dal_i2c_sw_engine_set_speed( - struct i2c_engine *ptr, - uint32_t speed); -void dal_i2c_sw_engine_submit_channel_request( - struct i2c_engine *ptr, - struct i2c_request_transaction_data *req); -enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status( - struct i2c_engine *engine, - uint8_t *returned_bytes); -#endif diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c deleted file mode 100644 index 1ad6e49102ff..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#include "dm_services.h" - -/* - * Pre-requisites: headers required by header of this unit - */ -#include "include/i2caux_interface.h" -#include "dc_bios_types.h" - -/* - * Header of this unit - */ - -#include "i2caux.h" - -/* - * Post-requisites: headers required by this unit - */ - -#include "engine.h" -#include "i2c_engine.h" -#include "aux_engine.h" - -/* - * This unit - */ - -#include "dce80/i2caux_dce80.h" - -#include "dce100/i2caux_dce100.h" - -#include "dce110/i2caux_dce110.h" - -#include "dce112/i2caux_dce112.h" - -#include "dce120/i2caux_dce120.h" - -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) -#include "dcn10/i2caux_dcn10.h" -#endif - -#include "diagnostics/i2caux_diag.h" - -/* - * @brief - * Plain API, available publicly - */ - -struct i2caux *dal_i2caux_create( - struct dc_context *ctx) -{ - if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { - return dal_i2caux_diag_fpga_create(ctx); - } - - switch (ctx->dce_version) { - case DCE_VERSION_8_0: - case DCE_VERSION_8_1: - case DCE_VERSION_8_3: - return dal_i2caux_dce80_create(ctx); - case DCE_VERSION_11_2: - case DCE_VERSION_11_22: - return dal_i2caux_dce112_create(ctx); - case DCE_VERSION_11_0: - return dal_i2caux_dce110_create(ctx); - case DCE_VERSION_10_0: - return dal_i2caux_dce100_create(ctx); - case DCE_VERSION_12_0: - case DCE_VERSION_12_1: - return dal_i2caux_dce120_create(ctx); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - case DCN_VERSION_1_0: - return dal_i2caux_dcn10_create(ctx); -#endif - -#if defined(CONFIG_DRM_AMD_DC_DCN1_01) - case DCN_VERSION_1_01: - return dal_i2caux_dcn10_create(ctx); -#endif - default: - BREAK_TO_DEBUGGER(); - return NULL; - } -} - -bool dal_i2caux_submit_i2c_command( - struct i2caux *i2caux, - struct ddc *ddc, - struct i2c_command *cmd) -{ - struct i2c_engine *engine; - uint8_t index_of_payload = 0; - bool result; - - if (!ddc) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!cmd) { - BREAK_TO_DEBUGGER(); - return false; - } - - /* - * default will be SW, however there is a feature flag in adapter - * service that determines whether SW i2c_engine will be available or - * not, if sw i2c is not available we will fallback to hw. This feature - * flag is set to not creating sw i2c engine for every dce except dce80 - * currently - */ - switch (cmd->engine) { - case I2C_COMMAND_ENGINE_DEFAULT: - case I2C_COMMAND_ENGINE_SW: - /* try to acquire SW engine first, - * acquire HW engine if SW engine not available */ - engine = i2caux->funcs->acquire_i2c_sw_engine(i2caux, ddc); - - if (!engine) - engine = i2caux->funcs->acquire_i2c_hw_engine( - i2caux, ddc); - break; - case I2C_COMMAND_ENGINE_HW: - default: - /* try to acquire HW engine first, - * acquire SW engine if HW engine not available */ - engine = i2caux->funcs->acquire_i2c_hw_engine(i2caux, ddc); - - if (!engine) - engine = i2caux->funcs->acquire_i2c_sw_engine( - i2caux, ddc); - } - - if (!engine) - return false; - - engine->funcs->set_speed(engine, cmd->speed); - - result = true; - - while (index_of_payload < cmd->number_of_payloads) { - bool mot = (index_of_payload != cmd->number_of_payloads - 1); - - struct i2c_payload *payload = cmd->payloads + index_of_payload; - - struct i2caux_transaction_request request = { 0 }; - - request.operation = payload->write ? - I2CAUX_TRANSACTION_WRITE : - I2CAUX_TRANSACTION_READ; - - request.payload.address_space = - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C; - request.payload.address = (payload->address << 1) | - !payload->write; - request.payload.length = payload->length; - request.payload.data = payload->data; - - if (!engine->base.funcs->submit_request( - &engine->base, &request, mot)) { - result = false; - break; - } - - ++index_of_payload; - } - - i2caux->funcs->release_engine(i2caux, &engine->base); - - return result; -} - -bool dal_i2caux_submit_aux_command( - struct i2caux *i2caux, - struct ddc *ddc, - struct aux_command *cmd) -{ - struct aux_engine *engine; - uint8_t index_of_payload = 0; - bool result; - bool mot; - - if (!ddc) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!cmd) { - BREAK_TO_DEBUGGER(); - return false; - } - - engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc); - - if (!engine) - return false; - - engine->delay = cmd->defer_delay; - engine->max_defer_write_retry = cmd->max_defer_write_retry; - - result = true; - - while (index_of_payload < cmd->number_of_payloads) { - struct aux_payload *payload = cmd->payloads + index_of_payload; - struct i2caux_transaction_request request = { 0 }; - - if (cmd->mot == I2C_MOT_UNDEF) - mot = (index_of_payload != cmd->number_of_payloads - 1); - else - mot = (cmd->mot == I2C_MOT_TRUE); - - request.operation = payload->write ? - I2CAUX_TRANSACTION_WRITE : - I2CAUX_TRANSACTION_READ; - - if (payload->i2c_over_aux) { - request.payload.address_space = - I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C; - - request.payload.address = (payload->address << 1) | - !payload->write; - } else { - request.payload.address_space = - I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD; - - request.payload.address = payload->address; - } - - request.payload.length = payload->length; - request.payload.data = payload->data; - - if (!engine->base.funcs->submit_request( - &engine->base, &request, mot)) { - result = false; - break; - } - - ++index_of_payload; - } - - i2caux->funcs->release_engine(i2caux, &engine->base); - - return result; -} - -static bool get_hw_supported_ddc_line( - struct ddc *ddc, - enum gpio_ddc_line *line) -{ - enum gpio_ddc_line line_found; - - *line = GPIO_DDC_LINE_UNKNOWN; - - if (!ddc) { - BREAK_TO_DEBUGGER(); - return false; - } - - if (!ddc->hw_info.hw_supported) - return false; - - line_found = dal_ddc_get_line(ddc); - - if (line_found >= GPIO_DDC_LINE_COUNT) - return false; - - *line = line_found; - - return true; -} - -void dal_i2caux_configure_aux( - struct i2caux *i2caux, - struct ddc *ddc, - union aux_config cfg) -{ - struct aux_engine *engine = - i2caux->funcs->acquire_aux_engine(i2caux, ddc); - - if (!engine) - return; - - engine->funcs->configure(engine, cfg); - - i2caux->funcs->release_engine(i2caux, &engine->base); -} - -void dal_i2caux_destroy( - struct i2caux **i2caux) -{ - if (!i2caux || !*i2caux) { - BREAK_TO_DEBUGGER(); - return; - } - - (*i2caux)->funcs->destroy(i2caux); - - *i2caux = NULL; -} - -/* - * @brief - * An utility function used by 'struct i2caux' and its descendants - */ - -uint32_t dal_i2caux_get_reference_clock( - struct dc_bios *bios) -{ - struct dc_firmware_info info = { { 0 } }; - - if (bios->funcs->get_firmware_info(bios, &info) != BP_RESULT_OK) - return 0; - - return info.pll_info.crystal_frequency; -} - -/* - * @brief - * i2caux - */ - -enum { - /* following are expressed in KHz */ - DEFAULT_I2C_SW_SPEED = 50, - DEFAULT_I2C_HW_SPEED = 50, - - DEFAULT_I2C_SW_SPEED_100KHZ = 100, - DEFAULT_I2C_HW_SPEED_100KHZ = 100, - - /* This is the timeout as defined in DP 1.2a, - * 2.3.4 "Detailed uPacket TX AUX CH State Description". */ - AUX_TIMEOUT_PERIOD = 400, - - /* Ideally, the SW timeout should be just above 550usec - * which is programmed in HW. - * But the SW timeout of 600usec is not reliable, - * because on some systems, delay_in_microseconds() - * returns faster than it should. - * EPR #379763: by trial-and-error on different systems, - * 700usec is the minimum reliable SW timeout for polling - * the AUX_SW_STATUS.AUX_SW_DONE bit. - * This timeout expires *only* when there is - * AUX Error or AUX Timeout conditions - not during normal operation. - * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set - * at most within ~240usec. That means, - * increasing this timeout will not affect normal operation, - * and we'll timeout after - * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec. - * This timeout is especially important for - * resume from S3 and CTS. */ - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4 -}; - -struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine( - struct i2caux *i2caux, - struct ddc *ddc) -{ - enum gpio_ddc_line line; - struct i2c_engine *engine = NULL; - - if (get_hw_supported_ddc_line(ddc, &line)) - engine = i2caux->i2c_sw_engines[line]; - - if (!engine) - engine = i2caux->i2c_generic_sw_engine; - - if (!engine) - return NULL; - - if (!engine->base.funcs->acquire(&engine->base, ddc)) - return NULL; - - return engine; -} - -struct aux_engine *dal_i2caux_acquire_aux_engine( - struct i2caux *i2caux, - struct ddc *ddc) -{ - enum gpio_ddc_line line; - struct aux_engine *engine; - - if (!get_hw_supported_ddc_line(ddc, &line)) - return NULL; - - engine = i2caux->aux_engines[line]; - - if (!engine) - return NULL; - - if (!engine->base.funcs->acquire(&engine->base, ddc)) - return NULL; - - return engine; -} - -void dal_i2caux_release_engine( - struct i2caux *i2caux, - struct engine *engine) -{ - engine->funcs->release_engine(engine); - - dal_ddc_close(engine->ddc); - - engine->ddc = NULL; -} - -void dal_i2caux_construct( - struct i2caux *i2caux, - struct dc_context *ctx) -{ - uint32_t i = 0; - - i2caux->ctx = ctx; - do { - i2caux->i2c_sw_engines[i] = NULL; - i2caux->i2c_hw_engines[i] = NULL; - i2caux->aux_engines[i] = NULL; - - ++i; - } while (i < GPIO_DDC_LINE_COUNT); - - i2caux->i2c_generic_sw_engine = NULL; - i2caux->i2c_generic_hw_engine = NULL; - - i2caux->aux_timeout_period = - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD; - - if (ctx->dce_version >= DCE_VERSION_11_2) { - i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED_100KHZ; - i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED_100KHZ; - } else { - i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED; - i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED; - } -} - -void dal_i2caux_destruct( - struct i2caux *i2caux) -{ - uint32_t i = 0; - - if (i2caux->i2c_generic_hw_engine) - i2caux->i2c_generic_hw_engine->funcs->destroy( - &i2caux->i2c_generic_hw_engine); - - if (i2caux->i2c_generic_sw_engine) - i2caux->i2c_generic_sw_engine->funcs->destroy( - &i2caux->i2c_generic_sw_engine); - - do { - if (i2caux->aux_engines[i]) - i2caux->aux_engines[i]->funcs->destroy( - &i2caux->aux_engines[i]); - - if (i2caux->i2c_hw_engines[i]) - i2caux->i2c_hw_engines[i]->funcs->destroy( - &i2caux->i2c_hw_engines[i]); - - if (i2caux->i2c_sw_engines[i]) - i2caux->i2c_sw_engines[i]->funcs->destroy( - &i2caux->i2c_sw_engines[i]); - - ++i; - } while (i < GPIO_DDC_LINE_COUNT); -} - diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h deleted file mode 100644 index 64f51bb06915..000000000000 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2012-15 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: AMD - * - */ - -#ifndef __DAL_I2C_AUX_H__ -#define __DAL_I2C_AUX_H__ - -uint32_t dal_i2caux_get_reference_clock( - struct dc_bios *bios); - -struct i2caux; - -struct engine; - -struct i2caux_funcs { - void (*destroy)(struct i2caux **ptr); - struct i2c_engine * (*acquire_i2c_sw_engine)( - struct i2caux *i2caux, - struct ddc *ddc); - struct i2c_engine * (*acquire_i2c_hw_engine)( - struct i2caux *i2caux, - struct ddc *ddc); - struct aux_engine * (*acquire_aux_engine)( - struct i2caux *i2caux, - struct ddc *ddc); - void (*release_engine)( - struct i2caux *i2caux, - struct engine *engine); -}; - -struct i2c_engine; -struct aux_engine; - -struct i2caux { - struct dc_context *ctx; - const struct i2caux_funcs *funcs; - /* On ASIC we have certain amount of lines with HW DDC engine - * (4, 6, or maybe more in the future). - * For every such line, we create separate HW DDC engine - * (since we have these engines in HW) and separate SW DDC engine - * (to allow concurrent use of few lines). - * In similar way we have AUX engines. */ - - /* I2C SW engines, per DDC line. - * Only lines with HW DDC support will be initialized */ - struct i2c_engine *i2c_sw_engines[GPIO_DDC_LINE_COUNT]; - - /* I2C HW engines, per DDC line. - * Only lines with HW DDC support will be initialized */ - struct i2c_engine *i2c_hw_engines[GPIO_DDC_LINE_COUNT]; - - /* AUX engines, per DDC line. - * Only lines with HW AUX support will be initialized */ - struct aux_engine *aux_engines[GPIO_DDC_LINE_COUNT]; - - /* For all other lines, we can use - * single instance of generic I2C HW engine - * (since in HW, there is single instance of it) - * or single instance of generic I2C SW engine. - * AUX is not supported for other lines. */ - - /* General-purpose I2C SW engine. - * Can be assigned dynamically to any line per transaction */ - struct i2c_engine *i2c_generic_sw_engine; - - /* General-purpose I2C generic HW engine. - * Can be assigned dynamically to almost any line per transaction */ - struct i2c_engine *i2c_generic_hw_engine; - - /* [anaumov] in DAL2, there is a Mutex */ - - uint32_t aux_timeout_period; - - /* expressed in KHz */ - uint32_t default_i2c_sw_speed; - uint32_t default_i2c_hw_speed; -}; - -void dal_i2caux_construct( - struct i2caux *i2caux, - struct dc_context *ctx); - -void dal_i2caux_release_engine( - struct i2caux *i2caux, - struct engine *engine); - -void dal_i2caux_destruct( - struct i2caux *i2caux); - -void dal_i2caux_destroy( - struct i2caux **ptr); - -struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine( - struct i2caux *i2caux, - struct ddc *ddc); - -struct aux_engine *dal_i2caux_acquire_aux_engine( - struct i2caux *i2caux, - struct ddc *ddc); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h index 47ef90495376..fe6301cb8681 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h @@ -78,7 +78,7 @@ struct csdp_ref_clk_ds_params { }; struct pixel_clk_params { - uint32_t requested_pix_clk; /* in KHz */ + uint32_t requested_pix_clk_100hz; /*> Requested Pixel Clock * (based on Video Timing standard used for requested mode)*/ uint32_t requested_sym_clk; /* in KHz */ @@ -104,9 +104,9 @@ struct pixel_clk_params { * with actually calculated Clock and reference Crystal frequency */ struct pll_settings { - uint32_t actual_pix_clk; - uint32_t adjusted_pix_clk; - uint32_t calculated_pix_clk; + uint32_t actual_pix_clk_100hz; + uint32_t adjusted_pix_clk_100hz; + uint32_t calculated_pix_clk_100hz; uint32_t vco_freq; uint32_t reference_freq; uint32_t reference_divider; @@ -166,6 +166,10 @@ struct clock_source_funcs { struct clock_source *, struct pixel_clk_params *, struct pll_settings *); + bool (*get_pixel_clk_frequency_100hz)( + struct clock_source *clock_source, + unsigned int inst, + unsigned int *pixel_clk_khz); }; struct clock_source { diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_status.h b/drivers/gpu/drm/amd/display/dc/inc/core_status.h index 94fc31080fda..2e61a22ef4b2 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -30,7 +30,7 @@ enum dc_status { DC_OK = 1, DC_NO_CONTROLLER_RESOURCE = 2, - DC_NO_STREAM_ENG_RESOURCE = 3, + DC_NO_STREAM_ENC_RESOURCE = 3, DC_NO_CLOCK_SOURCE_RESOURCE = 4, DC_FAIL_CONTROLLER_VALIDATE = 5, DC_FAIL_ENC_VALIDATE = 6, diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index b168a5e9dd9d..986ed1728644 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -146,7 +146,7 @@ struct resource_pool { struct mpc *mpc; struct pp_smu_funcs_rv *pp_smu; struct pp_smu_display_requirement_rv pp_smu_req; - struct aux_engine *engines[MAX_PIPES]; + struct dce_aux *engines[MAX_PIPES]; struct dce_i2c_hw *hw_i2cs[MAX_PIPES]; struct dce_i2c_sw *sw_i2cs[MAX_PIPES]; bool i2c_hw_buffer_in_use; @@ -180,13 +180,8 @@ struct resource_pool { const struct resource_caps *res_cap; }; -struct dcn_fe_clocks { - int dppclk_khz; -}; - struct dcn_fe_bandwidth { - struct dcn_fe_clocks calc; - struct dcn_fe_clocks cur; + int dppclk_khz; }; struct stream_resource { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h index 538b83303b86..16fd4dc6c4dd 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h @@ -64,13 +64,6 @@ void dal_ddc_i2c_payloads_add( uint8_t *data, bool write); -void dal_ddc_aux_payloads_add( - struct aux_payloads *payloads, - uint32_t address, - uint32_t len, - uint8_t *data, - bool write); - struct ddc_service_init_data { struct graphics_object_id id; struct dc_context *ctx; @@ -103,12 +96,10 @@ bool dal_ddc_service_query_ddc_data( uint32_t read_size); int dc_link_aux_transfer(struct ddc_service *ddc, - unsigned int address, - uint8_t *reply, - void *buffer, - unsigned int size, - enum aux_transaction_type type, - enum i2caux_transaction_action action); + struct aux_payload *payload); + +bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, + struct aux_payload *payload); void dal_ddc_service_write_scdc_data( struct ddc_service *ddc_service, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h index 02f757dd70d4..9d2d8e51306c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -39,6 +39,18 @@ enum segment_order { segment_order__non_contiguous, }; +struct dcn_hubbub_wm_set { + uint32_t wm_set; + uint32_t data_urgent; + uint32_t pte_meta_urgent; + uint32_t sr_enter; + uint32_t sr_exit; + uint32_t dram_clk_chanage; +}; + +struct dcn_hubbub_wm { + struct dcn_hubbub_wm_set sets[4]; +}; struct hubbub_funcs { void (*update_dchub)( @@ -58,7 +70,14 @@ struct hubbub_funcs { bool (*dcc_support_pixel_format)( enum surface_pixel_format format, unsigned int *bytes_per_element); + + void (*wm_read_state)(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm); }; +struct hubbub { + const struct hubbub_funcs *funcs; + struct dc_context *ctx; +}; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h index cb85eaa9857f..cbaa43853611 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h @@ -27,16 +27,22 @@ #include "dm_services_types.h" +/* If HW itself ever powered down it will be 0. + * fwDmcuInit will write to 1. + * Driver will only call MCP init if current state is 1, + * and the MCP command will transition this to 2. + */ enum dmcu_state { - DMCU_NOT_INITIALIZED = 0, - DMCU_RUNNING = 1 + DMCU_UNLOADED = 0, + DMCU_LOADED_UNINITIALIZED = 1, + DMCU_RUNNING = 2, }; struct dmcu_version { - unsigned int date; - unsigned int month; - unsigned int year; unsigned int interface_version; + unsigned int abm_version; + unsigned int psr_version; + unsigned int build_version; }; struct dmcu { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h index e894e649ce5a..fb7967b39edb 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -39,6 +39,11 @@ struct dpp { }; +struct dpp_input_csc_matrix { + enum dc_color_space color_space; + uint16_t regval[12]; +}; + struct dpp_grph_csc_adjustment { struct fixed31_32 temperature_matrix[CSC_TEMPERATURE_MATRIX_SIZE]; enum graphics_gamut_adjust_type gamut_adjust_type; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 04c6989aac58..1cd07e94ee63 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -78,7 +78,8 @@ struct hubp_funcs { bool (*hubp_program_surface_flip_and_addr)( struct hubp *hubp, const struct dc_plane_address *address, - bool flip_immediate); + bool flip_immediate, + uint8_t vmid); void (*hubp_program_pte_vm)( struct hubp *hubp, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index c20fdcaac53b..c9d3e37e9531 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -153,6 +153,7 @@ struct link_encoder_funcs { void (*enable_hpd)(struct link_encoder *enc); void (*disable_hpd)(struct link_encoder *enc); bool (*is_dig_enabled)(struct link_encoder *enc); + unsigned int (*get_dig_frontend)(struct link_encoder *enc); void (*destroy)(struct link_encoder **enc); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h index 06df02ddff6a..da89c2edb07c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h @@ -31,7 +31,7 @@ #include "dml/display_mode_structs.h" struct dchub_init_data; -struct cstate_pstate_watermarks_st1 { +struct cstate_pstate_watermarks_st { uint32_t cstate_exit_ns; uint32_t cstate_enter_plus_exit_ns; uint32_t pstate_change_ns; @@ -40,7 +40,7 @@ struct cstate_pstate_watermarks_st1 { struct dcn_watermarks { uint32_t pte_meta_urgent_ns; uint32_t urgent_ns; - struct cstate_pstate_watermarks_st1 cstate_pstate; + struct cstate_pstate_watermarks_st cstate_pstate; }; struct dcn_watermark_set { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h index 53a9b64df11a..4051493557bc 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h @@ -161,6 +161,10 @@ struct stream_encoder_funcs { void (*set_avmute)( struct stream_encoder *enc, bool enable); + void (*dig_connect_to_otg)( + struct stream_encoder *enc, + int tg_inst); + }; #endif /* STREAM_ENCODER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h index af700c7dac50..03ae941895f3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h @@ -134,15 +134,29 @@ struct dc_crtc_timing; struct drr_params; +union vline_config; + + +enum vline_select { + VLINE0, + VLINE1, + VLINE2 +}; + struct timing_generator_funcs { bool (*validate_timing)(struct timing_generator *tg, const struct dc_crtc_timing *timing); void (*program_timing)(struct timing_generator *tg, const struct dc_crtc_timing *timing, bool use_vbios); - void (*program_vline_interrupt)(struct timing_generator *optc, + void (*program_vline_interrupt)( + struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing, - unsigned long long vsync_delta); + enum vline_select vline, + const union vline_config *vline_config); + + void (*program_vupdate_interrupt)(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); bool (*enable_crtc)(struct timing_generator *tg); bool (*disable_crtc)(struct timing_generator *tg); bool (*is_counter_moving)(struct timing_generator *tg); @@ -159,6 +173,8 @@ struct timing_generator_funcs { bool (*get_otg_active_size)(struct timing_generator *optc, uint32_t *otg_active_width, uint32_t *otg_active_height); + bool (*is_matching_timing)(struct timing_generator *tg, + const struct dc_crtc_timing *otg_timing); void (*set_early_control)(struct timing_generator *tg, uint32_t early_cntl); void (*wait_for_state)(struct timing_generator *tg, diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h index c48c61f540a8..037beb0a2a27 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-15 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,21 +23,27 @@ * */ -#ifndef __DAL_I2C_SW_ENGINE_DCE110_H__ -#define __DAL_I2C_SW_ENGINE_DCE110_H__ +#ifndef DAL_DC_INC_HW_VMID_H_ +#define DAL_DC_INC_HW_VMID_H_ -struct i2c_sw_engine_dce110 { - struct i2c_sw_engine base; - uint32_t engine_id; -}; +#include "core_types.h" +#include "dchubbub.h" -struct i2c_sw_engine_dce110_create_arg { - uint32_t engine_id; - uint32_t default_speed; - struct dc_context *ctx; +struct dcn_vmid_registers { + uint32_t CNTL; + uint32_t PAGE_TABLE_BASE_ADDR_HI32; + uint32_t PAGE_TABLE_BASE_ADDR_LO32; + uint32_t PAGE_TABLE_START_ADDR_HI32; + uint32_t PAGE_TABLE_START_ADDR_LO32; + uint32_t PAGE_TABLE_END_ADDR_HI32; + uint32_t PAGE_TABLE_END_ADDR_LO32; }; -struct i2c_engine *dal_i2c_sw_engine_dce110_create( - const struct i2c_sw_engine_dce110_create_arg *arg); +struct dcn_vmid_page_table_config { + uint64_t page_table_start_addr; + uint64_t page_table_end_addr; + enum dcn_hubbub_page_table_depth depth; + enum dcn_hubbub_page_table_block_size block_size; +}; -#endif +#endif /* DAL_DC_INC_HW_VMID_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index d6a85f48b6d1..341b4810288c 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -70,6 +70,8 @@ struct hw_sequencer_funcs { void (*init_hw)(struct dc *dc); + void (*init_pipes)(struct dc *dc, struct dc_state *context); + enum dc_status (*apply_ctx_to_hw)( struct dc *dc, struct dc_state *context); diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h index 26355c088746..193407f76a80 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h +++ b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h @@ -1,5 +1,5 @@ /* - * Copyright 2012-15 Advanced Micro Devices, Inc. + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,21 +23,34 @@ * */ -#ifndef __DAL_I2C_SW_ENGINE_DCE80_H__ -#define __DAL_I2C_SW_ENGINE_DCE80_H__ +#ifndef DC_INC_VM_HELPER_H_ +#define DC_INC_VM_HELPER_H_ -struct i2c_sw_engine_dce80 { - struct i2c_sw_engine base; - uint32_t engine_id; +#include "dc_types.h" + +#define MAX_VMID 16 +#define MAX_HUBP 6 + +struct vmid_usage { + uint16_t vmid_usage[2]; }; -struct i2c_sw_engine_dce80_create_arg { - uint32_t engine_id; - uint32_t default_speed; - struct dc_context *ctx; +struct vm_helper { + unsigned int num_vmid; + unsigned int num_hubp; + unsigned int num_vmids_available; + uint64_t ptb_assigned_to_vmid[MAX_VMID]; + struct vmid_usage hubp_vmid_usage[MAX_HUBP]; }; -struct i2c_engine *dal_i2c_sw_engine_dce80_create( - const struct i2c_sw_engine_dce80_create_arg *arg); +uint8_t get_vmid_for_ptb( + struct vm_helper *vm_helper, + int64_t ptb, + uint8_t pipe_idx); + +void init_vm_helper( + struct vm_helper *vm_helper, + unsigned int num_vmid, + unsigned int num_hubp); -#endif +#endif /* DC_INC_VM_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/irq_types.h b/drivers/gpu/drm/amd/display/dc/irq_types.h index 0b5f3a278c22..d0ccd81ad5b4 100644 --- a/drivers/gpu/drm/amd/display/dc/irq_types.h +++ b/drivers/gpu/drm/amd/display/dc/irq_types.h @@ -144,6 +144,14 @@ enum dc_irq_source { DC_IRQ_SOURCE_DC5_VLINE0, DC_IRQ_SOURCE_DC6_VLINE0, + DC_IRQ_SOURCE_DC1_VLINE1, + DC_IRQ_SOURCE_DC2_VLINE1, + DC_IRQ_SOURCE_DC3_VLINE1, + DC_IRQ_SOURCE_DC4_VLINE1, + DC_IRQ_SOURCE_DC5_VLINE1, + DC_IRQ_SOURCE_DC6_VLINE1, + + DAL_IRQ_SOURCES_NUMBER }; diff --git a/drivers/gpu/drm/amd/display/include/bios_parser_types.h b/drivers/gpu/drm/amd/display/include/bios_parser_types.h index 7fd78a696800..01bf01a34a08 100644 --- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h +++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h @@ -211,8 +211,8 @@ struct bp_pixel_clock_parameters { /* signal_type -> Encoder Mode - needed by VBIOS Exec table */ enum signal_type signal_type; /* Adjusted Pixel Clock (after VBIOS exec table) - * that becomes Target Pixel Clock (KHz) */ - uint32_t target_pixel_clock; + * that becomes Target Pixel Clock (100 Hz units) */ + uint32_t target_pixel_clock_100hz; /* Calculated Reference divider of Display PLL */ uint32_t reference_divider; /* Calculated Feedback divider of Display PLL */ diff --git a/drivers/gpu/drm/amd/display/include/gpio_interface.h b/drivers/gpu/drm/amd/display/include/gpio_interface.h index e4fd31024b92..7de64195dc33 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_interface.h @@ -59,6 +59,14 @@ enum gpio_result dal_gpio_change_mode( struct gpio *gpio, enum gpio_mode mode); +/* Lock Pin */ +enum gpio_result dal_gpio_lock_pin( + struct gpio *gpio); + +/* Unlock Pin */ +enum gpio_result dal_gpio_unlock_pin( + struct gpio *gpio); + /* Get the GPIO id */ enum gpio_id dal_gpio_get_id( const struct gpio *gpio); diff --git a/drivers/gpu/drm/amd/display/include/i2caux_interface.h b/drivers/gpu/drm/amd/display/include/i2caux_interface.h index 13a3c82d118f..bb012cb1a9f5 100644 --- a/drivers/gpu/drm/amd/display/include/i2caux_interface.h +++ b/drivers/gpu/drm/amd/display/include/i2caux_interface.h @@ -40,9 +40,19 @@ struct aux_payload { /* set following flag to write data, * reset it to read data */ bool write; + bool mot; uint32_t address; uint8_t length; uint8_t *data; + /* + * used to return the reply type of the transaction + * ignored if NULL + */ + uint8_t *reply; + /* expressed in milliseconds + * zero means "use default value" + */ + uint32_t defer_delay; }; struct aux_command { @@ -66,27 +76,4 @@ union aux_config { uint32_t raw; }; -struct i2caux; - -struct i2caux *dal_i2caux_create( - struct dc_context *ctx); - -bool dal_i2caux_submit_i2c_command( - struct i2caux *i2caux, - struct ddc *ddc, - struct i2c_command *cmd); - -bool dal_i2caux_submit_aux_command( - struct i2caux *i2caux, - struct ddc *ddc, - struct aux_command *cmd); - -void dal_i2caux_configure_aux( - struct i2caux *i2caux, - struct ddc *ddc, - union aux_config cfg); - -void dal_i2caux_destroy( - struct i2caux **ptr); - #endif diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c index 479b77c2e89e..0fbc8fbc3541 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -823,7 +823,7 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, bool is_clipped = false; struct fixed31_32 sdr_white_level; - if (fs_params == NULL || fs_params->max_content == 0 || + if (fs_params->max_content == 0 || fs_params->max_display == 0) return false; @@ -1508,7 +1508,7 @@ static bool map_regamma_hw_to_x_user( struct hw_x_point *coords = coords_x; const struct pwl_float_data_ex *regamma = rgb_regamma; - if (mapUserRamp) { + if (ramp && mapUserRamp) { copy_rgb_regamma_to_coordinates_x(coords, hw_points_num, rgb_regamma); @@ -1545,7 +1545,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, struct pwl_float_data *rgb_user = NULL; struct pwl_float_data_ex *rgb_regamma = NULL; - struct gamma_pixel *axix_x = NULL; + struct gamma_pixel *axis_x = NULL; struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; bool ret = false; @@ -1555,47 +1555,54 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, /* we can use hardcoded curve for plain SRGB TF */ if (output_tf->type == TF_TYPE_PREDEFINED && canRomBeUsed == true && - output_tf->tf == TRANSFER_FUNCTION_SRGB && - (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256))) - return true; + output_tf->tf == TRANSFER_FUNCTION_SRGB) { + if (ramp == NULL) + return true; + if (ramp->is_identity || (!mapUserRamp && ramp->type == GAMMA_RGB_256)) + return true; + } output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, + if (ramp && (mapUserRamp || ramp->type != GAMMA_RGB_256)) { + rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*rgb_user), GFP_KERNEL); - if (!rgb_user) - goto rgb_user_alloc_fail; + if (!rgb_user) + goto rgb_user_alloc_fail; + + axis_x = kvcalloc(ramp->num_entries + 3, sizeof(*axis_x), + GFP_KERNEL); + if (!axis_x) + goto axis_x_alloc_fail; + + dividers.divider1 = dc_fixpt_from_fraction(3, 2); + dividers.divider2 = dc_fixpt_from_int(2); + dividers.divider3 = dc_fixpt_from_fraction(5, 2); + + build_evenly_distributed_points( + axis_x, + ramp->num_entries, + dividers); + + if (ramp->type == GAMMA_RGB_256 && mapUserRamp) + scale_gamma(rgb_user, ramp, dividers); + else if (ramp->type == GAMMA_RGB_FLOAT_1024) + scale_gamma_dx(rgb_user, ramp, dividers); + } + rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; - axix_x = kvcalloc(ramp->num_entries + 3, sizeof(*axix_x), - GFP_KERNEL); - if (!axix_x) - goto axix_x_alloc_fail; + coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff), GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; - dividers.divider1 = dc_fixpt_from_fraction(3, 2); - dividers.divider2 = dc_fixpt_from_int(2); - dividers.divider3 = dc_fixpt_from_fraction(5, 2); - tf = output_tf->tf; - - build_evenly_distributed_points( - axix_x, - ramp->num_entries, - dividers); - - if (ramp->type == GAMMA_RGB_256 && mapUserRamp) - scale_gamma(rgb_user, ramp, dividers); - else if (ramp->type == GAMMA_RGB_FLOAT_1024) - scale_gamma_dx(rgb_user, ramp, dividers); - if (tf == TRANSFER_FUNCTION_PQ) { tf_pts->end_exponent = 7; tf_pts->x_point_at_y1_red = 125; @@ -1623,22 +1630,22 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? true:false); } map_regamma_hw_to_x_user(ramp, coeff, rgb_user, - coordinates_x, axix_x, rgb_regamma, + coordinates_x, axis_x, rgb_regamma, MAX_HW_POINTS, tf_pts, - (mapUserRamp || ramp->type != GAMMA_RGB_256) && - ramp->type != GAMMA_CS_TFM_1D); + (mapUserRamp || (ramp && ramp->type != GAMMA_RGB_256)) && + (ramp && ramp->type != GAMMA_CS_TFM_1D)); - if (ramp->type == GAMMA_CS_TFM_1D) + if (ramp && ramp->type == GAMMA_CS_TFM_1D) apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); ret = true; kvfree(coeff); coeff_alloc_fail: - kvfree(axix_x); -axix_x_alloc_fail: kvfree(rgb_regamma); rgb_regamma_alloc_fail: + kvfree(axis_x); +axis_x_alloc_fail: kvfree(rgb_user); rgb_user_alloc_fail: return ret; @@ -1758,69 +1765,85 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, { struct dc_transfer_func_distributed_points *tf_pts = &input_tf->tf_pts; struct dividers dividers; - struct pwl_float_data *rgb_user = NULL; struct pwl_float_data_ex *curve = NULL; struct gamma_pixel *axis_x = NULL; struct pixel_gamma_point *coeff = NULL; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; + uint32_t i; bool ret = false; if (input_tf->type == TF_TYPE_BYPASS) return false; - /* we can use hardcoded curve for plain SRGB TF */ + /* we can use hardcoded curve for plain SRGB TF + * If linear, it's bypass if on user ramp + */ if (input_tf->type == TF_TYPE_PREDEFINED && - input_tf->tf == TRANSFER_FUNCTION_SRGB && - (!mapUserRamp && - (ramp->type == GAMMA_RGB_256 || ramp->num_entries == 0))) + (input_tf->tf == TRANSFER_FUNCTION_SRGB || + input_tf->tf == TRANSFER_FUNCTION_LINEAR) && + !mapUserRamp) return true; input_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, - sizeof(*rgb_user), - GFP_KERNEL); - if (!rgb_user) - goto rgb_user_alloc_fail; + if (mapUserRamp && ramp && ramp->type == GAMMA_RGB_256) { + rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, + sizeof(*rgb_user), + GFP_KERNEL); + if (!rgb_user) + goto rgb_user_alloc_fail; + + axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x), + GFP_KERNEL); + if (!axis_x) + goto axis_x_alloc_fail; + + dividers.divider1 = dc_fixpt_from_fraction(3, 2); + dividers.divider2 = dc_fixpt_from_int(2); + dividers.divider3 = dc_fixpt_from_fraction(5, 2); + + build_evenly_distributed_points( + axis_x, + ramp->num_entries, + dividers); + + scale_gamma(rgb_user, ramp, dividers); + } + curve = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*curve), - GFP_KERNEL); + GFP_KERNEL); if (!curve) goto curve_alloc_fail; - axis_x = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*axis_x), - GFP_KERNEL); - if (!axis_x) - goto axis_x_alloc_fail; + coeff = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*coeff), - GFP_KERNEL); + GFP_KERNEL); if (!coeff) goto coeff_alloc_fail; - dividers.divider1 = dc_fixpt_from_fraction(3, 2); - dividers.divider2 = dc_fixpt_from_int(2); - dividers.divider3 = dc_fixpt_from_fraction(5, 2); - tf = input_tf->tf; - build_evenly_distributed_points( - axis_x, - ramp->num_entries, - dividers); - - if (ramp->type == GAMMA_RGB_256 && mapUserRamp) - scale_gamma(rgb_user, ramp, dividers); - else if (ramp->type == GAMMA_RGB_FLOAT_1024) - scale_gamma_dx(rgb_user, ramp, dividers); - if (tf == TRANSFER_FUNCTION_PQ) build_de_pq(curve, MAX_HW_POINTS, coordinates_x); - else + else if (tf == TRANSFER_FUNCTION_SRGB || + tf == TRANSFER_FUNCTION_BT709) build_degamma(curve, MAX_HW_POINTS, coordinates_x, - tf == TRANSFER_FUNCTION_SRGB ? true:false); + tf == TRANSFER_FUNCTION_SRGB ? true : false); + else if (tf == TRANSFER_FUNCTION_LINEAR) { + // just copy coordinates_x into curve + i = 0; + while (i != MAX_HW_POINTS + 1) { + curve[i].r = coordinates_x[i].x; + curve[i].g = curve[i].r; + curve[i].b = curve[i].r; + i++; + } + } else + goto invalid_tf_fail; tf_pts->end_exponent = 0; tf_pts->x_point_at_y1_red = 1; @@ -1830,23 +1853,21 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, curve, MAX_HW_POINTS, tf_pts, - mapUserRamp && ramp->type != GAMMA_CUSTOM); - if (ramp->type == GAMMA_CUSTOM) - apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts); + mapUserRamp && ramp && ramp->type == GAMMA_RGB_256); ret = true; +invalid_tf_fail: kvfree(coeff); coeff_alloc_fail: - kvfree(axis_x); -axis_x_alloc_fail: kvfree(curve); curve_alloc_fail: + kvfree(axis_x); +axis_x_alloc_fail: kvfree(rgb_user); rgb_user_alloc_fail: return ret; - } diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 1544ed3f1747..94a84bc57c7a 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -108,8 +108,8 @@ static unsigned int calc_duration_in_us_from_v_total( { unsigned int duration_in_us = (unsigned int)(div64_u64(((unsigned long long)(v_total) - * 1000) * stream->timing.h_total, - stream->timing.pix_clk_khz)); + * 10000) * stream->timing.h_total, + stream->timing.pix_clk_100hz)); return duration_in_us; } @@ -126,7 +126,7 @@ static unsigned int calc_v_total_from_refresh( refresh_in_uhz))); v_total = div64_u64(div64_u64(((unsigned long long)( - frame_duration_in_ns) * stream->timing.pix_clk_khz), + frame_duration_in_ns) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000000); /* v_total cannot be less than nominal */ @@ -152,7 +152,7 @@ static unsigned int calc_v_total_from_duration( duration_in_us = vrr->max_duration_in_us; v_total = div64_u64(div64_u64(((unsigned long long)( - duration_in_us) * stream->timing.pix_clk_khz), + duration_in_us) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000); /* v_total cannot be less than nominal */ @@ -227,7 +227,7 @@ static void update_v_total_for_static_ramp( } v_total = div64_u64(div64_u64(((unsigned long long)( - current_duration_in_us) * stream->timing.pix_clk_khz), + current_duration_in_us) * (stream->timing.pix_clk_100hz / 10)), stream->timing.h_total), 1000); in_out_vrr->adjust.v_total_min = v_total; @@ -461,6 +461,26 @@ bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, return false; } +static void build_vrr_infopacket_header_vtem(enum signal_type signal, + struct dc_info_packet *infopacket) +{ + // HEADER + + // HB0, HB1, HB2 indicates PacketType VTEMPacket + infopacket->hb0 = 0x7F; + infopacket->hb1 = 0xC0; + infopacket->hb2 = 0x00; + /* HB3 Bit Fields + * Reserved :1 = 0 + * Sync :1 = 0 + * VFR :1 = 1 + * Ds_Type :2 = 0 + * End :1 = 0 + * New :1 = 0 + */ + infopacket->hb3 = 0x20; +} + static void build_vrr_infopacket_header_v1(enum signal_type signal, struct dc_info_packet *infopacket, unsigned int *payload_size) @@ -559,6 +579,54 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal, } } +static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream, + const struct mod_vrr_params *vrr, + struct dc_info_packet *infopacket) +{ + /* dc_info_packet to VtemPacket Translation of Bit-fields, + * SB[6] + * unsigned char VRR_EN :1 + * unsigned char M_CONST :1 + * unsigned char Reserved2 :2 + * unsigned char FVA_Factor_M1 :4 + * SB[7] + * unsigned char Base_Vfront :8 + * SB[8] + * unsigned char Base_Refresh_Rate_98 :2 + * unsigned char RB :1 + * unsigned char Reserved3 :5 + * SB[9] + * unsigned char Base_RefreshRate_07 :8 + */ + unsigned int fieldRateInHz; + + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || + vrr->state == VRR_STATE_ACTIVE_FIXED){ + infopacket->sb[6] |= 0x80; //VRR_EN Bit = 1 + } else { + infopacket->sb[6] &= 0x7F; //VRR_EN Bit = 0 + } + + if (!stream->timing.vic) { + infopacket->sb[7] = stream->timing.v_front_porch; + + /* TODO: In dal2, we check mode flags for a reduced blanking timing. + * Need a way to relay that information to this function. + * if("ReducedBlanking") + * { + * infopacket->sb[8] |= 0x20; //Set 3rd bit to 1 + * } + */ + fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/ + (stream->timing.h_total * stream->timing.v_total); + + infopacket->sb[8] |= ((fieldRateInHz & 0x300) >> 2); + infopacket->sb[9] |= fieldRateInHz & 0xFF; + + } + infopacket->valid = true; +} + static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, struct dc_info_packet *infopacket) { @@ -672,6 +740,19 @@ static void build_vrr_infopacket_v2(enum signal_type signal, infopacket->valid = true; } +static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream, + const struct mod_vrr_params *vrr, + struct dc_info_packet *infopacket) +{ + //VTEM info packet for HdmiVrr + + //VTEM Packet is structured differently + build_vrr_infopacket_header_vtem(stream->signal, infopacket); + build_vrr_vtem_infopacket_data(stream, vrr, infopacket); + + infopacket->valid = true; +} + void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, const struct dc_stream_state *stream, const struct mod_vrr_params *vrr, @@ -679,18 +760,21 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, const enum color_transfer_func *app_tf, struct dc_info_packet *infopacket) { - /* SPD info packet for FreeSync */ - - /* Check if Freesync is supported. Return if false. If true, + /* SPD info packet for FreeSync + * VTEM info packet for HdmiVRR + * Check if Freesync is supported. Return if false. If true, * set the corresponding bit in the info packet */ - if (!vrr->supported || !vrr->send_vsif) + if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM)) return; switch (packet_type) { case PACKET_TYPE_FS2: build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); break; + case PACKET_TYPE_VTEM: + build_vrr_infopacket_vtem(stream, vrr, infopacket); + break; case PACKET_TYPE_VRR: case PACKET_TYPE_FS1: default: @@ -739,7 +823,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, return; in_out_vrr->state = in_config->state; - in_out_vrr->send_vsif = in_config->vsif_supported; + in_out_vrr->send_info_frame = in_config->vsif_supported; if (in_config->state == VRR_STATE_UNSUPPORTED) { in_out_vrr->state = VRR_STATE_UNSUPPORTED; @@ -972,7 +1056,7 @@ unsigned long long mod_freesync_calc_nominal_field_rate( unsigned long long nominal_field_rate_in_uhz = 0; /* Calculate nominal field rate for stream */ - nominal_field_rate_in_uhz = stream->timing.pix_clk_khz; + nominal_field_rate_in_uhz = stream->timing.pix_clk_100hz / 10; nominal_field_rate_in_uhz *= 1000ULL * 1000ULL * 1000ULL; nominal_field_rate_in_uhz = div_u64(nominal_field_rate_in_uhz, stream->timing.h_total); diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index 949a8b62aa98..4222e403b151 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -104,7 +104,7 @@ struct mod_vrr_params_fixed_refresh { struct mod_vrr_params { bool supported; - bool send_vsif; + bool send_info_frame; enum mod_vrr_state state; uint32_t min_refresh_in_uhz; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h index 1bd02c0ac30c..b711e7e6c204 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h @@ -41,7 +41,8 @@ enum color_transfer_func { enum vrr_packet_type { PACKET_TYPE_VRR, PACKET_TYPE_FS1, - PACKET_TYPE_FS2 + PACKET_TYPE_FS2, + PACKET_TYPE_VTEM }; diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index 00f63b7dd32f..3ba87b076287 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -41,6 +41,17 @@ static const unsigned char min_reduction_table[13] = { static const unsigned char max_reduction_table[13] = { 0xf5, 0xe5, 0xd9, 0xcd, 0xb1, 0xa5, 0xa5, 0x80, 0x65, 0x4d, 0x4d, 0x4d, 0x32}; +/* ABM 2.2 Min Reduction effectively disabled (100% for all configs)*/ +static const unsigned char min_reduction_table_v_2_2[13] = { +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +/* Possible ABM 2.2 Max Reduction configs from least aggressive to most aggressive + * 0 1 2 3 4 5 6 7 8 9 10 11 12 + * 96.1 89.8 74.9 69.4 64.7 52.2 48.6 39.6 30.2 25.1 19.6 12.5 12.5 % + */ +static const unsigned char max_reduction_table_v_2_2[13] = { +0xf5, 0xe5, 0xbf, 0xb1, 0xa5, 0x85, 0x7c, 0x65, 0x4d, 0x40, 0x32, 0x20, 0x20}; + /* Predefined ABM configuration sets. We may have different configuration sets * in order to satisfy different power/quality requirements. */ @@ -56,7 +67,15 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le #define NUM_AGGR_LEVEL 4 #define NUM_POWER_FN_SEGS 8 #define NUM_BL_CURVE_SEGS 16 +#define IRAM_SIZE 256 +#define IRAM_RESERVE_AREA_START_V2 0xF0 // reserve 0xF0~0xF6 are write by DMCU only +#define IRAM_RESERVE_AREA_END_V2 0xF6 // reserve 0xF0~0xF6 are write by DMCU only + +#define IRAM_RESERVE_AREA_START_V2_2 0xF0 // reserve 0xF0~0xFF are write by DMCU only +#define IRAM_RESERVE_AREA_END_V2_2 0xFF // reserve 0xF0~0xFF are write by DMCU only + +#pragma pack(push, 1) /* NOTE: iRAM is 256B in size */ struct iram_table_v_2 { /* flags */ @@ -85,11 +104,10 @@ struct iram_table_v_2 { /* For reading PSR State directly from IRAM */ uint8_t psr_state; /* 0xf0 */ - uint8_t dmcu_interface_version; /* 0xf1 */ - uint8_t dmcu_date_version_year_b0; /* 0xf2 */ - uint8_t dmcu_date_version_year_b1; /* 0xf3 */ - uint8_t dmcu_date_version_month; /* 0xf4 */ - uint8_t dmcu_date_version_day; /* 0xf5 */ + uint8_t dmcu_mcp_interface_version; /* 0xf1 */ + uint8_t dmcu_abm_feature_version; /* 0xf2 */ + uint8_t dmcu_psr_feature_version; /* 0xf3 */ + uint16_t dmcu_version; /* 0xf4 */ uint8_t dmcu_state; /* 0xf6 */ uint16_t blRampReduction; /* 0xf7 */ @@ -101,6 +119,52 @@ struct iram_table_v_2 { uint8_t dummy9; /* 0xff */ }; +struct iram_table_v_2_2 { + /* flags */ + uint16_t flags; /* 0x00 U16 */ + + /* parameters for ABM2.2 algorithm */ + uint8_t min_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x02 U0.8 */ + uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */ + uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */ + uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */ + uint8_t hybridFactor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */ + uint8_t contrastFactor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */ + uint8_t deviation_gain[NUM_AGGR_LEVEL]; /* 0x5a U0.8 */ + uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x5e U0.8 */ + uint8_t pad[29]; /* 0x63 U0.8 */ + + /* parameters for crgb conversion */ + uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */ + uint16_t crgb_offset[NUM_POWER_FN_SEGS]; /* 0x90 U1.15 */ + uint16_t crgb_slope[NUM_POWER_FN_SEGS]; /* 0xa0 U4.12 */ + + /* parameters for custom curve */ + /* thresholds for brightness --> backlight */ + uint16_t backlight_thresholds[NUM_BL_CURVE_SEGS]; /* 0xb0 U16.0 */ + /* offsets for brightness --> backlight */ + uint16_t backlight_offsets[NUM_BL_CURVE_SEGS]; /* 0xd0 U16.0 */ + + /* For reading PSR State directly from IRAM */ + uint8_t psr_state; /* 0xf0 */ + uint8_t dmcu_mcp_interface_version; /* 0xf1 */ + uint8_t dmcu_abm_feature_version; /* 0xf2 */ + uint8_t dmcu_psr_feature_version; /* 0xf3 */ + uint16_t dmcu_version; /* 0xf4 */ + uint8_t dmcu_state; /* 0xf6 */ + + uint8_t dummy1; /* 0xf7 */ + uint8_t dummy2; /* 0xf8 */ + uint8_t dummy3; /* 0xf9 */ + uint8_t dummy4; /* 0xfa */ + uint8_t dummy5; /* 0xfb */ + uint8_t dummy6; /* 0xfc */ + uint8_t dummy7; /* 0xfd */ + uint8_t dummy8; /* 0xfe */ + uint8_t dummy9; /* 0xff */ +}; +#pragma pack(pop) + static uint16_t backlight_8_to_16(unsigned int backlight_8bit) { return (uint16_t)(backlight_8bit * 0x101); @@ -143,11 +207,363 @@ static void fill_backlight_transform_table(struct dmcu_iram_parameters params, } } +static void fill_backlight_transform_table_v_2_2(struct dmcu_iram_parameters params, + struct iram_table_v_2_2 *table) +{ + unsigned int i; + unsigned int num_entries = NUM_BL_CURVE_SEGS; + unsigned int query_input_8bit; + unsigned int query_output_8bit; + unsigned int lut_index; + + table->backlight_thresholds[0] = 0; + table->backlight_offsets[0] = params.backlight_lut_array[0]; + table->backlight_thresholds[num_entries-1] = 0xFFFF; + table->backlight_offsets[num_entries-1] = + params.backlight_lut_array[params.backlight_lut_array_size - 1]; + + /* Setup all brightness levels between 0% and 100% exclusive + * Fills brightness-to-backlight transform table. Backlight custom curve + * describes transform from brightness to backlight. It will be defined + * as set of thresholds and set of offsets, together, implying + * extrapolation of custom curve into 16 uniformly spanned linear + * segments. Each threshold/offset represented by 16 bit entry in + * format U4.10. + */ + for (i = 1; i+1 < num_entries; i++) { + query_input_8bit = DIV_ROUNDUP((i * 256), num_entries); + + lut_index = (params.backlight_lut_array_size - 1) * i / (num_entries - 1); + ASSERT(lut_index < params.backlight_lut_array_size); + query_output_8bit = params.backlight_lut_array[lut_index] >> 8; + + table->backlight_thresholds[i] = + backlight_8_to_16(query_input_8bit); + table->backlight_offsets[i] = + backlight_8_to_16(query_output_8bit); + } +} + +void fill_iram_v_2(struct iram_table_v_2 *ram_table, struct dmcu_iram_parameters params) +{ + unsigned int set = params.set; + + ram_table->flags = 0x0; + ram_table->deviation_gain = 0xb3; + + ram_table->blRampReduction = + cpu_to_be16(params.backlight_ramping_reduction); + ram_table->blRampStart = + cpu_to_be16(params.backlight_ramping_start); + + ram_table->min_reduction[0][0] = min_reduction_table[abm_config[set][0]]; + ram_table->min_reduction[1][0] = min_reduction_table[abm_config[set][0]]; + ram_table->min_reduction[2][0] = min_reduction_table[abm_config[set][0]]; + ram_table->min_reduction[3][0] = min_reduction_table[abm_config[set][0]]; + ram_table->min_reduction[4][0] = min_reduction_table[abm_config[set][0]]; + ram_table->max_reduction[0][0] = max_reduction_table[abm_config[set][0]]; + ram_table->max_reduction[1][0] = max_reduction_table[abm_config[set][0]]; + ram_table->max_reduction[2][0] = max_reduction_table[abm_config[set][0]]; + ram_table->max_reduction[3][0] = max_reduction_table[abm_config[set][0]]; + ram_table->max_reduction[4][0] = max_reduction_table[abm_config[set][0]]; + + ram_table->min_reduction[0][1] = min_reduction_table[abm_config[set][1]]; + ram_table->min_reduction[1][1] = min_reduction_table[abm_config[set][1]]; + ram_table->min_reduction[2][1] = min_reduction_table[abm_config[set][1]]; + ram_table->min_reduction[3][1] = min_reduction_table[abm_config[set][1]]; + ram_table->min_reduction[4][1] = min_reduction_table[abm_config[set][1]]; + ram_table->max_reduction[0][1] = max_reduction_table[abm_config[set][1]]; + ram_table->max_reduction[1][1] = max_reduction_table[abm_config[set][1]]; + ram_table->max_reduction[2][1] = max_reduction_table[abm_config[set][1]]; + ram_table->max_reduction[3][1] = max_reduction_table[abm_config[set][1]]; + ram_table->max_reduction[4][1] = max_reduction_table[abm_config[set][1]]; + + ram_table->min_reduction[0][2] = min_reduction_table[abm_config[set][2]]; + ram_table->min_reduction[1][2] = min_reduction_table[abm_config[set][2]]; + ram_table->min_reduction[2][2] = min_reduction_table[abm_config[set][2]]; + ram_table->min_reduction[3][2] = min_reduction_table[abm_config[set][2]]; + ram_table->min_reduction[4][2] = min_reduction_table[abm_config[set][2]]; + ram_table->max_reduction[0][2] = max_reduction_table[abm_config[set][2]]; + ram_table->max_reduction[1][2] = max_reduction_table[abm_config[set][2]]; + ram_table->max_reduction[2][2] = max_reduction_table[abm_config[set][2]]; + ram_table->max_reduction[3][2] = max_reduction_table[abm_config[set][2]]; + ram_table->max_reduction[4][2] = max_reduction_table[abm_config[set][2]]; + + ram_table->min_reduction[0][3] = min_reduction_table[abm_config[set][3]]; + ram_table->min_reduction[1][3] = min_reduction_table[abm_config[set][3]]; + ram_table->min_reduction[2][3] = min_reduction_table[abm_config[set][3]]; + ram_table->min_reduction[3][3] = min_reduction_table[abm_config[set][3]]; + ram_table->min_reduction[4][3] = min_reduction_table[abm_config[set][3]]; + ram_table->max_reduction[0][3] = max_reduction_table[abm_config[set][3]]; + ram_table->max_reduction[1][3] = max_reduction_table[abm_config[set][3]]; + ram_table->max_reduction[2][3] = max_reduction_table[abm_config[set][3]]; + ram_table->max_reduction[3][3] = max_reduction_table[abm_config[set][3]]; + ram_table->max_reduction[4][3] = max_reduction_table[abm_config[set][3]]; + + ram_table->bright_pos_gain[0][0] = 0x20; + ram_table->bright_pos_gain[0][1] = 0x20; + ram_table->bright_pos_gain[0][2] = 0x20; + ram_table->bright_pos_gain[0][3] = 0x20; + ram_table->bright_pos_gain[1][0] = 0x20; + ram_table->bright_pos_gain[1][1] = 0x20; + ram_table->bright_pos_gain[1][2] = 0x20; + ram_table->bright_pos_gain[1][3] = 0x20; + ram_table->bright_pos_gain[2][0] = 0x20; + ram_table->bright_pos_gain[2][1] = 0x20; + ram_table->bright_pos_gain[2][2] = 0x20; + ram_table->bright_pos_gain[2][3] = 0x20; + ram_table->bright_pos_gain[3][0] = 0x20; + ram_table->bright_pos_gain[3][1] = 0x20; + ram_table->bright_pos_gain[3][2] = 0x20; + ram_table->bright_pos_gain[3][3] = 0x20; + ram_table->bright_pos_gain[4][0] = 0x20; + ram_table->bright_pos_gain[4][1] = 0x20; + ram_table->bright_pos_gain[4][2] = 0x20; + ram_table->bright_pos_gain[4][3] = 0x20; + ram_table->bright_neg_gain[0][1] = 0x00; + ram_table->bright_neg_gain[0][2] = 0x00; + ram_table->bright_neg_gain[0][3] = 0x00; + ram_table->bright_neg_gain[1][0] = 0x00; + ram_table->bright_neg_gain[1][1] = 0x00; + ram_table->bright_neg_gain[1][2] = 0x00; + ram_table->bright_neg_gain[1][3] = 0x00; + ram_table->bright_neg_gain[2][0] = 0x00; + ram_table->bright_neg_gain[2][1] = 0x00; + ram_table->bright_neg_gain[2][2] = 0x00; + ram_table->bright_neg_gain[2][3] = 0x00; + ram_table->bright_neg_gain[3][0] = 0x00; + ram_table->bright_neg_gain[3][1] = 0x00; + ram_table->bright_neg_gain[3][2] = 0x00; + ram_table->bright_neg_gain[3][3] = 0x00; + ram_table->bright_neg_gain[4][0] = 0x00; + ram_table->bright_neg_gain[4][1] = 0x00; + ram_table->bright_neg_gain[4][2] = 0x00; + ram_table->bright_neg_gain[4][3] = 0x00; + ram_table->dark_pos_gain[0][0] = 0x00; + ram_table->dark_pos_gain[0][1] = 0x00; + ram_table->dark_pos_gain[0][2] = 0x00; + ram_table->dark_pos_gain[0][3] = 0x00; + ram_table->dark_pos_gain[1][0] = 0x00; + ram_table->dark_pos_gain[1][1] = 0x00; + ram_table->dark_pos_gain[1][2] = 0x00; + ram_table->dark_pos_gain[1][3] = 0x00; + ram_table->dark_pos_gain[2][0] = 0x00; + ram_table->dark_pos_gain[2][1] = 0x00; + ram_table->dark_pos_gain[2][2] = 0x00; + ram_table->dark_pos_gain[2][3] = 0x00; + ram_table->dark_pos_gain[3][0] = 0x00; + ram_table->dark_pos_gain[3][1] = 0x00; + ram_table->dark_pos_gain[3][2] = 0x00; + ram_table->dark_pos_gain[3][3] = 0x00; + ram_table->dark_pos_gain[4][0] = 0x00; + ram_table->dark_pos_gain[4][1] = 0x00; + ram_table->dark_pos_gain[4][2] = 0x00; + ram_table->dark_pos_gain[4][3] = 0x00; + ram_table->dark_neg_gain[0][0] = 0x00; + ram_table->dark_neg_gain[0][1] = 0x00; + ram_table->dark_neg_gain[0][2] = 0x00; + ram_table->dark_neg_gain[0][3] = 0x00; + ram_table->dark_neg_gain[1][0] = 0x00; + ram_table->dark_neg_gain[1][1] = 0x00; + ram_table->dark_neg_gain[1][2] = 0x00; + ram_table->dark_neg_gain[1][3] = 0x00; + ram_table->dark_neg_gain[2][0] = 0x00; + ram_table->dark_neg_gain[2][1] = 0x00; + ram_table->dark_neg_gain[2][2] = 0x00; + ram_table->dark_neg_gain[2][3] = 0x00; + ram_table->dark_neg_gain[3][0] = 0x00; + ram_table->dark_neg_gain[3][1] = 0x00; + ram_table->dark_neg_gain[3][2] = 0x00; + ram_table->dark_neg_gain[3][3] = 0x00; + ram_table->dark_neg_gain[4][0] = 0x00; + ram_table->dark_neg_gain[4][1] = 0x00; + ram_table->dark_neg_gain[4][2] = 0x00; + ram_table->dark_neg_gain[4][3] = 0x00; + + ram_table->iir_curve[0] = 0x65; + ram_table->iir_curve[1] = 0x65; + ram_table->iir_curve[2] = 0x65; + ram_table->iir_curve[3] = 0x65; + ram_table->iir_curve[4] = 0x65; + + //Gamma 2.4 + ram_table->crgb_thresh[0] = cpu_to_be16(0x13b6); + ram_table->crgb_thresh[1] = cpu_to_be16(0x1648); + ram_table->crgb_thresh[2] = cpu_to_be16(0x18e3); + ram_table->crgb_thresh[3] = cpu_to_be16(0x1b41); + ram_table->crgb_thresh[4] = cpu_to_be16(0x1d46); + ram_table->crgb_thresh[5] = cpu_to_be16(0x1f21); + ram_table->crgb_thresh[6] = cpu_to_be16(0x2167); + ram_table->crgb_thresh[7] = cpu_to_be16(0x2384); + ram_table->crgb_offset[0] = cpu_to_be16(0x2999); + ram_table->crgb_offset[1] = cpu_to_be16(0x3999); + ram_table->crgb_offset[2] = cpu_to_be16(0x4666); + ram_table->crgb_offset[3] = cpu_to_be16(0x5999); + ram_table->crgb_offset[4] = cpu_to_be16(0x6333); + ram_table->crgb_offset[5] = cpu_to_be16(0x7800); + ram_table->crgb_offset[6] = cpu_to_be16(0x8c00); + ram_table->crgb_offset[7] = cpu_to_be16(0xa000); + ram_table->crgb_slope[0] = cpu_to_be16(0x3147); + ram_table->crgb_slope[1] = cpu_to_be16(0x2978); + ram_table->crgb_slope[2] = cpu_to_be16(0x23a2); + ram_table->crgb_slope[3] = cpu_to_be16(0x1f55); + ram_table->crgb_slope[4] = cpu_to_be16(0x1c63); + ram_table->crgb_slope[5] = cpu_to_be16(0x1a0f); + ram_table->crgb_slope[6] = cpu_to_be16(0x178d); + ram_table->crgb_slope[7] = cpu_to_be16(0x15ab); + + fill_backlight_transform_table( + params, ram_table); +} + +void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params) +{ + unsigned int set = params.set; + + ram_table->flags = 0x0; + + ram_table->deviation_gain[0] = 0xb3; + ram_table->deviation_gain[1] = 0xb3; + ram_table->deviation_gain[2] = 0xb3; + ram_table->deviation_gain[3] = 0xb3; + + ram_table->min_reduction[0][0] = min_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->min_reduction[1][0] = min_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->min_reduction[2][0] = min_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->min_reduction[3][0] = min_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->min_reduction[4][0] = min_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->max_reduction[0][0] = max_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->max_reduction[1][0] = max_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->max_reduction[2][0] = max_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->max_reduction[3][0] = max_reduction_table_v_2_2[abm_config[set][0]]; + ram_table->max_reduction[4][0] = max_reduction_table_v_2_2[abm_config[set][0]]; + + ram_table->min_reduction[0][1] = min_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->min_reduction[1][1] = min_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->min_reduction[2][1] = min_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->min_reduction[3][1] = min_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->min_reduction[4][1] = min_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->max_reduction[0][1] = max_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->max_reduction[1][1] = max_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->max_reduction[2][1] = max_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->max_reduction[3][1] = max_reduction_table_v_2_2[abm_config[set][1]]; + ram_table->max_reduction[4][1] = max_reduction_table_v_2_2[abm_config[set][1]]; + + ram_table->min_reduction[0][2] = min_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->min_reduction[1][2] = min_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->min_reduction[2][2] = min_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->min_reduction[3][2] = min_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->min_reduction[4][2] = min_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->max_reduction[0][2] = max_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->max_reduction[1][2] = max_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->max_reduction[2][2] = max_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->max_reduction[3][2] = max_reduction_table_v_2_2[abm_config[set][2]]; + ram_table->max_reduction[4][2] = max_reduction_table_v_2_2[abm_config[set][2]]; + + ram_table->min_reduction[0][3] = min_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->min_reduction[1][3] = min_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->min_reduction[2][3] = min_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->min_reduction[3][3] = min_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->min_reduction[4][3] = min_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->max_reduction[0][3] = max_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->max_reduction[1][3] = max_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->max_reduction[2][3] = max_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->max_reduction[3][3] = max_reduction_table_v_2_2[abm_config[set][3]]; + ram_table->max_reduction[4][3] = max_reduction_table_v_2_2[abm_config[set][3]]; + + ram_table->bright_pos_gain[0][0] = 0x20; + ram_table->bright_pos_gain[0][1] = 0x20; + ram_table->bright_pos_gain[0][2] = 0x20; + ram_table->bright_pos_gain[0][3] = 0x20; + ram_table->bright_pos_gain[1][0] = 0x20; + ram_table->bright_pos_gain[1][1] = 0x20; + ram_table->bright_pos_gain[1][2] = 0x20; + ram_table->bright_pos_gain[1][3] = 0x20; + ram_table->bright_pos_gain[2][0] = 0x20; + ram_table->bright_pos_gain[2][1] = 0x20; + ram_table->bright_pos_gain[2][2] = 0x20; + ram_table->bright_pos_gain[2][3] = 0x20; + ram_table->bright_pos_gain[3][0] = 0x20; + ram_table->bright_pos_gain[3][1] = 0x20; + ram_table->bright_pos_gain[3][2] = 0x20; + ram_table->bright_pos_gain[3][3] = 0x20; + ram_table->bright_pos_gain[4][0] = 0x20; + ram_table->bright_pos_gain[4][1] = 0x20; + ram_table->bright_pos_gain[4][2] = 0x20; + ram_table->bright_pos_gain[4][3] = 0x20; + + ram_table->dark_pos_gain[0][0] = 0x00; + ram_table->dark_pos_gain[0][1] = 0x00; + ram_table->dark_pos_gain[0][2] = 0x00; + ram_table->dark_pos_gain[0][3] = 0x00; + ram_table->dark_pos_gain[1][0] = 0x00; + ram_table->dark_pos_gain[1][1] = 0x00; + ram_table->dark_pos_gain[1][2] = 0x00; + ram_table->dark_pos_gain[1][3] = 0x00; + ram_table->dark_pos_gain[2][0] = 0x00; + ram_table->dark_pos_gain[2][1] = 0x00; + ram_table->dark_pos_gain[2][2] = 0x00; + ram_table->dark_pos_gain[2][3] = 0x00; + ram_table->dark_pos_gain[3][0] = 0x00; + ram_table->dark_pos_gain[3][1] = 0x00; + ram_table->dark_pos_gain[3][2] = 0x00; + ram_table->dark_pos_gain[3][3] = 0x00; + ram_table->dark_pos_gain[4][0] = 0x00; + ram_table->dark_pos_gain[4][1] = 0x00; + ram_table->dark_pos_gain[4][2] = 0x00; + ram_table->dark_pos_gain[4][3] = 0x00; + + ram_table->hybridFactor[0] = 0xff; + ram_table->hybridFactor[1] = 0xff; + ram_table->hybridFactor[2] = 0xff; + ram_table->hybridFactor[3] = 0xc0; + + ram_table->contrastFactor[0] = 0x99; + ram_table->contrastFactor[1] = 0x99; + ram_table->contrastFactor[2] = 0x99; + ram_table->contrastFactor[3] = 0x80; + + ram_table->iir_curve[0] = 0x65; + ram_table->iir_curve[1] = 0x65; + ram_table->iir_curve[2] = 0x65; + ram_table->iir_curve[3] = 0x65; + ram_table->iir_curve[4] = 0x65; + + //Gamma 2.2 + ram_table->crgb_thresh[0] = cpu_to_be16(0x127c); + ram_table->crgb_thresh[1] = cpu_to_be16(0x151b); + ram_table->crgb_thresh[2] = cpu_to_be16(0x17d5); + ram_table->crgb_thresh[3] = cpu_to_be16(0x1a56); + ram_table->crgb_thresh[4] = cpu_to_be16(0x1c83); + ram_table->crgb_thresh[5] = cpu_to_be16(0x1e72); + ram_table->crgb_thresh[6] = cpu_to_be16(0x20f0); + ram_table->crgb_thresh[7] = cpu_to_be16(0x232b); + ram_table->crgb_offset[0] = cpu_to_be16(0x2999); + ram_table->crgb_offset[1] = cpu_to_be16(0x3999); + ram_table->crgb_offset[2] = cpu_to_be16(0x4666); + ram_table->crgb_offset[3] = cpu_to_be16(0x5999); + ram_table->crgb_offset[4] = cpu_to_be16(0x6333); + ram_table->crgb_offset[5] = cpu_to_be16(0x7800); + ram_table->crgb_offset[6] = cpu_to_be16(0x8c00); + ram_table->crgb_offset[7] = cpu_to_be16(0xa000); + ram_table->crgb_slope[0] = cpu_to_be16(0x3609); + ram_table->crgb_slope[1] = cpu_to_be16(0x2dfa); + ram_table->crgb_slope[2] = cpu_to_be16(0x27ea); + ram_table->crgb_slope[3] = cpu_to_be16(0x235d); + ram_table->crgb_slope[4] = cpu_to_be16(0x2042); + ram_table->crgb_slope[5] = cpu_to_be16(0x1dc3); + ram_table->crgb_slope[6] = cpu_to_be16(0x1b1a); + ram_table->crgb_slope[7] = cpu_to_be16(0x1910); + + fill_backlight_transform_table_v_2_2( + params, ram_table); +} + bool dmcu_load_iram(struct dmcu *dmcu, struct dmcu_iram_parameters params) { - struct iram_table_v_2 ram_table; - unsigned int set = params.set; + unsigned char ram_table[IRAM_SIZE]; + bool result = false; if (dmcu == NULL) return false; @@ -157,170 +573,23 @@ bool dmcu_load_iram(struct dmcu *dmcu, memset(&ram_table, 0, sizeof(ram_table)); - ram_table.flags = 0x0; - ram_table.deviation_gain = 0xb3; + if (dmcu->dmcu_version.abm_version == 0x22) { + fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params); - ram_table.blRampReduction = - cpu_to_be16(params.backlight_ramping_reduction); - ram_table.blRampStart = - cpu_to_be16(params.backlight_ramping_start); + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2); + } else { + fill_iram_v_2((struct iram_table_v_2 *)ram_table, params); - ram_table.min_reduction[0][0] = min_reduction_table[abm_config[set][0]]; - ram_table.min_reduction[1][0] = min_reduction_table[abm_config[set][0]]; - ram_table.min_reduction[2][0] = min_reduction_table[abm_config[set][0]]; - ram_table.min_reduction[3][0] = min_reduction_table[abm_config[set][0]]; - ram_table.min_reduction[4][0] = min_reduction_table[abm_config[set][0]]; - ram_table.max_reduction[0][0] = max_reduction_table[abm_config[set][0]]; - ram_table.max_reduction[1][0] = max_reduction_table[abm_config[set][0]]; - ram_table.max_reduction[2][0] = max_reduction_table[abm_config[set][0]]; - ram_table.max_reduction[3][0] = max_reduction_table[abm_config[set][0]]; - ram_table.max_reduction[4][0] = max_reduction_table[abm_config[set][0]]; - - ram_table.min_reduction[0][1] = min_reduction_table[abm_config[set][1]]; - ram_table.min_reduction[1][1] = min_reduction_table[abm_config[set][1]]; - ram_table.min_reduction[2][1] = min_reduction_table[abm_config[set][1]]; - ram_table.min_reduction[3][1] = min_reduction_table[abm_config[set][1]]; - ram_table.min_reduction[4][1] = min_reduction_table[abm_config[set][1]]; - ram_table.max_reduction[0][1] = max_reduction_table[abm_config[set][1]]; - ram_table.max_reduction[1][1] = max_reduction_table[abm_config[set][1]]; - ram_table.max_reduction[2][1] = max_reduction_table[abm_config[set][1]]; - ram_table.max_reduction[3][1] = max_reduction_table[abm_config[set][1]]; - ram_table.max_reduction[4][1] = max_reduction_table[abm_config[set][1]]; - - ram_table.min_reduction[0][2] = min_reduction_table[abm_config[set][2]]; - ram_table.min_reduction[1][2] = min_reduction_table[abm_config[set][2]]; - ram_table.min_reduction[2][2] = min_reduction_table[abm_config[set][2]]; - ram_table.min_reduction[3][2] = min_reduction_table[abm_config[set][2]]; - ram_table.min_reduction[4][2] = min_reduction_table[abm_config[set][2]]; - ram_table.max_reduction[0][2] = max_reduction_table[abm_config[set][2]]; - ram_table.max_reduction[1][2] = max_reduction_table[abm_config[set][2]]; - ram_table.max_reduction[2][2] = max_reduction_table[abm_config[set][2]]; - ram_table.max_reduction[3][2] = max_reduction_table[abm_config[set][2]]; - ram_table.max_reduction[4][2] = max_reduction_table[abm_config[set][2]]; - - ram_table.min_reduction[0][3] = min_reduction_table[abm_config[set][3]]; - ram_table.min_reduction[1][3] = min_reduction_table[abm_config[set][3]]; - ram_table.min_reduction[2][3] = min_reduction_table[abm_config[set][3]]; - ram_table.min_reduction[3][3] = min_reduction_table[abm_config[set][3]]; - ram_table.min_reduction[4][3] = min_reduction_table[abm_config[set][3]]; - ram_table.max_reduction[0][3] = max_reduction_table[abm_config[set][3]]; - ram_table.max_reduction[1][3] = max_reduction_table[abm_config[set][3]]; - ram_table.max_reduction[2][3] = max_reduction_table[abm_config[set][3]]; - ram_table.max_reduction[3][3] = max_reduction_table[abm_config[set][3]]; - ram_table.max_reduction[4][3] = max_reduction_table[abm_config[set][3]]; - - ram_table.bright_pos_gain[0][0] = 0x20; - ram_table.bright_pos_gain[0][1] = 0x20; - ram_table.bright_pos_gain[0][2] = 0x20; - ram_table.bright_pos_gain[0][3] = 0x20; - ram_table.bright_pos_gain[1][0] = 0x20; - ram_table.bright_pos_gain[1][1] = 0x20; - ram_table.bright_pos_gain[1][2] = 0x20; - ram_table.bright_pos_gain[1][3] = 0x20; - ram_table.bright_pos_gain[2][0] = 0x20; - ram_table.bright_pos_gain[2][1] = 0x20; - ram_table.bright_pos_gain[2][2] = 0x20; - ram_table.bright_pos_gain[2][3] = 0x20; - ram_table.bright_pos_gain[3][0] = 0x20; - ram_table.bright_pos_gain[3][1] = 0x20; - ram_table.bright_pos_gain[3][2] = 0x20; - ram_table.bright_pos_gain[3][3] = 0x20; - ram_table.bright_pos_gain[4][0] = 0x20; - ram_table.bright_pos_gain[4][1] = 0x20; - ram_table.bright_pos_gain[4][2] = 0x20; - ram_table.bright_pos_gain[4][3] = 0x20; - ram_table.bright_neg_gain[0][1] = 0x00; - ram_table.bright_neg_gain[0][2] = 0x00; - ram_table.bright_neg_gain[0][3] = 0x00; - ram_table.bright_neg_gain[1][0] = 0x00; - ram_table.bright_neg_gain[1][1] = 0x00; - ram_table.bright_neg_gain[1][2] = 0x00; - ram_table.bright_neg_gain[1][3] = 0x00; - ram_table.bright_neg_gain[2][0] = 0x00; - ram_table.bright_neg_gain[2][1] = 0x00; - ram_table.bright_neg_gain[2][2] = 0x00; - ram_table.bright_neg_gain[2][3] = 0x00; - ram_table.bright_neg_gain[3][0] = 0x00; - ram_table.bright_neg_gain[3][1] = 0x00; - ram_table.bright_neg_gain[3][2] = 0x00; - ram_table.bright_neg_gain[3][3] = 0x00; - ram_table.bright_neg_gain[4][0] = 0x00; - ram_table.bright_neg_gain[4][1] = 0x00; - ram_table.bright_neg_gain[4][2] = 0x00; - ram_table.bright_neg_gain[4][3] = 0x00; - ram_table.dark_pos_gain[0][0] = 0x00; - ram_table.dark_pos_gain[0][1] = 0x00; - ram_table.dark_pos_gain[0][2] = 0x00; - ram_table.dark_pos_gain[0][3] = 0x00; - ram_table.dark_pos_gain[1][0] = 0x00; - ram_table.dark_pos_gain[1][1] = 0x00; - ram_table.dark_pos_gain[1][2] = 0x00; - ram_table.dark_pos_gain[1][3] = 0x00; - ram_table.dark_pos_gain[2][0] = 0x00; - ram_table.dark_pos_gain[2][1] = 0x00; - ram_table.dark_pos_gain[2][2] = 0x00; - ram_table.dark_pos_gain[2][3] = 0x00; - ram_table.dark_pos_gain[3][0] = 0x00; - ram_table.dark_pos_gain[3][1] = 0x00; - ram_table.dark_pos_gain[3][2] = 0x00; - ram_table.dark_pos_gain[3][3] = 0x00; - ram_table.dark_pos_gain[4][0] = 0x00; - ram_table.dark_pos_gain[4][1] = 0x00; - ram_table.dark_pos_gain[4][2] = 0x00; - ram_table.dark_pos_gain[4][3] = 0x00; - ram_table.dark_neg_gain[0][0] = 0x00; - ram_table.dark_neg_gain[0][1] = 0x00; - ram_table.dark_neg_gain[0][2] = 0x00; - ram_table.dark_neg_gain[0][3] = 0x00; - ram_table.dark_neg_gain[1][0] = 0x00; - ram_table.dark_neg_gain[1][1] = 0x00; - ram_table.dark_neg_gain[1][2] = 0x00; - ram_table.dark_neg_gain[1][3] = 0x00; - ram_table.dark_neg_gain[2][0] = 0x00; - ram_table.dark_neg_gain[2][1] = 0x00; - ram_table.dark_neg_gain[2][2] = 0x00; - ram_table.dark_neg_gain[2][3] = 0x00; - ram_table.dark_neg_gain[3][0] = 0x00; - ram_table.dark_neg_gain[3][1] = 0x00; - ram_table.dark_neg_gain[3][2] = 0x00; - ram_table.dark_neg_gain[3][3] = 0x00; - ram_table.dark_neg_gain[4][0] = 0x00; - ram_table.dark_neg_gain[4][1] = 0x00; - ram_table.dark_neg_gain[4][2] = 0x00; - ram_table.dark_neg_gain[4][3] = 0x00; - ram_table.iir_curve[0] = 0x65; - ram_table.iir_curve[1] = 0x65; - ram_table.iir_curve[2] = 0x65; - ram_table.iir_curve[3] = 0x65; - ram_table.iir_curve[4] = 0x65; - ram_table.crgb_thresh[0] = cpu_to_be16(0x13b6); - ram_table.crgb_thresh[1] = cpu_to_be16(0x1648); - ram_table.crgb_thresh[2] = cpu_to_be16(0x18e3); - ram_table.crgb_thresh[3] = cpu_to_be16(0x1b41); - ram_table.crgb_thresh[4] = cpu_to_be16(0x1d46); - ram_table.crgb_thresh[5] = cpu_to_be16(0x1f21); - ram_table.crgb_thresh[6] = cpu_to_be16(0x2167); - ram_table.crgb_thresh[7] = cpu_to_be16(0x2384); - ram_table.crgb_offset[0] = cpu_to_be16(0x2999); - ram_table.crgb_offset[1] = cpu_to_be16(0x3999); - ram_table.crgb_offset[2] = cpu_to_be16(0x4666); - ram_table.crgb_offset[3] = cpu_to_be16(0x5999); - ram_table.crgb_offset[4] = cpu_to_be16(0x6333); - ram_table.crgb_offset[5] = cpu_to_be16(0x7800); - ram_table.crgb_offset[6] = cpu_to_be16(0x8c00); - ram_table.crgb_offset[7] = cpu_to_be16(0xa000); - ram_table.crgb_slope[0] = cpu_to_be16(0x3147); - ram_table.crgb_slope[1] = cpu_to_be16(0x2978); - ram_table.crgb_slope[2] = cpu_to_be16(0x23a2); - ram_table.crgb_slope[3] = cpu_to_be16(0x1f55); - ram_table.crgb_slope[4] = cpu_to_be16(0x1c63); - ram_table.crgb_slope[5] = cpu_to_be16(0x1a0f); - ram_table.crgb_slope[6] = cpu_to_be16(0x178d); - ram_table.crgb_slope[7] = cpu_to_be16(0x15ab); + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2); - fill_backlight_transform_table( - params, &ram_table); + if (result) + result = dmcu->funcs->load_iram( + dmcu, IRAM_RESERVE_AREA_END_V2 + 1, + (char *)(&ram_table) + IRAM_RESERVE_AREA_END_V2 + 1, + sizeof(ram_table) - IRAM_RESERVE_AREA_END_V2 - 1); + } - return dmcu->funcs->load_iram( - dmcu, 0, (char *)(&ram_table), sizeof(ram_table)); + return result; } |