diff options
author | Maxime Ripard <maxime.ripard@bootlin.com> | 2019-07-22 22:24:10 +0300 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@bootlin.com> | 2019-07-22 22:24:10 +0300 |
commit | 03b0f2ce735e97e9f49790d4563c82515b8fa702 (patch) | |
tree | da561805bffd06bfba81c867f83cacb28f3a64e5 /drivers/gpu/drm/amd/display | |
parent | e4f86e43716443e934d705952902d40de0fa9a05 (diff) | |
parent | 5f9e832c137075045d15cd6899ab0505cfb2ca4b (diff) | |
download | linux-03b0f2ce735e97e9f49790d4563c82515b8fa702.tar.xz |
Merge v5.3-rc1 into drm-misc-next
Noralf needs some SPI patches in 5.3 to merge some work on tinydrm.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display')
170 files changed, 35556 insertions, 523 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 5c826faae240..f954bf61af28 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -5,6 +5,7 @@ menu "Display Engine Configuration" config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y + select SND_HDA_COMPONENT if SND_HDA_CORE select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) help Choose this option if you want to use the new display engine @@ -16,6 +17,25 @@ config DRM_AMD_DC_DCN1_0 help RV family support for display engine +config DRM_AMD_DC_DCN2_0 + bool "DCN 2.0 family" + default y + depends on DRM_AMD_DC && X86 + depends on DRM_AMD_DC_DCN1_0 + help + Choose this option if you want to have + Navi support for display engine + +config DRM_AMD_DC_DSC_SUPPORT + bool "DSC support" + default y + depends on DRM_AMD_DC && X86 + depends on DRM_AMD_DC_DCN1_0 + depends on DRM_AMD_DC_DCN2_0 + help + Choose this option if you want to have + Dynamic Stream Compression support + config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC 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 b16c658074d2..4a29f72334d0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -56,6 +56,7 @@ #include <linux/pm_runtime.h> #include <linux/pci.h> #include <linux/firmware.h> +#include <linux/component.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_uapi.h> @@ -65,9 +66,10 @@ #include <drm/drm_fourcc.h> #include <drm/drm_edid.h> #include <drm/drm_vblank.h> +#include <drm/drm_audio_component.h> #if defined(CONFIG_DRM_AMD_DC_DCN1_0) -#include "ivsrcid/irqsrcs_dcn_1_0.h" +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" #include "dcn/dcn_1_0_sh_mask.h" @@ -508,6 +510,139 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector) } +static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, + int pipe, bool *enabled, + unsigned char *buf, int max_bytes) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct amdgpu_dm_connector *aconnector; + int ret = 0; + + *enabled = false; + + mutex_lock(&adev->dm.audio_lock); + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->audio_inst != port) + continue; + + *enabled = true; + ret = drm_eld_size(connector->eld); + memcpy(buf, connector->eld, min(max_bytes, ret)); + + break; + } + drm_connector_list_iter_end(&conn_iter); + + mutex_unlock(&adev->dm.audio_lock); + + DRM_DEBUG_KMS("Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + + return ret; +} + +static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = { + .get_eld = amdgpu_dm_audio_component_get_eld, +}; + +static int amdgpu_dm_audio_component_bind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_audio_component *acomp = data; + + acomp->ops = &amdgpu_dm_audio_component_ops; + acomp->dev = kdev; + adev->dm.audio_component = acomp; + + return 0; +} + +static void amdgpu_dm_audio_component_unbind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = dev->dev_private; + struct drm_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; + adev->dm.audio_component = NULL; +} + +static const struct component_ops amdgpu_dm_audio_component_bind_ops = { + .bind = amdgpu_dm_audio_component_bind, + .unbind = amdgpu_dm_audio_component_unbind, +}; + +static int amdgpu_dm_audio_init(struct amdgpu_device *adev) +{ + int i, ret; + + if (!amdgpu_audio) + return 0; + + adev->mode_info.audio.enabled = true; + + adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count; + + for (i = 0; i < adev->mode_info.audio.num_pins; i++) { + adev->mode_info.audio.pin[i].channels = -1; + adev->mode_info.audio.pin[i].rate = -1; + adev->mode_info.audio.pin[i].bits_per_sample = -1; + adev->mode_info.audio.pin[i].status_bits = 0; + adev->mode_info.audio.pin[i].category_code = 0; + adev->mode_info.audio.pin[i].connected = false; + adev->mode_info.audio.pin[i].id = + adev->dm.dc->res_pool->audios[i]->inst; + adev->mode_info.audio.pin[i].offset = 0; + } + + ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops); + if (ret < 0) + return ret; + + adev->dm.audio_registered = true; + + return 0; +} + +static void amdgpu_dm_audio_fini(struct amdgpu_device *adev) +{ + if (!amdgpu_audio) + return; + + if (!adev->mode_info.audio.enabled) + return; + + if (adev->dm.audio_registered) { + component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops); + adev->dm.audio_registered = false; + } + + /* TODO: Disable audio? */ + + adev->mode_info.audio.enabled = false; +} + +void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) +{ + struct drm_audio_component *acomp = adev->dm.audio_component; + + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + DRM_DEBUG_KMS("Notify ELD: %d\n", pin); + + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, + pin, -1); + } +} + static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; @@ -518,6 +653,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) memset(&init_data, 0, sizeof(init_data)); mutex_init(&adev->dm.dc_lock); + mutex_init(&adev->dm.audio_lock); if(amdgpu_dm_irq_init(adev)) { DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n"); @@ -560,6 +696,10 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.flags.power_down_display_on_boot = true; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + init_data.soc_bounding_box = adev->dm.soc_bounding_box; +#endif + /* Display Core create. */ adev->dm.dc = dc_create(&init_data); @@ -617,6 +757,8 @@ error: static void amdgpu_dm_fini(struct amdgpu_device *adev) { + amdgpu_dm_audio_fini(adev); + amdgpu_dm_destroy_drm_device(&adev->dm); /* DC Destroy TODO: Replace destroy DAL */ @@ -637,6 +779,7 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev) adev->dm.freesync_module = NULL; } + mutex_destroy(&adev->dm.audio_lock); mutex_destroy(&adev->dm.dc_lock); return; @@ -665,6 +808,7 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: + case CHIP_NAVI10: return 0; case CHIP_RAVEN: if (ASICREV_IS_PICASSO(adev->external_rev_id)) @@ -779,7 +923,7 @@ static int dm_late_init(void *handle) unsigned int linear_lut[16]; int i; struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; - bool ret; + bool ret = false; for (i = 0; i < 16; i++) linear_lut[i] = 0xFFFF * i / 15; @@ -790,10 +934,13 @@ static int dm_late_init(void *handle) params.backlight_lut_array_size = 16; params.backlight_lut_array = linear_lut; - ret = dmcu_load_iram(dmcu, params); + /* todo will enable for navi10 */ + if (adev->asic_type <= CHIP_RAVEN) { + ret = dmcu_load_iram(dmcu, params); - if (!ret) - return -EINVAL; + if (!ret) + return -EINVAL; + } return detect_mst_link_for_all_connectors(adev->ddev); } @@ -1527,10 +1674,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) int i; unsigned client_id = AMDGPU_IRQ_CLIENTID_LEGACY; - if (adev->asic_type == CHIP_VEGA10 || - adev->asic_type == CHIP_VEGA12 || - adev->asic_type == CHIP_VEGA20 || - adev->asic_type == CHIP_RAVEN) + if (adev->asic_type >= CHIP_VEGA10) client_id = SOC15_IH_CLIENTID_DCE; int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; @@ -1883,6 +2027,10 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) if (r) return r; + r = amdgpu_dm_audio_init(adev); + if (r) + return r; + return 0; } @@ -2209,6 +2357,9 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) break; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case CHIP_NAVI10: +#endif if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); goto fail; @@ -2362,6 +2513,13 @@ static int dm_early_init(void *handle) adev->mode_info.num_dig = 4; break; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case CHIP_NAVI10: + adev->mode_info.num_crtc = 6; + adev->mode_info.num_hpd = 6; + adev->mode_info.num_dig = 6; + break; +#endif default: DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type); return -EINVAL; @@ -2654,6 +2812,9 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, if (adev->asic_type == CHIP_VEGA10 || adev->asic_type == CHIP_VEGA12 || adev->asic_type == CHIP_VEGA20 || +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + adev->asic_type == CHIP_NAVI10 || +#endif adev->asic_type == CHIP_RAVEN) { /* Fill GFX9 params */ tiling_info->gfx9.num_pipes = @@ -2859,6 +3020,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, struct drm_plane_state *plane_state, struct drm_crtc_state *crtc_state) { + struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); const struct amdgpu_framebuffer *amdgpu_fb = to_amdgpu_framebuffer(plane_state->fb); struct dc_scaling_info scaling_info; @@ -2903,13 +3065,11 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, * Always set input transfer function, since plane state is refreshed * every time. */ - ret = amdgpu_dm_set_degamma_lut(crtc_state, dc_plane_state); - if (ret) { - dc_transfer_func_release(dc_plane_state->in_transfer_func); - dc_plane_state->in_transfer_func = NULL; - } + ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state); + if (ret) + return ret; - return ret; + return 0; } static void update_stream_scaling_settings(const struct drm_display_mode *mode, @@ -2973,6 +3133,9 @@ convert_color_depth_from_display_info(const struct drm_connector *connector, { uint32_t bpc = connector->display_info.bpc; + if (!state) + state = connector->state; + if (state) { bpc = state->max_bpc; /* Round down to the nearest even number. */ @@ -3399,6 +3562,20 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, fill_stream_properties_from_drm_display_mode(stream, &mode, &aconnector->base, con_state, old_stream); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* stream->timing.flags.DSC = 0; */ + /* */ + /* if (aconnector->dc_link && */ + /* aconnector->dc_link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT #<{(|&& */ + /* aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.is_dsc_supported|)}>#) */ + /* if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc, */ + /* &aconnector->dc_link->dpcd_caps.dsc_caps, */ + /* dc_link_bandwidth_kbps(aconnector->dc_link, dc_link_get_link_cap(aconnector->dc_link)), */ + /* &stream->timing, */ + /* &stream->timing.dsc_cfg)) */ + /* stream->timing.flags.DSC = 1; */ +#endif + update_stream_scaling_settings(&mode, dm_state, stream); fill_audio_info( @@ -3481,6 +3658,8 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) state->vrr_supported = cur->vrr_supported; state->freesync_config = cur->freesync_config; state->crc_enabled = cur->crc_enabled; + state->cm_has_degamma = cur->cm_has_degamma; + state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; /* TODO Duplicate dc_stream after objects are stream object is flattened */ @@ -3735,6 +3914,10 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) state->underscan_enable = false; state->underscan_hborder = 0; state->underscan_vborder = 0; + state->base.max_requested_bpc = 8; + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + state->abm_level = amdgpu_dm_abm_level; __drm_atomic_helper_connector_reset(connector, &state->base); } @@ -4780,6 +4963,13 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, { struct amdgpu_device *adev = dm->ddev->dev_private; + /* + * Some of the properties below require access to state, like bpc. + * Allocate some default initial connector state with our reset helper. + */ + if (aconnector->base.funcs->reset) + aconnector->base.funcs->reset(&aconnector->base); + aconnector->connector_id = link_index; aconnector->dc_link = link; aconnector->base.interlace_allowed = false; @@ -4787,6 +4977,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, aconnector->base.stereo_allowed = false; aconnector->base.dpms = DRM_MODE_DPMS_OFF; aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ + aconnector->audio_inst = -1; mutex_init(&aconnector->hpd_lock); /* @@ -4969,9 +5160,6 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, &aconnector->base, &amdgpu_dm_connector_helper_funcs); - if (aconnector->base.funcs->reset) - aconnector->base.funcs->reset(&aconnector->base); - amdgpu_dm_connector_init_helper( dm, aconnector, @@ -4984,11 +5172,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, drm_connector_register(&aconnector->base); #if defined(CONFIG_DEBUG_FS) - res = connector_debugfs_init(aconnector); - if (res) { - DRM_ERROR("Failed to create debugfs for connector"); - goto out_free; - } + connector_debugfs_init(aconnector); aconnector->debugfs_dpcd_address = 0; aconnector->debugfs_dpcd_size = 0; #endif @@ -5628,14 +5812,25 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, } /* Update the planes if changed or disable if we don't have any. */ - if (planes_count || acrtc_state->active_planes == 0) { + if ((planes_count || acrtc_state->active_planes == 0) && + acrtc_state->stream) { if (new_pcrtc_state->mode_changed) { bundle->stream_update.src = acrtc_state->stream->src; bundle->stream_update.dst = acrtc_state->stream->dst; } - if (new_pcrtc_state->color_mgmt_changed) - bundle->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func; + if (new_pcrtc_state->color_mgmt_changed) { + /* + * TODO: This isn't fully correct since we've actually + * already modified the stream in place. + */ + bundle->stream_update.gamut_remap = + &acrtc_state->stream->gamut_remap_matrix; + bundle->stream_update.output_csc_transform = + &acrtc_state->stream->csc_color_matrix; + bundle->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) @@ -5677,6 +5872,81 @@ cleanup: kfree(bundle); } +static void amdgpu_dm_commit_audio(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct amdgpu_device *adev = dev->dev_private; + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_state *old_con_state, *new_con_state; + struct drm_crtc_state *new_crtc_state; + struct dm_crtc_state *new_dm_crtc_state; + const struct dc_stream_status *status; + int i, inst; + + /* Notify device removals. */ + for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { + if (old_con_state->crtc != new_con_state->crtc) { + /* CRTC changes require notification. */ + goto notify; + } + + if (!new_con_state->crtc) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state( + state, new_con_state->crtc); + + if (!new_crtc_state) + continue; + + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + + notify: + aconnector = to_amdgpu_dm_connector(connector); + + mutex_lock(&adev->dm.audio_lock); + inst = aconnector->audio_inst; + aconnector->audio_inst = -1; + mutex_unlock(&adev->dm.audio_lock); + + amdgpu_dm_audio_eld_notify(adev, inst); + } + + /* Notify audio device additions. */ + for_each_new_connector_in_state(state, connector, new_con_state, i) { + if (!new_con_state->crtc) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state( + state, new_con_state->crtc); + + if (!new_crtc_state) + continue; + + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + + new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); + if (!new_dm_crtc_state->stream) + continue; + + status = dc_stream_get_status(new_dm_crtc_state->stream); + if (!status) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + + mutex_lock(&adev->dm.audio_lock); + inst = status->audio_inst; + aconnector->audio_inst = inst; + mutex_unlock(&adev->dm.audio_lock); + + amdgpu_dm_audio_eld_notify(adev, inst); + } +} + /* * Enable interrupts on CRTCs that are newly active, undergone * a modeset, or have active planes again. @@ -6055,6 +6325,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) /* Enable interrupts for CRTCs going from 0 to n active planes. */ amdgpu_dm_enable_crtc_interrupts(dev, state, false); + /* Update audio instances for each connector. */ + amdgpu_dm_commit_audio(dev, state); + /* * send vblank event on all events not handled in flip and * mark consumed event for drm_atomic_helper_commit_hw_done @@ -6346,7 +6619,17 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, if (ret) goto fail; - if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && + /* + * If we already removed the old stream from the context + * (and set the new stream to NULL) then we can't reuse + * the old stream even if the stream and scaling are unchanged. + * We'll hit the BUG_ON and black screen. + * + * TODO: Refactor this function to allow this check to work + * in all conditions. + */ + if (dm_new_crtc_state->stream && + 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", @@ -6475,10 +6758,9 @@ skip_modeset: */ 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); + ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state); if (ret) goto fail; - amdgpu_dm_set_ctm(dm_new_crtc_state); } /* Update Freesync settings. */ @@ -6781,6 +7063,8 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, new_dm_plane_state->dc_state->in_transfer_func; stream_update.gamut_remap = &new_dm_crtc_state->stream->gamut_remap_matrix; + stream_update.output_csc_transform = + &new_dm_crtc_state->stream->csc_color_matrix; stream_update.out_transfer_func = new_dm_crtc_state->stream->out_transfer_func; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 811253d7f157..b89cbbfcc0e9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -144,6 +144,28 @@ struct amdgpu_display_manager { struct mutex dc_lock; /** + * @audio_lock: + * + * Guards access to audio instance changes. + */ + struct mutex audio_lock; + + /** + * @audio_component: + * + * Used to notify ELD changes to sound driver. + */ + struct drm_audio_component *audio_component; + + /** + * @audio_registered: + * + * True if the audio component has been registered + * successfully, false otherwise. + */ + bool audio_registered; + + /** * @irq_handler_list_low_tab: * * Low priority IRQ handler table. @@ -209,6 +231,13 @@ struct amdgpu_display_manager { const struct firmware *fw_dmcu; uint32_t dmcu_fw_version; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + /** + * gpu_info FW provided soc bounding box struct or 0 if not + * available in FW + */ + const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; +#endif }; struct amdgpu_dm_connector { @@ -247,6 +276,9 @@ struct amdgpu_dm_connector { int max_vfreq ; int pixel_clock_mhz; + /* Audio instance - protected by audio_lock. */ + int audio_inst; + struct mutex hpd_lock; bool fake_enable; @@ -274,6 +306,9 @@ struct dm_crtc_state { struct drm_crtc_state base; struct dc_stream_state *stream; + bool cm_has_degamma; + bool cm_is_degamma_srgb; + int active_planes; bool interrupts_enabled; @@ -363,10 +398,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); -int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, - struct dc_plane_state *dc_plane_state); -void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc); -int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc); +int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); +int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct dc_plane_state *dc_plane_state); extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 7258c992a2bf..b43bb7f90e4e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -27,6 +27,47 @@ #include "amdgpu_dm.h" #include "dc.h" #include "modules/color/color_gamma.h" +#include "basics/conversion.h" + +/* + * The DC interface to HW gives us the following color management blocks + * per pipe (surface): + * + * - Input gamma LUT (de-normalized) + * - Input CSC (normalized) + * - Surface degamma LUT (normalized) + * - Surface CSC (normalized) + * - Surface regamma LUT (normalized) + * - Output CSC (normalized) + * + * But these aren't a direct mapping to DRM color properties. The current DRM + * interface exposes CRTC degamma, CRTC CTM and CRTC regamma while our hardware + * is essentially giving: + * + * Plane CTM -> Plane degamma -> Plane CTM -> Plane regamma -> Plane CTM + * + * The input gamma LUT block isn't really applicable here since it operates + * on the actual input data itself rather than the HW fp representation. The + * input and output CSC blocks are technically available to use as part of + * the DC interface but are typically used internally by DC for conversions + * between color spaces. These could be blended together with user + * adjustments in the future but for now these should remain untouched. + * + * The pipe blending also happens after these blocks so we don't actually + * support any CRTC props with correct blending with multiple planes - but we + * can still support CRTC color management properties in DM in most single + * plane cases correctly with clever management of the DC interface in DM. + * + * As per DRM documentation, blocks should be in hardware bypass when their + * respective property is set to NULL. A linear DGM/RGM LUT should also + * considered as putting the respective block into bypass mode. + * + * This means that the following + * configuration is assumed to be the default: + * + * Plane DGM Bypass -> Plane CTM Bypass -> Plane RGM Bypass -> ... + * CRTC DGM Bypass -> CRTC CTM Bypass -> CRTC RGM Bypass + */ #define MAX_DRM_LUT_VALUE 0xFFFF @@ -41,6 +82,13 @@ void amdgpu_dm_init_color_mod(void) setup_x_points_distribution(); } +/* Extracts the DRM lut and lut size from a blob. */ +static const struct drm_color_lut * +__extract_blob_lut(const struct drm_property_blob *blob, uint32_t *size) +{ + *size = blob ? drm_color_lut_size(blob) : 0; + return blob ? (struct drm_color_lut *)blob->data : NULL; +} /* * Return true if the given lut is a linear mapping of values, i.e. it acts @@ -50,7 +98,7 @@ void amdgpu_dm_init_color_mod(void) * f(a) = (0xFF00/MAX_COLOR_LUT_ENTRIES-1)a; for integer a in * [0, MAX_COLOR_LUT_ENTRIES) */ -static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size) +static bool __is_lut_linear(const struct drm_color_lut *lut, uint32_t size) { int i; uint32_t expected; @@ -75,9 +123,8 @@ static bool __is_lut_linear(struct drm_color_lut *lut, uint32_t size) * Convert the drm_color_lut to dc_gamma. The conversion depends on the size * of the lut - whether or not it's legacy. */ -static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut, - struct dc_gamma *gamma, - bool is_legacy) +static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut, + struct dc_gamma *gamma, bool is_legacy) { uint32_t r, g, b; int i; @@ -107,103 +154,16 @@ static void __drm_lut_to_dc_gamma(struct drm_color_lut *lut, } } -/** - * amdgpu_dm_set_regamma_lut: Set regamma lut for the given CRTC. - * @crtc: amdgpu_dm crtc state - * - * Update the underlying dc_stream_state's output transfer function (OTF) in - * preparation for hardware commit. If no lut is specified by user, we default - * to SRGB. - * - * RETURNS: - * 0 on success, -ENOMEM if memory cannot be allocated to calculate the OTF. - */ -int amdgpu_dm_set_regamma_lut(struct dm_crtc_state *crtc) -{ - struct drm_property_blob *blob = crtc->base.gamma_lut; - struct dc_stream_state *stream = crtc->stream; - struct amdgpu_device *adev = (struct amdgpu_device *) - crtc->base.state->dev->dev_private; - struct drm_color_lut *lut; - uint32_t lut_size; - struct dc_gamma *gamma = NULL; - enum dc_transfer_func_type old_type = stream->out_transfer_func->type; - - bool ret; - - if (!blob && adev->asic_type <= CHIP_RAVEN) { - /* By default, use the SRGB predefined curve.*/ - stream->out_transfer_func->type = TF_TYPE_PREDEFINED; - stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - return 0; - } - - if (blob) { - lut = (struct drm_color_lut *)blob->data; - lut_size = blob->length / sizeof(struct drm_color_lut); - - gamma = dc_create_gamma(); - if (!gamma) - return -ENOMEM; - - gamma->num_entries = lut_size; - if (gamma->num_entries == MAX_COLOR_LEGACY_LUT_ENTRIES) - gamma->type = GAMMA_RGB_256; - else if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) - gamma->type = GAMMA_CS_TFM_1D; - else { - /* Invalid lut size */ - dc_gamma_release(&gamma); - return -EINVAL; - } - - /* Convert drm_lut into dc_gamma */ - __drm_lut_to_dc_gamma(lut, gamma, gamma->type == GAMMA_RGB_256); - } - - /* predefined gamma ROM only exist for RAVEN and pre-RAVEN ASIC, - * set canRomBeUsed accordingly - */ - stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; - ret = mod_color_calculate_regamma_params(stream->out_transfer_func, - gamma, true, adev->asic_type <= CHIP_RAVEN, NULL); - - if (gamma) - dc_gamma_release(&gamma); - - if (!ret) { - stream->out_transfer_func->type = old_type; - DRM_ERROR("Out of memory when calculating regamma params\n"); - return -ENOMEM; - } - - return 0; -} - -/** - * amdgpu_dm_set_ctm: Set the color transform matrix for the given CRTC. - * @crtc: amdgpu_dm crtc state - * - * Update the underlying dc_stream_state's gamut remap matrix in preparation - * for hardware commit. If no matrix is specified by user, gamut remap will be - * disabled. +/* + * Converts a DRM CTM to a DC CSC float matrix. + * The matrix needs to be a 3x4 (12 entry) matrix. */ -void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) +static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, + struct fixed31_32 *matrix) { - - struct drm_property_blob *blob = crtc->base.ctm; - struct dc_stream_state *stream = crtc->stream; - struct drm_color_ctm *ctm; int64_t val; int i; - if (!blob) { - stream->gamut_remap_matrix.enable_remap = false; - return; - } - - stream->gamut_remap_matrix.enable_remap = true; - ctm = (struct drm_color_ctm *)blob->data; /* * DRM gives a 3x3 matrix, but DC wants 3x4. Assuming we're operating * with homogeneous coordinates, augment the matrix with 0's. @@ -215,83 +175,306 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc) for (i = 0; i < 12; i++) { /* Skip 4th element */ if (i % 4 == 3) { - stream->gamut_remap_matrix.matrix[i] = dc_fixpt_zero; + matrix[i] = dc_fixpt_zero; continue; } /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ - val = ctm->matrix[i - (i/4)]; + val = ctm->matrix[i - (i / 4)]; /* If negative, convert to 2's complement. */ if (val & (1ULL << 63)) val = -(val & ~(1ULL << 63)); - stream->gamut_remap_matrix.matrix[i].value = val; + matrix[i].value = val; } } +/* Calculates the legacy transfer function - only for sRGB input space. */ +static int __set_legacy_tf(struct dc_transfer_func *func, + const struct drm_color_lut *lut, uint32_t lut_size, + bool has_rom) +{ + struct dc_gamma *gamma = NULL; + bool res; -/** - * amdgpu_dm_set_degamma_lut: Set degamma lut for the given CRTC. - * @crtc: amdgpu_dm crtc state - * - * Update the underlying dc_stream_state's input transfer function (ITF) in - * preparation for hardware commit. If no lut is specified by user, we default - * to SRGB degamma. - * - * We support degamma bypass, predefined SRGB, and custom degamma - * - * RETURNS: - * 0 on success - * -EINVAL if crtc_state has a degamma_lut of invalid size - * -ENOMEM if gamma allocation fails - */ -int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state, - struct dc_plane_state *dc_plane_state) + ASSERT(lut && lut_size == MAX_COLOR_LEGACY_LUT_ENTRIES); + + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + gamma->type = GAMMA_RGB_256; + gamma->num_entries = lut_size; + __drm_lut_to_dc_gamma(lut, gamma, true); + + res = mod_color_calculate_regamma_params(func, gamma, true, has_rom, + NULL); + + return res ? 0 : -ENOMEM; +} + +/* Calculates the output transfer function based on expected input space. */ +static int __set_output_tf(struct dc_transfer_func *func, + const struct drm_color_lut *lut, uint32_t lut_size, + bool has_rom) { - struct drm_property_blob *blob = crtc_state->degamma_lut; - struct drm_color_lut *lut; - uint32_t lut_size; - struct dc_gamma *gamma; - bool ret; - - if (!blob) { - /* Default to SRGB */ - dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; - dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - return 0; - } + struct dc_gamma *gamma = NULL; + bool res; - lut = (struct drm_color_lut *)blob->data; - if (__is_lut_linear(lut, MAX_COLOR_LUT_ENTRIES)) { - dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; - dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; - return 0; - } + ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); gamma = dc_create_gamma(); if (!gamma) return -ENOMEM; - lut_size = blob->length / sizeof(struct drm_color_lut); gamma->num_entries = lut_size; - if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES) + __drm_lut_to_dc_gamma(lut, gamma, false); + + if (func->tf == TRANSFER_FUNCTION_LINEAR) { + /* + * Color module doesn't like calculating regamma params + * on top of a linear input. But degamma params can be used + * instead to simulate this. + */ gamma->type = GAMMA_CUSTOM; - else { - dc_gamma_release(&gamma); - return -EINVAL; + res = mod_color_calculate_degamma_params(func, gamma, true); + } else { + /* + * Assume sRGB. The actual mapping will depend on whether the + * input was legacy or not. + */ + gamma->type = GAMMA_CS_TFM_1D; + res = mod_color_calculate_regamma_params(func, gamma, false, + has_rom, NULL); } + dc_gamma_release(&gamma); + + return res ? 0 : -ENOMEM; +} + +/* Caculates the input transfer function based on expected input space. */ +static int __set_input_tf(struct dc_transfer_func *func, + const struct drm_color_lut *lut, uint32_t lut_size) +{ + struct dc_gamma *gamma = NULL; + bool res; + + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + gamma->type = GAMMA_CUSTOM; + gamma->num_entries = lut_size; + __drm_lut_to_dc_gamma(lut, gamma, false); - dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; - ret = mod_color_calculate_degamma_params(dc_plane_state->in_transfer_func, gamma, true); + res = mod_color_calculate_degamma_params(func, gamma, true); dc_gamma_release(&gamma); - if (!ret) { - dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; - DRM_ERROR("Out of memory when calculating degamma params\n"); - return -ENOMEM; + + return res ? 0 : -ENOMEM; +} + +/** + * amdgpu_dm_update_crtc_color_mgmt: Maps DRM color management to DC stream. + * @crtc: amdgpu_dm crtc state + * + * With no plane level color management properties we're free to use any + * of the HW blocks as long as the CRTC CTM always comes before the + * CRTC RGM and after the CRTC DGM. + * + * The CRTC RGM block will be placed in the RGM LUT block if it is non-linear. + * The CRTC DGM block will be placed in the DGM LUT block if it is non-linear. + * The CRTC CTM will be placed in the gamut remap block if it is non-linear. + * + * The RGM block is typically more fully featured and accurate across + * all ASICs - DCE can't support a custom non-linear CRTC DGM. + * + * For supporting both plane level color management and CRTC level color + * management at once we have to either restrict the usage of CRTC properties + * or blend adjustments together. + * + * Returns 0 on success. + */ +int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) +{ + struct dc_stream_state *stream = crtc->stream; + struct amdgpu_device *adev = + (struct amdgpu_device *)crtc->base.state->dev->dev_private; + bool has_rom = adev->asic_type <= CHIP_RAVEN; + struct drm_color_ctm *ctm = NULL; + const struct drm_color_lut *degamma_lut, *regamma_lut; + uint32_t degamma_size, regamma_size; + bool has_regamma, has_degamma; + bool is_legacy; + int r; + + degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, °amma_size); + if (degamma_lut && degamma_size != MAX_COLOR_LUT_ENTRIES) + return -EINVAL; + + regamma_lut = __extract_blob_lut(crtc->base.gamma_lut, ®amma_size); + if (regamma_lut && regamma_size != MAX_COLOR_LUT_ENTRIES && + regamma_size != MAX_COLOR_LEGACY_LUT_ENTRIES) + return -EINVAL; + + has_degamma = + degamma_lut && !__is_lut_linear(degamma_lut, degamma_size); + + has_regamma = + regamma_lut && !__is_lut_linear(regamma_lut, regamma_size); + + is_legacy = regamma_size == MAX_COLOR_LEGACY_LUT_ENTRIES; + + /* Reset all adjustments. */ + crtc->cm_has_degamma = false; + crtc->cm_is_degamma_srgb = false; + + /* Setup regamma and degamma. */ + if (is_legacy) { + /* + * Legacy regamma forces us to use the sRGB RGM as a base. + * This also means we can't use linear DGM since DGM needs + * to use sRGB as a base as well, resulting in incorrect CRTC + * DGM and CRTC CTM. + * + * TODO: Just map this to the standard regamma interface + * instead since this isn't really right. One of the cases + * where this setup currently fails is trying to do an + * inverse color ramp in legacy userspace. + */ + crtc->cm_is_degamma_srgb = true; + stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + + r = __set_legacy_tf(stream->out_transfer_func, regamma_lut, + regamma_size, has_rom); + if (r) + return r; + } else if (has_regamma) { + /* CRTC RGM goes into RGM LUT. */ + stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + + r = __set_output_tf(stream->out_transfer_func, regamma_lut, + regamma_size, has_rom); + if (r) + return r; + } else { + /* + * No CRTC RGM means we can just put the block into bypass + * since we don't have any plane level adjustments using it. + */ + stream->out_transfer_func->type = TF_TYPE_BYPASS; + stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + } + + /* + * CRTC DGM goes into DGM LUT. It would be nice to place it + * into the RGM since it's a more featured block but we'd + * have to place the CTM in the OCSC in that case. + */ + crtc->cm_has_degamma = has_degamma; + + /* Setup CRTC CTM. */ + if (crtc->base.ctm) { + ctm = (struct drm_color_ctm *)crtc->base.ctm->data; + + /* + * Gamut remapping must be used for gamma correction + * since it comes before the regamma correction. + * + * OCSC could be used for gamma correction, but we'd need to + * blend the adjustments together with the required output + * conversion matrix - so just use the gamut remap block + * for now. + */ + __drm_ctm_to_dc_matrix(ctm, stream->gamut_remap_matrix.matrix); + + stream->gamut_remap_matrix.enable_remap = true; + stream->csc_color_matrix.enable_adjustment = false; + } else { + /* Bypass CTM. */ + stream->gamut_remap_matrix.enable_remap = false; + stream->csc_color_matrix.enable_adjustment = false; } return 0; } +/** + * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. + * @crtc: amdgpu_dm crtc state + * @ dc_plane_state: target DC surface + * + * Update the underlying dc_stream_state's input transfer function (ITF) in + * preparation for hardware commit. The transfer function used depends on + * the prepartion done on the stream for color management. + * + * Returns 0 on success. + */ +int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct dc_plane_state *dc_plane_state) +{ + const struct drm_color_lut *degamma_lut; + uint32_t degamma_size; + int r; + + if (crtc->cm_has_degamma) { + degamma_lut = __extract_blob_lut(crtc->base.degamma_lut, + °amma_size); + ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); + + dc_plane_state->in_transfer_func->type = + TF_TYPE_DISTRIBUTED_POINTS; + + /* + * This case isn't fully correct, but also fairly + * uncommon. This is userspace trying to use a + * legacy gamma LUT + atomic degamma LUT + * at the same time. + * + * Legacy gamma requires the input to be in linear + * space, so that means we need to apply an sRGB + * degamma. But color module also doesn't support + * a user ramp in this case so the degamma will + * be lost. + * + * Even if we did support it, it's still not right: + * + * Input -> CRTC DGM -> sRGB DGM -> CRTC CTM -> + * sRGB RGM -> CRTC RGM -> Output + * + * The CSC will be done in the wrong space since + * we're applying an sRGB DGM on top of the CRTC + * DGM. + * + * TODO: Don't use the legacy gamma interface and just + * map these to the atomic one instead. + */ + if (crtc->cm_is_degamma_srgb) + dc_plane_state->in_transfer_func->tf = + TRANSFER_FUNCTION_SRGB; + else + dc_plane_state->in_transfer_func->tf = + TRANSFER_FUNCTION_LINEAR; + + r = __set_input_tf(dc_plane_state->in_transfer_func, + degamma_lut, degamma_size); + if (r) + return r; + } else if (crtc->cm_is_degamma_srgb) { + /* + * For legacy gamma support we need the regamma input + * in linear space. Assume that the input is sRGB. + */ + dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB; + } else { + /* ...Otherwise we can just bypass the DGM block. */ + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + } + + 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 e611b5376d8c..36a1d794b4af 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 @@ -675,6 +675,71 @@ static ssize_t dp_phy_test_pattern_debugfs_write(struct file *f, const char __us } /* + * Returns the current and maximum output bpc for the connector. + * Example usage: cat /sys/kernel/debug/dri/0/DP-1/output_bpc + */ +static int output_bpc_show(struct seq_file *m, void *data) +{ + struct drm_connector *connector = m->private; + struct drm_device *dev = connector->dev; + struct drm_crtc *crtc = NULL; + struct dm_crtc_state *dm_crtc_state = NULL; + int res = -ENODEV; + unsigned int bpc; + + mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + + if (connector->state == NULL) + goto unlock; + + crtc = connector->state->crtc; + if (crtc == NULL) + goto unlock; + + drm_modeset_lock(&crtc->mutex, NULL); + if (crtc->state == NULL) + goto unlock; + + dm_crtc_state = to_dm_crtc_state(crtc->state); + if (dm_crtc_state->stream == NULL) + goto unlock; + + switch (dm_crtc_state->stream->timing.display_color_depth) { + case COLOR_DEPTH_666: + bpc = 6; + break; + case COLOR_DEPTH_888: + bpc = 8; + break; + case COLOR_DEPTH_101010: + bpc = 10; + break; + case COLOR_DEPTH_121212: + bpc = 12; + break; + case COLOR_DEPTH_161616: + bpc = 16; + break; + default: + goto unlock; + } + + seq_printf(m, "Current: %u\n", bpc); + seq_printf(m, "Maximum: %u\n", connector->display_info.bpc); + res = 0; + +unlock: + if (crtc) + drm_modeset_unlock(&crtc->mutex); + + drm_modeset_unlock(&dev->mode_config.connection_mutex); + mutex_unlock(&dev->mode_config.mutex); + + return res; +} + +/* * Returns the min and max vrr vfreq through the connector's debugfs file. * Example usage: cat /sys/kernel/debug/dri/0/DP-1/vrr_range */ @@ -732,8 +797,6 @@ static ssize_t dp_sdp_message_debugfs_write(struct file *f, const char __user *b return write_size; } -DEFINE_SHOW_ATTRIBUTE(vrr_range); - static ssize_t dp_dpcd_address_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { @@ -816,6 +879,9 @@ static ssize_t dp_dpcd_data_read(struct file *f, char __user *buf, return read_size - r; } +DEFINE_SHOW_ATTRIBUTE(output_bpc); +DEFINE_SHOW_ATTRIBUTE(vrr_range); + static const struct file_operations dp_link_settings_debugfs_fops = { .owner = THIS_MODULE, .read = dp_link_settings_read, @@ -868,6 +934,7 @@ static const struct { {"link_settings", &dp_link_settings_debugfs_fops}, {"phy_settings", &dp_phy_settings_debugfs_fop}, {"test_pattern", &dp_phy_test_pattern_fops}, + {"output_bpc", &output_bpc_fops}, {"vrr_range", &vrr_range_fops}, {"sdp_message", &sdp_message_fops}, {"aux_dpcd_address", &dp_dpcd_address_debugfs_fops}, @@ -875,25 +942,19 @@ static const struct { {"aux_dpcd_data", &dp_dpcd_data_debugfs_fops} }; -int connector_debugfs_init(struct amdgpu_dm_connector *connector) +void connector_debugfs_init(struct amdgpu_dm_connector *connector) { int i; - struct dentry *ent, *dir = connector->base.debugfs_entry; + struct dentry *dir = connector->base.debugfs_entry; if (connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort || connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) { for (i = 0; i < ARRAY_SIZE(dp_debugfs_entries); i++) { - ent = debugfs_create_file(dp_debugfs_entries[i].name, - 0644, - dir, - connector, - dp_debugfs_entries[i].fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + debugfs_create_file(dp_debugfs_entries[i].name, + 0644, dir, connector, + dp_debugfs_entries[i].fops); } } - - return 0; } /* @@ -1036,7 +1097,7 @@ int dtn_debugfs_init(struct amdgpu_device *adev) }; struct drm_minor *minor = adev->ddev->primary; - struct dentry *ent, *root = minor->debugfs_root; + struct dentry *root = minor->debugfs_root; int ret; ret = amdgpu_debugfs_add_files(adev, amdgpu_dm_debugfs_list, @@ -1044,20 +1105,11 @@ int dtn_debugfs_init(struct amdgpu_device *adev) if (ret) return ret; - ent = debugfs_create_file( - "amdgpu_dm_dtn_log", - 0644, - root, - adev, - &dtn_log_fops); - - if (IS_ERR(ent)) - return PTR_ERR(ent); + debugfs_create_file("amdgpu_dm_dtn_log", 0644, root, adev, + &dtn_log_fops); - ent = debugfs_create_file_unsafe("amdgpu_dm_visual_confirm", 0644, root, - adev, &visual_confirm_fops); - if (IS_ERR(ent)) - return PTR_ERR(ent); + debugfs_create_file_unsafe("amdgpu_dm_visual_confirm", 0644, root, adev, + &visual_confirm_fops); return 0; } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h index bdef1587b0a0..5e5b2b2afa31 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.h @@ -29,7 +29,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" -int connector_debugfs_init(struct amdgpu_dm_connector *connector); +void connector_debugfs_init(struct amdgpu_dm_connector *connector); int dtn_debugfs_init(struct amdgpu_device *adev); #endif 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 97b2c3b16bef..a0ed0154a9f0 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 @@ -541,6 +541,16 @@ bool dm_helpers_submit_i2c( return result; } +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +bool dm_helpers_dp_write_dsc_enable( + struct dc_context *ctx, + const struct dc_stream_state *stream, + bool enable +) +{ + return false; +} +#endif bool dm_helpers_is_dp_sink_present(struct dc_link *link) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 1b59d3d42f7b..fa5d503d379c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -277,8 +277,6 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev, return DAL_INVALID_IRQ_HANDLER_IDX; } - memset(handler_data, 0, sizeof(*handler_data)); - init_handler_common_data(handler_data, ih, handler_args, &adev->dm); irq_source = int_params->irq_source; 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 b37e8c9653e1..592fa499c9f8 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 @@ -148,6 +148,23 @@ static void get_default_clock_levels( } } +static enum smu_clk_type dc_to_smu_clock_type( + enum dm_pp_clock_type dm_pp_clk_type) +{ +#define DCCLK_MAP_SMUCLK(dcclk, smuclk) \ + [dcclk] = smuclk + + static int dc_clk_type_map[] = { + DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_DISPLAY_CLK, SMU_DISPCLK), + DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_ENGINE_CLK, SMU_GFXCLK), + DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_MEMORY_CLK, SMU_MCLK), + DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_DCEFCLK, SMU_DCEFCLK), + DCCLK_MAP_SMUCLK(DM_PP_CLOCK_TYPE_SOCCLK, SMU_SOCCLK), + }; + + return dc_clk_type_map[dm_pp_clk_type]; +} + static enum amd_pp_clock_type dc_to_pp_clock_type( enum dm_pp_clock_type dm_pp_clk_type) { @@ -291,7 +308,8 @@ static void pp_to_dc_clock_levels_with_voltage( DC_DECODE_PP_CLOCK_TYPE(dc_clk_type)); for (i = 0; i < clk_level_info->num_levels; i++) { - DRM_INFO("DM_PPLIB:\t %d in kHz\n", pp_clks->data[i].clocks_in_khz); + DRM_INFO("DM_PPLIB:\t %d in kHz, %d in mV\n", pp_clks->data[i].clocks_in_khz, + pp_clks->data[i].voltage_in_mv); clk_level_info->data[i].clocks_in_khz = pp_clks->data[i].clocks_in_khz; clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; } @@ -316,7 +334,7 @@ bool dm_pp_get_clock_levels_by_type( } } else if (adev->smu.funcs && adev->smu.funcs->get_clock_by_type) { if (smu_get_clock_by_type(&adev->smu, - dc_to_pp_clock_type(clk_type), + dc_to_smu_clock_type(clk_type), &pp_clks)) { get_default_clock_levels(clk_type, dc_clks); return true; @@ -629,16 +647,279 @@ void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) pp_funcs->set_hard_min_fclk_by_freq(pp_handle, mhz); } +enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; + struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = + wm_with_clock_ranges.wm_dmif_clocks_ranges; + struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = + wm_with_clock_ranges.wm_mcif_clocks_ranges; + int32_t i; + + wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; + wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; + + for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { + if (ranges->reader_wm_sets[i].wm_inst > 3) + wm_dce_clocks[i].wm_set_id = WM_SET_A; + else + wm_dce_clocks[i].wm_set_id = + ranges->reader_wm_sets[i].wm_inst; + wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; + wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = + ranges->reader_wm_sets[i].min_drain_clk_mhz * 1000; + wm_dce_clocks[i].wm_max_mem_clk_in_khz = + ranges->reader_wm_sets[i].max_fill_clk_mhz * 1000; + wm_dce_clocks[i].wm_min_mem_clk_in_khz = + ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; + } + + for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { + if (ranges->writer_wm_sets[i].wm_inst > 3) + wm_soc_clocks[i].wm_set_id = WM_SET_A; + else + wm_soc_clocks[i].wm_set_id = + ranges->writer_wm_sets[i].wm_inst; + wm_soc_clocks[i].wm_max_socclk_clk_in_khz = + ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; + wm_soc_clocks[i].wm_min_socclk_clk_in_khz = + ranges->writer_wm_sets[i].min_fill_clk_mhz * 1000; + wm_soc_clocks[i].wm_max_mem_clk_in_khz = + ranges->writer_wm_sets[i].max_drain_clk_mhz * 1000; + wm_soc_clocks[i].wm_min_mem_clk_in_khz = + ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; + } + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + /* 0: successful or smu.funcs->set_watermarks_for_clock_ranges = NULL; + * 1: fail + */ + if (smu_set_watermarks_for_clock_ranges(&adev->smu, + &wm_with_clock_ranges)) + return PP_SMU_RESULT_UNSUPPORTED; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_pme_wa_enable(struct pp_smu *pp) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + /* 0: successful or smu.funcs->set_azalia_d3_pme = NULL; 1: fail */ + if (smu_set_azalia_d3_pme(smu)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + /* 0: successful or smu.funcs->set_display_count = NULL; 1: fail */ + if (smu_set_display_count(smu, count)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + /* 0: successful or smu.funcs->set_deep_sleep_dcefclk = NULL;1: fail */ + if (smu_set_deep_sleep_dcefclk(smu, mhz)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( + struct pp_smu *pp, int mhz) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + struct pp_display_clock_request clock_req; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + clock_req.clock_type = amd_pp_dcef_clock; + clock_req.clock_freq_in_khz = mhz * 1000; + + /* 0: successful or smu.funcs->display_clock_voltage_request = NULL + * 1: fail + */ + if (smu_display_clock_voltage_request(smu, &clock_req)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + struct pp_display_clock_request clock_req; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + clock_req.clock_type = amd_pp_mem_clock; + clock_req.clock_freq_in_khz = mhz * 1000; + + /* 0: successful or smu.funcs->display_clock_voltage_request = NULL + * 1: fail + */ + if (smu_display_clock_voltage_request(smu, &clock_req)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, + enum pp_smu_nv_clock_id clock_id, int mhz) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + struct pp_display_clock_request clock_req; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + switch (clock_id) { + case PP_SMU_NV_DISPCLK: + clock_req.clock_type = amd_pp_disp_clock; + break; + case PP_SMU_NV_PHYCLK: + clock_req.clock_type = amd_pp_phy_clock; + break; + case PP_SMU_NV_PIXELCLK: + clock_req.clock_type = amd_pp_pixel_clock; + break; + default: + break; + } + clock_req.clock_freq_in_khz = mhz * 1000; + + /* 0: successful or smu.funcs->display_clock_voltage_request = NULL + * 1: fail + */ + if (smu_display_clock_voltage_request(smu, &clock_req)) + return PP_SMU_RESULT_FAIL; + + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( + struct pp_smu *pp, struct pp_smu_nv_clock_table *max_clocks) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (!smu->funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + if (!smu->funcs->get_max_sustainable_clocks_by_dc) + return PP_SMU_RESULT_UNSUPPORTED; + + if (!smu->funcs->get_max_sustainable_clocks_by_dc(smu, max_clocks)) + return PP_SMU_RESULT_OK; + + return PP_SMU_RESULT_FAIL; +} + +enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, + unsigned int *clock_values_in_khz, unsigned int *num_states) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (!smu->ppt_funcs) + return PP_SMU_RESULT_UNSUPPORTED; + + if (!smu->ppt_funcs->get_uclk_dpm_states) + return PP_SMU_RESULT_UNSUPPORTED; + + if (!smu->ppt_funcs->get_uclk_dpm_states(smu, + clock_values_in_khz, num_states)) + return PP_SMU_RESULT_OK; + + return PP_SMU_RESULT_FAIL; +} + void dm_pp_get_funcs( struct dc_context *ctx, struct pp_smu_funcs *funcs) { - funcs->rv_funcs.pp_smu.dm = ctx; - funcs->rv_funcs.set_wm_ranges = pp_rv_set_wm_ranges; - funcs->rv_funcs.set_pme_wa_enable = pp_rv_set_pme_wa_enable; - funcs->rv_funcs.set_display_count = pp_rv_set_active_display_count; - funcs->rv_funcs.set_min_deep_sleep_dcfclk = pp_rv_set_min_deep_sleep_dcfclk; - funcs->rv_funcs.set_hard_min_dcfclk_by_freq = pp_rv_set_hard_min_dcefclk_by_freq; - funcs->rv_funcs.set_hard_min_fclk_by_freq = pp_rv_set_hard_min_fclk_by_freq; + switch (ctx->dce_version) { + case DCN_VERSION_1_0: + case DCN_VERSION_1_01: + funcs->ctx.ver = PP_SMU_VER_RV; + funcs->rv_funcs.pp_smu.dm = ctx; + funcs->rv_funcs.set_wm_ranges = pp_rv_set_wm_ranges; + funcs->rv_funcs.set_pme_wa_enable = pp_rv_set_pme_wa_enable; + funcs->rv_funcs.set_display_count = + pp_rv_set_active_display_count; + funcs->rv_funcs.set_min_deep_sleep_dcfclk = + pp_rv_set_min_deep_sleep_dcfclk; + funcs->rv_funcs.set_hard_min_dcfclk_by_freq = + pp_rv_set_hard_min_dcefclk_by_freq; + funcs->rv_funcs.set_hard_min_fclk_by_freq = + pp_rv_set_hard_min_fclk_by_freq; + break; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + case DCN_VERSION_2_0: + funcs->ctx.ver = PP_SMU_VER_NV; + funcs->nv_funcs.pp_smu.dm = ctx; + funcs->nv_funcs.set_display_count = pp_nv_set_display_count; + funcs->nv_funcs.set_hard_min_dcfclk_by_freq = + pp_nv_set_hard_min_dcefclk_by_freq; + funcs->nv_funcs.set_min_deep_sleep_dcfclk = + pp_nv_set_min_deep_sleep_dcfclk; + funcs->nv_funcs.set_voltage_by_freq = + pp_nv_set_voltage_by_freq; + funcs->nv_funcs.set_wm_ranges = pp_nv_set_wm_ranges; + + /* todo set_pme_wa_enable cause 4k@6ohz display not light up */ + funcs->nv_funcs.set_pme_wa_enable = NULL; + /* todo debug waring message */ + funcs->nv_funcs.set_hard_min_uclk_by_freq = pp_nv_set_hard_min_uclk_by_freq; + /* todo compare data with window driver*/ + funcs->nv_funcs.get_maximum_sustainable_clocks = pp_nv_get_maximum_sustainable_clocks; + /*todo compare data with window driver */ + funcs->nv_funcs.get_uclk_dpm_states = pp_nv_get_uclk_dpm_states; + break; +#endif + default: + DRM_ERROR("smu version is not supported !\n"); + break; + } } - diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 6da4e4f844b2..55ce5b657390 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -25,6 +25,15 @@ DC_LIBS = basics bios calcs clk_mgr dce gpio irq virtual +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +DC_LIBS += dcn20 +endif + + +ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +DC_LIBS += dsc +endif + ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml endif @@ -41,8 +50,11 @@ 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_vm_helper.o +dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o + +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +DISPLAY_CORE += dc_vm_helper.o +endif AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE)) 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 fecd766ece37..6aa2e56dfb67 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1402,6 +1402,10 @@ static enum bp_result get_integrated_info_v11( info->ma_channel_number = info_v11->umachannelnumber; info->lvds_ss_percentage = le16_to_cpu(info_v11->lvds_ss_percentage); +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + info->dp_ss_control = + le16_to_cpu(info_v11->reserved1); +#endif info->lvds_sspread_rate_in_10hz = le16_to_cpu(info_v11->lvds_ss_rate_10hz); info->hdmi_ss_percentage = diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 53deba42007a..f9439dfc7b75 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -61,6 +61,12 @@ bool dal_bios_parser_init_cmd_tbl_helper2( *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; #endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case DCN_VERSION_2_0: + *h = dal_cmd_tbl_helper_dce112_get_table2(); + return true; +#endif case DCE_VERSION_12_0: case DCE_VERSION_12_1: *h = dal_cmd_tbl_helper_dce112_get_table2(); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c index 7600a4a4abc7..07d18e78de49 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c @@ -73,6 +73,17 @@ float dcn_bw_floor2(const float arg, const float significance) return 0; return ((int) (arg / significance)) * significance; } +float dcn_bw_floor(const float arg) +{ + return ((int) (arg)); +} + +float dcn_bw_ceil(const float arg) +{ + float flr = dcn_bw_floor2(arg, 1); + + return flr + 0.00001 >= arg ? arg : flr + 1; +} float dcn_bw_ceil2(const float arg, const float significance) { @@ -109,6 +120,15 @@ float dcn_bw_pow(float a, float exp) } } +double dcn_bw_fabs(double a) +{ + if (a > 0) + return (a); + else + return (-a); +} + + float dcn_bw_log(float a, float b) { int * const exp_ptr = (int *)(&a); diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h index f46ab0e24ca1..45a07eeffbb6 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h @@ -31,10 +31,13 @@ float dcn_bw_min2(const float arg1, const float arg2); unsigned int dcn_bw_max(const unsigned int arg1, const unsigned int arg2); float dcn_bw_max2(const float arg1, const float arg2); float dcn_bw_floor2(const float arg, const float significance); +float dcn_bw_floor(const float arg); float dcn_bw_ceil2(const float arg, const float significance); +float dcn_bw_ceil(const float arg); float dcn_bw_max3(float v1, float v2, float v3); float dcn_bw_max5(float v1, float v2, float v3, float v4, float v5); float dcn_bw_pow(float a, float exp); float dcn_bw_log(float a, float b); +double dcn_bw_fabs(double a); #endif /* _DCN_CALC_MATH_H_ */ 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 5c1e0adb142b..38365dd911a3 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -31,6 +31,7 @@ #include "resource.h" #include "dcn10/dcn10_resource.h" #include "dcn10/dcn10_hubbub.h" +#include "dml/dml1_display_rq_dlg_calc.h" #include "dcn_calc_math.h" @@ -52,7 +53,13 @@ * remain as-is as it provides us with a guarantee from HW that it is correct. */ +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +/* Defaults from spreadsheet rev#247. + * RV2 delta: dram_clock_change_latency, max_num_dpp + */ +#else /* Defaults from spreadsheet rev#247 */ +#endif const struct dcn_soc_bounding_box dcn10_soc_defaults = { /* latencies */ .sr_exit_time = 17, /*us*/ @@ -1109,9 +1116,8 @@ bool dcn_validate_bandwidth( context->bw_ctx.bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / (ddr4_dram_factor_single_Channel * v->number_of_channels)); - if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) { + if (bw_consumed == v->fabric_and_dram_bandwidth_vmin0p65) context->bw_ctx.bw.dcn.clk.fclk_khz = (int)(bw_consumed * 1000000 / 32); - } context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000); context->bw_ctx.bw.dcn.clk.dcfclk_khz = (int)(v->dcfclk * 1000); @@ -1126,7 +1132,8 @@ bool dcn_validate_bandwidth( dc->debug.min_disp_clk_khz; } - context->bw_ctx.bw.dcn.clk.dppclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz / v->dispclk_dppclk_ratio; + context->bw_ctx.bw.dcn.clk.dppclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz / + v->dispclk_dppclk_ratio; context->bw_ctx.bw.dcn.clk.phyclk_khz = v->phyclk_per_state[v->voltage_level]; switch (v->voltage_level) { case 0: @@ -1213,9 +1220,7 @@ bool dcn_validate_bandwidth( /* pipe not split previously needs split */ hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, pool, pipe); ASSERT(hsplit_pipe); - split_stream_across_pipes( - &context->res_ctx, pool, - pipe, hsplit_pipe); + split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe); } dcn_bw_calc_rq_dlg_ttu(dc, v, hsplit_pipe, input_idx); @@ -1246,7 +1251,6 @@ bool dcn_validate_bandwidth( } if (v->voltage_level == 0) { - context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->dcn_soc->sr_enter_plus_exit_time; context->bw_ctx.dml.soc.sr_exit_time_us = dc->dcn_soc->sr_exit_time; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile index 650e2b88c917..003c27767e9c 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile @@ -73,3 +73,15 @@ AMD_DAL_CLK_MGR_DCN10 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn10/,$(CLK_MGR_DC AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN10) endif + +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +############################################################################### +# DCN20 +############################################################################### +CLK_MGR_DCN20 = dcn20_clk_mgr.o + +AMD_DAL_CLK_MGR_DCN20 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn20/,$(CLK_MGR_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN20) +endif + diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c index cb3f6a74d9e3..6b8fc5cbabb8 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c @@ -36,6 +36,7 @@ #include "dce120/dce120_clk_mgr.h" #include "dcn10/rv1_clk_mgr.h" #include "dcn10/rv2_clk_mgr.h" +#include "dcn20/dcn20_clk_mgr.h" int clk_mgr_helper_get_active_display_cnt( @@ -119,6 +120,12 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p break; #endif /* Family RV */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case FAMILY_NV: + dcn20_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); + break; +#endif /* Family NV */ + default: ASSERT(0); /* Unknown Asic */ break; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.h index f3bc7ab68aab..f6622f58f62e 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.h @@ -29,28 +29,6 @@ #include "dc.h" -/* Starting DID for each range */ -enum dentist_base_divider_id { - DENTIST_BASE_DID_1 = 0x08, - DENTIST_BASE_DID_2 = 0x40, - DENTIST_BASE_DID_3 = 0x60, - DENTIST_BASE_DID_4 = 0x7e, - DENTIST_MAX_DID = 0x7f -}; - -/* Starting point and step size for each divider range.*/ -enum dentist_divider_range { - DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ - DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ - DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ - DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ - DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ - DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ - DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */ - DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */ - DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 -}; - /* functions shared by other dce clk mgrs */ int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz); int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c index 08f2e253ccb0..906310c3e2eb 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce120/dce120_clk_mgr.c @@ -30,6 +30,7 @@ #include "dce110/dce110_clk_mgr.h" #include "dce120_clk_mgr.h" #include "dce100/dce_clk_mgr.h" +#include "dce120/dce120_hw_sequencer.h" static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /*ClocksStateInvalid - should not be used*/ @@ -45,16 +46,15 @@ static const struct state_dependent_clocks dce120_max_clks_by_state[] = { /** * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info - * @clk_mgr: clock manager base structure + * @clk_mgr_dce: clock manager internal 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_base) +static void dce121_clock_patch_xgmi_ss_info(struct clk_mgr_internal *clk_mgr_dce) { - struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base); enum bp_result result; struct spread_spectrum_info info = { { 0 } }; struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios; @@ -141,5 +141,13 @@ void dce121_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *c { dce120_clk_mgr_construct(ctx, clk_mgr); clk_mgr->base.dprefclk_khz = 625000; + + /* + * The xGMI enabled info is used to determine if audio and display + * clocks need to be adjusted with the WAFL link's SS info. + */ + if (dce121_xgmi_enabled(ctx->dc->hwseq)) + dce121_clock_patch_xgmi_ss_info(clk_mgr); + } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c index 04b12bb2243d..caf8a4a4e442 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c @@ -218,9 +218,23 @@ static void rv1_update_clocks(struct clk_mgr *clk_mgr_base, } } +static void rv1_enable_pme_wa(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct pp_smu_funcs_rv *pp_smu = NULL; + + if (clk_mgr->pp_smu) { + pp_smu = &clk_mgr->pp_smu->rv_funcs; + + if (pp_smu->set_pme_wa_enable) + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); + } +} + static struct clk_mgr_funcs rv1_clk_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = rv1_update_clocks, + .enable_pme_wa = rv1_enable_pme_wa, }; static struct clk_mgr_internal_funcs rv1_clk_internal_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c new file mode 100644 index 000000000000..08a774fc7b67 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c @@ -0,0 +1,391 @@ +/* + * 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 "dccg.h" +#include "clk_mgr_internal.h" + + +#include "dcn20/dcn20_clk_mgr.h" +#include "dce100/dce_clk_mgr.h" +#include "reg_helper.h" +#include "core_types.h" +#include "dm_helpers.h" + +#include "navi10_ip_offset.h" +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "clk/clk_11_0_0_offset.h" +#include "clk/clk_11_0_0_sh_mask.h" + +#undef FN +#define FN(reg_name, field_name) \ + clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name + +#define REG(reg) \ + (clk_mgr->regs->reg) + +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + + +static const struct clk_mgr_registers clk_mgr_regs = { + CLK_REG_LIST_NV10() +}; + +static const struct clk_mgr_shift clk_mgr_shift = { + CLK_MASK_SH_LIST_NV10(__SHIFT) +}; + +static const struct clk_mgr_mask clk_mgr_mask = { + CLK_MASK_SH_LIST_NV10(_MASK) +}; + +uint32_t dentist_get_did_from_divider(int divider) +{ + uint32_t divider_id; + + /* we want to floor here to get higher clock than required rather than lower */ + if (divider < DENTIST_DIVIDER_RANGE_2_START) { + if (divider < DENTIST_DIVIDER_RANGE_1_START) + divider_id = DENTIST_BASE_DID_1; + else + divider_id = DENTIST_BASE_DID_1 + + (divider - DENTIST_DIVIDER_RANGE_1_START) + / DENTIST_DIVIDER_RANGE_1_STEP; + } else if (divider < DENTIST_DIVIDER_RANGE_3_START) { + divider_id = DENTIST_BASE_DID_2 + + (divider - DENTIST_DIVIDER_RANGE_2_START) + / DENTIST_DIVIDER_RANGE_2_STEP; + } else if (divider < DENTIST_DIVIDER_RANGE_4_START) { + divider_id = DENTIST_BASE_DID_3 + + (divider - DENTIST_DIVIDER_RANGE_3_START) + / DENTIST_DIVIDER_RANGE_3_STEP; + } else { + divider_id = DENTIST_BASE_DID_4 + + (divider - DENTIST_DIVIDER_RANGE_4_START) + / DENTIST_DIVIDER_RANGE_4_STEP; + if (divider_id > DENTIST_MAX_DID) + divider_id = DENTIST_MAX_DID; + } + + return divider_id; +} + +void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, + struct dc_state *context) +{ + int i; + + clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz; + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + int dpp_inst, dppclk_khz; + + if (!context->res_ctx.pipe_ctx[i].plane_state) + continue; + + dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst; + dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; + clk_mgr->dccg->funcs->update_dpp_dto( + clk_mgr->dccg, dpp_inst, dppclk_khz); + } +} + +void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr) +{ + int dpp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->dentist_vco_freq_khz / clk_mgr->base.clks.dppclk_khz; + int disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz; + + uint32_t dppclk_wdivider = dentist_get_did_from_divider(dpp_divider); + uint32_t dispclk_wdivider = dentist_get_did_from_divider(disp_divider); + + REG_UPDATE(DENTIST_DISPCLK_CNTL, + DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider); +// REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 5, 100); + REG_UPDATE(DENTIST_DISPCLK_CNTL, + DENTIST_DPPCLK_WDIVIDER, dppclk_wdivider); + REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, 1, 5, 100); +} + + +void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + struct dc *dc = clk_mgr_base->ctx->dc; + struct pp_smu_funcs_nv *pp_smu = NULL; + int display_count; + bool update_dppclk = false; + bool update_dispclk = false; + bool enter_display_off = false; + bool dpp_clock_lowered = false; + struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; + + display_count = clk_mgr_helper_get_active_display_cnt(dc, context); + if (dc->res_pool->pp_smu) + pp_smu = &dc->res_pool->pp_smu->nv_funcs; + + if (display_count == 0) + enter_display_off = true; + + if (enter_display_off == safe_to_lower) { + if (pp_smu && pp_smu->set_display_count) + pp_smu->set_display_count(&pp_smu->pp_smu, display_count); + } + + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { + clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; + if (pp_smu && pp_smu->set_voltage_by_freq) + pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); + } + + if (dc->debug.force_min_dcfclk_mhz > 0) + new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? + new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); + + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { + clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; + if (pp_smu && pp_smu->set_hard_min_dcfclk_by_freq) + pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.dcfclk_khz / 1000); + } + + if (should_set_clock(safe_to_lower, + new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { + clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; + if (pp_smu && pp_smu->set_min_deep_sleep_dcfclk) + pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, clk_mgr_base->clks.dcfclk_deep_sleep_khz / 1000); + } + + if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) { + clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz; + if (pp_smu && pp_smu->set_hard_min_socclk_by_freq) + pp_smu->set_hard_min_socclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.socclk_khz / 1000); + } + + if (should_update_pstate_support(safe_to_lower, new_clocks->p_state_change_support, clk_mgr_base->clks.p_state_change_support)) { + clk_mgr_base->clks.p_state_change_support = new_clocks->p_state_change_support; + if (pp_smu && pp_smu->set_pstate_handshake_support) + pp_smu->set_pstate_handshake_support(&pp_smu->pp_smu, clk_mgr_base->clks.p_state_change_support); + } + + if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) { + clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; + if (pp_smu && pp_smu->set_hard_min_uclk_by_freq) + pp_smu->set_hard_min_uclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.dramclk_khz / 1000); + } + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { + if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) + dpp_clock_lowered = true; + clk_mgr->base.clks.dppclk_khz = new_clocks->dppclk_khz; + + if (pp_smu && pp_smu->set_voltage_by_freq) + pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PIXELCLK, clk_mgr_base->clks.dppclk_khz / 1000); + + update_dppclk = true; + } + + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { + clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; + if (pp_smu && pp_smu->set_voltage_by_freq) + pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_DISPCLK, clk_mgr_base->clks.dispclk_khz / 1000); + + update_dispclk = true; + } + if (dc->config.forced_clocks == false) { + if (dpp_clock_lowered) { + // if clock is being lowered, increase DTO before lowering refclk + dcn20_update_clocks_update_dpp_dto(clk_mgr, context); + dcn20_update_clocks_update_dentist(clk_mgr); + } else { + // if clock is being raised, increase refclk before lowering DTO + if (update_dppclk || update_dispclk) + dcn20_update_clocks_update_dentist(clk_mgr); + if (update_dppclk) + dcn20_update_clocks_update_dpp_dto(clk_mgr, context); + } + } + if (update_dispclk && + dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { + /*update dmcu for wait_loop count*/ + dmcu->funcs->set_psr_wait_loop(dmcu, + clk_mgr_base->clks.dispclk_khz / 1000 / 7); + } +} + +void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr, + struct dc_state *context, + bool safe_to_lower) +{ + struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; + /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */ + int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000; + + if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) { + clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz; + } + + if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) { + clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz; + } + + 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; + } + + if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz)) { + clk_mgr->clks.socclk_khz = new_clocks->socclk_khz; + } + + if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz)) { + clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz; + } + + if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) { + clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz; + } + + if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz)) { + clk_mgr->clks.fclk_khz = fclk_adj; + } + + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) { + clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; + } + + /* Both fclk and dppclk ref are run on the same scemi clock so we + * need to keep the same value for both + */ + if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz) + clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz; + if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz) + clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz; + + dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks); +} + +void dcn2_init_clocks(struct clk_mgr *clk_mgr) +{ + memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); +} + +void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct pp_smu_funcs_nv *pp_smu = NULL; + + if (clk_mgr->pp_smu) { + pp_smu = &clk_mgr->pp_smu->nv_funcs; + + if (pp_smu->set_pme_wa_enable) + pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); + } +} + +static struct clk_mgr_funcs dcn2_funcs = { + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .update_clocks = dcn2_update_clocks, + .init_clocks = dcn2_init_clocks, + .enable_pme_wa = dcn2_enable_pme_wa +}; + + +void dcn20_clk_mgr_construct( + struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg) +{ + clk_mgr->base.ctx = ctx; + clk_mgr->base.funcs = &dcn2_funcs; + clk_mgr->regs = &clk_mgr_regs; + clk_mgr->clk_mgr_shift = &clk_mgr_shift; + clk_mgr->clk_mgr_mask = &clk_mgr_mask; + + clk_mgr->dccg = dccg; + clk_mgr->dfs_bypass_disp_clk = 0; + + clk_mgr->dprefclk_ss_percentage = 0; + clk_mgr->dprefclk_ss_divider = 1000; + clk_mgr->ss_on_dprefclk = false; + + clk_mgr->base.dprefclk_khz = 700000; // 700 MHz planned if VCO is 3.85 GHz, will be retrieved + + if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { + dcn2_funcs.update_clocks = dcn2_update_clocks_fpga; + clk_mgr->dentist_vco_freq_khz = 3850000; + + } else { + /* DFS Slice 2 should be used for DPREFCLK */ + int dprefclk_did = REG_READ(CLK3_CLK2_DFS_CNTL); + /* Convert DPREFCLK DFS Slice DID to actual divider*/ + int target_div = dentist_get_divider_from_did(dprefclk_did); + + /* get FbMult value */ + uint32_t pll_req_reg = REG_READ(CLK3_CLK_PLL_REQ); + struct fixed31_32 pll_req; + + /* set up a fixed-point number + * this works because the int part is on the right edge of the register + * and the frac part is on the left edge + */ + + pll_req = dc_fixpt_from_int(pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_int); + pll_req.value |= pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_frac; + + /* multiply by REFCLK period */ + pll_req = dc_fixpt_mul_int(pll_req, 100000); + + /* integer part is now VCO frequency in kHz */ + clk_mgr->dentist_vco_freq_khz = dc_fixpt_floor(pll_req); + + /* in case we don't get a value from the register, use default */ + if (clk_mgr->dentist_vco_freq_khz == 0) + clk_mgr->dentist_vco_freq_khz = 3850000; + + /* Calculate the DPREFCLK in kHz.*/ + clk_mgr->base.dprefclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->dentist_vco_freq_khz) / target_div; + } + //Integrated_info table does not exist on dGPU projects so should not be referenced + //anywhere in code for dGPUs. + //Also there is no plan for now that DFS BYPASS will be used on NV10/12/14. + clk_mgr->dfs_bypass_enabled = false; + + dce_clock_read_ss_info(clk_mgr); +} + diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h new file mode 100644 index 000000000000..5661a5a89847 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.h @@ -0,0 +1,48 @@ +/* + * 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 + * + */ + +#ifndef __DCN20_CLK_MGR_H__ +#define __DCN20_CLK_MGR_H__ + +void dcn2_update_clocks(struct clk_mgr *dccg, + struct dc_state *context, + bool safe_to_lower); + +void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr, + struct dc_state *context, + bool safe_to_lower); +void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, + struct dc_state *context); + +void dcn2_init_clocks(struct clk_mgr *clk_mgr); + +void dcn20_clk_mgr_construct(struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg); + +uint32_t dentist_get_did_from_divider(int divider); + +#endif //__DCN20_CLK_MGR_H__ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index ed466087c8b5..4ef4dc63e221 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -58,6 +58,14 @@ #include "dc_link_dp.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dsc.h" +#endif + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#include "vm_helper.h" +#endif + #include "dce/dce_i2c.h" #define DC_LOGGER \ @@ -459,7 +467,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 ? pipes->plane_res.hubp->opp_id : 0); + pipes->stream_res.opp->inst); ret = true; } } @@ -531,6 +539,11 @@ static void destruct(struct dc *dc) dc->dcn_ip = NULL; #endif +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + kfree(dc->vm_helper); + dc->vm_helper = NULL; + +#endif } static bool construct(struct dc *dc, @@ -547,6 +560,11 @@ static bool construct(struct dc *dc, enum dce_version dc_version = DCE_VERSION_UNKNOWN; dc->config = init_params->flags; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + // Allocate memory for the vm_helper + dc->vm_helper = kzalloc(sizeof(struct vm_helper), GFP_KERNEL); + +#endif memcpy(&dc->bb_overrides, &init_params->bb_overrides, sizeof(dc->bb_overrides)); dc_dceip = kzalloc(sizeof(*dc_dceip), GFP_KERNEL); @@ -580,6 +598,9 @@ static bool construct(struct dc *dc, } dc->dcn_ip = dcn_ip; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + dc->soc_bounding_box = init_params->soc_bounding_box; +#endif #endif dc_ctx = kzalloc(sizeof(*dc_ctx), GFP_KERNEL); @@ -676,6 +697,21 @@ fail: return false; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +static bool disable_all_writeback_pipes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_state *context) +{ + int i; + + for (i = 0; i < stream->num_wb_info; i++) + stream->writeback_info[i].wb_enabled = false; + + return true; +} +#endif + static void disable_dangling_plane(struct dc *dc, struct dc_state *context) { int i, j; @@ -700,6 +736,9 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) } if (should_disable && old_stream) { dc_rem_all_planes_for_stream(dc, old_stream, dangling_context); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context); +#endif dc->hwss.apply_ctx_for_surface(dc, old_stream, 0, dangling_context); } } @@ -1151,14 +1190,12 @@ struct dc_state *dc_create_state(struct dc *dc) struct dc_state *dc_copy_state(struct dc_state *src_ctx) { int i, j; - struct dc_state *new_ctx = kzalloc(sizeof(struct dc_state), - GFP_KERNEL); + struct dc_state *new_ctx = kmemdup(src_ctx, + sizeof(struct dc_state), GFP_KERNEL); if (!new_ctx) return NULL; - memcpy(new_ctx, src_ctx, sizeof(struct dc_state)); - for (i = 0; i < MAX_PIPES; i++) { struct pipe_ctx *cur_pipe = &new_ctx->res_ctx.pipe_ctx[i]; @@ -1370,6 +1407,9 @@ static enum surface_update_type det_surface_update(const struct dc *dc, update_flags->raw = 0; // Reset all flags + if (u->flip_addr) + update_flags->bits.addr_update = 1; + if (!is_surface_in_context(context, u->surface)) { update_flags->bits.new_plane = 1; return UPDATE_TYPE_FULL; @@ -1456,6 +1496,11 @@ static enum surface_update_type check_update_surfaces_for_stream( if (stream_update->dpms_off) return UPDATE_TYPE_FULL; + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (stream_update->wb_update) + return UPDATE_TYPE_FULL; +#endif } for (i = 0 ; i < surface_count; i++) { @@ -1600,6 +1645,26 @@ static void copy_surface_update_to_plane( sizeof(struct dc_transfer_func_distributed_points)); } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (srf_update->func_shaper && + (surface->in_shaper_func != + srf_update->func_shaper)) + memcpy(surface->in_shaper_func, srf_update->func_shaper, + sizeof(*surface->in_shaper_func)); + + if (srf_update->lut3d_func && + (surface->lut3d_func != + srf_update->lut3d_func)) + memcpy(surface->lut3d_func, srf_update->lut3d_func, + sizeof(*surface->lut3d_func)); + + if (srf_update->blend_tf && + (surface->blend_tf != + srf_update->blend_tf)) + memcpy(surface->blend_tf, srf_update->blend_tf, + sizeof(*surface->blend_tf)); + +#endif if (srf_update->input_csc_color_matrix) surface->input_csc_color_matrix = *srf_update->input_csc_color_matrix; @@ -1609,6 +1674,101 @@ static void copy_surface_update_to_plane( *srf_update->coeff_reduction_factor; } +static void copy_stream_update_to_stream(struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream, + const struct dc_stream_update *update) +{ + if (update == NULL || stream == NULL) + return; + + if (update->src.height && update->src.width) + stream->src = update->src; + + if (update->dst.height && update->dst.width) + stream->dst = update->dst; + + if (update->out_transfer_func && + stream->out_transfer_func != update->out_transfer_func) { + stream->out_transfer_func->sdr_ref_white_level = + update->out_transfer_func->sdr_ref_white_level; + stream->out_transfer_func->tf = update->out_transfer_func->tf; + stream->out_transfer_func->type = + update->out_transfer_func->type; + memcpy(&stream->out_transfer_func->tf_pts, + &update->out_transfer_func->tf_pts, + sizeof(struct dc_transfer_func_distributed_points)); + } + + if (update->hdr_static_metadata) + stream->hdr_static_metadata = *update->hdr_static_metadata; + + if (update->abm_level) + stream->abm_level = *update->abm_level; + + if (update->periodic_interrupt0) + stream->periodic_interrupt0 = *update->periodic_interrupt0; + + if (update->periodic_interrupt1) + stream->periodic_interrupt1 = *update->periodic_interrupt1; + + if (update->gamut_remap) + stream->gamut_remap_matrix = *update->gamut_remap; + + /* Note: this being updated after mode set is currently not a use case + * however if it arises OCSC would need to be reprogrammed at the + * minimum + */ + if (update->output_color_space) + stream->output_color_space = *update->output_color_space; + + if (update->output_csc_transform) + stream->csc_color_matrix = *update->output_csc_transform; + + if (update->vrr_infopacket) + stream->vrr_infopacket = *update->vrr_infopacket; + + if (update->dpms_off) + stream->dpms_off = *update->dpms_off; + + if (update->vsc_infopacket) + stream->vsc_infopacket = *update->vsc_infopacket; + + if (update->vsp_infopacket) + stream->vsp_infopacket = *update->vsp_infopacket; + + if (update->dither_option) + stream->dither_option = *update->dither_option; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* update current stream with writeback info */ + if (update->wb_update) { + int i; + + stream->num_wb_info = update->wb_update->num_wb_info; + ASSERT(stream->num_wb_info <= MAX_DWB_PIPES); + for (i = 0; i < stream->num_wb_info; i++) + stream->writeback_info[i] = + update->wb_update->writeback_info[i]; + } +#endif +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) + if (update->dsc_config) { + struct dc_dsc_config old_dsc_cfg = stream->timing.dsc_cfg; + uint32_t old_dsc_enabled = stream->timing.flags.DSC; + uint32_t enable_dsc = (update->dsc_config->num_slices_h != 0 && + update->dsc_config->num_slices_v != 0); + + stream->timing.dsc_cfg = *update->dsc_config; + stream->timing.flags.DSC = enable_dsc; + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, + true)) { + stream->timing.dsc_cfg = old_dsc_cfg; + stream->timing.flags.DSC = old_dsc_enabled; + } + } +#endif +} + static void commit_planes_do_stream_update(struct dc *dc, struct dc_stream_state *stream, struct dc_stream_update *stream_update, @@ -1648,13 +1808,29 @@ static void commit_planes_do_stream_update(struct dc *dc, dc_stream_program_csc_matrix(dc, stream); if (stream_update->dither_option) { +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); +#endif resource_build_bit_depth_reduction_params(pipe_ctx->stream, &pipe_ctx->stream->bit_depth_params); pipe_ctx->stream_res.opp->funcs->opp_program_fmt(pipe_ctx->stream_res.opp, &stream->bit_depth_params, &stream->clamping); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (odm_pipe) + odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); +#endif } +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) + if (stream_update->dsc_config && dc->hwss.pipe_control_lock_global) { + dc->hwss.pipe_control_lock_global(dc, pipe_ctx, true); + dp_update_dsc_config(pipe_ctx); + dc->hwss.pipe_control_lock_global(dc, pipe_ctx, false); + } +#endif /* Full fe update*/ if (update_type == UPDATE_TYPE_FAST) continue; @@ -1728,6 +1904,30 @@ static void commit_planes_for_stream(struct dc *dc, return; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (!IS_DIAG_DC(dc->ctx->dce_environment)) { + for (i = 0; i < surface_count; i++) { + struct dc_plane_state *plane_state = srf_updates[i].surface; + /*set logical flag for lock/unlock use*/ + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; + if (!pipe_ctx->plane_state) + continue; + if (pipe_ctx->plane_state != plane_state) + continue; + plane_state->triplebuffer_flips = false; + if (update_type == UPDATE_TYPE_FAST && + dc->hwss.program_triplebuffer != NULL && + !plane_state->flip_immediate && + !dc->debug.disable_tri_buf) { + /*triple buffer for VUpdate only*/ + plane_state->triplebuffer_flips = true; + } + } + } + } +#endif + // Update Type FULL, Surface updates for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; @@ -1746,6 +1946,16 @@ static void commit_planes_for_stream(struct dc *dc, if (update_type == UPDATE_TYPE_FAST) continue; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + ASSERT(!pipe_ctx->plane_state->triplebuffer_flips); + + if (dc->hwss.program_triplebuffer != NULL && + !dc->debug.disable_tri_buf) { + /*turn off triple buffer for full update*/ + dc->hwss.program_triplebuffer( + dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); + } +#endif stream_status = stream_get_status(context, pipe_ctx->stream); @@ -1762,6 +1972,26 @@ static void commit_planes_for_stream(struct dc *dc, */ dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (dc->hwss.set_flip_control_gsl) + for (i = 0; i < surface_count; i++) { + struct dc_plane_state *plane_state = srf_updates[i].surface; + + for (j = 0; j < dc->res_pool->pipe_count; j++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; + + if (pipe_ctx->stream != stream) + continue; + + if (pipe_ctx->plane_state != plane_state) + continue; + + // GSL has to be used for flip immediate + dc->hwss.set_flip_control_gsl(pipe_ctx, + plane_state->flip_immediate); + } + } +#endif /* Perform requested Updates */ for (i = 0; i < surface_count; i++) { struct dc_plane_state *plane_state = srf_updates[i].surface; @@ -1774,7 +2004,15 @@ static void commit_planes_for_stream(struct dc *dc, if (pipe_ctx->plane_state != plane_state) continue; - +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /*program triple buffer after lock based on flip type*/ + if (dc->hwss.program_triplebuffer != NULL && + !dc->debug.disable_tri_buf) { + /*only enable triplebuffer for fast_update*/ + dc->hwss.program_triplebuffer( + dc, pipe_ctx, plane_state->triplebuffer_flips); + } +#endif if (srf_updates[i].flip_addr) dc->hwss.update_plane_addr(dc, pipe_ctx); } @@ -1859,6 +2097,8 @@ void dc_commit_updates_for_stream(struct dc *dc, } } + copy_stream_update_to_stream(dc, context, stream, stream_update); + commit_planes_for_stream( dc, srf_updates, @@ -1932,6 +2172,12 @@ void dc_set_power_state( enum dc_acpi_cm_power_state power_state) { struct kref refcount; + struct display_mode_lib *dml = kzalloc(sizeof(struct display_mode_lib), + GFP_KERNEL); + + ASSERT(dml); + if (!dml) + return; switch (power_state) { case DC_ACPI_CM_POWER_STATE_D0: @@ -1948,15 +2194,20 @@ void dc_set_power_state( /* Preserve refcount */ refcount = dc->current_state->refcount; + /* Preserve display mode lib */ + memcpy(dml, &dc->current_state->bw_ctx.dml, sizeof(struct display_mode_lib)); + dc_resource_state_destruct(dc->current_state); memset(dc->current_state, 0, sizeof(*dc->current_state)); dc->current_state->refcount = refcount; + dc->current_state->bw_ctx.dml = *dml; break; } + kfree(dml); } void dc_resume(struct dc *dc) 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 f48863cf796b..8dbf759eba45 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -45,6 +45,10 @@ #include "dpcd_defs.h" #include "dmcu.h" #include "hw/clk_mgr.h" +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "resource.h" +#endif +#include "hw/clk_mgr.h" #define DC_LOGGER_INIT(logger) @@ -219,8 +223,11 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type) return true; } - if (link->connector_signal == SIGNAL_TYPE_EDP) + if (link->connector_signal == SIGNAL_TYPE_EDP) { + /*in case it is not on*/ + link->dc->hwss.edp_power_control(link, true); link->dc->hwss.edp_wait_for_hpd_ready(link, true); + } /* todo: may need to lock gpio access */ hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); @@ -522,11 +529,31 @@ static void read_edp_current_link_settings_on_detect(struct dc_link *link) union lane_count_set lane_count_set = { {0} }; uint8_t link_bw_set; uint8_t link_rate_set; + uint32_t read_dpcd_retry_cnt = 10; + enum dc_status status = DC_ERROR_UNEXPECTED; + int i; // Read DPCD 00101h to find out the number of lanes currently set - core_link_read_dpcd(link, DP_LANE_COUNT_SET, - &lane_count_set.raw, sizeof(lane_count_set)); - link->cur_link_settings.lane_count = lane_count_set.bits.LANE_COUNT_SET; + for (i = 0; i < read_dpcd_retry_cnt; i++) { + status = core_link_read_dpcd( + link, + DP_LANE_COUNT_SET, + &lane_count_set.raw, + sizeof(lane_count_set)); + /* First DPCD read after VDD ON can fail if the particular board + * does not have HPD pin wired correctly. So if DPCD read fails, + * which it should never happen, retry a few times. Target worst + * case scenario of 80 ms. + */ + if (status == DC_OK) { + link->cur_link_settings.lane_count = lane_count_set.bits.LANE_COUNT_SET; + break; + } + + msleep(8); + } + + ASSERT(status == DC_OK); // Read DPCD 00100h to find if standard link rates are set core_link_read_dpcd(link, DP_LINK_BW_SET, @@ -680,6 +707,11 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) if (dc_is_virtual_signal(link->connector_signal)) return false; + if ((link->connector_signal == SIGNAL_TYPE_LVDS || + link->connector_signal == SIGNAL_TYPE_EDP) && + link->local_sink) + return true; + if (false == dc_link_detect_sink(link, &new_connection_type)) { BREAK_TO_DEBUGGER(); return false; @@ -690,14 +722,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) * up to date, especially if link was powered on by GOP. */ read_edp_current_link_settings_on_detect(link); - if (link->local_sink) - return true; } - if (link->connector_signal == SIGNAL_TYPE_LVDS && - link->local_sink) - return true; - prev_sink = link->local_sink; if (prev_sink != NULL) { dc_sink_retain(prev_sink); @@ -964,6 +990,12 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) link->type = dc_connection_none; sink_caps.signal = SIGNAL_TYPE_NONE; + /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk + * is not cleared. If we emulate a DP signal on this connection, it thinks + * the dongle is still there and limits the number of modes we can emulate. + * Clear dongle_max_pix_clk on disconnect to fix this + */ + link->dongle_max_pix_clk = 0; } LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p dpcd same=%d edid same=%d\n", @@ -1160,7 +1192,7 @@ static bool construct( link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { - dm_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", + dm_output_to_console("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", __func__, init_params->connector_index, link->link_id.type, OBJECT_TYPE_CONNECTOR); goto create_fail; @@ -1478,6 +1510,10 @@ static enum dc_status enable_link_dp( if (link_settings.link_rate == LINK_RATE_LOW) skip_video_pattern = false; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + dp_set_fec_ready(link, true); +#endif + if (perform_link_training_with_retries( link, &link_settings, @@ -1489,6 +1525,9 @@ static enum dc_status enable_link_dp( else status = DC_FAIL_DP_LINK_TRAINING; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + dp_set_fec_enable(link, true); +#endif return status; } @@ -2111,6 +2150,14 @@ static void disable_link(struct dc_link *link, enum signal_type signal) dp_disable_link_phy(link, signal); else dp_disable_link_phy_mst(link, signal); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + + if (dc_is_dp_sst_signal(signal) || + link->mst_stream_alloc_table.stream_count == 0) { + dp_set_fec_enable(link, false); + dp_set_fec_ready(link, false); + } +#endif } else link->link_enc->funcs->disable_output(link->link_enc, signal); @@ -2707,13 +2754,30 @@ void core_link_enable_stream( if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) allocate_mst_payload(pipe_ctx); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (pipe_ctx->stream->timing.flags.DSC && + (dc_is_dp_signal(pipe_ctx->stream->signal) || + dc_is_virtual_signal(pipe_ctx->stream->signal))) { + dp_set_dsc_enable(pipe_ctx, true); + pipe_ctx->stream_res.tg->funcs->wait_for_state( + pipe_ctx->stream_res.tg, + CRTC_STATE_VBLANK); + } +#endif core_dc->hwss.unblank_stream(pipe_ctx, &pipe_ctx->stream->link->cur_link_settings); if (dc_is_dp_signal(pipe_ctx->stream->signal)) enable_stream_features(pipe_ctx); } +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + else { // if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) + if (dc_is_dp_signal(pipe_ctx->stream->signal) || + dc_is_virtual_signal(pipe_ctx->stream->signal)) + dp_set_dsc_enable(pipe_ctx, true); + } +#endif } void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) @@ -2754,6 +2818,12 @@ 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->link, pipe_ctx->stream->signal); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (pipe_ctx->stream->timing.flags.DSC && + dc_is_dp_signal(pipe_ctx->stream->signal)) { + dp_set_dsc_enable(pipe_ctx, false); + } +#endif } void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) @@ -2821,6 +2891,14 @@ uint32_t dc_bandwidth_in_kbps_from_timing( uint32_t bits_per_channel = 0; uint32_t kbps; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (timing->flags.DSC) { + kbps = (timing->pix_clk_100hz * timing->dsc_cfg.bits_per_pixel); + kbps = kbps / 160 + ((kbps % 160) ? 1 : 0); + return kbps; + } +#endif + switch (timing->display_color_depth) { case COLOR_DEPTH_666: bits_per_channel = 6; @@ -2972,6 +3050,33 @@ uint32_t dc_link_bandwidth_kbps( link_bw_kbps *= 8; /* 8 bits per byte*/ link_bw_kbps *= link_setting->lane_count; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { + /* Account for FEC overhead. + * We have to do it based on caps, + * and not based on FEC being set ready, + * because FEC is set ready too late in + * the process to correctly be picked up + * by mode enumeration. + * + * There's enough zeros at the end of 'kbps' + * that make the below operation 100% precise + * for our purposes. + * 'long long' makes it work even for HDMI 2.1 + * max bandwidth (and much, much bigger bandwidths + * than that, actually). + * + * NOTE: Reducing link BW by 3% may not be precise + * because it may be a stream BT that increases by 3%, and so + * 1/1.03 = 0.970873 factor should have been used instead, + * but the difference is minimal and is in a safe direction, + * which all works well around potential ambiguity of DP 1.4a spec. + */ + link_bw_kbps = mul_u64_u32_shr(BIT_ULL(32) * 970LL / 1000, + link_bw_kbps, 32); + } +#endif + return link_bw_kbps; } @@ -2984,4 +3089,3 @@ const struct dc_link_settings *dc_link_get_link_cap( return &link->preferred_link_setting; return &link->verified_link_cap; } - 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 eecc631ca4f8..e6da8506128b 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 @@ -93,6 +93,8 @@ union hdmi_scdc_status_flags_data { uint8_t CH2_LOCKED:1; uint8_t RESERVED:4; uint8_t RESERVED2:8; + uint8_t RESERVED3:8; + } fields; }; @@ -109,14 +111,10 @@ union hdmi_scdc_ced_data { uint8_t CH2_7HIGH:7; uint8_t CH2_VALID:1; uint8_t CHECKSUM:8; - } fields; -}; - -union hdmi_scdc_test_config_Data { - uint8_t byte; - struct { - uint8_t TEST_READ_REQUEST_DELAY:7; - uint8_t TEST_READ_REQUEST: 1; + uint8_t RESERVED:8; + uint8_t RESERVED2:8; + uint8_t RESERVED3:8; + uint8_t RESERVED4:4; } fields; }; 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 65d6caedbd82..056be4c34a98 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 @@ -4,6 +4,12 @@ #include "dc_link_dp.h" #include "dm_helpers.h" #include "opp.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dsc.h" +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "resource.h" +#endif #include "inc/core_types.h" #include "link_hwss.h" @@ -89,6 +95,29 @@ static void dpcd_set_training_pattern( dpcd_pattern.v1_4.TRAINING_PATTERN_SET); } +static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link) +{ + enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2; + struct encoder_feature_support *features = &link->link_enc->features; + struct dpcd_caps *dpcd_caps = &link->dpcd_caps; + + if (features->flags.bits.IS_TPS3_CAPABLE) + highest_tp = HW_DP_TRAINING_PATTERN_3; + + if (features->flags.bits.IS_TPS4_CAPABLE) + highest_tp = HW_DP_TRAINING_PATTERN_4; + + if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED && + highest_tp >= HW_DP_TRAINING_PATTERN_4) + return HW_DP_TRAINING_PATTERN_4; + + if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED && + highest_tp >= HW_DP_TRAINING_PATTERN_3) + return HW_DP_TRAINING_PATTERN_3; + + return HW_DP_TRAINING_PATTERN_2; +} + static void dpcd_set_link_settings( struct dc_link *link, const struct link_training_settings *lt_settings) @@ -97,6 +126,7 @@ static void dpcd_set_link_settings( union down_spread_ctrl downspread = { {0} }; union lane_count_set lane_count_set = { {0} }; + enum hw_dp_training_pattern hw_tr_pattern; downspread.raw = (uint8_t) (lt_settings->link_settings.link_spread); @@ -106,8 +136,13 @@ static void dpcd_set_link_settings( lane_count_set.bits.ENHANCED_FRAMING = 1; - lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = - link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + hw_tr_pattern = get_supported_tp(link); + if (hw_tr_pattern != HW_DP_TRAINING_PATTERN_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, &downspread.raw, sizeof(downspread)); @@ -698,29 +733,6 @@ static bool perform_post_lt_adj_req_sequence( } -static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link) -{ - enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2; - struct encoder_feature_support *features = &link->link_enc->features; - struct dpcd_caps *dpcd_caps = &link->dpcd_caps; - - if (features->flags.bits.IS_TPS3_CAPABLE) - highest_tp = HW_DP_TRAINING_PATTERN_3; - - if (features->flags.bits.IS_TPS4_CAPABLE) - highest_tp = HW_DP_TRAINING_PATTERN_4; - - if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED && - highest_tp >= HW_DP_TRAINING_PATTERN_4) - return HW_DP_TRAINING_PATTERN_4; - - if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED && - highest_tp >= HW_DP_TRAINING_PATTERN_3) - return HW_DP_TRAINING_PATTERN_3; - - return HW_DP_TRAINING_PATTERN_2; -} - static enum link_training_result get_cr_failure(enum dc_lane_count ln_count, union lane_status *dpcd_lane_status) { @@ -1624,8 +1636,7 @@ static bool decide_edp_link_settings(struct dc_link *link, struct dc_link_settin uint32_t link_bw; if (link->dpcd_caps.dpcd_rev.raw < DPCD_REV_14 || - link->dpcd_caps.edp_supported_link_rates_count == 0 || - link->dc->config.optimize_edp_link_rate == false) { + link->dpcd_caps.edp_supported_link_rates_count == 0) { *link_setting = link->verified_link_cap; return true; } @@ -2542,6 +2553,30 @@ static bool retrieve_link_cap(struct dc_link *link) dp_hw_fw_revision.ieee_fw_rev, sizeof(dp_hw_fw_revision.ieee_fw_rev)); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + memset(&link->dpcd_caps.dsc_caps, '\0', + sizeof(link->dpcd_caps.dsc_caps)); + memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap)); + /* Read DSC and FEC sink capabilities if DP revision is 1.4 and up */ + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14) { + status = core_link_read_dpcd( + link, + DP_FEC_CAPABILITY, + &link->dpcd_caps.fec_cap.raw, + sizeof(link->dpcd_caps.fec_cap.raw)); + status = core_link_read_dpcd( + link, + DP_DSC_SUPPORT, + link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, + sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw)); + status = core_link_read_dpcd( + link, + DP_DSC_BRANCH_OVERALL_THROUGHPUT_0, + link->dpcd_caps.dsc_caps.dsc_ext_caps.raw, + sizeof(link->dpcd_caps.dsc_caps.dsc_ext_caps.raw)); + } +#endif + /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); @@ -2609,7 +2644,8 @@ void detect_edp_sink_caps(struct dc_link *link) memset(supported_link_rates, 0, sizeof(supported_link_rates)); if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && - link->dc->config.optimize_edp_link_rate) { + (link->dc->config.optimize_edp_link_rate || + link->reported_link_cap.link_rate == LINK_RATE_UNKNOWN)) { // 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)); @@ -2624,6 +2660,9 @@ void detect_edp_sink_caps(struct dc_link *link) link_rate = linkRateInKHzToLinkRateMultiplier(link_rate_in_khz); link->dpcd_caps.edp_supported_link_rates[link->dpcd_caps.edp_supported_link_rates_count] = link_rate; link->dpcd_caps.edp_supported_link_rates_count++; + + if (link->reported_link_cap.link_rate < link_rate) + link->reported_link_cap.link_rate = link_rate; } } } @@ -2665,6 +2704,14 @@ static void set_crtc_test_pattern(struct dc_link *link, stream->timing.display_color_depth; struct bit_depth_reduction_params params; struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + int width = pipe_ctx->stream->timing.h_addressable + + pipe_ctx->stream->timing.h_border_left + + pipe_ctx->stream->timing.h_border_right; + int height = pipe_ctx->stream->timing.v_addressable + + pipe_ctx->stream->timing.v_border_bottom + + pipe_ctx->stream->timing.v_border_top; +#endif memset(¶ms, 0, sizeof(params)); @@ -2708,6 +2755,30 @@ static void set_crtc_test_pattern(struct dc_link *link, if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, controller_test_pattern, color_depth); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + else if (opp->funcs->opp_set_disp_pattern_generator) { + struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (bot_odm_pipe) { + struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp; + + bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, ¶ms); + width /= 2; + bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp, + controller_test_pattern, + color_depth, + NULL, + width, + height); + } + opp->funcs->opp_set_disp_pattern_generator(opp, + controller_test_pattern, + color_depth, + NULL, + width, + height); + } +#endif } break; case DP_TEST_PATTERN_VIDEO_MODE: @@ -2720,6 +2791,30 @@ static void set_crtc_test_pattern(struct dc_link *link, pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + else if (opp->funcs->opp_set_disp_pattern_generator) { + struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (bot_odm_pipe) { + struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp; + + bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, ¶ms); + width /= 2; + bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + color_depth, + NULL, + width, + height); + } + opp->funcs->opp_set_disp_pattern_generator(opp, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + color_depth, + NULL, + width, + height); + } +#endif } break; @@ -2894,3 +2989,67 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable) core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1); } + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +void dp_set_fec_ready(struct dc_link *link, bool ready) +{ + /* FEC has to be "set ready" before the link training. + * The policy is to always train with FEC + * if the sink supports it and leave it enabled on link. + * If FEC is not supported, disable it. + */ + struct link_encoder *link_enc = link->link_enc; + uint8_t fec_config = 0; + + if (link->dc->debug.disable_fec || + IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)) + return; + + if (link_enc->funcs->fec_set_ready && + link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { + if (link->fec_state == dc_link_fec_not_ready && ready) { + fec_config = 1; + if (core_link_write_dpcd(link, + DP_FEC_CONFIGURATION, + &fec_config, + sizeof(fec_config)) == DC_OK) { + link_enc->funcs->fec_set_ready(link_enc, true); + link->fec_state = dc_link_fec_ready; + } else { + dm_error("dpcd write failed to set fec_ready"); + } + } else if (link->fec_state == dc_link_fec_ready && !ready) { + fec_config = 0; + core_link_write_dpcd(link, + DP_FEC_CONFIGURATION, + &fec_config, + sizeof(fec_config)); + link->link_enc->funcs->fec_set_ready( + link->link_enc, false); + link->fec_state = dc_link_fec_not_ready; + } + } +} + +void dp_set_fec_enable(struct dc_link *link, bool enable) +{ + struct link_encoder *link_enc = link->link_enc; + + if (link->dc->debug.disable_fec || + IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)) + return; + + if (link_enc->funcs->fec_set_enable && + link->dpcd_caps.fec_cap.bits.FEC_CAPABLE) { + if (link->fec_state == dc_link_fec_ready && enable) { + msleep(1); + link_enc->funcs->fec_set_enable(link_enc, true); + link->fec_state = dc_link_fec_enabled; + } else if (link->fec_state == dc_link_fec_enabled && !enable) { + link_enc->funcs->fec_set_enable(link_enc, false); + link->fec_state = dc_link_fec_ready; + } + } +} +#endif + 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 b0dea759cd86..2d019e1f6135 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 @@ -12,6 +12,12 @@ #include "dc_link_ddc.h" #include "dm_helpers.h" #include "dpcd_defs.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dsc.h" +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "resource.h" +#endif enum dc_status core_link_read_dpcd( struct dc_link *link, @@ -360,3 +366,141 @@ void dp_retrain_link_dp_test(struct dc_link *link, } } } + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#define DC_LOGGER \ + dsc->ctx->logger +static void dsc_optc_config_log(struct display_stream_compressor *dsc, + struct dsc_optc_config *config) +{ + DC_LOG_DSC("Setting optc DSC config at DSC inst %d", dsc->inst); + DC_LOG_DSC("\n\tbytes_per_pixel %d\n\tis_pixel_format_444 %d\n\tslice_width %d", + config->bytes_per_pixel, + config->is_pixel_format_444, config->slice_width); +} + +static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc_stream_state *stream = pipe_ctx->stream; + bool result = false; + + if (IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) + result = true; + else + result = dm_helpers_dp_write_dsc_enable(core_dc->ctx, stream, enable); + return result; +} + +/* This has to be done after DSC was enabled on RX first, i.e. after dp_enable_dsc_on_rx() had been called + */ +static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + struct dc *core_dc = pipe_ctx->stream->ctx->dc; + struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (enable) { + /* TODO proper function */ + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg; + enum optc_dsc_mode optc_dsc_mode; + uint8_t dsc_packed_pps[128]; + + /* Enable DSC hw block */ + dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + + dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps[0]); + if (odm_pipe) { + struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc; + uint8_t dsc_packed_pps_odm[128]; + + dsc_cfg.pic_width /= 2; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= 2; + dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]); + bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg, &dsc_packed_pps_odm[0]); + bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst); + } + dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + + optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED; + + dsc_optc_config_log(dsc, &dsc_optc_cfg); + /* Enable DSC in encoder */ + if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment) && pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config) + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width, + &dsc_packed_pps[0]); + + /* Enable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, + optc_dsc_mode, + dsc_optc_cfg.bytes_per_pixel, + dsc_optc_cfg.slice_width); + } else { + /* disable DSC in OPTC */ + pipe_ctx->stream_res.tg->funcs->set_dsc_config( + pipe_ctx->stream_res.tg, + OPTC_DSC_DISABLED, 0, 0); + + /* disable DSC in stream encoder */ + if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config( + pipe_ctx->stream_res.stream_enc, + OPTC_DSC_DISABLED, 0, 0, NULL); + } + + /* disable DSC block */ + pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); + if (odm_pipe) + odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } +} + +bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + bool result = false; + + if (!pipe_ctx->stream->timing.flags.DSC) + goto out; + if (!dsc) + goto out; + + if (enable) { + if (dp_set_dsc_on_rx(pipe_ctx, true)) { + dp_set_dsc_on_stream(pipe_ctx, true); + result = true; + } + } else { + dp_set_dsc_on_rx(pipe_ctx, false); + dp_set_dsc_on_stream(pipe_ctx, false); + result = true; + } +out: + return result; +} + +bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx) +{ + struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; + + if (!pipe_ctx->stream->timing.flags.DSC) + return false; + if (!dsc) + return false; + + dp_set_dsc_on_stream(pipe_ctx, true); + return true; +} + +#endif + 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 1b5756590a6a..51a78283a86d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -49,6 +49,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/dcn10_resource.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dcn20/dcn20_resource.h" +#endif #include "dce120/dce120_resource.h" #define DC_LOGGER_INIT(logger) @@ -100,6 +103,12 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) dc_version = DCN_VERSION_1_01; break; #endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case FAMILY_NV: + dc_version = DCN_VERSION_2_0; + break; +#endif default: dc_version = DCE_VERSION_UNKNOWN; break; @@ -154,38 +163,34 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case DCN_VERSION_2_0: + res_pool = dcn20_create_resource_pool(init_data, dc); + break; +#endif + default: break; } if (res_pool != NULL) { struct dc_firmware_info fw_info = { { 0 } }; - if (dc->ctx->dc_bios->funcs->get_firmware_info( - dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) { - res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency; - - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { - // On FPGA these dividers are currently not configured by GDB - res_pool->ref_clocks.dccg_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz; - } else if (res_pool->dccg && res_pool->hubbub) { - // If DCCG reference frequency cannot be determined (usually means not set to xtalin) then this is a critical error - // as this value must be known for DCHUB programming - (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, - fw_info.pll_info.crystal_frequency, - &res_pool->ref_clocks.dccg_ref_clock_inKhz); - - // Similarly, if DCHUB reference frequency cannot be determined, then it is also a critical error - (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, - res_pool->ref_clocks.dccg_ref_clock_inKhz, - &res_pool->ref_clocks.dchub_ref_clock_inKhz); - } else { - // Not all ASICs have DCCG sw component - res_pool->ref_clocks.dccg_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz; - res_pool->ref_clocks.dchub_ref_clock_inKhz = res_pool->ref_clocks.xtalin_clock_inKhz; - } - } else - ASSERT_CRITICAL(false); + if (dc->ctx->dc_bios->funcs->get_firmware_info(dc->ctx->dc_bios, + &fw_info) == BP_RESULT_OK) { + res_pool->ref_clocks.xtalin_clock_inKhz = + fw_info.pll_info.crystal_frequency; + /* initialize with firmware data first, no all + * ASIC have DCCG SW component. FPGA or + * simulation need initialization of + * dccg_ref_clock_inKhz, dchub_ref_clock_inKhz + * with xtalin_clock_inKhz + */ + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } else + ASSERT_CRITICAL(false); } return res_pool; @@ -1996,6 +2001,9 @@ enum dc_status resource_map_pool_resources( if (context->streams[i] == stream) { context->stream_status[i].primary_otg_inst = pipe_ctx->stream_res.tg->inst; context->stream_status[i].stream_enc_inst = pipe_ctx->stream_res.stream_enc->id; + context->stream_status[i].audio_inst = + pipe_ctx->stream_res.audio ? pipe_ctx->stream_res.audio->inst : -1; + return 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 7fe0dbe30666..af7f8be230f7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -108,6 +108,17 @@ 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; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + memset(&stream->timing.dsc_cfg, 0, sizeof(stream->timing.dsc_cfg)); + stream->timing.dsc_cfg.num_slices_h = 0; + stream->timing.dsc_cfg.num_slices_v = 0; + stream->timing.dsc_cfg.bits_per_pixel = 128; + stream->timing.dsc_cfg.block_pred_enable = 1; + stream->timing.dsc_cfg.linebuf_depth = 9; + stream->timing.dsc_cfg.version_minor = 2; + stream->timing.dsc_cfg.ycbcr422_simple = 0; +#endif + update_stream_signal(stream, dc_sink_data); stream->out_transfer_func = dc_create_transfer_func(); @@ -170,12 +181,10 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) { struct dc_stream_state *new_stream; - new_stream = kzalloc(sizeof(struct dc_stream_state), GFP_KERNEL); + new_stream = kmemdup(stream, sizeof(struct dc_stream_state), GFP_KERNEL); if (!new_stream) return NULL; - memcpy(new_stream, stream, sizeof(struct dc_stream_state)); - if (new_stream->sink) dc_sink_retain(new_stream->sink); @@ -358,6 +367,121 @@ bool dc_stream_set_cursor_position( return true; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dc_stream_add_writeback(struct dc *dc, + struct dc_stream_state *stream, + struct dc_writeback_info *wb_info) +{ + bool isDrc = false; + int i = 0; + struct dwbc *dwb; + + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } + + if (wb_info == NULL) { + dm_error("DC: dc_writeback_info is NULL!\n"); + return false; + } + + if (wb_info->dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; + } + + wb_info->dwb_params.out_transfer_func = stream->out_transfer_func; + + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + dwb->dwb_is_drc = false; + + /* recalculate and apply DML parameters */ + + for (i = 0; i < stream->num_wb_info; i++) { + /*dynamic update*/ + if (stream->writeback_info[i].wb_enabled && + stream->writeback_info[i].dwb_pipe_inst == wb_info->dwb_pipe_inst) { + stream->writeback_info[i] = *wb_info; + isDrc = true; + } + } + + if (!isDrc) { + stream->writeback_info[stream->num_wb_info++] = *wb_info; + } + + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* enable writeback */ + if (dc->hwss.enable_writeback) { + struct dc_stream_status *stream_status = dc_stream_get_status(stream); + struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) { + /* writeback pipe already enabled, only need to update */ + dc->hwss.update_writeback(dc, stream_status, wb_info); + } else { + /* Enable writeback pipe from scratch*/ + dc->hwss.enable_writeback(dc, stream_status, wb_info); + } + } + + return true; +} + +bool dc_stream_remove_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst) +{ + int i = 0, j = 0; + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } + + if (dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; + } + +// stream->writeback_info[dwb_pipe_inst].wb_enabled = false; + for (i = 0; i < stream->num_wb_info; i++) { + /*dynamic update*/ + if (stream->writeback_info[i].wb_enabled && + stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) { + stream->writeback_info[i].wb_enabled = false; + } + } + + /* remove writeback info for disabled writeback pipes from stream */ + for (i = 0, j = 0; i < stream->num_wb_info; i++) { + if (stream->writeback_info[i].wb_enabled) { + if (i != j) + /* trim the array */ + stream->writeback_info[j] = stream->writeback_info[i]; + j++; + } + } + stream->num_wb_info = j; + + /* recalculate and apply DML parameters */ + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* disable writeback */ + if (dc->hwss.disable_writeback) + dc->hwss.disable_writeback(dc, dwb_pipe_inst); + + return true; +} +#endif + uint32_t dc_stream_get_vblank_counter(const struct dc_stream_state *stream) { uint8_t i; @@ -442,6 +566,77 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, return ret; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream) +{ + bool status = true; + struct pipe_ctx *pipe = NULL; + int i; + + if (!dc->hwss.dmdata_status_done) + return false; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream == stream) + break; + } + /* Stream not found, by default we'll assume HUBP fetched dm data */ + if (i == MAX_PIPES) + return true; + + status = dc->hwss.dmdata_status_done(pipe); + return status; +} + +bool dc_stream_set_dynamic_metadata(struct dc *dc, + struct dc_stream_state *stream, + struct dc_dmdata_attributes *attr) +{ + struct pipe_ctx *pipe_ctx = NULL; + struct hubp *hubp; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe_ctx->stream == stream) + break; + } + + if (i == MAX_PIPES) + return false; + + hubp = pipe_ctx->plane_res.hubp; + if (hubp == NULL) + return false; + + pipe_ctx->stream->dmdata_address = attr->address; + + if (pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL) { + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + /* if using dynamic meta, don't set up generic infopackets */ + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + true, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } else + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + false, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } + + if (hubp->funcs->dmdata_set_attributes != NULL && + pipe_ctx->stream->dmdata_address.quad_part != 0) { + hubp->funcs->dmdata_set_attributes(hubp, attr); + } + + return true; +} +#endif void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream) { 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 87b3b03c3556..f40e4fd52fa2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -50,6 +50,25 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state plane_state->in_transfer_func->type = TF_TYPE_BYPASS; plane_state->in_transfer_func->ctx = ctx; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + plane_state->in_shaper_func = dc_create_transfer_func(); + if (plane_state->in_shaper_func != NULL) { + plane_state->in_shaper_func->type = TF_TYPE_BYPASS; + plane_state->in_shaper_func->ctx = ctx; + } + + plane_state->lut3d_func = dc_create_3dlut_func(); + if (plane_state->lut3d_func != NULL) { + plane_state->lut3d_func->ctx = ctx; + plane_state->lut3d_func->initialized = false; + } + plane_state->blend_tf = dc_create_transfer_func(); + if (plane_state->blend_tf != NULL) { + plane_state->blend_tf->type = TF_TYPE_BYPASS; + plane_state->blend_tf->ctx = ctx; + } + +#endif } static void destruct(struct dc_plane_state *plane_state) @@ -62,6 +81,24 @@ static void destruct(struct dc_plane_state *plane_state) plane_state->in_transfer_func); plane_state->in_transfer_func = NULL; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (plane_state->in_shaper_func != NULL) { + dc_transfer_func_release( + plane_state->in_shaper_func); + plane_state->in_shaper_func = NULL; + } + if (plane_state->lut3d_func != NULL) { + dc_3dlut_func_release( + plane_state->lut3d_func); + plane_state->lut3d_func = NULL; + } + if (plane_state->blend_tf != NULL) { + dc_transfer_func_release( + plane_state->blend_tf); + plane_state->blend_tf = NULL; + } + +#endif } /******************************************************************************* @@ -226,4 +263,40 @@ alloc_fail: return NULL; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +static void dc_3dlut_func_free(struct kref *kref) +{ + struct dc_3dlut *lut = container_of(kref, struct dc_3dlut, refcount); + + kvfree(lut); +} + +struct dc_3dlut *dc_create_3dlut_func(void) +{ + struct dc_3dlut *lut = kvzalloc(sizeof(*lut), GFP_KERNEL); + + if (lut == NULL) + goto alloc_fail; + + kref_init(&lut->refcount); + lut->initialized = false; + + return lut; + +alloc_fail: + return NULL; + +} + +void dc_3dlut_func_release(struct dc_3dlut *lut) +{ + kref_put(&lut->refcount, dc_3dlut_func_free); +} + +void dc_3dlut_func_retain(struct dc_3dlut *lut) +{ + kref_get(&lut->refcount); +} +#endif + 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 index 6ce87b682a32..a96d8de9380e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c @@ -24,8 +24,9 @@ */ #include "vm_helper.h" +#include "dc.h" -static void mark_vmid_used(struct vm_helper *vm_helper, unsigned int pos, uint8_t hubp_idx) +void vm_helper_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]; @@ -33,91 +34,43 @@ static void mark_vmid_used(struct vm_helper *vm_helper, unsigned int pos, uint8_ vmids.vmid_usage[1] = 1 << pos; } -static void add_ptb_to_table(struct vm_helper *vm_helper, unsigned int vmid, uint64_t ptb) +int dc_setup_system_context(struct dc *dc, struct dc_phy_addr_space_config *pa_config) { - 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; + int num_vmids = 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]; + /* Call HWSS to setup HUBBUB for address config */ + if (dc->hwss.init_sys_ctx) { + num_vmids = dc->hwss.init_sys_ctx(dc->hwseq, dc, pa_config); - // 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); + /* Pre-init system aperture start/end for all HUBP instances (if not gating?) + * or cache system aperture if using power gating + */ + memcpy(&dc->vm_pa_config, pa_config, sizeof(struct dc_phy_addr_space_config)); + dc->vm_pa_config.valid = true; } -} - -// 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; + return num_vmids; } -// Expected to be called only when there's an available vmid -static int get_next_available_vmid(struct vm_helper *vm_helper) +void dc_setup_vm_context(struct dc *dc, struct dc_virtual_addr_space_config *va_config, int vmid) { - int i; - - for (i = 1; i < vm_helper->num_vmid; i++) { - if (vm_helper->ptb_assigned_to_vmid[i] == 0) - return i; - } - - return -1; + dc->hwss.init_vm_ctx(dc->hwseq, dc, va_config, vmid); } -uint8_t get_vmid_for_ptb(struct vm_helper *vm_helper, int64_t ptb, uint8_t hubp_idx) +int dc_get_vmid_use_vector(struct dc *dc) { - 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); - } + int i; + int in_use = 0; - return vmid; + for (i = 0; i < dc->vm_helper->num_vmid; i++) + in_use |= dc->vm_helper->hubp_vmid_usage[i].vmid_usage[0] + | dc->vm_helper->hubp_vmid_usage[i].vmid_usage[1]; + return in_use; } -void init_vm_helper(struct vm_helper *vm_helper, unsigned int num_vmid, unsigned int num_hubp) +void vm_helper_init(struct vm_helper *vm_helper, unsigned int num_vmid) { 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 7ec6884acee4..e513028faefa 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.32" +#define DC_VER "3.2.35" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -70,6 +70,8 @@ struct dc_plane_cap { uint32_t argb8888 : 1; uint32_t nv12 : 1; uint32_t fp16 : 1; + uint32_t p010 : 1; + uint32_t ayuv : 1; } pixel_format_support; // max upscaling factor x1000 // upscaling factors are always >= 1 @@ -109,9 +111,19 @@ struct dc_caps { bool force_dp_tps4_for_cp2520; bool disable_dp_clk_share; bool psp_setup_panel_mode; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + bool hw_3d_lut; +#endif struct dc_plane_cap planes[MAX_PLANES]; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dc_bug_wa { + bool no_connect_phy_config; + bool dedcn20_305_wa; +}; +#endif + struct dc_dcc_surface_param { struct dc_size surface_size; enum surface_pixel_format format; @@ -206,6 +218,8 @@ struct dc_config { bool allow_seamless_boot_optimization; bool power_down_display_on_boot; bool edp_not_connected; + bool forced_clocks; + }; enum visual_confirm { @@ -321,6 +335,9 @@ struct dc_debug_options { bool disable_dfs_bypass; bool disable_dpp_power_gate; bool disable_hubp_power_gate; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool disable_dsc_power_gate; +#endif bool disable_pplib_wm_range; enum wm_report_mode pplib_wm_report_mode; unsigned int min_disp_clk_khz; @@ -329,6 +346,7 @@ struct dc_debug_options { int sr_exit_time_ns; int sr_enter_plus_exit_time_ns; int urgent_latency_ns; + uint32_t underflow_assert_delay_us; int percent_of_ideal_drambw; int dram_clock_change_latency_ns; bool optimized_watermark; @@ -353,6 +371,13 @@ struct dc_debug_options { unsigned int force_fclk_khz; bool disable_tri_buf; struct dc_bw_validation_profile bw_val_profile; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool disable_fec; +#endif + /* This forces a hard min on the DCFCLK requested to SMU/PP + * watermarks are not affected. + */ + unsigned int force_min_dcfclk_mhz; }; struct dc_debug_data { @@ -361,18 +386,54 @@ struct dc_debug_data { uint32_t auxErrorCount; }; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +struct dc_phy_addr_space_config { + struct { + uint64_t start_addr; + uint64_t end_addr; + uint64_t fb_top; + uint64_t fb_offset; + uint64_t fb_base; + uint64_t agp_top; + uint64_t agp_bot; + uint64_t agp_base; + } system_aperture; + + struct { + uint64_t page_table_start_addr; + uint64_t page_table_end_addr; + uint64_t page_table_base_addr; + } gart_config; + + bool valid; +}; + +struct dc_virtual_addr_space_config { + uint64_t page_table_base_addr; + uint64_t page_table_start_addr; + uint64_t page_table_end_addr; + uint32_t page_table_block_size_in_bytes; + uint8_t page_table_depth; // 1 = 1 level, 2 = 2 level, etc. 0 = invalid +}; +#endif + struct dc_bounding_box_overrides { int sr_exit_time_ns; int sr_enter_plus_exit_time_ns; int urgent_latency_ns; int percent_of_ideal_drambw; int dram_clock_change_latency_ns; + /* This forces a hard min on the DCFCLK we use + * for DML. Unlike the debug option for forcing + * DCFCLK, this override affects watermark calculations + */ int min_dcfclk_mhz; }; struct dc_state; struct resource_pool; struct dce_hwseq; +struct gpu_info_soc_bounding_box_v1_0; struct dc { struct dc_versions versions; struct dc_caps caps; @@ -380,7 +441,13 @@ struct dc { struct dc_config config; struct dc_debug_options debug; struct dc_bounding_box_overrides bb_overrides; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dc_bug_wa work_arounds; +#endif struct dc_context *ctx; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + struct dc_phy_addr_space_config vm_pa_config; +#endif uint8_t link_count; struct dc_link *links[MAX_PIPES * 2]; @@ -418,6 +485,10 @@ struct dc { struct dc_debug_data debug_data; const char *build_id; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + struct vm_helper *vm_helper; + const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; +#endif }; enum frame_buffer_mode { @@ -451,6 +522,13 @@ struct dc_init_data { struct dc_config flags; uint32_t log_mask; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + /** + * gpu_info FW provided soc bounding box struct or 0 if not + * available in FW + */ + const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box; +#endif }; struct dc_callback_init { @@ -458,6 +536,12 @@ struct dc_callback_init { }; struct dc *dc_create(const struct dc_init_data *init_params); +int dc_get_vmid_use_vector(struct dc *dc); +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +void dc_setup_vm_context(struct dc *dc, struct dc_virtual_addr_space_config *va_config, int vmid); +/* Returns the number of vmids supported */ +int dc_setup_system_context(struct dc *dc, struct dc_phy_addr_space_config *pa_config); +#endif void dc_init_callbacks(struct dc *dc, const struct dc_callback_init *init_params); void dc_destroy(struct dc **dc); @@ -529,6 +613,17 @@ struct dc_transfer_func { }; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + + +struct dc_3dlut { + struct kref refcount; + struct tetrahedral_params lut_3d; + uint32_t hdr_multiplier; + bool initialized; + struct dc_context *ctx; +}; +#endif /* * This structure is filled in by dc_surface_get_status and contains * the last requested address and the currently active address so the called @@ -579,6 +674,9 @@ union surface_update_flags { struct dc_plane_state { struct dc_plane_address address; struct dc_plane_flip_time time; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + bool triplebuffer_flips; +#endif struct scaling_taps scaling_quality; struct rect src_rect; struct rect dst_rect; @@ -601,6 +699,12 @@ struct dc_plane_state { enum dc_color_space color_space; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dc_3dlut *lut3d_func; + struct dc_transfer_func *in_shaper_func; + struct dc_transfer_func *blend_tf; +#endif + enum surface_pixel_format format; enum dc_rotation_angle rotation; enum plane_stereo_format stereo_format; @@ -666,6 +770,11 @@ struct dc_surface_update { const struct dc_csc_transform *input_csc_color_matrix; const struct fixed31_32 *coeff_reduction_factor; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + const struct dc_transfer_func *func_shaper; + const struct dc_3dlut *lut3d_func; + const struct dc_transfer_func *blend_tf; +#endif }; /* @@ -686,6 +795,11 @@ void dc_transfer_func_retain(struct dc_transfer_func *dc_tf); void dc_transfer_func_release(struct dc_transfer_func *dc_tf); struct dc_transfer_func *dc_create_transfer_func(void); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dc_3dlut *dc_create_3dlut_func(void); +void dc_3dlut_func_release(struct dc_3dlut *lut); +void dc_3dlut_func_retain(struct dc_3dlut *lut); +#endif /* * This structure holds a surface address. There could be multiple addresses * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such @@ -799,6 +913,10 @@ struct dpcd_caps { bool panel_mode_edp; bool dpcd_display_control_capable; bool ext_receiver_cap_field_present; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + union dpcd_fec_capability fec_cap; + struct dpcd_dsc_capabilities dsc_caps; +#endif }; #include "dc_link.h" @@ -819,6 +937,14 @@ struct dc_container_id { }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +struct dc_sink_dsc_caps { + // 'true' if these are virtual DPCD's DSC caps (immediately upstream of sink in MST topology), + // 'false' if they are sink's DSC caps + bool is_virtual_dpcd_dsc; + struct dsc_dec_dpcd_caps dsc_dec_caps; +}; +#endif /* * The sink structure contains EDID and other display device properties @@ -833,6 +959,10 @@ struct dc_sink { struct stereo_3d_features features_3d[TIMING_3D_FORMAT_MAX]; bool converter_disable_audio; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct dc_sink_dsc_caps sink_dsc_caps; +#endif + /* private to DC core */ struct dc_link *link; struct dc_context *ctx; @@ -890,4 +1020,10 @@ unsigned int dc_get_target_backlight_pwm(struct dc *dc); bool dc_is_dmcu_initialized(struct dc *dc); +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) +/******************************************************************************* + * DSC Interfaces + ******************************************************************************/ +#include "dc_dsc.h" +#endif #endif /* DC_INTERFACE_H_ */ 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 11c68a399267..dfcec4d3e9c0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -512,4 +512,131 @@ union test_misc { unsigned char raw; }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* FEC capability DPCD register field bits-*/ +union dpcd_fec_capability { + struct { + uint8_t FEC_CAPABLE:1; + uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1; + uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1; + uint8_t BIT_ERROR_COUNT_CAPABLE:1; + uint8_t RESERVED:4; + } bits; + uint8_t raw; +}; + +/* DSC capability DPCD register field bits-*/ +struct dpcd_dsc_support { + uint8_t DSC_SUPPORT :1; + uint8_t DSC_PASSTHROUGH_SUPPORT :1; + uint8_t RESERVED :6; +}; + +struct dpcd_dsc_algorithm_revision { + uint8_t DSC_VERSION_MAJOR :4; + uint8_t DSC_VERSION_MINOR :4; +}; + +struct dpcd_dsc_rc_buffer_block_size { + uint8_t RC_BLOCK_BUFFER_SIZE :2; + uint8_t RESERVED :6; +}; + +struct dpcd_dsc_slice_capability1 { + uint8_t ONE_SLICE_PER_DP_DSC_SINK_DEVICE :1; + uint8_t TWO_SLICES_PER_DP_DSC_SINK_DEVICE :1; + uint8_t RESERVED :1; + uint8_t FOUR_SLICES_PER_DP_DSC_SINK_DEVICE :1; + uint8_t SIX_SLICES_PER_DP_DSC_SINK_DEVICE :1; + uint8_t EIGHT_SLICES_PER_DP_DSC_SINK_DEVICE :1; + uint8_t TEN_SLICES_PER_DP_DSC_SINK_DEVICE :1; + uint8_t TWELVE_SLICES_PER_DP_DSC_SINK_DEVICE :1; +}; + +struct dpcd_dsc_line_buffer_bit_depth { + uint8_t LINE_BUFFER_BIT_DEPTH :4; + uint8_t RESERVED :4; +}; + +struct dpcd_dsc_block_prediction_support { + uint8_t BLOCK_PREDICTION_SUPPORT:1; + uint8_t RESERVED :7; +}; + +struct dpcd_maximum_bits_per_pixel_supported_by_the_decompressor { + uint8_t MAXIMUM_BITS_PER_PIXEL_SUPPORTED_BY_THE_DECOMPRESSOR_LOW :7; + uint8_t MAXIMUM_BITS_PER_PIXEL_SUPPORTED_BY_THE_DECOMPRESSOR_HIGH :7; + uint8_t RESERVED :2; +}; + +struct dpcd_dsc_decoder_color_format_capabilities { + uint8_t RGB_SUPPORT :1; + uint8_t Y_CB_CR_444_SUPPORT :1; + uint8_t Y_CB_CR_SIMPLE_422_SUPPORT :1; + uint8_t Y_CB_CR_NATIVE_422_SUPPORT :1; + uint8_t Y_CB_CR_NATIVE_420_SUPPORT :1; + uint8_t RESERVED :3; +}; + +struct dpcd_dsc_decoder_color_depth_capabilities { + uint8_t RESERVED0 :1; + uint8_t EIGHT_BITS_PER_COLOR_SUPPORT :1; + uint8_t TEN_BITS_PER_COLOR_SUPPORT :1; + uint8_t TWELVE_BITS_PER_COLOR_SUPPORT :1; + uint8_t RESERVED1 :4; +}; + +struct dpcd_peak_dsc_throughput_dsc_sink { + uint8_t THROUGHPUT_MODE_0:4; + uint8_t THROUGHPUT_MODE_1:4; +}; + +struct dpcd_dsc_slice_capabilities_2 { + uint8_t SIXTEEN_SLICES_PER_DSC_SINK_DEVICE :1; + uint8_t TWENTY_SLICES_PER_DSC_SINK_DEVICE :1; + uint8_t TWENTYFOUR_SLICES_PER_DSC_SINK_DEVICE :1; + uint8_t RESERVED :5; +}; + +struct dpcd_bits_per_pixel_increment{ + uint8_t INCREMENT_OF_BITS_PER_PIXEL_SUPPORTED :3; + uint8_t RESERVED :5; +}; +union dpcd_dsc_basic_capabilities { + struct { + struct dpcd_dsc_support dsc_support; + struct dpcd_dsc_algorithm_revision dsc_algorithm_revision; + struct dpcd_dsc_rc_buffer_block_size dsc_rc_buffer_block_size; + uint8_t dsc_rc_buffer_size; + struct dpcd_dsc_slice_capability1 dsc_slice_capabilities_1; + struct dpcd_dsc_line_buffer_bit_depth dsc_line_buffer_bit_depth; + struct dpcd_dsc_block_prediction_support dsc_block_prediction_support; + struct dpcd_maximum_bits_per_pixel_supported_by_the_decompressor maximum_bits_per_pixel_supported_by_the_decompressor; + struct dpcd_dsc_decoder_color_format_capabilities dsc_decoder_color_format_capabilities; + struct dpcd_dsc_decoder_color_depth_capabilities dsc_decoder_color_depth_capabilities; + struct dpcd_peak_dsc_throughput_dsc_sink peak_dsc_throughput_dsc_sink; + uint8_t dsc_maximum_slice_width; + struct dpcd_dsc_slice_capabilities_2 dsc_slice_capabilities_2; + uint8_t reserved; + struct dpcd_bits_per_pixel_increment bits_per_pixel_increment; + } fields; + uint8_t raw[16]; +}; + +union dpcd_dsc_ext_capabilities { + struct { + uint8_t BRANCH_OVERALL_THROUGHPUT_0; + uint8_t BRANCH_OVERALL_THROUGHPUT_1; + uint8_t BRANCH_MAX_LINE_WIDTH; + } fields; + uint8_t raw[3]; +}; + +struct dpcd_dsc_capabilities { + union dpcd_dsc_basic_capabilities dsc_basic_caps; + union dpcd_dsc_ext_capabilities dsc_ext_caps; +}; + +#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */ + #endif /* DC_DP_TYPES_H */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_dsc.h b/drivers/gpu/drm/amd/display/dc/dc_dsc.h new file mode 100644 index 000000000000..6e42209f0e20 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_dsc.h @@ -0,0 +1,62 @@ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#ifndef DC_DSC_H_ +#define DC_DSC_H_ +/* + * Copyright 2019 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. + * + * Author: AMD + */ + +/* put it here temporarily until linux has the new addresses official defined */ +/* DP Extended DSC Capabilities */ +#define DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 0x0a0 /* DP 1.4a SCR */ +#define DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 0x0a1 +#define DP_DSC_BRANCH_MAX_LINE_WIDTH 0x0a2 + +struct dc_dsc_bw_range { + uint32_t min_kbps; /* Bandwidth if min_target_bpp_x16 is used */ + uint32_t min_target_bpp_x16; + uint32_t max_kbps; /* Bandwidth if max_target_bpp_x16 is used */ + uint32_t max_target_bpp_x16; + uint32_t stream_kbps; /* Uncompressed stream bandwidth */ +}; + + +bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_basic_data, + const uint8_t *dpcd_dsc_ext_data, + struct dsc_dec_dpcd_caps *dsc_sink_caps); + +bool dc_dsc_compute_bandwidth_range( + const struct dc *dc, + const uint32_t min_kbps, + const uint32_t max_kbps, + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + const struct dc_crtc_timing *timing, + struct dc_dsc_bw_range *range); + +bool dc_dsc_compute_config( + const struct dc *dc, + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + uint32_t target_bandwidth_kbps, + const struct dc_crtc_timing *timing, + struct dc_dsc_config *dsc_cfg); +#endif +#endif 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 c91b8aad78c9..22db5682aa6c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -99,6 +99,8 @@ struct dc_plane_address { }; union large_integer page_table_base; + + uint8_t vmid; }; struct dc_size { @@ -194,6 +196,12 @@ enum surface_pixel_format { /*swaped & float*/ SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F, /*grow graphics here if necessary */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX, + SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX, + SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT, + SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT, +#endif SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr = SURFACE_PIXEL_FORMAT_VIDEO_BEGIN, @@ -201,6 +209,10 @@ enum surface_pixel_format { SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr, SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb, SURFACE_PIXEL_FORMAT_SUBSAMPLE_END, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010, + SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102, +#endif SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888, SURFACE_PIXEL_FORMAT_INVALID @@ -239,6 +251,13 @@ enum tile_split_values { DC_ROTATED_MICRO_TILING = 0x3, }; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +enum tripleBuffer_enable { + DC_TRIPLEBUFFER_DISABLE = 0x0, + DC_TRIPLEBUFFER_ENABLE = 0x1, +}; +#endif + /* TODO: These values come from hardware spec. We need to readdress this * if they ever change. */ @@ -437,6 +456,14 @@ struct dc_csc_transform { bool enable_adjustment; }; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +struct dc_rgb_fixed { + struct fixed31_32 red; + struct fixed31_32 green; + struct fixed31_32 blue; +}; +#endif + struct dc_gamma { struct kref refcount; enum dc_gamma_type type; @@ -451,7 +478,11 @@ struct dc_gamma { /* private to DC core */ struct dc_context *ctx; + /* is_identity is used for RGB256 gamma identity which can also be programmed in INPUT_LUT. + * is_logical_identity indicates the given gamma ramp regardless of type is identity. + */ bool is_identity; + bool is_logical_identity; }; /* Used by both ipp amd opp functions*/ @@ -466,7 +497,11 @@ enum dc_cursor_color_format { CURSOR_MODE_MONO, CURSOR_MODE_COLOR_1BIT_AND, CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA, - CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA + CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED, + CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED +#endif }; /* @@ -612,6 +647,10 @@ enum dc_color_depth { COLOR_DEPTH_121212, COLOR_DEPTH_141414, COLOR_DEPTH_161616, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + COLOR_DEPTH_999, + COLOR_DEPTH_111111, +#endif COLOR_DEPTH_COUNT }; @@ -672,6 +711,9 @@ struct dc_crtc_timing_flags { * rates less than or equal to 340Mcsc */ uint32_t LTE_340MCSC_SCRAMBLE:1; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + uint32_t DSC : 1; /* Use DSC with this timing */ +#endif }; enum dc_timing_3d_format { @@ -718,6 +760,18 @@ struct dc_crtc_timing_adjust { uint32_t v_total_max; }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +struct dc_dsc_config { + uint32_t num_slices_h; /* Number of DSC slices - horizontal */ + uint32_t num_slices_v; /* Number of DSC slices - vertical */ + uint32_t bits_per_pixel; /* DSC target bitrate in 1/16 of bpp (e.g. 128 -> 8bpp) */ + bool block_pred_enable; /* DSC block prediction enable */ + uint32_t linebuf_depth; /* DSC line buffer depth */ + uint32_t version_minor; /* DSC minor version. Full version is formed as 1.version_minor. */ + bool ycbcr422_simple; /* Tell DSC engine to convert YCbCr 4:2:2 to 'YCbCr 4:2:2 simple'. */ + int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */ +}; +#endif struct dc_crtc_timing { uint32_t h_total; uint32_t h_border_left; @@ -744,8 +798,73 @@ struct dc_crtc_timing { enum scanning_type scan_type; struct dc_crtc_timing_flags flags; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct dc_dsc_config dsc_cfg; +#endif }; +/* Passed on init */ +enum vram_type { + VIDEO_MEMORY_TYPE_GDDR5 = 2, + VIDEO_MEMORY_TYPE_DDR3 = 3, + VIDEO_MEMORY_TYPE_DDR4 = 4, + VIDEO_MEMORY_TYPE_HBM = 5, + VIDEO_MEMORY_TYPE_GDDR6 = 6, +}; + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +enum dwb_cnv_out_bpc { + DWB_CNV_OUT_BPC_8BPC = 0, + DWB_CNV_OUT_BPC_10BPC = 1, +}; + +enum dwb_output_depth { + DWB_OUTPUT_PIXEL_DEPTH_8BPC = 0, + DWB_OUTPUT_PIXEL_DEPTH_10BPC = 1, +}; + +enum dwb_capture_rate { + dwb_capture_rate_0 = 0, /* Every frame is captured. */ + dwb_capture_rate_1 = 1, /* Every other frame is captured. */ + dwb_capture_rate_2 = 2, /* Every 3rd frame is captured. */ + dwb_capture_rate_3 = 3, /* Every 4th frame is captured. */ +}; + +enum dwb_scaler_mode { + dwb_scaler_mode_bypass444 = 0, + dwb_scaler_mode_rgb444 = 1, + dwb_scaler_mode_yuv444 = 2, + dwb_scaler_mode_yuv420 = 3 +}; + +enum dwb_subsample_position { + DWB_INTERSTITIAL_SUBSAMPLING = 0, + DWB_COSITED_SUBSAMPLING = 1 +}; + +enum dwb_stereo_eye_select { + DWB_STEREO_EYE_LEFT = 1, /* Capture left eye only */ + DWB_STEREO_EYE_RIGHT = 2, /* Capture right eye only */ +}; + +enum dwb_stereo_type { + DWB_STEREO_TYPE_FRAME_PACKING = 0, /* Frame packing */ + DWB_STEREO_TYPE_FRAME_SEQUENTIAL = 3, /* Frame sequential */ +}; + +#define MCIF_BUF_COUNT 4 + +struct mcif_buf_params { + unsigned long long luma_address[MCIF_BUF_COUNT]; + unsigned long long chroma_address[MCIF_BUF_COUNT]; + unsigned int luma_pitch; + unsigned int chroma_pitch; + unsigned int warmup_pitch; + unsigned int swlock; +}; + +#endif + #define MAX_TG_COLOR_VALUE 0x3FF struct tg_color { /* Maximum 10 bits color value */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 094009127e25..6f0b80111e58 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -29,6 +29,13 @@ #include "dc_types.h" #include "grph_object_defs.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +enum dc_link_fec_state { + dc_link_fec_not_ready, + dc_link_fec_ready, + dc_link_fec_enabled +}; +#endif struct dc_link_status { bool link_active; struct dpcd_caps *dpcd_caps; @@ -129,6 +136,9 @@ struct dc_link { struct link_trace link_trace; struct gpio *hpd_gpio; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + enum dc_link_fec_state fec_state; +#endif }; const struct dc_link_status *dc_link_get_status(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 4da138ded8b7..0fa1c26bc20d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -42,6 +42,7 @@ struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; int plane_count; + int audio_inst; struct timing_sync_info timing_sync_info; struct dc_plane_state *plane_states[MAX_SURFACE_NUM]; }; @@ -51,6 +52,52 @@ struct freesync_context { bool dummy; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +enum hubp_dmdata_mode { + DMDATA_SW_MODE, + DMDATA_HW_MODE +}; + +struct dc_dmdata_attributes { + /* Specifies whether dynamic meta data will be updated by software + * or has to be fetched by hardware (DMA mode) + */ + enum hubp_dmdata_mode dmdata_mode; + /* Specifies if current dynamic meta data is to be used only for the current frame */ + bool dmdata_repeat; + /* Specifies the size of Dynamic Metadata surface in byte. Size of 0 means no Dynamic metadata is fetched */ + uint32_t dmdata_size; + /* Specifies if a new dynamic meta data should be fetched for an upcoming frame */ + bool dmdata_updated; + /* If hardware mode is used, the base address where DMDATA surface is located */ + PHYSICAL_ADDRESS_LOC address; + /* Specifies whether QOS level will be provided by TTU or it will come from DMDATA_QOS_LEVEL */ + bool dmdata_qos_mode; + /* If qos_mode = 1, this is the QOS value to be used: */ + uint32_t dmdata_qos_level; + /* Specifies the value in unit of REFCLK cycles to be added to the + * current time to produce the Amortized deadline for Dynamic Metadata chunk request + */ + uint32_t dmdata_dl_delta; + /* An unbounded array of uint32s, represents software dmdata to be loaded */ + uint32_t *dmdata_sw_data; +}; +#endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dc_writeback_info { + bool wb_enabled; + int dwb_pipe_inst; + struct dc_dwb_params dwb_params; + struct mcif_buf_params mcif_buf_params; +}; + +struct dc_writeback_update { + unsigned int num_wb_info; + struct dc_writeback_info writeback_info[MAX_DWB_PIPES]; +}; +#endif + enum vertical_interrupt_ref_point { START_V_UPDATE = 0, START_V_SYNC, @@ -80,7 +127,6 @@ struct dc_stream_state { struct dc_info_packet vrr_infopacket; struct dc_info_packet vsc_infopacket; struct dc_info_packet vsp_infopacket; - struct dc_info_packet dpsdp_infopacket; struct rect src; /* composition area */ struct rect dst; /* stream addressable area */ @@ -142,6 +188,11 @@ struct dc_stream_state { struct crtc_trigger_info triggered_crtc_reset; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* writeback */ + unsigned int num_wb_info; + struct dc_writeback_info writeback_info[MAX_DWB_PIPES]; +#endif /* Computed state bits */ bool mode_changed : 1; @@ -160,6 +211,9 @@ struct dc_stream_state { bool apply_seamless_boot_optimization; uint32_t stream_id; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool is_dsc_enabled; +#endif }; struct dc_stream_update { @@ -184,6 +238,12 @@ struct dc_stream_update { struct dc_csc_transform *output_csc_transform; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dc_writeback_update *wb_update; +#endif +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) + struct dc_dsc_config *dsc_config; +#endif }; bool dc_is_stream_unchanged( @@ -273,6 +333,19 @@ bool dc_add_all_planes_for_stream( int plane_count, struct dc_state *context); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dc_stream_add_writeback(struct dc *dc, + struct dc_stream_state *stream, + struct dc_writeback_info *wb_info); +bool dc_stream_remove_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst); +bool dc_stream_dmdata_status_done(struct dc *dc, struct dc_stream_state *stream); +bool dc_stream_set_dynamic_metadata(struct dc *dc, + struct dc_stream_state *stream, + struct dc_dmdata_attributes *dmdata_attr); +#endif + enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream); /* diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 92a670894c05..6eabb6491a3d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -421,6 +421,39 @@ enum display_content_type { DISPLAY_CONTENT_TYPE_GAME = 8 }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +/* writeback */ +struct dwb_stereo_params { + bool stereo_enabled; /* false: normal mode, true: 3D stereo */ + enum dwb_stereo_type stereo_type; /* indicates stereo format */ + bool stereo_polarity; /* indicates left eye or right eye comes first in stereo mode */ + enum dwb_stereo_eye_select stereo_eye_select; /* indicate which eye should be captured */ +}; + +struct dc_dwb_cnv_params { + unsigned int src_width; /* input active width */ + unsigned int src_height; /* input active height (half-active height in interlaced mode) */ + unsigned int crop_width; /* cropped window width at cnv output */ + bool crop_en; /* window cropping enable in cnv */ + unsigned int crop_height; /* cropped window height at cnv output */ + unsigned int crop_x; /* cropped window start x value at cnv output */ + unsigned int crop_y; /* cropped window start y value at cnv output */ + enum dwb_cnv_out_bpc cnv_out_bpc; /* cnv output pixel depth - 8bpc or 10bpc */ +}; + +struct dc_dwb_params { + struct dc_dwb_cnv_params cnv_params; /* CNV source size and cropping window parameters */ + unsigned int dest_width; /* Destination width */ + unsigned int dest_height; /* Destination height */ + enum dwb_scaler_mode out_format; /* default = YUV420 - TODO: limit this to 0 and 1 on dcn3 */ + enum dwb_output_depth output_depth; /* output pixel depth - 8bpc or 10bpc */ + enum dwb_capture_rate capture_rate; /* controls the frame capture rate */ + struct scaling_taps scaler_taps; /* Scaling taps */ + enum dwb_subsample_position subsample_position; + struct dc_transfer_func *out_transfer_func; +}; +#endif + /* audio*/ union audio_sample_rates { @@ -527,6 +560,9 @@ enum dc_infoframe_type { DC_HDMI_INFOFRAME_TYPE_AVI = 0x82, DC_HDMI_INFOFRAME_TYPE_SPD = 0x83, DC_HDMI_INFOFRAME_TYPE_AUDIO = 0x84, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + DC_DP_INFOFRAME_TYPE_PPS = 0x10, +#endif }; struct dc_info_packet { @@ -538,6 +574,15 @@ struct dc_info_packet { uint8_t sb[32]; }; +struct dc_info_packet_128 { + bool valid; + uint8_t hb0; + uint8_t hb1; + uint8_t hb2; + uint8_t hb3; + uint8_t sb[128]; +}; + #define DC_PLANE_UPDATE_TIMES_MAX 10 struct dc_plane_flip_time { @@ -680,4 +725,75 @@ struct AsicStateEx { unsigned int phyClock; }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* DSC DPCD capabilities */ +union dsc_slice_caps1 { + struct { + uint8_t NUM_SLICES_1 : 1; + uint8_t NUM_SLICES_2 : 1; + uint8_t RESERVED : 1; + uint8_t NUM_SLICES_4 : 1; + uint8_t NUM_SLICES_6 : 1; + uint8_t NUM_SLICES_8 : 1; + uint8_t NUM_SLICES_10 : 1; + uint8_t NUM_SLICES_12 : 1; + } bits; + uint8_t raw; +}; + +union dsc_slice_caps2 { + struct { + uint8_t NUM_SLICES_16 : 1; + uint8_t NUM_SLICES_20 : 1; + uint8_t NUM_SLICES_24 : 1; + uint8_t RESERVED : 5; + } bits; + uint8_t raw; +}; + +union dsc_color_formats { + struct { + uint8_t RGB : 1; + uint8_t YCBCR_444 : 1; + uint8_t YCBCR_SIMPLE_422 : 1; + uint8_t YCBCR_NATIVE_422 : 1; + uint8_t YCBCR_NATIVE_420 : 1; + uint8_t RESERVED : 3; + } bits; + uint8_t raw; +}; + +union dsc_color_depth { + struct { + uint8_t RESERVED1 : 1; + uint8_t COLOR_DEPTH_8_BPC : 1; + uint8_t COLOR_DEPTH_10_BPC : 1; + uint8_t COLOR_DEPTH_12_BPC : 1; + uint8_t RESERVED2 : 3; + } bits; + uint8_t raw; +}; + +struct dsc_dec_dpcd_caps { + bool is_dsc_supported; + uint8_t dsc_version; + int32_t rc_buffer_size; /* DSC RC buffer block size in bytes */ + union dsc_slice_caps1 slice_caps1; + union dsc_slice_caps2 slice_caps2; + int32_t lb_bit_depth; + bool is_block_pred_supported; + int32_t edp_max_bits_per_pixel; /* Valid only in eDP */ + union dsc_color_formats color_formats; + union dsc_color_depth color_depth; + int32_t throughput_mode_0_mps; /* In MPs */ + int32_t throughput_mode_1_mps; /* In MPs */ + int32_t max_slice_width; + uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */ + + /* Extended DSC caps */ + uint32_t branch_overall_throughput_0_mps; /* In MPs */ + uint32_t branch_overall_throughput_1_mps; /* In MPs */ + uint32_t branch_max_line_width; +}; +#endif #endif /* DC_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h index ff9436966041..7ba7e6f722f6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.h @@ -67,6 +67,22 @@ SRI(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ NBIO_SR(BIOS_SCRATCH_2) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define ABM_DCN20_REG_LIST() \ + ABM_COMMON_REG_LIST_DCE_BASE(), \ + SR(DC_ABM1_HG_SAMPLE_RATE), \ + SR(DC_ABM1_LS_SAMPLE_RATE), \ + SR(BL1_PWM_BL_UPDATE_SAMPLE_RATE), \ + SR(DC_ABM1_HG_MISC_CTRL), \ + SR(DC_ABM1_IPCSC_COEFF_SEL), \ + SR(BL1_PWM_CURRENT_ABM_LEVEL), \ + SR(BL1_PWM_TARGET_ABM_LEVEL), \ + SR(BL1_PWM_USER_LEVEL), \ + SR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES), \ + SR(DC_ABM1_HGLS_REG_READ_PROGRESS), \ + NBIO_SR(BIOS_SCRATCH_2) +#endif + #define ABM_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -147,6 +163,10 @@ ABM_SF(ABM0_DC_ABM1_HGLS_REG_READ_PROGRESS, \ ABM1_BL_REG_READ_MISSED_FRAME_CLEAR, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define ABM_MASK_SH_LIST_DCN20(mask_sh) ABM_MASK_SH_LIST_DCE110(mask_sh) +#endif + #define ABM_REG_FIELD_LIST(type) \ type ABM1_HG_NUM_OF_BINS_SEL; \ type ABM1_HG_VMAX_SEL; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 9b078a71de2e..4a10a5d22c90 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -843,8 +843,6 @@ void dce_aud_wall_dto_setup( REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, 1); - REG_UPDATE(DCCG_AUDIO_DTO_SOURCE, - DCCG_AUDIO_DTO_SEL, 1); /* DCCG_AUDIO_DTO2_USE_512FBR_DTO, 1) * Select 512fs for DP TODO: web register definition * does not match register header file diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h index 0dc5ff137c7a..a0d5724aab31 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h @@ -49,6 +49,8 @@ SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\ SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\ SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO2_USE_512FBR_DTO, mask_sh),\ + SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_USE_512FBR_DTO, mask_sh),\ + SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO1_USE_512FBR_DTO, mask_sh),\ SF(DCCG_AUDIO_DTO0_MODULE, DCCG_AUDIO_DTO0_MODULE, mask_sh),\ SF(DCCG_AUDIO_DTO0_PHASE, DCCG_AUDIO_DTO0_PHASE, mask_sh),\ SF(DCCG_AUDIO_DTO1_MODULE, DCCG_AUDIO_DTO1_MODULE, mask_sh),\ @@ -95,6 +97,8 @@ struct dce_audio_shift { uint8_t DCCG_AUDIO_DTO1_MODULE; uint8_t DCCG_AUDIO_DTO1_PHASE; uint8_t DCCG_AUDIO_DTO2_USE_512FBR_DTO; + uint32_t DCCG_AUDIO_DTO0_USE_512FBR_DTO; + uint32_t DCCG_AUDIO_DTO1_USE_512FBR_DTO; }; struct dce_aduio_mask { @@ -112,6 +116,9 @@ struct dce_aduio_mask { uint32_t DCCG_AUDIO_DTO1_MODULE; uint32_t DCCG_AUDIO_DTO1_PHASE; uint32_t DCCG_AUDIO_DTO2_USE_512FBR_DTO; + uint32_t DCCG_AUDIO_DTO0_USE_512FBR_DTO; + uint32_t DCCG_AUDIO_DTO1_USE_512FBR_DTO; + }; struct dce_audio { 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 ce6a26d189b0..ed7fec8fe253 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h @@ -29,6 +29,16 @@ #include "i2caux_interface.h" #include "inc/hw/aux_engine.h" +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#define AUX_COMMON_REG_LIST0(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) +#endif + #define AUX_COMMON_REG_LIST(id)\ SRI(AUX_CONTROL, DP_AUX, id), \ SRI(AUX_ARB_CONTROL, DP_AUX, id), \ 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 8347be76c60a..5fae77e201d5 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 @@ -55,6 +55,8 @@ #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + static const struct spread_spectrum_data *get_ss_data_entry( struct dce110_clk_src *clk_src, enum signal_type signal, @@ -1002,6 +1004,67 @@ static bool get_pixel_clk_frequency_100hz( return false; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + +/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */ +struct pixel_rate_range_table_entry { + unsigned int range_min_khz; + unsigned int range_max_khz; + unsigned int target_pixel_rate_khz; + unsigned short mult_factor; + unsigned short div_factor; +}; + +static const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = { + // /1.001 rates + {25170, 25180, 25200, 1000, 1001}, //25.2MHz -> 25.17 + {59340, 59350, 59400, 1000, 1001}, //59.4Mhz -> 59.340 + {74170, 74180, 74250, 1000, 1001}, //74.25Mhz -> 74.1758 + {125870, 125880, 126000, 1000, 1001}, //126Mhz -> 125.87 + {148350, 148360, 148500, 1000, 1001}, //148.5Mhz -> 148.3516 + {167830, 167840, 168000, 1000, 1001}, //168Mhz -> 167.83 + {222520, 222530, 222750, 1000, 1001}, //222.75Mhz -> 222.527 + {257140, 257150, 257400, 1000, 1001}, //257.4Mhz -> 257.1429 + {296700, 296710, 297000, 1000, 1001}, //297Mhz -> 296.7033 + {342850, 342860, 343200, 1000, 1001}, //343.2Mhz -> 342.857 + {395600, 395610, 396000, 1000, 1001}, //396Mhz -> 395.6 + {409090, 409100, 409500, 1000, 1001}, //409.5Mhz -> 409.091 + {445050, 445060, 445500, 1000, 1001}, //445.5Mhz -> 445.055 + {467530, 467540, 468000, 1000, 1001}, //468Mhz -> 467.5325 + {519230, 519240, 519750, 1000, 1001}, //519.75Mhz -> 519.231 + {525970, 525980, 526500, 1000, 1001}, //526.5Mhz -> 525.974 + {545450, 545460, 546000, 1000, 1001}, //546Mhz -> 545.455 + {593400, 593410, 594000, 1000, 1001}, //594Mhz -> 593.4066 + {623370, 623380, 624000, 1000, 1001}, //624Mhz -> 623.377 + {692300, 692310, 693000, 1000, 1001}, //693Mhz -> 692.308 + {701290, 701300, 702000, 1000, 1001}, //702Mhz -> 701.2987 + {791200, 791210, 792000, 1000, 1001}, //792Mhz -> 791.209 + {890100, 890110, 891000, 1000, 1001}, //891Mhz -> 890.1099 + {1186810, 1186820, 1188000, 1000, 1001},//1188Mhz -> 1186.8131 + + // *1.001 rates + {27020, 27030, 27000, 1001, 1000}, //27Mhz + {54050, 54060, 54000, 1001, 1000}, //54Mhz + {108100, 108110, 108000, 1001, 1000},//108Mhz +}; + +static bool dcn20_program_pix_clk( + struct clock_source *clock_source, + struct pixel_clk_params *pix_clk_params, + struct pll_settings *pll_settings) +{ + dce112_program_pix_clk(clock_source, pix_clk_params, pll_settings); + + return true; +} + +static const struct clock_source_funcs dcn20_clk_src_funcs = { + .cs_power_down = dce110_clock_source_power_down, + .program_pix_clk = dcn20_program_pix_clk, + .get_pix_clk_dividers = dce112_get_pix_clk_dividers +}; +#endif + /*****************************************/ /* Constructor */ /*****************************************/ @@ -1378,3 +1441,20 @@ bool dce112_clk_src_construct( return true; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dcn20_clk_src_construct( + struct dce110_clk_src *clk_src, + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + const struct dce110_clk_src_shift *cs_shift, + const struct dce110_clk_src_mask *cs_mask) +{ + bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask); + + clk_src->base.funcs = &dcn20_clk_src_funcs; + + return ret; +} +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h index 1ed7695a76d3..adae03b1f3a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h @@ -55,6 +55,37 @@ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define CS_COMMON_REG_LIST_DCN2_0(index, pllid) \ + SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ + SRII(PHASE, DP_DTO, 0),\ + SRII(PHASE, DP_DTO, 1),\ + SRII(PHASE, DP_DTO, 2),\ + SRII(PHASE, DP_DTO, 3),\ + SRII(PHASE, DP_DTO, 4),\ + SRII(PHASE, DP_DTO, 5),\ + SRII(MODULO, DP_DTO, 0),\ + SRII(MODULO, DP_DTO, 1),\ + SRII(MODULO, DP_DTO, 2),\ + SRII(MODULO, DP_DTO, 3),\ + SRII(MODULO, DP_DTO, 4),\ + SRII(MODULO, DP_DTO, 5),\ + SRII(PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PIXEL_RATE_CNTL, OTG, 4),\ + SRII(PIXEL_RATE_CNTL, OTG, 5) +#endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define CS_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ + CS_SF(DP_DTO0_PHASE, DP_DTO0_PHASE, mask_sh),\ + CS_SF(DP_DTO0_MODULO, DP_DTO0_MODULO, mask_sh),\ + CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ + CS_SF(OTG0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh) +#endif + #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ @@ -153,4 +184,15 @@ bool dce112_clk_src_construct( const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_mask *cs_mask); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +bool dcn20_clk_src_construct( + struct dce110_clk_src *clk_src, + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + const struct dce110_clk_src_shift *cs_shift, + const struct dce110_clk_src_mask *cs_mask); +#endif + #endif 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 ddd30fc0d76b..0b86cee4876f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -729,6 +729,56 @@ static bool dcn10_is_dmcu_initialized(struct dmcu *dmcu) #endif //(CONFIG_DRM_AMD_DC_DCN1_0) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + +static bool dcn20_lock_phy(struct dmcu *dmcu) +{ + struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); + + /* If microcontroller is not running, do nothing */ + if (dmcu->dmcu_state != DMCU_RUNNING) + return false; + + /* waitDMCUReadyForCmd */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); + + /* setDMCUParam_Cmd */ + REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_LOCK); + + /* notifyDMCUMsg */ + REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + + /* waitDMCUReadyForCmd */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); + + return true; +} + +static bool dcn20_unlock_phy(struct dmcu *dmcu) +{ + struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); + + /* If microcontroller is not running, do nothing */ + if (dmcu->dmcu_state != DMCU_RUNNING) + return false; + + /* waitDMCUReadyForCmd */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); + + /* setDMCUParam_Cmd */ + REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0, MCP_SYNC_PHY_UNLOCK); + + /* notifyDMCUMsg */ + REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1); + + /* waitDMCUReadyForCmd */ + REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 1, 10000); + + return true; +} + +#endif //(CONFIG_DRM_AMD_DC_DCN2_0) + static const struct dmcu_funcs dce_funcs = { .dmcu_init = dce_dmcu_init, .load_iram = dce_dmcu_load_iram, @@ -753,6 +803,21 @@ static const struct dmcu_funcs dcn10_funcs = { }; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +static const struct dmcu_funcs dcn20_funcs = { + .dmcu_init = dcn10_dmcu_init, + .load_iram = dcn10_dmcu_load_iram, + .set_psr_enable = dcn10_dmcu_set_psr_enable, + .setup_psr = dcn10_dmcu_setup_psr, + .get_psr_state = dcn10_get_dmcu_psr_state, + .set_psr_wait_loop = dcn10_psr_wait_loop, + .get_psr_wait_loop = dcn10_get_psr_wait_loop, + .is_dmcu_initialized = dcn10_is_dmcu_initialized, + .lock_phy = dcn20_lock_phy, + .unlock_phy = dcn20_unlock_phy +}; +#endif + static void dce_dmcu_construct( struct dce_dmcu *dmcu_dce, struct dc_context *ctx, @@ -815,6 +880,29 @@ struct dmcu *dcn10_dmcu_create( } #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dmcu *dcn20_dmcu_create( + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask) +{ + struct dce_dmcu *dmcu_dce = kzalloc(sizeof(*dmcu_dce), GFP_KERNEL); + + if (dmcu_dce == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_dmcu_construct( + dmcu_dce, ctx, regs, dmcu_shift, dmcu_mask); + + dmcu_dce->base.funcs = &dcn20_funcs; + + return &dmcu_dce->base; +} +#endif + void dce_dmcu_destroy(struct dmcu **dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(*dmcu); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h index 5bd0df55aa5d..cc8587683b4b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h @@ -261,6 +261,14 @@ struct dmcu *dcn10_dmcu_create( const struct dce_dmcu_shift *dmcu_shift, const struct dce_dmcu_mask *dmcu_mask); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dmcu *dcn20_dmcu_create( + struct dc_context *ctx, + const struct dce_dmcu_registers *regs, + const struct dce_dmcu_shift *dmcu_shift, + const struct dce_dmcu_mask *dmcu_mask); +#endif + void dce_dmcu_destroy(struct dmcu **dmcu); static const uint32_t abm_gain_stepsize = 0x0060; 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 956bdf14503f..cb0a037b1c4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -199,6 +199,70 @@ SR(DC_IP_REQUEST_CNTL), \ BL_REG_LIST() +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define HWSEQ_DCN2_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HWSEQ_PIXEL_RATE_REG_LIST(OTG), \ + HWSEQ_PHYPLL_REG_LIST(OTG), \ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN4_PG_CONFIG), \ + SR(DOMAIN5_PG_CONFIG), \ + SR(DOMAIN6_PG_CONFIG), \ + SR(DOMAIN7_PG_CONFIG), \ + SR(DOMAIN8_PG_CONFIG), \ + SR(DOMAIN9_PG_CONFIG), \ + SR(DOMAIN10_PG_CONFIG), \ + SR(DOMAIN11_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN20_PG_CONFIG), \ + SR(DOMAIN21_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN4_PG_STATUS), \ + SR(DOMAIN5_PG_STATUS), \ + SR(DOMAIN6_PG_STATUS), \ + SR(DOMAIN7_PG_STATUS), \ + SR(DOMAIN8_PG_STATUS), \ + SR(DOMAIN9_PG_STATUS), \ + SR(DOMAIN10_PG_STATUS), \ + SR(DOMAIN11_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(DOMAIN20_PG_STATUS), \ + SR(DOMAIN21_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + BL_REG_LIST() +#endif + struct dce_hwseq_registers { /* Backlight registers */ @@ -453,6 +517,69 @@ struct dce_hwseq_registers { HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh), \ HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define HWSEQ_DCN2_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN0_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN1_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN2_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN3_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN4_PG_CONFIG, DOMAIN4_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN5_PG_CONFIG, DOMAIN5_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN6_PG_CONFIG, DOMAIN6_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN7_PG_CONFIG, DOMAIN7_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN8_PG_CONFIG, DOMAIN8_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN9_PG_CONFIG, DOMAIN9_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN10_PG_CONFIG, DOMAIN10_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN11_PG_CONFIG, DOMAIN11_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN16_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN17_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN18_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN19_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN20_PG_CONFIG, DOMAIN20_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN21_PG_CONFIG, DOMAIN21_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN0_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN1_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN2_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN3_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN4_PG_STATUS, DOMAIN4_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN5_PG_STATUS, DOMAIN5_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN8_PG_STATUS, DOMAIN8_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN9_PG_STATUS, DOMAIN9_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN10_PG_STATUS, DOMAIN10_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN11_PG_STATUS, DOMAIN11_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN16_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN17_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN18_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN19_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN20_PG_STATUS, DOMAIN20_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN21_PG_STATUS, DOMAIN21_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) +#endif + #define HWSEQ_REG_FIELD_LIST(type) \ type DCFE_CLOCK_ENABLE; \ type DCFEV_CLOCK_ENABLE; \ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c index 5ca558766d2e..a9061aaf1562 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.c @@ -152,6 +152,36 @@ static void process_channel_reply( } } +static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw) +{ + unsigned int arbitrate; + unsigned int i2c_hw_status; + + REG_GET(HW_STATUS, DC_I2C_DDC1_HW_STATUS, &i2c_hw_status); + if (i2c_hw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW) + return false; + + REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate); + if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY) + return false; + + return true; +} + +static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw) +{ + 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; + + if (is_engine_available(dce_i2c_hw)) + return false; + + return true; +} + static bool process_transaction( struct dce_i2c_hw *dce_i2c_hw, struct i2c_request_transaction_data *request) @@ -162,6 +192,11 @@ static bool process_transaction( bool last_transaction = false; uint32_t value = 0; + if (is_hw_busy(dce_i2c_hw)) { + request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; + return false; + } + last_transaction = ((dce_i2c_hw->transaction_count == 3) || (request->action == DCE_I2C_TRANSACTION_ACTION_I2C_WRITE) || (request->action & DCE_I2C_TRANSACTION_ACTION_I2C_READ)); @@ -271,6 +306,12 @@ static bool setup_engine( struct dce_i2c_hw *dce_i2c_hw) { uint32_t i2c_setup_limit = I2C_SETUP_TIME_LIMIT_DCE; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint32_t reset_length = 0; +#endif + /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ + REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); + /* we have checked I2c not used by DMCU, set SW use I2C REQ to 1 to indicate SW using it*/ REG_UPDATE(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 1); @@ -291,33 +332,26 @@ static bool setup_engine( 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); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + } else { + reset_length = dce_i2c_hw->send_reset_length; + REG_UPDATE_N(SETUP, 3, + FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_TIME_LIMIT), i2c_setup_limit, + FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH), reset_length, + FN(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE), 1); +#endif } /* 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); + REG_UPDATE(DC_I2C_ARBITRATION, + DC_I2C_NO_QUEUED_SW_GO, 0); return true; } -static bool is_hw_busy(struct dce_i2c_hw *dce_i2c_hw) -{ - 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(dce_i2c_hw); - - REG_GET(DC_I2C_SW_STATUS, DC_I2C_SW_STATUS, &i2c_sw_status); - return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE; -} - static void release_engine( struct dce_i2c_hw *dce_i2c_hw) { @@ -352,16 +386,6 @@ static void release_engine( } -static bool is_engine_available(struct dce_i2c_hw *dce_i2c_hw) -{ - unsigned int arbitrate; - - REG_GET(DC_I2C_ARBITRATION, DC_I2C_REG_RW_CNTL_STATUS, &arbitrate); - if (arbitrate == DC_I2C_REG_RW_CNTL_STATUS_DMCU_ONLY) - return false; - return true; -} - struct dce_i2c_hw *acquire_i2c_hw_engine( struct resource_pool *pool, struct ddc *ddc) @@ -459,6 +483,7 @@ static void submit_channel_request_hw( request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY; return; } + reset_hw_engine(dce_i2c_hw); execute_transaction(dce_i2c_hw); @@ -690,3 +715,23 @@ void dcn1_i2c_hw_construct( dce_i2c_hw->setup_limit = I2C_SETUP_TIME_LIMIT_DCN; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +void dcn2_i2c_hw_construct( + struct dce_i2c_hw *dce_i2c_hw, + struct dc_context *ctx, + uint32_t engine_id, + const struct dce_i2c_registers *regs, + const struct dce_i2c_shift *shifts, + const struct dce_i2c_mask *masks) +{ + dcn1_i2c_hw_construct(dce_i2c_hw, + ctx, + engine_id, + regs, + shifts, + masks); + dce_i2c_hw->send_reset_length = I2C_SEND_RESET_LENGTH_9; + if (ctx->dc->debug.scl_reset_length10) + dce_i2c_hw->send_reset_length = I2C_SEND_RESET_LENGTH_10; +} +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h index f718e3d396f2..cb0234e5d597 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c_hw.h @@ -84,6 +84,7 @@ enum { #define I2C_HW_ENGINE_COMMON_REG_LIST(id)\ SRI(SETUP, DC_I2C_DDC, id),\ SRI(SPEED, DC_I2C_DDC, id),\ + SRI(HW_STATUS, DC_I2C_DDC, id),\ SR(DC_I2C_ARBITRATION),\ SR(DC_I2C_CONTROL),\ SR(DC_I2C_SW_STATUS),\ @@ -105,6 +106,7 @@ enum { 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_DDC1_HW_STATUS, DC_I2C_DDC1_HW_STATUS, mask_sh),\ I2C_SF(DC_I2C_ARBITRATION, DC_I2C_SW_USE_I2C_REG_REQ, 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),\ @@ -146,6 +148,7 @@ struct dce_i2c_shift { 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_DDC1_HW_STATUS; uint8_t DC_I2C_SW_DONE_USING_I2C_REG; uint8_t DC_I2C_SW_USE_I2C_REG_REQ; uint8_t DC_I2C_NO_QUEUED_SW_GO; @@ -174,6 +177,9 @@ struct dce_i2c_shift { uint8_t DC_I2C_INDEX; uint8_t DC_I2C_INDEX_WRITE; uint8_t XTAL_REF_DIV; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint8_t DC_I2C_DDC1_SEND_RESET_LENGTH; +#endif uint8_t DC_I2C_REG_RW_CNTL_STATUS; }; @@ -185,6 +191,7 @@ struct dce_i2c_mask { 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_DDC1_HW_STATUS; uint32_t DC_I2C_SW_DONE_USING_I2C_REG; uint32_t DC_I2C_SW_USE_I2C_REG_REQ; uint32_t DC_I2C_NO_QUEUED_SW_GO; @@ -213,12 +220,22 @@ struct dce_i2c_mask { uint32_t DC_I2C_INDEX; uint32_t DC_I2C_INDEX_WRITE; uint32_t XTAL_REF_DIV; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint32_t DC_I2C_DDC1_SEND_RESET_LENGTH; +#endif uint32_t DC_I2C_REG_RW_CNTL_STATUS; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define I2C_COMMON_MASK_SH_LIST_DCN2(mask_sh)\ + I2C_COMMON_MASK_SH_LIST_DCE110(mask_sh),\ + I2C_SF(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_SEND_RESET_LENGTH, mask_sh) +#endif + struct dce_i2c_registers { uint32_t SETUP; uint32_t SPEED; + uint32_t HW_STATUS; uint32_t DC_I2C_ARBITRATION; uint32_t DC_I2C_CONTROL; uint32_t DC_I2C_SW_STATUS; @@ -295,6 +312,16 @@ void dcn1_i2c_hw_construct( const struct dce_i2c_shift *shifts, const struct dce_i2c_mask *masks); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +void dcn2_i2c_hw_construct( + struct dce_i2c_hw *dce_i2c_hw, + struct dc_context *ctx, + uint32_t engine_id, + const struct dce_i2c_registers *regs, + const struct dce_i2c_shift *shifts, + const struct dce_i2c_mask *masks); +#endif + bool dce_i2c_submit_command_hw( struct resource_pool *pool, struct ddc *ddc, 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 753c96f74af0..858a58856ebd 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 @@ -669,6 +669,26 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) /* update AVI info frame (HDMI, DP)*/ /* TODO: FPGA may change to hwss.update_info_frame */ + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata != NULL && + pipe_ctx->plane_res.hubp != NULL) { + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + /* if using dynamic meta, don't set up generic infopackets */ + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + true, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } else + pipe_ctx->stream_res.stream_enc->funcs->set_dynamic_metadata( + pipe_ctx->stream_res.stream_enc, + false, pipe_ctx->plane_res.hubp->inst, + dc_is_dp_signal(pipe_ctx->stream->signal) ? + dmdata_dp : dmdata_hdmi); + } +#endif dce110_update_info_frame(pipe_ctx); /* enable early control to avoid corruption on DP monitor*/ @@ -942,26 +962,12 @@ void hwss_edp_backlight_control( edp_receiver_ready_T9(link); } -// Static helper function which calls the correct function -// based on pp_smu version -static void set_pme_wa_enable_by_version(struct dc *dc) -{ - struct pp_smu_funcs *pp_smu = NULL; - - if (dc->res_pool->pp_smu) - pp_smu = dc->res_pool->pp_smu; - - if (pp_smu) { - if (pp_smu->ctx.ver == PP_SMU_VER_RV && pp_smu->rv_funcs.set_pme_wa_enable) - pp_smu->rv_funcs.set_pme_wa_enable(&(pp_smu->ctx)); - } -} - void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) { /* notify audio driver for audio modes of monitor */ struct dc *core_dc = pipe_ctx->stream->ctx->dc; struct pp_smu_funcs *pp_smu = NULL; + struct clk_mgr *clk_mgr = core_dc->clk_mgr; unsigned int i, num_audio = 1; if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == true) @@ -979,9 +985,9 @@ 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) + if (num_audio >= 1 && clk_mgr->funcs->enable_pme_wa) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - set_pme_wa_enable_by_version(core_dc); + clk_mgr->funcs->enable_pme_wa(clk_mgr); /* un-mute audio */ /* TODO: audio should be per stream rather than per link */ pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control( @@ -995,6 +1001,7 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) { struct dc *dc = pipe_ctx->stream->ctx->dc; struct pp_smu_funcs *pp_smu = NULL; + struct clk_mgr *clk_mgr = dc->clk_mgr; if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false) return; @@ -1023,9 +1030,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) + if (clk_mgr->funcs->enable_pme_wa) /*this is the first audio. apply the PME w/a in order to wake AZ from D3*/ - set_pme_wa_enable_by_version(dc); + clk_mgr->funcs->enable_pme_wa(clk_mgr); /* TODO: notify audio driver for if audio modes list changed * add audio mode list change flag */ @@ -1340,6 +1347,9 @@ static enum dc_status apply_single_controller_ctx_to_hw( struct dc_stream_state *stream = pipe_ctx->stream; struct drr_params params = {0}; unsigned int event_triggers = 0; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); +#endif if (dc->hwss.disable_stream_gating) { dc->hwss.disable_stream_gating(dc, pipe_ctx); @@ -1405,6 +1415,20 @@ static enum dc_status apply_single_controller_ctx_to_hw( pipe_ctx->stream_res.opp, &stream->bit_depth_params, &stream->clamping); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion( + odm_pipe->stream_res.opp, + COLOR_SPACE_YCBCR601, + stream->timing.display_color_depth, + stream->signal); + + odm_pipe->stream_res.opp->funcs->opp_program_fmt( + odm_pipe->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); + } +#endif if (!stream->dpms_off) core_link_enable_stream(context, pipe_ctx); @@ -1510,6 +1534,18 @@ static void disable_vga_and_power_gate_all_controllers( } } + +static struct dc_stream_state *get_edp_stream(struct dc_state *context) +{ + int i; + + for (i = 0; i < context->stream_count; i++) { + if (context->streams[i]->signal == SIGNAL_TYPE_EDP) + return context->streams[i]; + } + return NULL; +} + static struct dc_link *get_edp_link(struct dc *dc) { int i; @@ -1553,12 +1589,16 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) int i; struct dc_link *edp_link_with_sink = get_edp_link_with_sink(dc, context); struct dc_link *edp_link = get_edp_link(dc); + struct dc_stream_state *edp_stream = NULL; bool can_apply_edp_fast_boot = false; bool can_apply_seamless_boot = false; + bool keep_edp_vdd_on = false; if (dc->hwss.init_pipes) dc->hwss.init_pipes(dc, context); + edp_stream = get_edp_stream(context); + // Check fastboot support, disable on DCE8 because of blank screens if (edp_link && dc->ctx->dce_version != DCE_VERSION_8_0 && dc->ctx->dce_version != DCE_VERSION_8_1 && @@ -1566,15 +1606,16 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) // enable fastboot if backend is enabled on eDP if (edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc)) { - /* Find eDP stream and set optimization flag */ - for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->signal == SIGNAL_TYPE_EDP) { - context->streams[i]->apply_edp_fast_boot_optimization = true; - can_apply_edp_fast_boot = true; - break; - } + /* Set optimization flag on eDP stream*/ + if (edp_stream) { + edp_stream->apply_edp_fast_boot_optimization = true; + can_apply_edp_fast_boot = true; } } + + // We are trying to enable eDP, don't power down VDD + if (edp_stream) + keep_edp_vdd_on = true; } // Check seamless boot support @@ -1589,14 +1630,14 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) * it should get turned off */ if (!can_apply_edp_fast_boot && !can_apply_seamless_boot) { - if (edp_link_with_sink) { + if (edp_link_with_sink && !keep_edp_vdd_on) { /*turn off backlight before DP_blank and encoder powered down*/ dc->hwss.edp_backlight_control(edp_link_with_sink, false); } /*resume from S3, no vbios posting, no need to power down again*/ power_down_all_hw_blocks(dc); disable_vga_and_power_gate_all_controllers(dc); - if (edp_link_with_sink) + if (edp_link_with_sink && !keep_edp_vdd_on) dc->hwss.edp_power_control(edp_link_with_sink, false); } bios_set_scratch_acc_mode_change(dc->ctx->dc_bios); 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 54be7ab370df..4a6ba3173a5a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -1165,16 +1165,6 @@ static bool construct( 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(dc->clk_mgr); - /* Create hardware sequencer */ if (!dce120_hw_sequencer_create(dc)) goto controller_create_fail; 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 6f4b24756323..b95ec73fcae3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -290,7 +290,12 @@ void dpp1_cnv_setup ( enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + enum dc_color_space input_color_space, + struct cnv_alpha_2bit_lut *alpha_2bit_lut) +#else enum dc_color_space input_color_space) +#endif { uint32_t pixel_format; uint32_t alpha_en; @@ -523,6 +528,11 @@ static const struct dpp_funcs dcn10_dpp_funcs = { .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, .dpp_dppclk_control = dpp1_dppclk_control, .dpp_set_hdr_multiplier = dpp1_set_hdr_multiplier, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + .dpp_program_blnd_lut = NULL, + .dpp_program_shaper_lut = NULL, + .dpp_program_3dlut = NULL +#endif }; static struct dpp_caps dcn10_dpp_cap = { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h index 282e22f9b175..8a5517eebb7c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1486,7 +1486,12 @@ void dpp1_cnv_setup ( enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + enum dc_color_space input_color_space, + struct cnv_alpha_2bit_lut *alpha_2bit_lut); +#else enum dc_color_space input_color_space); +#endif void dpp1_full_bypass(struct dpp *dpp_base); 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 882bcc5a40f6..aa0c7a7d13a0 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 @@ -731,6 +731,10 @@ void dpp1_full_bypass(struct dpp *dpp_base) /* COLOR_KEYER_CONTROL.COLOR_KEYER_EN = 0 this should be default */ if (dpp->tf_mask->CM_BYPASS_EN) REG_SET(CM_CONTROL, 0, CM_BYPASS_EN, 1); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + else + REG_SET(CM_CONTROL, 0, CM_BYPASS, 1); +#endif /* Setting degamma bypass for now */ REG_SET(CM_DGAM_CONTROL, 0, CM_DGAM_LUT_MODE, 0); 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 ce21a290bf3e..d67e0abeee93 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 @@ -218,6 +218,14 @@ static void dpp1_dscl_set_lb( INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + else { + /* DSCL caps: pixel data processed in float format */ + REG_SET_2(LB_DATA_FORMAT, 0, + INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ + LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ + } +#endif REG_SET_2(LB_MEMORY_CTRL, 0, MEMORY_CONFIG, mem_size_config, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c new file mode 100644 index 000000000000..374cc9acda3b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.c @@ -0,0 +1,136 @@ +/* + * Copyright 2012-17 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 + * + */ + +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) + +#include "reg_helper.h" +#include "resource.h" +#include "dwb.h" +#include "dcn10_dwb.h" + + +#define REG(reg)\ + dwbc10->dwbc_regs->reg + +#define CTX \ + dwbc10->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dwbc10->dwbc_shift->field_name, dwbc10->dwbc_mask->field_name + +#define TO_DCN10_DWBC(dwbc_base) \ + container_of(dwbc_base, struct dcn10_dwbc, base) + +static bool dwb1_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) +{ + if (caps) { + caps->adapter_id = 0; /* we only support 1 adapter currently */ + caps->hw_version = DCN_VERSION_1_0; + caps->num_pipes = 2; + memset(&caps->reserved, 0, sizeof(caps->reserved)); + memset(&caps->reserved2, 0, sizeof(caps->reserved2)); + caps->sw_version = dwb_ver_1_0; + caps->caps.support_dwb = true; + caps->caps.support_ogam = false; + caps->caps.support_wbscl = true; + caps->caps.support_ocsc = false; + return true; + } else { + return false; + } +} + +static bool dwb1_enable(struct dwbc *dwbc, struct dc_dwb_params *params) +{ + struct dcn10_dwbc *dwbc10 = TO_DCN10_DWBC(dwbc); + + /* disable first. */ + dwbc->funcs->disable(dwbc); + + /* disable power gating */ + REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 1, + DISPCLK_G_WB_GATE_DIS, 1, DISPCLK_G_WBSCL_GATE_DIS, 1, + WB_LB_LS_DIS, 1, WB_LUT_LS_DIS, 1); + + REG_UPDATE(WB_ENABLE, WB_ENABLE, 1); + + return true; +} + +static bool dwb1_disable(struct dwbc *dwbc) +{ + struct dcn10_dwbc *dwbc10 = TO_DCN10_DWBC(dwbc); + + /* disable CNV */ + REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, 0); + + /* disable WB */ + REG_UPDATE(WB_ENABLE, WB_ENABLE, 0); + + /* soft reset */ + REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 1); + REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 0); + + /* enable power gating */ + REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 0, + DISPCLK_G_WB_GATE_DIS, 0, DISPCLK_G_WBSCL_GATE_DIS, 0, + WB_LB_LS_DIS, 0, WB_LUT_LS_DIS, 0); + + return true; +} + +const struct dwbc_funcs dcn10_dwbc_funcs = { + .get_caps = dwb1_get_caps, + .enable = dwb1_enable, + .disable = dwb1_disable, + .update = NULL, + .set_stereo = NULL, + .set_new_content = NULL, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + .set_warmup = NULL, +#endif + .dwb_set_scaler = NULL, +}; + +void dcn10_dwbc_construct(struct dcn10_dwbc *dwbc10, + struct dc_context *ctx, + const struct dcn10_dwbc_registers *dwbc_regs, + const struct dcn10_dwbc_shift *dwbc_shift, + const struct dcn10_dwbc_mask *dwbc_mask, + int inst) +{ + dwbc10->base.ctx = ctx; + + dwbc10->base.inst = inst; + dwbc10->base.funcs = &dcn10_dwbc_funcs; + + dwbc10->dwbc_regs = dwbc_regs; + dwbc10->dwbc_shift = dwbc_shift; + dwbc10->dwbc_mask = dwbc_mask; +} + + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h new file mode 100644 index 000000000000..c175edd0bae7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dwb.h @@ -0,0 +1,271 @@ +/* Copyright 2012-17 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 __DC_DWBC_DCN10_H__ +#define __DC_DWBC_DCN10_H__ + +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) + +/* DCN */ +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#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 + + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + + +#define DWBC_COMMON_REG_LIST_DCN1_0(inst) \ + SRI(WB_ENABLE, CNV, inst),\ + SRI(WB_EC_CONFIG, CNV, inst),\ + SRI(CNV_MODE, CNV, inst),\ + SRI(WB_SOFT_RESET, CNV, inst),\ + SRI(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_PITCH, MCIF_WB, inst),\ + SRI(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_SCLK_CHANGE, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, MCIF_WB, inst),\ + SRI(MCIF_WB_NB_PSTATE_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_WATERMARK, MCIF_WB, inst),\ + SRI(MCIF_WB_WARM_UP_CNTL, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_LUMA_SIZE, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB, inst) + +#define DWBC_COMMON_MASK_SH_LIST_DCN1_0(mask_sh) \ + SF(CNV0_WB_ENABLE, WB_ENABLE, mask_sh),\ + SF(CNV0_WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, mask_sh),\ + SF(CNV0_WB_EC_CONFIG, DISPCLK_G_WB_GATE_DIS, mask_sh),\ + SF(CNV0_WB_EC_CONFIG, DISPCLK_G_WBSCL_GATE_DIS, mask_sh),\ + SF(CNV0_WB_EC_CONFIG, WB_LB_LS_DIS, mask_sh),\ + SF(CNV0_WB_EC_CONFIG, WB_LUT_LS_DIS, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_WINDOW_CROP_EN, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_STEREO_TYPE, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_INTERLACED_MODE, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_EYE_SELECTION, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_STEREO_POLARITY, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_INTERLACED_FIELD_ORDER, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_STEREO_SPLIT, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_NEW_CONTENT, mask_sh),\ + SF(CNV0_CNV_MODE, CNV_FRAME_CAPTURE_EN, mask_sh),\ + SF(CNV0_WB_SOFT_RESET, WB_SOFT_RESET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_ENABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUF_DUALSIZE_REQ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_INT_ACK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_SLICE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_OVERRUN_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_LOCK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_P_VMID, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUF_ADDR_FENCE_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_PITCH, MCIF_WB_BUF_LUMA_PITCH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_PITCH, MCIF_WB_BUF_CHROMA_PITCH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_CLIENT_ARBITRATION_SLICE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_TIME_PER_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SCLK_CHANGE, WM_CHANGE_ACK_FORCE_ON, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_Y, MCIF_WB_BUF_1_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_Y_OFFSET, MCIF_WB_BUF_1_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_C, MCIF_WB_BUF_1_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_C_OFFSET, MCIF_WB_BUF_1_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_Y, MCIF_WB_BUF_2_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_Y_OFFSET, MCIF_WB_BUF_2_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_C, MCIF_WB_BUF_2_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_C_OFFSET, MCIF_WB_BUF_2_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_Y, MCIF_WB_BUF_3_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_Y_OFFSET, MCIF_WB_BUF_3_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_C, MCIF_WB_BUF_3_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_C_OFFSET, MCIF_WB_BUF_3_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_Y, MCIF_WB_BUF_4_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_Y_OFFSET, MCIF_WB_BUF_4_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_C, MCIF_WB_BUF_4_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_C_OFFSET, MCIF_WB_BUF_4_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_LOCK_IGNORE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_INT_ACK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_SLICE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_LOCK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_SLICE_SIZE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, NB_PSTATE_CHANGE_REFRESH_WATERMARK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_URGENT_DURING_REQUEST, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_FORCE_ON, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_ALLOW_FOR_URGENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_WARM_UP_CNTL, MCIF_WB_PITCH_SIZE_WARMUP, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_LUMA_SIZE, MCIF_WB_BUF_LUMA_SIZE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB_BUF_CHROMA_SIZE, mask_sh) + +#define DWBC_REG_FIELD_LIST(type) \ + type WB_ENABLE;\ + type DISPCLK_R_WB_GATE_DIS;\ + type DISPCLK_G_WB_GATE_DIS;\ + type DISPCLK_G_WBSCL_GATE_DIS;\ + type WB_LB_LS_DIS;\ + type WB_LB_SD_DIS;\ + type WB_LUT_LS_DIS;\ + type CNV_WINDOW_CROP_EN;\ + type CNV_STEREO_TYPE;\ + type CNV_INTERLACED_MODE;\ + type CNV_EYE_SELECTION;\ + type CNV_STEREO_POLARITY;\ + type CNV_INTERLACED_FIELD_ORDER;\ + type CNV_STEREO_SPLIT;\ + type CNV_NEW_CONTENT;\ + type CNV_FRAME_CAPTURE_EN;\ + type WB_SOFT_RESET;\ + type MCIF_WB_BUFMGR_ENABLE;\ + type MCIF_WB_BUF_DUALSIZE_REQ;\ + type MCIF_WB_BUFMGR_SW_INT_EN;\ + type MCIF_WB_BUFMGR_SW_INT_ACK;\ + type MCIF_WB_BUFMGR_SW_SLICE_INT_EN;\ + type MCIF_WB_BUFMGR_SW_OVERRUN_INT_EN;\ + type MCIF_WB_BUFMGR_SW_LOCK;\ + type MCIF_WB_P_VMID;\ + type MCIF_WB_BUF_ADDR_FENCE_EN;\ + type MCIF_WB_BUF_LUMA_PITCH;\ + type MCIF_WB_BUF_CHROMA_PITCH;\ + type MCIF_WB_CLIENT_ARBITRATION_SLICE;\ + type MCIF_WB_TIME_PER_PIXEL;\ + type WM_CHANGE_ACK_FORCE_ON;\ + type MCIF_WB_CLI_WATERMARK_MASK;\ + type MCIF_WB_BUF_1_ADDR_Y;\ + type MCIF_WB_BUF_1_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_1_ADDR_C;\ + type MCIF_WB_BUF_1_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_2_ADDR_Y;\ + type MCIF_WB_BUF_2_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_2_ADDR_C;\ + type MCIF_WB_BUF_2_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_3_ADDR_Y;\ + type MCIF_WB_BUF_3_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_3_ADDR_C;\ + type MCIF_WB_BUF_3_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_4_ADDR_Y;\ + type MCIF_WB_BUF_4_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_4_ADDR_C;\ + type MCIF_WB_BUF_4_ADDR_C_OFFSET;\ + type MCIF_WB_BUFMGR_VCE_LOCK_IGNORE;\ + type MCIF_WB_BUFMGR_VCE_INT_EN;\ + type MCIF_WB_BUFMGR_VCE_INT_ACK;\ + type MCIF_WB_BUFMGR_VCE_SLICE_INT_EN;\ + type MCIF_WB_BUFMGR_VCE_LOCK;\ + type MCIF_WB_BUFMGR_SLICE_SIZE;\ + type NB_PSTATE_CHANGE_REFRESH_WATERMARK;\ + type NB_PSTATE_CHANGE_URGENT_DURING_REQUEST;\ + type NB_PSTATE_CHANGE_FORCE_ON;\ + type NB_PSTATE_ALLOW_FOR_URGENT;\ + type NB_PSTATE_CHANGE_WATERMARK_MASK;\ + type MCIF_WB_CLI_WATERMARK;\ + type MCIF_WB_CLI_CLOCK_GATER_OVERRIDE;\ + type MCIF_WB_PITCH_SIZE_WARMUP;\ + type MCIF_WB_BUF_LUMA_SIZE;\ + type MCIF_WB_BUF_CHROMA_SIZE;\ + +struct dcn10_dwbc_registers { + uint32_t WB_ENABLE; + uint32_t WB_EC_CONFIG; + uint32_t CNV_MODE; + uint32_t WB_SOFT_RESET; + uint32_t MCIF_WB_BUFMGR_SW_CONTROL; + uint32_t MCIF_WB_BUF_PITCH; + uint32_t MCIF_WB_ARBITRATION_CONTROL; + uint32_t MCIF_WB_SCLK_CHANGE; + uint32_t MCIF_WB_BUF_1_ADDR_Y; + uint32_t MCIF_WB_BUF_1_ADDR_Y_OFFSET; + uint32_t MCIF_WB_BUF_1_ADDR_C; + uint32_t MCIF_WB_BUF_1_ADDR_C_OFFSET; + uint32_t MCIF_WB_BUF_2_ADDR_Y; + uint32_t MCIF_WB_BUF_2_ADDR_Y_OFFSET; + uint32_t MCIF_WB_BUF_2_ADDR_C; + uint32_t MCIF_WB_BUF_2_ADDR_C_OFFSET; + uint32_t MCIF_WB_BUF_3_ADDR_Y; + uint32_t MCIF_WB_BUF_3_ADDR_Y_OFFSET; + uint32_t MCIF_WB_BUF_3_ADDR_C; + uint32_t MCIF_WB_BUF_3_ADDR_C_OFFSET; + uint32_t MCIF_WB_BUF_4_ADDR_Y; + uint32_t MCIF_WB_BUF_4_ADDR_Y_OFFSET; + uint32_t MCIF_WB_BUF_4_ADDR_C; + uint32_t MCIF_WB_BUF_4_ADDR_C_OFFSET; + uint32_t MCIF_WB_BUFMGR_VCE_CONTROL; + uint32_t MCIF_WB_NB_PSTATE_LATENCY_WATERMARK; + uint32_t MCIF_WB_NB_PSTATE_CONTROL; + uint32_t MCIF_WB_WATERMARK; + uint32_t MCIF_WB_WARM_UP_CNTL; + uint32_t MCIF_WB_BUF_LUMA_SIZE; + uint32_t MCIF_WB_BUF_CHROMA_SIZE; +}; +struct dcn10_dwbc_mask { + DWBC_REG_FIELD_LIST(uint32_t) +}; +struct dcn10_dwbc_shift { + DWBC_REG_FIELD_LIST(uint8_t) +}; +struct dcn10_dwbc { + struct dwbc base; + const struct dcn10_dwbc_registers *dwbc_regs; + const struct dcn10_dwbc_shift *dwbc_shift; + const struct dcn10_dwbc_mask *dwbc_mask; +}; + +void dcn10_dwbc_construct(struct dcn10_dwbc *dwbc10, + struct dc_context *ctx, + const struct dcn10_dwbc_registers *dwbc_regs, + const struct dcn10_dwbc_shift *dwbc_shift, + const struct dcn10_dwbc_mask *dwbc_mask, + int inst); + +#endif + +#endif 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 a1c824efa686..a780057e2dbc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -182,8 +182,43 @@ bool hubbub1_verify_allow_pstate_change_high( * 29: WB1 Allow Pstate Change * 30: Arbiter's allow_pstate_change * 31: SOC pstate change request" - * - * RV1: + */ + /*DCN2.x: + HUBBUB:DCHUBBUB_TEST_ARB_DEBUG10 DCHUBBUBDEBUGIND:0xB + 0: Pipe0 Plane0 Allow P-state Change + 1: Pipe0 Plane1 Allow P-state Change + 2: Pipe0 Cursor0 Allow P-state Change + 3: Pipe0 Cursor1 Allow P-state Change + 4: Pipe1 Plane0 Allow P-state Change + 5: Pipe1 Plane1 Allow P-state Change + 6: Pipe1 Cursor0 Allow P-state Change + 7: Pipe1 Cursor1 Allow P-state Change + 8: Pipe2 Plane0 Allow P-state Change + 9: Pipe2 Plane1 Allow P-state Change + 10: Pipe2 Cursor0 Allow P-state Change + 11: Pipe2 Cursor1 Allow P-state Change + 12: Pipe3 Plane0 Allow P-state Change + 13: Pipe3 Plane1 Allow P-state Change + 14: Pipe3 Cursor0 Allow P-state Change + 15: Pipe3 Cursor1 Allow P-state Change + 16: Pipe4 Plane0 Allow P-state Change + 17: Pipe4 Plane1 Allow P-state Change + 18: Pipe4 Cursor0 Allow P-state Change + 19: Pipe4 Cursor1 Allow P-state Change + 20: Pipe5 Plane0 Allow P-state Change + 21: Pipe5 Plane1 Allow P-state Change + 22: Pipe5 Cursor0 Allow P-state Change + 23: Pipe5 Cursor1 Allow P-state Change + 24: Pipe6 Plane0 Allow P-state Change + 25: Pipe6 Plane1 Allow P-state Change + 26: Pipe6 Cursor0 Allow P-state Change + 27: Pipe6 Cursor1 Allow P-state Change + 28: WB0 Allow P-state Change + 29: WB1 Allow P-state Change + 30: Arbiter`s Allow P-state Change + 31: SOC P-state Change request + */ + /* RV1: * dchubbubdebugind, at: 0x7 * description "3-0: Pipe0 cursor0 QOS * 7-4: Pipe1 cursor0 QOS 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 54b219a710d8..934bacc0c6ad 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -63,7 +63,7 @@ void hubp1_set_blank(struct hubp *hubp, bool blank) } hubp->mpcc_id = 0xf; - hubp->opp_id = 0xf; + hubp->opp_id = OPP_ID_INVALID; } } @@ -306,6 +306,28 @@ void hubp1_program_pixel_format( REG_UPDATE(DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, 12); break; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 112); + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 113); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 114); + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 118); + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 119); + break; +#endif default: BREAK_TO_DEBUGGER(); break; @@ -317,8 +339,7 @@ void hubp1_program_pixel_format( bool hubp1_program_surface_flip_and_addr( struct hubp *hubp, const struct dc_plane_address *address, - bool flip_immediate, - uint8_t vmid) + bool flip_immediate) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -1206,6 +1227,11 @@ static const struct hubp_funcs dcn10_hubp_funcs = { .hubp_disable_control = hubp1_disable_control, .hubp_get_underflow_status = hubp1_get_underflow_status, .hubp_init = hubp1_init, + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + .dmdata_set_attributes = NULL, + .dmdata_load = NULL, +#endif }; /*****************************************/ @@ -1226,7 +1252,7 @@ void dcn10_hubp_construct( hubp1->hubp_shift = hubp_shift; hubp1->hubp_mask = hubp_mask; hubp1->base.inst = inst; - hubp1->base.opp_id = 0xf; + hubp1->base.opp_id = OPP_ID_INVALID; hubp1->base.mpcc_id = 0xf; } 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 99d2b7e2a578..31c8fdd3206c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -459,6 +459,7 @@ type ROTATION_ANGLE;\ type H_MIRROR_EN;\ type SURFACE_PIXEL_FORMAT;\ + type ALPHA_PLANE_EN;\ type SURFACE_FLIP_TYPE;\ type SURFACE_FLIP_MODE_FOR_STEREOSYNC;\ type SURFACE_FLIP_IN_STEREOSYNC;\ @@ -715,6 +716,13 @@ void hubp1_dcc_control(struct hubp *hubp, bool enable, bool independent_64b_blks); +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +bool hubp1_program_surface_flip_and_addr( + struct hubp *hubp, + const struct dc_plane_address *address, + bool flip_immediate); + +#endif bool hubp1_is_flip_pending(struct hubp *hubp); void hubp1_cursor_set_attributes( 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 821a280eb481..e50a696fcb5d 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 @@ -23,6 +23,7 @@ * */ +#include <linux/delay.h> #include "dm_services.h" #include "core_types.h" #include "resource.h" @@ -48,6 +49,10 @@ #include "clk_mgr.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dsc.h" +#endif + #define DC_LOGGER_INIT(logger) #define CTX \ @@ -345,6 +350,62 @@ void dcn10_log_hw_state(struct dc *dc, } DTN_INFO("\n"); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + DTN_INFO("DSC: CLOCK_EN SLICE_WIDTH Bytes_pp\n"); + for (i = 0; i < pool->res_cap->num_dsc; i++) { + struct display_stream_compressor *dsc = pool->dscs[i]; + struct dcn_dsc_state s = {0}; + + dsc->funcs->dsc_read_state(dsc, &s); + DTN_INFO("[%d]: %-9d %-12d %-10d\n", + dsc->inst, + s.dsc_clock_en, + s.dsc_slice_width, + s.dsc_bytes_per_pixel); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + + DTN_INFO("S_ENC: DSC_MODE SEC_GSP7_LINE_NUM" + " VBID6_LINE_REFERENCE VBID6_LINE_NUM SEC_GSP7_ENABLE SEC_STREAM_ENABLE\n"); + for (i = 0; i < pool->stream_enc_count; i++) { + struct stream_encoder *enc = pool->stream_enc[i]; + struct enc_state s = {0}; + + if (enc->funcs->enc_read_state) { + enc->funcs->enc_read_state(enc, &s); + DTN_INFO("[%-3d]: %-9d %-18d %-21d %-15d %-16d %-17d\n", + enc->id, + s.dsc_mode, + s.sec_gsp_pps_line_num, + s.vbid6_line_reference, + s.vbid6_line_num, + s.sec_gsp_pps_enable, + s.sec_stream_enable); + DTN_INFO("\n"); + } + } + DTN_INFO("\n"); + + DTN_INFO("L_ENC: DPHY_FEC_EN DPHY_FEC_READY_SHADOW DPHY_FEC_ACTIVE_STATUS\n"); + for (i = 0; i < dc->link_count; i++) { + struct link_encoder *lenc = dc->links[i]->link_enc; + + struct link_enc_state s = {0}; + + if (lenc->funcs->read_state) { + lenc->funcs->read_state(lenc, &s); + DTN_INFO("[%-3d]: %-12d %-22d %-22d\n", + i, + s.dphy_fec_en, + s.dphy_fec_ready_shadow, + s.dphy_fec_active_status); + DTN_INFO("\n"); + } + } + DTN_INFO("\n"); +#endif + DTN_INFO("\nCALCULATED Clocks: dcfclk_khz:%d dcfclk_deep_sleep_khz:%d dispclk_khz:%d\n" "dppclk_khz:%d max_supported_dppclk_khz:%d fclk_khz:%d socclk_khz:%d\n\n", dc->current_state->bw_ctx.bw.dcn.clk.dcfclk_khz, @@ -360,6 +421,23 @@ void dcn10_log_hw_state(struct dc *dc, DTN_INFO_END(); } +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + if (tg->funcs->is_optc_underflow_occurred(tg)) { + tg->funcs->clear_optc_underflow(tg); + return true; + } + + if (hubp->funcs->hubp_get_underflow_status(hubp)) { + hubp->funcs->hubp_clear_underflow(hubp); + return true; + } + return false; +} + static void enable_power_gating_plane( struct dce_hwseq *hws, bool enable) @@ -1025,7 +1103,7 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) pipe_ctx->plane_res.dpp = dpp; pipe_ctx->plane_res.mpcc_inst = dpp->inst; hubp->mpcc_id = dpp->inst; - hubp->opp_id = 0xf; + hubp->opp_id = OPP_ID_INVALID; hubp->power_gated = false; dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; @@ -1236,8 +1314,7 @@ 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, - 0); + plane_state->flip_immediate); plane_state->status.requested_address = plane_state->address; @@ -1951,7 +2028,12 @@ static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) plane_state->format, EXPANSION_MODE_ZERO, plane_state->input_csc_color_matrix, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + plane_state->color_space, + NULL); +#else plane_state->color_space); +#endif //set scale and bias registers dcn10_build_prescale_params(&bns_params, plane_state); @@ -2153,7 +2235,7 @@ void update_dchubp_dpp( pipe_ctx, pipe_ctx->stream->output_color_space, pipe_ctx->stream->csc_color_matrix.matrix, - hubp->opp_id); + pipe_ctx->stream_res.opp->inst); } if (plane_state->update_flags.bits.full_update || @@ -2333,6 +2415,7 @@ static void dcn10_apply_ctx_for_surface( { int i; struct timing_generator *tg; + uint32_t underflow_check_delay_us; bool removed_pipe[4] = { false }; bool interdependent_update = false; struct pipe_ctx *top_pipe_to_program = @@ -2347,11 +2430,22 @@ static void dcn10_apply_ctx_for_surface( interdependent_update = top_pipe_to_program->plane_state && top_pipe_to_program->plane_state->update_flags.bits.full_update; + underflow_check_delay_us = dc->debug.underflow_assert_delay_us; + + if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) + ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (interdependent_update) lock_all_pipes(dc, context, true); else dcn10_pipe_control_lock(dc, top_pipe_to_program, true); + if (underflow_check_delay_us != 0xFFFFFFFF) + udelay(underflow_check_delay_us); + + if (underflow_check_delay_us != 0xFFFFFFFF && dc->hwss.did_underflow_occur) + ASSERT(dc->hwss.did_underflow_occur(dc, top_pipe_to_program)); + if (num_planes == 0) { /* OTG blank before remove all front end */ dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); @@ -2371,7 +2465,7 @@ static void dcn10_apply_ctx_for_surface( if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { if (old_pipe_ctx->stream_res.tg == tg && old_pipe_ctx->plane_res.hubp && - old_pipe_ctx->plane_res.hubp->opp_id != 0xf) + old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) dcn10_disable_plane(dc, old_pipe_ctx); } @@ -2391,6 +2485,11 @@ static void dcn10_apply_ctx_for_surface( if (num_planes > 0) program_all_pipe_in_tree(dc, top_pipe_to_program, context); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* Program secondary blending tree and writeback pipes */ + if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) + dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); +#endif if (interdependent_update) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -3023,7 +3122,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .disable_stream_gating = NULL, .enable_stream_gating = NULL, .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt + .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h index ef94d6b15843..d3616b1948cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -71,6 +71,8 @@ void dcn10_get_hdr_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color); +bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx); + void update_dchubp_dpp( struct dc *dc, struct pipe_ctx *pipe_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c index 0e0c6850247d..0fb9e440cb9d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c @@ -53,6 +53,12 @@ static const struct ipp_funcs dcn10_ipp_funcs = { .ipp_destroy = dcn10_ipp_destroy }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +static const struct ipp_funcs dcn20_ipp_funcs = { + .ipp_destroy = dcn10_ipp_destroy +}; +#endif + void dcn10_ipp_construct( struct dcn10_ipp *ippn10, struct dc_context *ctx, @@ -70,3 +76,21 @@ void dcn10_ipp_construct( ippn10->ipp_mask = ipp_mask; } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +void dcn20_ipp_construct( + struct dcn10_ipp *ippn10, + struct dc_context *ctx, + int inst, + const struct dcn10_ipp_registers *regs, + const struct dcn10_ipp_shift *ipp_shift, + const struct dcn10_ipp_mask *ipp_mask) +{ + ippn10->base.ctx = ctx; + ippn10->base.inst = inst; + ippn10->base.funcs = &dcn20_ipp_funcs; + + ippn10->regs = regs; + ippn10->ipp_shift = ipp_shift; + ippn10->ipp_mask = ipp_mask; +} +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h index 819b749c6e31..cfa24459242b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h @@ -49,6 +49,19 @@ SRI(CURSOR_HOT_SPOT, CURSOR, id), \ SRI(CURSOR_DST_OFFSET, CURSOR, id) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define IPP_REG_LIST_DCN20(id) \ + IPP_REG_LIST_DCN(id), \ + SRI(CURSOR_SETTINGS, HUBPREQ, id), \ + SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \ + SRI(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \ + SRI(CURSOR_SIZE, CURSOR0_, id), \ + SRI(CURSOR_CONTROL, CURSOR0_, id), \ + SRI(CURSOR_POSITION, CURSOR0_, id), \ + SRI(CURSOR_HOT_SPOT, CURSOR0_, id), \ + SRI(CURSOR_DST_OFFSET, CURSOR0_, id) +#endif + #define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 #define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L #define CURSOR1_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 @@ -92,6 +105,27 @@ IPP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ IPP_SF(CNVC_CFG0_FORMAT_CONTROL, OUTPUT_FP, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define IPP_MASK_SH_LIST_DCN20(mask_sh) \ + IPP_MASK_SH_LIST_DCN(mask_sh), \ + IPP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \ + IPP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + IPP_SF(CURSOR0_0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) +#endif + #define IPP_DCN10_REG_FIELD_LIST(type) \ type CNVC_SURFACE_PIXEL_FORMAT; \ type CNVC_BYPASS; \ @@ -162,4 +196,13 @@ void dcn10_ipp_construct(struct dcn10_ipp *ippn10, const struct dcn10_ipp_shift *ipp_shift, const struct dcn10_ipp_mask *ipp_mask); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +void dcn20_ipp_construct(struct dcn10_ipp *ippn10, + struct dc_context *ctx, + int inst, + const struct dcn10_ipp_registers *regs, + const struct dcn10_ipp_shift *ipp_shift, + const struct dcn10_ipp_mask *ipp_mask); +#endif + #endif /* _DCN10_IPP_H_ */ 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 0a520591fd3a..549d423a01f6 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 @@ -232,7 +232,9 @@ static void setup_panel_mode( { uint32_t value; - ASSERT(REG(DP_DPHY_INTERNAL_CTRL)); + if (!REG(DP_DPHY_INTERNAL_CTRL)) + return; + value = REG_READ(DP_DPHY_INTERNAL_CTRL); switch (panel_mode) { 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 b74b80a247ec..33b2af1a181c 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 @@ -72,6 +72,9 @@ struct dcn10_link_enc_aux_registers { uint32_t AUX_CONTROL; uint32_t AUX_DPHY_RX_CONTROL0; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + uint32_t AUX_DPHY_TX_CONTROL; +#endif }; struct dcn10_link_enc_hpd_registers { @@ -103,6 +106,23 @@ struct dcn10_link_enc_registers { uint32_t DP_DPHY_HBR2_PATTERN_CONTROL; uint32_t DP_SEC_CNTL1; uint32_t TMDS_CTL_BITS; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* DCCG */ + uint32_t CLOCK_ENABLE; + /* DIG */ + uint32_t DIG_LANE_ENABLE; + /* UNIPHY */ + uint32_t CHANNEL_XBAR_CNTL; + /* indirect registers */ + uint32_t RAWLANE0_DIG_PCS_XF_RX_OVRD_IN_2; + uint32_t RAWLANE0_DIG_PCS_XF_RX_OVRD_IN_3; + uint32_t RAWLANE1_DIG_PCS_XF_RX_OVRD_IN_2; + uint32_t RAWLANE1_DIG_PCS_XF_RX_OVRD_IN_3; + uint32_t RAWLANE2_DIG_PCS_XF_RX_OVRD_IN_2; + uint32_t RAWLANE2_DIG_PCS_XF_RX_OVRD_IN_3; + uint32_t RAWLANE3_DIG_PCS_XF_RX_OVRD_IN_2; + uint32_t RAWLANE3_DIG_PCS_XF_RX_OVRD_IN_3; +#endif }; #define LE_SF(reg_name, field_name, post_fix)\ @@ -208,12 +228,166 @@ struct dcn10_link_enc_registers { type AUX_LS_READ_EN;\ type AUX_RX_RECEIVE_WINDOW +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + +#define DCN20_LINK_ENCODER_DPCS_REG_FIELD_LIST(type) \ + type RDPCS_PHY_DP_TX0_DATA_EN;\ + type RDPCS_PHY_DP_TX1_DATA_EN;\ + type RDPCS_PHY_DP_TX2_DATA_EN;\ + type RDPCS_PHY_DP_TX3_DATA_EN;\ + type RDPCS_PHY_DP_TX0_PSTATE;\ + type RDPCS_PHY_DP_TX1_PSTATE;\ + type RDPCS_PHY_DP_TX2_PSTATE;\ + type RDPCS_PHY_DP_TX3_PSTATE;\ + type RDPCS_PHY_DP_TX0_MPLL_EN;\ + type RDPCS_PHY_DP_TX1_MPLL_EN;\ + type RDPCS_PHY_DP_TX2_MPLL_EN;\ + type RDPCS_PHY_DP_TX3_MPLL_EN;\ + type RDPCS_TX_FIFO_LANE0_EN;\ + type RDPCS_TX_FIFO_LANE1_EN;\ + type RDPCS_TX_FIFO_LANE2_EN;\ + type RDPCS_TX_FIFO_LANE3_EN;\ + type RDPCS_EXT_REFCLK_EN;\ + type RDPCS_TX_FIFO_EN;\ + type UNIPHY_LINK_ENABLE;\ + type UNIPHY_CHANNEL0_INVERT;\ + type UNIPHY_CHANNEL1_INVERT;\ + type UNIPHY_CHANNEL2_INVERT;\ + type UNIPHY_CHANNEL3_INVERT;\ + type UNIPHY_LINK_ENABLE_HPD_MASK;\ + type UNIPHY_LANE_STAGGER_DELAY;\ + type RDPCS_SRAMCLK_BYPASS;\ + type RDPCS_SRAMCLK_EN;\ + type RDPCS_SRAMCLK_CLOCK_ON;\ + type DPCS_TX_FIFO_EN;\ + type RDPCS_PHY_DP_TX0_DISABLE;\ + type RDPCS_PHY_DP_TX1_DISABLE;\ + type RDPCS_PHY_DP_TX2_DISABLE;\ + type RDPCS_PHY_DP_TX3_DISABLE;\ + type RDPCS_PHY_DP_TX0_CLK_RDY;\ + type RDPCS_PHY_DP_TX1_CLK_RDY;\ + type RDPCS_PHY_DP_TX2_CLK_RDY;\ + type RDPCS_PHY_DP_TX3_CLK_RDY;\ + type RDPCS_PHY_DP_TX0_REQ;\ + type RDPCS_PHY_DP_TX1_REQ;\ + type RDPCS_PHY_DP_TX2_REQ;\ + type RDPCS_PHY_DP_TX3_REQ;\ + type RDPCS_PHY_DP_TX0_ACK;\ + type RDPCS_PHY_DP_TX1_ACK;\ + type RDPCS_PHY_DP_TX2_ACK;\ + type RDPCS_PHY_DP_TX3_ACK;\ + type RDPCS_PHY_DP_TX0_RESET;\ + type RDPCS_PHY_DP_TX1_RESET;\ + type RDPCS_PHY_DP_TX2_RESET;\ + type RDPCS_PHY_DP_TX3_RESET;\ + type RDPCS_PHY_RESET;\ + type RDPCS_PHY_CR_MUX_SEL;\ + type RDPCS_PHY_REF_RANGE;\ + type RDPCS_PHY_DP4_POR;\ + type RDPCS_SRAM_BYPASS;\ + type RDPCS_SRAM_EXT_LD_DONE;\ + type RDPCS_PHY_DP_TX0_TERM_CTRL;\ + type RDPCS_PHY_DP_TX1_TERM_CTRL;\ + type RDPCS_PHY_DP_TX2_TERM_CTRL;\ + type RDPCS_PHY_DP_TX3_TERM_CTRL;\ + type RDPCS_PHY_DP_REF_CLK_MPLLB_DIV;\ + type RDPCS_PHY_DP_MPLLB_MULTIPLIER;\ + type RDPCS_PHY_DP_MPLLB_SSC_EN;\ + type RDPCS_PHY_DP_MPLLB_DIV5_CLK_EN;\ + type RDPCS_PHY_DP_MPLLB_TX_CLK_DIV;\ + type RDPCS_PHY_DP_MPLLB_WORD_DIV2_EN;\ + type RDPCS_PHY_DP_MPLLB_FRACN_EN;\ + type RDPCS_PHY_DP_MPLLB_PMIX_EN;\ + type RDPCS_PHY_DP_MPLLB_FRACN_QUOT;\ + type RDPCS_PHY_DP_MPLLB_FRACN_DEN;\ + type RDPCS_PHY_DP_MPLLB_FRACN_REM;\ + type RDPCS_PHY_DP_MPLLB_SSC_UP_SPREAD;\ + type RDPCS_PHY_DP_MPLLB_SSC_STEPSIZE;\ + type RDPCS_PHY_DP_MPLLB_SSC_PEAK;\ + type RDPCS_PHY_DP_MPLLB_DIV_CLK_EN;\ + type RDPCS_PHY_DP_MPLLB_DIV_MULTIPLIER;\ + type RDPCS_PHY_TX_VBOOST_LVL;\ + type RDPCS_PHY_HDMIMODE_ENABLE;\ + type RDPCS_PHY_DP_REF_CLK_EN;\ + type RDPCS_PLL_UPDATE_DATA;\ + type RDPCS_SRAM_INIT_DONE;\ + type RDPCS_TX_CR_ADDR;\ + type RDPCS_TX_CR_DATA;\ + type RDPCS_PHY_HDMI_MPLLB_HDMI_DIV;\ + type RDPCS_PHY_DP_MPLLB_STATE;\ + type RDPCS_PHY_DP_TX0_WIDTH;\ + type RDPCS_PHY_DP_TX0_RATE;\ + type RDPCS_PHY_DP_TX1_WIDTH;\ + type RDPCS_PHY_DP_TX1_RATE;\ + type RDPCS_PHY_DP_TX2_WIDTH;\ + type RDPCS_PHY_DP_TX2_RATE;\ + type RDPCS_PHY_DP_TX3_WIDTH;\ + type RDPCS_PHY_DP_TX3_RATE;\ + type DPCS_SYMCLK_CLOCK_ON;\ + type DPCS_SYMCLK_GATE_DIS;\ + type DPCS_SYMCLK_EN;\ + type RDPCS_SYMCLK_DIV2_CLOCK_ON;\ + type RDPCS_SYMCLK_DIV2_GATE_DIS;\ + type RDPCS_SYMCLK_DIV2_EN;\ + type DPCS_TX_DATA_SWAP;\ + type DPCS_TX_DATA_ORDER_INVERT;\ + type DPCS_TX_FIFO_RD_START_DELAY;\ + type RDPCS_TX_FIFO_RD_START_DELAY;\ + type RDPCS_REG_FIFO_ERROR_MASK;\ + type RDPCS_TX_FIFO_ERROR_MASK;\ + type RDPCS_DPALT_DISABLE_TOGGLE_MASK;\ + type RDPCS_DPALT_4LANE_TOGGLE_MASK;\ + type RDPCS_PHY_DPALT_DISABLE_ACK;\ + type RDPCS_PHY_DP_MPLLB_V2I;\ + type RDPCS_PHY_DP_MPLLB_FREQ_VCO;\ + type RDPCS_PHY_DP_MPLLB_CP_INT;\ + type RDPCS_PHY_DP_MPLLB_CP_PROP;\ + type RDPCS_PHY_RX_REF_LD_VAL;\ + type RDPCS_PHY_RX_VCO_LD_VAL;\ + type DPCSTX_DEBUG_CONFIG; \ + type RDPCSTX_DEBUG_CONFIG + +#define DCN20_LINK_ENCODER_REG_FIELD_LIST(type) \ + type DIG_LANE0EN;\ + type DIG_LANE1EN;\ + type DIG_LANE2EN;\ + type DIG_LANE3EN;\ + type DIG_CLK_EN;\ + type SYMCLKA_CLOCK_ENABLE;\ + type DPHY_FEC_EN;\ + type DPHY_FEC_READY_SHADOW;\ + type DPHY_FEC_ACTIVE_STATUS;\ + DCN20_LINK_ENCODER_DPCS_REG_FIELD_LIST(type);\ + type VCO_LD_VAL_OVRD;\ + type VCO_LD_VAL_OVRD_EN;\ + type REF_LD_VAL_OVRD;\ + type REF_LD_VAL_OVRD_EN;\ + type AUX_RX_START_WINDOW; \ + type AUX_RX_HALF_SYM_DETECT_LEN; \ + type AUX_RX_TRANSITION_FILTER_EN; \ + type AUX_RX_ALLOW_BELOW_THRESHOLD_PHASE_DETECT; \ + type AUX_RX_ALLOW_BELOW_THRESHOLD_START; \ + type AUX_RX_ALLOW_BELOW_THRESHOLD_STOP; \ + type AUX_RX_PHASE_DETECT_LEN; \ + type AUX_RX_DETECTION_THRESHOLD; \ + type AUX_TX_PRECHARGE_LEN; \ + type AUX_TX_PRECHARGE_SYMBOLS; \ + type AUX_MODE_DET_CHECK_DELAY;\ + type DPCS_DBG_CBUS_DIS +#endif + struct dcn10_link_enc_shift { DCN_LINK_ENCODER_REG_FIELD_LIST(uint8_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + DCN20_LINK_ENCODER_REG_FIELD_LIST(uint8_t); +#endif }; struct dcn10_link_enc_mask { DCN_LINK_ENCODER_REG_FIELD_LIST(uint32_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + DCN20_LINK_ENCODER_REG_FIELD_LIST(uint32_t); +#endif }; struct dcn10_link_encoder { diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c index 958994edf2c4..0bca011ed7c9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -438,6 +438,12 @@ static const struct mpc_funcs dcn10_mpc_funcs = { .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect, .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw, .update_blending = mpc1_update_blending, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + .set_denorm = NULL, + .set_denorm_clamp = NULL, + .set_output_csc = NULL, + .set_output_gamma = NULL, +#endif }; void dcn10_mpc_construct(struct dcn10_mpc *mpc10, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c index cec69cecf521..e9ebbbe256b4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -367,6 +367,11 @@ void opp1_program_oppbuf( */ REG_UPDATE(OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, oppbuf->pixel_repetition); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* Controls the number of padded pixels at the end of a segment */ + if (REG(OPPBUF_CONTROL1)) + REG_UPDATE(OPPBUF_CONTROL1, OPPBUF_NUM_SEGMENT_PADDED_PIXELS, oppbuf->num_segment_padded_pixels); +#endif } void opp1_pipe_clock_control(struct output_pixel_processor *opp, bool enable) @@ -393,6 +398,9 @@ static const struct opp_funcs dcn10_opp_funcs = { .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, .opp_program_stereo = opp1_program_stereo, .opp_pipe_clock_control = opp1_pipe_clock_control, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + .opp_set_disp_pattern_generator = NULL, +#endif .opp_destroy = opp1_destroy }; 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 e4b850a2d31f..a546c2bc9129 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -584,6 +584,13 @@ uint32_t optc1_get_vblank_counter(struct timing_generator *optc) void optc1_lock(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t regval = 0; + + regval = REG_READ(OTG_CONTROL); + + /* otg is not running, do not need to be locked */ + if ((regval & 0x1) == 0x0) + return; REG_SET(OTG_GLOBAL_CONTROL0, 0, OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); @@ -591,10 +598,12 @@ void optc1_lock(struct timing_generator *optc) OTG_MASTER_UPDATE_LOCK, 1); /* Should be fast, status does not update on maximus */ - if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) { + REG_WAIT(OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, 1, 1, 10); + } } void optc1_unlock(struct timing_generator *optc) @@ -1507,10 +1516,28 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->comb_opp_id = 0xf; } +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: + * + * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as + * containter rate. + * + * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be + * halved to maintain the correct pixel rate. + * + * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied + * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. + * + */ +#endif bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) { bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 + && !timing->dsc_cfg.ycbcr422_simple); +#endif 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 444c56c8104f..02599eb92ca6 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -89,7 +89,6 @@ SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) - #define TG_COMMON_REG_LIST_DCN1_0(inst) \ TG_COMMON_REG_LIST_DCN(inst),\ SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ @@ -164,6 +163,13 @@ struct dcn_optc_registers { uint32_t OTG_CRC0_WINDOWB_X_CONTROL; uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; uint32_t GSL_SOURCE_SELECT; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + uint32_t DWB_SOURCE_SELECT; + uint32_t OTG_DSC_START_POSITION; + uint32_t OPTC_DATA_FORMAT_CONTROL; + uint32_t OPTC_BYTES_PER_PIXEL; + uint32_t OPTC_WIDTH_CONTROL; +#endif }; #define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ @@ -442,10 +448,36 @@ struct dcn_optc_registers { type MANUAL_FLOW_CONTROL;\ type MANUAL_FLOW_CONTROL_SEL; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + +#define TG_REG_FIELD_LIST(type) \ + TG_REG_FIELD_LIST_DCN1_0(type)\ + type MASTER_UPDATE_LOCK_DB_X;\ + type MASTER_UPDATE_LOCK_DB_Y;\ + type MASTER_UPDATE_LOCK_DB_EN;\ + type GLOBAL_UPDATE_LOCK_EN;\ + type DIG_UPDATE_LOCATION;\ + type OTG_DSC_START_POSITION_X;\ + type OTG_DSC_START_POSITION_LINE_NUM;\ + type OPTC_NUM_OF_INPUT_SEGMENT;\ + type OPTC_SEG0_SRC_SEL;\ + type OPTC_SEG1_SRC_SEL;\ + type OPTC_MEM_SEL;\ + type OPTC_DATA_FORMAT;\ + type OPTC_DSC_MODE;\ + type OPTC_DSC_BYTES_PER_PIXEL;\ + type OPTC_DSC_SLICE_WIDTH;\ + type OPTC_SEGMENT_WIDTH;\ + type OPTC_DWB0_SOURCE_SELECT;\ + type OPTC_DWB1_SOURCE_SELECT; + +#else #define TG_REG_FIELD_LIST(type) \ TG_REG_FIELD_LIST_DCN1_0(type) +#endif + struct dcn_optc_shift { TG_REG_FIELD_LIST(uint8_t) 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 3272030c82c5..1a20461c2937 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -562,6 +562,7 @@ static const struct dc_debug_options debug_defaults_drv = { .az_endpoint_mute_only = true, .recovery_enabled = false, /*enable this by default after testing.*/ .max_downscale_src_width = 3840, + .underflow_assert_delay_us = 0xFFFFFFFF, }; static const struct dc_debug_options debug_defaults_diags = { @@ -571,7 +572,8 @@ static const struct dc_debug_options debug_defaults_diags = { .clock_trace = true, .disable_stutter = true, .disable_pplib_clock_request = true, - .disable_pplib_wm_range = true + .disable_pplib_wm_range = true, + .underflow_assert_delay_us = 0xFFFFFFFF, }; static void dcn10_dpp_destroy(struct dpp **dpp) 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 46c93ffc28d2..bc2b4af9543b 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 @@ -82,6 +82,7 @@ SRI(DP_PIXEL_FORMAT, DP, id), \ SRI(DP_SEC_CNTL, DP, id), \ SRI(DP_SEC_CNTL2, DP, id), \ + SRI(DP_SEC_CNTL6, DP, id), \ SRI(DP_STEER_FIFO, DP, id), \ SRI(DP_VID_M, DP, id), \ SRI(DP_VID_N, DP, id), \ @@ -125,6 +126,7 @@ struct dcn10_stream_enc_registers { uint32_t DP_PIXEL_FORMAT; uint32_t DP_SEC_CNTL; uint32_t DP_SEC_CNTL2; + uint32_t DP_SEC_CNTL6; uint32_t DP_STEER_FIFO; uint32_t DP_VID_M; uint32_t DP_VID_N; @@ -153,12 +155,21 @@ struct dcn10_stream_enc_registers { uint32_t HDMI_ACR_48_1; uint32_t DP_DB_CNTL; uint32_t DP_MSA_MISC; + uint32_t DP_MSA_VBID_MISC; uint32_t DP_MSA_COLORIMETRY; uint32_t DP_MSA_TIMING_PARAM1; uint32_t DP_MSA_TIMING_PARAM2; uint32_t DP_MSA_TIMING_PARAM3; uint32_t DP_MSA_TIMING_PARAM4; uint32_t HDMI_DB_CONTROL; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint32_t DP_DSC_CNTL; + uint32_t DP_DSC_BYTES_PER_PIXEL; + uint32_t DME_CONTROL; + uint32_t DP_SEC_METADATA_TRANSMISSION; + uint32_t HDMI_METADATA_PACKET_CONTROL; + uint32_t DP_SEC_FRAMING4; +#endif }; @@ -271,6 +282,7 @@ struct dcn10_stream_enc_registers { SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_PPS, mask_sh),\ SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_SEND, mask_sh),\ + SE_SF(DP0_DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, mask_sh),\ SE_SF(DP0_DP_DB_CNTL, DP_DB_DISABLE, mask_sh),\ SE_SF(DP0_DP_MSA_COLORIMETRY, DP_MSA_MISC0, mask_sh),\ SE_SF(DP0_DP_MSA_TIMING_PARAM1, DP_MSA_HTOTAL, mask_sh),\ @@ -424,6 +436,7 @@ struct dcn10_stream_enc_registers { type DP_SEC_ATP_ENABLE;\ type DP_SEC_AIP_ENABLE;\ type DP_SEC_ACM_ENABLE;\ + type DP_SEC_GSP7_LINE_NUM;\ type AFMT_AUDIO_SAMPLE_SEND;\ type AFMT_AUDIO_CLOCK_EN;\ type TMDS_PIXEL_ENCODING;\ @@ -447,12 +460,39 @@ struct dcn10_stream_enc_registers { type DP_VID_M_DOUBLE_VALUE_EN;\ type DIG_SOURCE_SELECT +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define SE_REG_FIELD_LIST_DCN2_0(type) \ + type DP_DSC_MODE;\ + type DP_DSC_SLICE_WIDTH;\ + type DP_DSC_BYTES_PER_PIXEL;\ + type DP_VBID6_LINE_REFERENCE;\ + type DP_VBID6_LINE_NUM;\ + type METADATA_ENGINE_EN;\ + type METADATA_HUBP_REQUESTOR_ID;\ + type METADATA_STREAM_TYPE;\ + type DP_SEC_METADATA_PACKET_ENABLE;\ + type DP_SEC_METADATA_PACKET_LINE_REFERENCE;\ + type DP_SEC_METADATA_PACKET_LINE;\ + type HDMI_METADATA_PACKET_ENABLE;\ + type HDMI_METADATA_PACKET_LINE_REFERENCE;\ + type HDMI_METADATA_PACKET_LINE;\ + type DOLBY_VISION_EN;\ + type DP_PIXEL_COMBINE;\ + type DP_SST_SDP_SPLITTING +#endif + struct dcn10_stream_encoder_shift { SE_REG_FIELD_LIST_DCN1_0(uint8_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + SE_REG_FIELD_LIST_DCN2_0(uint8_t); +#endif }; struct dcn10_stream_encoder_mask { SE_REG_FIELD_LIST_DCN1_0(uint32_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + SE_REG_FIELD_LIST_DCN2_0(uint32_t); +#endif }; struct dcn10_stream_encoder { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile new file mode 100644 index 000000000000..e9721a906592 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for DCN. + +DCN20 = dcn20_resource.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ + dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ + dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ + dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o + +ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +DCN20 += dcn20_dsc.o +endif + +ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) + cc_stack_align := -mpreferred-stack-boundary=4 +else ifneq ($(call cc-option, -mstack-alignment=16),) + cc_stack_align := -mstack-alignment=16 +endif + +CFLAGS_dcn20_resource.o := -mhard-float -msse $(cc_stack_align) + +AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCN20) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c new file mode 100644 index 000000000000..51a3dfe97f0e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c @@ -0,0 +1,159 @@ +/* + * 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 <linux/slab.h> + +#include "reg_helper.h" +#include "core_types.h" +#include "dcn20_dccg.h" + +#define TO_DCN_DCCG(dccg)\ + container_of(dccg, struct dcn_dccg, base) + +#define REG(reg) \ + (dccg_dcn->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name + +#define CTX \ + dccg_dcn->base.ctx +#define DC_LOGGER \ + dccg->ctx->logger + +void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + if (dccg->ref_dppclk && req_dppclk) { + int ref_dppclk = dccg->ref_dppclk; + + ASSERT(req_dppclk <= ref_dppclk); + /* need to clamp to 8 bits */ + if (ref_dppclk > 0xff) { + int divider = (ref_dppclk + 0xfe) / 0xff; + + ref_dppclk /= divider; + req_dppclk = (req_dppclk + divider - 1) / divider; + if (req_dppclk > ref_dppclk) + req_dppclk = ref_dppclk; + } + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, req_dppclk, + DPPCLK0_DTO_MODULO, ref_dppclk); + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 1); + } else { + REG_UPDATE(DPPCLK_DTO_CTRL, + DPPCLK_DTO_ENABLE[dpp_inst], 0); + } +} + +void dccg2_get_dccg_ref_freq(struct dccg *dccg, + unsigned int xtalin_freq_inKhz, + unsigned int *dccg_ref_freq_inKhz) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t clk_en = 0; + uint32_t clk_sel = 0; + + REG_GET_2(REFCLK_CNTL, REFCLK_CLOCK_EN, &clk_en, REFCLK_SRC_SEL, &clk_sel); + + if (clk_en != 0) { + // DCN20 has never been validated for non-xtalin as reference + // frequency. There's actually no way for DC to determine what + // frequency a non-xtalin source is. + ASSERT_CRITICAL(false); + } + + *dccg_ref_freq_inKhz = xtalin_freq_inKhz; + + return; +} + +void dccg2_init(struct dccg *dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + // Fallthrough intentional to program all available dpp_dto's + switch (dccg_dcn->base.ctx->dc->res_pool->pipe_count) { + case 6: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[5], 1); + case 5: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[4], 1); + case 4: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[3], 1); + case 3: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[2], 1); + case 2: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[1], 1); + case 1: + REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_DB_EN[0], 1); + break; + default: + ASSERT(false); + break; + } +} + +static const struct dccg_funcs dccg2_funcs = { + .update_dpp_dto = dccg2_update_dpp_dto, + .get_dccg_ref_freq = dccg2_get_dccg_ref_freq, + .dccg_init = dccg2_init +}; + +struct dccg *dccg2_create( + struct dc_context *ctx, + const struct dccg_registers *regs, + const struct dccg_shift *dccg_shift, + const struct dccg_mask *dccg_mask) +{ + struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL); + struct dccg *base; + + if (dccg_dcn == NULL) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + base = &dccg_dcn->base; + base->ctx = ctx; + base->funcs = &dccg2_funcs; + + dccg_dcn->regs = regs; + dccg_dcn->dccg_shift = dccg_shift; + dccg_dcn->dccg_mask = dccg_mask; + + return &dccg_dcn->base; +} + +void dcn_dccg_destroy(struct dccg **dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(*dccg); + + kfree(dccg_dcn); + *dccg = NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h new file mode 100644 index 000000000000..2205cb0204e7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -0,0 +1,116 @@ +/* + * 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 + * + */ + +#ifndef __DCN20_DCCG_H__ +#define __DCN20_DCCG_H__ + +#include "dccg.h" + +#define DCCG_COMMON_REG_LIST_DCN_BASE() \ + SR(DPPCLK_DTO_CTRL),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 0),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 1),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 2),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 3),\ + SR(REFCLK_CNTL) + +#define DCCG_REG_LIST_DCN2() \ + DCCG_COMMON_REG_LIST_DCN_BASE(),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 4),\ + DCCG_SRII(DTO_PARAM, DPPCLK, 5) + +#define DCCG_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SFI(reg_name, field_name, field_prefix, inst, post_fix)\ + .field_prefix ## _ ## field_name[inst] = reg_name ## __ ## field_prefix ## inst ## _ ## field_name ## post_fix + +#define DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh) \ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 0, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 1, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 2, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 3, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\ + DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(REFCLK_CNTL, REFCLK_CLOCK_EN, mask_sh),\ + DCCG_SF(REFCLK_CNTL, REFCLK_SRC_SEL, mask_sh) + +#define DCCG_MASK_SH_LIST_DCN2(mask_sh) \ + DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 4, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 4, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_ENABLE, DPPCLK, 5, mask_sh),\ + DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 5, mask_sh) + +#define DCCG_REG_FIELD_LIST(type) \ + type DPPCLK0_DTO_PHASE;\ + type DPPCLK0_DTO_MODULO;\ + type DPPCLK_DTO_ENABLE[6];\ + type DPPCLK_DTO_DB_EN[6];\ + type REFCLK_CLOCK_EN;\ + type REFCLK_SRC_SEL; + +struct dccg_shift { + DCCG_REG_FIELD_LIST(uint8_t) +}; + +struct dccg_mask { + DCCG_REG_FIELD_LIST(uint32_t) +}; + +struct dccg_registers { + uint32_t DPPCLK_DTO_CTRL; + uint32_t DPPCLK_DTO_PARAM[6]; + uint32_t REFCLK_CNTL; +}; + +struct dcn_dccg { + struct dccg base; + const struct dccg_registers *regs; + const struct dccg_shift *dccg_shift; + const struct dccg_mask *dccg_mask; +}; + +void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk); + +void dccg2_get_dccg_ref_freq(struct dccg *dccg, + unsigned int xtalin_freq_inKhz, + unsigned int *dccg_ref_freq_inKhz); + +void dccg2_init(struct dccg *dccg); + +struct dccg *dccg2_create( + struct dc_context *ctx, + const struct dccg_registers *regs, + const struct dccg_shift *dccg_shift, + const struct dccg_mask *dccg_mask); + +void dcn_dccg_destroy(struct dccg **dccg); + +#endif //__DCN20_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c new file mode 100644 index 000000000000..9bc5dd23d297 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c @@ -0,0 +1,502 @@ +/* + * Copyright 2016 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 "core_types.h" + +#include "reg_helper.h" +#include "dcn20_dpp.h" +#include "basics/conversion.h" + +#define NUM_PHASES 64 +#define HORZ_MAX_TAPS 8 +#define VERT_MAX_TAPS 8 + +#define BLACK_OFFSET_RGB_Y 0x0 +#define BLACK_OFFSET_CBCR 0x8000 + +#define REG(reg)\ + dpp->tf_regs->reg + +#define CTX \ + dpp->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dpp->tf_shift->field_name, dpp->tf_mask->field_name + +void dpp20_read_state(struct dpp *dpp_base, + struct dcn_dpp_state *s) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_GET(DPP_CONTROL, + DPP_CLOCK_ENABLE, &s->is_enabled); + REG_GET(CM_DGAM_CONTROL, + CM_DGAM_LUT_MODE, &s->dgam_lut_mode); + // BGAM has no ROM, and definition is different, can't reuse same dump + //REG_GET(CM_BLNDGAM_CONTROL, + // CM_BLNDGAM_LUT_MODE, &s->rgam_lut_mode); + REG_GET(CM_GAMUT_REMAP_CONTROL, + CM_GAMUT_REMAP_MODE, &s->gamut_remap_mode); + if (s->gamut_remap_mode) { + s->gamut_remap_c11_c12 = REG_READ(CM_GAMUT_REMAP_C11_C12); + s->gamut_remap_c13_c14 = REG_READ(CM_GAMUT_REMAP_C13_C14); + s->gamut_remap_c21_c22 = REG_READ(CM_GAMUT_REMAP_C21_C22); + s->gamut_remap_c23_c24 = REG_READ(CM_GAMUT_REMAP_C23_C24); + s->gamut_remap_c31_c32 = REG_READ(CM_GAMUT_REMAP_C31_C32); + s->gamut_remap_c33_c34 = REG_READ(CM_GAMUT_REMAP_C33_C34); + } +} + +void dpp2_dummy_program_input_lut( + struct dpp *dpp_base, + const struct dc_gamma *gamma) +{} + +static void dpp2_cnv_setup ( + struct dpp *dpp_base, + enum surface_pixel_format format, + enum expansion_mode mode, + struct dc_csc_transform input_csc_color_matrix, + enum dc_color_space input_color_space, + struct cnv_alpha_2bit_lut *alpha_2bit_lut) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + uint32_t pixel_format = 0; + uint32_t alpha_en = 1; + enum dc_color_space color_space = COLOR_SPACE_SRGB; + enum dcn10_input_csc_select select = INPUT_CSC_SELECT_BYPASS; + bool force_disable_cursor = false; + struct out_csc_color_matrix tbl_entry; + uint32_t is_2bit = 0; + int i = 0; + + REG_SET_2(FORMAT_CONTROL, 0, + CNVC_BYPASS, 0, + FORMAT_EXPANSION_MODE, mode); + + //hardcode default + //FORMAT_CONTROL. FORMAT_CNV16 default 0: U0.16/S.1.15; 1: U1.15/ S.1.14 + //FORMAT_CONTROL. CNVC_BYPASS_MSB_ALIGN default 0: disabled 1: enabled + //FORMAT_CONTROL. CLAMP_POSITIVE default 0: disabled 1: enabled + //FORMAT_CONTROL. CLAMP_POSITIVE_C default 0: disabled 1: enabled + REG_UPDATE(FORMAT_CONTROL, FORMAT_CNV16, 0); + REG_UPDATE(FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, 0); + REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE, 0); + REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE_C, 0); + + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + pixel_format = 1; + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + pixel_format = 3; + alpha_en = 0; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + pixel_format = 8; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + pixel_format = 10; + is_2bit = 1; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + force_disable_cursor = false; + pixel_format = 65; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + force_disable_cursor = true; + pixel_format = 64; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + force_disable_cursor = true; + pixel_format = 67; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + force_disable_cursor = true; + pixel_format = 66; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + pixel_format = 22; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + pixel_format = 24; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + pixel_format = 25; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: + pixel_format = 12; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: + pixel_format = 112; + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: + pixel_format = 113; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010: + pixel_format = 114; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + is_2bit = 1; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102: + pixel_format = 115; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + is_2bit = 1; + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: + pixel_format = 118; + break; + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: + pixel_format = 119; + break; + default: + break; + } + + if (is_2bit == 1 && alpha_2bit_lut != NULL) { + REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0); + REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1); + REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT2, alpha_2bit_lut->lut2); + REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT3, alpha_2bit_lut->lut3); + } + + REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0, + CNVC_SURFACE_PIXEL_FORMAT, pixel_format); + REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en); + + // if input adjustments exist, program icsc with those values + if (input_csc_color_matrix.enable_adjustment + == true) { + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = input_csc_color_matrix.matrix[i]; + + tbl_entry.color_space = input_color_space; + + if (color_space >= COLOR_SPACE_YCBCR601) + select = INPUT_CSC_SELECT_ICSC; + else + select = INPUT_CSC_SELECT_BYPASS; + + dpp1_program_input_csc(dpp_base, color_space, select, &tbl_entry); + } else + dpp1_program_input_csc(dpp_base, color_space, select, NULL); + + if (force_disable_cursor) { + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, 0); + REG_UPDATE(CURSOR0_CONTROL, + CUR0_ENABLE, 0); + + } + +} + +void dpp2_cnv_set_bias_scale( + struct dpp *dpp_base, + struct dc_bias_and_scale *bias_and_scale) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(FCNV_FP_BIAS_R, FCNV_FP_BIAS_R, bias_and_scale->bias_red); + REG_UPDATE(FCNV_FP_BIAS_G, FCNV_FP_BIAS_G, bias_and_scale->bias_green); + REG_UPDATE(FCNV_FP_BIAS_B, FCNV_FP_BIAS_B, bias_and_scale->bias_blue); + REG_UPDATE(FCNV_FP_SCALE_R, FCNV_FP_SCALE_R, bias_and_scale->scale_red); + REG_UPDATE(FCNV_FP_SCALE_G, FCNV_FP_SCALE_G, bias_and_scale->scale_green); + REG_UPDATE(FCNV_FP_SCALE_B, FCNV_FP_SCALE_B, bias_and_scale->scale_blue); +} + +/*compute the maximum number of lines that we can fit in the line buffer*/ +void dscl2_calc_lb_num_partitions( + const struct scaler_data *scl_data, + enum lb_memory_config lb_config, + int *num_part_y, + int *num_part_c) +{ + int memory_line_size_y, memory_line_size_c, memory_line_size_a, + lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a; + + int line_size = scl_data->viewport.width < scl_data->recout.width ? + scl_data->viewport.width : scl_data->recout.width; + int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ? + scl_data->viewport_c.width : scl_data->recout.width; + + if (line_size == 0) + line_size = 1; + + if (line_size_c == 0) + line_size_c = 1; + + memory_line_size_y = (line_size + 5) / 6; /* +5 to ceil */ + memory_line_size_c = (line_size_c + 5) / 6; /* +5 to ceil */ + memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */ + + if (lb_config == LB_MEMORY_CONFIG_1) { + lb_memory_size = 970; + lb_memory_size_c = 970; + lb_memory_size_a = 970; + } else if (lb_config == LB_MEMORY_CONFIG_2) { + lb_memory_size = 1290; + lb_memory_size_c = 1290; + lb_memory_size_a = 1290; + } else if (lb_config == LB_MEMORY_CONFIG_3) { + /* 420 mode: using 3rd mem from Y, Cr and Cb */ + lb_memory_size = 970 + 1290 + 484 + 484 + 484; + lb_memory_size_c = 970 + 1290; + lb_memory_size_a = 970 + 1290 + 484; + } else { + lb_memory_size = 970 + 1290 + 484; + lb_memory_size_c = 970 + 1290 + 484; + lb_memory_size_a = 970 + 1290 + 484; + } + *num_part_y = lb_memory_size / memory_line_size_y; + *num_part_c = lb_memory_size_c / memory_line_size_c; + num_partitions_a = lb_memory_size_a / memory_line_size_a; + + if (scl_data->lb_params.alpha_en + && (num_partitions_a < *num_part_y)) + *num_part_y = num_partitions_a; + + if (*num_part_y > 64) + *num_part_y = 64; + if (*num_part_c > 64) + *num_part_c = 64; +} + +void dpp2_cnv_set_alpha_keyer( + struct dpp *dpp_base, + struct cnv_color_keyer_params *color_keyer) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(COLOR_KEYER_CONTROL, COLOR_KEYER_EN, color_keyer->color_keyer_en); + + REG_UPDATE(COLOR_KEYER_CONTROL, COLOR_KEYER_MODE, color_keyer->color_keyer_mode); + + REG_UPDATE(COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_LOW, color_keyer->color_keyer_alpha_low); + REG_UPDATE(COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_HIGH, color_keyer->color_keyer_alpha_high); + + REG_UPDATE(COLOR_KEYER_RED, COLOR_KEYER_RED_LOW, color_keyer->color_keyer_red_low); + REG_UPDATE(COLOR_KEYER_RED, COLOR_KEYER_RED_HIGH, color_keyer->color_keyer_red_high); + + REG_UPDATE(COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_LOW, color_keyer->color_keyer_green_low); + REG_UPDATE(COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_HIGH, color_keyer->color_keyer_green_high); + + REG_UPDATE(COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_LOW, color_keyer->color_keyer_blue_low); + REG_UPDATE(COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_HIGH, color_keyer->color_keyer_blue_high); +} + +void dpp2_set_cursor_attributes( + struct dpp *dpp_base, + enum dc_cursor_color_format color_format) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + int cur_rom_en = 0; + + if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || + color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) + cur_rom_en = 1; + + REG_UPDATE_3(CURSOR0_CONTROL, + CUR0_MODE, color_format, + CUR0_EXPANSION_MODE, 0, + CUR0_ROM_EN, cur_rom_en); + + if (color_format == CURSOR_MODE_MONO) { + /* todo: clarify what to program these to */ + REG_UPDATE(CURSOR0_COLOR0, + CUR0_COLOR0, 0x00000000); + REG_UPDATE(CURSOR0_COLOR1, + CUR0_COLOR1, 0xFFFFFFFF); + } +} + +#define IDENTITY_RATIO(ratio) (dc_fixpt_u3d19(ratio) == (1 << 19)) + +bool dpp2_get_optimal_number_of_taps( + struct dpp *dpp, + struct scaler_data *scl_data, + const struct scaling_taps *in_taps) +{ + uint32_t pixel_width; + + if (scl_data->viewport.width > scl_data->recout.width) + pixel_width = scl_data->recout.width; + else + pixel_width = scl_data->viewport.width; + + /* Some ASICs does not support FP16 scaling, so we reject modes require this*/ + if (scl_data->viewport.width != scl_data->h_active && + scl_data->viewport.height != scl_data->v_active && + dpp->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT && + scl_data->format == PIXEL_FORMAT_FP16) + return false; + + if (scl_data->viewport.width > scl_data->h_active && + dpp->ctx->dc->debug.max_downscale_src_width != 0 && + scl_data->viewport.width > dpp->ctx->dc->debug.max_downscale_src_width) + return false; + + /* TODO: add lb check */ + + /* No support for programming ratio of 8, drop to 7.99999.. */ + if (scl_data->ratios.horz.value == (8ll << 32)) + scl_data->ratios.horz.value--; + if (scl_data->ratios.vert.value == (8ll << 32)) + scl_data->ratios.vert.value--; + if (scl_data->ratios.horz_c.value == (8ll << 32)) + scl_data->ratios.horz_c.value--; + if (scl_data->ratios.vert_c.value == (8ll << 32)) + scl_data->ratios.vert_c.value--; + + /* Set default taps if none are provided */ + if (in_taps->h_taps == 0) { + if (dc_fixpt_ceil(scl_data->ratios.horz) > 4) + scl_data->taps.h_taps = 8; + else + scl_data->taps.h_taps = 4; + } else + scl_data->taps.h_taps = in_taps->h_taps; + if (in_taps->v_taps == 0) { + if (dc_fixpt_ceil(scl_data->ratios.vert) > 4) + scl_data->taps.v_taps = 8; + else + scl_data->taps.v_taps = 4; + } else + scl_data->taps.v_taps = in_taps->v_taps; + if (in_taps->v_taps_c == 0) { + if (dc_fixpt_ceil(scl_data->ratios.vert_c) > 4) + scl_data->taps.v_taps_c = 4; + else + scl_data->taps.v_taps_c = 2; + } else + scl_data->taps.v_taps_c = in_taps->v_taps_c; + if (in_taps->h_taps_c == 0) { + if (dc_fixpt_ceil(scl_data->ratios.horz_c) > 4) + scl_data->taps.h_taps_c = 4; + else + scl_data->taps.h_taps_c = 2; + } else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1) + /* Only 1 and even h_taps_c are supported by hw */ + scl_data->taps.h_taps_c = in_taps->h_taps_c - 1; + else + scl_data->taps.h_taps_c = in_taps->h_taps_c; + + if (!dpp->ctx->dc->debug.always_scale) { + if (IDENTITY_RATIO(scl_data->ratios.horz)) + scl_data->taps.h_taps = 1; + if (IDENTITY_RATIO(scl_data->ratios.vert)) + scl_data->taps.v_taps = 1; + if (IDENTITY_RATIO(scl_data->ratios.horz_c)) + scl_data->taps.h_taps_c = 1; + if (IDENTITY_RATIO(scl_data->ratios.vert_c)) + scl_data->taps.v_taps_c = 1; + } + + return true; +} + +void oppn20_dummy_program_regamma_pwl( + struct dpp *dpp, + const struct pwl_params *params, + enum opp_regamma mode) +{} + +static struct dpp_funcs dcn20_dpp_funcs = { + .dpp_read_state = dpp20_read_state, + .dpp_reset = dpp_reset, + .dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale, + .dpp_get_optimal_number_of_taps = dpp2_get_optimal_number_of_taps, + .dpp_set_gamut_remap = dpp1_cm_set_gamut_remap, + .dpp_set_csc_adjustment = NULL, + .dpp_set_csc_default = NULL, + .dpp_program_regamma_pwl = oppn20_dummy_program_regamma_pwl, + .dpp_set_degamma = dpp2_set_degamma, + .dpp_program_input_lut = dpp2_dummy_program_input_lut, + .dpp_full_bypass = dpp1_full_bypass, + .dpp_setup = dpp2_cnv_setup, + .dpp_program_degamma_pwl = dpp2_set_degamma_pwl, + .dpp_program_blnd_lut = dpp20_program_blnd_lut, + .dpp_program_shaper_lut = dpp20_program_shaper, + .dpp_program_3dlut = dpp20_program_3dlut, + .dpp_program_bias_and_scale = NULL, + .dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer, + .set_cursor_attributes = dpp2_set_cursor_attributes, + .set_cursor_position = dpp1_set_cursor_position, + .set_optional_cursor_attributes = dpp1_cnv_set_optional_cursor_attributes, + .dpp_dppclk_control = dpp1_dppclk_control, + .dpp_set_hdr_multiplier = dpp2_set_hdr_multiplier, +}; + +static struct dpp_caps dcn20_dpp_cap = { + .dscl_data_proc_format = DSCL_DATA_PRCESSING_FLOAT_FORMAT, + .dscl_calc_lb_num_partitions = dscl2_calc_lb_num_partitions, +}; + +bool dpp2_construct( + struct dcn20_dpp *dpp, + struct dc_context *ctx, + uint32_t inst, + const struct dcn2_dpp_registers *tf_regs, + const struct dcn2_dpp_shift *tf_shift, + const struct dcn2_dpp_mask *tf_mask) +{ + dpp->base.ctx = ctx; + + dpp->base.inst = inst; + dpp->base.funcs = &dcn20_dpp_funcs; + dpp->base.caps = &dcn20_dpp_cap; + + dpp->tf_regs = tf_regs; + dpp->tf_shift = tf_shift; + dpp->tf_mask = tf_mask; + + dpp->lb_pixel_depth_supported = + LB_PIXEL_DEPTH_18BPP | + LB_PIXEL_DEPTH_24BPP | + LB_PIXEL_DEPTH_30BPP; + + dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; + dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ + + return true; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h new file mode 100644 index 000000000000..59b67ed57c19 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h @@ -0,0 +1,698 @@ +/* Copyright 2016 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 __DCN20_DPP_H__ +#define __DCN20_DPP_H__ + +#include "dcn10/dcn10_dpp.h" + +#define TO_DCN20_DPP(dpp)\ + container_of(dpp, struct dcn20_dpp, base) + +#define TF_REG_LIST_DCN20(id) \ + TF_REG_LIST_DCN(id), \ + SRI(CM_BLNDGAM_LUT_WRITE_EN_MASK, CM, id), \ + SRI(CM_BLNDGAM_CONTROL, CM, id), \ + SRI(CM_BLNDGAM_RAMB_START_CNTL_B, CM, id), \ + SRI(CM_BLNDGAM_RAMB_START_CNTL_G, CM, id), \ + SRI(CM_BLNDGAM_RAMB_START_CNTL_R, CM, id), \ + SRI(CM_BLNDGAM_RAMB_SLOPE_CNTL_B, CM, id), \ + SRI(CM_BLNDGAM_RAMB_SLOPE_CNTL_G, CM, id), \ + SRI(CM_BLNDGAM_RAMB_SLOPE_CNTL_R, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL1_B, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL2_B, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL1_G, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL2_G, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL1_R, CM, id), \ + SRI(CM_BLNDGAM_RAMB_END_CNTL2_R, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_0_1, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_2_3, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_4_5, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_6_7, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_8_9, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_10_11, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_12_13, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_14_15, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_16_17, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_18_19, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_20_21, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_22_23, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_24_25, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_26_27, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_28_29, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_30_31, CM, id), \ + SRI(CM_BLNDGAM_RAMB_REGION_32_33, CM, id), \ + SRI(CM_BLNDGAM_RAMA_START_CNTL_B, CM, id), \ + SRI(CM_BLNDGAM_RAMA_START_CNTL_G, CM, id), \ + SRI(CM_BLNDGAM_RAMA_START_CNTL_R, CM, id), \ + SRI(CM_BLNDGAM_RAMA_SLOPE_CNTL_B, CM, id), \ + SRI(CM_BLNDGAM_RAMA_SLOPE_CNTL_G, CM, id), \ + SRI(CM_BLNDGAM_RAMA_SLOPE_CNTL_R, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL1_B, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL2_B, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL1_G, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL2_G, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL1_R, CM, id), \ + SRI(CM_BLNDGAM_RAMA_END_CNTL2_R, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_0_1, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_2_3, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_4_5, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_6_7, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_8_9, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_10_11, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_12_13, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_14_15, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_16_17, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_18_19, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_20_21, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_22_23, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_24_25, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_26_27, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_28_29, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_30_31, CM, id), \ + SRI(CM_BLNDGAM_RAMA_REGION_32_33, CM, id), \ + SRI(CM_BLNDGAM_LUT_INDEX, CM, id), \ + SRI(CM_BLNDGAM_LUT_DATA, CM, id), \ + SRI(CM_3DLUT_MODE, CM, id), \ + SRI(CM_3DLUT_INDEX, CM, id), \ + SRI(CM_3DLUT_DATA, CM, id), \ + SRI(CM_3DLUT_DATA_30BIT, CM, id), \ + SRI(CM_3DLUT_READ_WRITE_CONTROL, CM, id), \ + SRI(CM_SHAPER_LUT_WRITE_EN_MASK, CM, id), \ + SRI(CM_SHAPER_CONTROL, CM, id), \ + SRI(CM_SHAPER_RAMB_START_CNTL_B, CM, id), \ + SRI(CM_SHAPER_RAMB_START_CNTL_G, CM, id), \ + SRI(CM_SHAPER_RAMB_START_CNTL_R, CM, id), \ + SRI(CM_SHAPER_RAMB_END_CNTL_B, CM, id), \ + SRI(CM_SHAPER_RAMB_END_CNTL_G, CM, id), \ + SRI(CM_SHAPER_RAMB_END_CNTL_R, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_0_1, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_2_3, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_4_5, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_6_7, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_8_9, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_10_11, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_12_13, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_14_15, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_16_17, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_18_19, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_20_21, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_22_23, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_24_25, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_26_27, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_28_29, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_30_31, CM, id), \ + SRI(CM_SHAPER_RAMB_REGION_32_33, CM, id), \ + SRI(CM_SHAPER_RAMA_START_CNTL_B, CM, id), \ + SRI(CM_SHAPER_RAMA_START_CNTL_G, CM, id), \ + SRI(CM_SHAPER_RAMA_START_CNTL_R, CM, id), \ + SRI(CM_SHAPER_RAMA_END_CNTL_B, CM, id), \ + SRI(CM_SHAPER_RAMA_END_CNTL_G, CM, id), \ + SRI(CM_SHAPER_RAMA_END_CNTL_R, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_0_1, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_2_3, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_4_5, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_6_7, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_8_9, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_10_11, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_12_13, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_14_15, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_16_17, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_18_19, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_20_21, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_22_23, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_24_25, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_26_27, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_28_29, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_30_31, CM, id), \ + SRI(CM_SHAPER_RAMA_REGION_32_33, CM, id), \ + SRI(CM_SHAPER_LUT_INDEX, CM, id), \ + SRI(CURSOR_CONTROL, CURSOR0_, id), \ + SRI(ALPHA_2BIT_LUT, CNVC_CFG, id), \ + SRI(FCNV_FP_BIAS_R, CNVC_CFG, id), \ + SRI(FCNV_FP_BIAS_G, CNVC_CFG, id), \ + SRI(FCNV_FP_BIAS_B, CNVC_CFG, id), \ + SRI(FCNV_FP_SCALE_R, CNVC_CFG, id), \ + SRI(FCNV_FP_SCALE_G, CNVC_CFG, id), \ + SRI(FCNV_FP_SCALE_B, CNVC_CFG, id), \ + SRI(COLOR_KEYER_CONTROL, CNVC_CFG, id), \ + SRI(COLOR_KEYER_ALPHA, CNVC_CFG, id), \ + SRI(COLOR_KEYER_RED, CNVC_CFG, id), \ + SRI(COLOR_KEYER_GREEN, CNVC_CFG, id), \ + SRI(COLOR_KEYER_BLUE, CNVC_CFG, id), \ + SRI(CM_SHAPER_LUT_DATA, CM, id), \ + SRI(CURSOR_CONTROL, CURSOR0_, id) + +#define TF_REG_LIST_SH_MASK_DCN20(mask_sh)\ + TF_REG_LIST_SH_MASK_DCN(mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_CONTROL, CM_BLNDGAM_LUT_MODE, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_B, CM_BLNDGAM_RAMB_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_B, CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_G, CM_BLNDGAM_RAMB_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_G, CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_R, CM_BLNDGAM_RAMB_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_START_CNTL_R, CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_SLOPE_CNTL_B, CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_SLOPE_CNTL_G, CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_SLOPE_CNTL_R, CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL1_B, CM_BLNDGAM_RAMB_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_B, CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_B, CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL1_G, CM_BLNDGAM_RAMB_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_G, CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_G, CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL1_R, CM_BLNDGAM_RAMB_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_R, CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_END_CNTL2_R, CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_0_1, CM_BLNDGAM_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_0_1, CM_BLNDGAM_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_0_1, CM_BLNDGAM_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_0_1, CM_BLNDGAM_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_2_3, CM_BLNDGAM_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_2_3, CM_BLNDGAM_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_2_3, CM_BLNDGAM_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_2_3, CM_BLNDGAM_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_4_5, CM_BLNDGAM_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_4_5, CM_BLNDGAM_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_4_5, CM_BLNDGAM_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_4_5, CM_BLNDGAM_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_6_7, CM_BLNDGAM_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_6_7, CM_BLNDGAM_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_6_7, CM_BLNDGAM_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_6_7, CM_BLNDGAM_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_8_9, CM_BLNDGAM_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_8_9, CM_BLNDGAM_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_8_9, CM_BLNDGAM_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_8_9, CM_BLNDGAM_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_10_11, CM_BLNDGAM_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_10_11, CM_BLNDGAM_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_10_11, CM_BLNDGAM_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_10_11, CM_BLNDGAM_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_12_13, CM_BLNDGAM_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_12_13, CM_BLNDGAM_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_12_13, CM_BLNDGAM_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_12_13, CM_BLNDGAM_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_14_15, CM_BLNDGAM_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_14_15, CM_BLNDGAM_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_14_15, CM_BLNDGAM_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_14_15, CM_BLNDGAM_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_16_17, CM_BLNDGAM_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_16_17, CM_BLNDGAM_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_16_17, CM_BLNDGAM_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_16_17, CM_BLNDGAM_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_18_19, CM_BLNDGAM_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_18_19, CM_BLNDGAM_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_18_19, CM_BLNDGAM_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_18_19, CM_BLNDGAM_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_20_21, CM_BLNDGAM_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_20_21, CM_BLNDGAM_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_20_21, CM_BLNDGAM_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_20_21, CM_BLNDGAM_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_22_23, CM_BLNDGAM_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_22_23, CM_BLNDGAM_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_22_23, CM_BLNDGAM_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_22_23, CM_BLNDGAM_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_24_25, CM_BLNDGAM_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_24_25, CM_BLNDGAM_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_24_25, CM_BLNDGAM_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_24_25, CM_BLNDGAM_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_26_27, CM_BLNDGAM_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_26_27, CM_BLNDGAM_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_26_27, CM_BLNDGAM_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_26_27, CM_BLNDGAM_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_28_29, CM_BLNDGAM_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_28_29, CM_BLNDGAM_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_28_29, CM_BLNDGAM_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_28_29, CM_BLNDGAM_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_30_31, CM_BLNDGAM_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_30_31, CM_BLNDGAM_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_30_31, CM_BLNDGAM_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_30_31, CM_BLNDGAM_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_32_33, CM_BLNDGAM_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_32_33, CM_BLNDGAM_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_32_33, CM_BLNDGAM_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMB_REGION_32_33, CM_BLNDGAM_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_B, CM_BLNDGAM_RAMA_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_B, CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_G, CM_BLNDGAM_RAMA_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_G, CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_R, CM_BLNDGAM_RAMA_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_START_CNTL_R, CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_SLOPE_CNTL_B, CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_SLOPE_CNTL_G, CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_SLOPE_CNTL_R, CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL1_B, CM_BLNDGAM_RAMA_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_B, CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_B, CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL1_G, CM_BLNDGAM_RAMA_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_G, CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_G, CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL1_R, CM_BLNDGAM_RAMA_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_R, CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_END_CNTL2_R, CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_0_1, CM_BLNDGAM_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_0_1, CM_BLNDGAM_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_0_1, CM_BLNDGAM_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_0_1, CM_BLNDGAM_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_2_3, CM_BLNDGAM_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_2_3, CM_BLNDGAM_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_2_3, CM_BLNDGAM_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_2_3, CM_BLNDGAM_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_4_5, CM_BLNDGAM_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_4_5, CM_BLNDGAM_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_4_5, CM_BLNDGAM_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_4_5, CM_BLNDGAM_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_6_7, CM_BLNDGAM_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_6_7, CM_BLNDGAM_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_6_7, CM_BLNDGAM_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_6_7, CM_BLNDGAM_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_8_9, CM_BLNDGAM_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_8_9, CM_BLNDGAM_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_8_9, CM_BLNDGAM_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_8_9, CM_BLNDGAM_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_10_11, CM_BLNDGAM_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_10_11, CM_BLNDGAM_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_10_11, CM_BLNDGAM_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_10_11, CM_BLNDGAM_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_12_13, CM_BLNDGAM_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_12_13, CM_BLNDGAM_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_12_13, CM_BLNDGAM_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_12_13, CM_BLNDGAM_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_14_15, CM_BLNDGAM_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_14_15, CM_BLNDGAM_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_14_15, CM_BLNDGAM_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_14_15, CM_BLNDGAM_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_16_17, CM_BLNDGAM_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_16_17, CM_BLNDGAM_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_16_17, CM_BLNDGAM_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_16_17, CM_BLNDGAM_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_18_19, CM_BLNDGAM_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_18_19, CM_BLNDGAM_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_18_19, CM_BLNDGAM_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_18_19, CM_BLNDGAM_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_20_21, CM_BLNDGAM_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_20_21, CM_BLNDGAM_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_20_21, CM_BLNDGAM_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_20_21, CM_BLNDGAM_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_22_23, CM_BLNDGAM_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_22_23, CM_BLNDGAM_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_22_23, CM_BLNDGAM_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_22_23, CM_BLNDGAM_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_24_25, CM_BLNDGAM_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_24_25, CM_BLNDGAM_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_24_25, CM_BLNDGAM_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_24_25, CM_BLNDGAM_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_26_27, CM_BLNDGAM_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_26_27, CM_BLNDGAM_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_26_27, CM_BLNDGAM_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_26_27, CM_BLNDGAM_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_28_29, CM_BLNDGAM_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_28_29, CM_BLNDGAM_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_28_29, CM_BLNDGAM_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_28_29, CM_BLNDGAM_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_30_31, CM_BLNDGAM_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_30_31, CM_BLNDGAM_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_30_31, CM_BLNDGAM_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_30_31, CM_BLNDGAM_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_32_33, CM_BLNDGAM_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_32_33, CM_BLNDGAM_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_32_33, CM_BLNDGAM_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_RAMA_REGION_32_33, CM_BLNDGAM_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_LUT_WRITE_EN_MASK, CM_BLNDGAM_LUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_LUT_WRITE_EN_MASK, CM_BLNDGAM_LUT_WRITE_SEL, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_LUT_WRITE_EN_MASK, CM_BLNDGAM_CONFIG_STATUS, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_LUT_INDEX, CM_BLNDGAM_LUT_INDEX, mask_sh), \ + TF_SF(CM0_CM_BLNDGAM_LUT_DATA, CM_BLNDGAM_LUT_DATA, mask_sh), \ + TF_SF(CM0_CM_MEM_PWR_CTRL, BLNDGAM_MEM_PWR_FORCE, mask_sh), \ + TF_SF(CM0_CM_3DLUT_MODE, CM_3DLUT_MODE, mask_sh), \ + TF_SF(CM0_CM_3DLUT_MODE, CM_3DLUT_SIZE, mask_sh), \ + TF_SF(CM0_CM_3DLUT_INDEX, CM_3DLUT_INDEX, mask_sh), \ + TF_SF(CM0_CM_3DLUT_DATA, CM_3DLUT_DATA0, mask_sh), \ + TF_SF(CM0_CM_3DLUT_DATA, CM_3DLUT_DATA1, mask_sh), \ + TF_SF(CM0_CM_3DLUT_DATA_30BIT, CM_3DLUT_DATA_30BIT, mask_sh), \ + TF_SF(CM0_CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_RAM_SEL, mask_sh), \ + TF_SF(CM0_CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_30BIT_EN, mask_sh), \ + TF_SF(CM0_CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_CONFIG_STATUS, mask_sh), \ + TF_SF(CM0_CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_READ_SEL, mask_sh), \ + TF_SF(CM0_CM_SHAPER_CONTROL, CM_SHAPER_LUT_MODE, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_B, CM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_B, CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_G, CM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_G, CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_R, CM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_START_CNTL_R, CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_B, CM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_B, CM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_G, CM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_G, CM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_R, CM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_END_CNTL_R, CM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_0_1, CM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_0_1, CM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_0_1, CM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_0_1, CM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_2_3, CM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_2_3, CM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_2_3, CM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_2_3, CM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_4_5, CM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_4_5, CM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_4_5, CM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_4_5, CM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_6_7, CM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_6_7, CM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_6_7, CM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_6_7, CM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_8_9, CM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_8_9, CM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_8_9, CM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_8_9, CM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_10_11, CM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_10_11, CM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_10_11, CM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_10_11, CM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_12_13, CM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_12_13, CM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_12_13, CM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_12_13, CM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_14_15, CM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_14_15, CM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_14_15, CM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_14_15, CM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_16_17, CM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_16_17, CM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_16_17, CM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_16_17, CM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_18_19, CM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_18_19, CM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_18_19, CM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_18_19, CM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_20_21, CM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_20_21, CM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_20_21, CM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_20_21, CM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_22_23, CM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_22_23, CM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_22_23, CM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_22_23, CM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_24_25, CM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_24_25, CM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_24_25, CM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_24_25, CM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_26_27, CM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_26_27, CM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_26_27, CM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_26_27, CM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_28_29, CM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_28_29, CM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_28_29, CM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_28_29, CM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_30_31, CM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_30_31, CM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_30_31, CM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_30_31, CM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_32_33, CM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_32_33, CM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_32_33, CM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMB_REGION_32_33, CM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_B, CM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_B, CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_G, CM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_G, CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_R, CM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_START_CNTL_R, CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_B, CM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_B, CM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_G, CM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_G, CM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_R, CM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_END_CNTL_R, CM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_0_1, CM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_0_1, CM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_0_1, CM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_0_1, CM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_2_3, CM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_2_3, CM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_2_3, CM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_2_3, CM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_4_5, CM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_4_5, CM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_4_5, CM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_4_5, CM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_6_7, CM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_6_7, CM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_6_7, CM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_6_7, CM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_8_9, CM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_8_9, CM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_8_9, CM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_8_9, CM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_10_11, CM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_10_11, CM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_10_11, CM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_10_11, CM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_12_13, CM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_12_13, CM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_12_13, CM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_12_13, CM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_14_15, CM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_14_15, CM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_14_15, CM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_14_15, CM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_16_17, CM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_16_17, CM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_16_17, CM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_16_17, CM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_18_19, CM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_18_19, CM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_18_19, CM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_18_19, CM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_20_21, CM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_20_21, CM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_20_21, CM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_20_21, CM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_22_23, CM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_22_23, CM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_22_23, CM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_22_23, CM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_24_25, CM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_24_25, CM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_24_25, CM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_24_25, CM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_26_27, CM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_26_27, CM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_26_27, CM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_26_27, CM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_28_29, CM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_28_29, CM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_28_29, CM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_28_29, CM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_30_31, CM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_30_31, CM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_30_31, CM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_30_31, CM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_32_33, CM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_32_33, CM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_32_33, CM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_SHAPER_RAMA_REGION_32_33, CM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_LUT_WRITE_EN_MASK, CM_SHAPER_LUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_SHAPER_LUT_WRITE_EN_MASK, CM_SHAPER_LUT_WRITE_SEL, mask_sh), \ + TF_SF(CM0_CM_SHAPER_LUT_WRITE_EN_MASK, CM_SHAPER_CONFIG_STATUS, mask_sh), \ + TF_SF(CM0_CM_SHAPER_LUT_INDEX, CM_SHAPER_LUT_INDEX, mask_sh), \ + TF_SF(CM0_CM_SHAPER_LUT_DATA, CM_SHAPER_LUT_DATA, mask_sh), \ + TF_SF(CM0_CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_CONFIG_STATUS, mask_sh), \ + TF_SF(CM0_CM_CONTROL, CM_BYPASS, mask_sh), \ + TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_CNV16, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, CLAMP_POSITIVE, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, CLAMP_POSITIVE_C, mask_sh), \ + TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, mask_sh), \ + TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, mask_sh), \ + TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT, ALPHA_2BIT_LUT2, mask_sh), \ + TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT, ALPHA_2BIT_LUT3, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_BIAS_R, FCNV_FP_BIAS_R, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_BIAS_G, FCNV_FP_BIAS_G, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_BIAS_B, FCNV_FP_BIAS_B, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_SCALE_R, FCNV_FP_SCALE_R, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_SCALE_G, FCNV_FP_SCALE_G, mask_sh), \ + TF_SF(CNVC_CFG0_FCNV_FP_SCALE_B, FCNV_FP_SCALE_B, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_CONTROL, COLOR_KEYER_EN, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_CONTROL, COLOR_KEYER_MODE, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_LOW, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_HIGH, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_RED, COLOR_KEYER_RED_LOW, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_RED, COLOR_KEYER_RED_HIGH, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_LOW, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_HIGH, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_LOW, mask_sh), \ + TF_SF(CNVC_CFG0_COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_HIGH, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_PIX_INV_MODE, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_PIXEL_ALPHA_MOD_EN, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ROM_EN, mask_sh) + +#define TF_REG_FIELD_LIST_DCN2_0(type) \ + TF_REG_FIELD_LIST(type) \ + type CM_BLNDGAM_LUT_DATA; \ + type FORMAT_CNV16; \ + type CNVC_BYPASS_MSB_ALIGN; \ + type CLAMP_POSITIVE; \ + type CLAMP_POSITIVE_C; \ + type ALPHA_2BIT_LUT0; \ + type ALPHA_2BIT_LUT1; \ + type ALPHA_2BIT_LUT2; \ + type ALPHA_2BIT_LUT3; \ + type FCNV_FP_BIAS_R; \ + type FCNV_FP_BIAS_G; \ + type FCNV_FP_BIAS_B; \ + type FCNV_FP_SCALE_R; \ + type FCNV_FP_SCALE_G; \ + type FCNV_FP_SCALE_B; \ + type COLOR_KEYER_EN; \ + type COLOR_KEYER_MODE; \ + type COLOR_KEYER_ALPHA_LOW; \ + type COLOR_KEYER_ALPHA_HIGH; \ + type COLOR_KEYER_RED_LOW; \ + type COLOR_KEYER_RED_HIGH; \ + type COLOR_KEYER_GREEN_LOW; \ + type COLOR_KEYER_GREEN_HIGH; \ + type COLOR_KEYER_BLUE_LOW; \ + type COLOR_KEYER_BLUE_HIGH; \ + type CUR0_PIX_INV_MODE; \ + type CUR0_PIXEL_ALPHA_MOD_EN; \ + type CUR0_ROM_EN + +struct dcn2_dpp_shift { + TF_REG_FIELD_LIST_DCN2_0(uint8_t); +}; + +struct dcn2_dpp_mask { + TF_REG_FIELD_LIST_DCN2_0(uint32_t); +}; + +#define DPP_DCN2_REG_VARIABLE_LIST \ + DPP_COMMON_REG_VARIABLE_LIST \ + uint32_t CM_BLNDGAM_LUT_DATA; \ + uint32_t ALPHA_2BIT_LUT; \ + uint32_t FCNV_FP_BIAS_R; \ + uint32_t FCNV_FP_BIAS_G; \ + uint32_t FCNV_FP_BIAS_B; \ + uint32_t FCNV_FP_SCALE_R; \ + uint32_t FCNV_FP_SCALE_G; \ + uint32_t FCNV_FP_SCALE_B; \ + uint32_t COLOR_KEYER_CONTROL; \ + uint32_t COLOR_KEYER_ALPHA; \ + uint32_t COLOR_KEYER_RED; \ + uint32_t COLOR_KEYER_GREEN; \ + uint32_t COLOR_KEYER_BLUE + +struct dcn2_dpp_registers { + DPP_DCN2_REG_VARIABLE_LIST; +}; + +struct dcn20_dpp { + struct dpp base; + + const struct dcn2_dpp_registers *tf_regs; + const struct dcn2_dpp_shift *tf_shift; + const struct dcn2_dpp_mask *tf_mask; + + const uint16_t *filter_v; + const uint16_t *filter_h; + const uint16_t *filter_v_c; + const uint16_t *filter_h_c; + int lb_pixel_depth_supported; + int lb_memory_size; + int lb_bits_per_entry; + bool is_write_to_ram_a_safe; + struct scaler_data scl_data; + struct pwl_params pwl_data; +}; + +void dpp20_read_state(struct dpp *dpp_base, + struct dcn_dpp_state *s); + +void dpp2_set_degamma_pwl( + struct dpp *dpp_base, + const struct pwl_params *params); + +void dpp2_set_degamma( + struct dpp *dpp_base, + enum ipp_degamma_mode mode); + +bool dpp20_program_blnd_lut( + struct dpp *dpp_base, const struct pwl_params *params); + +bool dpp20_program_shaper( + struct dpp *dpp_base, + const struct pwl_params *params); + +bool dpp20_program_3dlut( + struct dpp *dpp_base, + struct tetrahedral_params *params); + +void dpp2_cnv_set_alpha_keyer( + struct dpp *dpp_base, + struct cnv_color_keyer_params *color_keyer); + +void dscl2_calc_lb_num_partitions( + const struct scaler_data *scl_data, + enum lb_memory_config lb_config, + int *num_part_y, + int *num_part_c); + +void dpp2_set_cursor_attributes( + struct dpp *dpp_base, + enum dc_cursor_color_format color_format); + +void dpp2_dummy_program_input_lut( + struct dpp *dpp_base, + const struct dc_gamma *gamma); + +void oppn20_dummy_program_regamma_pwl( + struct dpp *dpp, + const struct pwl_params *params, + enum opp_regamma mode); + +void dpp2_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier); + +bool dpp2_get_optimal_number_of_taps( + struct dpp *dpp, + struct scaler_data *scl_data, + const struct scaling_taps *in_taps); + +bool dpp2_construct(struct dcn20_dpp *dpp2, + struct dc_context *ctx, + uint32_t inst, + const struct dcn2_dpp_registers *tf_regs, + const struct dcn2_dpp_shift *tf_shift, + const struct dcn2_dpp_mask *tf_mask); + +#endif /* __DC_HWSS_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c new file mode 100644 index 000000000000..e28b8e7bedf5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c @@ -0,0 +1,990 @@ +/* + * Copyright 2016 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 "core_types.h" + +#include "reg_helper.h" +#include "dcn20_dpp.h" +#include "basics/conversion.h" + +#include "dcn10/dcn10_cm_common.h" + +#define REG(reg)\ + dpp->tf_regs->reg + +#define CTX \ + dpp->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dpp->tf_shift->field_name, dpp->tf_mask->field_name + + + + + +static void dpp2_enable_cm_block( + struct dpp *dpp_base) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_CONTROL, CM_BYPASS, 0); +} + + +static bool dpp2_degamma_ram_inuse( + struct dpp *dpp_base, + bool *ram_a_inuse) +{ + bool ret = false; + uint32_t status_reg = 0; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_GET(CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_CONFIG_STATUS, + &status_reg); + + if (status_reg == 3) { + *ram_a_inuse = true; + ret = true; + } else if (status_reg == 4) { + *ram_a_inuse = false; + ret = true; + } + return ret; +} + +static void dpp2_program_degamma_lut( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num, + bool is_ram_a) +{ + uint32_t i; + + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK, + CM_DGAM_LUT_WRITE_EN_MASK, 7); + REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_SEL, + is_ram_a == true ? 0:1); + + REG_SET(CM_DGAM_LUT_INDEX, 0, CM_DGAM_LUT_INDEX, 0); + for (i = 0 ; i < num; i++) { + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].red_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].green_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].blue_reg); + + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_red_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_green_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_blue_reg); + + } + +} + +void dpp2_set_degamma_pwl( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + bool is_ram_a = true; + + dpp1_power_on_degamma_lut(dpp_base, true); + dpp2_enable_cm_block(dpp_base); + dpp2_degamma_ram_inuse(dpp_base, &is_ram_a); + if (is_ram_a == true) + dpp1_program_degamma_lutb_settings(dpp_base, params); + else + dpp1_program_degamma_luta_settings(dpp_base, params); + + dpp2_program_degamma_lut(dpp_base, params->rgb_resulted, params->hw_points_num, !is_ram_a); + dpp1_degamma_ram_select(dpp_base, !is_ram_a); +} + +void dpp2_set_degamma( + struct dpp *dpp_base, + enum ipp_degamma_mode mode) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + dpp2_enable_cm_block(dpp_base); + + switch (mode) { + case IPP_DEGAMMA_MODE_BYPASS: + /* Setting de gamma bypass for now */ + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 0); + break; + case IPP_DEGAMMA_MODE_HW_sRGB: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 1); + break; + case IPP_DEGAMMA_MODE_HW_xvYCC: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 2); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +static void dpp20_power_on_blnd_lut( + struct dpp *dpp_base, + bool power_on) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_SET(CM_MEM_PWR_CTRL, 0, + BLNDGAM_MEM_PWR_FORCE, power_on == true ? 0:1); + +} + +static void dpp20_configure_blnd_lut( + struct dpp *dpp_base, + bool is_ram_a) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_BLNDGAM_LUT_WRITE_EN_MASK, + CM_BLNDGAM_LUT_WRITE_EN_MASK, 7); + REG_UPDATE(CM_BLNDGAM_LUT_WRITE_EN_MASK, + CM_BLNDGAM_LUT_WRITE_SEL, is_ram_a == true ? 0:1); + REG_SET(CM_BLNDGAM_LUT_INDEX, 0, CM_BLNDGAM_LUT_INDEX, 0); +} + +static void dpp20_program_blnd_pwl( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num) +{ + uint32_t i; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + for (i = 0 ; i < num; i++) { + REG_SET(CM_BLNDGAM_LUT_DATA, 0, CM_BLNDGAM_LUT_DATA, rgb[i].red_reg); + REG_SET(CM_BLNDGAM_LUT_DATA, 0, CM_BLNDGAM_LUT_DATA, rgb[i].green_reg); + REG_SET(CM_BLNDGAM_LUT_DATA, 0, CM_BLNDGAM_LUT_DATA, rgb[i].blue_reg); + + REG_SET(CM_BLNDGAM_LUT_DATA, 0, + CM_BLNDGAM_LUT_DATA, rgb[i].delta_red_reg); + REG_SET(CM_BLNDGAM_LUT_DATA, 0, + CM_BLNDGAM_LUT_DATA, rgb[i].delta_green_reg); + REG_SET(CM_BLNDGAM_LUT_DATA, 0, + CM_BLNDGAM_LUT_DATA, rgb[i].delta_blue_reg); + + } + +} + +static void dcn20_dpp_cm_get_reg_field( + struct dcn20_dpp *dpp, + struct xfer_func_reg *reg) +{ + reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + + reg->shifts.field_region_end = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_END_B; + reg->masks.field_region_end = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_END_B; + reg->shifts.field_region_end_slope = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_B; + reg->masks.field_region_end_slope = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_B; + reg->shifts.field_region_end_base = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_B; + reg->masks.field_region_end_base = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_B; + reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; + reg->masks.field_region_linear_slope = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; + reg->shifts.exp_region_start = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_START_B; + reg->masks.exp_region_start = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_START_B; + reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_B; + reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_B; +} + +/*program blnd lut RAM A*/ +static void dpp20_program_blnd_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dcn20_dpp_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_BLNDGAM_RAMA_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_BLNDGAM_RAMA_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_BLNDGAM_RAMA_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_BLNDGAM_RAMA_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_BLNDGAM_RAMA_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_BLNDGAM_RAMA_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_BLNDGAM_RAMA_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_BLNDGAM_RAMA_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_BLNDGAM_RAMA_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_BLNDGAM_RAMA_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_BLNDGAM_RAMA_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_BLNDGAM_RAMA_END_CNTL2_R); + gam_regs.region_start = REG(CM_BLNDGAM_RAMA_REGION_0_1); + gam_regs.region_end = REG(CM_BLNDGAM_RAMA_REGION_32_33); + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); +} + +/*program blnd lut RAM B*/ +static void dpp20_program_blnd_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dcn20_dpp_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_BLNDGAM_RAMB_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_BLNDGAM_RAMB_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_BLNDGAM_RAMB_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_BLNDGAM_RAMB_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_BLNDGAM_RAMB_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_BLNDGAM_RAMB_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_BLNDGAM_RAMB_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_BLNDGAM_RAMB_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_BLNDGAM_RAMB_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_BLNDGAM_RAMB_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_BLNDGAM_RAMB_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_BLNDGAM_RAMB_END_CNTL2_R); + gam_regs.region_start = REG(CM_BLNDGAM_RAMB_REGION_0_1); + gam_regs.region_end = REG(CM_BLNDGAM_RAMB_REGION_32_33); + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); +} + +static enum dc_lut_mode dpp20_get_blndgam_current(struct dpp *dpp_base) +{ + enum dc_lut_mode mode; + uint32_t state_mode; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_GET(CM_BLNDGAM_LUT_WRITE_EN_MASK, + CM_BLNDGAM_CONFIG_STATUS, &state_mode); + + switch (state_mode) { + case 0: + mode = LUT_BYPASS; + break; + case 1: + mode = LUT_RAM_A; + break; + case 2: + mode = LUT_RAM_B; + break; + default: + mode = LUT_BYPASS; + break; + } + return mode; +} + +bool dpp20_program_blnd_lut( + struct dpp *dpp_base, const struct pwl_params *params) +{ + enum dc_lut_mode current_mode; + enum dc_lut_mode next_mode; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + if (params == NULL) { + REG_SET(CM_BLNDGAM_CONTROL, 0, CM_BLNDGAM_LUT_MODE, 0); + return false; + } + current_mode = dpp20_get_blndgam_current(dpp_base); + if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A) + next_mode = LUT_RAM_B; + else + next_mode = LUT_RAM_A; + + dpp20_power_on_blnd_lut(dpp_base, true); + dpp20_configure_blnd_lut(dpp_base, next_mode == LUT_RAM_A ? true:false); + + if (next_mode == LUT_RAM_A) + dpp20_program_blnd_luta_settings(dpp_base, params); + else + dpp20_program_blnd_lutb_settings(dpp_base, params); + + dpp20_program_blnd_pwl( + dpp_base, params->rgb_resulted, params->hw_points_num); + + REG_SET(CM_BLNDGAM_CONTROL, 0, CM_BLNDGAM_LUT_MODE, + next_mode == LUT_RAM_A ? 1:2); + + return true; +} + + +static void dpp20_program_shaper_lut( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num) +{ + uint32_t i, red, green, blue; + uint32_t red_delta, green_delta, blue_delta; + uint32_t red_value, green_value, blue_value; + + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + for (i = 0 ; i < num; i++) { + + red = rgb[i].red_reg; + green = rgb[i].green_reg; + blue = rgb[i].blue_reg; + + red_delta = rgb[i].delta_red_reg; + green_delta = rgb[i].delta_green_reg; + blue_delta = rgb[i].delta_blue_reg; + + red_value = ((red_delta & 0x3ff) << 14) | (red & 0x3fff); + green_value = ((green_delta & 0x3ff) << 14) | (green & 0x3fff); + blue_value = ((blue_delta & 0x3ff) << 14) | (blue & 0x3fff); + + REG_SET(CM_SHAPER_LUT_DATA, 0, CM_SHAPER_LUT_DATA, red_value); + REG_SET(CM_SHAPER_LUT_DATA, 0, CM_SHAPER_LUT_DATA, green_value); + REG_SET(CM_SHAPER_LUT_DATA, 0, CM_SHAPER_LUT_DATA, blue_value); + } + +} + +static enum dc_lut_mode dpp20_get_shaper_current(struct dpp *dpp_base) +{ + enum dc_lut_mode mode; + uint32_t state_mode; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_GET(CM_SHAPER_LUT_WRITE_EN_MASK, + CM_SHAPER_CONFIG_STATUS, &state_mode); + + switch (state_mode) { + case 0: + mode = LUT_BYPASS; + break; + case 1: + mode = LUT_RAM_A; + break; + case 2: + mode = LUT_RAM_B; + break; + default: + mode = LUT_BYPASS; + break; + } + return mode; +} + +static void dpp20_configure_shaper_lut( + struct dpp *dpp_base, + bool is_ram_a) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_SHAPER_LUT_WRITE_EN_MASK, + CM_SHAPER_LUT_WRITE_EN_MASK, 7); + REG_UPDATE(CM_SHAPER_LUT_WRITE_EN_MASK, + CM_SHAPER_LUT_WRITE_SEL, is_ram_a == true ? 0:1); + REG_SET(CM_SHAPER_LUT_INDEX, 0, CM_SHAPER_LUT_INDEX, 0); +} + +/*program shaper RAM A*/ + +static void dpp20_program_shaper_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + const struct gamma_curve *curve; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_SET_2(CM_SHAPER_RAMA_START_CNTL_B, 0, + CM_SHAPER_RAMA_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, 0); + REG_SET_2(CM_SHAPER_RAMA_START_CNTL_G, 0, + CM_SHAPER_RAMA_EXP_REGION_START_G, params->corner_points[0].green.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, 0); + REG_SET_2(CM_SHAPER_RAMA_START_CNTL_R, 0, + CM_SHAPER_RAMA_EXP_REGION_START_R, params->corner_points[0].red.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, 0); + + REG_SET_2(CM_SHAPER_RAMA_END_CNTL_B, 0, + CM_SHAPER_RAMA_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y); + + REG_SET_2(CM_SHAPER_RAMA_END_CNTL_G, 0, + CM_SHAPER_RAMA_EXP_REGION_END_G, params->corner_points[1].green.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_END_BASE_G, params->corner_points[1].green.custom_float_y); + + REG_SET_2(CM_SHAPER_RAMA_END_CNTL_R, 0, + CM_SHAPER_RAMA_EXP_REGION_END_R, params->corner_points[1].red.custom_float_x, + CM_SHAPER_RAMA_EXP_REGION_END_BASE_R, params->corner_points[1].red.custom_float_y); + + curve = params->arr_curve_points; + REG_SET_4(CM_SHAPER_RAMA_REGION_0_1, 0, + CM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_2_3, 0, + CM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_4_5, 0, + CM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_6_7, 0, + CM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_8_9, 0, + CM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_10_11, 0, + CM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_12_13, 0, + CM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_14_15, 0, + CM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_16_17, 0, + CM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_18_19, 0, + CM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_20_21, 0, + CM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_22_23, 0, + CM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_24_25, 0, + CM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_26_27, 0, + CM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_28_29, 0, + CM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_30_31, 0, + CM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMA_REGION_32_33, 0, + CM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, curve[1].segments_num); +} + +/*program shaper RAM B*/ +static void dpp20_program_shaper_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + const struct gamma_curve *curve; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_SET_2(CM_SHAPER_RAMB_START_CNTL_B, 0, + CM_SHAPER_RAMB_EXP_REGION_START_B, params->corner_points[0].blue.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, 0); + REG_SET_2(CM_SHAPER_RAMB_START_CNTL_G, 0, + CM_SHAPER_RAMB_EXP_REGION_START_G, params->corner_points[0].green.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, 0); + REG_SET_2(CM_SHAPER_RAMB_START_CNTL_R, 0, + CM_SHAPER_RAMB_EXP_REGION_START_R, params->corner_points[0].red.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, 0); + + REG_SET_2(CM_SHAPER_RAMB_END_CNTL_B, 0, + CM_SHAPER_RAMB_EXP_REGION_END_B, params->corner_points[1].blue.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_END_BASE_B, params->corner_points[1].blue.custom_float_y); + + REG_SET_2(CM_SHAPER_RAMB_END_CNTL_G, 0, + CM_SHAPER_RAMB_EXP_REGION_END_G, params->corner_points[1].green.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_END_BASE_G, params->corner_points[1].green.custom_float_y); + + REG_SET_2(CM_SHAPER_RAMB_END_CNTL_R, 0, + CM_SHAPER_RAMB_EXP_REGION_END_R, params->corner_points[1].red.custom_float_x, + CM_SHAPER_RAMB_EXP_REGION_END_BASE_R, params->corner_points[1].red.custom_float_y); + + curve = params->arr_curve_points; + REG_SET_4(CM_SHAPER_RAMB_REGION_0_1, 0, + CM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_2_3, 0, + CM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_4_5, 0, + CM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_6_7, 0, + CM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_8_9, 0, + CM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_10_11, 0, + CM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_12_13, 0, + CM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_14_15, 0, + CM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_16_17, 0, + CM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_18_19, 0, + CM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_20_21, 0, + CM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_22_23, 0, + CM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_24_25, 0, + CM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_26_27, 0, + CM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_28_29, 0, + CM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_30_31, 0, + CM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, curve[1].segments_num); + + curve += 2; + REG_SET_4(CM_SHAPER_RAMB_REGION_32_33, 0, + CM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, curve[0].offset, + CM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, curve[0].segments_num, + CM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, curve[1].offset, + CM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, curve[1].segments_num); + +} + + +bool dpp20_program_shaper( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + enum dc_lut_mode current_mode; + enum dc_lut_mode next_mode; + + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + if (params == NULL) { + REG_SET(CM_SHAPER_CONTROL, 0, CM_SHAPER_LUT_MODE, 0); + return false; + } + current_mode = dpp20_get_shaper_current(dpp_base); + + if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A) + next_mode = LUT_RAM_B; + else + next_mode = LUT_RAM_A; + + dpp20_configure_shaper_lut(dpp_base, next_mode == LUT_RAM_A ? true:false); + + if (next_mode == LUT_RAM_A) + dpp20_program_shaper_luta_settings(dpp_base, params); + else + dpp20_program_shaper_lutb_settings(dpp_base, params); + + dpp20_program_shaper_lut( + dpp_base, params->rgb_resulted, params->hw_points_num); + + REG_SET(CM_SHAPER_CONTROL, 0, CM_SHAPER_LUT_MODE, next_mode == LUT_RAM_A ? 1:2); + + return true; + +} + +static enum dc_lut_mode get3dlut_config( + struct dpp *dpp_base, + bool *is_17x17x17, + bool *is_12bits_color_channel) +{ + uint32_t i_mode, i_enable_10bits, lut_size; + enum dc_lut_mode mode; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_GET_2(CM_3DLUT_READ_WRITE_CONTROL, + CM_3DLUT_CONFIG_STATUS, &i_mode, + CM_3DLUT_30BIT_EN, &i_enable_10bits); + + switch (i_mode) { + case 0: + mode = LUT_BYPASS; + break; + case 1: + mode = LUT_RAM_A; + break; + case 2: + mode = LUT_RAM_B; + break; + default: + mode = LUT_BYPASS; + break; + } + if (i_enable_10bits > 0) + *is_12bits_color_channel = false; + else + *is_12bits_color_channel = true; + + REG_GET(CM_3DLUT_MODE, CM_3DLUT_SIZE, &lut_size); + + if (lut_size == 0) + *is_17x17x17 = true; + else + *is_17x17x17 = false; + + return mode; +} +/* + * select ramA or ramB, or bypass + * select color channel size 10 or 12 bits + * select 3dlut size 17x17x17 or 9x9x9 + */ +static void dpp20_set_3dlut_mode( + struct dpp *dpp_base, + enum dc_lut_mode mode, + bool is_color_channel_12bits, + bool is_lut_size17x17x17) +{ + uint32_t lut_mode; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + if (mode == LUT_BYPASS) + lut_mode = 0; + else if (mode == LUT_RAM_A) + lut_mode = 1; + else + lut_mode = 2; + + REG_UPDATE_2(CM_3DLUT_MODE, + CM_3DLUT_MODE, lut_mode, + CM_3DLUT_SIZE, is_lut_size17x17x17 == true ? 0 : 1); +} + +static void dpp20_select_3dlut_ram( + struct dpp *dpp_base, + enum dc_lut_mode mode, + bool is_color_channel_12bits) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE_2(CM_3DLUT_READ_WRITE_CONTROL, + CM_3DLUT_RAM_SEL, mode == LUT_RAM_A ? 0 : 1, + CM_3DLUT_30BIT_EN, + is_color_channel_12bits == true ? 0:1); +} + + + +static void dpp20_set3dlut_ram12( + struct dpp *dpp_base, + const struct dc_rgb *lut, + uint32_t entries) +{ + uint32_t i, red, green, blue, red1, green1, blue1; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + for (i = 0 ; i < entries; i += 2) { + red = lut[i].red<<4; + green = lut[i].green<<4; + blue = lut[i].blue<<4; + red1 = lut[i+1].red<<4; + green1 = lut[i+1].green<<4; + blue1 = lut[i+1].blue<<4; + + REG_SET_2(CM_3DLUT_DATA, 0, + CM_3DLUT_DATA0, red, + CM_3DLUT_DATA1, red1); + + REG_SET_2(CM_3DLUT_DATA, 0, + CM_3DLUT_DATA0, green, + CM_3DLUT_DATA1, green1); + + REG_SET_2(CM_3DLUT_DATA, 0, + CM_3DLUT_DATA0, blue, + CM_3DLUT_DATA1, blue1); + + } +} + +/* + * load selected lut with 10 bits color channels + */ +static void dpp20_set3dlut_ram10( + struct dpp *dpp_base, + const struct dc_rgb *lut, + uint32_t entries) +{ + uint32_t i, red, green, blue, value; + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + for (i = 0; i < entries; i++) { + red = lut[i].red; + green = lut[i].green; + blue = lut[i].blue; + + value = (red<<20) | (green<<10) | blue; + + REG_SET(CM_3DLUT_DATA_30BIT, 0, CM_3DLUT_DATA_30BIT, value); + } + +} + + +static void dpp20_select_3dlut_ram_mask( + struct dpp *dpp_base, + uint32_t ram_selection_mask) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_3DLUT_READ_WRITE_CONTROL, CM_3DLUT_WRITE_EN_MASK, + ram_selection_mask); + REG_SET(CM_3DLUT_INDEX, 0, CM_3DLUT_INDEX, 0); +} + +bool dpp20_program_3dlut( + struct dpp *dpp_base, + struct tetrahedral_params *params) +{ + enum dc_lut_mode mode; + bool is_17x17x17; + bool is_12bits_color_channel; + struct dc_rgb *lut0; + struct dc_rgb *lut1; + struct dc_rgb *lut2; + struct dc_rgb *lut3; + int lut_size0; + int lut_size; + + if (params == NULL) { + dpp20_set_3dlut_mode(dpp_base, LUT_BYPASS, false, false); + return false; + } + mode = get3dlut_config(dpp_base, &is_17x17x17, &is_12bits_color_channel); + + if (mode == LUT_BYPASS || mode == LUT_RAM_B) + mode = LUT_RAM_A; + else + mode = LUT_RAM_B; + + is_17x17x17 = !params->use_tetrahedral_9; + is_12bits_color_channel = params->use_12bits; + if (is_17x17x17) { + lut0 = params->tetrahedral_17.lut0; + lut1 = params->tetrahedral_17.lut1; + lut2 = params->tetrahedral_17.lut2; + lut3 = params->tetrahedral_17.lut3; + lut_size0 = sizeof(params->tetrahedral_17.lut0)/ + sizeof(params->tetrahedral_17.lut0[0]); + lut_size = sizeof(params->tetrahedral_17.lut1)/ + sizeof(params->tetrahedral_17.lut1[0]); + } else { + lut0 = params->tetrahedral_9.lut0; + lut1 = params->tetrahedral_9.lut1; + lut2 = params->tetrahedral_9.lut2; + lut3 = params->tetrahedral_9.lut3; + lut_size0 = sizeof(params->tetrahedral_9.lut0)/ + sizeof(params->tetrahedral_9.lut0[0]); + lut_size = sizeof(params->tetrahedral_9.lut1)/ + sizeof(params->tetrahedral_9.lut1[0]); + } + + dpp20_select_3dlut_ram(dpp_base, mode, + is_12bits_color_channel); + dpp20_select_3dlut_ram_mask(dpp_base, 0x1); + if (is_12bits_color_channel) + dpp20_set3dlut_ram12(dpp_base, lut0, lut_size0); + else + dpp20_set3dlut_ram10(dpp_base, lut0, lut_size0); + + dpp20_select_3dlut_ram_mask(dpp_base, 0x2); + if (is_12bits_color_channel) + dpp20_set3dlut_ram12(dpp_base, lut1, lut_size); + else + dpp20_set3dlut_ram10(dpp_base, lut1, lut_size); + + dpp20_select_3dlut_ram_mask(dpp_base, 0x4); + if (is_12bits_color_channel) + dpp20_set3dlut_ram12(dpp_base, lut2, lut_size); + else + dpp20_set3dlut_ram10(dpp_base, lut2, lut_size); + + dpp20_select_3dlut_ram_mask(dpp_base, 0x8); + if (is_12bits_color_channel) + dpp20_set3dlut_ram12(dpp_base, lut3, lut_size); + else + dpp20_set3dlut_ram10(dpp_base, lut3, lut_size); + + + dpp20_set_3dlut_mode(dpp_base, mode, is_12bits_color_channel, + is_17x17x17); + + return true; +} + +void dpp2_set_hdr_multiplier( + struct dpp *dpp_base, + uint32_t multiplier) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, multiplier); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c new file mode 100644 index 000000000000..ffd0014ec3b5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c @@ -0,0 +1,694 @@ +/* + * 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. + * + * Authors: AMD + * + */ + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "reg_helper.h" +#include "dcn20_dsc.h" +#include "dsc/dscc_types.h" + +static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps); +static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg); +static void dsc_init_reg_values(struct dsc_reg_values *reg_vals); +static void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params); +static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals); +static enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple); +static enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth); + +/* Object I/F functions */ +static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz); +static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); +static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); +static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps); +static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe); +static void dsc2_disable(struct display_stream_compressor *dsc); + +const struct dsc_funcs dcn20_dsc_funcs = { + .dsc_get_enc_caps = dsc2_get_enc_caps, + .dsc_read_state = dsc2_read_state, + .dsc_validate_stream = dsc2_validate_stream, + .dsc_set_config = dsc2_set_config, + .dsc_enable = dsc2_enable, + .dsc_disable = dsc2_disable, +}; + +/* Macro definitios for REG_SET macros*/ +#define CTX \ + dsc20->base.ctx + +#define REG(reg)\ + dsc20->dsc_regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + dsc20->dsc_shift->field_name, dsc20->dsc_mask->field_name +#define DC_LOGGER \ + dsc->ctx->logger + +enum dsc_bits_per_comp { + DSC_BPC_8 = 8, + DSC_BPC_10 = 10, + DSC_BPC_12 = 12, + DSC_BPC_UNKNOWN +}; + +/* API functions (external or via structure->function_pointer) */ + +void dsc2_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn20_dsc_shift *dsc_shift, + const struct dcn20_dsc_mask *dsc_mask) +{ + dsc->base.ctx = ctx; + dsc->base.inst = inst; + dsc->base.funcs = &dcn20_dsc_funcs; + + dsc->dsc_regs = dsc_regs; + dsc->dsc_shift = dsc_shift; + dsc->dsc_mask = dsc_mask; + + dsc->max_image_width = 5184; +} + + +#define DCN20_MAX_PIXEL_CLOCK_Mhz 1188 +#define DCN20_MAX_DISPLAY_CLOCK_Mhz 1200 + +/* This returns the capabilities for a single DSC encoder engine. Number of slices and total throughput + * can be doubled, tripled etc. by using additional DSC engines. + */ +static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz) +{ + dsc_enc_caps->dsc_version = 0x21; /* v1.2 - DP spec defined it in reverse order and we kept it */ + + dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_3 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1; + + dsc_enc_caps->lb_bit_depth = 13; + dsc_enc_caps->is_block_pred_supported = true; + + dsc_enc_caps->color_formats.bits.RGB = 1; + dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; + + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_10_BPC = 1; + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_12_BPC = 1; + + /* Maximum total throughput with all the slices combined. This is different from how DP spec specifies it. + * Our decoder's total throughput in Pix/s is equal to DISPCLK. This is then shared between slices. + * The value below is the absolute maximum value. The actual throughput may be lower, but it'll always + * be sufficient to process the input pixel rate fed into a single DSC engine. + */ + dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz; + + /* For pixel clock bigger than a single-pipe limit we'll need two engines, which then doubles our + * throughput and number of slices, but also introduces a lower limit of 2 slices + */ + if (pixel_clock_100Hz >= DCN20_MAX_PIXEL_CLOCK_Mhz*10000) { + dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 0; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_8 = 1; + dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 2; + } + + // TODO DSC: This is actually image width limitation, not a slice width. This should be added to the criteria to use ODM. + dsc_enc_caps->max_slice_width = 5184; /* (including 64 overlap pixels for eDP MSO mode) */ + dsc_enc_caps->bpp_increment_div = 16; /* 1/16th of a bit */ +} + + +/* this function read dsc related register fields to be logged later in dcn10_log_hw_state + * into a dcn_dsc_state struct. + */ +static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &s->dsc_clock_en); + REG_GET(DSCC_PPS_CONFIG3, SLICE_WIDTH, &s->dsc_slice_width); + REG_GET(DSCC_PPS_CONFIG1, BITS_PER_PIXEL, &s->dsc_bytes_per_pixel); +} + + +static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg) +{ + struct dsc_optc_config dsc_optc_cfg; + + if (dsc_cfg->pic_width > TO_DCN20_DSC(dsc)->max_image_width) + return false; + + return dsc_prepare_config(dsc, dsc_cfg, &dsc_optc_cfg); +} + + +static void dsc_config_log(struct display_stream_compressor *dsc, + const struct dsc_config *config) +{ + DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst); + DC_LOG_DSC("\n\tnum_slices_h %d\n\tnum_slices_v %d\n\tbits_per_pixel %d\n\tcolor_depth %d", + config->dc_dsc_cfg.num_slices_h, + config->dc_dsc_cfg.num_slices_v, + config->dc_dsc_cfg.bits_per_pixel, + config->color_depth); +} + +static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps) +{ + bool is_config_ok; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + dsc_config_log(dsc, dsc_cfg); + is_config_ok = dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg); + ASSERT(is_config_ok); + drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc20->reg_vals.pps); + dsc_log_pps(dsc, &dsc20->reg_vals.pps); + dsc_write_to_registers(dsc, &dsc20->reg_vals); +} + + +static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + /* TODO Check if DSC alreay in use? */ + DC_LOG_DSC("enable DSC at opp pipe %d", opp_pipe); + + REG_UPDATE(DSC_TOP_CONTROL, + DSC_CLOCK_EN, 1); + + REG_UPDATE_2(DSCRM_DSC_FORWARD_CONFIG, + DSCRM_DSC_FORWARD_EN, 1, + DSCRM_DSC_OPP_PIPE_SOURCE, opp_pipe); +} + + +static void dsc2_disable(struct display_stream_compressor *dsc) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + DC_LOG_DSC("disable DSC"); + + REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, + DSCRM_DSC_FORWARD_EN, 0); + + REG_UPDATE(DSC_TOP_CONTROL, + DSC_CLOCK_EN, 0); +} + + +/* This module's internal functions */ +static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps) +{ + int i; + int bits_per_pixel = pps->bits_per_pixel; + + DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); + DC_LOG_DSC("\tdsc_version_major %d", pps->dsc_version_major); + DC_LOG_DSC("\tdsc_version_minor %d", pps->dsc_version_minor); + DC_LOG_DSC("\tbits_per_component %d", pps->bits_per_component); + DC_LOG_DSC("\tline_buf_depth %d", pps->line_buf_depth); + DC_LOG_DSC("\tblock_pred_enable %d", pps->block_pred_enable); + DC_LOG_DSC("\tconvert_rgb %d", pps->convert_rgb); + DC_LOG_DSC("\tsimple_422 %d", pps->simple_422); + DC_LOG_DSC("\tvbr_enable %d", pps->vbr_enable); + DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", bits_per_pixel, bits_per_pixel / 16, ((bits_per_pixel % 16) * 10000) / 16); + DC_LOG_DSC("\tpic_height %d", pps->pic_height); + DC_LOG_DSC("\tpic_width %d", pps->pic_width); + DC_LOG_DSC("\tslice_height %d", pps->slice_height); + DC_LOG_DSC("\tslice_width %d", pps->slice_width); + DC_LOG_DSC("\tslice_chunk_size %d", pps->slice_chunk_size); + DC_LOG_DSC("\tinitial_xmit_delay %d", pps->initial_xmit_delay); + DC_LOG_DSC("\tinitial_dec_delay %d", pps->initial_dec_delay); + DC_LOG_DSC("\tinitial_scale_value %d", pps->initial_scale_value); + DC_LOG_DSC("\tscale_increment_interval %d", pps->scale_increment_interval); + DC_LOG_DSC("\tscale_decrement_interval %d", pps->scale_decrement_interval); + DC_LOG_DSC("\tfirst_line_bpg_offset %d", pps->first_line_bpg_offset); + DC_LOG_DSC("\tnfl_bpg_offset %d", pps->nfl_bpg_offset); + DC_LOG_DSC("\tslice_bpg_offset %d", pps->slice_bpg_offset); + DC_LOG_DSC("\tinitial_offset %d", pps->initial_offset); + DC_LOG_DSC("\tfinal_offset %d", pps->final_offset); + DC_LOG_DSC("\tflatness_min_qp %d", pps->flatness_min_qp); + DC_LOG_DSC("\tflatness_max_qp %d", pps->flatness_max_qp); + /* DC_LOG_DSC("\trc_parameter_set %d", pps->rc_parameter_set); */ + DC_LOG_DSC("\tnative_420 %d", pps->native_420); + DC_LOG_DSC("\tnative_422 %d", pps->native_422); + DC_LOG_DSC("\tsecond_line_bpg_offset %d", pps->second_line_bpg_offset); + DC_LOG_DSC("\tnsl_bpg_offset %d", pps->nsl_bpg_offset); + DC_LOG_DSC("\tsecond_line_offset_adj %d", pps->second_line_offset_adj); + DC_LOG_DSC("\trc_model_size %d", pps->rc_model_size); + DC_LOG_DSC("\trc_edge_factor %d", pps->rc_edge_factor); + DC_LOG_DSC("\trc_quant_incr_limit0 %d", pps->rc_quant_incr_limit0); + DC_LOG_DSC("\trc_quant_incr_limit1 %d", pps->rc_quant_incr_limit1); + DC_LOG_DSC("\trc_tgt_offset_high %d", pps->rc_tgt_offset_high); + DC_LOG_DSC("\trc_tgt_offset_low %d", pps->rc_tgt_offset_low); + + for (i = 0; i < NUM_BUF_RANGES - 1; i++) + DC_LOG_DSC("\trc_buf_thresh[%d] %d", i, pps->rc_buf_thresh[i]); + + for (i = 0; i < NUM_BUF_RANGES; i++) { + DC_LOG_DSC("\trc_range_parameters[%d].range_min_qp %d", i, pps->rc_range_params[i].range_min_qp); + DC_LOG_DSC("\trc_range_parameters[%d].range_max_qp %d", i, pps->rc_range_params[i].range_max_qp); + DC_LOG_DSC("\trc_range_parameters[%d].range_bpg_offset %d", i, pps->rc_range_params[i].range_bpg_offset); + } +} + +static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg) +{ + struct dsc_parameters dsc_params; + + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + /* Validate input parameters */ + ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h); + ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v); + ASSERT(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2); + ASSERT(dsc_cfg->pic_width); + ASSERT(dsc_cfg->pic_height); + ASSERT((dsc_cfg->dc_dsc_cfg.version_minor == 1 && + (8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13)) || + (dsc_cfg->dc_dsc_cfg.version_minor == 2 && + ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || + dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))); + ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375 + + if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_v || + !(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) || + !dsc_cfg->pic_width || !dsc_cfg->pic_height || + !((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range: + 8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13) || + (dsc_cfg->dc_dsc_cfg.version_minor == 2 && // v1.2 line buffer depth range: + ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || + dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))) || + !(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff)) { + dm_output_to_console("%s: Invalid parameters\n", __func__); + return false; + } + + dsc_init_reg_values(&dsc20->reg_vals); + + /* Copy input config */ + dsc20->reg_vals.pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); + dsc20->reg_vals.num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc20->reg_vals.num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; + dsc20->reg_vals.pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; + dsc20->reg_vals.pps.pic_width = dsc_cfg->pic_width; + dsc20->reg_vals.pps.pic_height = dsc_cfg->pic_height; + dsc20->reg_vals.pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); + dsc20->reg_vals.pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; + dsc20->reg_vals.pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; + dsc20->reg_vals.alternate_ich_encoding_en = dsc20->reg_vals.pps.dsc_version_minor == 1 ? 0 : 1; + + // TODO: in addition to validating slice height (pic height must be divisible by slice height), + // see what happens when the same condition doesn't apply for slice_width/pic_width. + dsc20->reg_vals.pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc20->reg_vals.pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v; + + ASSERT(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); + if (!(dsc20->reg_vals.pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) { + dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v); + return false; + } + + dsc20->reg_vals.bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; + if (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32; + else + dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32 >> 1; + + dsc20->reg_vals.pps.convert_rgb = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB ? 1 : 0; + dsc20->reg_vals.pps.native_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); + dsc20->reg_vals.pps.native_420 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_NATIVE_YCBCR420); + dsc20->reg_vals.pps.simple_422 = (dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422); + + if (dscc_compute_dsc_parameters(&dsc20->reg_vals.pps, &dsc_params)) { + dm_output_to_console("%s: DSC config failed\n", __func__); + return false; + } + + dsc_update_from_dsc_parameters(&dsc20->reg_vals, &dsc_params); + + dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel; + dsc_optc_cfg->slice_width = dsc20->reg_vals.pps.slice_width; + dsc_optc_cfg->is_pixel_format_444 = dsc20->reg_vals.pixel_format == DSC_PIXFMT_RGB || + dsc20->reg_vals.pixel_format == DSC_PIXFMT_YCBCR444 || + dsc20->reg_vals.pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; + + return true; +} + + +static enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple) +{ + enum dsc_pixel_format dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; + + /* NOTE: We don't support DSC_PIXFMT_SIMPLE_YCBCR422 */ + + switch (dc_pix_enc) { + case PIXEL_ENCODING_RGB: + dsc_pix_fmt = DSC_PIXFMT_RGB; + break; + case PIXEL_ENCODING_YCBCR422: + if (is_ycbcr422_simple) + dsc_pix_fmt = DSC_PIXFMT_SIMPLE_YCBCR422; + else + dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR422; + break; + case PIXEL_ENCODING_YCBCR444: + dsc_pix_fmt = DSC_PIXFMT_YCBCR444; + break; + case PIXEL_ENCODING_YCBCR420: + dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR420; + break; + default: + dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; + break; + } + + ASSERT(dsc_pix_fmt != DSC_PIXFMT_UNKNOWN); + return dsc_pix_fmt; +} + + +static enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth) +{ + enum dsc_bits_per_comp bpc = DSC_BPC_UNKNOWN; + + switch (dc_color_depth) { + case COLOR_DEPTH_888: + bpc = DSC_BPC_8; + break; + case COLOR_DEPTH_101010: + bpc = DSC_BPC_10; + break; + case COLOR_DEPTH_121212: + bpc = DSC_BPC_12; + break; + default: + bpc = DSC_BPC_UNKNOWN; + break; + } + + return bpc; +} + + +static void dsc_init_reg_values(struct dsc_reg_values *reg_vals) +{ + int i; + + /* Non-PPS values */ + reg_vals->dsc_clock_enable = 1; + reg_vals->dsc_clock_gating_disable = 0; + reg_vals->underflow_recovery_en = 0; + reg_vals->underflow_occurred_int_en = 0; + reg_vals->underflow_occurred_status = 0; + reg_vals->ich_reset_at_eol = 0; + reg_vals->alternate_ich_encoding_en = 0; + reg_vals->rc_buffer_model_size = 0; + reg_vals->disable_ich = 0; + reg_vals->dsc_dbg_en = 0; + + for (i = 0; i < 4; i++) + reg_vals->rc_buffer_model_overflow_int_en[i] = 0; + + /* PPS values */ + reg_vals->pps.dsc_version_minor = 2; + reg_vals->pps.dsc_version_major = 1; + reg_vals->pps.line_buf_depth = 9; + reg_vals->pps.bits_per_component = 8; + reg_vals->pps.block_pred_enable = 1; + reg_vals->pps.slice_chunk_size = 0; + reg_vals->pps.pic_width = 0; + reg_vals->pps.pic_height = 0; + reg_vals->pps.slice_width = 0; + reg_vals->pps.slice_height = 0; + reg_vals->pps.initial_xmit_delay = 170; + reg_vals->pps.initial_dec_delay = 0; + reg_vals->pps.initial_scale_value = 0; + reg_vals->pps.scale_increment_interval = 0; + reg_vals->pps.scale_decrement_interval = 0; + reg_vals->pps.nfl_bpg_offset = 0; + reg_vals->pps.slice_bpg_offset = 0; + reg_vals->pps.nsl_bpg_offset = 0; + reg_vals->pps.initial_offset = 6144; + reg_vals->pps.final_offset = 0; + reg_vals->pps.flatness_min_qp = 3; + reg_vals->pps.flatness_max_qp = 12; + reg_vals->pps.rc_model_size = 8192; + reg_vals->pps.rc_edge_factor = 6; + reg_vals->pps.rc_quant_incr_limit0 = 11; + reg_vals->pps.rc_quant_incr_limit1 = 11; + reg_vals->pps.rc_tgt_offset_low = 3; + reg_vals->pps.rc_tgt_offset_high = 3; +} + +/* Updates dsc_reg_values::reg_vals::xxx fields based on the values from computed params. + * This is required because dscc_compute_dsc_parameters returns a modified PPS, which in turn + * affects non-PPS register values. + */ +static void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params) +{ + int i; + + reg_vals->pps = dsc_params->pps; + + // pps_computed will have the "expanded" values; need to shift them to make them fit for regs. + for (i = 0; i < NUM_BUF_RANGES - 1; i++) + reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6; + + reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size; + reg_vals->ich_reset_at_eol = reg_vals->num_slices_h == 1 ? 0 : 0xf; +} + +static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals) +{ + uint32_t temp_int; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + REG_SET(DSC_DEBUG_CONTROL, 0, + DSC_DBG_EN, reg_vals->dsc_dbg_en); + + // dsccif registers + REG_SET_5(DSCCIF_CONFIG0, 0, + INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, reg_vals->underflow_recovery_en, + INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, reg_vals->underflow_occurred_int_en, + INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, reg_vals->underflow_occurred_status, + INPUT_PIXEL_FORMAT, reg_vals->pixel_format, + DSCCIF_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); + + REG_SET_2(DSCCIF_CONFIG1, 0, + PIC_WIDTH, reg_vals->pps.pic_width, + PIC_HEIGHT, reg_vals->pps.pic_height); + + // dscc registers + REG_SET_4(DSCC_CONFIG0, 0, + ICH_RESET_AT_END_OF_LINE, reg_vals->ich_reset_at_eol, + NUMBER_OF_SLICES_PER_LINE, reg_vals->num_slices_h - 1, + ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en, + NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1); + + REG_SET_2(DSCC_CONFIG1, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size, + DSCC_DISABLE_ICH, reg_vals->disable_ich); + + REG_SET_4(DSCC_INTERRUPT_CONTROL_STATUS, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[0], + DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[1], + DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[2], + DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[3]); + + REG_SET_3(DSCC_PPS_CONFIG0, 0, + DSC_VERSION_MINOR, reg_vals->pps.dsc_version_minor, + LINEBUF_DEPTH, reg_vals->pps.line_buf_depth, + DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); + + if (reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + temp_int = reg_vals->bpp_x32; + else + temp_int = reg_vals->bpp_x32 >> 1; + + REG_SET_7(DSCC_PPS_CONFIG1, 0, + BITS_PER_PIXEL, temp_int, + SIMPLE_422, reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422, + CONVERT_RGB, reg_vals->pixel_format == DSC_PIXFMT_RGB, + BLOCK_PRED_ENABLE, reg_vals->pps.block_pred_enable, + NATIVE_422, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422, + NATIVE_420, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420, + CHUNK_SIZE, reg_vals->pps.slice_chunk_size); + + REG_SET_2(DSCC_PPS_CONFIG2, 0, + PIC_WIDTH, reg_vals->pps.pic_width, + PIC_HEIGHT, reg_vals->pps.pic_height); + + REG_SET_2(DSCC_PPS_CONFIG3, 0, + SLICE_WIDTH, reg_vals->pps.slice_width, + SLICE_HEIGHT, reg_vals->pps.slice_height); + + REG_SET(DSCC_PPS_CONFIG4, 0, + INITIAL_XMIT_DELAY, reg_vals->pps.initial_xmit_delay); + + REG_SET_2(DSCC_PPS_CONFIG5, 0, + INITIAL_SCALE_VALUE, reg_vals->pps.initial_scale_value, + SCALE_INCREMENT_INTERVAL, reg_vals->pps.scale_increment_interval); + + REG_SET_3(DSCC_PPS_CONFIG6, 0, + SCALE_DECREMENT_INTERVAL, reg_vals->pps.scale_decrement_interval, + FIRST_LINE_BPG_OFFSET, reg_vals->pps.first_line_bpg_offset, + SECOND_LINE_BPG_OFFSET, reg_vals->pps.second_line_bpg_offset); + + REG_SET_2(DSCC_PPS_CONFIG7, 0, + NFL_BPG_OFFSET, reg_vals->pps.nfl_bpg_offset, + SLICE_BPG_OFFSET, reg_vals->pps.slice_bpg_offset); + + REG_SET_2(DSCC_PPS_CONFIG8, 0, + NSL_BPG_OFFSET, reg_vals->pps.nsl_bpg_offset, + SECOND_LINE_OFFSET_ADJ, reg_vals->pps.second_line_offset_adj); + + REG_SET_2(DSCC_PPS_CONFIG9, 0, + INITIAL_OFFSET, reg_vals->pps.initial_offset, + FINAL_OFFSET, reg_vals->pps.final_offset); + + REG_SET_3(DSCC_PPS_CONFIG10, 0, + FLATNESS_MIN_QP, reg_vals->pps.flatness_min_qp, + FLATNESS_MAX_QP, reg_vals->pps.flatness_max_qp, + RC_MODEL_SIZE, reg_vals->pps.rc_model_size); + + REG_SET_5(DSCC_PPS_CONFIG11, 0, + RC_EDGE_FACTOR, reg_vals->pps.rc_edge_factor, + RC_QUANT_INCR_LIMIT0, reg_vals->pps.rc_quant_incr_limit0, + RC_QUANT_INCR_LIMIT1, reg_vals->pps.rc_quant_incr_limit1, + RC_TGT_OFFSET_LO, reg_vals->pps.rc_tgt_offset_low, + RC_TGT_OFFSET_HI, reg_vals->pps.rc_tgt_offset_high); + + REG_SET_4(DSCC_PPS_CONFIG12, 0, + RC_BUF_THRESH0, reg_vals->pps.rc_buf_thresh[0], + RC_BUF_THRESH1, reg_vals->pps.rc_buf_thresh[1], + RC_BUF_THRESH2, reg_vals->pps.rc_buf_thresh[2], + RC_BUF_THRESH3, reg_vals->pps.rc_buf_thresh[3]); + + REG_SET_4(DSCC_PPS_CONFIG13, 0, + RC_BUF_THRESH4, reg_vals->pps.rc_buf_thresh[4], + RC_BUF_THRESH5, reg_vals->pps.rc_buf_thresh[5], + RC_BUF_THRESH6, reg_vals->pps.rc_buf_thresh[6], + RC_BUF_THRESH7, reg_vals->pps.rc_buf_thresh[7]); + + REG_SET_4(DSCC_PPS_CONFIG14, 0, + RC_BUF_THRESH8, reg_vals->pps.rc_buf_thresh[8], + RC_BUF_THRESH9, reg_vals->pps.rc_buf_thresh[9], + RC_BUF_THRESH10, reg_vals->pps.rc_buf_thresh[10], + RC_BUF_THRESH11, reg_vals->pps.rc_buf_thresh[11]); + + REG_SET_5(DSCC_PPS_CONFIG15, 0, + RC_BUF_THRESH12, reg_vals->pps.rc_buf_thresh[12], + RC_BUF_THRESH13, reg_vals->pps.rc_buf_thresh[13], + RANGE_MIN_QP0, reg_vals->pps.rc_range_params[0].range_min_qp, + RANGE_MAX_QP0, reg_vals->pps.rc_range_params[0].range_max_qp, + RANGE_BPG_OFFSET0, reg_vals->pps.rc_range_params[0].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG16, 0, + RANGE_MIN_QP1, reg_vals->pps.rc_range_params[1].range_min_qp, + RANGE_MAX_QP1, reg_vals->pps.rc_range_params[1].range_max_qp, + RANGE_BPG_OFFSET1, reg_vals->pps.rc_range_params[1].range_bpg_offset, + RANGE_MIN_QP2, reg_vals->pps.rc_range_params[2].range_min_qp, + RANGE_MAX_QP2, reg_vals->pps.rc_range_params[2].range_max_qp, + RANGE_BPG_OFFSET2, reg_vals->pps.rc_range_params[2].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG17, 0, + RANGE_MIN_QP3, reg_vals->pps.rc_range_params[3].range_min_qp, + RANGE_MAX_QP3, reg_vals->pps.rc_range_params[3].range_max_qp, + RANGE_BPG_OFFSET3, reg_vals->pps.rc_range_params[3].range_bpg_offset, + RANGE_MIN_QP4, reg_vals->pps.rc_range_params[4].range_min_qp, + RANGE_MAX_QP4, reg_vals->pps.rc_range_params[4].range_max_qp, + RANGE_BPG_OFFSET4, reg_vals->pps.rc_range_params[4].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG18, 0, + RANGE_MIN_QP5, reg_vals->pps.rc_range_params[5].range_min_qp, + RANGE_MAX_QP5, reg_vals->pps.rc_range_params[5].range_max_qp, + RANGE_BPG_OFFSET5, reg_vals->pps.rc_range_params[5].range_bpg_offset, + RANGE_MIN_QP6, reg_vals->pps.rc_range_params[6].range_min_qp, + RANGE_MAX_QP6, reg_vals->pps.rc_range_params[6].range_max_qp, + RANGE_BPG_OFFSET6, reg_vals->pps.rc_range_params[6].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG19, 0, + RANGE_MIN_QP7, reg_vals->pps.rc_range_params[7].range_min_qp, + RANGE_MAX_QP7, reg_vals->pps.rc_range_params[7].range_max_qp, + RANGE_BPG_OFFSET7, reg_vals->pps.rc_range_params[7].range_bpg_offset, + RANGE_MIN_QP8, reg_vals->pps.rc_range_params[8].range_min_qp, + RANGE_MAX_QP8, reg_vals->pps.rc_range_params[8].range_max_qp, + RANGE_BPG_OFFSET8, reg_vals->pps.rc_range_params[8].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG20, 0, + RANGE_MIN_QP9, reg_vals->pps.rc_range_params[9].range_min_qp, + RANGE_MAX_QP9, reg_vals->pps.rc_range_params[9].range_max_qp, + RANGE_BPG_OFFSET9, reg_vals->pps.rc_range_params[9].range_bpg_offset, + RANGE_MIN_QP10, reg_vals->pps.rc_range_params[10].range_min_qp, + RANGE_MAX_QP10, reg_vals->pps.rc_range_params[10].range_max_qp, + RANGE_BPG_OFFSET10, reg_vals->pps.rc_range_params[10].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG21, 0, + RANGE_MIN_QP11, reg_vals->pps.rc_range_params[11].range_min_qp, + RANGE_MAX_QP11, reg_vals->pps.rc_range_params[11].range_max_qp, + RANGE_BPG_OFFSET11, reg_vals->pps.rc_range_params[11].range_bpg_offset, + RANGE_MIN_QP12, reg_vals->pps.rc_range_params[12].range_min_qp, + RANGE_MAX_QP12, reg_vals->pps.rc_range_params[12].range_max_qp, + RANGE_BPG_OFFSET12, reg_vals->pps.rc_range_params[12].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG22, 0, + RANGE_MIN_QP13, reg_vals->pps.rc_range_params[13].range_min_qp, + RANGE_MAX_QP13, reg_vals->pps.rc_range_params[13].range_max_qp, + RANGE_BPG_OFFSET13, reg_vals->pps.rc_range_params[13].range_bpg_offset, + RANGE_MIN_QP14, reg_vals->pps.rc_range_params[14].range_min_qp, + RANGE_MAX_QP14, reg_vals->pps.rc_range_params[14].range_max_qp, + RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset); + + if (IS_FPGA_MAXIMUS_DC(dsc20->base.ctx->dce_environment)) { + /* It's safe to do this as long as debug bus is not being used in DAL Diag environment. + * + * This is because DSCC_PPS_CONFIG4.INITIAL_DEC_DELAY is a read-only register field (because it's a decoder + * value not required by DSC encoder). However, since decoding fails when this value is missing from PPS, it's + * required to communicate this value to the PPS header. When testing on FPGA, the values for PPS header are + * being read from Diag register dump. The register below is used in place of a scratch register to make + * 'initial_dec_delay' available. + */ + + temp_int = reg_vals->pps.initial_dec_delay; + REG_SET_4(DSCC_TEST_DEBUG_BUS_ROTATE, 0, + DSCC_TEST_DEBUG_BUS0_ROTATE, temp_int & 0x1f, + DSCC_TEST_DEBUG_BUS1_ROTATE, temp_int >> 5 & 0x1f, + DSCC_TEST_DEBUG_BUS2_ROTATE, temp_int >> 10 & 0x1f, + DSCC_TEST_DEBUG_BUS3_ROTATE, temp_int >> 15 & 0x1); + } +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h new file mode 100644 index 000000000000..168865a16288 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -0,0 +1,575 @@ +/* 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. + * + * Authors: AMD + * + */ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#ifndef __DCN20_DSC_H__ +#define __DCN20_DSC_H__ + +#include "dsc.h" +#include "dsc/dscc_types.h" +#include <drm/drm_dsc.h> + +#define TO_DCN20_DSC(dsc)\ + container_of(dsc, struct dcn20_dsc, base) + +#define DSC_REG_LIST_DCN20(id) \ + SRI(DSC_TOP_CONTROL, DSC_TOP, id),\ + SRI(DSC_DEBUG_CONTROL, DSC_TOP, id),\ + SRI(DSCC_CONFIG0, DSCC, id),\ + SRI(DSCC_CONFIG1, DSCC, id),\ + SRI(DSCC_STATUS, DSCC, id),\ + SRI(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id),\ + SRI(DSCC_PPS_CONFIG0, DSCC, id),\ + SRI(DSCC_PPS_CONFIG1, DSCC, id),\ + SRI(DSCC_PPS_CONFIG2, DSCC, id),\ + SRI(DSCC_PPS_CONFIG3, DSCC, id),\ + SRI(DSCC_PPS_CONFIG4, DSCC, id),\ + SRI(DSCC_PPS_CONFIG5, DSCC, id),\ + SRI(DSCC_PPS_CONFIG6, DSCC, id),\ + SRI(DSCC_PPS_CONFIG7, DSCC, id),\ + SRI(DSCC_PPS_CONFIG8, DSCC, id),\ + SRI(DSCC_PPS_CONFIG9, DSCC, id),\ + SRI(DSCC_PPS_CONFIG10, DSCC, id),\ + SRI(DSCC_PPS_CONFIG11, DSCC, id),\ + SRI(DSCC_PPS_CONFIG12, DSCC, id),\ + SRI(DSCC_PPS_CONFIG13, DSCC, id),\ + SRI(DSCC_PPS_CONFIG14, DSCC, id),\ + SRI(DSCC_PPS_CONFIG15, DSCC, id),\ + SRI(DSCC_PPS_CONFIG16, DSCC, id),\ + SRI(DSCC_PPS_CONFIG17, DSCC, id),\ + SRI(DSCC_PPS_CONFIG18, DSCC, id),\ + SRI(DSCC_PPS_CONFIG19, DSCC, id),\ + SRI(DSCC_PPS_CONFIG20, DSCC, id),\ + SRI(DSCC_PPS_CONFIG21, DSCC, id),\ + SRI(DSCC_PPS_CONFIG22, DSCC, id),\ + SRI(DSCC_MEM_POWER_CONTROL, DSCC, id),\ + SRI(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_MAX_ABS_ERROR0, DSCC, id),\ + SRI(DSCC_MAX_ABS_ERROR1, DSCC, id),\ + SRI(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_TEST_DEBUG_BUS_ROTATE, DSCC, id),\ + SRI(DSCCIF_CONFIG0, DSCCIF, id),\ + SRI(DSCCIF_CONFIG1, DSCCIF, id),\ + SRI(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) + + +#define DSC_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +//Used in resolving the corner case with duplicate field name +#define DSC2_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## _ ## field_name ## post_fix + +#define DSC_REG_LIST_SH_MASK_DCN20(mask_sh)\ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_TEST_CLOCK_MUX_SEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh), \ + DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \ + DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_FORCE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_DIS, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_FORCE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_DIS, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC_R_Y_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC_R_Y_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC_G_CB_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC_G_CB_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC_B_CR_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC_B_CR_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_R_Y_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_G_CB_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR1, DSCC_B_CR_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS0_ROTATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS1_ROTATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS2_ROTATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS3_ROTATE, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_PIXEL_FORMAT, mask_sh), \ + DSC2_SF(DSCCIF0, DSCCIF_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_WIDTH, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_HEIGHT, mask_sh), \ + DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \ + DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh) + + + +#define DSC_FIELD_LIST_DCN20(type)\ + type DSC_CLOCK_EN; \ + type DSC_DISPCLK_R_GATE_DIS; \ + type DSC_DSCCLK_R_GATE_DIS; \ + type DSC_DBG_EN; \ + type DSC_TEST_CLOCK_MUX_SEL; \ + type ICH_RESET_AT_END_OF_LINE; \ + type NUMBER_OF_SLICES_PER_LINE; \ + type ALTERNATE_ICH_ENCODING_EN; \ + type NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE; \ + type DSCC_DISABLE_ICH; \ + type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \ + type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN; \ + type DSC_VERSION_MINOR; \ + type DSC_VERSION_MAJOR; \ + type PPS_IDENTIFIER; \ + type LINEBUF_DEPTH; \ + type DSCC_PPS_CONFIG0__BITS_PER_COMPONENT; \ + type BITS_PER_PIXEL; \ + type VBR_ENABLE; \ + type SIMPLE_422; \ + type CONVERT_RGB; \ + type BLOCK_PRED_ENABLE; \ + type NATIVE_422; \ + type NATIVE_420; \ + type CHUNK_SIZE; \ + type PIC_WIDTH; \ + type PIC_HEIGHT; \ + type SLICE_WIDTH; \ + type SLICE_HEIGHT; \ + type INITIAL_XMIT_DELAY; \ + type INITIAL_DEC_DELAY; \ + type INITIAL_SCALE_VALUE; \ + type SCALE_INCREMENT_INTERVAL; \ + type SCALE_DECREMENT_INTERVAL; \ + type FIRST_LINE_BPG_OFFSET; \ + type SECOND_LINE_BPG_OFFSET; \ + type NFL_BPG_OFFSET; \ + type SLICE_BPG_OFFSET; \ + type NSL_BPG_OFFSET; \ + type SECOND_LINE_OFFSET_ADJ; \ + type INITIAL_OFFSET; \ + type FINAL_OFFSET; \ + type FLATNESS_MIN_QP; \ + type FLATNESS_MAX_QP; \ + type RC_MODEL_SIZE; \ + type RC_EDGE_FACTOR; \ + type RC_QUANT_INCR_LIMIT0; \ + type RC_QUANT_INCR_LIMIT1; \ + type RC_TGT_OFFSET_LO; \ + type RC_TGT_OFFSET_HI; \ + type RC_BUF_THRESH0; \ + type RC_BUF_THRESH1; \ + type RC_BUF_THRESH2; \ + type RC_BUF_THRESH3; \ + type RC_BUF_THRESH4; \ + type RC_BUF_THRESH5; \ + type RC_BUF_THRESH6; \ + type RC_BUF_THRESH7; \ + type RC_BUF_THRESH8; \ + type RC_BUF_THRESH9; \ + type RC_BUF_THRESH10; \ + type RC_BUF_THRESH11; \ + type RC_BUF_THRESH12; \ + type RC_BUF_THRESH13; \ + type RANGE_MIN_QP0; \ + type RANGE_MAX_QP0; \ + type RANGE_BPG_OFFSET0; \ + type RANGE_MIN_QP1; \ + type RANGE_MAX_QP1; \ + type RANGE_BPG_OFFSET1; \ + type RANGE_MIN_QP2; \ + type RANGE_MAX_QP2; \ + type RANGE_BPG_OFFSET2; \ + type RANGE_MIN_QP3; \ + type RANGE_MAX_QP3; \ + type RANGE_BPG_OFFSET3; \ + type RANGE_MIN_QP4; \ + type RANGE_MAX_QP4; \ + type RANGE_BPG_OFFSET4; \ + type RANGE_MIN_QP5; \ + type RANGE_MAX_QP5; \ + type RANGE_BPG_OFFSET5; \ + type RANGE_MIN_QP6; \ + type RANGE_MAX_QP6; \ + type RANGE_BPG_OFFSET6; \ + type RANGE_MIN_QP7; \ + type RANGE_MAX_QP7; \ + type RANGE_BPG_OFFSET7; \ + type RANGE_MIN_QP8; \ + type RANGE_MAX_QP8; \ + type RANGE_BPG_OFFSET8; \ + type RANGE_MIN_QP9; \ + type RANGE_MAX_QP9; \ + type RANGE_BPG_OFFSET9; \ + type RANGE_MIN_QP10; \ + type RANGE_MAX_QP10; \ + type RANGE_BPG_OFFSET10; \ + type RANGE_MIN_QP11; \ + type RANGE_MAX_QP11; \ + type RANGE_BPG_OFFSET11; \ + type RANGE_MIN_QP12; \ + type RANGE_MAX_QP12; \ + type RANGE_BPG_OFFSET12; \ + type RANGE_MIN_QP13; \ + type RANGE_MAX_QP13; \ + type RANGE_BPG_OFFSET13; \ + type RANGE_MIN_QP14; \ + type RANGE_MAX_QP14; \ + type RANGE_BPG_OFFSET14; \ + type DSCC_DEFAULT_MEM_LOW_POWER_STATE; \ + type DSCC_MEM_PWR_FORCE; \ + type DSCC_MEM_PWR_DIS; \ + type DSCC_MEM_PWR_STATE; \ + type DSCC_NATIVE_422_MEM_PWR_FORCE; \ + type DSCC_NATIVE_422_MEM_PWR_DIS; \ + type DSCC_NATIVE_422_MEM_PWR_STATE; \ + type DSCC_R_Y_SQUARED_ERROR_LOWER; \ + type DSCC_R_Y_SQUARED_ERROR_UPPER; \ + type DSCC_G_CB_SQUARED_ERROR_LOWER; \ + type DSCC_G_CB_SQUARED_ERROR_UPPER; \ + type DSCC_B_CR_SQUARED_ERROR_LOWER; \ + type DSCC_B_CR_SQUARED_ERROR_UPPER; \ + type DSCC_R_Y_MAX_ABS_ERROR; \ + type DSCC_G_CB_MAX_ABS_ERROR; \ + type DSCC_B_CR_MAX_ABS_ERROR; \ + type DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; \ + type DSCC_UPDATE_PENDING_STATUS; \ + type DSCC_UPDATE_TAKEN_STATUS; \ + type DSCC_UPDATE_TAKEN_ACK; \ + type DSCC_TEST_DEBUG_BUS0_ROTATE; \ + type DSCC_TEST_DEBUG_BUS1_ROTATE; \ + type DSCC_TEST_DEBUG_BUS2_ROTATE; \ + type DSCC_TEST_DEBUG_BUS3_ROTATE; \ + type DSCC_RATE_BUFFER0_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER1_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER2_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER3_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER0_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER1_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER2_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER3_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER0_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER1_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER2_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER3_INITIAL_XMIT_DELAY_REACHED; \ + type INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN; \ + type INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN; \ + type INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS; \ + type INPUT_PIXEL_FORMAT; \ + type DSCCIF_CONFIG0__BITS_PER_COMPONENT; \ + type DOUBLE_BUFFER_REG_UPDATE_PENDING; \ + type DSCCIF_UPDATE_PENDING_STATUS; \ + type DSCCIF_UPDATE_TAKEN_STATUS; \ + type DSCCIF_UPDATE_TAKEN_ACK; \ + type DSCRM_DSC_FORWARD_EN; \ + type DSCRM_DSC_OPP_PIPE_SOURCE + + +struct dcn20_dsc_registers { + uint32_t DSC_TOP_CONTROL; + uint32_t DSC_DEBUG_CONTROL; + uint32_t DSCC_CONFIG0; + uint32_t DSCC_CONFIG1; + uint32_t DSCC_STATUS; + uint32_t DSCC_INTERRUPT_CONTROL_STATUS; + uint32_t DSCC_PPS_CONFIG0; + uint32_t DSCC_PPS_CONFIG1; + uint32_t DSCC_PPS_CONFIG2; + uint32_t DSCC_PPS_CONFIG3; + uint32_t DSCC_PPS_CONFIG4; + uint32_t DSCC_PPS_CONFIG5; + uint32_t DSCC_PPS_CONFIG6; + uint32_t DSCC_PPS_CONFIG7; + uint32_t DSCC_PPS_CONFIG8; + uint32_t DSCC_PPS_CONFIG9; + uint32_t DSCC_PPS_CONFIG10; + uint32_t DSCC_PPS_CONFIG11; + uint32_t DSCC_PPS_CONFIG12; + uint32_t DSCC_PPS_CONFIG13; + uint32_t DSCC_PPS_CONFIG14; + uint32_t DSCC_PPS_CONFIG15; + uint32_t DSCC_PPS_CONFIG16; + uint32_t DSCC_PPS_CONFIG17; + uint32_t DSCC_PPS_CONFIG18; + uint32_t DSCC_PPS_CONFIG19; + uint32_t DSCC_PPS_CONFIG20; + uint32_t DSCC_PPS_CONFIG21; + uint32_t DSCC_PPS_CONFIG22; + uint32_t DSCC_MEM_POWER_CONTROL; + uint32_t DSCC_R_Y_SQUARED_ERROR_LOWER; + uint32_t DSCC_R_Y_SQUARED_ERROR_UPPER; + uint32_t DSCC_G_CB_SQUARED_ERROR_LOWER; + uint32_t DSCC_G_CB_SQUARED_ERROR_UPPER; + uint32_t DSCC_B_CR_SQUARED_ERROR_LOWER; + uint32_t DSCC_B_CR_SQUARED_ERROR_UPPER; + uint32_t DSCC_MAX_ABS_ERROR0; + uint32_t DSCC_MAX_ABS_ERROR1; + uint32_t DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; + uint32_t DSCC_TEST_DEBUG_BUS_ROTATE; + uint32_t DSCCIF_CONFIG0; + uint32_t DSCCIF_CONFIG1; + uint32_t DSCRM_DSC_FORWARD_CONFIG; +}; + + +struct dcn20_dsc_shift { + DSC_FIELD_LIST_DCN20(uint8_t); +}; + +struct dcn20_dsc_mask { + DSC_FIELD_LIST_DCN20(uint32_t); +}; + +/* DSCCIF_CONFIG.INPUT_PIXEL_FORMAT values */ +enum dsc_pixel_format { + DSC_PIXFMT_RGB, + DSC_PIXFMT_YCBCR444, + DSC_PIXFMT_SIMPLE_YCBCR422, + DSC_PIXFMT_NATIVE_YCBCR422, + DSC_PIXFMT_NATIVE_YCBCR420, + DSC_PIXFMT_UNKNOWN +}; + +struct dsc_reg_values { + /* PPS registers */ + struct drm_dsc_config pps; + + /* Additional registers */ + uint32_t dsc_clock_enable; + uint32_t dsc_clock_gating_disable; + uint32_t underflow_recovery_en; + uint32_t underflow_occurred_int_en; + uint32_t underflow_occurred_status; + enum dsc_pixel_format pixel_format; + uint32_t ich_reset_at_eol; + uint32_t alternate_ich_encoding_en; + uint32_t num_slices_h; + uint32_t num_slices_v; + uint32_t rc_buffer_model_size; + uint32_t disable_ich; + uint32_t bpp_x32; + uint32_t dsc_dbg_en; + uint32_t rc_buffer_model_overflow_int_en[4]; +}; + +struct dcn20_dsc { + struct display_stream_compressor base; + const struct dcn20_dsc_registers *dsc_regs; + const struct dcn20_dsc_shift *dsc_shift; + const struct dcn20_dsc_mask *dsc_mask; + + struct dsc_reg_values reg_vals; + + int max_image_width; +}; + + +void dsc2_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn20_dsc_shift *dsc_shift, + const struct dcn20_dsc_mask *dsc_mask); + +#endif + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.c new file mode 100644 index 000000000000..8d3884b306dd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.c @@ -0,0 +1,332 @@ +/* + * Copyright 2012-17 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 "reg_helper.h" +#include "resource.h" +#include "dwb.h" +#include "dcn20_dwb.h" + + +#define REG(reg)\ + dwbc20->dwbc_regs->reg + +#define CTX \ + dwbc20->base.ctx + +#define DC_LOGGER \ + dwbc20->base.ctx->logger +#undef FN +#define FN(reg_name, field_name) \ + dwbc20->dwbc_shift->field_name, dwbc20->dwbc_mask->field_name + +enum dwb_outside_pix_strategy { + DWB_OUTSIDE_PIX_STRATEGY_BLACK = 0, + DWB_OUTSIDE_PIX_STRATEGY_EDGE = 1 +}; + +static bool dwb2_get_caps(struct dwbc *dwbc, struct dwb_caps *caps) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + if (caps) { + caps->adapter_id = 0; /* we only support 1 adapter currently */ + caps->hw_version = DCN_VERSION_2_0; + caps->num_pipes = 1; + memset(&caps->reserved, 0, sizeof(caps->reserved)); + memset(&caps->reserved2, 0, sizeof(caps->reserved2)); + caps->sw_version = dwb_ver_1_0; + caps->caps.support_dwb = true; + caps->caps.support_ogam = false; + caps->caps.support_wbscl = false; + caps->caps.support_ocsc = false; + DC_LOG_DWB("%s SUPPORTED! inst = %d", __func__, dwbc20->base.inst); + return true; + } else { + DC_LOG_DWB("%s NOT SUPPORTED! inst = %d", __func__, dwbc20->base.inst); + return false; + } +} + +void dwb2_config_dwb_cnv(struct dwbc *dwbc, struct dc_dwb_params *params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); + + /* Set DWB source size */ + REG_UPDATE_2(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, params->cnv_params.src_width, + CNV_SOURCE_HEIGHT, params->cnv_params.src_height); + + /* source size is not equal the source size, then enable cropping. */ + if (params->cnv_params.crop_en) { + REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 1); + REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_X, params->cnv_params.crop_x); + REG_UPDATE(CNV_WINDOW_START, CNV_WINDOW_START_Y, params->cnv_params.crop_y); + REG_UPDATE(CNV_WINDOW_SIZE, CNV_WINDOW_WIDTH, params->cnv_params.crop_width); + REG_UPDATE(CNV_WINDOW_SIZE, CNV_WINDOW_HEIGHT, params->cnv_params.crop_height); + } else { + REG_UPDATE(CNV_MODE, CNV_WINDOW_CROP_EN, 0); + } + + /* Set CAPTURE_RATE */ + REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_RATE, params->capture_rate); + + /* Set CNV output pixel depth */ + REG_UPDATE(CNV_MODE, CNV_OUT_BPC, params->cnv_params.cnv_out_bpc); +} + +static bool dwb2_enable(struct dwbc *dwbc, struct dc_dwb_params *params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + + /* Only chroma scaling (sub-sampling) is supported in DCN2 */ +if ((params->cnv_params.src_width != params->dest_width) || + (params->cnv_params.src_height != params->dest_height)) { + + DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst); + return false; + } + DC_LOG_DWB("%s inst = %d, ENABLED", __func__, dwbc20->base.inst); + + /* disable power gating */ + //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 1, + // DISPCLK_G_WB_GATE_DIS, 1, DISPCLK_G_WBSCL_GATE_DIS, 1, + // WB_LB_LS_DIS, 1, WB_LUT_LS_DIS, 1); + + /* Set WB_ENABLE (not double buffered; capture not enabled) */ + REG_UPDATE(WB_ENABLE, WB_ENABLE, 1); + + /* Set CNV parameters */ + dwb2_config_dwb_cnv(dwbc, params); + + /* Set scaling parameters */ + dwb2_set_scaler(dwbc, params); + + /* Enable DWB capture enable (double buffered) */ + REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_ENABLE); + + // disable warmup + REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, 0); + + return true; +} + +bool dwb2_disable(struct dwbc *dwbc) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d, Disabled", __func__, dwbc20->base.inst); + + /* disable CNV */ + REG_UPDATE(CNV_MODE, CNV_FRAME_CAPTURE_EN, DWB_FRAME_CAPTURE_DISABLE); + + /* disable WB */ + REG_UPDATE(WB_ENABLE, WB_ENABLE, 0); + + /* soft reset */ + REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 1); + REG_UPDATE(WB_SOFT_RESET, WB_SOFT_RESET, 0); + + /* enable power gating */ + //REG_UPDATE_5(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, 0, + // DISPCLK_G_WB_GATE_DIS, 0, DISPCLK_G_WBSCL_GATE_DIS, 0, + // WB_LB_LS_DIS, 0, WB_LUT_LS_DIS, 0); + + return true; +} + +static bool dwb2_update(struct dwbc *dwbc, struct dc_dwb_params *params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + unsigned int pre_locked; + + /* Only chroma scaling (sub-sampling) is supported in DCN2 */ + if ((params->cnv_params.src_width != params->dest_width) || + (params->cnv_params.src_height != params->dest_height)) { + DC_LOG_DWB("%s inst = %d, FAILED!LUMA SCALING NOT SUPPORTED", __func__, dwbc20->base.inst); + return false; + } + DC_LOG_DWB("%s inst = %d, scaling", __func__, dwbc20->base.inst); + + /* + * Check if the caller has already locked CNV registers. + * If so: assume the caller will unlock, so don't touch the lock. + * If not: lock them for this update, then unlock after the + * update is complete. + */ + REG_GET(CNV_UPDATE, CNV_UPDATE_LOCK, &pre_locked); + + if (pre_locked == 0) { + /* Lock DWB registers */ + REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 1); + } + + /* Set CNV parameters */ + dwb2_config_dwb_cnv(dwbc, params); + + /* Set scaling parameters */ + dwb2_set_scaler(dwbc, params); + + if (pre_locked == 0) { + /* Unlock DWB registers */ + REG_UPDATE(CNV_UPDATE, CNV_UPDATE_LOCK, 0); + } + + return true; +} + +bool dwb2_is_enabled(struct dwbc *dwbc) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + unsigned int wb_enabled = 0; + unsigned int cnv_frame_capture_en = 0; + + REG_GET(WB_ENABLE, WB_ENABLE, &wb_enabled); + REG_GET(CNV_MODE, CNV_FRAME_CAPTURE_EN, &cnv_frame_capture_en); + + return ((wb_enabled != 0) && (cnv_frame_capture_en != 0)); +} + +void dwb2_set_stereo(struct dwbc *dwbc, + struct dwb_stereo_params *stereo_params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d, enabled =%d", __func__,\ + dwbc20->base.inst, stereo_params->stereo_enabled); + + if (stereo_params->stereo_enabled) { + REG_UPDATE(CNV_MODE, CNV_STEREO_TYPE, stereo_params->stereo_type); + REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION, stereo_params->stereo_eye_select); + REG_UPDATE(CNV_MODE, CNV_STEREO_POLARITY, stereo_params->stereo_polarity); + } else { + REG_UPDATE(CNV_MODE, CNV_EYE_SELECTION, 0); + } +} + +void dwb2_set_new_content(struct dwbc *dwbc, + bool is_new_content) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); + + REG_UPDATE(CNV_MODE, CNV_NEW_CONTENT, is_new_content); +} + +static void dwb2_set_warmup(struct dwbc *dwbc, + struct dwb_warmup_params *warmup_params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); + + REG_UPDATE(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, warmup_params->warmup_en); + REG_UPDATE(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, warmup_params->warmup_width); + REG_UPDATE(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, warmup_params->warmup_height); + + REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, warmup_params->warmup_data); + REG_UPDATE(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, warmup_params->warmup_mode); + REG_UPDATE(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, warmup_params->warmup_depth); +} + +void dwb2_set_scaler(struct dwbc *dwbc, struct dc_dwb_params *params) +{ + struct dcn20_dwbc *dwbc20 = TO_DCN20_DWBC(dwbc); + DC_LOG_DWB("%s inst = %d", __func__, dwbc20->base.inst); + + /* Program scaling mode */ + REG_UPDATE_2(WBSCL_MODE, WBSCL_MODE, params->out_format, + WBSCL_OUT_BIT_DEPTH, params->output_depth); + + if (params->out_format != dwb_scaler_mode_bypass444) { + /* Program output size */ + REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH, params->dest_width); + REG_UPDATE(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT, params->dest_height); + + /* Program round offsets */ + REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, 0x40); + REG_UPDATE(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR, 0x200); + + /* Program clamp values */ + REG_UPDATE(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_UPPER_Y_RGB, 0x3fe); + REG_UPDATE(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_LOWER_Y_RGB, 0x1); + REG_UPDATE(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_UPPER_CBCR, 0x3fe); + REG_UPDATE(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_LOWER_CBCR, 0x1); + + /* Program outside pixel strategy to use edge pixels */ + REG_UPDATE(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, DWB_OUTSIDE_PIX_STRATEGY_EDGE); + + if (params->cnv_params.crop_en) { + /* horizontal scale */ + dwb_program_horz_scalar(dwbc20, params->cnv_params.crop_width, + params->dest_width, + params->scaler_taps); + + /* vertical scale */ + dwb_program_vert_scalar(dwbc20, params->cnv_params.crop_height, + params->dest_height, + params->scaler_taps, + params->subsample_position); + } else { + /* horizontal scale */ + dwb_program_horz_scalar(dwbc20, params->cnv_params.src_width, + params->dest_width, + params->scaler_taps); + + /* vertical scale */ + dwb_program_vert_scalar(dwbc20, params->cnv_params.src_height, + params->dest_height, + params->scaler_taps, + params->subsample_position); + } + } + +} + +const struct dwbc_funcs dcn20_dwbc_funcs = { + .get_caps = dwb2_get_caps, + .enable = dwb2_enable, + .disable = dwb2_disable, + .update = dwb2_update, + .is_enabled = dwb2_is_enabled, + .set_stereo = dwb2_set_stereo, + .set_new_content = dwb2_set_new_content, + .set_warmup = dwb2_set_warmup, + .dwb_set_scaler = dwb2_set_scaler, +}; + +void dcn20_dwbc_construct(struct dcn20_dwbc *dwbc20, + struct dc_context *ctx, + const struct dcn20_dwbc_registers *dwbc_regs, + const struct dcn20_dwbc_shift *dwbc_shift, + const struct dcn20_dwbc_mask *dwbc_mask, + int inst) +{ + dwbc20->base.ctx = ctx; + + dwbc20->base.inst = inst; + dwbc20->base.funcs = &dcn20_dwbc_funcs; + + dwbc20->dwbc_regs = dwbc_regs; + dwbc20->dwbc_shift = dwbc_shift; + dwbc20->dwbc_mask = dwbc_mask; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h new file mode 100644 index 000000000000..a85ed228dfc2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb.h @@ -0,0 +1,458 @@ +/* Copyright 2012-17 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 __DC_DWBC_DCN20_H__ +#define __DC_DWBC_DCN20_H__ + +#define TO_DCN20_DWBC(dwbc_base) \ + container_of(dwbc_base, struct dcn20_dwbc, base) + +/* DCN */ +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#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 + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + + +#define DWBC_COMMON_REG_LIST_DCN2_0(inst) \ + SRI2(WB_ENABLE, CNV, inst),\ + SRI2(WB_EC_CONFIG, CNV, inst),\ + SRI2(CNV_MODE, CNV, inst),\ + SRI2(CNV_WINDOW_START, CNV, inst),\ + SRI2(CNV_WINDOW_SIZE, CNV, inst),\ + SRI2(CNV_UPDATE, CNV, inst),\ + SRI2(CNV_SOURCE_SIZE, CNV, inst),\ + SRI2(CNV_TEST_CNTL, CNV, inst),\ + SRI2(CNV_TEST_CRC_RED, CNV, inst),\ + SRI2(CNV_TEST_CRC_GREEN, CNV, inst),\ + SRI2(CNV_TEST_CRC_BLUE, CNV, inst),\ + SRI2(WBSCL_COEF_RAM_SELECT, WBSCL, inst),\ + SRI2(WBSCL_COEF_RAM_TAP_DATA, WBSCL, inst),\ + SRI2(WBSCL_MODE, WBSCL, inst),\ + SRI2(WBSCL_TAP_CONTROL, WBSCL, inst),\ + SRI2(WBSCL_DEST_SIZE, WBSCL, inst),\ + SRI2(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL, inst),\ + SRI2(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL, inst),\ + SRI2(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL, inst),\ + SRI2(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL, inst),\ + SRI2(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL, inst),\ + SRI2(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL, inst),\ + SRI2(WBSCL_ROUND_OFFSET, WBSCL, inst),\ + SRI2(WBSCL_OVERFLOW_STATUS, WBSCL, inst),\ + SRI2(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL, inst),\ + SRI2(WBSCL_TEST_CNTL, WBSCL, inst),\ + SRI2(WBSCL_TEST_CRC_RED, WBSCL, inst),\ + SRI2(WBSCL_TEST_CRC_GREEN, WBSCL, inst),\ + SRI2(WBSCL_TEST_CRC_BLUE, WBSCL, inst),\ + SRI2(WBSCL_BACKPRESSURE_CNT_EN, WBSCL, inst),\ + SRI2(WB_MCIF_BACKPRESSURE_CNT, WBSCL, inst),\ + SRI2(WBSCL_CLAMP_Y_RGB, WBSCL, inst),\ + SRI2(WBSCL_CLAMP_CBCR, WBSCL, inst),\ + SRI2(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL, inst),\ + SRI2(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL, inst),\ + SRI2(WBSCL_DEBUG, WBSCL, inst),\ + SRI2(WBSCL_TEST_DEBUG_INDEX, WBSCL, inst),\ + SRI2(WBSCL_TEST_DEBUG_DATA, WBSCL, inst),\ + SRI2(WB_DEBUG_CTRL, CNV, inst),\ + SRI2(WB_DBG_MODE, CNV, inst),\ + SRI2(WB_HW_DEBUG, CNV, inst),\ + SRI2(CNV_TEST_DEBUG_INDEX, CNV, inst),\ + SRI2(CNV_TEST_DEBUG_DATA, CNV, inst),\ + SRI2(WB_SOFT_RESET, CNV, inst),\ + SRI2(WB_WARM_UP_MODE_CTL1, CNV, inst),\ + SRI2(WB_WARM_UP_MODE_CTL2, CNV, inst) + +#define DWBC_COMMON_MASK_SH_LIST_DCN2_0(mask_sh) \ + SF(WB_ENABLE, WB_ENABLE, mask_sh),\ + SF(WB_EC_CONFIG, DISPCLK_R_WB_GATE_DIS, mask_sh),\ + SF(WB_EC_CONFIG, DISPCLK_G_WB_GATE_DIS, mask_sh),\ + SF(WB_EC_CONFIG, DISPCLK_G_WBSCL_GATE_DIS, mask_sh),\ + SF(WB_EC_CONFIG, WB_TEST_CLK_SEL, mask_sh),\ + SF(WB_EC_CONFIG, WB_LB_LS_DIS, mask_sh),\ + SF(WB_EC_CONFIG, WB_LB_SD_DIS, mask_sh),\ + SF(WB_EC_CONFIG, WB_LUT_LS_DIS, mask_sh),\ + SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_MODE_SEL, mask_sh),\ + SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_DIS, mask_sh),\ + SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_FORCE, mask_sh),\ + SF(WB_EC_CONFIG, WBSCL_LB_MEM_PWR_STATE, mask_sh),\ + SF(WB_EC_CONFIG, WB_RAM_PW_SAVE_MODE, mask_sh),\ + SF(WB_EC_CONFIG, WBSCL_LUT_MEM_PWR_STATE, mask_sh),\ + SF(CNV_MODE, CNV_OUT_BPC, mask_sh),\ + SF(CNV_MODE, CNV_FRAME_CAPTURE_RATE, mask_sh),\ + SF(CNV_MODE, CNV_WINDOW_CROP_EN, mask_sh),\ + SF(CNV_MODE, CNV_STEREO_TYPE, mask_sh),\ + SF(CNV_MODE, CNV_INTERLACED_MODE, mask_sh),\ + SF(CNV_MODE, CNV_EYE_SELECTION, mask_sh),\ + SF(CNV_MODE, CNV_STEREO_POLARITY, mask_sh),\ + SF(CNV_MODE, CNV_INTERLACED_FIELD_ORDER, mask_sh),\ + SF(CNV_MODE, CNV_STEREO_SPLIT, mask_sh),\ + SF(CNV_MODE, CNV_NEW_CONTENT, mask_sh),\ + SF(CNV_MODE, CNV_FRAME_CAPTURE_EN_CURRENT, mask_sh),\ + SF(CNV_MODE, CNV_FRAME_CAPTURE_EN, mask_sh),\ + SF(CNV_WINDOW_START, CNV_WINDOW_START_X, mask_sh),\ + SF(CNV_WINDOW_START, CNV_WINDOW_START_Y, mask_sh),\ + SF(CNV_WINDOW_SIZE, CNV_WINDOW_WIDTH, mask_sh),\ + SF(CNV_WINDOW_SIZE, CNV_WINDOW_HEIGHT, mask_sh),\ + SF(CNV_UPDATE, CNV_UPDATE_PENDING, mask_sh),\ + SF(CNV_UPDATE, CNV_UPDATE_TAKEN, mask_sh),\ + SF(CNV_UPDATE, CNV_UPDATE_LOCK, mask_sh),\ + SF(CNV_SOURCE_SIZE, CNV_SOURCE_WIDTH, mask_sh),\ + SF(CNV_SOURCE_SIZE, CNV_SOURCE_HEIGHT, mask_sh),\ + SF(CNV_TEST_CNTL, CNV_TEST_CRC_EN, mask_sh),\ + SF(CNV_TEST_CNTL, CNV_TEST_CRC_CONT_EN, mask_sh),\ + SF(CNV_TEST_CRC_RED, CNV_TEST_CRC_RED_MASK, mask_sh),\ + SF(CNV_TEST_CRC_RED, CNV_TEST_CRC_SIG_RED, mask_sh),\ + SF(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_GREEN_MASK, mask_sh),\ + SF(CNV_TEST_CRC_GREEN, CNV_TEST_CRC_SIG_GREEN, mask_sh),\ + SF(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_BLUE_MASK, mask_sh),\ + SF(CNV_TEST_CRC_BLUE, CNV_TEST_CRC_SIG_BLUE, mask_sh),\ + SF(WB_DEBUG_CTRL, WB_DEBUG_EN, mask_sh),\ + SF(WB_DEBUG_CTRL, WB_DEBUG_SEL, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_MODE_EN, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_DIN_FMT, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_36MODE, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_CMAP, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_PXLRATE_ERROR, mask_sh),\ + SF(WB_DBG_MODE, WB_DBG_SOURCE_WIDTH, mask_sh),\ + SF(WB_HW_DEBUG, WB_HW_DEBUG, mask_sh),\ + SF(WB_SOFT_RESET, WB_SOFT_RESET, mask_sh),\ + SF(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_INDEX, mask_sh),\ + SF(CNV_TEST_DEBUG_INDEX, CNV_TEST_DEBUG_WRITE_EN, mask_sh),\ + SF(CNV_TEST_DEBUG_DATA, CNV_TEST_DEBUG_DATA, mask_sh),\ + SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_TAP_PAIR_IDX, mask_sh),\ + SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_PHASE, mask_sh),\ + SF(WBSCL_COEF_RAM_SELECT, WBSCL_COEF_RAM_FILTER_TYPE, mask_sh),\ + SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF, mask_sh),\ + SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_EVEN_TAP_COEF_EN, mask_sh),\ + SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF, mask_sh),\ + SF(WBSCL_COEF_RAM_TAP_DATA, WBSCL_COEF_RAM_ODD_TAP_COEF_EN, mask_sh),\ + SF(WBSCL_MODE, WBSCL_MODE, mask_sh),\ + SF(WBSCL_MODE, WBSCL_OUT_BIT_DEPTH, mask_sh),\ + SF(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_Y_RGB, mask_sh),\ + SF(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_CBCR, mask_sh),\ + SF(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_Y_RGB, mask_sh),\ + SF(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_CBCR, mask_sh),\ + SF(WBSCL_DEST_SIZE, WBSCL_DEST_HEIGHT, mask_sh),\ + SF(WBSCL_DEST_SIZE, WBSCL_DEST_WIDTH, mask_sh),\ + SF(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL_H_SCALE_RATIO, mask_sh),\ + SF(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_FRAC_Y_RGB, mask_sh),\ + SF(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_INT_Y_RGB, mask_sh),\ + SF(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_FRAC_CBCR, mask_sh),\ + SF(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_INT_CBCR, mask_sh),\ + SF(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL_V_SCALE_RATIO, mask_sh),\ + SF(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_FRAC_Y_RGB, mask_sh),\ + SF(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_INT_Y_RGB, mask_sh),\ + SF(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_FRAC_CBCR, mask_sh),\ + SF(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_INT_CBCR, mask_sh),\ + SF(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_Y_RGB, mask_sh),\ + SF(WBSCL_ROUND_OFFSET, WBSCL_ROUND_OFFSET_CBCR, mask_sh),\ + SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_FLAG, mask_sh),\ + SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_ACK, mask_sh),\ + SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_MASK, mask_sh),\ + SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_STATUS, mask_sh),\ + SF(WBSCL_OVERFLOW_STATUS, WBSCL_DATA_OVERFLOW_INT_TYPE, mask_sh),\ + SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_FLAG, mask_sh),\ + SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_ACK, mask_sh),\ + SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_MASK, mask_sh),\ + SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_STATUS, mask_sh),\ + SF(WBSCL_COEF_RAM_CONFLICT_STATUS, WBSCL_HOST_CONFLICT_INT_TYPE, mask_sh),\ + SF(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_EN, mask_sh),\ + SF(WBSCL_TEST_CNTL, WBSCL_TEST_CRC_CONT_EN, mask_sh),\ + SF(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_RED_MASK, mask_sh),\ + SF(WBSCL_TEST_CRC_RED, WBSCL_TEST_CRC_SIG_RED, mask_sh),\ + SF(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_GREEN_MASK, mask_sh),\ + SF(WBSCL_TEST_CRC_GREEN, WBSCL_TEST_CRC_SIG_GREEN, mask_sh),\ + SF(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_BLUE_MASK, mask_sh),\ + SF(WBSCL_TEST_CRC_BLUE, WBSCL_TEST_CRC_SIG_BLUE, mask_sh),\ + SF(WBSCL_BACKPRESSURE_CNT_EN, WBSCL_BACKPRESSURE_CNT_EN, mask_sh),\ + SF(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_Y_MAX_BACKPRESSURE, mask_sh),\ + SF(WB_MCIF_BACKPRESSURE_CNT, WB_MCIF_C_MAX_BACKPRESSURE, mask_sh),\ + SF(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_UPPER_Y_RGB, mask_sh),\ + SF(WBSCL_CLAMP_Y_RGB, WBSCL_CLAMP_LOWER_Y_RGB, mask_sh),\ + SF(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_UPPER_CBCR, mask_sh),\ + SF(WBSCL_CLAMP_CBCR, WBSCL_CLAMP_LOWER_CBCR, mask_sh),\ + SF(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_OUTSIDE_PIX_STRATEGY, mask_sh),\ + SF(WBSCL_OUTSIDE_PIX_STRATEGY, WBSCL_BLACK_COLOR_G_Y, mask_sh),\ + SF(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_B_CB, mask_sh),\ + SF(WBSCL_OUTSIDE_PIX_STRATEGY_CBCR, WBSCL_BLACK_COLOR_R_CR, mask_sh),\ + SF(WBSCL_DEBUG, WBSCL_DEBUG, mask_sh),\ + SF(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_INDEX, mask_sh),\ + SF(WBSCL_TEST_DEBUG_INDEX, WBSCL_TEST_DEBUG_WRITE_EN, mask_sh),\ + SF(WBSCL_TEST_DEBUG_DATA, WBSCL_TEST_DEBUG_DATA, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL1, WIDTH_WARMUP, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL1, HEIGHT_WARMUP, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL1, GMC_WARM_UP_ENABLE, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL2, DATA_VALUE_WARMUP, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL2, MODE_WARMUP, mask_sh),\ + SF(WB_WARM_UP_MODE_CTL2, DATA_DEPTH_WARMUP, mask_sh) + +#define DWBC_REG_FIELD_LIST_DCN2_0(type) \ + type WB_ENABLE;\ + type DISPCLK_R_WB_GATE_DIS;\ + type DISPCLK_G_WB_GATE_DIS;\ + type DISPCLK_G_WBSCL_GATE_DIS;\ + type WB_TEST_CLK_SEL;\ + type WB_LB_LS_DIS;\ + type WB_LB_SD_DIS;\ + type WB_LUT_LS_DIS;\ + type WBSCL_LB_MEM_PWR_MODE_SEL;\ + type WBSCL_LB_MEM_PWR_DIS;\ + type WBSCL_LB_MEM_PWR_FORCE;\ + type WBSCL_LB_MEM_PWR_STATE;\ + type WB_RAM_PW_SAVE_MODE;\ + type WBSCL_LUT_MEM_PWR_STATE;\ + type CNV_OUT_BPC;\ + type CNV_FRAME_CAPTURE_RATE;\ + type CNV_WINDOW_CROP_EN;\ + type CNV_STEREO_TYPE;\ + type CNV_INTERLACED_MODE;\ + type CNV_EYE_SELECTION;\ + type CNV_STEREO_POLARITY;\ + type CNV_INTERLACED_FIELD_ORDER;\ + type CNV_STEREO_SPLIT;\ + type CNV_NEW_CONTENT;\ + type CNV_FRAME_CAPTURE_EN_CURRENT;\ + type CNV_FRAME_CAPTURE_EN;\ + type CNV_WINDOW_START_X;\ + type CNV_WINDOW_START_Y;\ + type CNV_WINDOW_WIDTH;\ + type CNV_WINDOW_HEIGHT;\ + type CNV_UPDATE_PENDING;\ + type CNV_UPDATE_TAKEN;\ + type CNV_UPDATE_LOCK;\ + type CNV_SOURCE_WIDTH;\ + type CNV_SOURCE_HEIGHT;\ + type CNV_TEST_CRC_EN;\ + type CNV_TEST_CRC_CONT_EN;\ + type CNV_TEST_CRC_RED_MASK;\ + type CNV_TEST_CRC_SIG_RED;\ + type CNV_TEST_CRC_GREEN_MASK;\ + type CNV_TEST_CRC_SIG_GREEN;\ + type CNV_TEST_CRC_BLUE_MASK;\ + type CNV_TEST_CRC_SIG_BLUE;\ + type WB_DEBUG_EN;\ + type WB_DEBUG_SEL;\ + type WB_DBG_MODE_EN;\ + type WB_DBG_DIN_FMT;\ + type WB_DBG_36MODE;\ + type WB_DBG_CMAP;\ + type WB_DBG_PXLRATE_ERROR;\ + type WB_DBG_SOURCE_WIDTH;\ + type WB_HW_DEBUG;\ + type CNV_TEST_DEBUG_INDEX;\ + type CNV_TEST_DEBUG_WRITE_EN;\ + type CNV_TEST_DEBUG_DATA;\ + type WB_SOFT_RESET;\ + type WBSCL_COEF_RAM_TAP_PAIR_IDX;\ + type WBSCL_COEF_RAM_PHASE;\ + type WBSCL_COEF_RAM_FILTER_TYPE;\ + type WBSCL_COEF_RAM_SEL;\ + type WBSCL_COEF_RAM_SEL_CURRENT;\ + type WBSCL_COEF_RAM_RD_SEL;\ + type WBSCL_COEF_RAM_EVEN_TAP_COEF;\ + type WBSCL_COEF_RAM_EVEN_TAP_COEF_EN;\ + type WBSCL_COEF_RAM_ODD_TAP_COEF;\ + type WBSCL_COEF_RAM_ODD_TAP_COEF_EN;\ + type WBSCL_MODE;\ + type WBSCL_OUT_BIT_DEPTH;\ + type WBSCL_V_NUM_OF_TAPS_Y_RGB;\ + type WBSCL_V_NUM_OF_TAPS_CBCR;\ + type WBSCL_H_NUM_OF_TAPS_Y_RGB;\ + type WBSCL_H_NUM_OF_TAPS_CBCR;\ + type WBSCL_DEST_HEIGHT;\ + type WBSCL_DEST_WIDTH;\ + type WBSCL_H_SCALE_RATIO;\ + type WBSCL_H_INIT_FRAC_Y_RGB;\ + type WBSCL_H_INIT_INT_Y_RGB;\ + type WBSCL_H_INIT_FRAC_CBCR;\ + type WBSCL_H_INIT_INT_CBCR;\ + type WBSCL_V_SCALE_RATIO;\ + type WBSCL_V_INIT_FRAC_Y_RGB;\ + type WBSCL_V_INIT_INT_Y_RGB;\ + type WBSCL_V_INIT_FRAC_CBCR;\ + type WBSCL_V_INIT_INT_CBCR;\ + type WBSCL_ROUND_OFFSET_Y_RGB;\ + type WBSCL_ROUND_OFFSET_CBCR;\ + type WBSCL_DATA_OVERFLOW_FLAG;\ + type WBSCL_DATA_OVERFLOW_ACK;\ + type WBSCL_DATA_OVERFLOW_MASK;\ + type WBSCL_DATA_OVERFLOW_INT_STATUS;\ + type WBSCL_DATA_OVERFLOW_INT_TYPE;\ + type WBSCL_HOST_CONFLICT_FLAG;\ + type WBSCL_HOST_CONFLICT_ACK;\ + type WBSCL_HOST_CONFLICT_MASK;\ + type WBSCL_HOST_CONFLICT_INT_STATUS;\ + type WBSCL_HOST_CONFLICT_INT_TYPE;\ + type WBSCL_TEST_CRC_EN;\ + type WBSCL_TEST_CRC_CONT_EN;\ + type WBSCL_TEST_CRC_RED_MASK;\ + type WBSCL_TEST_CRC_SIG_RED;\ + type WBSCL_TEST_CRC_GREEN_MASK;\ + type WBSCL_TEST_CRC_SIG_GREEN;\ + type WBSCL_TEST_CRC_BLUE_MASK;\ + type WBSCL_TEST_CRC_SIG_BLUE;\ + type WBSCL_BACKPRESSURE_CNT_EN;\ + type WB_MCIF_Y_MAX_BACKPRESSURE;\ + type WB_MCIF_C_MAX_BACKPRESSURE;\ + type WBSCL_CLAMP_UPPER_Y_RGB;\ + type WBSCL_CLAMP_LOWER_Y_RGB;\ + type WBSCL_CLAMP_UPPER_CBCR;\ + type WBSCL_CLAMP_LOWER_CBCR;\ + type WBSCL_OUTSIDE_PIX_STRATEGY;\ + type WBSCL_BLACK_COLOR_G_Y;\ + type WBSCL_BLACK_COLOR_B_CB;\ + type WBSCL_BLACK_COLOR_R_CR;\ + type WBSCL_DEBUG;\ + type WBSCL_TEST_DEBUG_INDEX;\ + type WBSCL_TEST_DEBUG_WRITE_EN;\ + type WBSCL_TEST_DEBUG_DATA;\ + type WIDTH_WARMUP;\ + type HEIGHT_WARMUP;\ + type GMC_WARM_UP_ENABLE;\ + type DATA_VALUE_WARMUP;\ + type MODE_WARMUP;\ + type DATA_DEPTH_WARMUP; \ + +struct dcn20_dwbc_registers { + /* DCN2.0 */ + uint32_t WB_ENABLE; + uint32_t WB_EC_CONFIG; + uint32_t CNV_MODE; + uint32_t CNV_WINDOW_START; + uint32_t CNV_WINDOW_SIZE; + uint32_t CNV_UPDATE; + uint32_t CNV_SOURCE_SIZE; + uint32_t CNV_TEST_CNTL; + uint32_t CNV_TEST_CRC_RED; + uint32_t CNV_TEST_CRC_GREEN; + uint32_t CNV_TEST_CRC_BLUE; + uint32_t WB_DEBUG_CTRL; + uint32_t WB_DBG_MODE; + uint32_t WB_HW_DEBUG; + uint32_t CNV_TEST_DEBUG_INDEX; + uint32_t CNV_TEST_DEBUG_DATA; + uint32_t WB_SOFT_RESET; + uint32_t WBSCL_COEF_RAM_SELECT; + uint32_t WBSCL_COEF_RAM_TAP_DATA; + uint32_t WBSCL_MODE; + uint32_t WBSCL_TAP_CONTROL; + uint32_t WBSCL_DEST_SIZE; + uint32_t WBSCL_HORZ_FILTER_SCALE_RATIO; + uint32_t WBSCL_HORZ_FILTER_INIT_Y_RGB; + uint32_t WBSCL_HORZ_FILTER_INIT_CBCR; + uint32_t WBSCL_VERT_FILTER_SCALE_RATIO; + uint32_t WBSCL_VERT_FILTER_INIT_Y_RGB; + uint32_t WBSCL_VERT_FILTER_INIT_CBCR; + uint32_t WBSCL_ROUND_OFFSET; + uint32_t WBSCL_OVERFLOW_STATUS; + uint32_t WBSCL_COEF_RAM_CONFLICT_STATUS; + uint32_t WBSCL_TEST_CNTL; + uint32_t WBSCL_TEST_CRC_RED; + uint32_t WBSCL_TEST_CRC_GREEN; + uint32_t WBSCL_TEST_CRC_BLUE; + uint32_t WBSCL_BACKPRESSURE_CNT_EN; + uint32_t WB_MCIF_BACKPRESSURE_CNT; + uint32_t WBSCL_CLAMP_Y_RGB; + uint32_t WBSCL_CLAMP_CBCR; + uint32_t WBSCL_OUTSIDE_PIX_STRATEGY; + uint32_t WBSCL_OUTSIDE_PIX_STRATEGY_CBCR; + uint32_t WBSCL_DEBUG; + uint32_t WBSCL_TEST_DEBUG_INDEX; + uint32_t WBSCL_TEST_DEBUG_DATA; + uint32_t WB_WARM_UP_MODE_CTL1; + uint32_t WB_WARM_UP_MODE_CTL2; +}; + + +struct dcn20_dwbc_mask { + DWBC_REG_FIELD_LIST_DCN2_0(uint32_t) +}; + +struct dcn20_dwbc_shift { + DWBC_REG_FIELD_LIST_DCN2_0(uint8_t) +}; + +struct dcn20_dwbc { + struct dwbc base; + const struct dcn20_dwbc_registers *dwbc_regs; + const struct dcn20_dwbc_shift *dwbc_shift; + const struct dcn20_dwbc_mask *dwbc_mask; +}; + +void dcn20_dwbc_construct(struct dcn20_dwbc *dwbc20, + struct dc_context *ctx, + const struct dcn20_dwbc_registers *dwbc_regs, + const struct dcn20_dwbc_shift *dwbc_shift, + const struct dcn20_dwbc_mask *dwbc_mask, + int inst); + +bool dwb2_disable(struct dwbc *dwbc); + +bool dwb2_is_enabled(struct dwbc *dwbc); + +void dwb2_set_stereo(struct dwbc *dwbc, + struct dwb_stereo_params *stereo_params); + +void dwb2_set_new_content(struct dwbc *dwbc, + bool is_new_content); + +void dwb2_config_dwb_cnv(struct dwbc *dwbc, + struct dc_dwb_params *params); + +void dwb2_set_scaler(struct dwbc *dwbc, struct dc_dwb_params *params); + +bool dwb_program_vert_scalar(struct dcn20_dwbc *dwbc20, + uint32_t src_height, + uint32_t dest_height, + struct scaling_taps num_taps, + enum dwb_subsample_position subsample_position); + +bool dwb_program_horz_scalar(struct dcn20_dwbc *dwbc20, + uint32_t src_width, + uint32_t dest_width, + struct scaling_taps num_taps); + + +#endif + + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c new file mode 100644 index 000000000000..cd8bc92ce3ba --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dwb_scl.c @@ -0,0 +1,877 @@ +/* + * Copyright 2012-17 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 "reg_helper.h" +#include "fixed31_32.h" +#include "resource.h" +#include "dwb.h" +#include "dcn20_dwb.h" + +#define NUM_PHASES 16 +#define HORZ_MAX_TAPS 12 +#define VERT_MAX_TAPS 12 + +#define REG(reg)\ + dwbc20->dwbc_regs->reg + +#define CTX \ + dwbc20->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dwbc20->dwbc_shift->field_name, dwbc20->dwbc_mask->field_name + +#define TO_DCN20_DWBC(dwbc_base) \ + container_of(dwbc_base, struct dcn20_dwbc, base) + + +static const uint16_t filter_3tap_16p_upscale[27] = { + 2048, 2048, 0, + 1708, 2424, 16348, + 1372, 2796, 16308, + 1056, 3148, 16272, + 768, 3464, 16244, + 512, 3728, 16236, + 296, 3928, 16252, + 124, 4052, 16296, + 0, 4096, 0 +}; + +static const uint16_t filter_3tap_16p_117[27] = { + 2048, 2048, 0, + 1824, 2276, 16376, + 1600, 2496, 16380, + 1376, 2700, 16, + 1156, 2880, 52, + 948, 3032, 108, + 756, 3144, 192, + 580, 3212, 296, + 428, 3236, 428 +}; + +static const uint16_t filter_3tap_16p_150[27] = { + 2048, 2048, 0, + 1872, 2184, 36, + 1692, 2308, 88, + 1516, 2420, 156, + 1340, 2516, 236, + 1168, 2592, 328, + 1004, 2648, 440, + 844, 2684, 560, + 696, 2696, 696 +}; + +static const uint16_t filter_3tap_16p_183[27] = { + 2048, 2048, 0, + 1892, 2104, 92, + 1744, 2152, 196, + 1592, 2196, 300, + 1448, 2232, 412, + 1304, 2256, 528, + 1168, 2276, 648, + 1032, 2288, 772, + 900, 2292, 900 +}; + +static const uint16_t filter_4tap_16p_upscale[36] = { + 0, 4096, 0, 0, + 16240, 4056, 180, 16380, + 16136, 3952, 404, 16364, + 16072, 3780, 664, 16344, + 16040, 3556, 952, 16312, + 16036, 3284, 1268, 16272, + 16052, 2980, 1604, 16224, + 16084, 2648, 1952, 16176, + 16128, 2304, 2304, 16128 +}; + +static const uint16_t filter_4tap_16p_117[36] = { + 428, 3236, 428, 0, + 276, 3232, 604, 16364, + 148, 3184, 800, 16340, + 44, 3104, 1016, 16312, + 16344, 2984, 1244, 16284, + 16284, 2832, 1488, 16256, + 16244, 2648, 1732, 16236, + 16220, 2440, 1976, 16220, + 16212, 2216, 2216, 16212 +}; + +static const uint16_t filter_4tap_16p_150[36] = { + 696, 2700, 696, 0, + 560, 2700, 848, 16364, + 436, 2676, 1008, 16348, + 328, 2628, 1180, 16336, + 232, 2556, 1356, 16328, + 152, 2460, 1536, 16328, + 84, 2344, 1716, 16332, + 28, 2208, 1888, 16348, + 16376, 2052, 2052, 16376 +}; + +static const uint16_t filter_4tap_16p_183[36] = { + 940, 2208, 940, 0, + 832, 2200, 1052, 4, + 728, 2180, 1164, 16, + 628, 2148, 1280, 36, + 536, 2100, 1392, 60, + 448, 2044, 1504, 92, + 368, 1976, 1612, 132, + 296, 1900, 1716, 176, + 232, 1812, 1812, 232 +}; + +static const uint16_t filter_5tap_16p_upscale[45] = { + 15936, 2496, 2496, 15936, 0, + 15992, 2128, 2832, 15896, 12, + 16056, 1760, 3140, 15876, 24, + 16120, 1404, 3420, 15876, 36, + 16188, 1060, 3652, 15908, 44, + 16248, 744, 3844, 15972, 44, + 16304, 460, 3980, 16072, 40, + 16348, 212, 4064, 16208, 24, + 0, 0, 4096, 0, 0, +}; + +static const uint16_t filter_5tap_16p_117[45] = { + 16056, 2372, 2372, 16056, 0, + 16052, 2124, 2600, 16076, 0, + 16060, 1868, 2808, 16120, 0, + 16080, 1612, 2992, 16180, 16376, + 16112, 1356, 3144, 16268, 16364, + 16144, 1108, 3268, 16376, 16344, + 16184, 872, 3356, 124, 16320, + 16220, 656, 3412, 276, 16292, + 16256, 456, 3428, 456, 16256, +}; + +static const uint16_t filter_5tap_16p_150[45] = { + 16368, 2064, 2064, 16368, 0, + 16316, 1924, 2204, 44, 16372, + 16280, 1772, 2328, 116, 16356, + 16256, 1616, 2440, 204, 16340, + 16240, 1456, 2536, 304, 16320, + 16232, 1296, 2612, 416, 16300, + 16232, 1132, 2664, 544, 16284, + 16240, 976, 2700, 680, 16264, + 16248, 824, 2708, 824, 16248, +}; + +static const uint16_t filter_5tap_16p_183[45] = { + 228, 1816, 1816, 228, 0, + 168, 1728, 1904, 300, 16372, + 116, 1632, 1988, 376, 16360, + 72, 1528, 2060, 460, 16348, + 36, 1424, 2120, 552, 16340, + 4, 1312, 2168, 652, 16336, + 16368, 1200, 2204, 752, 16332, + 16352, 1084, 2224, 860, 16332, + 16340, 972, 2232, 972, 16340, +}; + +static const uint16_t filter_6tap_16p_upscale[54] = { + 0, 0, 4092, 0, 0, 0, + 44, 16188, 4064, 228, 16324, 0, + 80, 16036, 3980, 492, 16256, 4, + 108, 15916, 3844, 788, 16184, 16, + 120, 15836, 3656, 1108, 16104, 28, + 128, 15792, 3420, 1448, 16024, 44, + 124, 15776, 3144, 1800, 15948, 64, + 112, 15792, 2836, 2152, 15880, 80, + 100, 15828, 2504, 2504, 15828, 100, +}; + +static const uint16_t filter_6tap_16p_117[54] = { + 16168, 476, 3568, 476, 16168, 0, + 16216, 280, 3540, 692, 16116, 8, + 16264, 104, 3472, 924, 16068, 16, + 16304, 16340, 3372, 1168, 16024, 28, + 16344, 16212, 3236, 1424, 15988, 36, + 16372, 16112, 3072, 1680, 15956, 44, + 12, 16036, 2880, 1936, 15940, 48, + 28, 15984, 2668, 2192, 15936, 48, + 40, 15952, 2436, 2436, 15952, 40, +}; + +static const uint16_t filter_6tap_16p_150[54] = { + 16148, 920, 2724, 920, 16148, 0, + 16156, 768, 2712, 1072, 16144, 0, + 16172, 628, 2684, 1232, 16148, 16380, + 16192, 492, 2632, 1388, 16160, 16372, + 16212, 368, 2564, 1548, 16180, 16364, + 16232, 256, 2480, 1704, 16212, 16352, + 16256, 156, 2380, 1856, 16256, 16336, + 16276, 64, 2268, 2004, 16308, 16320, + 16300, 16372, 2140, 2140, 16372, 16300, +}; + +static const uint16_t filter_6tap_16p_183[54] = { + 16296, 1032, 2196, 1032, 16296, 0, + 16284, 924, 2196, 1144, 16320, 16376, + 16272, 820, 2180, 1256, 16348, 16364, + 16268, 716, 2156, 1364, 16380, 16352, + 16264, 620, 2116, 1472, 36, 16340, + 16268, 524, 2068, 1576, 88, 16328, + 16272, 436, 2008, 1680, 144, 16316, + 16280, 352, 1940, 1772, 204, 16304, + 16292, 276, 1860, 1860, 276, 16292, +}; + +static const uint16_t filter_7tap_16p_upscale[63] = { + 176, 15760, 2488, 2488, 15760, 176, 0, + 160, 15812, 2152, 2816, 15728, 192, 16376, + 136, 15884, 1812, 3124, 15720, 196, 16368, + 108, 15964, 1468, 3400, 15740, 196, 16364, + 84, 16048, 1132, 3640, 15792, 180, 16360, + 56, 16140, 812, 3832, 15884, 152, 16360, + 32, 16228, 512, 3976, 16012, 116, 16364, + 12, 16308, 240, 4064, 16180, 60, 16372, + 0, 0, 0, 4096, 0, 0, 0, +}; + +static const uint16_t filter_7tap_16p_117[63] = { + 92, 15868, 2464, 2464, 15868, 92, 0, + 108, 15852, 2216, 2700, 15904, 72, 0, + 112, 15856, 1960, 2916, 15964, 44, 0, + 116, 15876, 1696, 3108, 16048, 8, 8, + 112, 15908, 1428, 3268, 16156, 16348, 12, + 104, 15952, 1168, 3400, 16288, 16300, 24, + 92, 16004, 916, 3496, 64, 16244, 36, + 80, 16064, 676, 3556, 248, 16184, 48, + 64, 16124, 452, 3576, 452, 16124, 64, +}; + +static const uint16_t filter_7tap_16p_150[63] = { + 16224, 16380, 2208, 2208, 16380, 16224, 0, + 16252, 16304, 2072, 2324, 84, 16196, 4, + 16276, 16240, 1924, 2432, 184, 16172, 8, + 16300, 16184, 1772, 2524, 296, 16144, 12, + 16324, 16144, 1616, 2600, 416, 16124, 12, + 16344, 16112, 1456, 2660, 548, 16104, 12, + 16360, 16092, 1296, 2704, 688, 16088, 12, + 16372, 16080, 1140, 2732, 832, 16080, 8, + 0, 16076, 984, 2740, 984, 16076, 0, +}; + +static const uint16_t filter_7tap_16p_183[63] = { + 16216, 324, 1884, 1884, 324, 16216, 0, + 16228, 248, 1804, 1960, 408, 16212, 16380, + 16240, 176, 1716, 2028, 496, 16208, 16376, + 16252, 112, 1624, 2084, 588, 16208, 16372, + 16264, 56, 1524, 2132, 684, 16212, 16364, + 16280, 4, 1424, 2168, 788, 16220, 16356, + 16292, 16344, 1320, 2196, 892, 16232, 16344, + 16308, 16308, 1212, 2212, 996, 16252, 16332, + 16320, 16276, 1104, 2216, 1104, 16276, 16320, +}; + +static const uint16_t filter_8tap_16p_upscale[72] = { + 0, 0, 0, 4096, 0, 0, 0, 0, + 16360, 76, 16172, 4064, 244, 16296, 24, 16380, + 16340, 136, 15996, 3980, 524, 16204, 56, 16380, + 16328, 188, 15860, 3844, 828, 16104, 92, 16372, + 16320, 224, 15760, 3656, 1156, 16008, 128, 16368, + 16320, 248, 15696, 3428, 1496, 15912, 160, 16360, + 16320, 256, 15668, 3156, 1844, 15828, 192, 16348, + 16324, 256, 15672, 2856, 2192, 15756, 220, 16340, + 16332, 244, 15704, 2532, 2532, 15704, 244, 16332, +}; + +static const uint16_t filter_8tap_16p_117[72] = { + 116, 16100, 428, 3564, 428, 16100, 116, 0, + 96, 16168, 220, 3548, 656, 16032, 136, 16376, + 76, 16236, 32, 3496, 904, 15968, 152, 16372, + 56, 16300, 16252, 3408, 1164, 15908, 164, 16368, + 36, 16360, 16116, 3284, 1428, 15856, 172, 16364, + 20, 28, 16000, 3124, 1700, 15820, 176, 16364, + 4, 76, 15912, 2940, 1972, 15800, 172, 16364, + 16380, 112, 15848, 2724, 2236, 15792, 160, 16364, + 16372, 140, 15812, 2488, 2488, 15812, 140, 16372, +}; + +static const uint16_t filter_8tap_16p_150[72] = { + 16380, 16020, 1032, 2756, 1032, 16020, 16380, 0, + 12, 16020, 876, 2744, 1184, 16032, 16364, 4, + 24, 16028, 728, 2716, 1344, 16052, 16340, 8, + 36, 16040, 584, 2668, 1500, 16080, 16316, 16, + 40, 16060, 448, 2608, 1652, 16120, 16288, 20, + 44, 16080, 320, 2528, 1804, 16168, 16260, 28, + 48, 16108, 204, 2436, 1948, 16232, 16228, 32, + 44, 16136, 100, 2328, 2084, 16304, 16200, 40, + 44, 16168, 4, 2212, 2212, 4, 16168, 44, +}; + +static const uint16_t filter_8tap_16p_183[72] = { + 16264, 16264, 1164, 2244, 1164, 16264, 16264, 0, + 16280, 16232, 1056, 2236, 1268, 16300, 16248, 0, + 16296, 16204, 948, 2220, 1372, 16348, 16232, 0, + 16312, 16184, 844, 2192, 1472, 12, 16216, 4, + 16328, 16172, 740, 2156, 1572, 72, 16200, 0, + 16340, 16160, 640, 2108, 1668, 136, 16188, 0, + 16352, 16156, 544, 2052, 1756, 204, 16176, 16380, + 16360, 16156, 452, 1988, 1840, 280, 16164, 16376, + 16368, 16160, 364, 1920, 1920, 364, 16160, 16368, +}; + +static const uint16_t filter_9tap_16p_upscale[81] = { + 16284, 296, 15660, 2572, 2572, 15660, 296, 16284, 0, + 16296, 272, 15712, 2228, 2896, 15632, 304, 16276, 4, + 16308, 240, 15788, 1876, 3192, 15632, 304, 16276, 4, + 16320, 204, 15876, 1520, 3452, 15664, 288, 16280, 8, + 16336, 164, 15976, 1176, 3676, 15732, 260, 16288, 12, + 16348, 120, 16080, 844, 3856, 15840, 216, 16300, 12, + 16364, 76, 16188, 532, 3988, 15984, 156, 16324, 8, + 16376, 36, 16288, 252, 4068, 16164, 84, 16352, 4, + 0, 0, 0, 0, 4096, 0, 0, 0, 0, +}; + +static const uint16_t filter_9tap_16p_117[81] = { + 16356, 172, 15776, 2504, 2504, 15776, 172, 16356, 0, + 16344, 200, 15756, 2252, 2740, 15816, 136, 16372, 16380, + 16336, 216, 15756, 1988, 2956, 15884, 92, 8, 16380, + 16332, 224, 15780, 1720, 3144, 15976, 40, 28, 16376, + 16328, 224, 15816, 1448, 3304, 16096, 16364, 52, 16372, + 16328, 216, 15868, 1180, 3432, 16240, 16296, 80, 16364, + 16332, 200, 15928, 916, 3524, 24, 16224, 108, 16356, + 16336, 184, 15996, 668, 3580, 220, 16148, 132, 16352, + 16344, 160, 16072, 436, 3600, 436, 16072, 160, 16344, +}; + +static const uint16_t filter_9tap_16p_150[81] = { + 84, 16128, 0, 2216, 2216, 0, 16128, 84, 0, + 80, 16160, 16296, 2088, 2332, 100, 16092, 84, 0, + 76, 16196, 16220, 1956, 2432, 208, 16064, 80, 0, + 72, 16232, 16152, 1812, 2524, 328, 16036, 76, 4, + 64, 16264, 16096, 1664, 2600, 460, 16012, 64, 8, + 56, 16300, 16052, 1508, 2656, 596, 15996, 52, 12, + 48, 16328, 16020, 1356, 2700, 740, 15984, 36, 20, + 40, 16356, 15996, 1196, 2728, 888, 15980, 20, 24, + 32, 0, 15984, 1044, 2736, 1044, 15984, 0, 32, +}; + +static const uint16_t filter_9tap_16p_183[81] = { + 16356, 16112, 388, 1952, 1952, 388, 16112, 16356, 0, + 16368, 16116, 304, 1876, 2020, 480, 16112, 16344, 4, + 16376, 16124, 224, 1792, 2080, 576, 16116, 16328, 8, + 0, 16136, 148, 1700, 2132, 672, 16124, 16312, 8, + 8, 16148, 80, 1604, 2176, 772, 16140, 16296, 12, + 12, 16164, 16, 1504, 2208, 876, 16156, 16276, 16, + 16, 16180, 16344, 1404, 2232, 980, 16184, 16256, 20, + 20, 16200, 16296, 1300, 2244, 1088, 16212, 16240, 20, + 20, 16220, 16252, 1196, 2252, 1196, 16252, 16220, 20, +}; + +static const uint16_t filter_10tap_16p_upscale[90] = { + 0, 0, 0, 0, 4096, 0, 0, 0, 0, 0, + 12, 16344, 88, 16160, 4068, 252, 16280, 44, 16368, 0, + 24, 16308, 168, 15976, 3988, 540, 16176, 92, 16348, 0, + 32, 16280, 236, 15828, 3852, 852, 16064, 140, 16328, 4, + 36, 16260, 284, 15720, 3672, 1184, 15956, 188, 16308, 8, + 36, 16244, 320, 15648, 3448, 1528, 15852, 236, 16288, 12, + 36, 16240, 336, 15612, 3184, 1880, 15764, 276, 16272, 20, + 32, 16240, 340, 15608, 2888, 2228, 15688, 308, 16256, 24, + 28, 16244, 332, 15636, 2568, 2568, 15636, 332, 16244, 28, +}; + +static const uint16_t filter_10tap_16p_117[90] = { + 16308, 196, 16048, 440, 3636, 440, 16048, 196, 16308, 0, + 16316, 164, 16132, 220, 3612, 676, 15972, 220, 16300, 0, + 16324, 132, 16212, 20, 3552, 932, 15900, 240, 16296, 4, + 16336, 100, 16292, 16232, 3456, 1192, 15836, 256, 16296, 4, + 16348, 68, 16364, 16084, 3324, 1464, 15784, 264, 16296, 8, + 16356, 36, 48, 15960, 3164, 1736, 15748, 260, 16304, 4, + 16364, 8, 108, 15864, 2972, 2008, 15728, 252, 16312, 4, + 16372, 16368, 160, 15792, 2756, 2268, 15724, 228, 16328, 0, + 16380, 16344, 200, 15748, 2520, 2520, 15748, 200, 16344, 16380, +}; + +static const uint16_t filter_10tap_16p_150[90] = { + 64, 0, 15956, 1048, 2716, 1048, 15956, 0, 64, 0, + 52, 24, 15952, 896, 2708, 1204, 15972, 16356, 72, 16380, + 44, 48, 15952, 748, 2684, 1360, 16000, 16320, 84, 16380, + 32, 68, 15964, 604, 2644, 1516, 16032, 16288, 92, 16376, + 24, 88, 15980, 464, 2588, 1668, 16080, 16248, 100, 16376, + 16, 100, 16004, 332, 2516, 1816, 16140, 16212, 108, 16376, + 8, 108, 16032, 212, 2428, 1956, 16208, 16172, 112, 16376, + 4, 116, 16060, 100, 2328, 2092, 16288, 16132, 116, 16380, + 0, 116, 16096, 16380, 2216, 2216, 16380, 16096, 116, 0, +}; + +static const uint16_t filter_10tap_16p_183[90] = { + 40, 16180, 16240, 1216, 2256, 1216, 16240, 16180, 40, 0, + 44, 16204, 16200, 1112, 2252, 1320, 16288, 16160, 36, 0, + 44, 16224, 16168, 1004, 2236, 1424, 16344, 16144, 28, 4, + 44, 16248, 16136, 900, 2208, 1524, 16, 16124, 24, 8, + 44, 16268, 16116, 796, 2176, 1620, 84, 16108, 12, 12, + 40, 16288, 16100, 692, 2132, 1712, 156, 16096, 4, 16, + 36, 16308, 16088, 592, 2080, 1796, 232, 16088, 16376, 20, + 32, 16328, 16080, 496, 2020, 1876, 316, 16080, 16360, 24, + 28, 16344, 16080, 404, 1952, 1952, 404, 16080, 16344, 28, +}; + +static const uint16_t filter_11tap_16p_upscale[99] = { + 60, 16216, 356, 15620, 2556, 2556, 15620, 356, 16216, 60, 0, + 52, 16224, 336, 15672, 2224, 2876, 15592, 368, 16208, 64, 16380, + 44, 16244, 304, 15744, 1876, 3176, 15596, 364, 16212, 64, 16376, + 36, 16264, 260, 15836, 1532, 3440, 15636, 340, 16220, 60, 16376, + 28, 16288, 212, 15940, 1188, 3668, 15708, 304, 16236, 56, 16376, + 20, 16312, 160, 16052, 856, 3848, 15820, 248, 16264, 48, 16376, + 12, 16336, 104, 16164, 544, 3984, 15968, 180, 16296, 36, 16376, + 4, 16360, 48, 16276, 256, 4068, 16160, 96, 16336, 16, 16380, + 0, 0, 0, 0, 0, 4096, 0, 0, 0, 0, 0, +}; + +static const uint16_t filter_11tap_16p_117[99] = { + 16380, 16332, 220, 15728, 2536, 2536, 15728, 220, 16332, 16380, 0, + 4, 16308, 256, 15704, 2280, 2768, 15772, 176, 16360, 16368, 0, + 12, 16292, 280, 15704, 2016, 2984, 15848, 120, 8, 16356, 0, + 20, 16276, 292, 15724, 1744, 3172, 15948, 56, 40, 16340, 4, + 24, 16268, 292, 15760, 1468, 3328, 16072, 16368, 80, 16324, 8, + 24, 16264, 288, 15816, 1196, 3456, 16224, 16288, 116, 16312, 12, + 24, 16264, 272, 15880, 932, 3548, 16, 16208, 152, 16296, 16, + 24, 16268, 248, 15956, 676, 3604, 216, 16120, 188, 16284, 20, + 24, 16276, 220, 16036, 436, 3624, 436, 16036, 220, 16276, 24, +}; + +static const uint16_t filter_11tap_16p_150[99] = { + 0, 144, 16072, 0, 2212, 2212, 0, 16072, 144, 0, 0, + 16376, 144, 16112, 16288, 2092, 2324, 104, 16036, 140, 8, 16380, + 16368, 144, 16152, 16204, 1960, 2424, 216, 16004, 132, 16, 16376, + 16364, 140, 16192, 16132, 1820, 2512, 340, 15976, 116, 28, 16376, + 16364, 132, 16232, 16072, 1676, 2584, 476, 15952, 100, 40, 16372, + 16360, 124, 16272, 16020, 1528, 2644, 612, 15936, 80, 52, 16368, + 16360, 116, 16312, 15980, 1372, 2684, 760, 15928, 56, 64, 16364, + 16360, 104, 16348, 15952, 1216, 2712, 908, 15928, 28, 76, 16364, + 16360, 92, 0, 15936, 1064, 2720, 1064, 15936, 0, 92, 16360, +}; + +static const uint16_t filter_11tap_16p_183[99] = { + 60, 16336, 16052, 412, 1948, 1948, 412, 16052, 16336, 60, 0, + 56, 16356, 16052, 324, 1876, 2016, 504, 16056, 16316, 64, 0, + 48, 16372, 16060, 240, 1796, 2072, 604, 16064, 16292, 64, 0, + 44, 4, 16068, 160, 1712, 2124, 700, 16080, 16272, 68, 0, + 40, 20, 16080, 84, 1620, 2164, 804, 16096, 16248, 68, 4, + 32, 32, 16096, 16, 1524, 2200, 908, 16124, 16224, 68, 4, + 28, 40, 16112, 16340, 1428, 2220, 1012, 16152, 16200, 64, 8, + 24, 52, 16132, 16284, 1328, 2236, 1120, 16192, 16176, 64, 12, + 16, 56, 16156, 16236, 1224, 2240, 1224, 16236, 16156, 56, 16, +}; + +static const uint16_t filter_12tap_16p_upscale[108] = { + 0, 0, 0, 0, 0, 4096, 0, 0, 0, 0, 0, 0, + 16376, 24, 16332, 100, 16156, 4068, 260, 16272, 56, 16356, 8, 0, + 16368, 44, 16284, 188, 15964, 3988, 548, 16156, 112, 16328, 20, 16380, + 16360, 64, 16248, 260, 15812, 3856, 864, 16040, 172, 16296, 32, 16380, + 16360, 76, 16216, 320, 15696, 3672, 1196, 15928, 228, 16268, 44, 16376, + 16356, 84, 16196, 360, 15620, 3448, 1540, 15820, 280, 16240, 56, 16372, + 16356, 88, 16184, 384, 15580, 3188, 1888, 15728, 324, 16216, 68, 16368, + 16360, 88, 16180, 392, 15576, 2892, 2236, 15652, 360, 16200, 80, 16364, + 16360, 84, 16188, 384, 15600, 2576, 2576, 15600, 384, 16188, 84, 16360, +}; + +static const uint16_t filter_12tap_16p_117[108] = { + 48, 16248, 240, 16028, 436, 3612, 436, 16028, 240, 16248, 48, 0, + 44, 16260, 208, 16116, 212, 3596, 676, 15944, 272, 16240, 48, 16380, + 40, 16276, 168, 16204, 12, 3540, 932, 15868, 296, 16240, 48, 16380, + 36, 16292, 128, 16288, 16220, 3452, 1196, 15800, 312, 16240, 44, 16380, + 28, 16308, 84, 16372, 16064, 3324, 1472, 15748, 316, 16244, 40, 16380, + 24, 16328, 44, 64, 15936, 3168, 1744, 15708, 312, 16256, 32, 16380, + 16, 16344, 8, 132, 15836, 2980, 2016, 15688, 300, 16272, 20, 0, + 12, 16364, 16356, 188, 15760, 2768, 2280, 15688, 272, 16296, 8, 4, + 8, 16380, 16324, 236, 15712, 2532, 2532, 15712, 236, 16324, 16380, 8, +}; + +static const uint16_t filter_12tap_16p_150[108] = { + 16340, 116, 0, 15916, 1076, 2724, 1076, 15916, 0, 116, 16340, 0, + 16340, 100, 32, 15908, 920, 2716, 1232, 15936, 16344, 128, 16340, 0, + 16344, 84, 64, 15908, 772, 2692, 1388, 15968, 16304, 140, 16344, 16380, + 16344, 68, 92, 15912, 624, 2652, 1540, 16008, 16264, 152, 16344, 16380, + 16348, 52, 112, 15928, 484, 2592, 1688, 16060, 16220, 160, 16348, 16380, + 16352, 40, 132, 15952, 348, 2520, 1836, 16124, 16176, 168, 16356, 16376, + 16356, 24, 148, 15980, 224, 2436, 1976, 16200, 16132, 172, 16364, 16372, + 16360, 12, 160, 16012, 108, 2336, 2104, 16288, 16088, 172, 16372, 16368, + 16364, 0, 168, 16048, 0, 2228, 2228, 0, 16048, 168, 0, 16364, +}; + +static const uint16_t filter_12tap_16p_183[108] = { + 36, 72, 16132, 16228, 1224, 2224, 1224, 16228, 16132, 72, 36, 0, + 28, 80, 16156, 16184, 1120, 2224, 1328, 16280, 16112, 64, 40, 16380, + 24, 84, 16180, 16144, 1016, 2208, 1428, 16340, 16092, 52, 48, 16380, + 16, 88, 16208, 16112, 912, 2188, 1524, 16, 16072, 36, 56, 16380, + 12, 92, 16232, 16084, 812, 2156, 1620, 88, 16056, 24, 64, 16380, + 8, 92, 16256, 16064, 708, 2116, 1708, 164, 16044, 4, 68, 16380, + 4, 88, 16280, 16048, 608, 2068, 1792, 244, 16036, 16372, 76, 16380, + 0, 88, 16308, 16036, 512, 2008, 1872, 328, 16032, 16352, 80, 16380, + 0, 84, 16328, 16032, 416, 1944, 1944, 416, 16032, 16328, 84, 0, +}; + +const uint16_t *wbscl_get_filter_3tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_3tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_3tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_3tap_16p_150; + else + return filter_3tap_16p_183; +} + +const uint16_t *wbscl_get_filter_4tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_4tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_4tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_4tap_16p_150; + else + return filter_4tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_5tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_5tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_5tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_5tap_16p_150; + else + return filter_5tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_6tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_6tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_6tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_6tap_16p_150; + else + return filter_6tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_7tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_7tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_7tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_7tap_16p_150; + else + return filter_7tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_8tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_8tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_8tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_8tap_16p_150; + else + return filter_8tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_9tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_9tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_9tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_9tap_16p_150; + else + return filter_9tap_16p_183; +} +static const uint16_t *wbscl_get_filter_10tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_10tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_10tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_10tap_16p_150; + else + return filter_10tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_11tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_11tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_11tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_11tap_16p_150; + else + return filter_11tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_12tap_16p(struct fixed31_32 ratio) +{ + if (ratio.value < dc_fixpt_one.value) + return filter_12tap_16p_upscale; + else if (ratio.value < dc_fixpt_from_fraction(4, 3).value) + return filter_12tap_16p_117; + else if (ratio.value < dc_fixpt_from_fraction(5, 3).value) + return filter_12tap_16p_150; + else + return filter_12tap_16p_183; +} + +static const uint16_t *wbscl_get_filter_coeffs_16p(int taps, struct fixed31_32 ratio) +{ + if (taps == 12) + return wbscl_get_filter_12tap_16p(ratio); + else if (taps == 11) + return wbscl_get_filter_11tap_16p(ratio); + else if (taps == 10) + return wbscl_get_filter_10tap_16p(ratio); + else if (taps == 9) + return wbscl_get_filter_9tap_16p(ratio); + else if (taps == 8) + return wbscl_get_filter_8tap_16p(ratio); + else if (taps == 7) + return wbscl_get_filter_7tap_16p(ratio); + else if (taps == 6) + return wbscl_get_filter_6tap_16p(ratio); + else if (taps == 5) + return wbscl_get_filter_5tap_16p(ratio); + else if (taps == 4) + return wbscl_get_filter_4tap_16p(ratio); + else if (taps == 3) + return wbscl_get_filter_3tap_16p(ratio); + else if (taps == 2) + return get_filter_2tap_16p(); + else if (taps == 1) + return NULL; + else { + /* should never happen, bug */ + BREAK_TO_DEBUGGER(); + return NULL; + } +} + +static void wbscl_set_scaler_filter( + struct dcn20_dwbc *dwbc20, + uint32_t taps, + enum wbscl_coef_filter_type_sel filter_type, + const uint16_t *filter) +{ + const int tap_pairs = (taps + 1) / 2; + int phase; + int pair; + uint16_t odd_coef, even_coef; + + for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) { + for (pair = 0; pair < tap_pairs; pair++) { + even_coef = filter[phase * taps + 2 * pair]; + if ((pair * 2 + 1) < taps) + odd_coef = filter[phase * taps + 2 * pair + 1]; + else + odd_coef = 0; + + REG_SET_3(WBSCL_COEF_RAM_SELECT, 0, + WBSCL_COEF_RAM_TAP_PAIR_IDX, pair, + WBSCL_COEF_RAM_PHASE, phase, + WBSCL_COEF_RAM_FILTER_TYPE, filter_type); + + REG_SET_4(WBSCL_COEF_RAM_TAP_DATA, 0, + /* Even tap coefficient (bits 1:0 fixed to 0) */ + WBSCL_COEF_RAM_EVEN_TAP_COEF, even_coef, + /* Write/read control for even coefficient */ + WBSCL_COEF_RAM_EVEN_TAP_COEF_EN, 1, + /* Odd tap coefficient (bits 1:0 fixed to 0) */ + WBSCL_COEF_RAM_ODD_TAP_COEF, odd_coef, + /* Write/read control for odd coefficient */ + WBSCL_COEF_RAM_ODD_TAP_COEF_EN, 1); + } + } +} + +bool dwb_program_horz_scalar(struct dcn20_dwbc *dwbc20, + uint32_t src_width, + uint32_t dest_width, + struct scaling_taps num_taps) +{ + uint32_t h_ratio_luma = 1; + uint32_t h_ratio_chroma = 1; + uint32_t h_taps_luma = num_taps.h_taps; + uint32_t h_taps_chroma = num_taps.h_taps_c; + int32_t h_init_phase_luma = 0; + int32_t h_init_phase_chroma = 0; + uint32_t h_init_phase_luma_int = 0; + uint32_t h_init_phase_luma_frac = 0; + uint32_t h_init_phase_chroma_int = 0; + uint32_t h_init_phase_chroma_frac = 0; + const uint16_t *filter_h = NULL; + const uint16_t *filter_h_c = NULL; + + + struct fixed31_32 tmp_h_init_phase_luma = dc_fixpt_from_int(0); + struct fixed31_32 tmp_h_init_phase_chroma = dc_fixpt_from_int(0); + + + /*Calculate ratio*/ + struct fixed31_32 tmp_h_ratio_luma = dc_fixpt_from_fraction( + src_width, dest_width); + + if (dc_fixpt_floor(tmp_h_ratio_luma) == 8) + h_ratio_luma = -1; + else + h_ratio_luma = dc_fixpt_u3d19(tmp_h_ratio_luma) << 5; + h_ratio_chroma = h_ratio_luma * 2; + + /*Program ratio*/ + REG_UPDATE(WBSCL_HORZ_FILTER_SCALE_RATIO, WBSCL_H_SCALE_RATIO, h_ratio_luma); + + /* Program taps*/ + REG_UPDATE(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_Y_RGB, h_taps_luma - 1); + REG_UPDATE(WBSCL_TAP_CONTROL, WBSCL_H_NUM_OF_TAPS_CBCR, h_taps_chroma - 1); + + /* Calculate phase*/ + tmp_h_init_phase_luma = dc_fixpt_add_int(tmp_h_ratio_luma, h_taps_luma + 1); + tmp_h_init_phase_luma = dc_fixpt_div_int(tmp_h_init_phase_luma, 2); + tmp_h_init_phase_luma = dc_fixpt_sub_int(tmp_h_init_phase_luma, h_taps_luma); + + h_init_phase_luma = dc_fixpt_s4d19(tmp_h_init_phase_luma); + h_init_phase_luma_int = (h_init_phase_luma >> 19) & 0x1f; + h_init_phase_luma_frac = (h_init_phase_luma & 0x7ffff) << 5; + + tmp_h_init_phase_chroma = dc_fixpt_mul_int(tmp_h_ratio_luma, 2); + tmp_h_init_phase_chroma = dc_fixpt_add_int(tmp_h_init_phase_chroma, h_taps_chroma + 1); + tmp_h_init_phase_chroma = dc_fixpt_div_int(tmp_h_init_phase_chroma, 2); + tmp_h_init_phase_chroma = dc_fixpt_sub_int(tmp_h_init_phase_chroma, h_taps_chroma); + tmp_h_init_phase_chroma = dc_fixpt_add(tmp_h_init_phase_chroma, dc_fixpt_from_fraction(1, 4)); + + h_init_phase_chroma = dc_fixpt_s4d19(tmp_h_init_phase_chroma); + h_init_phase_chroma_int = (h_init_phase_chroma >> 19) & 0x1f; + h_init_phase_chroma_frac = (h_init_phase_chroma & 0x7ffff) << 5; + + /* Program phase*/ + REG_UPDATE(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_INT_Y_RGB, h_init_phase_luma_int); + REG_UPDATE(WBSCL_HORZ_FILTER_INIT_Y_RGB, WBSCL_H_INIT_FRAC_Y_RGB, h_init_phase_luma_frac); + REG_UPDATE(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_INT_CBCR, h_init_phase_chroma_int); + REG_UPDATE(WBSCL_HORZ_FILTER_INIT_CBCR, WBSCL_H_INIT_FRAC_CBCR, h_init_phase_chroma_frac); + + /* Program LUT coefficients*/ + filter_h = wbscl_get_filter_coeffs_16p( + h_taps_luma, tmp_h_ratio_luma); + filter_h_c = wbscl_get_filter_coeffs_16p( + h_taps_chroma, dc_fixpt_from_int(h_ratio_luma * 2)); + + wbscl_set_scaler_filter(dwbc20, h_taps_luma, + WBSCL_COEF_LUMA_HORZ_FILTER, filter_h); + + wbscl_set_scaler_filter(dwbc20, h_taps_chroma, + WBSCL_COEF_CHROMA_HORZ_FILTER, filter_h_c); + + return true; +} + +bool dwb_program_vert_scalar(struct dcn20_dwbc *dwbc20, + uint32_t src_height, + uint32_t dest_height, + struct scaling_taps num_taps, + enum dwb_subsample_position subsample_position) +{ + uint32_t v_ratio_luma = 1; + uint32_t v_ratio_chroma = 1; + uint32_t v_taps_luma = num_taps.v_taps; + uint32_t v_taps_chroma = num_taps.v_taps_c; + int32_t v_init_phase_luma = 0; + int32_t v_init_phase_chroma = 0; + uint32_t v_init_phase_luma_int = 0; + uint32_t v_init_phase_luma_frac = 0; + uint32_t v_init_phase_chroma_int = 0; + uint32_t v_init_phase_chroma_frac = 0; + + const uint16_t *filter_v = NULL; + const uint16_t *filter_v_c = NULL; + + struct fixed31_32 tmp_v_init_phase_luma = dc_fixpt_from_int(0); + struct fixed31_32 tmp_v_init_phase_chroma = dc_fixpt_from_int(0); + + /*Calculate ratio*/ + struct fixed31_32 tmp_v_ratio_luma = dc_fixpt_from_fraction( + src_height, dest_height); + + if (dc_fixpt_floor(tmp_v_ratio_luma) == 8) + v_ratio_luma = -1; + else + v_ratio_luma = dc_fixpt_u3d19(tmp_v_ratio_luma) << 5; + v_ratio_chroma = v_ratio_luma * 2; + + /*Program ratio*/ + REG_UPDATE(WBSCL_VERT_FILTER_SCALE_RATIO, WBSCL_V_SCALE_RATIO, v_ratio_luma); + + /* Program taps*/ + REG_UPDATE(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_Y_RGB, v_taps_luma - 1); + REG_UPDATE(WBSCL_TAP_CONTROL, WBSCL_V_NUM_OF_TAPS_CBCR, v_taps_chroma - 1); + + /* Calculate phase*/ + tmp_v_init_phase_luma = dc_fixpt_add_int(tmp_v_ratio_luma, v_taps_luma + 1); + tmp_v_init_phase_luma = dc_fixpt_div_int(tmp_v_init_phase_luma, 2); + tmp_v_init_phase_luma = dc_fixpt_sub_int(tmp_v_init_phase_luma, v_taps_luma); + + v_init_phase_luma = dc_fixpt_s4d19(tmp_v_init_phase_luma); + v_init_phase_luma_int = (v_init_phase_luma >> 19) & 0x1f; + v_init_phase_luma_frac = (v_init_phase_luma & 0x7ffff) << 5; + + tmp_v_init_phase_chroma = dc_fixpt_mul_int(tmp_v_ratio_luma, 2); + tmp_v_init_phase_chroma = dc_fixpt_add_int(tmp_v_init_phase_chroma, v_taps_chroma + 1); + tmp_v_init_phase_chroma = dc_fixpt_div_int(tmp_v_init_phase_chroma, 2); + tmp_v_init_phase_chroma = dc_fixpt_sub_int(tmp_v_init_phase_chroma, v_taps_chroma); + if (subsample_position == DWB_COSITED_SUBSAMPLING) + tmp_v_init_phase_chroma = dc_fixpt_add(tmp_v_init_phase_chroma, dc_fixpt_from_fraction(1, 4)); + + v_init_phase_chroma = dc_fixpt_s4d19(tmp_v_init_phase_chroma); + v_init_phase_chroma_int = (v_init_phase_chroma >> 19) & 0x1f; + v_init_phase_chroma_frac = (v_init_phase_chroma & 0x7ffff) << 5; + + /* Program phase*/ + REG_UPDATE(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_INT_Y_RGB, v_init_phase_luma_int); + REG_UPDATE(WBSCL_VERT_FILTER_INIT_Y_RGB, WBSCL_V_INIT_FRAC_Y_RGB, v_init_phase_luma_frac); + REG_UPDATE(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_INT_CBCR, v_init_phase_chroma_int); + REG_UPDATE(WBSCL_VERT_FILTER_INIT_CBCR, WBSCL_V_INIT_FRAC_CBCR, v_init_phase_chroma_frac); + + + /* Program LUT coefficients*/ + filter_v = wbscl_get_filter_coeffs_16p( + v_taps_luma, tmp_v_ratio_luma); + filter_v_c = wbscl_get_filter_coeffs_16p( + v_taps_chroma, dc_fixpt_from_int(v_ratio_luma * 2)); + wbscl_set_scaler_filter(dwbc20, v_taps_luma, + WBSCL_COEF_LUMA_VERT_FILTER, filter_v); + + wbscl_set_scaler_filter(dwbc20, v_taps_chroma, + WBSCL_COEF_CHROMA_VERT_FILTER, filter_v_c); + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c new file mode 100644 index 000000000000..ece6e136437b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c @@ -0,0 +1,592 @@ +/* + * Copyright 2016 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 "dcn20_hubbub.h" +#include "reg_helper.h" + +#define REG(reg)\ + hubbub1->regs->reg + +#define CTX \ + hubbub1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubbub1->shifts->field_name, hubbub1->masks->field_name + +#define REG(reg)\ + hubbub1->regs->reg + +#define CTX \ + hubbub1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubbub1->shifts->field_name, hubbub1->masks->field_name + +#ifdef NUM_VMID +#undef NUM_VMID +#endif +#define NUM_VMID 16 + +bool hubbub2_dcc_support_swizzle( + enum swizzle_mode_values swizzle, + unsigned int bytes_per_element, + enum segment_order *segment_order_horz, + enum segment_order *segment_order_vert) +{ + bool standard_swizzle = false; + bool display_swizzle = false; + bool render_swizzle = false; + + switch (swizzle) { + case DC_SW_4KB_S: + case DC_SW_64KB_S: + case DC_SW_VAR_S: + case DC_SW_4KB_S_X: + case DC_SW_64KB_S_X: + case DC_SW_VAR_S_X: + standard_swizzle = true; + break; + case DC_SW_64KB_R_X: + render_swizzle = true; + break; + case DC_SW_4KB_D: + case DC_SW_64KB_D: + case DC_SW_VAR_D: + case DC_SW_4KB_D_X: + case DC_SW_64KB_D_X: + case DC_SW_VAR_D_X: + display_swizzle = true; + break; + default: + break; + } + + if (standard_swizzle) { + if (bytes_per_element == 1) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__na; + return true; + } + if (bytes_per_element == 2) { + *segment_order_horz = segment_order__non_contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 4) { + *segment_order_horz = segment_order__non_contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 8) { + *segment_order_horz = segment_order__na; + *segment_order_vert = segment_order__contiguous; + return true; + } + } + if (render_swizzle) { + if (bytes_per_element == 2) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 4) { + *segment_order_horz = segment_order__non_contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 8) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__non_contiguous; + return true; + } + } + if (display_swizzle && bytes_per_element == 8) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__non_contiguous; + return true; + } + + return false; +} + +bool hubbub2_dcc_support_pixel_format( + enum surface_pixel_format format, + unsigned int *bytes_per_element) +{ + /* DML: get_bytes_per_element */ + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + *bytes_per_element = 2; + return true; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX: + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX: + case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT: + case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT: + *bytes_per_element = 4; + return true; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + *bytes_per_element = 8; + return true; + default: + return false; + } +} + +static void hubbub2_get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, + unsigned int bytes_per_element) +{ + /* copied from DML. might want to refactor DML to leverage from DML */ + /* DML : get_blk256_size */ + if (bytes_per_element == 1) { + *blk256_width = 16; + *blk256_height = 16; + } else if (bytes_per_element == 2) { + *blk256_width = 16; + *blk256_height = 8; + } else if (bytes_per_element == 4) { + *blk256_width = 8; + *blk256_height = 8; + } else if (bytes_per_element == 8) { + *blk256_width = 8; + *blk256_height = 4; + } +} + +static void hubbub2_det_request_size( + unsigned int height, + unsigned int width, + unsigned int bpe, + bool *req128_horz_wc, + bool *req128_vert_wc) +{ + unsigned int detile_buf_size = 164 * 1024; /* 164KB for DCN1.0 */ + + unsigned int blk256_height = 0; + unsigned int blk256_width = 0; + unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; + + hubbub2_get_blk256_size(&blk256_width, &blk256_height, bpe); + + swath_bytes_horz_wc = width * blk256_height * bpe; + swath_bytes_vert_wc = height * blk256_width * bpe; + + *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ + + *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ +} + +bool hubbub2_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; + /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */ + enum dcc_control dcc_control; + unsigned int bpe; + enum segment_order segment_order_horz, segment_order_vert; + bool req128_horz_wc, req128_vert_wc; + + memset(output, 0, sizeof(*output)); + + if (dc->debug.disable_dcc == DCC_DISABLE) + return false; + + if (!hubbub->funcs->dcc_support_pixel_format(input->format, + &bpe)) + return false; + + if (!hubbub->funcs->dcc_support_swizzle(input->swizzle_mode, bpe, + &segment_order_horz, &segment_order_vert)) + return false; + + hubbub2_det_request_size(input->surface_size.height, input->surface_size.width, + bpe, &req128_horz_wc, &req128_vert_wc); + + if (!req128_horz_wc && !req128_vert_wc) { + dcc_control = dcc_control__256_256_xxx; + } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { + if (!req128_horz_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_horz == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else if (input->scan == SCAN_DIRECTION_VERTICAL) { + if (!req128_vert_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_vert == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else { + if ((req128_horz_wc && + segment_order_horz == segment_order__non_contiguous) || + (req128_vert_wc && + segment_order_vert == segment_order__non_contiguous)) + /* access_dir not known, must use most constraining */ + dcc_control = dcc_control__256_64_64; + else + /* reg128 is true for either horz and vert + * but segment_order is contiguous + */ + dcc_control = dcc_control__128_128_xxx; + } + + /* Exception for 64KB_R_X */ + if ((bpe == 2) && (input->swizzle_mode == DC_SW_64KB_R_X)) + dcc_control = dcc_control__128_128_xxx; + + if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && + dcc_control != dcc_control__256_256_xxx) + return false; + + switch (dcc_control) { + case dcc_control__256_256_xxx: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 256; + output->grph.rgb.independent_64b_blks = false; + break; + case dcc_control__128_128_xxx: + output->grph.rgb.max_uncompressed_blk_size = 128; + output->grph.rgb.max_compressed_blk_size = 128; + output->grph.rgb.independent_64b_blks = false; + break; + case dcc_control__256_64_64: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 64; + output->grph.rgb.independent_64b_blks = true; + break; + } + output->capable = true; + output->const_color_support = true; + + return true; +} + +static enum dcn_hubbub_page_table_depth page_table_depth_to_hw(unsigned int page_table_depth) +{ + enum dcn_hubbub_page_table_depth depth = 0; + + switch (page_table_depth) { + case 1: + depth = DCN_PAGE_TABLE_DEPTH_1_LEVEL; + break; + case 2: + depth = DCN_PAGE_TABLE_DEPTH_2_LEVEL; + break; + case 3: + depth = DCN_PAGE_TABLE_DEPTH_3_LEVEL; + break; + case 4: + depth = DCN_PAGE_TABLE_DEPTH_4_LEVEL; + break; + default: + ASSERT(false); + break; + } + + return depth; +} + +static enum dcn_hubbub_page_table_block_size page_table_block_size_to_hw(unsigned int page_table_block_size) +{ + enum dcn_hubbub_page_table_block_size block_size = 0; + + switch (page_table_block_size) { + case 4096: + block_size = DCN_PAGE_TABLE_BLOCK_SIZE_4KB; + break; + case 65536: + block_size = DCN_PAGE_TABLE_BLOCK_SIZE_64KB; + break; + default: + ASSERT(false); + break; + } + + return block_size; +} + +void hubbub2_init_vm_ctx(struct hubbub *hubbub, + struct dcn_hubbub_virt_addr_config *va_config, + int vmid) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + struct dcn_vmid_page_table_config virt_config; + + virt_config.page_table_start_addr = va_config->page_table_start_addr >> 12; + virt_config.page_table_end_addr = va_config->page_table_end_addr >> 12; + virt_config.depth = page_table_depth_to_hw(va_config->page_table_depth); + virt_config.block_size = page_table_block_size_to_hw(va_config->page_table_block_size); + virt_config.page_table_base_addr = va_config->page_table_base_addr; + + dcn20_vmid_setup(&hubbub1->vmid[vmid], &virt_config); +} + +int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + struct dcn_vmid_page_table_config phys_config; + + REG_SET(DCN_VM_FB_LOCATION_BASE, 0, + FB_BASE, pa_config->system_aperture.fb_base); + REG_SET(DCN_VM_FB_LOCATION_TOP, 0, + FB_TOP, pa_config->system_aperture.fb_top); + REG_SET(DCN_VM_FB_OFFSET, 0, + FB_OFFSET, pa_config->system_aperture.fb_offset); + REG_SET(DCN_VM_AGP_BOT, 0, + AGP_BOT, pa_config->system_aperture.agp_bot); + REG_SET(DCN_VM_AGP_TOP, 0, + AGP_TOP, pa_config->system_aperture.agp_top); + REG_SET(DCN_VM_AGP_BASE, 0, + AGP_BASE, pa_config->system_aperture.agp_base); + + if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) { + phys_config.depth = 1; + phys_config.block_size = 4096; + phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12; + phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12; + phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + + // Init VMID 0 based on PA config + dcn20_vmid_setup(&hubbub1->vmid[0], &phys_config); + } + + return NUM_VMID; +} + +void hubbub2_update_dchub(struct hubbub *hubbub, + struct dchub_init_data *dh_data) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + + if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { + ASSERT(false); + /*should not come here*/ + return; + } + /* TODO: port code from dal2 */ + switch (dh_data->fb_mode) { + case FRAME_BUFFER_MODE_ZFB_ONLY: + /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ + REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP, + SDPIF_FB_TOP, 0); + + REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE, + SDPIF_FB_BASE, 0x0FFFF); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_LOCAL_ONLY: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, 0); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, 0X03FFFF); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, 0); + break; + default: + break; + } + + dh_data->dchub_initialzied = true; + dh_data->dchub_info_valid = false; +} + +void hubbub2_wm_read_state(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + + struct dcn_hubbub_wm_set *s; + + memset(wm, 0, sizeof(struct dcn_hubbub_wm)); + + s = &wm->sets[0]; + s->wm_set = 0; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A)) + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A); + + s = &wm->sets[1]; + s->wm_set = 1; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B)) + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B); + + s = &wm->sets[2]; + s->wm_set = 2; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C)) + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C); + + s = &wm->sets[3]; + s->wm_set = 3; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D); + if (REG(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D)) + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); +} + +void hubbub2_get_dchub_ref_freq(struct hubbub *hubbub, + unsigned int dccg_ref_freq_inKhz, + unsigned int *dchub_ref_freq_inKhz) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + uint32_t ref_div = 0; + uint32_t ref_en = 0; + + REG_GET_2(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, &ref_div, + DCHUBBUB_GLOBAL_TIMER_ENABLE, &ref_en); + + if (ref_en) { + if (ref_div == 2) + *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz / 2; + else + *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz; + + // DC hub reference frequency must be around 50Mhz, otherwise there may be + // overflow/underflow issues when doing HUBBUB programming + if (*dchub_ref_freq_inKhz < 40000 || *dchub_ref_freq_inKhz > 60000) + ASSERT_CRITICAL(false); + + return; + } else { + *dchub_ref_freq_inKhz = dccg_ref_freq_inKhz; + + // HUBBUB global timer must be enabled. + ASSERT_CRITICAL(false); + return; + } +} + +static void hubbub2_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + /* + * Need to clamp to max of the register values (i.e. no wrap) + * for dcn1, all wm registers are 21-bit wide + */ + hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + + REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, + DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); + REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 180); + + hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); +} + +static const struct hubbub_funcs hubbub2_funcs = { + .update_dchub = hubbub2_update_dchub, + .init_dchub_sys_ctx = hubbub2_init_dchub_sys_ctx, + .init_vm_ctx = hubbub2_init_vm_ctx, + .dcc_support_swizzle = hubbub2_dcc_support_swizzle, + .dcc_support_pixel_format = hubbub2_dcc_support_pixel_format, + .get_dcc_compression_cap = hubbub2_get_dcc_compression_cap, + .wm_read_state = hubbub2_wm_read_state, + .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, + .program_watermarks = hubbub2_program_watermarks, +}; + +void hubbub2_construct(struct dcn20_hubbub *hubbub, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask) +{ + hubbub->base.ctx = ctx; + + hubbub->base.funcs = &hubbub2_funcs; + + hubbub->regs = hubbub_regs; + hubbub->shifts = hubbub_shift; + hubbub->masks = hubbub_mask; + + hubbub->debug_test_index_pstate = 0xB; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h new file mode 100644 index 000000000000..a7b6ca26a9ad --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h @@ -0,0 +1,107 @@ +/* + * Copyright 2016 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 __DC_HUBBUB_DCN20_H__ +#define __DC_HUBBUB_DCN20_H__ + +#include "dcn10/dcn10_hubbub.h" +#include "dcn20_vmid.h" + +#define TO_DCN20_HUBBUB(hubbub)\ + container_of(hubbub, struct dcn20_hubbub, base) + +#define HUBBUB_REG_LIST_DCN20(id)\ + HUBBUB_REG_LIST_DCN_COMMON(), \ + HUBBUB_VM_REG_LIST(), \ + HUBBUB_SR_WATERMARK_REG_LIST(), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DCN_VM_FB_LOCATION_BASE),\ + SR(DCN_VM_FB_LOCATION_TOP),\ + SR(DCN_VM_FB_OFFSET),\ + SR(DCN_VM_AGP_BOT),\ + SR(DCN_VM_AGP_TOP),\ + SR(DCN_VM_AGP_BASE) + +#define HUBBUB_MASK_SH_LIST_DCN20(mask_sh)\ + HUBBUB_MASK_SH_LIST_DCN_COMMON(mask_sh), \ + HUBBUB_MASK_SH_LIST_STUTTER(mask_sh), \ + HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_LOCATION_TOP, FB_TOP, mask_sh), \ + HUBBUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh), \ + HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh) + +struct dcn20_hubbub { + struct hubbub base; + const struct dcn_hubbub_registers *regs; + const struct dcn_hubbub_shift *shifts; + const struct dcn_hubbub_mask *masks; + unsigned int debug_test_index_pstate; + struct dcn_watermark_set watermarks; + struct dcn20_vmid vmid[16]; +}; + +void hubbub2_construct(struct dcn20_hubbub *hubbub, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask); + +bool hubbub2_dcc_support_swizzle( + enum swizzle_mode_values swizzle, + unsigned int bytes_per_element, + enum segment_order *segment_order_horz, + enum segment_order *segment_order_vert); + +bool hubbub2_dcc_support_pixel_format( + enum surface_pixel_format format, + unsigned int *bytes_per_element); + +bool hubbub2_get_dcc_compression_cap(struct hubbub *hubbub, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output); + +bool hubbub2_initialize_vmids(struct hubbub *hubbub, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output); + +int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config); +void hubbub2_init_vm_ctx(struct hubbub *hubbub, + struct dcn_hubbub_virt_addr_config *va_config, + int vmid); +void hubbub2_update_dchub(struct hubbub *hubbub, + struct dchub_init_data *dh_data); + +void hubbub2_get_dchub_ref_freq(struct hubbub *hubbub, + unsigned int dccg_ref_freq_inKhz, + unsigned int *dchub_ref_freq_inKhz); + +void hubbub2_wm_read_state(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c new file mode 100644 index 000000000000..d3f7dd374d50 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -0,0 +1,700 @@ +/* + * Copyright 2012-17 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 "dcn20_hubp.h" + +#include "dm_services.h" +#include "dce_calcs.h" +#include "reg_helper.h" +#include "basics/conversion.h" + +#define REG(reg)\ + hubp2->hubp_regs->reg + +#define CTX \ + hubp2->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubp2->hubp_shift->field_name, hubp2->hubp_mask->field_name + +void hubp2_update_dchub( + struct hubp *hubp, + struct dchub_init_data *dh_data) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + if (REG(DCN_VM_FB_LOCATION_TOP) == 0) + return; + + switch (dh_data->fb_mode) { + case FRAME_BUFFER_MODE_ZFB_ONLY: + /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ + REG_UPDATE(DCN_VM_FB_LOCATION_TOP, + FB_TOP, 0); + + REG_UPDATE(DCN_VM_FB_LOCATION_BASE, + FB_BASE, 0xFFFFFF); + + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 24); + + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 24); + + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 24); + break; + case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, dh_data->zfb_phys_addr_base >> 24); + + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, dh_data->zfb_mc_base_addr >> 24); + + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 24); + break; + case FRAME_BUFFER_MODE_LOCAL_ONLY: + /*Should not touch FB LOCATION (should be done by VBIOS)*/ + + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, 0); + + /*This field defines the bottom range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_BOT, + AGP_BOT, 0xFFFFFF); + + /*This field defines the top range of the AGP aperture and represents the 24*/ + /*MSBs, bits [47:24] of the 48 address bits*/ + REG_UPDATE(DCN_VM_AGP_TOP, + AGP_TOP, 0); + break; + default: + break; + } + + dh_data->dchub_initialzied = true; + dh_data->dchub_info_valid = false; +} + +void hubp2_set_vm_system_aperture_settings(struct hubp *hubp, + struct vm_system_aperture_param *apt) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + PHYSICAL_ADDRESS_LOC mc_vm_apt_default; + PHYSICAL_ADDRESS_LOC mc_vm_apt_low; + PHYSICAL_ADDRESS_LOC mc_vm_apt_high; + + // The format of default addr is 48:12 of the 48 bit addr + mc_vm_apt_default.quad_part = apt->sys_default.quad_part >> 12; + + // The format of high/low are 48:18 of the 48 bit addr + mc_vm_apt_low.quad_part = apt->sys_low.quad_part >> 18; + mc_vm_apt_high.quad_part = apt->sys_high.quad_part >> 18; + + REG_UPDATE_2(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, + DCN_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, 1, /* 1 = system physical memory */ + DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mc_vm_apt_default.high_part); + + REG_SET(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, + DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mc_vm_apt_default.low_part); + + REG_SET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, 0, + MC_VM_SYSTEM_APERTURE_LOW_ADDR, mc_vm_apt_low.quad_part); + + REG_SET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, 0, + MC_VM_SYSTEM_APERTURE_HIGH_ADDR, mc_vm_apt_high.quad_part); + + REG_SET_2(DCN_VM_MX_L1_TLB_CNTL, 0, + ENABLE_L1_TLB, 1, + SYSTEM_ACCESS_MODE, 0x3); +} + +void hubp2_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + hubp1_program_deadline(hubp, dlg_attr, ttu_attr); + + REG_SET(FLIP_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_FLIP_L, dlg_attr->refcyc_per_pte_group_flip_l); +} + +void hubp2_vready_at_or_After_vsync(struct hubp *hubp, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest) +{ + uint32_t value = 0; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + /* disable_dlg_test_mode Set 9th bit to 1 to disable "dv" mode */ + REG_WRITE(HUBPREQ_DEBUG_DB, 1 << 8); + /* + if (VSTARTUP_START - (VREADY_OFFSET+VUPDATE_WIDTH+VUPDATE_OFFSET)/htotal) + <= OTG_V_BLANK_END + Set HUBP_VREADY_AT_OR_AFTER_VSYNC = 1 + else + Set HUBP_VREADY_AT_OR_AFTER_VSYNC = 0 + */ + if ((pipe_dest->vstartup_start - (pipe_dest->vready_offset+pipe_dest->vupdate_width + + pipe_dest->vupdate_offset) / pipe_dest->htotal) <= pipe_dest->vblank_end) { + value = 1; + } else + value = 0; + REG_UPDATE(DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, value); +} + +static void hubp2_setup( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr, + struct _vcs_dpi_display_rq_regs_st *rq_regs, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest) +{ + /* otg is locked when this func is called. Register are double buffered. + * disable the requestors is not needed + */ + + hubp2_vready_at_or_After_vsync(hubp, pipe_dest); + hubp1_program_requestor(hubp, rq_regs); + hubp2_program_deadline(hubp, dlg_attr, ttu_attr); + +} + +void hubp2_setup_interdependent( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_SET_2(PREFETCH_SETTINGS, 0, + DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, dlg_attr->vratio_prefetch); + + REG_SET(PREFETCH_SETTINGS_C, 0, + VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); + + REG_SET_2(VBLANK_PARAMETERS_0, 0, + DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, + DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); + + REG_SET_2(FLIP_PARAMETERS_0, 0, + DST_Y_PER_VM_FLIP, dlg_attr->dst_y_per_vm_flip, + DST_Y_PER_ROW_FLIP, dlg_attr->dst_y_per_row_flip); + + REG_SET(VBLANK_PARAMETERS_3, 0, + REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); + + REG_SET(VBLANK_PARAMETERS_4, 0, + REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); + + REG_SET(FLIP_PARAMETERS_2, 0, + REFCYC_PER_META_CHUNK_FLIP_L, dlg_attr->refcyc_per_meta_chunk_flip_l); + + REG_SET_2(PER_LINE_DELIVERY_PRE, 0, + REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); + + REG_SET(DCN_SURF0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_l); + REG_SET(DCN_SURF1_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_c); + REG_SET(DCN_CUR0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur0); + REG_SET(DCN_CUR1_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, ttu_attr->refcyc_per_req_delivery_pre_cur1); + + REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, + MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); +} + +/* DCN2 (GFX10), the following GFX fields are deprecated. They can be set but they will not be used: + * NUM_BANKS + * NUM_SE + * NUM_RB_PER_SE + * RB_ALIGNED + * Other things can be defaulted, since they never change: + * PIPE_ALIGNED = 0 + * META_LINEAR = 0 + * In GFX10, only these apply: + * PIPE_INTERLEAVE + * NUM_PIPES + * MAX_COMPRESSED_FRAGS + * SW_MODE + */ +static void hubp2_program_tiling( + struct dcn20_hubp *hubp2, + const union dc_tiling_info *info, + const enum surface_pixel_format pixel_format) +{ + REG_UPDATE_3(DCSURF_ADDR_CONFIG, + NUM_PIPES, log_2(info->gfx9.num_pipes), + PIPE_INTERLEAVE, info->gfx9.pipe_interleave, + MAX_COMPRESSED_FRAGS, log_2(info->gfx9.max_compressed_frags)); + + REG_UPDATE_4(DCSURF_TILING_CONFIG, + SW_MODE, info->gfx9.swizzle, + META_LINEAR, 0, + RB_ALIGNED, 0, + PIPE_ALIGNED, 0); +} + +void hubp2_program_surface_config( + struct hubp *hubp, + enum surface_pixel_format format, + union dc_tiling_info *tiling_info, + union plane_size *plane_size, + enum dc_rotation_angle rotation, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror, + unsigned int compat_level) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); + hubp2_program_tiling(hubp2, tiling_info, format); + hubp1_program_size(hubp, format, plane_size, dcc); + hubp1_program_rotation(hubp, rotation, horizontal_mirror); + hubp1_program_pixel_format(hubp, format); +} + +enum cursor_lines_per_chunk hubp2_get_lines_per_chunk( + unsigned int cursor_width, + enum dc_cursor_color_format cursor_mode) +{ + enum cursor_lines_per_chunk line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + + if (cursor_mode == CURSOR_MODE_MONO) + line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + else if (cursor_mode == CURSOR_MODE_COLOR_1BIT_AND || + cursor_mode == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA || + cursor_mode == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { + if (cursor_width >= 1 && cursor_width <= 32) + line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + else if (cursor_width >= 33 && cursor_width <= 64) + line_per_chunk = CURSOR_LINE_PER_CHUNK_8; + else if (cursor_width >= 65 && cursor_width <= 128) + line_per_chunk = CURSOR_LINE_PER_CHUNK_4; + else if (cursor_width >= 129 && cursor_width <= 256) + line_per_chunk = CURSOR_LINE_PER_CHUNK_2; + } else if (cursor_mode == CURSOR_MODE_COLOR_64BIT_FP_PRE_MULTIPLIED || + cursor_mode == CURSOR_MODE_COLOR_64BIT_FP_UN_PRE_MULTIPLIED) { + if (cursor_width >= 1 && cursor_width <= 16) + line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + else if (cursor_width >= 17 && cursor_width <= 32) + line_per_chunk = CURSOR_LINE_PER_CHUNK_8; + else if (cursor_width >= 33 && cursor_width <= 64) + line_per_chunk = CURSOR_LINE_PER_CHUNK_4; + else if (cursor_width >= 65 && cursor_width <= 128) + line_per_chunk = CURSOR_LINE_PER_CHUNK_2; + else if (cursor_width >= 129 && cursor_width <= 256) + line_per_chunk = CURSOR_LINE_PER_CHUNK_1; + } + + return line_per_chunk; +} + +void hubp2_cursor_set_attributes( + struct hubp *hubp, + const struct dc_cursor_attributes *attr) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch); + enum cursor_lines_per_chunk lpc = hubp2_get_lines_per_chunk( + attr->width, attr->color_format); + + hubp->curs_attr = *attr; + + REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH, + CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part); + REG_UPDATE(CURSOR_SURFACE_ADDRESS, + CURSOR_SURFACE_ADDRESS, attr->address.low_part); + + REG_UPDATE_2(CURSOR_SIZE, + CURSOR_WIDTH, attr->width, + CURSOR_HEIGHT, attr->height); + + REG_UPDATE_4(CURSOR_CONTROL, + CURSOR_MODE, attr->color_format, + CURSOR_2X_MAGNIFY, attr->attribute_flags.bits.ENABLE_MAGNIFICATION, + CURSOR_PITCH, hw_pitch, + CURSOR_LINES_PER_CHUNK, lpc); + + REG_SET_2(CURSOR_SETTINGS, 0, + /* no shift of the cursor HDL schedule */ + CURSOR0_DST_Y_OFFSET, 0, + /* used to shift the cursor chunk request deadline */ + CURSOR0_CHUNK_HDL_ADJUST, 3); +} + +void hubp2_dmdata_set_attributes( + struct hubp *hubp, + const struct dc_dmdata_attributes *attr) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + if (attr->dmdata_mode == DMDATA_HW_MODE) { + /* set to HW mode */ + REG_UPDATE(DMDATA_CNTL, + DMDATA_MODE, 1); + + /* for DMDATA flip, need to use SURFACE_UPDATE_LOCK */ + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_UPDATE_LOCK, 1); + + /* toggle DMDATA_UPDATED and set repeat and size */ + REG_UPDATE(DMDATA_CNTL, + DMDATA_UPDATED, 0); + REG_UPDATE_3(DMDATA_CNTL, + DMDATA_UPDATED, 1, + DMDATA_REPEAT, attr->dmdata_repeat, + DMDATA_SIZE, attr->dmdata_size); + + /* set DMDATA address */ + REG_WRITE(DMDATA_ADDRESS_LOW, attr->address.low_part); + REG_UPDATE(DMDATA_ADDRESS_HIGH, + DMDATA_ADDRESS_HIGH, attr->address.high_part); + + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_UPDATE_LOCK, 0); + + } else { + /* set to SW mode before loading data */ + REG_SET(DMDATA_CNTL, 0, + DMDATA_MODE, 0); + /* toggle DMDATA_SW_UPDATED to start loading sequence */ + REG_UPDATE(DMDATA_SW_CNTL, + DMDATA_SW_UPDATED, 0); + REG_UPDATE_3(DMDATA_SW_CNTL, + DMDATA_SW_UPDATED, 1, + DMDATA_SW_REPEAT, attr->dmdata_repeat, + DMDATA_SW_SIZE, attr->dmdata_size); + /* load data into hubp dmdata buffer */ + hubp2_dmdata_load(hubp, attr->dmdata_size, attr->dmdata_sw_data); + } + + /* Note that DL_DELTA must be programmed if we want to use TTU mode */ + REG_SET_3(DMDATA_QOS_CNTL, 0, + DMDATA_QOS_MODE, attr->dmdata_qos_mode, + DMDATA_QOS_LEVEL, attr->dmdata_qos_level, + DMDATA_DL_DELTA, attr->dmdata_dl_delta); +} + +void hubp2_dmdata_load( + struct hubp *hubp, + uint32_t dmdata_sw_size, + const uint32_t *dmdata_sw_data) +{ + int i; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + /* load dmdata into HUBP buffer in SW mode */ + for (i = 0; i < dmdata_sw_size / 4; i++) + REG_WRITE(DMDATA_SW_DATA, dmdata_sw_data[i]); +} + +bool hubp2_dmdata_status_done(struct hubp *hubp) +{ + uint32_t status; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_GET(DMDATA_STATUS, DMDATA_DONE, &status); + return (status == 1); +} + +bool hubp2_program_surface_flip_and_addr( + struct hubp *hubp, + const struct dc_plane_address *address, + bool flip_immediate) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + //program flip type + REG_UPDATE(DCSURF_FLIP_CONTROL, + SURFACE_FLIP_TYPE, flip_immediate); + + // Program VMID reg + REG_UPDATE(VMID_SETTINGS_0, + VMID, address->vmid); + + if (address->type == PLN_ADDR_TYPE_GRPH_STEREO) { + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x1); + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x1); + + } else { + // turn off stereo if not in stereo + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x0); + REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x0); + } + + + + /* HW automatically latch rest of address register on write to + * DCSURF_PRIMARY_SURFACE_ADDRESS if SURFACE_UPDATE_LOCK is not used + * + * program high first and then the low addr, order matters! + */ + switch (address->type) { + case PLN_ADDR_TYPE_GRAPHICS: + /* DCN1.0 does not support const color + * TODO: program DCHUBBUB_RET_PATH_DCC_CFGx_0/1 + * base on address->grph.dcc_const_color + * x = 0, 2, 4, 6 for pipe 0, 1, 2, 3 for rgb and luma + * x = 1, 3, 5, 7 for pipe 0, 1, 2, 3 for chroma + */ + + if (address->grph.addr.quad_part == 0) + break; + + REG_UPDATE_2(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface); + + if (address->grph.meta_addr.quad_part != 0) { + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->grph.meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->grph.meta_addr.low_part); + } + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->grph.addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->grph.addr.low_part); + break; + case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: + if (address->video_progressive.luma_addr.quad_part == 0 + || address->video_progressive.chroma_addr.quad_part == 0) + break; + + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_SURFACE_TMZ_C, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface); + + if (address->video_progressive.luma_meta_addr.quad_part != 0) { + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH_C, + address->video_progressive.chroma_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, 0, + PRIMARY_META_SURFACE_ADDRESS_C, + address->video_progressive.chroma_meta_addr.low_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->video_progressive.luma_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->video_progressive.luma_meta_addr.low_part); + } + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0, + PRIMARY_SURFACE_ADDRESS_HIGH_C, + address->video_progressive.chroma_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_C, 0, + PRIMARY_SURFACE_ADDRESS_C, + address->video_progressive.chroma_addr.low_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->video_progressive.luma_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->video_progressive.luma_addr.low_part); + break; + case PLN_ADDR_TYPE_GRPH_STEREO: + if (address->grph_stereo.left_addr.quad_part == 0) + break; + if (address->grph_stereo.right_addr.quad_part == 0) + break; + + REG_UPDATE_8(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface, + PRIMARY_SURFACE_TMZ_C, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ, address->tmz_surface, + PRIMARY_META_SURFACE_TMZ_C, address->tmz_surface, + SECONDARY_SURFACE_TMZ, address->tmz_surface, + SECONDARY_SURFACE_TMZ_C, address->tmz_surface, + SECONDARY_META_SURFACE_TMZ, address->tmz_surface, + SECONDARY_META_SURFACE_TMZ_C, address->tmz_surface); + + if (address->grph_stereo.right_meta_addr.quad_part != 0) { + + REG_SET(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, 0, + SECONDARY_META_SURFACE_ADDRESS_HIGH, + address->grph_stereo.right_meta_addr.high_part); + + REG_SET(DCSURF_SECONDARY_META_SURFACE_ADDRESS, 0, + SECONDARY_META_SURFACE_ADDRESS, + address->grph_stereo.right_meta_addr.low_part); + } + if (address->grph_stereo.left_meta_addr.quad_part != 0) { + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->grph_stereo.left_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->grph_stereo.left_meta_addr.low_part); + } + + REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, 0, + SECONDARY_SURFACE_ADDRESS_HIGH, + address->grph_stereo.right_addr.high_part); + + REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS, 0, + SECONDARY_SURFACE_ADDRESS, + address->grph_stereo.right_addr.low_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->grph_stereo.left_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->grph_stereo.left_addr.low_part); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + hubp->request_address = *address; + + return true; +} + +void hubp2_enable_triplebuffer( + struct hubp *hubp, + bool enable) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t triple_buffer_en = 0; + bool tri_buffer_en; + + REG_GET(DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, &triple_buffer_en); + tri_buffer_en = (triple_buffer_en == 1); + if (tri_buffer_en != enable) { + REG_UPDATE(DCSURF_FLIP_CONTROL2, + SURFACE_TRIPLE_BUFFER_ENABLE, enable ? DC_TRIPLEBUFFER_ENABLE : DC_TRIPLEBUFFER_DISABLE); + } +} + +bool hubp2_is_triplebuffer_enabled( + struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t triple_buffer_en = 0; + + REG_GET(DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, &triple_buffer_en); + + return (bool)triple_buffer_en; +} + +void hubp2_set_flip_control_surface_gsl(struct hubp *hubp, bool enable) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, enable ? 1 : 0); +} + +static struct hubp_funcs dcn20_hubp_funcs = { + .hubp_enable_tripleBuffer = hubp2_enable_triplebuffer, + .hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled, + .hubp_program_surface_flip_and_addr = hubp2_program_surface_flip_and_addr, + .hubp_program_surface_config = hubp2_program_surface_config, + .hubp_is_flip_pending = hubp1_is_flip_pending, + .hubp_setup = hubp2_setup, + .hubp_setup_interdependent = hubp2_setup_interdependent, + .hubp_set_vm_system_aperture_settings = hubp2_set_vm_system_aperture_settings, + .set_blank = hubp1_set_blank, + .dcc_control = hubp1_dcc_control, + .hubp_update_dchub = hubp2_update_dchub, + .mem_program_viewport = min_set_viewport, + .set_cursor_attributes = hubp2_cursor_set_attributes, + .set_cursor_position = hubp1_cursor_set_position, + .hubp_clk_cntl = hubp1_clk_cntl, + .hubp_vtg_sel = hubp1_vtg_sel, + .dmdata_set_attributes = hubp2_dmdata_set_attributes, + .dmdata_load = hubp2_dmdata_load, + .dmdata_status_done = hubp2_dmdata_status_done, + .hubp_read_state = hubp1_read_state, + .hubp_clear_underflow = hubp1_clear_underflow, + .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, + .hubp_init = hubp1_init, +}; + + +bool hubp2_construct( + struct dcn20_hubp *hubp2, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_hubp2_registers *hubp_regs, + const struct dcn_hubp2_shift *hubp_shift, + const struct dcn_hubp2_mask *hubp_mask) +{ + hubp2->base.funcs = &dcn20_hubp_funcs; + hubp2->base.ctx = ctx; + hubp2->hubp_regs = hubp_regs; + hubp2->hubp_shift = hubp_shift; + hubp2->hubp_mask = hubp_mask; + hubp2->base.inst = inst; + hubp2->base.opp_id = OPP_ID_INVALID; + hubp2->base.mpcc_id = 0xf; + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h new file mode 100644 index 000000000000..d5acc348be22 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h @@ -0,0 +1,277 @@ +/* + * Copyright 2012-17 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 __DC_MEM_INPUT_DCN20_H__ +#define __DC_MEM_INPUT_DCN20_H__ + +#include "../dcn10/dcn10_hubp.h" + +#define TO_DCN20_HUBP(hubp)\ + container_of(hubp, struct dcn20_hubp, base) + +#define HUBP_REG_LIST_DCN2_COMMON(id)\ + HUBP_REG_LIST_DCN(id),\ + HUBP_REG_LIST_DCN_VM(id),\ + SRI(PREFETCH_SETTINGS, HUBPREQ, id),\ + SRI(PREFETCH_SETTINGS_C, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, HUBPREQ, id),\ + SR(DCN_VM_FB_LOCATION_TOP),\ + SR(DCN_VM_FB_LOCATION_BASE),\ + SR(DCN_VM_FB_OFFSET),\ + SR(DCN_VM_AGP_BASE),\ + SR(DCN_VM_AGP_BOT),\ + SR(DCN_VM_AGP_TOP),\ + SRI(CURSOR_SETTINGS, HUBPREQ, id), \ + SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \ + SRI(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \ + SRI(CURSOR_SIZE, CURSOR0_, id), \ + SRI(CURSOR_CONTROL, CURSOR0_, id), \ + SRI(CURSOR_POSITION, CURSOR0_, id), \ + SRI(CURSOR_HOT_SPOT, CURSOR0_, id), \ + SRI(CURSOR_DST_OFFSET, CURSOR0_, id), \ + SRI(DMDATA_ADDRESS_HIGH, CURSOR0_, id), \ + SRI(DMDATA_ADDRESS_LOW, CURSOR0_, id), \ + SRI(DMDATA_CNTL, CURSOR0_, id), \ + SRI(DMDATA_SW_CNTL, CURSOR0_, id), \ + SRI(DMDATA_QOS_CNTL, CURSOR0_, id), \ + SRI(DMDATA_SW_DATA, CURSOR0_, id), \ + SRI(DMDATA_STATUS, CURSOR0_, id),\ + SRI(FLIP_PARAMETERS_0, HUBPREQ, id),\ + SRI(FLIP_PARAMETERS_1, HUBPREQ, id),\ + SRI(FLIP_PARAMETERS_2, HUBPREQ, id),\ + SRI(DCN_CUR1_TTU_CNTL0, HUBPREQ, id),\ + SRI(DCN_CUR1_TTU_CNTL1, HUBPREQ, id),\ + SRI(DCSURF_FLIP_CONTROL2, HUBPREQ, id), \ + SRI(VMID_SETTINGS_0, HUBPREQ, id) + +#define HUBP_REG_LIST_DCN20(id)\ + HUBP_REG_LIST_DCN2_COMMON(id),\ + SR(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB),\ + SR(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB) + +#define HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN(mask_sh),\ + HUBP_MASK_SH_LIST_DCN_VM(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, DST_Y_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, VRATIO_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS_C, VRATIO_PREFETCH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR, MC_VM_SYSTEM_APERTURE_LOW_ADDR, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, MC_VM_SYSTEM_APERTURE_HIGH_ADDR, mask_sh),\ + HUBP_SF(DCN_VM_FB_LOCATION_TOP, FB_TOP, mask_sh),\ + HUBP_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE, mask_sh),\ + HUBP_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh),\ + HUBP_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh),\ + HUBP_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh),\ + HUBP_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh),\ + HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \ + HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + HUBP_SF(CURSOR0_0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_ADDRESS_HIGH, DMDATA_ADDRESS_HIGH, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_UPDATED, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_REPEAT, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_SIZE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_UPDATED, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_REPEAT, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_SIZE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_QOS_MODE, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_QOS_LEVEL, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_DL_DELTA, mask_sh), \ + HUBP_SF(CURSOR0_0_DMDATA_STATUS, DMDATA_DONE, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_VM_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_ROW_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_1, REFCYC_PER_PTE_GROUP_FLIP_L, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_2, REFCYC_PER_META_CHUNK_FLIP_L, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE_STOP_DATA_DURING_VM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, HUBPREQ_MASTER_UPDATE_LOCK_STATUS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_VMID_SETTINGS_0, VMID, mask_sh) + +#define HUBP_MASK_SH_LIST_DCN20(mask_sh)\ + HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh),\ + HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, mask_sh),\ + HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mask_sh),\ + HUBP_SF(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mask_sh) + + +#define DCN2_HUBP_REG_COMMON_VARIABLE_LIST \ + HUBP_COMMON_REG_VARIABLE_LIST; \ + uint32_t DMDATA_ADDRESS_HIGH; \ + uint32_t DMDATA_ADDRESS_LOW; \ + uint32_t DMDATA_CNTL; \ + uint32_t DMDATA_SW_CNTL; \ + uint32_t DMDATA_QOS_CNTL; \ + uint32_t DMDATA_SW_DATA; \ + uint32_t DMDATA_STATUS;\ + uint32_t DCSURF_FLIP_CONTROL2;\ + uint32_t FLIP_PARAMETERS_0;\ + uint32_t FLIP_PARAMETERS_1;\ + uint32_t FLIP_PARAMETERS_2;\ + uint32_t DCN_CUR1_TTU_CNTL0;\ + uint32_t DCN_CUR1_TTU_CNTL1;\ + uint32_t VMID_SETTINGS_0;\ + uint32_t FLIP_PARAMETERS_3;\ + uint32_t FLIP_PARAMETERS_4;\ + uint32_t VBLANK_PARAMETERS_5;\ + uint32_t VBLANK_PARAMETERS_6 + +#define DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type) \ + DCN_HUBP_REG_FIELD_LIST(type); \ + type DMDATA_ADDRESS_HIGH;\ + type DMDATA_MODE;\ + type DMDATA_UPDATED;\ + type DMDATA_REPEAT;\ + type DMDATA_SIZE;\ + type DMDATA_SW_UPDATED;\ + type DMDATA_SW_REPEAT;\ + type DMDATA_SW_SIZE;\ + type DMDATA_QOS_MODE;\ + type DMDATA_QOS_LEVEL;\ + type DMDATA_DL_DELTA;\ + type DMDATA_DONE;\ + type DST_Y_PER_VM_FLIP;\ + type DST_Y_PER_ROW_FLIP;\ + type REFCYC_PER_PTE_GROUP_FLIP_L;\ + type REFCYC_PER_META_CHUNK_FLIP_L;\ + type HUBP_VREADY_AT_OR_AFTER_VSYNC;\ + type HUBP_DISABLE_STOP_DATA_DURING_VM;\ + type HUBPREQ_MASTER_UPDATE_LOCK_STATUS;\ + type SURFACE_GSL_ENABLE;\ + type SURFACE_TRIPLE_BUFFER_ENABLE;\ + type VMID + + +struct dcn_hubp2_registers { + DCN2_HUBP_REG_COMMON_VARIABLE_LIST; +}; + +struct dcn_hubp2_shift { + DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); +}; + +struct dcn_hubp2_mask { + DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); +}; + +struct dcn20_hubp { + struct hubp base; + struct dcn_hubp_state state; + const struct dcn_hubp2_registers *hubp_regs; + const struct dcn_hubp2_shift *hubp_shift; + const struct dcn_hubp2_mask *hubp_mask; +}; + +bool hubp2_construct( + struct dcn20_hubp *hubp2, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_hubp2_registers *hubp_regs, + const struct dcn_hubp2_shift *hubp_shift, + const struct dcn_hubp2_mask *hubp_mask); + +void hubp2_setup_interdependent( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr); + +void hubp2_vready_at_or_After_vsync(struct hubp *hubp, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); + +void hubp2_update_dchub( + struct hubp *hubp, + struct dchub_init_data *dh_data); + +void hubp2_cursor_set_attributes( + struct hubp *hubp, + const struct dc_cursor_attributes *attr); + +void hubp2_set_vm_system_aperture_settings(struct hubp *hubp, + struct vm_system_aperture_param *apt); + +enum cursor_lines_per_chunk hubp2_get_lines_per_chunk( + unsigned int cursor_width, + enum dc_cursor_color_format cursor_mode); + +void hubp2_dmdata_set_attributes( + struct hubp *hubp, + const struct dc_dmdata_attributes *attr); + +void hubp2_dmdata_load( + struct hubp *hubp, + uint32_t dmdata_sw_size, + const uint32_t *dmdata_sw_data); + +bool hubp2_dmdata_status_done(struct hubp *hubp); + +void hubp2_enable_triplebuffer( + struct hubp *hubp, + bool enable); + +bool hubp2_is_triplebuffer_enabled( + struct hubp *hubp); + +void hubp2_set_flip_control_surface_gsl(struct hubp *hubp, bool enable); + +void hubp2_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr); + +bool hubp2_program_surface_flip_and_addr( + struct hubp *hubp, + const struct dc_plane_address *address, + bool flip_immediate); + +void hubp2_program_surface_config( + struct hubp *hubp, + enum surface_pixel_format format, + union dc_tiling_info *tiling_info, + union plane_size *plane_size, + enum dc_rotation_angle rotation, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror, + unsigned int compat_level); + +#endif /* __DC_MEM_INPUT_DCN20_H__ */ + + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c new file mode 100644 index 000000000000..0b84a322b8a2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -0,0 +1,2033 @@ +/* + * Copyright 2016 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 <linux/delay.h> + +#include "dm_services.h" +#include "dm_helpers.h" +#include "core_types.h" +#include "resource.h" +#include "dcn20/dcn20_resource.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_hw_sequencer.h" +#include "dcn20_hwseq.h" +#include "dce/dce_hwseq.h" +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dcn20/dcn20_dsc.h" +#endif +#include "abm.h" +#include "clk_mgr.h" +#include "dmcu.h" +#include "hubp.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "mcif_wb.h" +#include "reg_helper.h" +#include "dcn10/dcn10_cm_common.h" +#include "dcn10/dcn10_hubbub.h" +#include "dcn10/dcn10_optc.h" +#include "dc_link_dp.h" +#include "vm_helper.h" +#include "dccg.h" + +#define DC_LOGGER_INIT(logger) + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +static void bios_golden_init(struct dc *dc) +{ + struct dc_bios *bp = dc->ctx->dc_bios; + int i; + + /* initialize dcn global */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0, ASIC_PIPE_INIT); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + /* initialize dcn per pipe */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); + } +} + +static void enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = 1; /* disable power gating */ + + if (enable) + force_on = 0; + + /* DCHUBP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); + /*Do not power gate DCHUB5, should be left at HW default, power on permanently*/ + /*REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN10_POWER_FORCEON, force_on);*/ + + /* DPP0/1/2/3/4/5 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + /*Do not power gate DPP5, should be left at HW default, power on permanently*/ + /*REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN11_POWER_FORCEON, force_on);*/ + + REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN16_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN17_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN18_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); +} + +static void dcn20_dccg_init(struct dce_hwseq *hws) +{ + /* + * set MICROSECOND_TIME_BASE_DIV + * 100Mhz refclk -> 0x120264 + * 27Mhz refclk -> 0x12021b + * 48Mhz refclk -> 0x120230 + * + */ + REG_WRITE(MICROSECOND_TIME_BASE_DIV, 0x120264); + + /* + * set MILLISECOND_TIME_BASE_DIV + * 100Mhz refclk -> 0x1186a0 + * 27Mhz refclk -> 0x106978 + * 48Mhz refclk -> 0x10bb80 + * + */ + REG_WRITE(MILLISECOND_TIME_BASE_DIV, 0x1186a0); + + /* This value is dependent on the hardware pipeline delay so set once per SOC */ + REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); +} + +static void disable_vga( + struct dce_hwseq *hws) +{ + REG_WRITE(D1VGA_CONTROL, 0); + REG_WRITE(D2VGA_CONTROL, 0); + REG_WRITE(D3VGA_CONTROL, 0); + REG_WRITE(D4VGA_CONTROL, 0); + REG_WRITE(D5VGA_CONTROL, 0); + REG_WRITE(D6VGA_CONTROL, 0); +} + +void dcn20_program_tripleBuffer( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enableTripleBuffer) +{ + if (pipe_ctx->plane_res.hubp && pipe_ctx->plane_res.hubp->funcs) { + pipe_ctx->plane_res.hubp->funcs->hubp_enable_tripleBuffer( + pipe_ctx->plane_res.hubp, + enableTripleBuffer); + } +} + +/* Blank pixel data during initialization */ +static void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg) +{ + enum dc_color_space color_space; + struct tg_color black_color = {0}; + struct output_pixel_processor *opp = NULL; + struct output_pixel_processor *bottom_opp = NULL; + uint32_t num_opps, opp_id_src0, opp_id_src1; + uint32_t otg_active_width, otg_active_height; + + /* program opp dpg blank color */ + color_space = COLOR_SPACE_SRGB; + color_space_to_black_color(dc, color_space, &black_color); + + /* get the OTG active size */ + tg->funcs->get_otg_active_size(tg, + &otg_active_width, + &otg_active_height); + + /* get the OPTC source */ + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); + ASSERT(opp_id_src0 < dc->res_pool->res_cap->num_opp); + opp = dc->res_pool->opps[opp_id_src0]; + + if (num_opps == 2) { + otg_active_width = otg_active_width / 2; + ASSERT(opp_id_src1 < dc->res_pool->res_cap->num_opp); + bottom_opp = dc->res_pool->opps[opp_id_src1]; + } + + opp->funcs->opp_set_disp_pattern_generator( + opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height); + + if (num_opps == 2) { + bottom_opp->funcs->opp_set_disp_pattern_generator( + bottom_opp, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR, + COLOR_DEPTH_UNDEFINED, + &black_color, + otg_active_width, + otg_active_height); + } + + dcn20_hwss_wait_for_blank_complete(opp); +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +static void dcn20_dsc_pg_control( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + uint32_t org_ip_request_cntl = 0; + + if (hws->ctx->dc->debug.disable_dsc_power_gate) + return; + + if (REG(DOMAIN16_PG_CONFIG) == 0) + return; + + REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); + + switch (dsc_inst) { + case 0: /* DSC0 */ + REG_UPDATE(DOMAIN16_PG_CONFIG, + DOMAIN16_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN16_PG_STATUS, + DOMAIN16_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DSC1 */ + REG_UPDATE(DOMAIN17_PG_CONFIG, + DOMAIN17_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN17_PG_STATUS, + DOMAIN17_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DSC2 */ + REG_UPDATE(DOMAIN18_PG_CONFIG, + DOMAIN18_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN18_PG_STATUS, + DOMAIN18_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DSC3 */ + REG_UPDATE(DOMAIN19_PG_CONFIG, + DOMAIN19_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN19_PG_STATUS, + DOMAIN19_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DSC4 */ + REG_UPDATE(DOMAIN20_PG_CONFIG, + DOMAIN20_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN20_PG_STATUS, + DOMAIN20_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DSC5 */ + REG_UPDATE(DOMAIN21_PG_CONFIG, + DOMAIN21_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN21_PG_STATUS, + DOMAIN21_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + if (org_ip_request_cntl == 0) + REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); +} +#endif + +static void dcn20_dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_dpp_power_gate) + return; + if (REG(DOMAIN1_PG_CONFIG) == 0) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DPP4 */ + REG_UPDATE(DOMAIN9_PG_CONFIG, + DOMAIN9_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN9_PG_STATUS, + DOMAIN9_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DPP5 */ + /* + * Do not power gate DPP5, should be left at HW default, power on permanently. + * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard + * reset. + * REG_UPDATE(DOMAIN11_PG_CONFIG, + * DOMAIN11_POWER_GATE, power_gate); + * + * REG_WAIT(DOMAIN11_PG_STATUS, + * DOMAIN11_PGFSM_PWR_STATUS, pwr_status, + * 1, 1000); + */ + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + + +static void dcn20_hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + if (REG(DOMAIN0_PG_CONFIG) == 0) + return; + + switch (hubp_inst) { + case 0: /* DCHUBP0 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, + DOMAIN0_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN0_PG_STATUS, + DOMAIN0_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DCHUBP1 */ + REG_UPDATE(DOMAIN2_PG_CONFIG, + DOMAIN2_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN2_PG_STATUS, + DOMAIN2_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DCHUBP2 */ + REG_UPDATE(DOMAIN4_PG_CONFIG, + DOMAIN4_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN4_PG_STATUS, + DOMAIN4_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DCHUBP3 */ + REG_UPDATE(DOMAIN6_PG_CONFIG, + DOMAIN6_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN6_PG_STATUS, + DOMAIN6_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 4: /* DCHUBP4 */ + REG_UPDATE(DOMAIN8_PG_CONFIG, + DOMAIN8_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN8_PG_STATUS, + DOMAIN8_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 5: /* DCHUBP5 */ + /* + * Do not power gate DCHUB5, should be left at HW default, power on permanently. + * PG on Pipe5 is De-featured, attempting to put it to PG state may result in hard + * reset. + * REG_UPDATE(DOMAIN10_PG_CONFIG, + * DOMAIN10_POWER_GATE, power_gate); + * + * REG_WAIT(DOMAIN10_PG_STATUS, + * DOMAIN10_PGFSM_PWR_STATUS, pwr_status, + * 1, 1000); + */ + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + + + +static void dcn20_plane_atomic_power_down(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + dcn20_dpp_pg_control(hws, dpp->inst, false); + dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, false); + dpp->funcs->dpp_reset(dpp); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + DC_LOG_DEBUG( + "Power gated front end %d\n", pipe_ctx->pipe_idx); + } +} + + + +/* disable HW used by plane. + * note: cannot disable until disconnect is complete + */ +static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + + /* In flip immediate with pipe splitting case GSL is used for + * synchronization so we must disable it when the plane is disabled. + */ + if (pipe_ctx->stream_res.gsl_group != 0) + dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false); + + dc->hwss.set_flip_control_gsl(pipe_ctx, false); + + hubp->funcs->hubp_clk_cntl(hubp, false); + + dpp->funcs->dpp_dppclk_control(dpp, false, false); + + hubp->power_gated = true; + dc->optimized_required = false; /* We're powering off, no need to optimize */ + + dcn20_plane_atomic_power_down(dc, pipe_ctx); + + pipe_ctx->stream = NULL; + memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); + memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->plane_state = NULL; +} + + +void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + DC_LOGGER_INIT(dc->ctx->logger); + + if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) + return; + + dcn20_plane_atomic_disable(dc, pipe_ctx); + + DC_LOG_DC("Power down front end %d\n", + pipe_ctx->pipe_idx); +} + +static void dcn20_init_hw(struct dc *dc) +{ + int i, j; + 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 resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + struct dc_firmware_info fw_info = { { 0 } }; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (res_pool->dccg->funcs->dccg_init) + res_pool->dccg->funcs->dccg_init(res_pool->dccg); + + //Enable ability to power gate / don't force power on permanently + enable_power_gating_plane(dc->hwseq, true); + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); + + dcn20_dccg_init(hws); + + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, 2); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(REFCLK_CNTL, 0); + } else { + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bios_golden_init(dc); + if (dc->ctx->dc_bios->funcs->get_firmware_info( + dc->ctx->dc_bios, &fw_info) == BP_RESULT_OK) { + res_pool->ref_clocks.xtalin_clock_inKhz = fw_info.pll_info.crystal_frequency; + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (res_pool->dccg && res_pool->hubbub) { + + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + fw_info.pll_info.crystal_frequency, + &res_pool->ref_clocks.dccg_ref_clock_inKhz); + + (res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub, + res_pool->ref_clocks.dccg_ref_clock_inKhz, + &res_pool->ref_clocks.dchub_ref_clock_inKhz); + } else { + // Not all ASICs have DCCG sw component + res_pool->ref_clocks.dccg_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + res_pool->ref_clocks.dchub_ref_clock_inKhz = + res_pool->ref_clocks.xtalin_clock_inKhz; + } + } + } else + ASSERT_CRITICAL(false); + 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]; + + link->link_enc->funcs->hw_init(link->link_enc); + } + } + + /* Blank pixel data with OPP DPG */ + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) { + dcn20_init_blank(dc, tg); + } + } + + for (i = 0; i < res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->lock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct dpp *dpp = res_pool->dpps[i]; + + dpp->funcs->dpp_reset(dpp); + } + + /* Reset all MPCC muxes */ + res_pool->mpc->funcs->mpc_init(res_pool->mpc); + + /* initialize OPP mpc_tree parameter */ + for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) { + res_pool->opps[i]->mpc_tree_params.opp_id = res_pool->opps[i]->inst; + res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + for (j = 0; j < MAX_PIPES; j++) + res_pool->opps[i]->mpcc_disconnect_pending[j] = false; + } + + 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]; + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + pipe_ctx->plane_res.dpp = dpp; + pipe_ctx->plane_res.mpcc_inst = dpp->inst; + hubp->mpcc_id = dpp->inst; + hubp->opp_id = OPP_ID_INVALID; + hubp->power_gated = false; + pipe_ctx->stream_res.opp = NULL; + + hubp->funcs->hubp_init(hubp); + + //dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + //dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + /*to do*/ + hwss1_plane_atomic_disconnect(dc, pipe_ctx); + } + + /* initialize DWB pointer to MCIF_WB */ + for (i = 0; i < res_pool->res_cap->num_dwb; i++) + res_pool->dwbc[i]->mcif = res_pool->mcif_wb[i]; + + for (i = 0; i < dc->res_pool->timing_generator_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 pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dc->hwss.disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + } + + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + tg->funcs->tg_init(tg); + } + + /* end of FPGA. Below if real ASIC */ + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + return; + + + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + if (abm != NULL) { + abm->funcs->init_backlight(abm); + abm->funcs->abm_init(abm); + } + + if (dmcu != NULL) + dmcu->funcs->dmcu_init(dmcu); + + if (abm != NULL && dmcu != NULL) + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + 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); + } + +} + +enum dc_status dcn20_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct drr_params params = {0}; + unsigned int event_triggers = 0; + + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); +#endif + + /* 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 + * with pipe 0. No program is needed. + */ + if (pipe_ctx->top_pipe != NULL) + return DC_OK; + + /* TODO check if timing_changed, disable stream if timing changed */ + + if (odm_pipe) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + odm_pipe->stream_res.opp->inst, + pipe_ctx->stream->timing.h_addressable/2, + pipe_ctx->stream->timing.pixel_encoding); + /* HW program guide assume display already disable + * by unplug sequence. OTG assume stop. + */ + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); + + if (false == pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + pipe_ctx->stream_res.tg->funcs->program_timing( + pipe_ctx->stream_res.tg, + &stream->timing, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width, + pipe_ctx->stream->signal, + true); + + if (pipe_ctx->stream_res.tg->funcs->setup_global_lock) + pipe_ctx->stream_res.tg->funcs->setup_global_lock( + pipe_ctx->stream_res.tg); + + if (odm_pipe) + odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( + odm_pipe->stream_res.opp, + true); + + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + + dc->hwss.blank_pixel_data(dc, pipe_ctx, true); + + /* VTG is within DCHUB command block. DCFCLK is always on */ + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + dcn20_hwss_wait_for_blank_complete(pipe_ctx->stream_res.opp); + + 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 */ + /* TODO set stream attributes */ + /* TODO program audio */ + /* TODO enable stream if timing changed */ + /* TODO unblank stream if DP */ + + return DC_OK; +} + +void dcn20_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + struct mpc *mpc = dc->res_pool->mpc; + enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; + + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + if (mpc->funcs->set_output_csc != NULL) + mpc->funcs->set_output_csc(mpc, + opp_id, + matrix, + ocsc_mode); + } else { + if (mpc->funcs->set_ocsc_default != NULL) + mpc->funcs->set_ocsc_default(mpc, + opp_id, + colorspace, + ocsc_mode); + } +} + +bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc; + struct pwl_params *params = NULL; + /* + * program OGAM only for the top pipe + * if there is a pipe split then fix diagnostic is required: + * how to pass OGAM parameter for stream. + * if programming for all pipes is required then remove condition + * pipe_ctx->top_pipe == NULL ,but then fix the diagnostic. + */ + if ((pipe_ctx->top_pipe == NULL || dc_res_is_odm_head_pipe(pipe_ctx)) + && mpc->funcs->set_output_gamma && stream->out_transfer_func) { + if (stream->out_transfer_func->type == TF_TYPE_HWPWL) + params = &stream->out_transfer_func->pwl; + else if (pipe_ctx->stream->out_transfer_func->type == + TF_TYPE_DISTRIBUTED_POINTS && + cm_helper_translate_curve_to_hw_format( + stream->out_transfer_func, + &mpc->blender_params, false)) + params = &mpc->blender_params; + /* + * there is no ROM + */ + if (stream->out_transfer_func->type == TF_TYPE_PREDEFINED) + BREAK_TO_DEBUGGER(); + } + /* + * if above if is not executed then 'params' equal to 0 and set in bypass + */ + mpc->funcs->set_output_gamma(mpc, mpcc_id, params); + + return true; +} + +static bool dcn20_set_blend_lut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + bool result = true; + struct pwl_params *blend_lut = NULL; + + if (plane_state->blend_tf) { + if (plane_state->blend_tf->type == TF_TYPE_HWPWL) + blend_lut = &plane_state->blend_tf->pwl; + else if (plane_state->blend_tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format( + plane_state->blend_tf, + &dpp_base->regamma_params, false); + blend_lut = &dpp_base->regamma_params; + } + } + result = dpp_base->funcs->dpp_program_blnd_lut(dpp_base, blend_lut); + + return result; +} + +static bool dcn20_set_shaper_3dlut( + struct pipe_ctx *pipe_ctx, const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + bool result = true; + struct pwl_params *shaper_lut = NULL; + + if (plane_state->in_shaper_func) { + if (plane_state->in_shaper_func->type == TF_TYPE_HWPWL) + shaper_lut = &plane_state->in_shaper_func->pwl; + else if (plane_state->in_shaper_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_hw_format( + plane_state->in_shaper_func, + &dpp_base->shaper_params, true); + shaper_lut = &dpp_base->shaper_params; + } + } + + result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); + if (plane_state->lut3d_func && + plane_state->lut3d_func->initialized == true) + result = dpp_base->funcs->dpp_program_3dlut(dpp_base, + &plane_state->lut3d_func->lut_3d); + else + result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); + + if (plane_state->lut3d_func && + plane_state->lut3d_func->initialized == true && + plane_state->lut3d_func->hdr_multiplier != 0) + dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, + plane_state->lut3d_func->hdr_multiplier); + else + dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, 0x1f000); + + return result; +} + +bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + const struct dc_transfer_func *tf = NULL; + bool result = true; + bool use_degamma_ram = false; + + if (dpp_base == NULL || plane_state == NULL) + return false; + + dcn20_set_shaper_3dlut(pipe_ctx, plane_state); + dcn20_set_blend_lut(pipe_ctx, plane_state); + + if (plane_state->in_transfer_func) + tf = plane_state->in_transfer_func; + + + if (tf == NULL) { + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + return true; + } + + if (tf->type == TF_TYPE_HWPWL || tf->type == TF_TYPE_DISTRIBUTED_POINTS) + use_degamma_ram = true; + + if (use_degamma_ram == true) { + if (tf->type == TF_TYPE_HWPWL) + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &tf->pwl); + else if (tf->type == TF_TYPE_DISTRIBUTED_POINTS) { + cm_helper_translate_curve_to_degamma_hw_format(tf, + &dpp_base->degamma_params); + dpp_base->funcs->dpp_program_degamma_pwl(dpp_base, + &dpp_base->degamma_params); + } + return true; + } + /* handle here the optimized cases when de-gamma ROM could be used. + * + */ + if (tf->type == TF_TYPE_PREDEFINED) { + switch (tf->tf) { + case TRANSFER_FUNCTION_SRGB: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_HW_sRGB); + break; + case TRANSFER_FUNCTION_BT709: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_HW_xvYCC); + break; + case TRANSFER_FUNCTION_LINEAR: + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + break; + case TRANSFER_FUNCTION_PQ: + default: + result = false; + break; + } + } else if (tf->type == TF_TYPE_BYPASS) + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + else { + /* + * if we are here, we did not handle correctly. + * fix is required for this use case + */ + BREAK_TO_DEBUGGER(); + dpp_base->funcs->dpp_set_degamma(dpp_base, + IPP_DEGAMMA_MODE_BYPASS); + } + + return result; +} + +static void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +{ + struct pipe_ctx *combine_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (combine_pipe) + pipe_ctx->stream_res.tg->funcs->set_odm_combine( + pipe_ctx->stream_res.tg, + combine_pipe->stream_res.opp->inst, + pipe_ctx->plane_res.scl_data.h_active, + pipe_ctx->stream->timing.pixel_encoding); + else + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); +} + +void dcn20_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank) +{ + struct tg_color black_color = {0}; + struct stream_resource *stream_res = &pipe_ctx->stream_res; + struct dc_stream_state *stream = pipe_ctx->stream; + enum dc_color_space color_space = stream->output_color_space; + enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; + struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; + int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; + + /* get opp dpg blank color */ + color_space_to_black_color(dc, color_space, &black_color); + + if (bot_odm_pipe) + width = width / 2; + + if (blank) { + if (stream_res->abm) + stream_res->abm->funcs->set_abm_immediate_disable(stream_res->abm); + + if (dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE) + test_pattern = CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; + } else { + test_pattern = CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; + } + + stream_res->opp->funcs->opp_set_disp_pattern_generator( + stream_res->opp, + test_pattern, + stream->timing.display_color_depth, + &black_color, + width, + height); + + if (bot_odm_pipe) { + bot_odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( + bot_odm_pipe->stream_res.opp, + dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ? + CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, + stream->timing.display_color_depth, + &black_color, + width, + height); + } + + if (!blank) + if (stream_res->abm) { + stream_res->abm->funcs->set_pipe(stream_res->abm, stream_res->tg->inst + 1); + stream_res->abm->funcs->set_abm_level(stream_res->abm, stream->abm_level); + } +} + + +static void dcn20_power_on_plane( + struct dce_hwseq *hws, + struct pipe_ctx *pipe_ctx) +{ + DC_LOGGER_INIT(hws->ctx->logger); + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + dcn20_dpp_pg_control(hws, pipe_ctx->plane_res.dpp->inst, true); + dcn20_hubp_pg_control(hws, pipe_ctx->plane_res.hubp->inst, true); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + DC_LOG_DEBUG( + "Un-gated front end for pipe %d\n", pipe_ctx->plane_res.hubp->inst); + } +} + +void dcn20_enable_plane( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + //if (dc->debug.sanity_checks) { + // dcn10_verify_allow_pstate_change_high(dc); + //} + dcn20_power_on_plane(dc->hwseq, pipe_ctx); + + /* enable DCFCLK current DCHUB */ + pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( + pipe_ctx->stream_res.opp, + true); + +/* TODO: enable/disable in dm as per update type. + if (plane_state) { + DC_LOG_DC(dc->ctx->logger, + "Pipe:%d 0x%x: addr hi:0x%x, " + "addr low:0x%x, " + "src: %d, %d, %d," + " %d; dst: %d, %d, %d, %d;\n", + pipe_ctx->pipe_idx, + plane_state, + plane_state->address.grph.addr.high_part, + plane_state->address.grph.addr.low_part, + plane_state->src_rect.x, + plane_state->src_rect.y, + plane_state->src_rect.width, + plane_state->src_rect.height, + plane_state->dst_rect.x, + plane_state->dst_rect.y, + plane_state->dst_rect.width, + plane_state->dst_rect.height); + + DC_LOG_DC(dc->ctx->logger, + "Pipe %d: width, height, x, y format:%d\n" + "viewport:%d, %d, %d, %d\n" + "recout: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + plane_state->format, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y); + print_rq_dlg_ttu(dc, pipe_ctx); + } +*/ + if (dc->vm_pa_config.valid) { + struct vm_system_aperture_param apt; + + apt.sys_default.quad_part = 0; + + apt.sys_high.quad_part = dc->vm_pa_config.system_aperture.start_addr; + apt.sys_low.quad_part = dc->vm_pa_config.system_aperture.end_addr; + + // Program system aperture settings + pipe_ctx->plane_res.hubp->funcs->hubp_set_vm_system_aperture_settings(pipe_ctx->plane_res.hubp, &apt); + } + +// if (dc->debug.sanity_checks) { +// dcn10_verify_allow_pstate_change_high(dc); +// } +} + + +static void dcn20_program_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + pipe_ctx->plane_state->update_flags.bits.full_update = + context->commit_hints.full_update_needed ? 1 : pipe_ctx->plane_state->update_flags.bits.full_update; + + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dcn20_enable_plane(dc, pipe_ctx, context); + + update_dchubp_dpp(dc, pipe_ctx, context); + + set_hdr_multiplier(pipe_ctx); + + if (pipe_ctx->plane_state->update_flags.bits.full_update || + pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || + pipe_ctx->plane_state->update_flags.bits.gamma_change) + dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish + * only do gamma programming for full update. + * TODO: This can be further optimized/cleaned up + * Always call this for now since it does memcmp inside before + * doing heavy calculation and programming + */ + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); +} + +static void dcn20_program_all_pipe_in_tree( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + + if (dc->hwss.update_odm) + dc->hwss.update_odm(dc, context, pipe_ctx); + } + + if (pipe_ctx->plane_state != NULL) + dcn20_program_pipe(dc, pipe_ctx, context); + + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) + dcn20_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); +} + +void dcn20_pipe_control_lock_global( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + if (lock) { + pipe->stream_res.tg->funcs->lock_doublebuffer_enable( + pipe->stream_res.tg); + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + } else { + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, + CRTC_STATE_VACTIVE); + pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, + CRTC_STATE_VBLANK); + pipe->stream_res.tg->funcs->lock_doublebuffer_disable( + pipe->stream_res.tg); + } +} + +void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + bool flip_immediate = false; + + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ + if (pipe->top_pipe) + return; + + if (pipe->plane_state != NULL) + flip_immediate = pipe->plane_state->flip_immediate; + + /* In flip immediate and pipe splitting case, we need to use GSL + * for synchronization. Only do setup on locking and on flip type change. + */ + if (lock && pipe->bottom_pipe != NULL) + if ((flip_immediate && pipe->stream_res.gsl_group == 0) || + (!flip_immediate && pipe->stream_res.gsl_group > 0)) + dcn20_setup_gsl_group_as_lock(dc, pipe, flip_immediate); + + if (pipe->plane_state != NULL && pipe->plane_state->triplebuffer_flips) { + if (lock) + pipe->stream_res.tg->funcs->triplebuffer_lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->triplebuffer_unlock(pipe->stream_res.tg); + } else { + if (lock) + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + } +} + +static void dcn20_apply_ctx_for_surface( + struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, + struct dc_state *context) +{ + + int i; + struct timing_generator *tg; + bool removed_pipe[6] = { false }; + bool interdependent_update = false; + struct pipe_ctx *top_pipe_to_program = + find_top_pipe_for_stream(dc, context, stream); + DC_LOGGER_INIT(dc->ctx->logger); + + if (!top_pipe_to_program) + return; + + tg = top_pipe_to_program->stream_res.tg; + + interdependent_update = top_pipe_to_program->plane_state && + top_pipe_to_program->plane_state->update_flags.bits.full_update; + + if (interdependent_update) + lock_all_pipes(dc, context, true); + else + dcn20_pipe_control_lock(dc, top_pipe_to_program, true); + + if (num_planes == 0) { + /* OTG blank before remove all front end */ + dc->hwss.blank_pixel_data(dc, top_pipe_to_program, true); + } + + /* Disconnect unused mpcc */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + /* + * Powergate reused pipes that are not powergated + * fairly hacky right now, using opp_id as indicator + * TODO: After move dc_post to dc_update, this will + * be removed. + */ + if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { + if (old_pipe_ctx->stream_res.tg == tg && + old_pipe_ctx->plane_res.hubp && + old_pipe_ctx->plane_res.hubp->opp_id != OPP_ID_INVALID) + dcn20_disable_plane(dc, old_pipe_ctx); + } + + 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; + + DC_LOG_DC("Reset mpcc for pipe %d\n", + old_pipe_ctx->pipe_idx); + } + } + + if (num_planes > 0) + dcn20_program_all_pipe_in_tree(dc, top_pipe_to_program, context); + + /* Program secondary blending tree and writeback pipes */ + if ((stream->num_wb_info > 0) && (dc->hwss.program_all_writeback_pipes_in_tree)) + dc->hwss.program_all_writeback_pipes_in_tree(dc, stream, context); + + if (interdependent_update) + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Skip inactive pipes and ones already updated */ + if (!pipe_ctx->stream || pipe_ctx->stream == stream || + !pipe_ctx->plane_state || !tg->funcs->is_tg_enabled(tg)) + continue; + + pipe_ctx->plane_res.hubp->funcs->hubp_setup_interdependent( + pipe_ctx->plane_res.hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs); + } + + if (interdependent_update) + lock_all_pipes(dc, context, false); + else + dcn20_pipe_control_lock(dc, top_pipe_to_program, false); + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (removed_pipe[i]) + dcn20_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); +} + + +void dcn20_prepare_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + + /* program dchubbub watermarks */ + hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + false); + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); +} + +void dcn20_optimize_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + + /* program dchubbub watermarks */ + hubbub->funcs->program_watermarks(hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + true); + + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + true); +} + +bool dcn20_update_bandwidth( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* recalculate DML parameters */ + if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) + return false; + + /* apply updated bandwidth parameters */ + dc->hwss.prepare_bandwidth(dc, context); + + /* update hubp configs for all pipes */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->plane_state == NULL) + continue; + + if (pipe_ctx->top_pipe == NULL) { + bool blank = !is_pipe_tree_visible(pipe_ctx); + + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg, + pipe_ctx->pipe_dlg_param.vready_offset, + pipe_ctx->pipe_dlg_param.vstartup_start, + pipe_ctx->pipe_dlg_param.vupdate_offset, + pipe_ctx->pipe_dlg_param.vupdate_width); + + pipe_ctx->stream_res.tg->funcs->set_vtg_params( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + + dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); + } + + pipe_ctx->plane_res.hubp->funcs->hubp_setup( + pipe_ctx->plane_res.hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs, + &pipe_ctx->rq_regs, + &pipe_ctx->pipe_dlg_param); + } + + return true; +} + +static void dcn20_enable_writeback( + struct dc *dc, + const struct dc_stream_status *stream_status, + struct dc_writeback_info *wb_info) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + struct timing_generator *optc; + + ASSERT(wb_info->dwb_pipe_inst < MAX_DWB_PIPES); + ASSERT(wb_info->wb_enabled); + dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[wb_info->dwb_pipe_inst]; + + /* set the OPTC source mux */ + ASSERT(stream_status->primary_otg_inst < MAX_PIPES); + optc = dc->res_pool->timing_generators[stream_status->primary_otg_inst]; + optc->funcs->set_dwb_source(optc, wb_info->dwb_pipe_inst); + /* set MCIF_WB buffer and arbitration configuration */ + mcif_wb->funcs->config_mcif_buf(mcif_wb, &wb_info->mcif_buf_params, wb_info->dwb_params.dest_height); + mcif_wb->funcs->config_mcif_arb(mcif_wb, &dc->current_state->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[wb_info->dwb_pipe_inst]); + /* Enable MCIF_WB */ + mcif_wb->funcs->enable_mcif(mcif_wb); + /* Enable DWB */ + dwb->funcs->enable(dwb, &wb_info->dwb_params); + /* TODO: add sequence to enable/disable warmup */ +} + +void dcn20_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst) +{ + struct dwbc *dwb; + struct mcif_wb *mcif_wb; + + ASSERT(dwb_pipe_inst < MAX_DWB_PIPES); + dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + mcif_wb = dc->res_pool->mcif_wb[dwb_pipe_inst]; + + dwb->funcs->disable(dwb); + mcif_wb->funcs->disable_mcif(mcif_wb); +} + +bool dcn20_hwss_wait_for_blank_complete( + struct output_pixel_processor *opp) +{ + int counter; + + for (counter = 0; counter < 1000; counter++) { + if (opp->funcs->dpg_is_blanked(opp)) + break; + + udelay(100); + } + + if (counter == 1000) { + dm_error("DC: failed to blank crtc!\n"); + return false; + } + + return true; +} + +bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + if (!hubp) + return false; + return hubp->funcs->dmdata_status_done(hubp); +} + +static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct dce_hwseq *hws = dc->hwseq; + struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (pipe_ctx->stream_res.dsc) { + dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true); + if (bot_odm_pipe) + dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true); + } +#endif +} + +static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct dce_hwseq *hws = dc->hwseq; + struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + if (pipe_ctx->stream_res.dsc) { + dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false); + if (bot_odm_pipe) + dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false); + } +#endif +} + +void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) +{ + struct dc_dmdata_attributes attr = { 0 }; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + + attr.dmdata_mode = DMDATA_HW_MODE; + attr.dmdata_size = + dc_is_hdmi_signal(pipe_ctx->stream->signal) ? 32 : 36; + attr.address.quad_part = + pipe_ctx->stream->dmdata_address.quad_part; + attr.dmdata_dl_delta = 0; + attr.dmdata_qos_mode = 0; + attr.dmdata_qos_level = 0; + attr.dmdata_repeat = 1; /* always repeat */ + attr.dmdata_updated = 1; + attr.dmdata_sw_data = NULL; + + hubp->funcs->dmdata_set_attributes(hubp, &attr); +} + +void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option) +{ + dce110_disable_stream(pipe_ctx, option); +} + +static void dcn20_init_vm_ctx( + struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid) +{ + struct dcn_hubbub_virt_addr_config config; + + if (vmid == 0) { + ASSERT(0); /* VMID cannot be 0 for vm context */ + return; + } + + config.page_table_start_addr = va_config->page_table_start_addr; + config.page_table_end_addr = va_config->page_table_end_addr; + config.page_table_block_size = va_config->page_table_block_size_in_bytes; + config.page_table_depth = va_config->page_table_depth; + config.page_table_base_addr = va_config->page_table_base_addr; + + dc->res_pool->hubbub->funcs->init_vm_ctx(dc->res_pool->hubbub, &config, vmid); +} + +static int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config) +{ + struct dcn_hubbub_phys_addr_config config; + + config.system_aperture.fb_top = pa_config->system_aperture.fb_top; + config.system_aperture.fb_offset = pa_config->system_aperture.fb_offset; + config.system_aperture.fb_base = pa_config->system_aperture.fb_base; + config.system_aperture.agp_top = pa_config->system_aperture.agp_top; + config.system_aperture.agp_bot = pa_config->system_aperture.agp_bot; + config.system_aperture.agp_base = pa_config->system_aperture.agp_base; + config.gart_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr; + config.gart_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr; + config.gart_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr; + + return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); +} + +static bool patch_address_for_sbs_tb_stereo( + struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + bool sec_split = pipe_ctx->top_pipe && + pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; + if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && + (pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE || + pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { + *addr = plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.left_addr = + plane_state->address.grph_stereo.right_addr; + return true; + } + + if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && + plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { + plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; + plane_state->address.grph_stereo.right_addr = + plane_state->address.grph_stereo.left_addr; + } + return false; +} + + +static void dcn20_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool addr_patched = false; + PHYSICAL_ADDRESS_LOC addr; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + + // Call Helper to track VMID use + vm_helper_mark_vmid_used(dc->vm_helper, plane_state->address.vmid, pipe_ctx->plane_res.hubp->inst); + + 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->status.requested_address = plane_state->address; + + if (plane_state->flip_immediate) + plane_state->status.current_address = plane_state->address; + + if (addr_patched) + pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; +} + +void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, + struct dc_link_settings *link_settings) +{ + struct encoder_unblank_param params = { { 0 } }; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dc_link *link = stream->link; + params.odm = dc_res_get_odm_bottom_pipe(pipe_ctx); + + /* only 3 items below are used by unblank */ + params.timing = pipe_ctx->stream->timing; + + params.link_settings.link_rate = link_settings->link_rate; + + if (dc_is_dp_signal(pipe_ctx->stream->signal)) { + if (optc1_is_two_pixels_per_containter(&stream->timing) || params.odm) + params.timing.pix_clk_100hz /= 2; + pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( + pipe_ctx->stream_res.stream_enc, params.odm); + pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); + } + + if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) { + link->dc->hwss.edp_backlight_control(link, true); + } +} + +void dcn20_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx) +{ + struct timing_generator *tg = pipe_ctx->stream_res.tg; + int start_line = get_vupdate_offset_from_vsync(pipe_ctx); + + if (start_line < 0) + start_line = 0; + + if (tg->funcs->setup_vertical_interrupt2) + tg->funcs->setup_vertical_interrupt2(tg, start_line); +} + +static void dcn20_reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + int i; + DC_LOGGER_INIT(dc->ctx->logger); + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + /* DPMS may already disable */ + if (!pipe_ctx->stream->dpms_off) + core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + else if (pipe_ctx->stream_res.audio) { + dc->hwss.disable_audio_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + } + + } + + /* by upper caller loop, parent pipe: pipe0, will be reset last. + * back end share by all pipes and will be disable only when disable + * parent pipe. + */ + if (pipe_ctx->top_pipe == NULL) { + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) + pipe_ctx->stream_res.tg->funcs->set_odm_bypass( + pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) + break; + + if (i == dc->res_pool->pipe_count) + return; + + pipe_ctx->stream = NULL; + DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +static void dcn20_reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + dcn20_reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (dc->hwss.enable_stream_gating) + dc->hwss.enable_stream_gating(dc, pipe_ctx); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } +} + +static void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct mpcc_blnd_cfg blnd_cfg = { {0} }; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + int mpcc_id; + struct mpcc *new_mpcc; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); + + // input to MPCC is always RGB, by default leave black_color at 0 + if (dc->debug.visual_confirm == VISUAL_CONFIRM_HDR) { + dcn10_get_hdr_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + } else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE) { + dcn10_get_surface_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + } + + if (per_pixel_alpha) + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; + else + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; + + blnd_cfg.overlap_only = false; + blnd_cfg.global_gain = 0xff; + + if (pipe_ctx->plane_state->global_alpha) + blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value; + else + blnd_cfg.global_alpha = 0xff; + + blnd_cfg.background_color_bpc = 4; + blnd_cfg.bottom_gain_mode = 0; + blnd_cfg.top_gain = 0x1f000; + blnd_cfg.bottom_inside_gain = 0x1f000; + blnd_cfg.bottom_outside_gain = 0x1f000; + blnd_cfg.pre_multiplied_alpha = per_pixel_alpha; + + /* + * TODO: remove hack + * Note: currently there is a bug in init_hw such that + * on resume from hibernate, BIOS sets up MPCC0, and + * we do mpcc_remove but the mpcc cannot go to idle + * after remove. This cause us to pick mpcc1 here, + * which causes a pstate hang for yet unknown reason. + */ + mpcc_id = hubp->inst; + + /* If there is no full update, don't need to touch MPC tree*/ + if (!pipe_ctx->plane_state->update_flags.bits.full_update) { + mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); + return; + } + + /* check if this MPCC is already being used */ + new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); + /* remove MPCC if being used */ + if (new_mpcc != NULL) + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); + else + if (dc->debug.sanity_checks) + mpc->funcs->assert_mpcc_idle_before_connect( + dc->res_pool->mpc, mpcc_id); + + /* Call MPC to insert new plane */ + new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, + mpc_tree_params, + &blnd_cfg, + NULL, + NULL, + hubp->inst, + mpcc_id); + + ASSERT(new_mpcc != NULL); + hubp->opp_id = pipe_ctx->stream_res.opp->inst; + hubp->mpcc_id = mpcc_id; +} + +static int find_free_gsl_group(const struct dc *dc) +{ + if (dc->res_pool->gsl_groups.gsl_0 == 0) + return 1; + if (dc->res_pool->gsl_groups.gsl_1 == 0) + return 2; + if (dc->res_pool->gsl_groups.gsl_2 == 0) + return 3; + + return 0; +} + +/* NOTE: This is not a generic setup_gsl function (hence the suffix as_lock) + * This is only used to lock pipes in pipe splitting case with immediate flip + * Ordinary MPC/OTG locks suppress VUPDATE which doesn't help with immediate, + * so we get tearing with freesync since we cannot flip multiple pipes + * atomically. + * We use GSL for this: + * - immediate flip: find first available GSL group if not already assigned + * program gsl with that group, set current OTG as master + * and always us 0x4 = AND of flip_ready from all pipes + * - vsync flip: disable GSL if used + * + * Groups in stream_res are stored as +1 from HW registers, i.e. + * gsl_0 <=> pipe_ctx->stream_res.gsl_group == 1 + * Using a magic value like -1 would require tracking all inits/resets + */ +void dcn20_setup_gsl_group_as_lock( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable) +{ + struct gsl_params gsl; + int group_idx; + + memset(&gsl, 0, sizeof(struct gsl_params)); + + if (enable) { + /* return if group already assigned since GSL was set up + * for vsync flip, we would unassign so it can't be "left over" + */ + if (pipe_ctx->stream_res.gsl_group > 0) + return; + + group_idx = find_free_gsl_group(dc); + ASSERT(group_idx != 0); + pipe_ctx->stream_res.gsl_group = group_idx; + + /* set gsl group reg field and mark resource used */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 1; + dc->res_pool->gsl_groups.gsl_0 = 1; + break; + case 2: + gsl.gsl1_en = 1; + dc->res_pool->gsl_groups.gsl_1 = 1; + break; + case 3: + gsl.gsl2_en = 1; + dc->res_pool->gsl_groups.gsl_2 = 1; + break; + default: + BREAK_TO_DEBUGGER(); + return; // invalid case + } + gsl.gsl_master_en = 1; + } else { + group_idx = pipe_ctx->stream_res.gsl_group; + if (group_idx == 0) + return; // if not in use, just return + + pipe_ctx->stream_res.gsl_group = 0; + + /* unset gsl group reg field and mark resource free */ + switch (group_idx) { + case 1: + gsl.gsl0_en = 0; + dc->res_pool->gsl_groups.gsl_0 = 0; + break; + case 2: + gsl.gsl1_en = 0; + dc->res_pool->gsl_groups.gsl_1 = 0; + break; + case 3: + gsl.gsl2_en = 0; + dc->res_pool->gsl_groups.gsl_2 = 0; + break; + default: + BREAK_TO_DEBUGGER(); + return; + } + gsl.gsl_master_en = 0; + } + + /* at this point we want to program whether it's to enable or disable */ + if (pipe_ctx->stream_res.tg->funcs->set_gsl != NULL && + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select != NULL) { + pipe_ctx->stream_res.tg->funcs->set_gsl( + pipe_ctx->stream_res.tg, + &gsl); + + pipe_ctx->stream_res.tg->funcs->set_gsl_source_select( + pipe_ctx->stream_res.tg, group_idx, enable ? 4 : 0); + } else + BREAK_TO_DEBUGGER(); +} + +static void dcn20_set_flip_control_gsl( + struct pipe_ctx *pipe_ctx, + bool flip_immediate) +{ + if (pipe_ctx && pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl) + pipe_ctx->plane_res.hubp->funcs->hubp_set_flip_control_surface_gsl( + pipe_ctx->plane_res.hubp, flip_immediate); + +} + +void dcn20_hw_sequencer_construct(struct dc *dc) +{ + dcn10_hw_sequencer_construct(dc); + dc->hwss.init_hw = dcn20_init_hw; + dc->hwss.init_pipes = NULL; + dc->hwss.unblank_stream = dcn20_unblank_stream; + dc->hwss.update_plane_addr = dcn20_update_plane_addr; + dc->hwss.disable_plane = dcn20_disable_plane, + dc->hwss.enable_stream_timing = dcn20_enable_stream_timing; + dc->hwss.program_triplebuffer = dcn20_program_tripleBuffer; + dc->hwss.set_input_transfer_func = dcn20_set_input_transfer_func; + dc->hwss.set_output_transfer_func = dcn20_set_output_transfer_func; + dc->hwss.apply_ctx_for_surface = dcn20_apply_ctx_for_surface; + dc->hwss.pipe_control_lock = dcn20_pipe_control_lock; + dc->hwss.pipe_control_lock_global = dcn20_pipe_control_lock_global; + dc->hwss.optimize_bandwidth = dcn20_optimize_bandwidth; + dc->hwss.prepare_bandwidth = dcn20_prepare_bandwidth; + dc->hwss.update_bandwidth = dcn20_update_bandwidth; + dc->hwss.enable_writeback = dcn20_enable_writeback; + dc->hwss.disable_writeback = dcn20_disable_writeback; + dc->hwss.program_output_csc = dcn20_program_output_csc; + dc->hwss.update_odm = dcn20_update_odm; + dc->hwss.blank_pixel_data = dcn20_blank_pixel_data; + dc->hwss.dmdata_status_done = dcn20_dmdata_status_done; + dc->hwss.disable_stream = dcn20_disable_stream; + dc->hwss.init_sys_ctx = dcn20_init_sys_ctx; + dc->hwss.init_vm_ctx = dcn20_init_vm_ctx; + dc->hwss.disable_stream_gating = dcn20_disable_stream_gating; + dc->hwss.enable_stream_gating = dcn20_enable_stream_gating; + dc->hwss.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt; + dc->hwss.reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap; + dc->hwss.update_mpcc = dcn20_update_mpcc; + dc->hwss.set_flip_control_gsl = dcn20_set_flip_control_gsl; + dc->hwss.did_underflow_occur = dcn10_did_underflow_occur; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h new file mode 100644 index 000000000000..2b0409454073 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h @@ -0,0 +1,103 @@ +/* +* Copyright 2016 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 __DC_HWSS_DCN20_H__ +#define __DC_HWSS_DCN20_H__ + +struct dc; + +void dcn20_hw_sequencer_construct(struct dc *dc); + +enum dc_status dcn20_enable_stream_timing( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc); + +void dcn20_blank_pixel_data( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool blank); + +void dcn20_program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id); + +void dcn20_prepare_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dcn20_optimize_bandwidth( + struct dc *dc, + struct dc_state *context); + +bool dcn20_update_bandwidth( + struct dc *dc, + struct dc_state *context); + +void dcn20_disable_writeback( + struct dc *dc, + unsigned int dwb_pipe_inst); + +bool dcn20_hwss_wait_for_blank_complete( + struct output_pixel_processor *opp); + +bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream); + +bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state); + +bool dcn20_dmdata_status_done(struct pipe_ctx *pipe_ctx); + +void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx); + +void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option); + +void dcn20_program_tripleBuffer( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enableTripleBuffer); + +void dcn20_setup_vupdate_interrupt(struct pipe_ctx *pipe_ctx); + +void dcn20_pipe_control_lock_global( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn20_setup_gsl_group_as_lock(const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enable); +void dcn20_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock); +void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_enable_plane( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context); +#endif /* __DC_HWSS_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c new file mode 100644 index 000000000000..f495582e9e87 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c @@ -0,0 +1,460 @@ +/* + * 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 "reg_helper.h" + +#include "core_types.h" +#include "link_encoder.h" +#include "dcn20_link_encoder.h" +#include "stream_encoder.h" +#include "i2caux_interface.h" +#include "dc_bios_types.h" + +#include "gpio_service_interface.h" + +#define CTX \ + enc10->base.ctx +#define DC_LOGGER \ + enc10->base.ctx->logger + +#define REG(reg)\ + (enc10->link_regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + enc10->link_shift->field_name, enc10->link_mask->field_name + +#define IND_REG(index) \ + (enc10->link_regs->index) + + +static struct mpll_cfg dcn2_mpll_cfg[] = { + // RBR + { + .hdmimode_enable = 1, + .ref_range = 3, + .ref_clk_mpllb_div = 2, + .mpllb_ssc_en = 1, + .mpllb_div5_clk_en = 1, + .mpllb_multiplier = 226, + .mpllb_fracn_en = 1, + .mpllb_fracn_quot = 39321, + .mpllb_fracn_rem = 3, + .mpllb_fracn_den = 5, + .mpllb_ssc_up_spread = 0, + .mpllb_ssc_peak = 38221, + .mpllb_ssc_stepsize = 49314, + .mpllb_div_clk_en = 0, + .mpllb_div_multiplier = 0, + .mpllb_hdmi_div = 0, + .mpllb_tx_clk_div = 2, + .tx_vboost_lvl = 4, + .mpllb_pmix_en = 1, + .mpllb_word_div2_en = 0, + .mpllb_ana_v2i = 2, + .mpllb_ana_freq_vco = 2, + .mpllb_ana_cp_int = 7, + .mpllb_ana_cp_prop = 18, + .hdmi_pixel_clk_div = 0, + }, + // HBR + { + .hdmimode_enable = 1, + .ref_range = 3, + .ref_clk_mpllb_div = 2, + .mpllb_ssc_en = 1, + .mpllb_div5_clk_en = 1, + .mpllb_multiplier = 184, + .mpllb_fracn_en = 0, + .mpllb_fracn_quot = 0, + .mpllb_fracn_rem = 0, + .mpllb_fracn_den = 1, + .mpllb_ssc_up_spread = 0, + .mpllb_ssc_peak = 31850, + .mpllb_ssc_stepsize = 41095, + .mpllb_div_clk_en = 0, + .mpllb_div_multiplier = 0, + .mpllb_hdmi_div = 0, + .mpllb_tx_clk_div = 1, + .tx_vboost_lvl = 4, + .mpllb_pmix_en = 1, + .mpllb_word_div2_en = 0, + .mpllb_ana_v2i = 2, + .mpllb_ana_freq_vco = 3, + .mpllb_ana_cp_int = 7, + .mpllb_ana_cp_prop = 18, + .hdmi_pixel_clk_div = 0, + }, + //HBR2 + { + .hdmimode_enable = 1, + .ref_range = 3, + .ref_clk_mpllb_div = 2, + .mpllb_ssc_en = 1, + .mpllb_div5_clk_en = 1, + .mpllb_multiplier = 184, + .mpllb_fracn_en = 0, + .mpllb_fracn_quot = 0, + .mpllb_fracn_rem = 0, + .mpllb_fracn_den = 1, + .mpllb_ssc_up_spread = 0, + .mpllb_ssc_peak = 31850, + .mpllb_ssc_stepsize = 41095, + .mpllb_div_clk_en = 0, + .mpllb_div_multiplier = 0, + .mpllb_hdmi_div = 0, + .mpllb_tx_clk_div = 0, + .tx_vboost_lvl = 4, + .mpllb_pmix_en = 1, + .mpllb_word_div2_en = 0, + .mpllb_ana_v2i = 2, + .mpllb_ana_freq_vco = 3, + .mpllb_ana_cp_int = 7, + .mpllb_ana_cp_prop = 18, + .hdmi_pixel_clk_div = 0, + }, + //HBR3 + { + .hdmimode_enable = 1, + .ref_range = 3, + .ref_clk_mpllb_div = 2, + .mpllb_ssc_en = 1, + .mpllb_div5_clk_en = 1, + .mpllb_multiplier = 292, + .mpllb_fracn_en = 0, + .mpllb_fracn_quot = 0, + .mpllb_fracn_rem = 0, + .mpllb_fracn_den = 1, + .mpllb_ssc_up_spread = 0, + .mpllb_ssc_peak = 47776, + .mpllb_ssc_stepsize = 61642, + .mpllb_div_clk_en = 0, + .mpllb_div_multiplier = 0, + .mpllb_hdmi_div = 0, + .mpllb_tx_clk_div = 0, + .tx_vboost_lvl = 4, + .mpllb_pmix_en = 1, + .mpllb_word_div2_en = 0, + .mpllb_ana_v2i = 2, + .mpllb_ana_freq_vco = 0, + .mpllb_ana_cp_int = 7, + .mpllb_ana_cp_prop = 18, + .hdmi_pixel_clk_div = 0, + }, +}; + +void enc2_fec_set_enable(struct link_encoder *enc, bool enable) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + DC_LOG_DSC("%s FEC at link encoder inst %d", + enable ? "Enabling" : "Disabling", enc->id.enum_id); +#endif + REG_UPDATE(DP_DPHY_CNTL, DPHY_FEC_EN, enable); +} + +void enc2_fec_set_ready(struct link_encoder *enc, bool ready) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + + REG_UPDATE(DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, ready); +} + +bool enc2_fec_is_active(struct link_encoder *enc) +{ + uint32_t active = 0; + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + + REG_GET(DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, &active); + + return (active != 0); +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* this function reads dsc related register fields to be logged later in dcn10_log_hw_state + * into a dcn_dsc_state struct. + */ +void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + + REG_GET(DP_DPHY_CNTL, DPHY_FEC_EN, &s->dphy_fec_en); + REG_GET(DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, &s->dphy_fec_ready_shadow); + REG_GET(DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, &s->dphy_fec_active_status); +} +#endif + +static bool update_cfg_data( + struct dcn10_link_encoder *enc10, + const struct dc_link_settings *link_settings, + struct dpcssys_phy_seq_cfg *cfg) +{ + int i; + + cfg->load_sram_fw = false; + + for (i = 0; i < link_settings->lane_count; i++) + cfg->lane_en[i] = true; + + switch (link_settings->link_rate) { + case LINK_RATE_LOW: + cfg->mpll_cfg = dcn2_mpll_cfg[0]; + break; + case LINK_RATE_HIGH: + cfg->mpll_cfg = dcn2_mpll_cfg[1]; + break; + case LINK_RATE_HIGH2: + cfg->mpll_cfg = dcn2_mpll_cfg[2]; + break; + case LINK_RATE_HIGH3: + cfg->mpll_cfg = dcn2_mpll_cfg[3]; + break; + default: + DC_LOG_ERROR("%s: No supported link rate found %X!\n", + __func__, link_settings->link_rate); + return false; + } + + return true; +} + +void dcn20_link_encoder_enable_dp_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + struct dcn20_link_encoder *enc20 = (struct dcn20_link_encoder *) enc10; + struct dpcssys_phy_seq_cfg *cfg = &enc20->phy_seq_cfg; + + if (!enc->ctx->dc->debug.avoid_vbios_exec_table) { + dcn10_link_encoder_enable_dp_output(enc, link_settings, clock_source); + return; + } + + if (!update_cfg_data(enc10, link_settings, cfg)) + return; + + enc1_configure_encoder(enc10, link_settings); + + dcn10_link_encoder_setup(enc, SIGNAL_TYPE_DISPLAY_PORT); + +} + +#define AUX_REG(reg)\ + (enc10->aux_regs->reg) + +#define AUX_REG_READ(reg_name) \ + dm_read_reg(CTX, AUX_REG(reg_name)) + +#define AUX_REG_WRITE(reg_name, val) \ + dm_write_reg(CTX, AUX_REG(reg_name), val) +void enc2_hw_init(struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + +/* + 00 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__1to2 : 1/2 + 01 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__3to4 : 3/4 + 02 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__7to8 : 7/8 + 03 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__15to16 : 15/16 + 04 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__31to32 : 31/32 + 05 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__63to64 : 63/64 + 06 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__127to128 : 127/128 + 07 - DP_AUX_DPHY_RX_DETECTION_THRESHOLD__255to256 : 255/256 +*/ + +/* + AUX_REG_UPDATE_5(AUX_DPHY_RX_CONTROL0, + AUX_RX_START_WINDOW = 1 [6:4] + AUX_RX_RECEIVE_WINDOW = 1 default is 2 [10:8] + AUX_RX_HALF_SYM_DETECT_LEN = 1 [13:12] default is 1 + AUX_RX_TRANSITION_FILTER_EN = 1 [16] default is 1 + AUX_RX_ALLOW_BELOW_THRESHOLD_PHASE_DETECT [17] is 0 default is 0 + AUX_RX_ALLOW_BELOW_THRESHOLD_START [18] is 1 default is 1 + AUX_RX_ALLOW_BELOW_THRESHOLD_STOP [19] is 1 default is 1 + AUX_RX_PHASE_DETECT_LEN, [21,20] = 0x3 default is 3 + AUX_RX_DETECTION_THRESHOLD [30:28] = 1 +*/ + AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110); + + AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a); + + //AUX_DPHY_TX_REF_CONTROL'AUX_TX_REF_DIV HW default is 0x32; + // Set AUX_TX_REF_DIV Divider to generate 2 MHz reference from refclk + // 27MHz -> 0xd + // 100MHz -> 0x32 + // 48MHz -> 0x18 + + // Set TMDS_CTL0 to 1. This is a legacy setting. + REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1); + + dcn10_aux_initialize(enc10); +} + +static const struct link_encoder_funcs dcn20_link_enc_funcs = { +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .read_state = link_enc2_read_state, +#endif + .validate_output_with_stream = + dcn10_link_encoder_validate_output_with_stream, + .hw_init = enc2_hw_init, + .setup = dcn10_link_encoder_setup, + .enable_tmds_output = dcn10_link_encoder_enable_tmds_output, + .enable_dp_output = dcn20_link_encoder_enable_dp_output, + .enable_dp_mst_output = dcn10_link_encoder_enable_dp_mst_output, + .disable_output = dcn10_link_encoder_disable_output, + .dp_set_lane_settings = dcn10_link_encoder_dp_set_lane_settings, + .dp_set_phy_pattern = dcn10_link_encoder_dp_set_phy_pattern, + .update_mst_stream_allocation_table = + dcn10_link_encoder_update_mst_stream_allocation_table, + .psr_program_dp_dphy_fast_training = + dcn10_psr_program_dp_dphy_fast_training, + .psr_program_secondary_packet = dcn10_psr_program_secondary_packet, + .connect_dig_be_to_fe = dcn10_link_encoder_connect_dig_be_to_fe, + .enable_hpd = dcn10_link_encoder_enable_hpd, + .disable_hpd = dcn10_link_encoder_disable_hpd, + .is_dig_enabled = dcn10_is_dig_enabled, + .destroy = dcn10_link_encoder_destroy, + .fec_set_enable = enc2_fec_set_enable, + .fec_set_ready = enc2_fec_set_ready, + .fec_is_active = enc2_fec_is_active, + .get_dig_frontend = dcn10_get_dig_frontend, +}; + +void dcn20_link_encoder_construct( + struct dcn20_link_encoder *enc20, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_aux_registers *aux_regs, + const struct dcn10_link_enc_hpd_registers *hpd_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask) +{ + struct bp_encoder_cap_info bp_cap_info = {0}; + const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs; + enum bp_result result = BP_RESULT_OK; + struct dcn10_link_encoder *enc10 = &enc20->enc10; + + enc10->base.funcs = &dcn20_link_enc_funcs; + enc10->base.ctx = init_data->ctx; + enc10->base.id = init_data->encoder; + + enc10->base.hpd_source = init_data->hpd_source; + enc10->base.connector = init_data->connector; + + enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; + + enc10->base.features = *enc_features; + + enc10->base.transmitter = init_data->transmitter; + + /* set the flag to indicate whether driver poll the I2C data pin + * while doing the DP sink detect + */ + +/* if (dal_adapter_service_is_feature_supported(as, + FEATURE_DP_SINK_DETECT_POLL_DATA_PIN)) + enc10->base.features.flags.bits. + DP_SINK_DETECT_POLL_DATA_PIN = true;*/ + + enc10->base.output_signals = + SIGNAL_TYPE_DVI_SINGLE_LINK | + SIGNAL_TYPE_DVI_DUAL_LINK | + SIGNAL_TYPE_LVDS | + SIGNAL_TYPE_DISPLAY_PORT | + SIGNAL_TYPE_DISPLAY_PORT_MST | + SIGNAL_TYPE_EDP | + SIGNAL_TYPE_HDMI_TYPE_A; + + /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE. + * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY. + * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer + * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS. + * Prefer DIG assignment is decided by board design. + * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design + * and VBIOS will filter out 7 UNIPHY for DCE 8.0. + * By this, adding DIGG should not hurt DCE 8.0. + * This will let DCE 8.1 share DCE 8.0 as much as possible + */ + + enc10->link_regs = link_regs; + enc10->aux_regs = aux_regs; + enc10->hpd_regs = hpd_regs; + enc10->link_shift = link_shift; + enc10->link_mask = link_mask; + + switch (enc10->base.transmitter) { + case TRANSMITTER_UNIPHY_A: + enc10->base.preferred_engine = ENGINE_ID_DIGA; + break; + case TRANSMITTER_UNIPHY_B: + enc10->base.preferred_engine = ENGINE_ID_DIGB; + break; + case TRANSMITTER_UNIPHY_C: + enc10->base.preferred_engine = ENGINE_ID_DIGC; + break; + case TRANSMITTER_UNIPHY_D: + enc10->base.preferred_engine = ENGINE_ID_DIGD; + break; + case TRANSMITTER_UNIPHY_E: + enc10->base.preferred_engine = ENGINE_ID_DIGE; + break; + case TRANSMITTER_UNIPHY_F: + enc10->base.preferred_engine = ENGINE_ID_DIGF; + break; + case TRANSMITTER_UNIPHY_G: + enc10->base.preferred_engine = ENGINE_ID_DIGG; + break; + default: + ASSERT_CRITICAL(false); + enc10->base.preferred_engine = ENGINE_ID_UNKNOWN; + } + + /* default to one to mirror Windows behavior */ + enc10->base.features.flags.bits.HDMI_6GB_EN = 1; + + result = bp_funcs->get_encoder_cap_info(enc10->base.ctx->dc_bios, + enc10->base.id, &bp_cap_info); + + /* Override features with DCE-specific values */ + if (result == BP_RESULT_OK) { + enc10->base.features.flags.bits.IS_HBR2_CAPABLE = + bp_cap_info.DP_HBR2_EN; + enc10->base.features.flags.bits.IS_HBR3_CAPABLE = + bp_cap_info.DP_HBR3_EN; + enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN; + enc10->base.features.flags.bits.DP_IS_USB_C = + bp_cap_info.DP_IS_USB_C; + } else { + DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", + __func__, + result); + } + if (enc10->base.ctx->dc->debug.hdmi20_disable) { + enc10->base.features.flags.bits.HDMI_6GB_EN = 0; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h new file mode 100644 index 000000000000..3736b5548a25 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.h @@ -0,0 +1,173 @@ +/* + * 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 __DC_LINK_ENCODER__DCN20_H__ +#define __DC_LINK_ENCODER__DCN20_H__ + +#include "dcn10/dcn10_link_encoder.h" + +#define DCN2_AUX_REG_LIST(id)\ + AUX_REG_LIST(id), \ + SRI(AUX_DPHY_TX_CONTROL, DP_AUX, id) + +#define UNIPHY_MASK_SH_LIST(mask_sh)\ + LE_SF(UNIPHYA_CHANNEL_XBAR_CNTL, UNIPHY_LINK_ENABLE, mask_sh) + +#define LINK_ENCODER_MASK_SH_LIST_DCN20(mask_sh)\ + LINK_ENCODER_MASK_SH_LIST_DCN10(mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_EN, mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_READY_SHADOW, mask_sh),\ + LE_SF(DP0_DP_DPHY_CNTL, DPHY_FEC_ACTIVE_STATUS, mask_sh),\ + LE_SF(DIG0_DIG_LANE_ENABLE, DIG_LANE0EN, mask_sh),\ + LE_SF(DIG0_DIG_LANE_ENABLE, DIG_LANE1EN, mask_sh),\ + LE_SF(DIG0_DIG_LANE_ENABLE, DIG_LANE2EN, mask_sh),\ + LE_SF(DIG0_DIG_LANE_ENABLE, DIG_LANE3EN, mask_sh),\ + LE_SF(DIG0_DIG_LANE_ENABLE, DIG_CLK_EN, mask_sh),\ + LE_SF(DIG0_TMDS_CTL_BITS, TMDS_CTL0, mask_sh), \ + UNIPHY_MASK_SH_LIST(mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_START_WINDOW, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_HALF_SYM_DETECT_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_TRANSITION_FILTER_EN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_PHASE_DETECT, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_START, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_ALLOW_BELOW_THRESHOLD_STOP, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_PHASE_DETECT_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_RX_CONTROL0, AUX_RX_DETECTION_THRESHOLD, mask_sh), \ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_TX_PRECHARGE_LEN, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_TX_PRECHARGE_SYMBOLS, mask_sh),\ + LE_SF(DP_AUX0_AUX_DPHY_TX_CONTROL, AUX_MODE_DET_CHECK_DELAY, mask_sh) + +#define UNIPHY_DCN2_REG_LIST(id) \ + SRI(CLOCK_ENABLE, SYMCLK, id), \ + SRI(CHANNEL_XBAR_CNTL, UNIPHY, id) + +struct mpll_cfg { + uint32_t mpllb_ana_v2i; + uint32_t mpllb_ana_freq_vco; + uint32_t mpllb_ana_cp_int; + uint32_t mpllb_ana_cp_prop; + uint32_t mpllb_multiplier; + uint32_t ref_clk_mpllb_div; + bool mpllb_word_div2_en; + bool mpllb_ssc_en; + bool mpllb_div5_clk_en; + bool mpllb_div_clk_en; + bool mpllb_fracn_en; + bool mpllb_pmix_en; + uint32_t mpllb_div_multiplier; + uint32_t mpllb_tx_clk_div; + uint32_t mpllb_fracn_quot; + uint32_t mpllb_fracn_den; + uint32_t mpllb_ssc_peak; + uint32_t mpllb_ssc_stepsize; + uint32_t mpllb_ssc_up_spread; + uint32_t mpllb_fracn_rem; + uint32_t mpllb_hdmi_div; + // TODO: May not mpll params, need to figure out. + uint32_t tx_vboost_lvl; + uint32_t hdmi_pixel_clk_div; + uint32_t ref_range; + uint32_t ref_clk; + bool hdmimode_enable; +}; + +struct dpcssys_phy_seq_cfg { + bool program_fuse; + bool bypass_sram; + bool lane_en[4]; + bool use_calibration_setting; + struct mpll_cfg mpll_cfg; + bool load_sram_fw; +#if 0 + + bool hdmimode_enable; + bool silver2; + bool ext_refclk_en; + uint32_t dp_tx0_term_ctrl; + uint32_t dp_tx1_term_ctrl; + uint32_t dp_tx2_term_ctrl; + uint32_t dp_tx3_term_ctrl; + uint32_t fw_data[0x1000]; + uint32_t dp_tx0_width; + uint32_t dp_tx1_width; + uint32_t dp_tx2_width; + uint32_t dp_tx3_width; + uint32_t dp_tx0_rate; + uint32_t dp_tx1_rate; + uint32_t dp_tx2_rate; + uint32_t dp_tx3_rate; + uint32_t dp_tx0_eq_main; + uint32_t dp_tx0_eq_pre; + uint32_t dp_tx0_eq_post; + uint32_t dp_tx1_eq_main; + uint32_t dp_tx1_eq_pre; + uint32_t dp_tx1_eq_post; + uint32_t dp_tx2_eq_main; + uint32_t dp_tx2_eq_pre; + uint32_t dp_tx2_eq_post; + uint32_t dp_tx3_eq_main; + uint32_t dp_tx3_eq_pre; + uint32_t dp_tx3_eq_post; + bool data_swap_en; + bool data_order_invert_en; + uint32_t ldpcs_fifo_start_delay; + uint32_t rdpcs_fifo_start_delay; + bool rdpcs_reg_fifo_error_mask; + bool rdpcs_tx_fifo_error_mask; + bool rdpcs_dpalt_disable_mask; + bool rdpcs_dpalt_4lane_mask; +#endif +}; + +struct dcn20_link_encoder { + struct dcn10_link_encoder enc10; + struct dpcssys_phy_seq_cfg phy_seq_cfg; +}; + +void enc2_fec_set_enable(struct link_encoder *enc, bool enable); +void enc2_fec_set_ready(struct link_encoder *enc, bool ready); +bool enc2_fec_is_active(struct link_encoder *enc); +void enc2_hw_init(struct link_encoder *enc); + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +void link_enc2_read_state(struct link_encoder *enc, struct link_enc_state *s); +#endif + +void dcn20_link_encoder_enable_dp_output( + struct link_encoder *enc, + const struct dc_link_settings *link_settings, + enum clock_source_id clock_source); + +void dcn20_link_encoder_construct( + struct dcn20_link_encoder *enc20, + const struct encoder_init_data *init_data, + const struct encoder_feature_support *enc_features, + const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_aux_registers *aux_regs, + const struct dcn10_link_enc_hpd_registers *hpd_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask); + +#endif /* __DC_LINK_ENCODER__DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.c new file mode 100644 index 000000000000..694260c10a01 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.c @@ -0,0 +1,323 @@ +/* + * 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 "reg_helper.h" +#include "resource.h" +#include "mcif_wb.h" +#include "dcn20_mmhubbub.h" + + +#define REG(reg)\ + mcif_wb20->mcif_wb_regs->reg + +#define CTX \ + mcif_wb20->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + mcif_wb20->mcif_wb_shift->field_name, mcif_wb20->mcif_wb_mask->field_name + +#define MCIF_ADDR(addr) (((unsigned long long)addr & 0xffffffffff) + 0xFE) >> 8 +#define MCIF_ADDR_HIGH(addr) (unsigned long long)addr >> 40 + +/* wbif programming guide: + * 1. set up wbif parameter: + * unsigned long long luma_address[4]; //4 frame buffer + * unsigned long long chroma_address[4]; + * unsigned int luma_pitch; + * unsigned int chroma_pitch; + * unsigned int warmup_pitch=0x10; //256B align, the page size is 4KB when it is 0x10 + * unsigned int slice_lines; //slice size + * unsigned int time_per_pixel; // time per pixel, in ns + * unsigned int arbitration_slice; // 0: 512 bytes 1: 1024 bytes 2: 2048 Bytes + * unsigned int max_scaled_time; // used for QOS generation + * unsigned int swlock=0x0; + * unsigned int cli_watermark[4]; //4 group urgent watermark + * unsigned int pstate_watermark[4]; //4 group pstate watermark + * unsigned int sw_int_en; // Software interrupt enable, frame end and overflow + * unsigned int sw_slice_int_en; // slice end interrupt enable + * unsigned int sw_overrun_int_en; // overrun error interrupt enable + * unsigned int vce_int_en; // VCE interrupt enable, frame end and overflow + * unsigned int vce_slice_int_en; // VCE slice end interrupt enable, frame end and overflow + * + * 2. configure wbif register + * a. call mmhubbub_config_wbif() + * + * 3. Enable wbif + * call set_wbif_bufmgr_enable(); + * + * 4. wbif_dump_status(), option, for debug purpose + * the bufmgr status can show the progress of write back, can be used for debug purpose + */ + +static void mmhubbub2_config_mcif_buf(struct mcif_wb *mcif_wb, + struct mcif_buf_params *params, + unsigned int dest_height) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + /* sw lock buffer0~buffer3, default is 0 */ + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_LOCK, params->swlock); + + /* buffer address for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_1_ADDR_Y, MCIF_WB_BUF_1_ADDR_Y, MCIF_ADDR(params->luma_address[0])); + REG_UPDATE(MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_ADDR_HIGH(params->luma_address[0])); + /* right eye sub-buffer address offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_1_ADDR_Y_OFFSET, MCIF_WB_BUF_1_ADDR_Y_OFFSET, 0); + + /* buffer address for Chroma in planar mode (unused in packing mode) */ + REG_UPDATE(MCIF_WB_BUF_1_ADDR_C, MCIF_WB_BUF_1_ADDR_C, MCIF_ADDR(params->chroma_address[0])); + REG_UPDATE(MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_ADDR_HIGH(params->chroma_address[0])); + /* right eye offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_1_ADDR_C_OFFSET, MCIF_WB_BUF_1_ADDR_C_OFFSET, 0); + + /* buffer address for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_2_ADDR_Y, MCIF_WB_BUF_2_ADDR_Y, MCIF_ADDR(params->luma_address[1])); + REG_UPDATE(MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_ADDR_HIGH(params->luma_address[1])); + /* right eye sub-buffer address offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_2_ADDR_Y_OFFSET, MCIF_WB_BUF_2_ADDR_Y_OFFSET, 0); + + /* buffer address for Chroma in planar mode (unused in packing mode) */ + REG_UPDATE(MCIF_WB_BUF_2_ADDR_C, MCIF_WB_BUF_2_ADDR_C, MCIF_ADDR(params->chroma_address[1])); + REG_UPDATE(MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_ADDR_HIGH(params->chroma_address[1])); + /* right eye offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_2_ADDR_C_OFFSET, MCIF_WB_BUF_2_ADDR_C_OFFSET, 0); + + /* buffer address for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_3_ADDR_Y, MCIF_WB_BUF_3_ADDR_Y, MCIF_ADDR(params->luma_address[2])); + REG_UPDATE(MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_ADDR_HIGH(params->luma_address[2])); + /* right eye sub-buffer address offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_3_ADDR_Y_OFFSET, MCIF_WB_BUF_3_ADDR_Y_OFFSET, 0); + + /* buffer address for Chroma in planar mode (unused in packing mode) */ + REG_UPDATE(MCIF_WB_BUF_3_ADDR_C, MCIF_WB_BUF_3_ADDR_C, MCIF_ADDR(params->chroma_address[2])); + REG_UPDATE(MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_ADDR_HIGH(params->chroma_address[2])); + /* right eye offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_3_ADDR_C_OFFSET, MCIF_WB_BUF_3_ADDR_C_OFFSET, 0); + + /* buffer address for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_4_ADDR_Y, MCIF_WB_BUF_4_ADDR_Y, MCIF_ADDR(params->luma_address[3])); + REG_UPDATE(MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_ADDR_HIGH(params->luma_address[3])); + /* right eye sub-buffer address offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_4_ADDR_Y_OFFSET, MCIF_WB_BUF_4_ADDR_Y_OFFSET, 0); + + /* buffer address for Chroma in planar mode (unused in packing mode) */ + REG_UPDATE(MCIF_WB_BUF_4_ADDR_C, MCIF_WB_BUF_4_ADDR_C, MCIF_ADDR(params->chroma_address[3])); + REG_UPDATE(MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_ADDR_HIGH(params->chroma_address[3])); + /* right eye offset for packing mode or Luma in planar mode */ + REG_UPDATE(MCIF_WB_BUF_4_ADDR_C_OFFSET, MCIF_WB_BUF_4_ADDR_C_OFFSET, 0); + + /* setup luma & chroma size + * should be enough to contain a whole frame Luma data, + * the programmed value is frame buffer size [27:8], 256-byte aligned + */ + REG_UPDATE(MCIF_WB_BUF_LUMA_SIZE, MCIF_WB_BUF_LUMA_SIZE, (params->luma_pitch>>8) * dest_height); + REG_UPDATE(MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB_BUF_CHROMA_SIZE, (params->chroma_pitch>>8) * dest_height); + + /* enable address fence */ + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUF_ADDR_FENCE_EN, 1); + + /* setup pitch, the programmed value is [15:8], 256B align */ + REG_UPDATE_2(MCIF_WB_BUF_PITCH, MCIF_WB_BUF_LUMA_PITCH, params->luma_pitch >> 8, + MCIF_WB_BUF_CHROMA_PITCH, params->chroma_pitch >> 8); + + /* Set pitch for MC cache warm up mode */ + /* Pitch is 256 bytes aligned. The default pitch is 4K */ + /* default is 0x10 */ + REG_UPDATE(MCIF_WB_WARM_UP_CNTL, MCIF_WB_PITCH_SIZE_WARMUP, params->warmup_pitch); +} + +static void mmhubbub2_config_mcif_arb(struct mcif_wb *mcif_wb, + struct mcif_arb_params *params) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + /* Programmed by the video driver based on the CRTC timing (for DWB) */ + REG_UPDATE(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_TIME_PER_PIXEL, params->time_per_pixel); + + /* Programming dwb watermark */ + /* Watermark to generate urgent in MCIF_WB_CLI, value is determined by MCIF_WB_CLI_WATERMARK_MASK. */ + /* Program in ns. A formula will be provided in the pseudo code to calculate the value. */ + REG_UPDATE(MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, 0x0); + /* urgent_watermarkA */ + REG_UPDATE(MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, params->cli_watermark[0]); + REG_UPDATE(MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, 0x1); + /* urgent_watermarkB */ + REG_UPDATE(MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, params->cli_watermark[1]); + REG_UPDATE(MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, 0x2); + /* urgent_watermarkC */ + REG_UPDATE(MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, params->cli_watermark[2]); + REG_UPDATE(MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, 0x3); + /* urgent_watermarkD */ + REG_UPDATE(MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, params->cli_watermark[3]); + + /* Programming nb pstate watermark */ + /* nbp_state_change_watermarkA */ + REG_UPDATE(MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, 0x0); + REG_UPDATE(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, + NB_PSTATE_CHANGE_REFRESH_WATERMARK, params->pstate_watermark[0]); + /* nbp_state_change_watermarkB */ + REG_UPDATE(MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, 0x1); + REG_UPDATE(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, + NB_PSTATE_CHANGE_REFRESH_WATERMARK, params->pstate_watermark[1]); + /* nbp_state_change_watermarkC */ + REG_UPDATE(MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, 0x2); + REG_UPDATE(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, + NB_PSTATE_CHANGE_REFRESH_WATERMARK, params->pstate_watermark[2]); + /* nbp_state_change_watermarkD */ + REG_UPDATE(MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, 0x3); + REG_UPDATE(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, + NB_PSTATE_CHANGE_REFRESH_WATERMARK, params->pstate_watermark[3]); + + /* max_scaled_time */ + REG_UPDATE(MULTI_LEVEL_QOS_CTRL, MAX_SCALED_TIME_TO_URGENT, params->max_scaled_time); + + /* slice_lines */ + REG_UPDATE(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_SLICE_SIZE, params->slice_lines-1); + + /* Set arbitration unit for Luma/Chroma */ + /* arb_unit=2 should be chosen for more efficiency */ + /* Arbitration size, 0: 512 bytes 1: 1024 bytes 2: 2048 Bytes */ + REG_UPDATE(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_CLIENT_ARBITRATION_SLICE, params->arbitration_slice); +} + +void mmhubbub2_config_mcif_irq(struct mcif_wb *mcif_wb, + struct mcif_irq_params *params) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + /* Set interrupt mask */ + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_INT_EN, params->sw_int_en); + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_SLICE_INT_EN, params->sw_slice_int_en); + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_OVERRUN_INT_EN, params->sw_overrun_int_en); + + REG_UPDATE(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_INT_EN, params->vce_int_en); + REG_UPDATE(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_SLICE_INT_EN, params->vce_slice_int_en); +} + +void mmhubbub2_enable_mcif(struct mcif_wb *mcif_wb) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + /* Enable Mcifwb */ + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_ENABLE, 1); +} + +void mmhubbub2_disable_mcif(struct mcif_wb *mcif_wb) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + /* disable buffer manager */ + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_ENABLE, 0); +} + +/* set which group of pstate watermark to use and set wbif watermark change request */ +/* +static void mmhubbub2_wbif_watermark_change_req(struct mcif_wb *mcif_wb, unsigned int wm_set) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + uint32_t change_req; + + REG_GET(SMU_WM_CONTROL, MCIF_WB0_WM_CHG_REQ, &change_req); + change_req = (change_req == 0) ? 1 : 0; + REG_UPDATE(SMU_WM_CONTROL, MCIF_WB0_WM_CHG_SEL, wm_set); + REG_UPDATE(SMU_WM_CONTROL, MCIF_WB0_WM_CHG_REQ, change_req); +} +*/ +/* Set watermark change interrupt disable bit */ +/* +static void mmhubbub2_set_wbif_watermark_change_int_disable(struct mcif_wb *mcif_wb, unsigned int ack_int_dis) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + REG_UPDATE(SMU_WM_CONTROL, MCIF_WB0_WM_CHG_ACK_INT_DIS, ack_int_dis); +} +*/ +/* Read watermark change interrupt status */ +/* +unsigned int mmhubbub2_get_wbif_watermark_change_int_status(struct mcif_wb *mcif_wb) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + uint32_t irq_status; + + REG_GET(SMU_WM_CONTROL, MCIF_WB0_WM_CHG_ACK_INT_STATUS, &irq_status); + return irq_status; +} +*/ + +void mcifwb2_dump_frame(struct mcif_wb *mcif_wb, + struct mcif_buf_params *mcif_params, + enum dwb_scaler_mode out_format, + unsigned int dest_width, + unsigned int dest_height, + struct mcif_wb_frame_dump_info *dump_info, + unsigned char *luma_buffer, + unsigned char *chroma_buffer, + unsigned char *dest_luma_buffer, + unsigned char *dest_chroma_buffer) +{ + struct dcn20_mmhubbub *mcif_wb20 = TO_DCN20_MMHUBBUB(mcif_wb); + + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_LOCK, 0xf); + + memcpy(dest_luma_buffer, luma_buffer, mcif_params->luma_pitch * dest_height); + memcpy(dest_chroma_buffer, chroma_buffer, mcif_params->chroma_pitch * dest_height / 2); + + REG_UPDATE(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_LOCK, 0x0); + + dump_info->format = out_format; + dump_info->width = dest_width; + dump_info->height = dest_height; + dump_info->luma_pitch = mcif_params->luma_pitch; + dump_info->chroma_pitch = mcif_params->chroma_pitch; + dump_info->size = dest_height * (mcif_params->luma_pitch + mcif_params->chroma_pitch); +} + +const struct mcif_wb_funcs dcn20_mmhubbub_funcs = { + .enable_mcif = mmhubbub2_enable_mcif, + .disable_mcif = mmhubbub2_disable_mcif, + .config_mcif_buf = mmhubbub2_config_mcif_buf, + .config_mcif_arb = mmhubbub2_config_mcif_arb, + .config_mcif_irq = mmhubbub2_config_mcif_irq, + .dump_frame = mcifwb2_dump_frame, +}; + +void dcn20_mmhubbub_construct(struct dcn20_mmhubbub *mcif_wb20, + struct dc_context *ctx, + const struct dcn20_mmhubbub_registers *mcif_wb_regs, + const struct dcn20_mmhubbub_shift *mcif_wb_shift, + const struct dcn20_mmhubbub_mask *mcif_wb_mask, + int inst) +{ + mcif_wb20->base.ctx = ctx; + + mcif_wb20->base.inst = inst; + mcif_wb20->base.funcs = &dcn20_mmhubbub_funcs; + + mcif_wb20->mcif_wb_regs = mcif_wb_regs; + mcif_wb20->mcif_wb_shift = mcif_wb_shift; + mcif_wb20->mcif_wb_mask = mcif_wb_mask; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h new file mode 100644 index 000000000000..3fccd5eeecbb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mmhubbub.h @@ -0,0 +1,544 @@ +/* + * 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 __DC_MCIF_WB_DCN20_H__ +#define __DC_MCIF_WB_DCN20_H__ + +#define TO_DCN20_MMHUBBUB(mcif_wb_base) \ + container_of(mcif_wb_base, struct dcn20_mmhubbub, base) + +/* DCN */ +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#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 + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + + +#define MCIF_WB_COMMON_REG_LIST_DCN2_0(inst) \ + SRI(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_BUFMGR_CUR_LINE_R, MCIF_WB, inst),\ + SRI(MCIF_WB_BUFMGR_STATUS, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_PITCH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_STATUS, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_STATUS2, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_STATUS, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_STATUS2, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_STATUS, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_STATUS2, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_STATUS, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_STATUS2, MCIF_WB, inst),\ + SRI(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_SCLK_CHANGE, MCIF_WB, inst),\ + SRI(MCIF_WB_TEST_DEBUG_INDEX, MCIF_WB, inst),\ + SRI(MCIF_WB_TEST_DEBUG_DATA, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_Y, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_Y_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_C, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_C_OFFSET, MCIF_WB, inst),\ + SRI(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, MCIF_WB, inst),\ + SRI(MCIF_WB_NB_PSTATE_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_WATERMARK, MCIF_WB, inst),\ + SRI(MCIF_WB_CLOCK_GATER_CONTROL, MCIF_WB, inst),\ + SRI(MCIF_WB_WARM_UP_CNTL, MCIF_WB, inst),\ + SRI(MCIF_WB_SELF_REFRESH_CONTROL, MCIF_WB, inst),\ + SRI(MULTI_LEVEL_QOS_CTRL, MCIF_WB, inst),\ + SRI(MCIF_WB_SECURITY_LEVEL, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_LUMA_SIZE, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_1_RESOLUTION, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_2_RESOLUTION, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_3_RESOLUTION, MCIF_WB, inst),\ + SRI(MCIF_WB_BUF_4_RESOLUTION, MCIF_WB, inst),\ + SRI(SMU_WM_CONTROL, WBIF, inst) + +#define MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(mask_sh) \ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_ENABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_INT_ACK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_SLICE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_OVERRUN_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUFMGR_SW_LOCK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_P_VMID, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB_BUF_ADDR_FENCE_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_CUR_LINE_R, MCIF_WB_BUFMGR_CUR_LINE_R, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_VCE_INT_STATUS, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_SW_INT_STATUS, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_SW_OVERRUN_INT_STATUS, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_CUR_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_BUFTAG, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_CUR_LINE_L, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_STATUS, MCIF_WB_BUFMGR_NEXT_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_PITCH, MCIF_WB_BUF_LUMA_PITCH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_PITCH, MCIF_WB_BUF_CHROMA_PITCH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_ACTIVE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_SW_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_VCE_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_OVERFLOW, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_DISABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_MODE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_BUFTAG, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_NXT_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_FIELD, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_CUR_LINE_L, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_LONG_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_SHORT_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS, MCIF_WB_BUF_1_FRAME_LENGTH_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_CUR_LINE_R, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_NEW_CONTENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_COLOR_DEPTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_TMZ_BLACK_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_TMZ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_Y_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_STATUS2, MCIF_WB_BUF_1_C_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_ACTIVE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_SW_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_VCE_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_OVERFLOW, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_DISABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_MODE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_BUFTAG, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_NXT_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_FIELD, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_CUR_LINE_L, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_LONG_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_SHORT_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS, MCIF_WB_BUF_2_FRAME_LENGTH_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_CUR_LINE_R, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_NEW_CONTENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_COLOR_DEPTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_TMZ_BLACK_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_TMZ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_Y_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_STATUS2, MCIF_WB_BUF_2_C_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_ACTIVE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_SW_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_VCE_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_OVERFLOW, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_DISABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_MODE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_BUFTAG, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_NXT_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_FIELD, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_CUR_LINE_L, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_LONG_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_SHORT_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS, MCIF_WB_BUF_3_FRAME_LENGTH_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_CUR_LINE_R, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_NEW_CONTENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_COLOR_DEPTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_TMZ_BLACK_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_TMZ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_Y_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_STATUS2, MCIF_WB_BUF_3_C_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_ACTIVE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_SW_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_VCE_LOCKED, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_OVERFLOW, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_DISABLE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_MODE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_BUFTAG, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_NXT_BUF, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_FIELD, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_CUR_LINE_L, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_LONG_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_SHORT_LINE_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS, MCIF_WB_BUF_4_FRAME_LENGTH_ERROR, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_CUR_LINE_R, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_NEW_CONTENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_COLOR_DEPTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_TMZ_BLACK_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_TMZ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_Y_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_STATUS2, MCIF_WB_BUF_4_C_OVERRUN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_CLIENT_ARBITRATION_SLICE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_ARBITRATION_CONTROL, MCIF_WB_TIME_PER_PIXEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SCLK_CHANGE, WM_CHANGE_ACK_FORCE_ON, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SCLK_CHANGE, MCIF_WB_CLI_WATERMARK_MASK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_TEST_DEBUG_INDEX, MCIF_WB_TEST_DEBUG_INDEX, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_TEST_DEBUG_DATA, MCIF_WB_TEST_DEBUG_DATA, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_Y, MCIF_WB_BUF_1_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_Y_OFFSET, MCIF_WB_BUF_1_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_C, MCIF_WB_BUF_1_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_C_OFFSET, MCIF_WB_BUF_1_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_Y, MCIF_WB_BUF_2_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_Y_OFFSET, MCIF_WB_BUF_2_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_C, MCIF_WB_BUF_2_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_C_OFFSET, MCIF_WB_BUF_2_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_Y, MCIF_WB_BUF_3_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_Y_OFFSET, MCIF_WB_BUF_3_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_C, MCIF_WB_BUF_3_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_C_OFFSET, MCIF_WB_BUF_3_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_Y, MCIF_WB_BUF_4_ADDR_Y, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_Y_OFFSET, MCIF_WB_BUF_4_ADDR_Y_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_C, MCIF_WB_BUF_4_ADDR_C, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_C_OFFSET, MCIF_WB_BUF_4_ADDR_C_OFFSET, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_LOCK_IGNORE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_INT_ACK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_SLICE_INT_EN, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_VCE_LOCK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB_BUFMGR_SLICE_SIZE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, NB_PSTATE_CHANGE_REFRESH_WATERMARK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_URGENT_DURING_REQUEST, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_FORCE_ON, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_ALLOW_FOR_URGENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_NB_PSTATE_CONTROL, NB_PSTATE_CHANGE_WATERMARK_MASK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_WATERMARK, MCIF_WB_CLI_WATERMARK, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_CLOCK_GATER_CONTROL, MCIF_WB_CLI_CLOCK_GATER_OVERRIDE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_WARM_UP_CNTL, MCIF_WB_PITCH_SIZE_WARMUP, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SELF_REFRESH_CONTROL, DIS_REFRESH_UNDER_NBPREQ, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SELF_REFRESH_CONTROL, PERFRAME_SELF_REFRESH, mask_sh),\ + SF(MCIF_WB0_MULTI_LEVEL_QOS_CTRL, MAX_SCALED_TIME_TO_URGENT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_SECURITY_LEVEL, MCIF_WB_SECURITY_LEVEL, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_LUMA_SIZE, MCIF_WB_BUF_LUMA_SIZE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB_BUF_CHROMA_SIZE, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_WB_BUF_1_ADDR_Y_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_WB_BUF_1_ADDR_C_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_WB_BUF_2_ADDR_Y_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_WB_BUF_2_ADDR_C_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_WB_BUF_3_ADDR_Y_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_WB_BUF_3_ADDR_C_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_WB_BUF_4_ADDR_Y_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_WB_BUF_4_ADDR_C_HIGH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_RESOLUTION, MCIF_WB_BUF_1_RESOLUTION_WIDTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_1_RESOLUTION, MCIF_WB_BUF_1_RESOLUTION_HEIGHT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_RESOLUTION, MCIF_WB_BUF_2_RESOLUTION_WIDTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_2_RESOLUTION, MCIF_WB_BUF_2_RESOLUTION_HEIGHT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_RESOLUTION, MCIF_WB_BUF_3_RESOLUTION_WIDTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_3_RESOLUTION, MCIF_WB_BUF_3_RESOLUTION_HEIGHT, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_RESOLUTION, MCIF_WB_BUF_4_RESOLUTION_WIDTH, mask_sh),\ + SF(MCIF_WB0_MCIF_WB_BUF_4_RESOLUTION, MCIF_WB_BUF_4_RESOLUTION_HEIGHT, mask_sh),\ + SF(WBIF0_SMU_WM_CONTROL, MCIF_WB0_WM_CHG_SEL, mask_sh),\ + SF(WBIF0_SMU_WM_CONTROL, MCIF_WB0_WM_CHG_REQ, mask_sh),\ + SF(WBIF0_SMU_WM_CONTROL, MCIF_WB0_WM_CHG_ACK_INT_DIS, mask_sh),\ + SF(WBIF0_SMU_WM_CONTROL, MCIF_WB0_WM_CHG_ACK_INT_STATUS, mask_sh) + +#define MCIF_WB_REG_FIELD_LIST_DCN2_0(type) \ + type MCIF_WB_BUFMGR_ENABLE;\ + type MCIF_WB_BUFMGR_SW_INT_EN;\ + type MCIF_WB_BUFMGR_SW_INT_ACK;\ + type MCIF_WB_BUFMGR_SW_SLICE_INT_EN;\ + type MCIF_WB_BUFMGR_SW_OVERRUN_INT_EN;\ + type MCIF_WB_BUFMGR_SW_LOCK;\ + type MCIF_WB_P_VMID;\ + type MCIF_WB_BUF_ADDR_FENCE_EN;\ + type MCIF_WB_BUFMGR_CUR_LINE_R;\ + type MCIF_WB_BUFMGR_VCE_INT_STATUS;\ + type MCIF_WB_BUFMGR_SW_INT_STATUS;\ + type MCIF_WB_BUFMGR_SW_OVERRUN_INT_STATUS;\ + type MCIF_WB_BUFMGR_CUR_BUF;\ + type MCIF_WB_BUFMGR_BUFTAG;\ + type MCIF_WB_BUFMGR_CUR_LINE_L;\ + type MCIF_WB_BUFMGR_NEXT_BUF;\ + type MCIF_WB_BUF_LUMA_PITCH;\ + type MCIF_WB_BUF_CHROMA_PITCH;\ + type MCIF_WB_BUF_1_ACTIVE;\ + type MCIF_WB_BUF_1_SW_LOCKED;\ + type MCIF_WB_BUF_1_VCE_LOCKED;\ + type MCIF_WB_BUF_1_OVERFLOW;\ + type MCIF_WB_BUF_1_DISABLE;\ + type MCIF_WB_BUF_1_MODE;\ + type MCIF_WB_BUF_1_BUFTAG;\ + type MCIF_WB_BUF_1_NXT_BUF;\ + type MCIF_WB_BUF_1_FIELD;\ + type MCIF_WB_BUF_1_CUR_LINE_L;\ + type MCIF_WB_BUF_1_LONG_LINE_ERROR;\ + type MCIF_WB_BUF_1_SHORT_LINE_ERROR;\ + type MCIF_WB_BUF_1_FRAME_LENGTH_ERROR;\ + type MCIF_WB_BUF_1_CUR_LINE_R;\ + type MCIF_WB_BUF_1_NEW_CONTENT;\ + type MCIF_WB_BUF_1_COLOR_DEPTH;\ + type MCIF_WB_BUF_1_TMZ_BLACK_PIXEL;\ + type MCIF_WB_BUF_1_TMZ;\ + type MCIF_WB_BUF_1_Y_OVERRUN;\ + type MCIF_WB_BUF_1_C_OVERRUN;\ + type MCIF_WB_BUF_2_ACTIVE;\ + type MCIF_WB_BUF_2_SW_LOCKED;\ + type MCIF_WB_BUF_2_VCE_LOCKED;\ + type MCIF_WB_BUF_2_OVERFLOW;\ + type MCIF_WB_BUF_2_DISABLE;\ + type MCIF_WB_BUF_2_MODE;\ + type MCIF_WB_BUF_2_BUFTAG;\ + type MCIF_WB_BUF_2_NXT_BUF;\ + type MCIF_WB_BUF_2_FIELD;\ + type MCIF_WB_BUF_2_CUR_LINE_L;\ + type MCIF_WB_BUF_2_LONG_LINE_ERROR;\ + type MCIF_WB_BUF_2_SHORT_LINE_ERROR;\ + type MCIF_WB_BUF_2_FRAME_LENGTH_ERROR;\ + type MCIF_WB_BUF_2_CUR_LINE_R;\ + type MCIF_WB_BUF_2_NEW_CONTENT;\ + type MCIF_WB_BUF_2_COLOR_DEPTH;\ + type MCIF_WB_BUF_2_TMZ_BLACK_PIXEL;\ + type MCIF_WB_BUF_2_TMZ;\ + type MCIF_WB_BUF_2_Y_OVERRUN;\ + type MCIF_WB_BUF_2_C_OVERRUN;\ + type MCIF_WB_BUF_3_ACTIVE;\ + type MCIF_WB_BUF_3_SW_LOCKED;\ + type MCIF_WB_BUF_3_VCE_LOCKED;\ + type MCIF_WB_BUF_3_OVERFLOW;\ + type MCIF_WB_BUF_3_DISABLE;\ + type MCIF_WB_BUF_3_MODE;\ + type MCIF_WB_BUF_3_BUFTAG;\ + type MCIF_WB_BUF_3_NXT_BUF;\ + type MCIF_WB_BUF_3_FIELD;\ + type MCIF_WB_BUF_3_CUR_LINE_L;\ + type MCIF_WB_BUF_3_LONG_LINE_ERROR;\ + type MCIF_WB_BUF_3_SHORT_LINE_ERROR;\ + type MCIF_WB_BUF_3_FRAME_LENGTH_ERROR;\ + type MCIF_WB_BUF_3_CUR_LINE_R;\ + type MCIF_WB_BUF_3_NEW_CONTENT;\ + type MCIF_WB_BUF_3_COLOR_DEPTH;\ + type MCIF_WB_BUF_3_TMZ_BLACK_PIXEL;\ + type MCIF_WB_BUF_3_TMZ;\ + type MCIF_WB_BUF_3_Y_OVERRUN;\ + type MCIF_WB_BUF_3_C_OVERRUN;\ + type MCIF_WB_BUF_4_ACTIVE;\ + type MCIF_WB_BUF_4_SW_LOCKED;\ + type MCIF_WB_BUF_4_VCE_LOCKED;\ + type MCIF_WB_BUF_4_OVERFLOW;\ + type MCIF_WB_BUF_4_DISABLE;\ + type MCIF_WB_BUF_4_MODE;\ + type MCIF_WB_BUF_4_BUFTAG;\ + type MCIF_WB_BUF_4_NXT_BUF;\ + type MCIF_WB_BUF_4_FIELD;\ + type MCIF_WB_BUF_4_CUR_LINE_L;\ + type MCIF_WB_BUF_4_LONG_LINE_ERROR;\ + type MCIF_WB_BUF_4_SHORT_LINE_ERROR;\ + type MCIF_WB_BUF_4_FRAME_LENGTH_ERROR;\ + type MCIF_WB_BUF_4_CUR_LINE_R;\ + type MCIF_WB_BUF_4_NEW_CONTENT;\ + type MCIF_WB_BUF_4_COLOR_DEPTH;\ + type MCIF_WB_BUF_4_TMZ_BLACK_PIXEL;\ + type MCIF_WB_BUF_4_TMZ;\ + type MCIF_WB_BUF_4_Y_OVERRUN;\ + type MCIF_WB_BUF_4_C_OVERRUN;\ + type MCIF_WB_CLIENT_ARBITRATION_SLICE;\ + type MCIF_WB_TIME_PER_PIXEL;\ + type WM_CHANGE_ACK_FORCE_ON;\ + type MCIF_WB_CLI_WATERMARK_MASK;\ + type MCIF_WB_TEST_DEBUG_INDEX;\ + type MCIF_WB_TEST_DEBUG_DATA;\ + type MCIF_WB_BUF_1_ADDR_Y;\ + type MCIF_WB_BUF_1_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_1_ADDR_C;\ + type MCIF_WB_BUF_1_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_2_ADDR_Y;\ + type MCIF_WB_BUF_2_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_2_ADDR_C;\ + type MCIF_WB_BUF_2_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_3_ADDR_Y;\ + type MCIF_WB_BUF_3_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_3_ADDR_C;\ + type MCIF_WB_BUF_3_ADDR_C_OFFSET;\ + type MCIF_WB_BUF_4_ADDR_Y;\ + type MCIF_WB_BUF_4_ADDR_Y_OFFSET;\ + type MCIF_WB_BUF_4_ADDR_C;\ + type MCIF_WB_BUF_4_ADDR_C_OFFSET;\ + type MCIF_WB_BUFMGR_VCE_LOCK_IGNORE;\ + type MCIF_WB_BUFMGR_VCE_INT_EN;\ + type MCIF_WB_BUFMGR_VCE_INT_ACK;\ + type MCIF_WB_BUFMGR_VCE_SLICE_INT_EN;\ + type MCIF_WB_BUFMGR_VCE_LOCK;\ + type MCIF_WB_BUFMGR_SLICE_SIZE;\ + type NB_PSTATE_CHANGE_REFRESH_WATERMARK;\ + type NB_PSTATE_CHANGE_URGENT_DURING_REQUEST;\ + type NB_PSTATE_CHANGE_FORCE_ON;\ + type NB_PSTATE_ALLOW_FOR_URGENT;\ + type NB_PSTATE_CHANGE_WATERMARK_MASK;\ + type MCIF_WB_CLI_WATERMARK;\ + type MCIF_WB_CLI_CLOCK_GATER_OVERRIDE;\ + type MCIF_WB_PITCH_SIZE_WARMUP;\ + type DIS_REFRESH_UNDER_NBPREQ;\ + type PERFRAME_SELF_REFRESH;\ + type MAX_SCALED_TIME_TO_URGENT;\ + type MCIF_WB_SECURITY_LEVEL;\ + type MCIF_WB_BUF_LUMA_SIZE;\ + type MCIF_WB_BUF_CHROMA_SIZE;\ + type MCIF_WB_BUF_1_ADDR_Y_HIGH;\ + type MCIF_WB_BUF_1_ADDR_C_HIGH;\ + type MCIF_WB_BUF_2_ADDR_Y_HIGH;\ + type MCIF_WB_BUF_2_ADDR_C_HIGH;\ + type MCIF_WB_BUF_3_ADDR_Y_HIGH;\ + type MCIF_WB_BUF_3_ADDR_C_HIGH;\ + type MCIF_WB_BUF_4_ADDR_Y_HIGH;\ + type MCIF_WB_BUF_4_ADDR_C_HIGH;\ + type MCIF_WB_BUF_1_RESOLUTION_WIDTH;\ + type MCIF_WB_BUF_1_RESOLUTION_HEIGHT;\ + type MCIF_WB_BUF_2_RESOLUTION_WIDTH;\ + type MCIF_WB_BUF_2_RESOLUTION_HEIGHT;\ + type MCIF_WB_BUF_3_RESOLUTION_WIDTH;\ + type MCIF_WB_BUF_3_RESOLUTION_HEIGHT;\ + type MCIF_WB_BUF_4_RESOLUTION_WIDTH;\ + type MCIF_WB_BUF_4_RESOLUTION_HEIGHT;\ + type MCIF_WB0_WM_CHG_SEL;\ + type MCIF_WB0_WM_CHG_REQ;\ + type MCIF_WB0_WM_CHG_ACK_INT_DIS;\ + type MCIF_WB0_WM_CHG_ACK_INT_STATUS + +#define MCIF_WB_REG_VARIABLE_LIST_DCN2_0 \ + uint32_t MCIF_WB_BUFMGR_SW_CONTROL;\ + uint32_t MCIF_WB_BUFMGR_CUR_LINE_R;\ + uint32_t MCIF_WB_BUFMGR_STATUS;\ + uint32_t MCIF_WB_BUF_PITCH;\ + uint32_t MCIF_WB_BUF_1_STATUS;\ + uint32_t MCIF_WB_BUF_1_STATUS2;\ + uint32_t MCIF_WB_BUF_2_STATUS;\ + uint32_t MCIF_WB_BUF_2_STATUS2;\ + uint32_t MCIF_WB_BUF_3_STATUS;\ + uint32_t MCIF_WB_BUF_3_STATUS2;\ + uint32_t MCIF_WB_BUF_4_STATUS;\ + uint32_t MCIF_WB_BUF_4_STATUS2;\ + uint32_t MCIF_WB_ARBITRATION_CONTROL;\ + uint32_t MCIF_WB_SCLK_CHANGE;\ + uint32_t MCIF_WB_TEST_DEBUG_INDEX;\ + uint32_t MCIF_WB_TEST_DEBUG_DATA;\ + uint32_t MCIF_WB_BUF_1_ADDR_Y;\ + uint32_t MCIF_WB_BUF_1_ADDR_Y_OFFSET;\ + uint32_t MCIF_WB_BUF_1_ADDR_C;\ + uint32_t MCIF_WB_BUF_1_ADDR_C_OFFSET;\ + uint32_t MCIF_WB_BUF_2_ADDR_Y;\ + uint32_t MCIF_WB_BUF_2_ADDR_Y_OFFSET;\ + uint32_t MCIF_WB_BUF_2_ADDR_C;\ + uint32_t MCIF_WB_BUF_2_ADDR_C_OFFSET;\ + uint32_t MCIF_WB_BUF_3_ADDR_Y;\ + uint32_t MCIF_WB_BUF_3_ADDR_Y_OFFSET;\ + uint32_t MCIF_WB_BUF_3_ADDR_C;\ + uint32_t MCIF_WB_BUF_3_ADDR_C_OFFSET;\ + uint32_t MCIF_WB_BUF_4_ADDR_Y;\ + uint32_t MCIF_WB_BUF_4_ADDR_Y_OFFSET;\ + uint32_t MCIF_WB_BUF_4_ADDR_C;\ + uint32_t MCIF_WB_BUF_4_ADDR_C_OFFSET;\ + uint32_t MCIF_WB_BUFMGR_VCE_CONTROL;\ + uint32_t MCIF_WB_NB_PSTATE_LATENCY_WATERMARK;\ + uint32_t MCIF_WB_NB_PSTATE_CONTROL;\ + uint32_t MCIF_WB_WATERMARK;\ + uint32_t MCIF_WB_CLOCK_GATER_CONTROL;\ + uint32_t MCIF_WB_WARM_UP_CNTL;\ + uint32_t MCIF_WB_SELF_REFRESH_CONTROL;\ + uint32_t MULTI_LEVEL_QOS_CTRL;\ + uint32_t MCIF_WB_SECURITY_LEVEL;\ + uint32_t MCIF_WB_BUF_LUMA_SIZE;\ + uint32_t MCIF_WB_BUF_CHROMA_SIZE;\ + uint32_t MCIF_WB_BUF_1_ADDR_Y_HIGH;\ + uint32_t MCIF_WB_BUF_1_ADDR_C_HIGH;\ + uint32_t MCIF_WB_BUF_2_ADDR_Y_HIGH;\ + uint32_t MCIF_WB_BUF_2_ADDR_C_HIGH;\ + uint32_t MCIF_WB_BUF_3_ADDR_Y_HIGH;\ + uint32_t MCIF_WB_BUF_3_ADDR_C_HIGH;\ + uint32_t MCIF_WB_BUF_4_ADDR_Y_HIGH;\ + uint32_t MCIF_WB_BUF_4_ADDR_C_HIGH;\ + uint32_t MCIF_WB_BUF_1_RESOLUTION;\ + uint32_t MCIF_WB_BUF_2_RESOLUTION;\ + uint32_t MCIF_WB_BUF_3_RESOLUTION;\ + uint32_t MCIF_WB_BUF_4_RESOLUTION;\ + uint32_t SMU_WM_CONTROL + +struct dcn20_mmhubbub_registers { + MCIF_WB_REG_VARIABLE_LIST_DCN2_0; +}; + + +struct dcn20_mmhubbub_mask { + MCIF_WB_REG_FIELD_LIST_DCN2_0(uint32_t); +}; + +struct dcn20_mmhubbub_shift { + MCIF_WB_REG_FIELD_LIST_DCN2_0(uint8_t); +}; + +struct dcn20_mmhubbub { + struct mcif_wb base; + const struct dcn20_mmhubbub_registers *mcif_wb_regs; + const struct dcn20_mmhubbub_shift *mcif_wb_shift; + const struct dcn20_mmhubbub_mask *mcif_wb_mask; +}; + +void mmhubbub2_config_mcif_irq(struct mcif_wb *mcif_wb, + struct mcif_irq_params *params); + +void mmhubbub2_enable_mcif(struct mcif_wb *mcif_wb); + +void mmhubbub2_disable_mcif(struct mcif_wb *mcif_wb); + +void mcifwb2_dump_frame(struct mcif_wb *mcif_wb, + struct mcif_buf_params *mcif_params, + enum dwb_scaler_mode out_format, + unsigned int dest_width, + unsigned int dest_height, + struct mcif_wb_frame_dump_info *dump_info, + unsigned char *luma_buffer, + unsigned char *chroma_buffer, + unsigned char *dest_luma_buffer, + unsigned char *dest_chroma_buffer); + +void dcn20_mmhubbub_construct(struct dcn20_mmhubbub *mcif_wb20, + struct dc_context *ctx, + const struct dcn20_mmhubbub_registers *mcif_wb_regs, + const struct dcn20_mmhubbub_shift *mcif_wb_shift, + const struct dcn20_mmhubbub_mask *mcif_wb_mask, + int inst); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c new file mode 100644 index 000000000000..240749e4cf83 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -0,0 +1,526 @@ +/* + * 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 "dcn20_mpc.h" + +#include "reg_helper.h" +#include "dc.h" +#include "mem_input.h" +#include "dcn10/dcn10_cm_common.h" + +#define REG(reg)\ + mpc20->mpc_regs->reg + +#define CTX \ + mpc20->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + mpc20->mpc_shift->field_name, mpc20->mpc_mask->field_name + +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +void mpc2_update_blending( + struct mpc *mpc, + struct mpcc_blnd_cfg *blnd_cfg, + int mpcc_id) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + struct mpcc *mpcc = mpc1_get_mpcc(mpc, mpcc_id); + + REG_UPDATE_7(MPCC_CONTROL[mpcc_id], + MPCC_ALPHA_BLND_MODE, blnd_cfg->alpha_mode, + MPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha, + MPCC_BLND_ACTIVE_OVERLAP_ONLY, blnd_cfg->overlap_only, + MPCC_GLOBAL_ALPHA, blnd_cfg->global_alpha, + MPCC_GLOBAL_GAIN, blnd_cfg->global_gain, + MPCC_BG_BPC, blnd_cfg->background_color_bpc, + MPCC_BOT_GAIN_MODE, blnd_cfg->bottom_gain_mode); + + REG_SET(MPCC_TOP_GAIN[mpcc_id], 0, MPCC_TOP_GAIN, blnd_cfg->top_gain); + REG_SET(MPCC_BOT_GAIN_INSIDE[mpcc_id], 0, MPCC_BOT_GAIN_INSIDE, blnd_cfg->bottom_inside_gain); + REG_SET(MPCC_BOT_GAIN_OUTSIDE[mpcc_id], 0, MPCC_BOT_GAIN_OUTSIDE, blnd_cfg->bottom_outside_gain); + + mpc1_set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id); + mpcc->blnd_cfg = *blnd_cfg; +} + +void mpc2_set_denorm( + struct mpc *mpc, + int opp_id, + enum dc_color_depth output_depth) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + int denorm_mode = 0; + + switch (output_depth) { + case COLOR_DEPTH_666: + denorm_mode = 1; + break; + case COLOR_DEPTH_888: + denorm_mode = 2; + break; + case COLOR_DEPTH_999: + denorm_mode = 3; + break; + case COLOR_DEPTH_101010: + denorm_mode = 4; + break; + case COLOR_DEPTH_111111: + denorm_mode = 5; + break; + case COLOR_DEPTH_121212: + denorm_mode = 6; + break; + case COLOR_DEPTH_141414: + case COLOR_DEPTH_161616: + default: + /* not valid used case! */ + break; + } + + REG_UPDATE(DENORM_CONTROL[opp_id], + MPC_OUT_DENORM_MODE, denorm_mode); +} + +void mpc2_set_denorm_clamp( + struct mpc *mpc, + int opp_id, + struct mpc_denorm_clamp denorm_clamp) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + REG_UPDATE_2(DENORM_CONTROL[opp_id], + MPC_OUT_DENORM_CLAMP_MAX_R_CR, denorm_clamp.clamp_max_r_cr, + MPC_OUT_DENORM_CLAMP_MIN_R_CR, denorm_clamp.clamp_min_r_cr); + REG_UPDATE_2(DENORM_CLAMP_G_Y[opp_id], + MPC_OUT_DENORM_CLAMP_MAX_G_Y, denorm_clamp.clamp_max_g_y, + MPC_OUT_DENORM_CLAMP_MIN_G_Y, denorm_clamp.clamp_min_g_y); + REG_UPDATE_2(DENORM_CLAMP_B_CB[opp_id], + MPC_OUT_DENORM_CLAMP_MAX_B_CB, denorm_clamp.clamp_max_b_cb, + MPC_OUT_DENORM_CLAMP_MIN_B_CB, denorm_clamp.clamp_min_b_cb); +} + + + +void mpc2_set_output_csc( + struct mpc *mpc, + int opp_id, + const uint16_t *regval, + enum mpc_output_csc_mode ocsc_mode) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + struct color_matrices_reg ocsc_regs; + + REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); + + if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) + return; + + if (regval == NULL) { + BREAK_TO_DEBUGGER(); + return; + } + + ocsc_regs.shifts.csc_c11 = mpc20->mpc_shift->MPC_OCSC_C11_A; + ocsc_regs.masks.csc_c11 = mpc20->mpc_mask->MPC_OCSC_C11_A; + ocsc_regs.shifts.csc_c12 = mpc20->mpc_shift->MPC_OCSC_C12_A; + ocsc_regs.masks.csc_c12 = mpc20->mpc_mask->MPC_OCSC_C12_A; + + if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) { + ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_A[opp_id]); + ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_A[opp_id]); + } else { + ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_B[opp_id]); + ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_B[opp_id]); + } + cm_helper_program_color_matrices( + mpc20->base.ctx, + regval, + &ocsc_regs); +} + +void mpc2_set_ocsc_default( + struct mpc *mpc, + int opp_id, + enum dc_color_space color_space, + enum mpc_output_csc_mode ocsc_mode) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + uint32_t arr_size; + struct color_matrices_reg ocsc_regs; + const uint16_t *regval = NULL; + + REG_SET(CSC_MODE[opp_id], 0, MPC_OCSC_MODE, ocsc_mode); + if (ocsc_mode == MPC_OUTPUT_CSC_DISABLE) + return; + + regval = find_color_matrix(color_space, &arr_size); + + if (regval == NULL) { + BREAK_TO_DEBUGGER(); + return; + } + + ocsc_regs.shifts.csc_c11 = mpc20->mpc_shift->MPC_OCSC_C11_A; + ocsc_regs.masks.csc_c11 = mpc20->mpc_mask->MPC_OCSC_C11_A; + ocsc_regs.shifts.csc_c12 = mpc20->mpc_shift->MPC_OCSC_C12_A; + ocsc_regs.masks.csc_c12 = mpc20->mpc_mask->MPC_OCSC_C12_A; + + + if (ocsc_mode == MPC_OUTPUT_CSC_COEF_A) { + ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_A[opp_id]); + ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_A[opp_id]); + } else { + ocsc_regs.csc_c11_c12 = REG(CSC_C11_C12_B[opp_id]); + ocsc_regs.csc_c33_c34 = REG(CSC_C33_C34_B[opp_id]); + } + + cm_helper_program_color_matrices( + mpc20->base.ctx, + regval, + &ocsc_regs); +} + +static void mpc2_ogam_get_reg_field( + struct mpc *mpc, + struct xfer_func_reg *reg) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + reg->shifts.exp_region0_lut_offset = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->masks.exp_region0_lut_offset = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->shifts.exp_region0_num_segments = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->masks.exp_region0_num_segments = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->shifts.exp_region1_lut_offset = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->masks.exp_region1_lut_offset = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->shifts.exp_region1_num_segments = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->masks.exp_region1_num_segments = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->shifts.field_region_end = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_B; + reg->masks.field_region_end = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_B; + reg->shifts.field_region_end_slope = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B; + reg->masks.field_region_end_slope = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B; + reg->shifts.field_region_end_base = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B; + reg->masks.field_region_end_base = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B; + reg->shifts.field_region_linear_slope = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; + reg->masks.field_region_linear_slope = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; + reg->shifts.exp_region_start = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_START_B; + reg->masks.exp_region_start = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_B; + reg->shifts.exp_resion_start_segment = mpc20->mpc_shift->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B; + reg->masks.exp_resion_start_segment = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B; +} + +static void mpc20_power_on_ogam_lut( + struct mpc *mpc, int mpcc_id, + bool power_on) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + REG_SET(MPCC_MEM_PWR_CTRL[mpcc_id], 0, + MPCC_OGAM_MEM_PWR_FORCE, power_on == true ? 0:1); + +} + +static void mpc20_configure_ogam_lut( + struct mpc *mpc, int mpcc_id, + bool is_ram_a) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + REG_UPDATE_2(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_id], + MPCC_OGAM_LUT_WRITE_EN_MASK, 7, + MPCC_OGAM_LUT_RAM_SEL, is_ram_a == true ? 0:1); + + REG_SET(MPCC_OGAM_LUT_INDEX[mpcc_id], 0, MPCC_OGAM_LUT_INDEX, 0); +} + +static enum dc_lut_mode mpc20_get_ogam_current(struct mpc *mpc, int mpcc_id) +{ + enum dc_lut_mode mode; + uint32_t state_mode; + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + REG_GET(MPCC_OGAM_LUT_RAM_CONTROL[mpcc_id], + MPCC_OGAM_CONFIG_STATUS, &state_mode); + + switch (state_mode) { + case 0: + mode = LUT_BYPASS; + break; + case 1: + mode = LUT_RAM_A; + break; + case 2: + mode = LUT_RAM_B; + break; + default: + mode = LUT_BYPASS; + break; + } + return mode; +} + +static void mpc2_program_lutb(struct mpc *mpc, int mpcc_id, + const struct pwl_params *params) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + struct xfer_func_reg gam_regs; + + mpc2_ogam_get_reg_field(mpc, &gam_regs); + + gam_regs.start_cntl_b = REG(MPCC_OGAM_RAMB_START_CNTL_B[mpcc_id]); + gam_regs.start_cntl_g = REG(MPCC_OGAM_RAMB_START_CNTL_G[mpcc_id]); + gam_regs.start_cntl_r = REG(MPCC_OGAM_RAMB_START_CNTL_R[mpcc_id]); + gam_regs.start_slope_cntl_b = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_B[mpcc_id]); + gam_regs.start_slope_cntl_g = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_G[mpcc_id]); + gam_regs.start_slope_cntl_r = REG(MPCC_OGAM_RAMB_SLOPE_CNTL_R[mpcc_id]); + gam_regs.start_end_cntl1_b = REG(MPCC_OGAM_RAMB_END_CNTL1_B[mpcc_id]); + gam_regs.start_end_cntl2_b = REG(MPCC_OGAM_RAMB_END_CNTL2_B[mpcc_id]); + gam_regs.start_end_cntl1_g = REG(MPCC_OGAM_RAMB_END_CNTL1_G[mpcc_id]); + gam_regs.start_end_cntl2_g = REG(MPCC_OGAM_RAMB_END_CNTL2_G[mpcc_id]); + gam_regs.start_end_cntl1_r = REG(MPCC_OGAM_RAMB_END_CNTL1_R[mpcc_id]); + gam_regs.start_end_cntl2_r = REG(MPCC_OGAM_RAMB_END_CNTL2_R[mpcc_id]); + gam_regs.region_start = REG(MPCC_OGAM_RAMB_REGION_0_1[mpcc_id]); + gam_regs.region_end = REG(MPCC_OGAM_RAMB_REGION_32_33[mpcc_id]); + + cm_helper_program_xfer_func(mpc20->base.ctx, params, &gam_regs); + +} + +static void mpc2_program_luta(struct mpc *mpc, int mpcc_id, + const struct pwl_params *params) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + struct xfer_func_reg gam_regs; + + mpc2_ogam_get_reg_field(mpc, &gam_regs); + + gam_regs.start_cntl_b = REG(MPCC_OGAM_RAMA_START_CNTL_B[mpcc_id]); + gam_regs.start_cntl_g = REG(MPCC_OGAM_RAMA_START_CNTL_G[mpcc_id]); + gam_regs.start_cntl_r = REG(MPCC_OGAM_RAMA_START_CNTL_R[mpcc_id]); + gam_regs.start_slope_cntl_b = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_B[mpcc_id]); + gam_regs.start_slope_cntl_g = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_G[mpcc_id]); + gam_regs.start_slope_cntl_r = REG(MPCC_OGAM_RAMA_SLOPE_CNTL_R[mpcc_id]); + gam_regs.start_end_cntl1_b = REG(MPCC_OGAM_RAMA_END_CNTL1_B[mpcc_id]); + gam_regs.start_end_cntl2_b = REG(MPCC_OGAM_RAMA_END_CNTL2_B[mpcc_id]); + gam_regs.start_end_cntl1_g = REG(MPCC_OGAM_RAMA_END_CNTL1_G[mpcc_id]); + gam_regs.start_end_cntl2_g = REG(MPCC_OGAM_RAMA_END_CNTL2_G[mpcc_id]); + gam_regs.start_end_cntl1_r = REG(MPCC_OGAM_RAMA_END_CNTL1_R[mpcc_id]); + gam_regs.start_end_cntl2_r = REG(MPCC_OGAM_RAMA_END_CNTL2_R[mpcc_id]); + gam_regs.region_start = REG(MPCC_OGAM_RAMA_REGION_0_1[mpcc_id]); + gam_regs.region_end = REG(MPCC_OGAM_RAMA_REGION_32_33[mpcc_id]); + + cm_helper_program_xfer_func(mpc20->base.ctx, params, &gam_regs); + +} + +static void mpc20_program_ogam_pwl( + struct mpc *mpc, int mpcc_id, + const struct pwl_result_data *rgb, + uint32_t num) +{ + uint32_t i; + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + for (i = 0 ; i < num; i++) { + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].red_reg); + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].green_reg); + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].blue_reg); + + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, + MPCC_OGAM_LUT_DATA, rgb[i].delta_red_reg); + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, + MPCC_OGAM_LUT_DATA, rgb[i].delta_green_reg); + REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, + MPCC_OGAM_LUT_DATA, rgb[i].delta_blue_reg); + + } + +} + +void apply_DEDCN20_305_wa( + struct mpc *mpc, + int mpcc_id, enum dc_lut_mode current_mode, + enum dc_lut_mode next_mode) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + if (mpc->ctx->dc->work_arounds.dedcn20_305_wa == false) { + /*hw fixed in new review*/ + return; + } + if (current_mode == LUT_BYPASS) + /*this will only work if OTG is locked. + *if we were to support OTG unlock case, + *the workaround will be more complex + */ + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, + next_mode == LUT_RAM_A ? 1:2); +} + +void mpc2_set_output_gamma( + struct mpc *mpc, + int mpcc_id, + const struct pwl_params *params) +{ + enum dc_lut_mode current_mode; + enum dc_lut_mode next_mode; + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + + if (params == NULL) { + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); + return; + } + current_mode = mpc20_get_ogam_current(mpc, mpcc_id); + if (current_mode == LUT_BYPASS || current_mode == LUT_RAM_A) + next_mode = LUT_RAM_B; + else + next_mode = LUT_RAM_A; + + mpc20_power_on_ogam_lut(mpc, mpcc_id, true); + mpc20_configure_ogam_lut(mpc, mpcc_id, next_mode == LUT_RAM_A ? true:false); + + if (next_mode == LUT_RAM_A) + mpc2_program_luta(mpc, mpcc_id, params); + else + mpc2_program_lutb(mpc, mpcc_id, params); + + apply_DEDCN20_305_wa(mpc, mpcc_id, current_mode, next_mode); + + mpc20_program_ogam_pwl( + mpc, mpcc_id, params->rgb_resulted, params->hw_points_num); + + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, + next_mode == LUT_RAM_A ? 1:2); +} +void mpc2_assert_idle_mpcc(struct mpc *mpc, int id) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + unsigned int mpc_disabled; + + ASSERT(!(mpc20->mpcc_in_use_mask & 1 << id)); + REG_GET(MPCC_STATUS[id], MPCC_DISABLED, &mpc_disabled); + if (mpc_disabled) + return; + + REG_WAIT(MPCC_STATUS[id], + MPCC_IDLE, 1, + 1, 100000); +} + +void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id) +{ + struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + unsigned int top_sel, mpc_busy, mpc_idle, mpc_disabled; + REG_GET(MPCC_STATUS[mpcc_id], MPCC_DISABLED, &mpc_disabled); + + if (mpc_disabled) { + ASSERT(0); + return; + } + + REG_GET(MPCC_TOP_SEL[mpcc_id], + MPCC_TOP_SEL, &top_sel); + + if (top_sel == 0xf) { + REG_GET_2(MPCC_STATUS[mpcc_id], + MPCC_BUSY, &mpc_busy, + MPCC_IDLE, &mpc_idle); + + ASSERT(mpc_busy == 0); + ASSERT(mpc_idle == 1); + } +} + +static void mpc2_init_mpcc(struct mpcc *mpcc, int mpcc_inst) +{ + mpcc->mpcc_id = mpcc_inst; + mpcc->dpp_id = 0xf; + mpcc->mpcc_bot = NULL; + mpcc->blnd_cfg.overlap_only = false; + mpcc->blnd_cfg.global_alpha = 0xff; + mpcc->blnd_cfg.global_gain = 0xff; + mpcc->blnd_cfg.background_color_bpc = 4; + mpcc->blnd_cfg.bottom_gain_mode = 0; + mpcc->blnd_cfg.top_gain = 0x1f000; + mpcc->blnd_cfg.bottom_inside_gain = 0x1f000; + mpcc->blnd_cfg.bottom_outside_gain = 0x1f000; + mpcc->sm_cfg.enable = false; +} + +struct mpcc *mpc2_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id) +{ + struct mpcc *tmp_mpcc = tree->opp_list; + + while (tmp_mpcc != NULL) { + if (tmp_mpcc->dpp_id == 0xf || tmp_mpcc->dpp_id == dpp_id) + return tmp_mpcc; + tmp_mpcc = tmp_mpcc->mpcc_bot; + } + return NULL; +} + +const struct mpc_funcs dcn20_mpc_funcs = { + .read_mpcc_state = mpc1_read_mpcc_state, + .insert_plane = mpc1_insert_plane, + .remove_mpcc = mpc1_remove_mpcc, + .mpc_init = mpc1_mpc_init, + .update_blending = mpc2_update_blending, + .get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp, + .wait_for_idle = mpc2_assert_idle_mpcc, + .assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect, + .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw, + .set_denorm = mpc2_set_denorm, + .set_denorm_clamp = mpc2_set_denorm_clamp, + .set_output_csc = mpc2_set_output_csc, + .set_ocsc_default = mpc2_set_ocsc_default, + .set_output_gamma = mpc2_set_output_gamma, +}; + +void dcn20_mpc_construct(struct dcn20_mpc *mpc20, + struct dc_context *ctx, + const struct dcn20_mpc_registers *mpc_regs, + const struct dcn20_mpc_shift *mpc_shift, + const struct dcn20_mpc_mask *mpc_mask, + int num_mpcc) +{ + int i; + + mpc20->base.ctx = ctx; + + mpc20->base.funcs = &dcn20_mpc_funcs; + + mpc20->mpc_regs = mpc_regs; + mpc20->mpc_shift = mpc_shift; + mpc20->mpc_mask = mpc_mask; + + mpc20->mpcc_in_use_mask = 0; + mpc20->num_mpcc = num_mpcc; + + for (i = 0; i < MAX_MPCC; i++) + mpc2_init_mpcc(&mpc20->base.mpcc_array[i], i); +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h new file mode 100644 index 000000000000..9750095d2d73 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h @@ -0,0 +1,285 @@ +/* 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 __DC_MPCC_DCN20_H__ +#define __DC_MPCC_DCN20_H__ + +#include "dcn10/dcn10_mpc.h" + +#define TO_DCN20_MPC(mpc_base) \ + container_of(mpc_base, struct dcn20_mpc, base) + +#define MPC_REG_LIST_DCN2_0(inst)\ + MPC_COMMON_REG_LIST_DCN1_0(inst),\ + SRII(MPCC_TOP_GAIN, MPCC, inst),\ + SRII(MPCC_BOT_GAIN_INSIDE, MPCC, inst),\ + SRII(MPCC_BOT_GAIN_OUTSIDE, MPCC, inst),\ + SRII(MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_START_CNTL_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_START_CNTL_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_SLOPE_CNTL_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_SLOPE_CNTL_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_SLOPE_CNTL_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL1_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL1_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL2_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL1_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_END_CNTL2_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMA_REGION_32_33, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_START_CNTL_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_START_CNTL_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_SLOPE_CNTL_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_SLOPE_CNTL_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_SLOPE_CNTL_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL1_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL2_B, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL1_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL2_G, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL1_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_END_CNTL2_R, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_RAMB_REGION_32_33, MPCC_OGAM, inst),\ + SRII(MPCC_MEM_PWR_CTRL, MPCC, inst),\ + SRII(MPCC_OGAM_LUT_INDEX, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_LUT_DATA, MPCC_OGAM, inst),\ + SRII(MPCC_OGAM_MODE, MPCC_OGAM, inst) + +#define MPC_OUT_MUX_REG_LIST_DCN2_0(inst) \ + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(inst),\ + SRII(CSC_MODE, MPC_OUT, inst),\ + SRII(CSC_C11_C12_A, MPC_OUT, inst),\ + SRII(CSC_C33_C34_A, MPC_OUT, inst),\ + SRII(CSC_C11_C12_B, MPC_OUT, inst),\ + SRII(CSC_C33_C34_B, MPC_OUT, inst),\ + SRII(DENORM_CONTROL, MPC_OUT, inst),\ + SRII(DENORM_CLAMP_G_Y, MPC_OUT, inst),\ + SRII(DENORM_CLAMP_B_CB, MPC_OUT, inst) + +#define MPC_REG_VARIABLE_LIST_DCN2_0 \ + MPC_COMMON_REG_VARIABLE_LIST \ + uint32_t MPCC_TOP_GAIN[MAX_MPCC]; \ + uint32_t MPCC_BOT_GAIN_INSIDE[MAX_MPCC]; \ + uint32_t MPCC_BOT_GAIN_OUTSIDE[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_START_CNTL_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_START_CNTL_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_START_CNTL_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_SLOPE_CNTL_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_SLOPE_CNTL_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_SLOPE_CNTL_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL1_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL2_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL1_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL2_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL1_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_END_CNTL2_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_REGION_0_1[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMA_REGION_32_33[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_START_CNTL_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_START_CNTL_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_START_CNTL_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_SLOPE_CNTL_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_SLOPE_CNTL_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_SLOPE_CNTL_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL1_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL2_B[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL1_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL2_G[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL1_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_END_CNTL2_R[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_REGION_0_1[MAX_MPCC]; \ + uint32_t MPCC_OGAM_RAMB_REGION_32_33[MAX_MPCC];\ + uint32_t MPCC_MEM_PWR_CTRL[MAX_MPCC];\ + uint32_t MPCC_OGAM_LUT_INDEX[MAX_MPCC];\ + uint32_t MPCC_OGAM_LUT_RAM_CONTROL[MAX_MPCC];\ + uint32_t MPCC_OGAM_LUT_DATA[MAX_MPCC];\ + uint32_t MPCC_OGAM_MODE[MAX_MPCC];\ + uint32_t CSC_MODE[MAX_OPP]; \ + uint32_t CSC_C11_C12_A[MAX_OPP]; \ + uint32_t CSC_C33_C34_A[MAX_OPP]; \ + uint32_t CSC_C11_C12_B[MAX_OPP]; \ + uint32_t CSC_C33_C34_B[MAX_OPP]; \ + uint32_t DENORM_CONTROL[MAX_OPP]; \ + uint32_t DENORM_CLAMP_G_Y[MAX_OPP]; \ + uint32_t DENORM_CLAMP_B_CB[MAX_OPP]; + +#define MPC_COMMON_MASK_SH_LIST_DCN2_0(mask_sh) \ + MPC_COMMON_MASK_SH_LIST_DCN1_0(mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_BG_BPC, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_BOT_GAIN_MODE, mask_sh),\ + SF(MPCC0_MPCC_TOP_GAIN, MPCC_TOP_GAIN, mask_sh),\ + SF(MPCC0_MPCC_BOT_GAIN_INSIDE, MPCC_BOT_GAIN_INSIDE, mask_sh),\ + SF(MPCC0_MPCC_BOT_GAIN_OUTSIDE, MPCC_BOT_GAIN_OUTSIDE, mask_sh),\ + SF(MPC_OUT0_CSC_MODE, MPC_OCSC_MODE, mask_sh),\ + SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C11_A, mask_sh),\ + SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C12_A, mask_sh),\ + SF(MPCC0_MPCC_STATUS, MPCC_DISABLED, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL1_B, MPCC_OGAM_RAMA_EXP_REGION_END_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_SLOPE_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_END_CNTL1_B, MPCC_OGAM_RAMB_EXP_REGION_END_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_END_CNTL2_B, MPCC_OGAM_RAMB_EXP_REGION_END_SLOPE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_END_CNTL2_B, MPCC_OGAM_RAMB_EXP_REGION_END_BASE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_SLOPE_CNTL_B, MPCC_OGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM_RAMB_EXP_REGION_START_B, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\ + SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_FORCE, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_LUT_INDEX, MPCC_OGAM_LUT_INDEX, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM_LUT_WRITE_EN_MASK, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM_LUT_RAM_SEL, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM_CONFIG_STATUS, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_LUT_DATA, MPCC_OGAM_LUT_DATA, mask_sh),\ + SF(MPCC_OGAM0_MPCC_OGAM_MODE, MPCC_OGAM_MODE, mask_sh),\ + SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_MODE, mask_sh),\ + SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_CLAMP_MAX_R_CR, mask_sh),\ + SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_CLAMP_MIN_R_CR, mask_sh),\ + SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MAX_G_Y, mask_sh),\ + SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MIN_G_Y, mask_sh),\ + SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MAX_B_CB, mask_sh),\ + SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MIN_B_CB, mask_sh) + +#define MPC_REG_FIELD_LIST_DCN2_0(type) \ + MPC_REG_FIELD_LIST(type)\ + type MPCC_BG_BPC;\ + type MPCC_BOT_GAIN_MODE;\ + type MPCC_TOP_GAIN;\ + type MPCC_BOT_GAIN_INSIDE;\ + type MPCC_BOT_GAIN_OUTSIDE;\ + type MPC_OCSC_MODE;\ + type MPC_OCSC_C11_A;\ + type MPC_OCSC_C12_A;\ + type MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET;\ + type MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS;\ + type MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET;\ + type MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS;\ + type MPCC_OGAM_RAMA_EXP_REGION_END_B;\ + type MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B;\ + type MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B;\ + type MPCC_OGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B;\ + type MPCC_OGAM_RAMA_EXP_REGION_START_B;\ + type MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B;\ + type MPCC_OGAM_RAMB_EXP_REGION0_LUT_OFFSET;\ + type MPCC_OGAM_RAMB_EXP_REGION0_NUM_SEGMENTS;\ + type MPCC_OGAM_RAMB_EXP_REGION1_LUT_OFFSET;\ + type MPCC_OGAM_RAMB_EXP_REGION1_NUM_SEGMENTS;\ + type MPCC_OGAM_RAMB_EXP_REGION_END_B;\ + type MPCC_OGAM_RAMB_EXP_REGION_END_SLOPE_B;\ + type MPCC_OGAM_RAMB_EXP_REGION_END_BASE_B;\ + type MPCC_OGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B;\ + type MPCC_OGAM_RAMB_EXP_REGION_START_B;\ + type MPCC_OGAM_RAMB_EXP_REGION_START_SEGMENT_B;\ + type MPCC_OGAM_MEM_PWR_FORCE;\ + type MPCC_OGAM_LUT_INDEX;\ + type MPCC_OGAM_LUT_WRITE_EN_MASK;\ + type MPCC_OGAM_LUT_RAM_SEL;\ + type MPCC_OGAM_CONFIG_STATUS;\ + type MPCC_OGAM_LUT_DATA;\ + type MPCC_OGAM_MODE;\ + type MPC_OUT_DENORM_MODE;\ + type MPC_OUT_DENORM_CLAMP_MAX_R_CR;\ + type MPC_OUT_DENORM_CLAMP_MIN_R_CR;\ + type MPC_OUT_DENORM_CLAMP_MAX_G_Y;\ + type MPC_OUT_DENORM_CLAMP_MIN_G_Y;\ + type MPC_OUT_DENORM_CLAMP_MAX_B_CB;\ + type MPC_OUT_DENORM_CLAMP_MIN_B_CB;\ + type MPCC_DISABLED; + +struct dcn20_mpc_registers { + MPC_REG_VARIABLE_LIST_DCN2_0 +}; + +struct dcn20_mpc_shift { + MPC_REG_FIELD_LIST_DCN2_0(uint8_t) +}; + +struct dcn20_mpc_mask { + MPC_REG_FIELD_LIST_DCN2_0(uint32_t) +}; + +struct dcn20_mpc { + struct mpc base; + + int mpcc_in_use_mask; + int num_mpcc; + const struct dcn20_mpc_registers *mpc_regs; + const struct dcn20_mpc_shift *mpc_shift; + const struct dcn20_mpc_mask *mpc_mask; +}; + +void dcn20_mpc_construct(struct dcn20_mpc *mpcc20, + struct dc_context *ctx, + const struct dcn20_mpc_registers *mpc_regs, + const struct dcn20_mpc_shift *mpc_shift, + const struct dcn20_mpc_mask *mpc_mask, + int num_mpcc); + +void mpc2_update_blending( + struct mpc *mpc, + struct mpcc_blnd_cfg *blnd_cfg, + int mpcc_id); + +void mpc2_set_denorm( + struct mpc *mpc, + int opp_id, + enum dc_color_depth output_depth); + +void mpc2_set_denorm_clamp( + struct mpc *mpc, + int opp_id, + struct mpc_denorm_clamp denorm_clamp); + +void mpc2_set_output_csc( + struct mpc *mpc, + int opp_id, + const uint16_t *regval, + enum mpc_output_csc_mode ocsc_mode); + +void mpc2_set_ocsc_default( + struct mpc *mpc, + int opp_id, + enum dc_color_space color_space, + enum mpc_output_csc_mode ocsc_mode); + +void mpc2_set_output_gamma( + struct mpc *mpc, + int mpcc_id, + const struct pwl_params *params); + +void mpc2_assert_idle_mpcc(struct mpc *mpc, int id); +void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id); +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c new file mode 100644 index 000000000000..d9e7c711a71c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c @@ -0,0 +1,355 @@ +/* + * 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 "dcn20_opp.h" +#include "reg_helper.h" + +#define REG(reg) \ + (oppn20->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + oppn20->opp_shift->field_name, oppn20->opp_mask->field_name + +#define CTX \ + oppn20->base.ctx + + +void opp2_set_disp_pattern_generator( + struct output_pixel_processor *opp, + enum controller_dp_test_pattern test_pattern, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, + int height) +{ + struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp); + enum test_pattern_color_format bit_depth; + enum test_pattern_dyn_range dyn_range; + enum test_pattern_mode mode; + + /* color ramp generator mixes 16-bits color */ + uint32_t src_bpc = 16; + /* requested bpc */ + uint32_t dst_bpc; + uint32_t index; + /* RGB values of the color bars. + * Produce two RGB colors: RGB0 - white (all Fs) + * and RGB1 - black (all 0s) + * (three RGB components for two colors) + */ + uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000}; + /* dest color (converted to the specified color format) */ + uint16_t dst_color[6]; + uint32_t inc_base; + + /* translate to bit depth */ + switch (color_depth) { + case COLOR_DEPTH_666: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; + break; + case COLOR_DEPTH_888: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + case COLOR_DEPTH_101010: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; + break; + case COLOR_DEPTH_121212: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; + break; + default: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + } + + /* set DPG dimentions */ + REG_SET_2(DPG_DIMENSIONS, 0, + DPG_ACTIVE_WIDTH, width, + DPG_ACTIVE_HEIGHT, height); + + switch (test_pattern) { + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: + { + dyn_range = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? + TEST_PATTERN_DYN_RANGE_CEA : + TEST_PATTERN_DYN_RANGE_VESA); + + REG_UPDATE_6(DPG_CONTROL, + DPG_EN, 1, + DPG_MODE, TEST_PATTERN_MODE_COLORSQUARES_RGB, + DPG_DYNAMIC_RANGE, dyn_range, + DPG_BIT_DEPTH, bit_depth, + DPG_VRES, 6, + DPG_HRES, 6); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: + case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: + { + mode = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? + TEST_PATTERN_MODE_VERTICALBARS : + TEST_PATTERN_MODE_HORIZONTALBARS); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* adjust color to the required colorFormat */ + for (index = 0; index < 6; index++) { + /* dst = 2^dstBpc * src / 2^srcBpc = src >> + * (srcBpc - dstBpc); + */ + dst_color[index] = + src_color[index] >> (src_bpc - dst_bpc); + /* DPG_COLOUR registers are 16-bit MSB aligned value with bits 3:0 hardwired to ZERO. + * XXXXXXXXXX000000 for 10 bit, + * XXXXXXXX00000000 for 8 bit, + * XXXXXX0000000000 for 6 bits + */ + dst_color[index] <<= (16 - dst_bpc); + } + + REG_SET_2(DPG_COLOUR_R_CR, 0, + DPG_COLOUR1_R_CR, dst_color[0], + DPG_COLOUR0_R_CR, dst_color[3]); + REG_SET_2(DPG_COLOUR_G_Y, 0, + DPG_COLOUR1_G_Y, dst_color[1], + DPG_COLOUR0_G_Y, dst_color[4]); + REG_SET_2(DPG_COLOUR_B_CB, 0, + DPG_COLOUR1_B_CB, dst_color[2], + DPG_COLOUR0_B_CB, dst_color[5]); + + /* enable test pattern */ + REG_UPDATE_6(DPG_CONTROL, + DPG_EN, 1, + DPG_MODE, mode, + DPG_DYNAMIC_RANGE, 0, + DPG_BIT_DEPTH, bit_depth, + DPG_VRES, 0, + DPG_HRES, 0); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: + { + mode = (bit_depth == + TEST_PATTERN_COLOR_FORMAT_BPC_10 ? + TEST_PATTERN_MODE_DUALRAMP_RGB : + TEST_PATTERN_MODE_SINGLERAMP_RGB); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* increment for the first ramp for one color gradation + * 1 gradation for 6-bit color is 2^10 + * gradations in 16-bit color + */ + inc_base = (src_bpc - dst_bpc); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + { + REG_SET_3(DPG_RAMP_CONTROL, 0, + DPG_RAMP0_OFFSET, 0, + DPG_INC0, inc_base, + DPG_INC1, 0); + REG_UPDATE_2(DPG_CONTROL, + DPG_VRES, 6, + DPG_HRES, 6); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + { + REG_SET_3(DPG_RAMP_CONTROL, 0, + DPG_RAMP0_OFFSET, 0, + DPG_INC0, inc_base, + DPG_INC1, 0); + REG_UPDATE_2(DPG_CONTROL, + DPG_VRES, 6, + DPG_HRES, 8); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + { + REG_SET_3(DPG_RAMP_CONTROL, 0, + DPG_RAMP0_OFFSET, 384 << 6, + DPG_INC0, inc_base, + DPG_INC1, inc_base + 2); + REG_UPDATE_2(DPG_CONTROL, + DPG_VRES, 5, + DPG_HRES, 8); + } + break; + default: + break; + } + + /* enable test pattern */ + REG_UPDATE_4(DPG_CONTROL, + DPG_EN, 1, + DPG_MODE, mode, + DPG_DYNAMIC_RANGE, 0, + DPG_BIT_DEPTH, bit_depth); + } + break; + case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: + { + REG_WRITE(DPG_CONTROL, 0); + REG_WRITE(DPG_COLOUR_R_CR, 0); + REG_WRITE(DPG_COLOUR_G_Y, 0); + REG_WRITE(DPG_COLOUR_B_CB, 0); + REG_WRITE(DPG_RAMP_CONTROL, 0); + } + break; + case CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR: + { + opp2_dpg_set_blank_color(opp, solid_color); + REG_UPDATE_2(DPG_CONTROL, + DPG_EN, 1, + DPG_MODE, TEST_PATTERN_MODE_HORIZONTALBARS); + + REG_SET_2(DPG_DIMENSIONS, 0, + DPG_ACTIVE_WIDTH, width, + DPG_ACTIVE_HEIGHT, height); + } + break; + default: + break; + + } +} + +void opp2_dpg_set_blank_color( + struct output_pixel_processor *opp, + const struct tg_color *color) +{ + struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp); + + /* 16-bit MSB aligned value. Bits 3:0 of this field are hardwired to ZERO */ + ASSERT(color); + REG_SET_2(DPG_COLOUR_B_CB, 0, + DPG_COLOUR1_B_CB, color->color_b_cb << 6, + DPG_COLOUR0_B_CB, color->color_b_cb << 6); + REG_SET_2(DPG_COLOUR_G_Y, 0, + DPG_COLOUR1_G_Y, color->color_g_y << 6, + DPG_COLOUR0_G_Y, color->color_g_y << 6); + REG_SET_2(DPG_COLOUR_R_CR, 0, + DPG_COLOUR1_R_CR, color->color_r_cr << 6, + DPG_COLOUR0_R_CR, color->color_r_cr << 6); +} + +bool opp2_dpg_is_blanked(struct output_pixel_processor *opp) +{ + struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp); + uint32_t dpg_en, dpg_mode; + uint32_t double_buffer_pending; + + REG_GET_2(DPG_CONTROL, + DPG_EN, &dpg_en, + DPG_MODE, &dpg_mode); + + REG_GET(DPG_STATUS, + DPG_DOUBLE_BUFFER_PENDING, &double_buffer_pending); + + return (dpg_en == 1) && + (double_buffer_pending == 0); +} + +void opp2_program_left_edge_extra_pixel ( + struct output_pixel_processor *opp, + bool count) +{ + struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp); + + /* Specifies the number of extra left edge pixels that are supplied to + * the 422 horizontal chroma sub-sample filter. + * Note that when left edge pixel is not "0", fmt pixel encoding can be in either 420 or 422 mode + * */ + REG_UPDATE(FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, count); +} + +/*****************************************/ +/* Constructor, Destructor */ +/*****************************************/ + +static struct opp_funcs dcn20_opp_funcs = { + .opp_set_dyn_expansion = opp1_set_dyn_expansion, + .opp_program_fmt = opp1_program_fmt, + .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, + .opp_program_stereo = opp1_program_stereo, + .opp_pipe_clock_control = opp1_pipe_clock_control, + .opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator, + .dpg_is_blanked = opp2_dpg_is_blanked, + .opp_dpg_set_blank_color = opp2_dpg_set_blank_color, + .opp_convert_pti = NULL, + .opp_destroy = opp1_destroy, + .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel, +}; + +void dcn20_opp_construct(struct dcn20_opp *oppn20, + struct dc_context *ctx, + uint32_t inst, + const struct dcn20_opp_registers *regs, + const struct dcn20_opp_shift *opp_shift, + const struct dcn20_opp_mask *opp_mask) +{ + oppn20->base.ctx = ctx; + oppn20->base.inst = inst; + oppn20->base.funcs = &dcn20_opp_funcs; + + oppn20->regs = regs; + oppn20->opp_shift = opp_shift; + oppn20->opp_mask = opp_mask; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h new file mode 100644 index 000000000000..abd8de9a78f8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h @@ -0,0 +1,158 @@ +/* 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 __DC_OPP_DCN20_H__ +#define __DC_OPP_DCN20_H__ + +#include "dcn10/dcn10_opp.h" + +#define TO_DCN20_OPP(opp)\ + container_of(opp, struct dcn20_opp, base) + +#define OPP_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define OPP_DPG_REG_LIST(id) \ + SRI(DPG_CONTROL, DPG, id), \ + SRI(DPG_DIMENSIONS, DPG, id), \ + SRI(DPG_COLOUR_B_CB, DPG, id), \ + SRI(DPG_COLOUR_G_Y, DPG, id), \ + SRI(DPG_COLOUR_R_CR, DPG, id), \ + SRI(DPG_RAMP_CONTROL, DPG, id), \ + SRI(DPG_STATUS, DPG, id) + +#define OPP_REG_LIST_DCN20(id) \ + OPP_REG_LIST_DCN10(id), \ + OPP_DPG_REG_LIST(id), \ + SRI(FMT_422_CONTROL, FMT, id), \ + SRI(OPPBUF_CONTROL1, OPPBUF, id) + +#define OPP_REG_VARIABLE_LIST_DCN2_0 \ + OPP_COMMON_REG_VARIABLE_LIST; \ + uint32_t FMT_422_CONTROL; \ + uint32_t DPG_CONTROL; \ + uint32_t DPG_DIMENSIONS; \ + uint32_t DPG_COLOUR_B_CB; \ + uint32_t DPG_COLOUR_G_Y; \ + uint32_t DPG_COLOUR_R_CR; \ + uint32_t DPG_RAMP_CONTROL; \ + uint32_t DPG_STATUS + +#define OPP_DPG_MASK_SH_LIST(mask_sh) \ + OPP_SF(DPG0_DPG_CONTROL, DPG_EN, mask_sh), \ + OPP_SF(DPG0_DPG_CONTROL, DPG_MODE, mask_sh), \ + OPP_SF(DPG0_DPG_CONTROL, DPG_DYNAMIC_RANGE, mask_sh), \ + OPP_SF(DPG0_DPG_CONTROL, DPG_BIT_DEPTH, mask_sh), \ + OPP_SF(DPG0_DPG_CONTROL, DPG_VRES, mask_sh), \ + OPP_SF(DPG0_DPG_CONTROL, DPG_HRES, mask_sh), \ + OPP_SF(DPG0_DPG_DIMENSIONS, DPG_ACTIVE_WIDTH, mask_sh), \ + OPP_SF(DPG0_DPG_DIMENSIONS, DPG_ACTIVE_HEIGHT, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_R_CR, DPG_COLOUR0_R_CR, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_R_CR, DPG_COLOUR1_R_CR, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_B_CB, DPG_COLOUR0_B_CB, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_B_CB, DPG_COLOUR1_B_CB, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_G_Y, DPG_COLOUR0_G_Y, mask_sh), \ + OPP_SF(DPG0_DPG_COLOUR_G_Y, DPG_COLOUR1_G_Y, mask_sh), \ + OPP_SF(DPG0_DPG_RAMP_CONTROL, DPG_RAMP0_OFFSET, mask_sh), \ + OPP_SF(DPG0_DPG_RAMP_CONTROL, DPG_INC0, mask_sh), \ + OPP_SF(DPG0_DPG_RAMP_CONTROL, DPG_INC1, mask_sh), \ + OPP_SF(DPG0_DPG_STATUS, DPG_DOUBLE_BUFFER_PENDING, mask_sh) + +#define OPP_MASK_SH_LIST_DCN20(mask_sh) \ + OPP_MASK_SH_LIST_DCN(mask_sh), \ + OPP_DPG_MASK_SH_LIST(mask_sh), \ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, mask_sh),\ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, mask_sh), \ + OPP_SF(FMT0_FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, mask_sh) + +#define OPP_DCN20_REG_FIELD_LIST(type) \ + OPP_DCN10_REG_FIELD_LIST(type); \ + type FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT; \ + type DPG_EN; \ + type DPG_MODE; \ + type DPG_DYNAMIC_RANGE; \ + type DPG_BIT_DEPTH; \ + type DPG_VRES; \ + type DPG_HRES; \ + type DPG_ACTIVE_WIDTH; \ + type DPG_ACTIVE_HEIGHT; \ + type DPG_COLOUR0_R_CR; \ + type DPG_COLOUR1_R_CR; \ + type DPG_COLOUR0_B_CB; \ + type DPG_COLOUR1_B_CB; \ + type DPG_COLOUR0_G_Y; \ + type DPG_COLOUR1_G_Y; \ + type DPG_RAMP0_OFFSET; \ + type DPG_INC0; \ + type DPG_INC1; \ + type DPG_DOUBLE_BUFFER_PENDING + +struct dcn20_opp_registers { + OPP_REG_VARIABLE_LIST_DCN2_0; +}; + +struct dcn20_opp_shift { + OPP_DCN20_REG_FIELD_LIST(uint8_t); +}; + +struct dcn20_opp_mask { + OPP_DCN20_REG_FIELD_LIST(uint32_t); +}; + +struct dcn20_opp { + struct output_pixel_processor base; + + const struct dcn20_opp_registers *regs; + const struct dcn20_opp_shift *opp_shift; + const struct dcn20_opp_mask *opp_mask; + + bool is_write_to_ram_a_safe; +}; + +void dcn20_opp_construct(struct dcn20_opp *oppn20, + struct dc_context *ctx, + uint32_t inst, + const struct dcn20_opp_registers *regs, + const struct dcn20_opp_shift *opp_shift, + const struct dcn20_opp_mask *opp_mask); + +void opp2_set_disp_pattern_generator( + struct output_pixel_processor *opp, + enum controller_dp_test_pattern test_pattern, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, + int height); + +bool opp2_dpg_is_blanked(struct output_pixel_processor *opp); + +void opp2_dpg_set_blank_color( + struct output_pixel_processor *opp, + const struct tg_color *color); + +void opp2_program_left_edge_extra_pixel ( + struct output_pixel_processor *opp, + bool count); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c new file mode 100644 index 000000000000..26a66ccf6e72 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c @@ -0,0 +1,542 @@ +/* + * 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 "reg_helper.h" +#include "dcn20_optc.h" +#include "dc.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +/** + * Enable CRTC + * Enable CRTC - call ASIC Control Object to enable Timing generator. + */ +bool optc2_enable_crtc(struct timing_generator *optc) +{ + /* TODO FPGA wait for answer + * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE + * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK + */ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG. For DCN1.0, ODM is remoed. + * OPP and OPTC should 1:1 mapping + */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 1); + + return true; +} + +/** + * DRR double buffering control to select buffer point + * for V_TOTAL, H_TOTAL, VTOTAL_MIN, VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers + * Options: anytime, start of frame, dp start of frame (range timing) + */ +void optc2_set_timing_db_mode(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + uint32_t blank_data_double_buffer_enable = enable ? 1 : 0; + + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, + OTG_RANGE_TIMING_DBUF_UPDATE_MODE, blank_data_double_buffer_enable); +} + +/** + *For the below, I'm not sure how your GSL parameters are stored in your env, + * so I will assume a gsl_params struct for now + */ +void optc2_set_gsl(struct timing_generator *optc, + const struct gsl_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + +/** + * There are (MAX_OPTC+1)/2 gsl groups available for use. + * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1, + * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves. + */ + REG_UPDATE_5(OTG_GSL_CONTROL, + OTG_GSL0_EN, params->gsl0_en, + OTG_GSL1_EN, params->gsl1_en, + OTG_GSL2_EN, params->gsl2_en, + OTG_GSL_MASTER_EN, params->gsl_master_en, + OTG_GSL_MASTER_MODE, params->gsl_master_mode); +} + + +/* Use the gsl allow flip as the master update lock */ +void optc2_use_gsl_as_master_update_lock(struct timing_generator *optc, + const struct gsl_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_GSL_CONTROL, + OTG_MASTER_UPDATE_LOCK_GSL_EN, params->master_update_lock_gsl_en); +} + +/* You can control the GSL timing by limiting GSL to a window (X,Y) */ +void optc2_set_gsl_window(struct timing_generator *optc, + const struct gsl_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_2(OTG_GSL_WINDOW_X, 0, + OTG_GSL_WINDOW_START_X, params->gsl_window_start_x, + OTG_GSL_WINDOW_END_X, params->gsl_window_end_x); + REG_SET_2(OTG_GSL_WINDOW_Y, 0, + OTG_GSL_WINDOW_START_Y, params->gsl_window_start_y, + OTG_GSL_WINDOW_END_Y, params->gsl_window_end_y); +} + +/** + * Vupdate keepout can be set to a window to block the update lock for that pipe from changing. + * Start offset begins with vstartup and goes for x number of clocks, + * end offset starts from end of vupdate to x number of clocks. + */ +void optc2_set_vupdate_keepout(struct timing_generator *optc, + const struct vupdate_keepout_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, params->start_offset, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, params->end_offset, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, params->enable); +} + +void optc2_set_gsl_source_select( + struct timing_generator *optc, + int group_idx, + uint32_t gsl_ready_signal) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + switch (group_idx) { + case 1: + REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal); + break; + case 2: + REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal); + break; + case 3: + REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal); + break; + default: + break; + } +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* DSC encoder frame start controls: x = h position, line_num = # of lines from vstartup */ +void optc2_set_dsc_encoder_frame_start(struct timing_generator *optc, + int x_position, + int line_num) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_2(OTG_DSC_START_POSITION, 0, + OTG_DSC_START_POSITION_X, x_position, + OTG_DSC_START_POSITION_LINE_NUM, line_num); +} + +/* Set DSC-related configuration. + * dsc_mode: 0 disables DSC, other values enable DSC in specified format + * sc_bytes_per_pixel: Bytes per pixel in u3.28 format + * dsc_slice_width: Slice width in pixels + */ +void optc2_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t data_format = 0; + /* skip if dsc mode is not changed */ + data_format = dm_read_reg(CTX, REG(OPTC_DATA_FORMAT_CONTROL)); + + data_format = data_format & 0x30; /* bit5:4 */ + data_format = data_format >> 4; + + if (data_format == dsc_mode) + return; + + REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, + OPTC_DSC_MODE, dsc_mode); + + REG_SET(OPTC_BYTES_PER_PIXEL, 0, + OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_DSC_SLICE_WIDTH, dsc_slice_width); +} +#endif + +/** + * PTI i think is already done somewhere else for 2ka + * (opp?, please double check. + * OPTC side only has 1 register to set for PTI_ENABLE) + */ + +void optc2_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t h_div_2 = 0; + + optc1->comb_opp_id = 0xf; + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf); + REG_WRITE(OTG_H_TIMING_CNTL, 0); + + h_div_2 = optc1_is_two_pixels_per_containter(dc_crtc_timing); + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_BY2, h_div_2); + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); +} + +void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, + int mpcc_hactive, enum dc_pixel_encoding pixel_encoding) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */ + int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf; + uint32_t data_fmt = 0; + + /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic + * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); + * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start + * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, + * MASTER_UPDATE_LOCK_DB_X, 160, + * MASTER_UPDATE_LOCK_DB_Y, 240); + */ + if (REG(OPTC_MEMORY_CONFIG)) + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask << (optc->inst * 4)); + + if (pixel_encoding == PIXEL_ENCODING_YCBCR422) + data_fmt = 1; + else if (pixel_encoding == PIXEL_ENCODING_YCBCR420) + data_fmt = 2; + + REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); + + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, combine_opp_id); + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); + optc1->comb_opp_id = combine_opp_id; +} + +void optc2_get_optc_source(struct timing_generator *optc, + uint32_t *num_of_src_opp, + uint32_t *src_opp_id_0, + uint32_t *src_opp_id_1) +{ + uint32_t num_of_input_segments; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET_3(OPTC_DATA_SOURCE_SELECT, + OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments, + OPTC_SEG0_SRC_SEL, src_opp_id_0, + OPTC_SEG1_SRC_SEL, src_opp_id_1); + + if (num_of_input_segments == 1) + *num_of_src_opp = 2; + else + *num_of_src_opp = 1; +} + +void optc2_set_dwb_source(struct timing_generator *optc, + uint32_t dwb_pipe_inst) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (dwb_pipe_inst == 0) + REG_UPDATE(DWB_SOURCE_SELECT, + OPTC_DWB0_SOURCE_SELECT, optc->inst); + else if (dwb_pipe_inst == 1) + REG_UPDATE(DWB_SOURCE_SELECT, + OPTC_DWB1_SOURCE_SELECT, optc->inst); +} + +void optc2_triplebuffer_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +void optc2_triplebuffer_unlock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); + +} + + +void optc2_setup_global_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t v_blank_start = 0; + uint32_t h_blank_start = 0, h_total = 0; + + REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 1); + + REG_SET(OTG_GLOBAL_CONTROL2, 0, DIG_UPDATE_LOCATION, 20); + + REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); + + REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); + + REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &h_total); + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + h_blank_start - 200 - 1, + MASTER_UPDATE_LOCK_DB_Y, + v_blank_start - 1); +} + +void optc2_lock_global(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + /* Should be fast, status does not update on maximus */ + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +void optc2_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + /* Should be fast, status does not update on maximus */ + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +void optc2_lock_doublebuffer_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t v_blank_start = 0; + uint32_t h_blank_start = 0; + + REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 1); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1, + DIG_UPDATE_LOCATION, 20); + + REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); + + REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + h_blank_start - 200 - 1, + MASTER_UPDATE_LOCK_DB_Y, + v_blank_start - 1); +} + +void optc2_lock_doublebuffer_disable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + 0, + MASTER_UPDATE_LOCK_DB_Y, + 0); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0, + DIG_UPDATE_LOCATION, 0); + + REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 0); +} + +void optc2_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 1); + + REG_SET(OTG_GLOBAL_CONTROL2, 0, + MANUAL_FLOW_CONTROL_SEL, optc->inst); + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 22, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +void optc2_program_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_TRIGA_MANUAL_TRIG, 0, + OTG_TRIGA_MANUAL_TRIG, 1); +} + +static struct timing_generator_funcs dcn20_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc2_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank = optc1_set_blank, + .is_blanked = optc1_is_blanked, + .set_blank_color = optc1_program_blank_color, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc2_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc2_lock, + .unlock = optc1_unlock, + .lock_global = optc2_lock_global, + .setup_global_lock = optc2_setup_global_lock, + .lock_doublebuffer_enable = optc2_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_set_drr, + .set_static_screen_control = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, + .tg_init = optc1_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc1_configure_crc, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .set_dsc_config = optc2_set_dsc_config, +#endif + .set_dwb_source = optc2_set_dwb_source, + .set_odm_bypass = optc2_set_odm_bypass, + .set_odm_combine = optc2_set_odm_combine, + .get_optc_source = optc2_get_optc_source, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger +}; + +void dcn20_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn20_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 8; + optc1->min_v_sync_width = 1; + optc1->comb_opp_id = 0xf; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h new file mode 100644 index 000000000000..ebf07c582da2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h @@ -0,0 +1,116 @@ +/* + * 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 __DC_OPTC_DCN20_H__ +#define __DC_OPTC_DCN20_H__ + +#include "../dcn10/dcn10_optc.h" + +#define TG_COMMON_REG_LIST_DCN2_0(inst) \ + TG_COMMON_REG_LIST_DCN(inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SR(DWB_SOURCE_SELECT),\ + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) + +#define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ + TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, DIG_UPDATE_LOCATION, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh) + +void dcn20_timing_generator_init(struct optc *optc); + +bool optc2_enable_crtc(struct timing_generator *optc); + +void optc2_set_gsl(struct timing_generator *optc, + const struct gsl_params *params); + +void optc2_set_gsl_source_select(struct timing_generator *optc, + int group_idx, + uint32_t gsl_ready_signal); + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +void optc2_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width); +#endif + +void optc2_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); + +void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, + int mpcc_hactive, enum dc_pixel_encoding pixel_encoding); + +void optc2_get_optc_source(struct timing_generator *optc, + uint32_t *num_of_src_opp, + uint32_t *src_opp_id_0, + uint32_t *src_opp_id_1); + +void optc2_triplebuffer_lock(struct timing_generator *optc); +void optc2_triplebuffer_unlock(struct timing_generator *optc); +void optc2_lock(struct timing_generator *optc); +void optc2_lock_global(struct timing_generator *optc); +void optc2_setup_global_lock(struct timing_generator *optc); +void optc2_lock_doublebuffer_disable(struct timing_generator *optc); +void optc2_lock_doublebuffer_enable(struct timing_generator *optc); +void optc2_program_manual_trigger(struct timing_generator *optc); + +#endif /* __DC_OPTC_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c new file mode 100644 index 000000000000..d200bc3cec71 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -0,0 +1,3187 @@ +/* +* Copyright 2016 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 <linux/slab.h> + +#include "dm_services.h" +#include "dc.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn20/dcn20_resource.h" + +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn20_hubbub.h" +#include "dcn20_mpc.h" +#include "dcn20_hubp.h" +#include "irq/dcn20/irq_service_dcn20.h" +#include "dcn20_dpp.h" +#include "dcn20_optc.h" +#include "dcn20_hwseq.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_resource.h" +#include "dcn20_opp.h" + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dcn20_dsc.h" +#endif + +#include "dcn20_link_encoder.h" +#include "dcn20_stream_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn20_dccg.h" +#include "dcn20_vmid.h" + +#include "navi10_ip_offset.h" + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" + +#include "nbio/nbio_2_3_offset.h" + +#include "dcn20/dcn20_dwb.h" +#include "dcn20/dcn20_mmhubbub.h" + +#include "mmhub/mmhub_2_0_0_offset.h" +#include "mmhub/mmhub_2_0_0_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "vm_helper.h" + +#include "amdgpu_socbb.h" + +#define SOC_BOUNDING_BOX_VALID false +#define DC_LOGGER_INIT(logger) + +struct _vcs_dpi_ip_params_st dcn2_0_ip = { + .odm_capable = 1, + .gpuvm_enable = 0, + .hostvm_enable = 0, + .gpuvm_max_page_table_levels = 4, + .hostvm_max_page_table_levels = 4, + .hostvm_cached_page_table_levels = 0, + .pte_group_size_bytes = 2048, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .num_dsc = 6, +#else + .num_dsc = 0, +#endif + .rob_buffer_size_kbytes = 168, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs_luma = 84, + .pde_proc_buffer_size_64k_reqs = 48, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_chunk_size_kbytes = 2, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 2, + .line_buffer_size_bits = 789504, + .is_line_buffer_bpp_fixed = 0, + .line_buffer_fixed_bpp = 0, + .dcc_supported = true, + .max_line_buffer_lines = 12, + .writeback_luma_buffer_size_kbytes = 12, + .writeback_chroma_buffer_size_kbytes = 8, + .writeback_chroma_line_buffer_width_pixels = 4, + .writeback_max_hscl_ratio = 1, + .writeback_max_vscl_ratio = 1, + .writeback_min_hscl_ratio = 1, + .writeback_min_vscl_ratio = 1, + .writeback_max_hscl_taps = 12, + .writeback_max_vscl_taps = 12, + .writeback_line_buffer_luma_buffer_size = 0, + .writeback_line_buffer_chroma_buffer_size = 14643, + .cursor_buffer_size = 8, + .cursor_chunk_size = 2, + .max_num_otg = 6, + .max_num_dpp = 6, + .max_num_wb = 1, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 8, + .max_vscl_ratio = 8, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.10, + .min_vblank_lines = 32, // + .dppclk_delay_subtotal = 77, // + .dppclk_delay_scl_lb_only = 16, + .dppclk_delay_scl = 50, + .dppclk_delay_cnvc_formatter = 8, + .dppclk_delay_cnvc_cursor = 6, + .dispclk_delay_subtotal = 87, // + .dcfclk_cstate_latency = 10, // SRExitTime + .max_inter_dcn_tile_repeaters = 8, + + .xfc_supported = true, + .xfc_fill_bw_overhead_percent = 10.0, + .xfc_fill_constant_bytes = 0, +}; + +struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { 0 }; + + +#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f + #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f + #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f + #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f + #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f + #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f + #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f + #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 +#endif + + +enum dcn20_clk_src_array_id { + DCN20_CLK_SRC_PLL0, + DCN20_CLK_SRC_PLL1, + DCN20_CLK_SRC_PLL2, + DCN20_CLK_SRC_PLL3, + DCN20_CLK_SRC_PLL4, + DCN20_CLK_SRC_PLL5, + DCN20_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +/* TODO awful hack. fixup dcn20_dwb.h */ +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#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 + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## 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(mmMM ## reg_name ## _BASE_IDX) + \ + mmMM ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN2_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), + clk_src_regs(5, F) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCN10_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCN20_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN20(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_aduio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN2_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5), +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN20(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN10_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E), + link_regs(5, F) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN20(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN20(_MASK), +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5), +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN20(id),\ +} + +static const struct dcn2_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), + tf_regs(4), + tf_regs(5), +}; + +static const struct dcn2_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn2_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +#define dwbc_regs_dcn2(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN2_0(id),\ + } + +static const struct dcn20_dwbc_registers dwbc20_regs[] = { + dwbc_regs_dcn2(0), +}; + +static const struct dcn20_dwbc_shift dwbc20_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn20_dwbc_mask dwbc20_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define mcif_wb_regs_dcn2(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN2_0(id),\ + } + +static const struct dcn20_mmhubbub_registers mcif_wb20_regs[] = { + mcif_wb_regs_dcn2(0), +}; + +static const struct dcn20_mmhubbub_shift mcif_wb20_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn20_mmhubbub_mask mcif_wb20_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct dcn20_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN2_0(0), + MPC_REG_LIST_DCN2_0(1), + MPC_REG_LIST_DCN2_0(2), + MPC_REG_LIST_DCN2_0(3), + MPC_REG_LIST_DCN2_0(4), + MPC_REG_LIST_DCN2_0(5), + MPC_OUT_MUX_REG_LIST_DCN2_0(0), + MPC_OUT_MUX_REG_LIST_DCN2_0(1), + MPC_OUT_MUX_REG_LIST_DCN2_0(2), + MPC_OUT_MUX_REG_LIST_DCN2_0(3), + MPC_OUT_MUX_REG_LIST_DCN2_0(4), + MPC_OUT_MUX_REG_LIST_DCN2_0(5), +}; + +static const struct dcn20_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn20_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define tg_regs(id)\ +[id] = {TG_COMMON_REG_LIST_DCN2_0(id)} + + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs(0), + tg_regs(1), + tg_regs(2), + tg_regs(3), + tg_regs(4), + tg_regs(5) +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN20(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), + hubp_regs(4), + hubp_regs(5) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN20(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN20(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN20(_MASK) +}; + +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), + dsc_regsDCN20(3), + dsc_regsDCN20(4), + dsc_regsDCN20(5) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; +#endif + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN2() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN2(_MASK) +}; + +static const struct resource_caps res_cap_nv10 = { + .num_timing_generator = 6, + .num_opp = 6, + .num_video_plane = 6, + .num_audio = 7, + .num_stream_encoder = 6, + .num_pll = 6, + .num_dwb = 1, + .num_ddc = 6, + .num_vmid = 16, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .num_dsc = 6, +#endif +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .blends_with_above = true, + .blends_with_below = true, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 1 + } +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = true, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 5120,/*upto 5K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .disable_tri_buf = true, + .underflow_assert_delay_us = 0xFFFFFFFF, +}; + +static const struct dc_debug_options debug_defaults_diags = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = true, + .clock_trace = true, + .disable_dpp_power_gate = true, + .disable_hubp_power_gate = true, + .disable_clock_gate = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true, + .disable_stutter = true, + .scl_reset_length10 = true, + .underflow_assert_delay_us = 0xFFFFFFFF, +}; + +void dcn20_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +struct dpp *dcn20_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_dpp *dpp = + kzalloc(sizeof(struct dcn20_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp2_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +struct input_pixel_processor *dcn20_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + + +struct output_pixel_processor *dcn20_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +struct dce_aux *dcn20_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst]); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +struct dce_i2c_hw *dcn20_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +struct mpc *dcn20_mpc_create(struct dc_context *ctx) +{ + struct dcn20_mpc *mpc20 = kzalloc(sizeof(struct dcn20_mpc), + GFP_KERNEL); + + if (!mpc20) + return NULL; + + dcn20_mpc_construct(mpc20, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + 6); + + return &mpc20->base; +} + +struct hubbub *dcn20_hubbub_create(struct dc_context *ctx) +{ + int i; + struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub) + return NULL; + + hubbub2_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + for (i = 0; i < res_cap_nv10.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub->base; +} + +struct timing_generator *dcn20_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn20_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +struct link_encoder *dcn20_link_encoder_create( + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn20_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +struct clock_source *dcn20_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn20_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static struct audio *dcn20_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +struct stream_encoder *dcn20_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1 = + kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + + if (!enc1) + return NULL; + + dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN2_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN2_MASK_SH_LIST(_MASK) +}; + +struct dce_hwseq *dcn20_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn20_create_audio, + .create_stream_encoder = dcn20_stream_encoder_create, + .create_hwseq = dcn20_hwseq_create, +}; + +static const struct resource_create_funcs res_create_maximus_funcs = { + .read_dce_straps = NULL, + .create_audio = NULL, + .create_stream_encoder = NULL, + .create_hwseq = dcn20_hwseq_create, +}; + +void dcn20_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + +struct display_stream_compressor *dcn20_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +void dcn20_dsc_destroy(struct display_stream_compressor **dsc) +{ + kfree(container_of(*dsc, struct dcn20_dsc, base)); + *dsc = NULL; +} + +#endif + +static void destruct(struct dcn20_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } +#endif + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn20_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + 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; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN20_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN20_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.pp_smu != NULL) + dcn20_pp_smu_destroy(&pool->base.pp_smu); + +} + +struct hubp *dcn20_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp2_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static void get_pixel_clock_parameters( + struct pipe_ctx *pipe_ctx, + struct pixel_clk_params *pixel_clk_params) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + bool odm_combine = dc_res_get_odm_bottom_pipe(pipe_ctx) != NULL; + + 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*/ + pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * + LINK_RATE_REF_FREQ_IN_KHZ; + pixel_clk_params->flags.ENABLE_SS = 0; + pixel_clk_params->color_depth = + stream->timing.display_color_depth; + pixel_clk_params->flags.DISPLAY_BLANKED = 1; + pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) + pixel_clk_params->color_depth = COLOR_DEPTH_888; + + if (optc1_is_two_pixels_per_containter(&stream->timing) || odm_combine) + 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_100hz *= 2; + +} + +static void build_clamping_params(struct dc_stream_state *stream) +{ + stream->clamping.clamping_level = CLAMPING_FULL_RANGE; + stream->clamping.c_depth = stream->timing.display_color_depth; + stream->clamping.pixel_encoding = stream->timing.pixel_encoding; +} + +static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) +{ + + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); + + pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + build_clamping_params(pipe_ctx->stream); + + return DC_OK; +} + +enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream) +{ + enum dc_status status = DC_OK; + struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + + /*TODO Seems unneeded anymore */ + /* if (old_context && resource_is_stream_unchanged(old_context, stream)) { + if (stream != NULL && old_context->streams[i] != NULL) { + todo: shouldn't have to copy missing parameter here + resource_build_bit_depth_reduction_params(stream, + &stream->bit_depth_params); + stream->clamping.pixel_encoding = + stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(stream, + &stream->bit_depth_params); + build_clamping_params(stream); + + continue; + } + } + */ + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + + status = build_pipe_hw_param(pipe_ctx); + + return status; +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + +static void acquire_dsc(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct display_stream_compressor **dsc) +{ + int i; + + ASSERT(*dsc == NULL); + *dsc = NULL; + + /* Find first free DSC */ + for (i = 0; i < pool->res_cap->num_dsc; i++) + if (!res_ctx->is_dsc_acquired[i]) { + *dsc = pool->dscs[i]; + res_ctx->is_dsc_acquired[i] = true; + break; + } +} + +static void release_dsc(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct display_stream_compressor **dsc) +{ + int i; + + for (i = 0; i < pool->res_cap->num_dsc; i++) + if (pool->dscs[i] == *dsc) { + res_ctx->is_dsc_acquired[i] = false; + *dsc = NULL; + break; + } +} + +#endif + + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +static enum dc_status add_dsc_to_stream_resource(struct dc *dc, + struct dc_state *dc_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_OK; + int i; + const struct resource_pool *pool = dc->res_pool; + + /* Get a DSC if required and available */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &dc_ctx->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream != dc_stream) + continue; + + acquire_dsc(&dc_ctx->res_ctx, pool, &pipe_ctx->stream_res.dsc); + + /* The number of DSCs can be less than the number of pipes */ + if (!pipe_ctx->stream_res.dsc) { + dm_output_to_console("No DSCs available\n"); + result = DC_NO_DSC_RESOURCE; + } + + break; + } + + return result; +} + + +static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + struct pipe_ctx *pipe_ctx = NULL; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (new_ctx->res_ctx.pipe_ctx[i].stream == dc_stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { + pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; + break; + } + } + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + if (pipe_ctx->stream_res.dsc) { + struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx); + + release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); + if (odm_pipe) + release_dsc(&new_ctx->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); + } + + return DC_OK; +} +#endif + + +enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* Get a DSC if required and available */ + if (result == DC_OK && dc_stream->timing.flags.DSC) + result = add_dsc_to_stream_resource(dc, new_ctx, dc_stream); +#endif + + if (result == DC_OK) + result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + + +enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_OK; + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + result = remove_dsc_from_stream_resource(dc, new_ctx, dc_stream); +#endif + + return result; +} + + +static void swizzle_to_dml_params( + enum swizzle_mode_values swizzle, + unsigned int *sw_mode) +{ + switch (swizzle) { + case DC_SW_LINEAR: + *sw_mode = dm_sw_linear; + break; + case DC_SW_4KB_S: + *sw_mode = dm_sw_4kb_s; + break; + case DC_SW_4KB_S_X: + *sw_mode = dm_sw_4kb_s_x; + break; + case DC_SW_4KB_D: + *sw_mode = dm_sw_4kb_d; + break; + case DC_SW_4KB_D_X: + *sw_mode = dm_sw_4kb_d_x; + break; + case DC_SW_64KB_S: + *sw_mode = dm_sw_64kb_s; + break; + case DC_SW_64KB_S_X: + *sw_mode = dm_sw_64kb_s_x; + break; + case DC_SW_64KB_S_T: + *sw_mode = dm_sw_64kb_s_t; + break; + case DC_SW_64KB_D: + *sw_mode = dm_sw_64kb_d; + break; + case DC_SW_64KB_D_X: + *sw_mode = dm_sw_64kb_d_x; + break; + case DC_SW_64KB_D_T: + *sw_mode = dm_sw_64kb_d_t; + break; + case DC_SW_64KB_R_X: + *sw_mode = dm_sw_64kb_r_x; + break; + case DC_SW_VAR_S: + *sw_mode = dm_sw_var_s; + break; + case DC_SW_VAR_S_X: + *sw_mode = dm_sw_var_s_x; + break; + case DC_SW_VAR_D: + *sw_mode = dm_sw_var_d; + break; + case DC_SW_VAR_D_X: + *sw_mode = dm_sw_var_d_x; + break; + + default: + ASSERT(0); /* Not supported */ + break; + } +} + +static bool dcn20_split_stream_for_combine( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *primary_pipe, + struct pipe_ctx *secondary_pipe, + bool is_odm_combine) +{ + int pipe_idx = secondary_pipe->pipe_idx; + struct scaler_data *sd = &primary_pipe->plane_res.scl_data; + struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe; + int new_width; + + *secondary_pipe = *primary_pipe; + secondary_pipe->bottom_pipe = sec_bot_pipe; + + secondary_pipe->pipe_idx = pipe_idx; + secondary_pipe->plane_res.mi = pool->mis[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.hubp = pool->hubps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.ipp = pool->ipps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.mpcc_inst = pool->dpps[secondary_pipe->pipe_idx]->inst; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + secondary_pipe->stream_res.dsc = NULL; +#endif + if (primary_pipe->bottom_pipe && primary_pipe->bottom_pipe != secondary_pipe) { + ASSERT(!secondary_pipe->bottom_pipe); + secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe; + secondary_pipe->bottom_pipe->top_pipe = secondary_pipe; + } + primary_pipe->bottom_pipe = secondary_pipe; + secondary_pipe->top_pipe = primary_pipe; + + if (is_odm_combine) { + if (primary_pipe->plane_state) { + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Copy scl_data to secondary pipe */ + secondary_pipe->plane_res.scl_data = *sd; + + /* Calculate new vp and recout for left pipe */ + /* Need at least 16 pixels width per side */ + if (sd->recout.x + 16 >= sd->h_active) + return false; + new_width = sd->h_active - sd->recout.x; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + + /* Calculate new vp and recout for right pipe */ + sd = &secondary_pipe->plane_res.scl_data; + new_width = sd->recout.width + sd->recout.x - sd->h_active; + /* Need at least 16 pixels width per side */ + if (new_width <= 16) + return false; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->h_active - sd->recout.x)); + sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->h_active - sd->recout.x)); + sd->recout.x = 0; + } + secondary_pipe->stream_res.opp = pool->opps[secondary_pipe->pipe_idx]; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (secondary_pipe->stream->timing.flags.DSC == 1) { + acquire_dsc(res_ctx, pool, &secondary_pipe->stream_res.dsc); + ASSERT(secondary_pipe->stream_res.dsc); + if (secondary_pipe->stream_res.dsc == NULL) + return false; + } +#endif + } else { + ASSERT(primary_pipe->plane_state); + resource_build_scaling_params(primary_pipe); + resource_build_scaling_params(secondary_pipe); + } + + return true; +} + +void dcn20_populate_dml_writeback_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) +{ + int pipe_cnt, i; + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_writeback_info *wb_info = &res_ctx->pipe_ctx[i].stream->writeback_info[0]; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + + /* Set writeback information */ + pipes[pipe_cnt].dout.wb_enable = (wb_info->wb_enabled == true) ? 1 : 0; + pipes[pipe_cnt].dout.num_active_wb++; + pipes[pipe_cnt].dout.wb.wb_src_height = wb_info->dwb_params.cnv_params.crop_height; + pipes[pipe_cnt].dout.wb.wb_src_width = wb_info->dwb_params.cnv_params.crop_width; + pipes[pipe_cnt].dout.wb.wb_dst_width = wb_info->dwb_params.dest_width; + pipes[pipe_cnt].dout.wb.wb_dst_height = wb_info->dwb_params.dest_height; + pipes[pipe_cnt].dout.wb.wb_htaps_luma = 1; + pipes[pipe_cnt].dout.wb.wb_vtaps_luma = 1; + pipes[pipe_cnt].dout.wb.wb_htaps_chroma = wb_info->dwb_params.scaler_taps.h_taps_c; + pipes[pipe_cnt].dout.wb.wb_vtaps_chroma = wb_info->dwb_params.scaler_taps.v_taps_c; + pipes[pipe_cnt].dout.wb.wb_hratio = 1.0; + pipes[pipe_cnt].dout.wb.wb_vratio = 1.0; + if (wb_info->dwb_params.out_format == dwb_scaler_mode_yuv420) { + if (wb_info->dwb_params.output_depth == DWB_OUTPUT_PIXEL_DEPTH_8BPC) + pipes[pipe_cnt].dout.wb.wb_pixel_format = dm_420_8; + else + pipes[pipe_cnt].dout.wb.wb_pixel_format = dm_420_10; + } else + pipes[pipe_cnt].dout.wb.wb_pixel_format = dm_444_32; + + pipe_cnt++; + } + +} + +int dcn20_populate_dml_pipes_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) +{ + int pipe_cnt, i; + bool synchronized_vblank = true; + + for (i = 0, pipe_cnt = -1; i < dc->res_pool->pipe_count; i++) { + if (!res_ctx->pipe_ctx[i].stream) + continue; + + if (pipe_cnt < 0) { + pipe_cnt = i; + continue; + } + if (!resource_are_streams_timing_synchronizable( + res_ctx->pipe_ctx[pipe_cnt].stream, + res_ctx->pipe_ctx[i].stream)) { + synchronized_vblank = false; + break; + } + } + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_crtc_timing *timing = &res_ctx->pipe_ctx[i].stream->timing; + int output_bpc; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + /* todo: + pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = 0; + pipes[pipe_cnt].pipe.src.dcc = 0; + pipes[pipe_cnt].pipe.src.vm = 0;*/ + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC; + /* todo: rotation?*/ + pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h; +#endif + if (res_ctx->pipe_ctx[i].stream->use_dynamic_meta) { + pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = true; + /* 1/2 vblank */ + pipes[pipe_cnt].pipe.src.dynamic_metadata_lines_before_active = + (timing->v_total - timing->v_addressable + - timing->v_border_top - timing->v_border_bottom) / 2; + /* 36 bytes dp, 32 hdmi */ + pipes[pipe_cnt].pipe.src.dynamic_metadata_xmit_bytes = + dc_is_dp_signal(res_ctx->pipe_ctx[i].stream->signal) ? 36 : 32; + } + pipes[pipe_cnt].pipe.src.dcc = false; + pipes[pipe_cnt].pipe.src.dcc_rate = 1; + pipes[pipe_cnt].pipe.dest.synchronized_vblank_all_planes = synchronized_vblank; + pipes[pipe_cnt].pipe.dest.hblank_start = timing->h_total - timing->h_front_porch; + pipes[pipe_cnt].pipe.dest.hblank_end = pipes[pipe_cnt].pipe.dest.hblank_start + - timing->h_addressable + - timing->h_border_left + - timing->h_border_right; + pipes[pipe_cnt].pipe.dest.vblank_start = timing->v_total - timing->v_front_porch; + pipes[pipe_cnt].pipe.dest.vblank_end = pipes[pipe_cnt].pipe.dest.vblank_start + - timing->v_addressable + - timing->v_border_top + - timing->v_border_bottom; + pipes[pipe_cnt].pipe.dest.htotal = timing->h_total; + pipes[pipe_cnt].pipe.dest.vtotal = timing->v_total; + pipes[pipe_cnt].pipe.dest.hactive = timing->h_addressable; + pipes[pipe_cnt].pipe.dest.vactive = timing->v_addressable; + pipes[pipe_cnt].pipe.dest.interlaced = timing->flags.INTERLACE; + pipes[pipe_cnt].pipe.dest.pixel_rate_mhz = timing->pix_clk_100hz/10000.0; + if (timing->timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + pipes[pipe_cnt].pipe.dest.pixel_rate_mhz *= 2; + pipes[pipe_cnt].pipe.dest.otg_inst = res_ctx->pipe_ctx[i].stream_res.tg->inst; + pipes[pipe_cnt].dout.dp_lanes = 4; + pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min; + pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max; + + switch (res_ctx->pipe_ctx[i].stream->signal) { + case SIGNAL_TYPE_DISPLAY_PORT_MST: + case SIGNAL_TYPE_DISPLAY_PORT: + pipes[pipe_cnt].dout.output_type = dm_dp; + break; + case SIGNAL_TYPE_EDP: + pipes[pipe_cnt].dout.output_type = dm_edp; + break; + case SIGNAL_TYPE_HDMI_TYPE_A: + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + pipes[pipe_cnt].dout.output_type = dm_hdmi; + break; + default: + /* In case there is no signal, set dp with 4 lanes to allow max config */ + pipes[pipe_cnt].dout.output_type = dm_dp; + pipes[pipe_cnt].dout.dp_lanes = 4; + } + + switch (res_ctx->pipe_ctx[i].stream->timing.display_color_depth) { + case COLOR_DEPTH_666: + output_bpc = 6; + break; + case COLOR_DEPTH_888: + output_bpc = 8; + break; + case COLOR_DEPTH_101010: + output_bpc = 10; + break; + case COLOR_DEPTH_121212: + output_bpc = 12; + break; + case COLOR_DEPTH_141414: + output_bpc = 14; + break; + case COLOR_DEPTH_161616: + output_bpc = 16; + break; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + case COLOR_DEPTH_999: + output_bpc = 9; + break; + case COLOR_DEPTH_111111: + output_bpc = 11; + break; +#endif + default: + output_bpc = 8; + break; + } + + + switch (res_ctx->pipe_ctx[i].stream->timing.pixel_encoding) { + case PIXEL_ENCODING_RGB: + case PIXEL_ENCODING_YCBCR444: + pipes[pipe_cnt].dout.output_format = dm_444; + pipes[pipe_cnt].dout.output_bpp = output_bpc * 3; + break; + case PIXEL_ENCODING_YCBCR420: + pipes[pipe_cnt].dout.output_format = dm_420; + pipes[pipe_cnt].dout.output_bpp = (output_bpc * 3) / 2; + break; + case PIXEL_ENCODING_YCBCR422: + if (true) /* todo */ + pipes[pipe_cnt].dout.output_format = dm_s422; + else + pipes[pipe_cnt].dout.output_format = dm_n422; + pipes[pipe_cnt].dout.output_bpp = output_bpc * 2; + break; + default: + pipes[pipe_cnt].dout.output_format = dm_444; + pipes[pipe_cnt].dout.output_bpp = output_bpc * 3; + } + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx; + if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state + == res_ctx->pipe_ctx[i].plane_state) + pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx; + + /* todo: default max for now, until there is logic reflecting this in dc*/ + pipes[pipe_cnt].dout.output_bpc = 12; + /* + * Use max cursor settings for calculations to minimize + * bw calculations due to cursor on/off + */ + pipes[pipe_cnt].pipe.src.num_cursors = 2; + pipes[pipe_cnt].pipe.src.cur0_src_width = 256; + pipes[pipe_cnt].pipe.src.cur0_bpp = dm_cur_32bit; + pipes[pipe_cnt].pipe.src.cur1_src_width = 256; + pipes[pipe_cnt].pipe.src.cur1_bpp = dm_cur_32bit; + + if (!res_ctx->pipe_ctx[i].plane_state) { + pipes[pipe_cnt].pipe.src.source_scan = dm_horz; + pipes[pipe_cnt].pipe.src.sw_mode = dm_sw_linear; + pipes[pipe_cnt].pipe.src.macro_tile_size = dm_64k_tile; + pipes[pipe_cnt].pipe.src.viewport_width = timing->h_addressable; + if (pipes[pipe_cnt].pipe.src.viewport_width > 1920) + pipes[pipe_cnt].pipe.src.viewport_width = 1920; + pipes[pipe_cnt].pipe.src.viewport_height = timing->v_addressable; + if (pipes[pipe_cnt].pipe.src.viewport_height > 1080) + pipes[pipe_cnt].pipe.src.viewport_height = 1080; + pipes[pipe_cnt].pipe.src.data_pitch = ((pipes[pipe_cnt].pipe.src.viewport_width + 63) / 64) * 64; /* linear sw only */ + pipes[pipe_cnt].pipe.src.source_format = dm_444_32; + pipes[pipe_cnt].pipe.dest.recout_width = pipes[pipe_cnt].pipe.src.viewport_width; /*vp_width/hratio*/ + pipes[pipe_cnt].pipe.dest.recout_height = pipes[pipe_cnt].pipe.src.viewport_height; /*vp_height/vratio*/ + pipes[pipe_cnt].pipe.dest.full_recout_width = pipes[pipe_cnt].pipe.dest.recout_width; /*when is_hsplit != 1*/ + pipes[pipe_cnt].pipe.dest.full_recout_height = pipes[pipe_cnt].pipe.dest.recout_height; /*when is_hsplit != 1*/ + pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16; + pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = 1.0; + pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = 1.0; + pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable = 0; /*Lb only or Full scl*/ + pipes[pipe_cnt].pipe.scale_taps.htaps = 1; + pipes[pipe_cnt].pipe.scale_taps.vtaps = 1; + pipes[pipe_cnt].pipe.src.is_hsplit = 0; + pipes[pipe_cnt].pipe.dest.odm_combine = 0; + pipes[pipe_cnt].pipe.dest.vtotal_min = timing->v_total; + pipes[pipe_cnt].pipe.dest.vtotal_max = timing->v_total; + } else { + struct dc_plane_state *pln = res_ctx->pipe_ctx[i].plane_state; + struct scaler_data *scl = &res_ctx->pipe_ctx[i].plane_res.scl_data; + + pipes[pipe_cnt].pipe.src.immediate_flip = pln->flip_immediate; + pipes[pipe_cnt].pipe.src.is_hsplit = (res_ctx->pipe_ctx[i].bottom_pipe + && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln) + || (res_ctx->pipe_ctx[i].top_pipe + && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln); + pipes[pipe_cnt].pipe.dest.odm_combine = (res_ctx->pipe_ctx[i].bottom_pipe + && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln + && res_ctx->pipe_ctx[i].bottom_pipe->stream_res.opp + != res_ctx->pipe_ctx[i].stream_res.opp) + || (res_ctx->pipe_ctx[i].top_pipe + && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln + && res_ctx->pipe_ctx[i].top_pipe->stream_res.opp + != res_ctx->pipe_ctx[i].stream_res.opp); + pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90 + || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz; + pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y; + pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y; + pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport.width; + pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width; + pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height; + pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height; + if (pln->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.video.luma_pitch; + pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.video.chroma_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.video.meta_pitch_l; + pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.video.meta_pitch_c; + } else { + pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.grph.surface_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.grph.meta_pitch; + } + pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable; + pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width; + pipes[pipe_cnt].pipe.dest.recout_height = scl->recout.height; + pipes[pipe_cnt].pipe.dest.full_recout_width = scl->recout.width; + pipes[pipe_cnt].pipe.dest.full_recout_height = scl->recout.height; + if (res_ctx->pipe_ctx[i].bottom_pipe && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln) { + pipes[pipe_cnt].pipe.dest.full_recout_width += + res_ctx->pipe_ctx[i].bottom_pipe->plane_res.scl_data.recout.width; + pipes[pipe_cnt].pipe.dest.full_recout_height += + res_ctx->pipe_ctx[i].bottom_pipe->plane_res.scl_data.recout.height; + } else if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln) { + pipes[pipe_cnt].pipe.dest.full_recout_width += + res_ctx->pipe_ctx[i].top_pipe->plane_res.scl_data.recout.width; + pipes[pipe_cnt].pipe.dest.full_recout_height += + res_ctx->pipe_ctx[i].top_pipe->plane_res.scl_data.recout.height; + } + + pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16; + pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = (double) scl->ratios.horz.value / (1ULL<<32); + pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio_c = (double) scl->ratios.horz_c.value / (1ULL<<32); + pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = (double) scl->ratios.vert.value / (1ULL<<32); + pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio_c = (double) scl->ratios.vert_c.value / (1ULL<<32); + pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable = + scl->ratios.vert.value != dc_fixpt_one.value + || scl->ratios.horz.value != dc_fixpt_one.value + || scl->ratios.vert_c.value != dc_fixpt_one.value + || scl->ratios.horz_c.value != dc_fixpt_one.value /*Lb only or Full scl*/ + || dc->debug.always_scale; /*support always scale*/ + pipes[pipe_cnt].pipe.scale_taps.htaps = scl->taps.h_taps; + pipes[pipe_cnt].pipe.scale_taps.htaps_c = scl->taps.h_taps_c; + pipes[pipe_cnt].pipe.scale_taps.vtaps = scl->taps.v_taps; + pipes[pipe_cnt].pipe.scale_taps.vtaps_c = scl->taps.v_taps_c; + + pipes[pipe_cnt].pipe.src.macro_tile_size = + swizzle_mode_to_macro_tile_size(pln->tiling_info.gfx9.swizzle); + swizzle_to_dml_params(pln->tiling_info.gfx9.swizzle, + &pipes[pipe_cnt].pipe.src.sw_mode); + + switch (pln->format) { + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + pipes[pipe_cnt].pipe.src.source_format = dm_420_8; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + pipes[pipe_cnt].pipe.src.source_format = dm_420_10; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + pipes[pipe_cnt].pipe.src.source_format = dm_444_64; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + pipes[pipe_cnt].pipe.src.source_format = dm_444_16; + break; + case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS: + pipes[pipe_cnt].pipe.src.source_format = dm_444_8; + break; + default: + pipes[pipe_cnt].pipe.src.source_format = dm_444_32; + break; + } + } + + pipe_cnt++; + } + + /* populate writeback information */ + dc->res_pool->funcs->populate_dml_writeback_from_context(dc, res_ctx, pipes); + + return pipe_cnt; +} + +unsigned int dcn20_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark) +{ + unsigned int time_per_byte = 0; + unsigned int total_y_free_entry = 0x200; /* two memory piece for luma */ + unsigned int total_c_free_entry = 0x140; /* two memory piece for chroma */ + unsigned int small_free_entry, max_free_entry; + unsigned int buf_lh_capability; + unsigned int max_scaled_time; + + if (mode == PACKED_444) /* packed mode */ + time_per_byte = time_per_pixel/4; + else if (mode == PLANAR_420_8BPC) + time_per_byte = time_per_pixel; + else if (mode == PLANAR_420_10BPC) /* p010 */ + time_per_byte = time_per_pixel * 819/1024; + + if (time_per_byte == 0) + time_per_byte = 1; + + small_free_entry = (total_y_free_entry > total_c_free_entry) ? total_c_free_entry : total_y_free_entry; + max_free_entry = (mode == PACKED_444) ? total_y_free_entry + total_c_free_entry : small_free_entry; + buf_lh_capability = max_free_entry*time_per_byte*32/16; /* there is 4bit fraction */ + max_scaled_time = buf_lh_capability - urgent_watermark; + return max_scaled_time; +} + +void dcn20_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + enum mmhubbub_wbif_mode wbif_mode; + struct mcif_arb_params *wb_arb_params; + int i, j, k, dwb_pipe; + + /* Writeback MCIF_WB arbitration parameters */ + dwb_pipe = 0; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + for (j = 0; j < MAX_DWB_PIPES; j++) { + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].wb_enabled == false) + continue; + + //wb_arb_params = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j].mcif_arb_params; + wb_arb_params = &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_pipe]; + + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.out_format == dwb_scaler_mode_yuv420) { + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.output_depth == DWB_OUTPUT_PIXEL_DEPTH_8BPC) + wbif_mode = PLANAR_420_8BPC; + else + wbif_mode = PLANAR_420_10BPC; + } else + wbif_mode = PACKED_444; + + for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) { + wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + } + wb_arb_params->time_per_pixel = 16.0 / context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; /* 4 bit fraction, ms */ + wb_arb_params->slice_lines = 32; + wb_arb_params->arbitration_slice = 2; + wb_arb_params->max_scaled_time = dcn20_calc_max_scaled_time(wb_arb_params->time_per_pixel, + wbif_mode, + wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */ + + dwb_pipe++; + + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) +{ + int i; + + /* Validate DSC config, dsc count validation is already done */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dsc_config dsc_cfg; + + /* Only need to validate top pipe */ + if (pipe_ctx->top_pipe || !stream || !stream->timing.flags.DSC) + continue; + + dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + + stream->timing.h_border_right; + dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + + stream->timing.v_border_bottom; + if (dc_res_get_odm_bottom_pipe(pipe_ctx)) + dsc_cfg.pic_width /= 2; + dsc_cfg.pixel_encoding = stream->timing.pixel_encoding; + dsc_cfg.color_depth = stream->timing.display_color_depth; + dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; + + if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg)) + return false; + } + return true; +} +#endif + +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + BW_VAL_TRACE_SETUP(); + + int pipe_cnt, i, pipe_idx, vlevel, vlevel_unsplit; + int pipe_split_from[MAX_PIPES]; + bool odm_capable = context->bw_ctx.dml.ip.odm_capable; + bool force_split = false; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool failed_non_odm_dsc = false; +#endif + int split_threshold = dc->res_pool->pipe_count / 2; + bool avoid_split = dc->debug.pipe_split_policy != MPC_SPLIT_DYNAMIC; + display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL); + DC_LOGGER_INIT(dc->ctx->logger); + + BW_VAL_TRACE_COUNT(); + + ASSERT(pipes); + if (!pipes) + return false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; + + if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) + continue; + + /* merge previously split pipe since mode support needs to make the decision */ + pipe->bottom_pipe = hsplit_pipe->bottom_pipe; + if (hsplit_pipe->bottom_pipe) + hsplit_pipe->bottom_pipe->top_pipe = pipe; + hsplit_pipe->plane_state = NULL; + hsplit_pipe->stream = NULL; + hsplit_pipe->top_pipe = NULL; + hsplit_pipe->bottom_pipe = NULL; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (hsplit_pipe->stream_res.dsc && hsplit_pipe->stream_res.dsc != pipe->stream_res.dsc) + release_dsc(&context->res_ctx, dc->res_pool, &hsplit_pipe->stream_res.dsc); +#endif + /* Clear plane_res and stream_res */ + memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res)); + memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res)); + if (pipe->plane_state) + resource_build_scaling_params(pipe); + } + + if (dc->res_pool->funcs->populate_dml_pipes) + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, + &context->res_ctx, pipes); + else + pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, + &context->res_ctx, pipes); + + if (!pipe_cnt) { + BW_VAL_TRACE_SKIP(pass); + out = true; + goto validate_out; + } + + context->bw_ctx.dml.ip.odm_capable = 0; + + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + + context->bw_ctx.dml.ip.odm_capable = odm_capable; + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* 1 dsc per stream dsc validation */ + if (vlevel <= context->bw_ctx.dml.soc.num_states) + if (!dcn20_validate_dsc(dc, context)) { + failed_non_odm_dsc = true; + vlevel = context->bw_ctx.dml.soc.num_states + 1; + } +#endif + + if (vlevel > context->bw_ctx.dml.soc.num_states && odm_capable) + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + + if (vlevel > context->bw_ctx.dml.soc.num_states) + goto validate_fail; + + if ((context->stream_count > split_threshold && dc->current_state->stream_count <= split_threshold) + || (context->stream_count <= split_threshold && dc->current_state->stream_count > split_threshold)) + context->commit_hints.full_update_needed = true; + + /*initialize pipe_just_split_from to invalid idx*/ + for (i = 0; i < MAX_PIPES; i++) + pipe_split_from[i] = -1; + + /* Single display only conditionals get set here */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + bool exit_loop = false; + + if (!pipe->stream || pipe->top_pipe) + continue; + + if (dc->debug.force_single_disp_pipe_split) { + if (!force_split) + force_split = true; + else { + force_split = false; + exit_loop = true; + } + } + if (dc->debug.pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP) { + if (avoid_split) + avoid_split = false; + else { + avoid_split = true; + exit_loop = true; + } + } + if (exit_loop) + break; + } + + if (context->stream_count > split_threshold) + avoid_split = true; + + vlevel_unsplit = vlevel; + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + for (; vlevel_unsplit <= context->bw_ctx.dml.soc.num_states; vlevel_unsplit++) + if (context->bw_ctx.dml.vba.NoOfDPP[vlevel_unsplit][0][pipe_idx] == 1) + break; + pipe_idx++; + } + + for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; + bool need_split = true; + bool need_split3d; + + if (!pipe->stream || pipe_split_from[i] >= 0) + continue; + + pipe_idx++; + + if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) { + force_split = true; + context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx] = true; + context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_idx] = true; + } + if (force_split && context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 1) + context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] /= 2; + if (dc->config.forced_clocks == true) { + context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] = + context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; + } + if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe); + if (!dcn20_split_stream_for_combine( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe, + true)) + goto validate_fail; + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + dcn20_build_mapped_resource(dc, context, pipe->stream); + } + + if (!pipe->plane_state) + continue; + /* Skip 2nd half of already split pipe */ + if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state) + continue; + + need_split3d = ((pipe->stream->view_format == + VIEW_3D_FORMAT_SIDE_BY_SIDE || + pipe->stream->view_format == + VIEW_3D_FORMAT_TOP_AND_BOTTOM) && + (pipe->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM || + pipe->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE)); + + if (avoid_split && vlevel_unsplit <= context->bw_ctx.dml.soc.num_states && !force_split && !need_split3d) { + need_split = false; + vlevel = vlevel_unsplit; + context->bw_ctx.dml.vba.maxMpcComb = 0; + } else + need_split = context->bw_ctx.dml.vba.NoOfDPP[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] == 2; + + /* We do not support mpo + odm at the moment */ + if (hsplit_pipe && hsplit_pipe->plane_state != pipe->plane_state + && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) + goto validate_fail; + + if (need_split3d || need_split || force_split) { + if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { + /* pipe not split previously needs split */ + hsplit_pipe = find_idle_secondary_pipe(&context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe || force_split); + if (!hsplit_pipe) + continue; + + if (!dcn20_split_stream_for_combine( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe, + context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx])) + goto validate_fail; + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + } + } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { + /* merge should already have been done */ + ASSERT(0); + } + } +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* Actual dsc count per stream dsc validation*/ + if (failed_non_odm_dsc && !dcn20_validate_dsc(dc, context)) { + context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = + DML_FAIL_DSC_VALIDATION_FAILURE; + goto validate_fail; + } +#endif + + BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + + if (fast_validate) { + BW_VAL_TRACE_SKIP(fast); + out = true; + goto validate_out; + } + + for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0; + pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.vba.RequiredDISPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb]; + + if (pipe_split_from[i] < 0) { + pipes[pipe_cnt].clks_cfg.dppclk_mhz = + context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx]; + if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_idx] == pipe_idx) + pipes[pipe_cnt].pipe.dest.odm_combine = + context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_idx]; + else + pipes[pipe_cnt].pipe.dest.odm_combine = 0; + pipe_idx++; + } else { + pipes[pipe_cnt].clks_cfg.dppclk_mhz = + context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_split_from[i]]; + if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_split_from[i]] == pipe_split_from[i]) + pipes[pipe_cnt].pipe.dest.odm_combine = + context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel][pipe_split_from[i]]; + else + pipes[pipe_cnt].pipe.dest.odm_combine = 0; + } + if (dc->config.forced_clocks) { + pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; + pipes[pipe_cnt].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; + } + pipe_cnt++; + } + + if (pipe_cnt != pipe_idx) { + if (dc->res_pool->funcs->populate_dml_pipes) + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, + &context->res_ctx, pipes); + else + pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, + &context->res_ctx, pipes); + } + + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz; + + /* only pipe 0 is read for voltage and dcf/soc clocks */ + if (vlevel < 1) { + pipes[0].clks_cfg.voltage = 1; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].socclk_mhz; + } + context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + + if (vlevel < 2) { + pipes[0].clks_cfg.voltage = 2; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz; + } + context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + + if (vlevel < 3) { + pipes[0].clks_cfg.voltage = 3; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz; + } + context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz; + context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000; + /* Writeback MCIF_WB arbitration parameters */ + dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt); + + context->bw_ctx.bw.dcn.clk.dispclk_khz = context->bw_ctx.dml.vba.DISPCLK * 1000; + context->bw_ctx.bw.dcn.clk.dcfclk_khz = context->bw_ctx.dml.vba.DCFCLK * 1000; + context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000; + context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16; + context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000; + context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000; + context->bw_ctx.bw.dcn.clk.p_state_change_support = + context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] + != dm_dram_clock_change_unsupported; + context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; + + BW_VAL_TRACE_END_WATERMARKS(); + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + pipes[pipe_idx].pipe.dest.vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx]; + pipes[pipe_idx].pipe.dest.vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx]; + pipes[pipe_idx].pipe.dest.vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx]; + pipes[pipe_idx].pipe.dest.vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx]; + if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) + context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; + context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz = + pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + context->res_ctx.pipe_ctx[i].stream_res.dscclk_khz = + context->bw_ctx.dml.vba.DSCCLK_calculated[pipe_idx] * 1000; +#endif + context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest; + pipe_idx++; + } + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + bool cstate_en = context->bw_ctx.dml.vba.PrefetchMode[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != 2; + + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + context->bw_ctx.dml.funcs.rq_dlg_get_dlg_reg(&context->bw_ctx.dml, + &context->res_ctx.pipe_ctx[i].dlg_regs, + &context->res_ctx.pipe_ctx[i].ttu_regs, + pipes, + pipe_cnt, + pipe_idx, + cstate_en, + context->bw_ctx.bw.dcn.clk.p_state_change_support, + false, false, false); + + context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg(&context->bw_ctx.dml, + &context->res_ctx.pipe_ctx[i].rq_regs, + pipes[pipe_idx].pipe); + pipe_idx++; + } + + out = true; + goto validate_out; + +validate_fail: + DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n", + dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states])); + + BW_VAL_TRACE_SKIP(fail); + out = false; + +validate_out: + kfree(pipes); + + BW_VAL_TRACE_FINISH(); + + return out; +} + +struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( + struct dc_state *state, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct resource_context *res_ctx = &state->res_ctx; + struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); + struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool, head_pipe); + + if (!head_pipe) + ASSERT(0); + + if (!idle_pipe) + return NULL; + + idle_pipe->stream = head_pipe->stream; + idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.opp = head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; + + return idle_pipe; +} + +bool dcn20_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( + dc->res_pool->hubbub, + input, + output); +} + +static void dcn20_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn20_resource_pool *dcn20_pool = TO_DCN20_RES_POOL(*pool); + + destruct(dcn20_pool); + kfree(dcn20_pool); + *pool = NULL; +} + + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + + +enum dc_status dcn20_get_default_swizzle_mode(struct dc_plane_state *plane_state) +{ + enum dc_status result = DC_OK; + + enum surface_pixel_format surf_pix_format = plane_state->format; + unsigned int bpp = resource_pixel_format_to_bpp(surf_pix_format); + + enum swizzle_mode_values swizzle = DC_SW_LINEAR; + + if (bpp == 64) + swizzle = DC_SW_64KB_D; + else + swizzle = DC_SW_64KB_S; + + plane_state->tiling_info.gfx9.swizzle = swizzle; + return result; +} + +static struct resource_funcs dcn20_res_pool_funcs = { + .destroy = dcn20_destroy_resource_pool, + .link_enc_create = dcn20_link_encoder_create, + .validate_bandwidth = dcn20_validate_bandwidth, + .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, + .add_stream_to_ctx = dcn20_add_stream_to_ctx, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, + .get_default_swizzle_mode = dcn20_get_default_swizzle_mode, + .set_mcif_arb_params = dcn20_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link +}; + +bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + ASSERT(pipe_count > 0); + + for (i = 0; i < pipe_count; i++) { + struct dcn20_dwbc *dwbc20 = kzalloc(sizeof(struct dcn20_dwbc), + GFP_KERNEL); + + if (!dwbc20) { + dm_error("DC: failed to create dwbc20!\n"); + return false; + } + dcn20_dwbc_construct(dwbc20, ctx, + &dwbc20_regs[i], + &dwbc20_shift, + &dwbc20_mask, + i); + pool->dwbc[i] = &dwbc20->base; + } + return true; +} + +bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + ASSERT(pipe_count > 0); + + for (i = 0; i < pipe_count; i++) { + struct dcn20_mmhubbub *mcif_wb20 = kzalloc(sizeof(struct dcn20_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb20) { + dm_error("DC: failed to create mcif_wb20!\n"); + return false; + } + + dcn20_mmhubbub_construct(mcif_wb20, ctx, + &mcif_wb20_regs[i], + &mcif_wb20_shift, + &mcif_wb20_mask, + i); + + pool->mcif_wb[i] = &mcif_wb20->base; + } + return true; +} + +struct pp_smu_funcs *dcn20_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); + + if (!pp_smu) + return pp_smu; + + dm_pp_get_funcs(ctx, pp_smu); + + if (pp_smu->ctx.ver != PP_SMU_VER_NV) + pp_smu = memset(pp_smu, 0, sizeof(struct pp_smu_funcs)); + + return pp_smu; +} + +void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu) +{ + if (pp_smu && *pp_smu) { + kfree(*pp_smu); + *pp_smu = NULL; + } +} + +static void cap_soc_clocks( + struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table max_clocks) +{ + int i; + + // First pass - cap all clocks higher than the reported max + for (i = 0; i < bb->num_states; i++) { + if ((bb->clock_limits[i].dcfclk_mhz > (max_clocks.dcfClockInKhz / 1000)) + && max_clocks.dcfClockInKhz != 0) + bb->clock_limits[i].dcfclk_mhz = (max_clocks.dcfClockInKhz / 1000); + + if ((bb->clock_limits[i].dram_speed_mts > (max_clocks.uClockInKhz / 1000) * 16) + && max_clocks.uClockInKhz != 0) + bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16; + + // HACK: Force every uclk to max for now to "disable" uclk switching. + bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16; + + if ((bb->clock_limits[i].fabricclk_mhz > (max_clocks.fabricClockInKhz / 1000)) + && max_clocks.fabricClockInKhz != 0) + bb->clock_limits[i].fabricclk_mhz = (max_clocks.fabricClockInKhz / 1000); + + if ((bb->clock_limits[i].dispclk_mhz > (max_clocks.displayClockInKhz / 1000)) + && max_clocks.displayClockInKhz != 0) + bb->clock_limits[i].dispclk_mhz = (max_clocks.displayClockInKhz / 1000); + + if ((bb->clock_limits[i].dppclk_mhz > (max_clocks.dppClockInKhz / 1000)) + && max_clocks.dppClockInKhz != 0) + bb->clock_limits[i].dppclk_mhz = (max_clocks.dppClockInKhz / 1000); + + if ((bb->clock_limits[i].phyclk_mhz > (max_clocks.phyClockInKhz / 1000)) + && max_clocks.phyClockInKhz != 0) + bb->clock_limits[i].phyclk_mhz = (max_clocks.phyClockInKhz / 1000); + + if ((bb->clock_limits[i].socclk_mhz > (max_clocks.socClockInKhz / 1000)) + && max_clocks.socClockInKhz != 0) + bb->clock_limits[i].socclk_mhz = (max_clocks.socClockInKhz / 1000); + + if ((bb->clock_limits[i].dscclk_mhz > (max_clocks.dscClockInKhz / 1000)) + && max_clocks.dscClockInKhz != 0) + bb->clock_limits[i].dscclk_mhz = (max_clocks.dscClockInKhz / 1000); + } + + // Second pass - remove all duplicate clock states + for (i = bb->num_states - 1; i > 1; i--) { + bool duplicate = true; + + if (bb->clock_limits[i-1].dcfclk_mhz != bb->clock_limits[i].dcfclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].dispclk_mhz != bb->clock_limits[i].dispclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].dppclk_mhz != bb->clock_limits[i].dppclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].dram_speed_mts != bb->clock_limits[i].dram_speed_mts) + duplicate = false; + if (bb->clock_limits[i-1].dscclk_mhz != bb->clock_limits[i].dscclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].fabricclk_mhz != bb->clock_limits[i].fabricclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].phyclk_mhz != bb->clock_limits[i].phyclk_mhz) + duplicate = false; + if (bb->clock_limits[i-1].socclk_mhz != bb->clock_limits[i].socclk_mhz) + duplicate = false; + + if (duplicate) + bb->num_states--; + } +} + +static void update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states) +{ + struct _vcs_dpi_voltage_scaling_st calculated_states[MAX_CLOCK_LIMIT_STATES] = {0}; + int i; + int num_calculated_states = 0; + int min_dcfclk = 0; + + if (num_states == 0) + return; + + if (dc->bb_overrides.min_dcfclk_mhz > 0) + min_dcfclk = dc->bb_overrides.min_dcfclk_mhz; + + for (i = 0; i < num_states; i++) { + int min_fclk_required_by_uclk; + calculated_states[i].state = i; + calculated_states[i].dram_speed_mts = uclk_states[i] * 16 / 1000; + + // FCLK:UCLK ratio is 1.08 + min_fclk_required_by_uclk = mul_u64_u32_shr(BIT_ULL(32) * 1080 / 1000000, uclk_states[i], 32); + + calculated_states[i].fabricclk_mhz = (min_fclk_required_by_uclk < min_dcfclk) ? + min_dcfclk : min_fclk_required_by_uclk; + + calculated_states[i].socclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->socClockInKhz / 1000) ? + max_clocks->socClockInKhz / 1000 : calculated_states[i].fabricclk_mhz; + + calculated_states[i].dcfclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->dcfClockInKhz / 1000) ? + max_clocks->dcfClockInKhz / 1000 : calculated_states[i].fabricclk_mhz; + + calculated_states[i].dispclk_mhz = max_clocks->displayClockInKhz / 1000; + calculated_states[i].dppclk_mhz = max_clocks->displayClockInKhz / 1000; + calculated_states[i].dscclk_mhz = max_clocks->displayClockInKhz / (1000 * 3); + + calculated_states[i].phyclk_mhz = max_clocks->phyClockInKhz / 1000; + + num_calculated_states++; + } + + memcpy(bb->clock_limits, calculated_states, sizeof(bb->clock_limits)); + bb->num_states = num_calculated_states; + + // Duplicate the last state, DML always an extra state identical to max state to work + memcpy(&bb->clock_limits[num_calculated_states], &bb->clock_limits[num_calculated_states - 1], sizeof(struct _vcs_dpi_voltage_scaling_st)); + bb->clock_limits[num_calculated_states].state = bb->num_states; +} + +static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb) +{ + kernel_fpu_begin(); + if ((int)(bb->sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns + && dc->bb_overrides.sr_exit_time_ns) { + bb->sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0; + } + + if ((int)(bb->sr_enter_plus_exit_time_us * 1000) + != dc->bb_overrides.sr_enter_plus_exit_time_ns + && dc->bb_overrides.sr_enter_plus_exit_time_ns) { + bb->sr_enter_plus_exit_time_us = + dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0; + } + + if ((int)(bb->urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns + && dc->bb_overrides.urgent_latency_ns) { + bb->urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0; + } + + if ((int)(bb->dram_clock_change_latency_us * 1000) + != dc->bb_overrides.dram_clock_change_latency_ns + && dc->bb_overrides.dram_clock_change_latency_ns) { + bb->dram_clock_change_latency_us = + dc->bb_overrides.dram_clock_change_latency_ns / 1000.0; + } + kernel_fpu_end(); +} + +#define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) +#define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) + +static bool init_soc_bounding_box(struct dc *dc, + struct dcn20_resource_pool *pool) +{ + const struct gpu_info_soc_bounding_box_v1_0 *bb = dc->soc_bounding_box; + DC_LOGGER_INIT(dc->ctx->logger); + + if (!bb && !SOC_BOUNDING_BOX_VALID) { + DC_LOG_ERROR("%s: not valid soc bounding box/n", __func__); + return false; + } + + if (bb && !SOC_BOUNDING_BOX_VALID) { + int i; + + dcn2_0_soc.sr_exit_time_us = + fixed16_to_double_to_cpu(bb->sr_exit_time_us); + dcn2_0_soc.sr_enter_plus_exit_time_us = + fixed16_to_double_to_cpu(bb->sr_enter_plus_exit_time_us); + dcn2_0_soc.urgent_latency_us = + fixed16_to_double_to_cpu(bb->urgent_latency_us); + dcn2_0_soc.urgent_latency_pixel_data_only_us = + fixed16_to_double_to_cpu(bb->urgent_latency_pixel_data_only_us); + dcn2_0_soc.urgent_latency_pixel_mixed_with_vm_data_us = + fixed16_to_double_to_cpu(bb->urgent_latency_pixel_mixed_with_vm_data_us); + dcn2_0_soc.urgent_latency_vm_data_only_us = + fixed16_to_double_to_cpu(bb->urgent_latency_vm_data_only_us); + dcn2_0_soc.urgent_out_of_order_return_per_channel_pixel_only_bytes = + le32_to_cpu(bb->urgent_out_of_order_return_per_channel_pixel_only_bytes); + dcn2_0_soc.urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = + le32_to_cpu(bb->urgent_out_of_order_return_per_channel_pixel_and_vm_bytes); + dcn2_0_soc.urgent_out_of_order_return_per_channel_vm_only_bytes = + le32_to_cpu(bb->urgent_out_of_order_return_per_channel_vm_only_bytes); + dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_only = + fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_pixel_only); + dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = + fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm); + dcn2_0_soc.pct_ideal_dram_sdp_bw_after_urgent_vm_only = + fixed16_to_double_to_cpu(bb->pct_ideal_dram_sdp_bw_after_urgent_vm_only); + dcn2_0_soc.max_avg_sdp_bw_use_normal_percent = + fixed16_to_double_to_cpu(bb->max_avg_sdp_bw_use_normal_percent); + dcn2_0_soc.max_avg_dram_bw_use_normal_percent = + fixed16_to_double_to_cpu(bb->max_avg_dram_bw_use_normal_percent); + dcn2_0_soc.writeback_latency_us = + fixed16_to_double_to_cpu(bb->writeback_latency_us); + dcn2_0_soc.ideal_dram_bw_after_urgent_percent = + fixed16_to_double_to_cpu(bb->ideal_dram_bw_after_urgent_percent); + dcn2_0_soc.max_request_size_bytes = + le32_to_cpu(bb->max_request_size_bytes); + dcn2_0_soc.dram_channel_width_bytes = + le32_to_cpu(bb->dram_channel_width_bytes); + dcn2_0_soc.fabric_datapath_to_dcn_data_return_bytes = + le32_to_cpu(bb->fabric_datapath_to_dcn_data_return_bytes); + dcn2_0_soc.dcn_downspread_percent = + fixed16_to_double_to_cpu(bb->dcn_downspread_percent); + dcn2_0_soc.downspread_percent = + fixed16_to_double_to_cpu(bb->downspread_percent); + dcn2_0_soc.dram_page_open_time_ns = + fixed16_to_double_to_cpu(bb->dram_page_open_time_ns); + dcn2_0_soc.dram_rw_turnaround_time_ns = + fixed16_to_double_to_cpu(bb->dram_rw_turnaround_time_ns); + dcn2_0_soc.dram_return_buffer_per_channel_bytes = + le32_to_cpu(bb->dram_return_buffer_per_channel_bytes); + dcn2_0_soc.round_trip_ping_latency_dcfclk_cycles = + le32_to_cpu(bb->round_trip_ping_latency_dcfclk_cycles); + dcn2_0_soc.urgent_out_of_order_return_per_channel_bytes = + le32_to_cpu(bb->urgent_out_of_order_return_per_channel_bytes); + dcn2_0_soc.channel_interleave_bytes = + le32_to_cpu(bb->channel_interleave_bytes); + dcn2_0_soc.num_banks = + le32_to_cpu(bb->num_banks); + dcn2_0_soc.num_chans = + le32_to_cpu(bb->num_chans); + dcn2_0_soc.vmm_page_size_bytes = + le32_to_cpu(bb->vmm_page_size_bytes); + dcn2_0_soc.dram_clock_change_latency_us = + fixed16_to_double_to_cpu(bb->dram_clock_change_latency_us); + // HACK!! Lower uclock latency switch time so we don't switch + dcn2_0_soc.dram_clock_change_latency_us = 10; + dcn2_0_soc.writeback_dram_clock_change_latency_us = + fixed16_to_double_to_cpu(bb->writeback_dram_clock_change_latency_us); + dcn2_0_soc.return_bus_width_bytes = + le32_to_cpu(bb->return_bus_width_bytes); + dcn2_0_soc.dispclk_dppclk_vco_speed_mhz = + le32_to_cpu(bb->dispclk_dppclk_vco_speed_mhz); + dcn2_0_soc.xfc_bus_transport_time_us = + le32_to_cpu(bb->xfc_bus_transport_time_us); + dcn2_0_soc.xfc_xbuf_latency_tolerance_us = + le32_to_cpu(bb->xfc_xbuf_latency_tolerance_us); + dcn2_0_soc.use_urgent_burst_bw = + le32_to_cpu(bb->use_urgent_burst_bw); + dcn2_0_soc.num_states = + le32_to_cpu(bb->num_states); + + for (i = 0; i < dcn2_0_soc.num_states; i++) { + dcn2_0_soc.clock_limits[i].state = + le32_to_cpu(bb->clock_limits[i].state); + dcn2_0_soc.clock_limits[i].dcfclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].dcfclk_mhz); + dcn2_0_soc.clock_limits[i].fabricclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].fabricclk_mhz); + dcn2_0_soc.clock_limits[i].dispclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].dispclk_mhz); + dcn2_0_soc.clock_limits[i].dppclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].dppclk_mhz); + dcn2_0_soc.clock_limits[i].phyclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].phyclk_mhz); + dcn2_0_soc.clock_limits[i].socclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].socclk_mhz); + dcn2_0_soc.clock_limits[i].dscclk_mhz = + fixed16_to_double_to_cpu(bb->clock_limits[i].dscclk_mhz); + dcn2_0_soc.clock_limits[i].dram_speed_mts = + fixed16_to_double_to_cpu(bb->clock_limits[i].dram_speed_mts); + } + } + + if (pool->base.pp_smu) { + struct pp_smu_nv_clock_table max_clocks = {0}; + unsigned int uclk_states[8] = {0}; + unsigned int num_states = 0; + int i; + enum pp_smu_status status; + bool clock_limits_available = false; + bool uclk_states_available = false; + + if (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) { + status = (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) + (&pool->base.pp_smu->nv_funcs.pp_smu, uclk_states, &num_states); + + uclk_states_available = (status == PP_SMU_RESULT_OK); + } + + if (pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) { + status = (*pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) + (&pool->base.pp_smu->nv_funcs.pp_smu, &max_clocks); + /* SMU cannot set DCF clock to anything equal to or higher than SOC clock + */ + if (max_clocks.dcfClockInKhz >= max_clocks.socClockInKhz) + max_clocks.dcfClockInKhz = max_clocks.socClockInKhz - 1000; + clock_limits_available = (status == PP_SMU_RESULT_OK); + } + + // HACK: Use the max uclk_states value for all elements. + for (i = 0; i < num_states; i++) + uclk_states[i] = uclk_states[num_states - 1]; + + if (clock_limits_available && uclk_states_available && num_states) + update_bounding_box(dc, &dcn2_0_soc, &max_clocks, uclk_states, num_states); + else if (clock_limits_available) + cap_soc_clocks(&dcn2_0_soc, max_clocks); + } + + dcn2_0_ip.max_num_otg = pool->base.res_cap->num_timing_generator; + dcn2_0_ip.max_num_dpp = pool->base.pipe_count; + patch_bounding_box(dc, &dcn2_0_soc); + + return true; +} + +static bool construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn20_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_nv10; + pool->base.funcs = &dcn20_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + pool->base.pipe_count = 6; + pool->base.mpcc_count = 6; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 256; + dc->caps.dmdata_alloc_size = 2048; + + dc->caps.max_slave_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.hw_3d_lut = true; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) { + dc->debug = debug_defaults_drv; + } else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) { + pool->base.pipe_count = 4; + pool->base.mpcc_count = pool->base.pipe_count; + dc->debug = debug_defaults_diags; + } else { + dc->debug = debug_defaults_diags; + } + //dcn2.0x + dc->work_arounds.dedcn20_305_wa = true; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL2] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL3] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL4] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL5] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL5, + &clk_src_regs[5], false); + pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL; + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + pool->base.dccg = dccg2_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.dmcu = dcn20_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.pp_smu = dcn20_pp_smu_create(ctx); + + + if (!init_soc_bounding_box(dc, pool)) { + dm_error("DC: failed to initialize soc bounding box!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + dml_init_instance(&dc->dml, &dcn2_0_soc, &dcn2_0_ip, DML_PROJECT_NAVI10); + + if (!dc->debug.disable_pplib_wm_range) { + struct pp_smu_wm_range_sets ranges = {0}; + int i = 0; + + ranges.num_reader_wm_sets = 0; + + if (dcn2_0_soc.num_states == 1) { + ranges.reader_wm_sets[0].wm_inst = i; + ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + ranges.num_reader_wm_sets = 1; + } else if (dcn2_0_soc.num_states > 1) { + for (i = 0; i < 4 && i < dcn2_0_soc.num_states; i++) { + ranges.reader_wm_sets[i].wm_inst = i; + ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (dcn2_0_soc.clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges.reader_wm_sets[i].max_fill_clk_mhz = dcn2_0_soc.clock_limits[i].dram_speed_mts / 16; + + ranges.num_reader_wm_sets = i + 1; + } + + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[ranges.num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + } + + ranges.num_writer_wm_sets = 1; + + ranges.writer_wm_sets[0].wm_inst = 0; + ranges.writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + if (pool->base.pp_smu->nv_funcs.set_wm_ranges) + pool->base.pp_smu->nv_funcs.set_wm_ranges(&pool->base.pp_smu->nv_funcs.pp_smu, &ranges); + } + + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn20_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn20_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto create_fail; + } + + pool->base.ipps[i] = dcn20_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn20_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn20_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn20_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn20_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn20_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + + pool->base.timing_generator_count = i; + + pool->base.mpc = dcn20_mpc_create(ctx); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + pool->base.hubbub = dcn20_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn20_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } +#endif + + if (!dcn20_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + if (!dcn20_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ? + &res_create_funcs : &res_create_maximus_funcs))) + goto create_fail; + + dcn20_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + return true; + +create_fail: + + destruct(pool); + + return false; +} + +struct resource_pool *dcn20_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn20_resource_pool *pool = + kzalloc(sizeof(struct dcn20_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h new file mode 100644 index 000000000000..b5a75289f444 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -0,0 +1,133 @@ +/* +* 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. + * + * Authors: AMD + * + */ + +#ifndef __DC_RESOURCE_DCN20_H__ +#define __DC_RESOURCE_DCN20_H__ + +#include "core_types.h" + +#define TO_DCN20_RES_POOL(pool)\ + container_of(pool, struct dcn20_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +struct dcn20_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn20_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +struct link_encoder *dcn20_link_encoder_create( + const struct encoder_init_data *enc_init_data); + +unsigned int dcn20_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark); +int dcn20_populate_dml_pipes_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); +struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( + struct dc_state *state, + const struct resource_pool *pool, + struct dc_stream_state *stream); +void dcn20_populate_dml_writeback_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); + +struct stream_encoder *dcn20_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx); + +struct dce_hwseq *dcn20_hwseq_create( + struct dc_context *ctx); + +bool dcn20_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output); + +void dcn20_dpp_destroy(struct dpp **dpp); + +struct dpp *dcn20_dpp_create( + struct dc_context *ctx, + uint32_t inst); + +struct input_pixel_processor *dcn20_ipp_create( + struct dc_context *ctx, uint32_t inst); + + +struct output_pixel_processor *dcn20_opp_create( + struct dc_context *ctx, uint32_t inst); + +struct dce_aux *dcn20_aux_engine_create( + struct dc_context *ctx, uint32_t inst); + +struct dce_i2c_hw *dcn20_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst); + +void dcn20_clock_source_destroy(struct clock_source **clk_src); + +struct display_stream_compressor *dcn20_dsc_create( + struct dc_context *ctx, uint32_t inst); +void dcn20_dsc_destroy(struct display_stream_compressor **dsc); + +struct pp_smu_funcs *dcn20_pp_smu_create(struct dc_context *ctx); +void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu); + +struct hubp *dcn20_hubp_create( + struct dc_context *ctx, + uint32_t inst); +struct timing_generator *dcn20_timing_generator_create( + struct dc_context *ctx, + uint32_t instance); +struct mpc *dcn20_mpc_create(struct dc_context *ctx); +struct hubbub *dcn20_hubbub_create(struct dc_context *ctx); + +bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool); +bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool); + +void dcn20_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt); +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); + +enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); +enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); +enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); +enum dc_status dcn20_get_default_swizzle_mode(struct dc_plane_state *plane_state); + +void dcn20_patch_bounding_box( + struct dc *dc, + struct _vcs_dpi_soc_bounding_box_st *bb); +void dcn20_cap_soc_clocks( + struct _vcs_dpi_soc_bounding_box_st *bb, + struct pp_smu_nv_clock_table max_clocks); + +#endif /* __DC_RESOURCE_DCN20_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c new file mode 100644 index 000000000000..f5bcffc426b8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -0,0 +1,610 @@ +/* + * 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 <linux/delay.h> + +#include "dc_bios_types.h" +#include "dcn20_stream_encoder.h" +#include "reg_helper.h" +#include "hw_shared.h" + +#define DC_LOGGER \ + enc1->base.ctx->logger + + +#define REG(reg)\ + (enc1->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + enc1->se_shift->field_name, enc1->se_mask->field_name + + +#define CTX \ + enc1->base.ctx + + +static void enc2_update_hdmi_info_packet( + struct dcn10_stream_encoder *enc1, + uint32_t packet_index, + const struct dc_info_packet *info_packet) +{ + uint32_t cont, send, line; + + if (info_packet->valid) { + enc1_update_generic_info_packet( + enc1, + packet_index, + info_packet); + + /* enable transmission of packet(s) - + * packet transmission begins on the next frame */ + cont = 1; + /* send packet(s) every frame */ + send = 1; + /* select line number to send packets on */ + line = 2; + } else { + cont = 0; + send = 0; + line = 0; + } + + /* DP_SEC_GSP[x]_LINE_REFERENCE - keep default value REFER_TO_DP_SOF */ + + /* choose which generic packet control to use */ + switch (packet_index) { + case 0: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC0_CONT, cont, + HDMI_GENERIC0_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL1, + HDMI_GENERIC0_LINE, line); + break; + case 1: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC1_CONT, cont, + HDMI_GENERIC1_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL1, + HDMI_GENERIC1_LINE, line); + break; + case 2: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC2_CONT, cont, + HDMI_GENERIC2_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL2, + HDMI_GENERIC2_LINE, line); + break; + case 3: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC3_CONT, cont, + HDMI_GENERIC3_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL2, + HDMI_GENERIC3_LINE, line); + break; + case 4: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC4_CONT, cont, + HDMI_GENERIC4_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL3, + HDMI_GENERIC4_LINE, line); + break; + case 5: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC5_CONT, cont, + HDMI_GENERIC5_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL3, + HDMI_GENERIC5_LINE, line); + break; + case 6: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC6_CONT, cont, + HDMI_GENERIC6_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL4, + HDMI_GENERIC6_LINE, line); + break; + case 7: + REG_UPDATE_2(HDMI_GENERIC_PACKET_CONTROL0, + HDMI_GENERIC7_CONT, cont, + HDMI_GENERIC7_SEND, send); + REG_UPDATE(HDMI_GENERIC_PACKET_CONTROL4, + HDMI_GENERIC7_LINE, line); + break; + default: + /* invalid HW packet index */ + DC_LOG_WARNING( + "Invalid HW packet index: %s()\n", + __func__); + return; + } +} + +static void enc2_stream_encoder_update_hdmi_info_packets( + struct stream_encoder *enc, + const struct encoder_info_frame *info_frame) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + /* for bring up, disable dp double TODO */ + REG_UPDATE(HDMI_DB_CONTROL, HDMI_DB_DISABLE, 1); + + /*Always add mandatory packets first followed by optional ones*/ + enc2_update_hdmi_info_packet(enc1, 0, &info_frame->avi); + enc2_update_hdmi_info_packet(enc1, 5, &info_frame->hfvsif); + enc2_update_hdmi_info_packet(enc1, 2, &info_frame->gamut); + enc2_update_hdmi_info_packet(enc1, 1, &info_frame->vendor); + enc2_update_hdmi_info_packet(enc1, 3, &info_frame->spd); + enc2_update_hdmi_info_packet(enc1, 4, &info_frame->hdrsmd); +} + +static void enc2_stream_encoder_stop_hdmi_info_packets( + struct stream_encoder *enc) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + /* stop generic packets 0,1 on HDMI */ + REG_SET_4(HDMI_GENERIC_PACKET_CONTROL0, 0, + HDMI_GENERIC0_CONT, 0, + HDMI_GENERIC0_SEND, 0, + HDMI_GENERIC1_CONT, 0, + HDMI_GENERIC1_SEND, 0); + REG_SET_2(HDMI_GENERIC_PACKET_CONTROL1, 0, + HDMI_GENERIC0_LINE, 0, + HDMI_GENERIC1_LINE, 0); + + /* stop generic packets 2,3 on HDMI */ + REG_SET_4(HDMI_GENERIC_PACKET_CONTROL0, 0, + HDMI_GENERIC2_CONT, 0, + HDMI_GENERIC2_SEND, 0, + HDMI_GENERIC3_CONT, 0, + HDMI_GENERIC3_SEND, 0); + REG_SET_2(HDMI_GENERIC_PACKET_CONTROL2, 0, + HDMI_GENERIC2_LINE, 0, + HDMI_GENERIC3_LINE, 0); + + /* stop generic packets 4,5 on HDMI */ + REG_SET_4(HDMI_GENERIC_PACKET_CONTROL0, 0, + HDMI_GENERIC4_CONT, 0, + HDMI_GENERIC4_SEND, 0, + HDMI_GENERIC5_CONT, 0, + HDMI_GENERIC5_SEND, 0); + REG_SET_2(HDMI_GENERIC_PACKET_CONTROL3, 0, + HDMI_GENERIC4_LINE, 0, + HDMI_GENERIC5_LINE, 0); + + /* stop generic packets 6,7 on HDMI */ + REG_SET_4(HDMI_GENERIC_PACKET_CONTROL0, 0, + HDMI_GENERIC6_CONT, 0, + HDMI_GENERIC6_SEND, 0, + HDMI_GENERIC7_CONT, 0, + HDMI_GENERIC7_SEND, 0); + REG_SET_2(HDMI_GENERIC_PACKET_CONTROL4, 0, + HDMI_GENERIC6_LINE, 0, + HDMI_GENERIC7_LINE, 0); +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + + +/* Update GSP7 SDP 128 byte long */ +static void enc2_send_gsp7_128_info_packet( + struct dcn10_stream_encoder *enc1, + const struct dc_info_packet_128 *info_packet) +{ + uint32_t i; + + /* TODOFPGA Figure out a proper number for max_retries polling for lock + * use 50 for now. + */ + uint32_t max_retries = 50; + const uint32_t *content = (const uint32_t *) &info_packet->sb[0]; + + ASSERT(info_packet->hb1 == DC_DP_INFOFRAME_TYPE_PPS); + + /* Configure for PPS packet size (128 bytes) */ + REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP7_PPS, 1); + + /* We need turn on clock before programming AFMT block*/ + REG_UPDATE(AFMT_CNTL, AFMT_AUDIO_CLOCK_EN, 1); + + /* Poll dig_update_lock is not locked -> asic internal signal + * assumes otg master lock will unlock it + */ + /*REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_LOCK_STATUS, 0, 10, max_retries);*/ + + /* Wait for HW/SW GSP memory access conflict to go away */ + REG_WAIT(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT, + 0, 10, max_retries); + + /* Clear HW/SW memory access conflict flag */ + REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_CONFLICT_CLR, 1); + + /* write generic packet header */ + REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_INDEX, 7); + REG_SET_4(AFMT_GENERIC_HDR, 0, + AFMT_GENERIC_HB0, info_packet->hb0, + AFMT_GENERIC_HB1, info_packet->hb1, + AFMT_GENERIC_HB2, info_packet->hb2, + AFMT_GENERIC_HB3, info_packet->hb3); + + /* Write generic packet content 128 bytes long. Four sets are used (indexes 7 + * through 10) to fit 128 bytes. + */ + for (i = 0; i < 4; i++) { + uint32_t packet_index = 7 + i; + REG_UPDATE(AFMT_VBI_PACKET_CONTROL, AFMT_GENERIC_INDEX, packet_index); + + REG_WRITE(AFMT_GENERIC_0, *content++); + REG_WRITE(AFMT_GENERIC_1, *content++); + REG_WRITE(AFMT_GENERIC_2, *content++); + REG_WRITE(AFMT_GENERIC_3, *content++); + REG_WRITE(AFMT_GENERIC_4, *content++); + REG_WRITE(AFMT_GENERIC_5, *content++); + REG_WRITE(AFMT_GENERIC_6, *content++); + REG_WRITE(AFMT_GENERIC_7, *content++); + } + + REG_UPDATE(AFMT_VBI_PACKET_CONTROL1, AFMT_GENERIC7_FRAME_UPDATE, 1); +} + +/* Set DSC-related configuration. + * dsc_mode: 0 disables DSC, other values enable DSC in specified format + * sc_bytes_per_pixel: Bytes per pixel in u3.28 format + * dsc_slice_width: Slice width in pixels + */ +static void enc2_dp_set_dsc_config(struct stream_encoder *enc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width, + uint8_t *dsc_packed_pps) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t dsc_value = 0; + + dsc_value = REG_READ(DP_DSC_CNTL); + + /* dsc disable skip */ + if ((dsc_value & 0x3) == 0x0) + return; + + + REG_UPDATE_2(DP_DSC_CNTL, + DP_DSC_MODE, dsc_mode, + DP_DSC_SLICE_WIDTH, dsc_slice_width); + + REG_SET(DP_DSC_BYTES_PER_PIXEL, 0, + DP_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); + + if (dsc_mode != OPTC_DSC_DISABLED) { + struct dc_info_packet_128 pps_sdp; + + ASSERT(dsc_packed_pps); + + /* Load PPS into infoframe (SDP) registers */ + pps_sdp.valid = true; + pps_sdp.hb0 = 0; + pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS; + pps_sdp.hb2 = 127; + pps_sdp.hb3 = 0; + memcpy(&pps_sdp.sb[0], dsc_packed_pps, sizeof(pps_sdp.sb)); + enc2_send_gsp7_128_info_packet(enc1, &pps_sdp); + + /* Enable Generic Stream Packet 7 (GSP) transmission */ + //REG_UPDATE(DP_SEC_CNTL, + // DP_SEC_GSP7_ENABLE, 1); + + /* SW should make sure VBID[6] update line number is bigger + * than PPS transmit line number + */ + REG_UPDATE(DP_SEC_CNTL6, + DP_SEC_GSP7_LINE_NUM, 2); + REG_UPDATE_2(DP_MSA_VBID_MISC, + DP_VBID6_LINE_REFERENCE, 0, + DP_VBID6_LINE_NUM, 3); + + /* Send PPS data at the line number specified above. + * DP spec requires PPS to be sent only when it changes, however since + * decoder has to be able to handle its change on every frame, we're + * sending it always (i.e. on every frame) to reduce the chance it'd be + * missed by decoder. If it turns out required to send PPS only when it + * changes, we can use DP_SEC_GSP7_SEND register. + */ + REG_UPDATE_2(DP_SEC_CNTL, + DP_SEC_GSP7_ENABLE, 1, + DP_SEC_STREAM_ENABLE, 1); + } else { + /* Disable Generic Stream Packet 7 (GSP) transmission */ + REG_UPDATE(DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, 0); + REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP7_PPS, 0); + } +} +#endif + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +/* this function read dsc related register fields to be logged later in dcn10_log_hw_state + * into a dcn_dsc_state struct. + */ +static void enc2_read_state(struct stream_encoder *enc, struct enc_state *s) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + //if dsc is enabled, continue to read + REG_GET(DP_DSC_CNTL, DP_DSC_MODE, &s->dsc_mode); + if (s->dsc_mode) { + REG_GET(DP_DSC_CNTL, DP_DSC_SLICE_WIDTH, &s->dsc_slice_width); + REG_GET(DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, &s->sec_gsp_pps_line_num); + + REG_GET(DP_MSA_VBID_MISC, DP_VBID6_LINE_REFERENCE, &s->vbid6_line_reference); + REG_GET(DP_MSA_VBID_MISC, DP_VBID6_LINE_NUM, &s->vbid6_line_num); + + REG_GET(DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, &s->sec_gsp_pps_enable); + REG_GET(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, &s->sec_stream_enable); + } +} +#endif + +/* Set Dynamic Metadata-configuration. + * enable_dme: TRUE: enables Dynamic Metadata Enfine, FALSE: disables DME + * hubp_requestor_id: HUBP physical instance that is the source of dynamic metadata + * only needs to be set when enable_dme is TRUE + * dmdata_mode: dynamic metadata packet type: DP, HDMI, or Dolby Vision + * + * Ensure the OTG master update lock is set when changing DME configuration. + */ +static void enc2_set_dynamic_metadata(struct stream_encoder *enc, + bool enable_dme, + uint32_t hubp_requestor_id, + enum dynamic_metadata_mode dmdata_mode) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + if (enable_dme) { + REG_UPDATE_2(DME_CONTROL, + METADATA_HUBP_REQUESTOR_ID, hubp_requestor_id, + METADATA_STREAM_TYPE, (dmdata_mode == dmdata_dolby_vision) ? 1 : 0); + + /* Use default line reference DP_SOF for bringup. + * Should use OTG_SOF for DRR cases + */ + if (dmdata_mode == dmdata_dp) + REG_UPDATE_3(DP_SEC_METADATA_TRANSMISSION, + DP_SEC_METADATA_PACKET_ENABLE, 1, + DP_SEC_METADATA_PACKET_LINE_REFERENCE, 0, + DP_SEC_METADATA_PACKET_LINE, 20); + else { + REG_UPDATE_3(HDMI_METADATA_PACKET_CONTROL, + HDMI_METADATA_PACKET_ENABLE, 1, + HDMI_METADATA_PACKET_LINE_REFERENCE, 0, + HDMI_METADATA_PACKET_LINE, 2); + + if (dmdata_mode == dmdata_dolby_vision) + REG_UPDATE(DIG_FE_CNTL, + DOLBY_VISION_EN, 1); + } + + REG_UPDATE(DME_CONTROL, + METADATA_ENGINE_EN, 1); + } else { + REG_UPDATE(DME_CONTROL, + METADATA_ENGINE_EN, 0); + + if (dmdata_mode == dmdata_dp) + REG_UPDATE(DP_SEC_METADATA_TRANSMISSION, + DP_SEC_METADATA_PACKET_ENABLE, 0); + else { + REG_UPDATE(HDMI_METADATA_PACKET_CONTROL, + HDMI_METADATA_PACKET_ENABLE, 0); + REG_UPDATE(DIG_FE_CNTL, + DOLBY_VISION_EN, 0); + } + } +} + +static void enc2_stream_encoder_update_dp_info_packets( + struct stream_encoder *enc, + const struct encoder_info_frame *info_frame) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + uint32_t dmdata_packet_enabled = 0; + + enc1_stream_encoder_update_dp_info_packets(enc, info_frame); + + /* check if dynamic metadata packet transmission is enabled */ + REG_GET(DP_SEC_METADATA_TRANSMISSION, + DP_SEC_METADATA_PACKET_ENABLE, &dmdata_packet_enabled); + + if (dmdata_packet_enabled) + REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1); +} + +static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 + && !timing->dsc_cfg.ycbcr422_simple); +#endif + return two_pix; +} + +void enc2_stream_encoder_dp_unblank( + struct stream_encoder *enc, + const struct encoder_unblank_param *param) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) { + uint32_t n_vid = 0x8000; + uint32_t m_vid; + uint32_t n_multiply = 0; + uint64_t m_vid_l = n_vid; + + /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */ + if (is_two_pixels_per_containter(¶m->timing) || param->odm) { + /*this logic should be the same in get_pixel_clock_parameters() */ + n_multiply = 1; + } + /* M / N = Fstream / Flink + * m_vid / n_vid = pixel rate / link rate + */ + + m_vid_l *= param->timing.pix_clk_100hz / 10; + m_vid_l = div_u64(m_vid_l, + param->link_settings.link_rate + * LINK_RATE_REF_FREQ_IN_KHZ); + + m_vid = (uint32_t) m_vid_l; + + /* enable auto measurement */ + + REG_UPDATE(DP_VID_TIMING, DP_VID_M_N_GEN_EN, 0); + + /* auto measurement need 1 full 0x8000 symbol cycle to kick in, + * therefore program initial value for Mvid and Nvid + */ + + REG_UPDATE(DP_VID_N, DP_VID_N, n_vid); + + REG_UPDATE(DP_VID_M, DP_VID_M, m_vid); + + REG_UPDATE_2(DP_VID_TIMING, + DP_VID_M_N_GEN_EN, 1, + DP_VID_N_MUL, n_multiply); + } + + /* set DIG_START to 0x1 to reset FIFO */ + + REG_UPDATE(DIG_FE_CNTL, DIG_START, 1); + + /* write 0 to take the FIFO out of reset */ + + REG_UPDATE(DIG_FE_CNTL, DIG_START, 0); + + /* switch DP encoder to CRTC data */ + + REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, 0); + + /* wait 100us for DIG/DP logic to prime + * (i.e. a few video lines) + */ + udelay(100); + + /* the hardware would start sending video at the start of the next DP + * frame (i.e. rising edge of the vblank). + * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this + * register has no effect on enable transition! HW always guarantees + * VID_STREAM enable at start of next frame, and this is not + * programmable + */ + + REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true); +} + +static void enc2_dp_set_odm_combine( + struct stream_encoder *enc, + bool odm_combine) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_COMBINE, odm_combine); +} + +void enc2_stream_encoder_dp_set_stream_attribute( + struct stream_encoder *enc, + struct dc_crtc_timing *crtc_timing, + enum dc_color_space output_color_space, + uint32_t enable_sdp_splitting) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + enc1_stream_encoder_dp_set_stream_attribute(enc, crtc_timing, output_color_space, enable_sdp_splitting); + + REG_UPDATE(DP_SEC_FRAMING4, + DP_SST_SDP_SPLITTING, enable_sdp_splitting); +} + +static const struct stream_encoder_funcs dcn20_str_enc_funcs = { + .dp_set_odm_combine = + enc2_dp_set_odm_combine, + .dp_set_stream_attribute = + enc2_stream_encoder_dp_set_stream_attribute, + .hdmi_set_stream_attribute = + enc1_stream_encoder_hdmi_set_stream_attribute, + .dvi_set_stream_attribute = + enc1_stream_encoder_dvi_set_stream_attribute, + .set_mst_bandwidth = + enc1_stream_encoder_set_mst_bandwidth, + .update_hdmi_info_packets = + enc2_stream_encoder_update_hdmi_info_packets, + .stop_hdmi_info_packets = + enc2_stream_encoder_stop_hdmi_info_packets, + .update_dp_info_packets = + enc2_stream_encoder_update_dp_info_packets, + .stop_dp_info_packets = + enc1_stream_encoder_stop_dp_info_packets, + .dp_blank = + enc1_stream_encoder_dp_blank, + .dp_unblank = + enc2_stream_encoder_dp_unblank, + .audio_mute_control = enc1_se_audio_mute_control, + + .dp_audio_setup = enc1_se_dp_audio_setup, + .dp_audio_enable = enc1_se_dp_audio_enable, + .dp_audio_disable = enc1_se_dp_audio_disable, + + .hdmi_audio_setup = enc1_se_hdmi_audio_setup, + .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, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .enc_read_state = enc2_read_state, +#endif + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .dp_set_dsc_config = enc2_dp_set_dsc_config, +#endif + .set_dynamic_metadata = enc2_set_dynamic_metadata, +}; + +void dcn20_stream_encoder_construct( + struct dcn10_stream_encoder *enc1, + struct dc_context *ctx, + struct dc_bios *bp, + enum engine_id eng_id, + const struct dcn10_stream_enc_registers *regs, + const struct dcn10_stream_encoder_shift *se_shift, + const struct dcn10_stream_encoder_mask *se_mask) +{ + enc1->base.funcs = &dcn20_str_enc_funcs; + enc1->base.ctx = ctx; + enc1->base.id = eng_id; + enc1->base.bp = bp; + enc1->regs = regs; + enc1->se_shift = se_shift; + enc1->se_mask = se_mask; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h new file mode 100644 index 000000000000..6d40e8c9b78f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h @@ -0,0 +1,107 @@ +/* + * 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 __DC_STREAM_ENCODER_DCN20_H__ +#define __DC_STREAM_ENCODER_DCN20_H__ + +#include "stream_encoder.h" +#include "dcn10/dcn10_stream_encoder.h" + + +#define SE_DCN2_REG_LIST(id)\ + SE_COMMON_DCN_REG_LIST(id),\ + SRI(HDMI_GENERIC_PACKET_CONTROL4, DIG, id), \ + SRI(HDMI_GENERIC_PACKET_CONTROL5, DIG, id), \ + SRI(DP_DSC_CNTL, DP, id), \ + SRI(DP_DSC_BYTES_PER_PIXEL, DP, id), \ + SRI(DME_CONTROL, DIG, id),\ + SRI(DP_SEC_METADATA_TRANSMISSION, DP, id), \ + SRI(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ + SRI(DP_SEC_FRAMING4, DP, id) + +#define SE_COMMON_MASK_SH_LIST_DCN20(mask_sh)\ + SE_COMMON_MASK_SH_LIST_SOC(mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC0_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC1_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC2_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC3_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC4_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC5_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC6_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC7_LINE, mask_sh),\ + SE_SF(DP0_DP_DSC_CNTL, DP_DSC_MODE, mask_sh),\ + SE_SF(DP0_DP_DSC_CNTL, DP_DSC_SLICE_WIDTH, mask_sh),\ + SE_SF(DP0_DP_DSC_BYTES_PER_PIXEL, DP_DSC_BYTES_PER_PIXEL, mask_sh),\ + SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_REFERENCE, mask_sh),\ + SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_NUM, mask_sh),\ + SE_SF(DIG0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\ + SE_SF(DIG0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\ + SE_SF(DIG0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\ + SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_ENABLE, mask_sh),\ + SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE_REFERENCE, mask_sh),\ + SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE, mask_sh),\ + SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\ + SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\ + SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh),\ + SE_SF(DIG0_DIG_FE_CNTL, DOLBY_VISION_EN, mask_sh),\ + SE_SF(DP0_DP_PIXEL_FORMAT, DP_PIXEL_COMBINE, mask_sh),\ + SE_SF(DP0_DP_SEC_FRAMING4, DP_SST_SDP_SPLITTING, mask_sh) + +void dcn20_stream_encoder_construct( + struct dcn10_stream_encoder *enc1, + struct dc_context *ctx, + struct dc_bios *bp, + enum engine_id eng_id, + const struct dcn10_stream_enc_registers *regs, + const struct dcn10_stream_encoder_shift *se_shift, + const struct dcn10_stream_encoder_mask *se_mask); + +void enc2_stream_encoder_dp_set_stream_attribute( + struct stream_encoder *enc, + struct dc_crtc_timing *crtc_timing, + enum dc_color_space output_color_space, + uint32_t enable_sdp_splitting); + +void enc2_stream_encoder_dp_unblank( + struct stream_encoder *enc, + const struct encoder_unblank_param *param); + +#endif /* __DC_STREAM_ENCODER_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c new file mode 100644 index 000000000000..27679ef6ebe8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.c @@ -0,0 +1,59 @@ +/* + * 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 "dcn20_vmid.h" +#include "reg_helper.h" + +#define REG(reg)\ + vmid->regs->reg + +#define CTX \ + vmid->ctx + +#undef FN +#define FN(reg_name, field_name) \ + vmid->shifts->field_name, vmid->masks->field_name + +void dcn20_vmid_setup(struct dcn20_vmid *vmid, const struct dcn_vmid_page_table_config *config) +{ + REG_SET(PAGE_TABLE_START_ADDR_HI32, 0, + VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_HI4, (config->page_table_start_addr >> 32) & 0xF); + REG_SET(PAGE_TABLE_START_ADDR_LO32, 0, + VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_LO32, config->page_table_start_addr & 0xFFFFFFFF); + + REG_SET(PAGE_TABLE_END_ADDR_HI32, 0, + VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_HI4, (config->page_table_end_addr >> 32) & 0xF); + REG_SET(PAGE_TABLE_END_ADDR_LO32, 0, + VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_LO32, config->page_table_end_addr & 0xFFFFFFFF); + + REG_SET_2(CNTL, 0, + VM_CONTEXT0_PAGE_TABLE_DEPTH, config->depth, + VM_CONTEXT0_PAGE_TABLE_BLOCK_SIZE, config->block_size); + + REG_SET(PAGE_TABLE_BASE_ADDR_HI32, 0, + VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_HI32, (config->page_table_base_addr >> 32) & 0xFFFFFFFF); + REG_SET(PAGE_TABLE_BASE_ADDR_LO32, 0, + VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_LO32, config->page_table_base_addr & 0xFFFFFFFF); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h new file mode 100644 index 000000000000..02fafb013fc6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_vmid.h @@ -0,0 +1,90 @@ +/* + * 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 + * + */ + +#ifndef DAL_DC_DCN20_DCN20_VMID_H_ +#define DAL_DC_DCN20_DCN20_VMID_H_ + +#include "vmid.h" + +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#define BASE(seg) \ + BASE_INNER(seg) + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCN20_VMID_REG_LIST(id)\ + SRI(CNTL, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_BASE_ADDR_HI32, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_BASE_ADDR_LO32, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_START_ADDR_HI32, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_START_ADDR_LO32, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_END_ADDR_HI32, DCN_VM_CONTEXT, id),\ + SRI(PAGE_TABLE_END_ADDR_LO32, DCN_VM_CONTEXT, id) + +#define DCN20_VMID_MASK_SH_LIST(mask_sh)\ + SF(DCN_VM_CONTEXT0_CNTL, VM_CONTEXT0_PAGE_TABLE_DEPTH, mask_sh),\ + SF(DCN_VM_CONTEXT0_CNTL, VM_CONTEXT0_PAGE_TABLE_BLOCK_SIZE, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_LO32, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_HI4, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_LO32, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_HI4, mask_sh),\ + SF(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_LO32, mask_sh) + +#define DCN20_VMID_REG_FIELD_LIST(type)\ + type VM_CONTEXT0_PAGE_TABLE_DEPTH;\ + type VM_CONTEXT0_PAGE_TABLE_BLOCK_SIZE;\ + type VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_HI32;\ + type VM_CONTEXT0_PAGE_DIRECTORY_ENTRY_LO32;\ + type VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_HI4;\ + type VM_CONTEXT0_START_LOGICAL_PAGE_NUMBER_LO32;\ + type VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_HI4;\ + type VM_CONTEXT0_END_LOGICAL_PAGE_NUMBER_LO32 + +struct dcn20_vmid_shift { + DCN20_VMID_REG_FIELD_LIST(uint8_t); +}; + +struct dcn20_vmid_mask { + DCN20_VMID_REG_FIELD_LIST(uint32_t); +}; + +struct dcn20_vmid { + struct dc_context *ctx; + const struct dcn_vmid_registers *regs; + const struct dcn20_vmid_shift *shifts; + const struct dcn20_vmid_mask *masks; +}; + +void dcn20_vmid_setup(struct dcn20_vmid *vmid, const struct dcn_vmid_page_table_config *config); + +#endif /* DAL_DC_DCN20_DCN20_VMID_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index ccbfe9680d27..b6b4333737f2 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -118,6 +118,13 @@ bool dm_helpers_submit_i2c( const struct dc_link *link, struct i2c_command *cmd); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +bool dm_helpers_dp_write_dsc_enable( + struct dc_context *ctx, + const struct dc_stream_state *stream, + bool enable +); +#endif bool dm_helpers_is_dp_sink_present( struct dc_link *link); 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 471f3df88c92..680689cab5dd 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -41,6 +41,9 @@ enum pp_smu_ver { */ PP_SMU_UNSUPPORTED, PP_SMU_VER_RV, +#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 + PP_SMU_VER_NV, +#endif PP_SMU_VER_MAX }; @@ -64,7 +67,6 @@ enum pp_smu_status { PP_SMU_RESULT_UNSUPPORTED }; - #define PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN 0x0 #define PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX 0xFFFF @@ -138,10 +140,119 @@ struct pp_smu_funcs_rv { void (*set_pme_wa_enable)(struct pp_smu *pp); }; +#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 +/* Used by pp_smu_funcs_nv.set_voltage_by_freq + * + */ +enum pp_smu_nv_clock_id { + PP_SMU_NV_DISPCLK, + PP_SMU_NV_PHYCLK, + PP_SMU_NV_PIXELCLK +}; + +/* + * Used by pp_smu_funcs_nv.get_maximum_sustainable_clocks + */ +struct pp_smu_nv_clock_table { + // voltage managed SMU, freq set by driver + unsigned int displayClockInKhz; + unsigned int dppClockInKhz; + unsigned int phyClockInKhz; + unsigned int pixelClockInKhz; + unsigned int dscClockInKhz; + + // freq/voltage managed by SMU + unsigned int fabricClockInKhz; + unsigned int socClockInKhz; + unsigned int dcfClockInKhz; + unsigned int uClockInKhz; +}; + +struct pp_smu_funcs_nv { + struct pp_smu pp_smu; + + /* PPSMC_MSG_SetDisplayCount + * 0 triggers S0i2 optimization + */ + enum pp_smu_status (*set_display_count)(struct pp_smu *pp, int count); + + /* PPSMC_MSG_SetHardMinDcfclkByFreq + * fixed clock at requested freq, either from FCH bypass or DFS + */ + enum pp_smu_status (*set_hard_min_dcfclk_by_freq)(struct pp_smu *pp, int Mhz); + + /* PPSMC_MSG_SetMinDeepSleepDcfclk + * when DF is in cstate, dcf clock is further divided down + * to just above given frequency + */ + enum pp_smu_status (*set_min_deep_sleep_dcfclk)(struct pp_smu *pp, int Mhz); + + /* PPSMC_MSG_SetHardMinUclkByFreq + * UCLK will vary with DPM, but never below requested hard min + */ + enum pp_smu_status (*set_hard_min_uclk_by_freq)(struct pp_smu *pp, int Mhz); + + /* PPSMC_MSG_SetHardMinSocclkByFreq + * Needed for DWB support + */ + enum pp_smu_status (*set_hard_min_socclk_by_freq)(struct pp_smu *pp, int Mhz); + + /* PME w/a */ + enum pp_smu_status (*set_pme_wa_enable)(struct pp_smu *pp); + + /* PPSMC_MSG_SetHardMinByFreq + * Needed to set ASIC voltages for clocks programmed by DAL + */ + enum pp_smu_status (*set_voltage_by_freq)(struct pp_smu *pp, + enum pp_smu_nv_clock_id clock_id, int Mhz); + + /* reader and writer WM's are sent together as part of one table*/ + /* + * PPSMC_MSG_SetDriverDramAddrHigh + * PPSMC_MSG_SetDriverDramAddrLow + * PPSMC_MSG_TransferTableDram2Smu + * + * on DCN20: + * reader fill clk = uclk + * reader drain clk = dcfclk + * writer fill clk = socclk + * writer drain clk = uclk + * */ + enum pp_smu_status (*set_wm_ranges)(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges); + + /* Not a single SMU message. This call should return maximum sustainable limit for all + * clocks that DC depends on. These will be used as basis for mode enumeration. + */ + enum pp_smu_status (*get_maximum_sustainable_clocks)(struct pp_smu *pp, + struct pp_smu_nv_clock_table *max_clocks); + + /* This call should return the discrete uclk DPM states available + */ + enum pp_smu_status (*get_uclk_dpm_states)(struct pp_smu *pp, + unsigned int *clock_values_in_khz, unsigned int *num_states); + + /* Not a single SMU message. This call informs PPLIB that display will not be able + * to perform pstate handshaking in its current state. Typically this handshake + * is used to perform uCLK switching, so disabling pstate disables uCLK switching. + * + * Note that when setting handshake to unsupported, the call is pre-emptive. That means + * DC will make the call BEFORE setting up the display state which would cause pstate + * request to go un-acked. Only when the call completes should such a state be applied to + * DC hardware + */ + enum pp_smu_status (*set_pstate_handshake_support)(struct pp_smu *pp, + BOOLEAN pstate_handshake_supported); +}; +#endif + struct pp_smu_funcs { struct pp_smu ctx; union { struct pp_smu_funcs_rv rv_funcs; +#ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 + struct pp_smu_funcs_nv nv_funcs; +#endif }; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index d97ca6528f9d..0bb7a20675c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -33,7 +33,15 @@ endif dml_ccflags := -mhard-float -msse $(cc_stack_align) CFLAGS_display_mode_lib.o := $(dml_ccflags) -CFLAGS_display_pipe_clocks.o := $(dml_ccflags) + +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +CFLAGS_display_mode_vba.o := $(dml_ccflags) +CFLAGS_display_mode_vba_20.o := $(dml_ccflags) +CFLAGS_display_rq_dlg_calc_20.o := $(dml_ccflags) +endif +ifdef CONFIG_DRM_AMD_DCN3AG +CFLAGS_display_mode_vba_3ag.o := $(dml_ccflags) +endif CFLAGS_dml1_display_rq_dlg_calc.o := $(dml_ccflags) CFLAGS_display_rq_dlg_helpers.o := $(dml_ccflags) CFLAGS_dml_common_defs.o := $(dml_ccflags) @@ -41,6 +49,10 @@ CFLAGS_dml_common_defs.o := $(dml_ccflags) DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \ dml_common_defs.o +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +DML += display_mode_vba.o dcn20/display_rq_dlg_calc_20.o dcn20/display_mode_vba_20.o +endif + AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) AMD_DISPLAY_FILES += $(AMD_DAL_DML) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c new file mode 100644 index 000000000000..649883777f62 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.c @@ -0,0 +1,5104 @@ +/* + * 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 "../display_mode_lib.h" +#include "display_mode_vba_20.h" +#include "../dml_inline_defs.h" + +/* + * NOTE: + * This file is gcc-parseable HW gospel, coming straight from HW engineers. + * + * It doesn't adhere to Linux kernel style and sometimes will do things in odd + * ways. Unless there is something clearly wrong with it the code should + * remain as-is as it provides us with a guarantee from HW that it is correct. + */ + +#define BPP_INVALID 0 +#define BPP_BLENDED_PIPE 0xffffffff + +static double adjust_ReturnBW( + struct display_mode_lib *mode_lib, + double ReturnBW, + bool DCCEnabledAnyPlane, + double ReturnBandwidthToDCN); +static unsigned int dscceComputeDelay( + unsigned int bpc, + double bpp, + unsigned int sliceWidth, + unsigned int numSlices, + enum output_format_class pixelFormat); +static unsigned int dscComputeDelay(enum output_format_class pixelFormat); +// Super monster function with some 45 argument +static bool CalculatePrefetchSchedule( + struct display_mode_lib *mode_lib, + double DPPCLK, + double DISPCLK, + double PixelClock, + double DCFCLKDeepSleep, + unsigned int DSCDelay, + unsigned int DPPPerPlane, + bool ScalerEnabled, + unsigned int NumberOfCursors, + double DPPCLKDelaySubtotal, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCFormater, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int ScalerRecoutWidth, + enum output_format_class OutputFormat, + unsigned int VBlank, + unsigned int HTotal, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int PageTableLevels, + bool GPUVMEnable, + bool DynamicMetadataEnable, + unsigned int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + bool DCCEnable, + double UrgentLatencyPixelDataOnly, + double UrgentExtraLatency, + double TCalc, + unsigned int PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + double PrefetchSourceLinesY, + unsigned int SwathWidthY, + double BytePerPixelDETY, + double VInitPreFillY, + unsigned int MaxNumSwathY, + double PrefetchSourceLinesC, + double BytePerPixelDETC, + double VInitPreFillC, + unsigned int MaxNumSwathC, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double TWait, + bool XFCEnabled, + double XFCRemoteSurfaceFlipDelay, + bool InterlaceEnable, + bool ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBW, + unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + double *Tno_bw, + unsigned int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix); +static double RoundToDFSGranularityUp(double Clock, double VCOSpeed); +static double RoundToDFSGranularityDown(double Clock, double VCOSpeed); +static double CalculatePrefetchSourceLines( + struct display_mode_lib *mode_lib, + double VRatio, + double vtaps, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + unsigned int SwathHeight, + unsigned int ViewportYStart, + double *VInitPreFill, + unsigned int *MaxNumSwath); +static unsigned int CalculateVMAndRowBytes( + struct display_mode_lib *mode_lib, + bool DCCEnable, + unsigned int BlockHeight256Bytes, + unsigned int BlockWidth256Bytes, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceTiling, + unsigned int BytePerPixel, + enum scan_direction_class ScanDirection, + unsigned int ViewportWidth, + unsigned int ViewportHeight, + unsigned int SwathWidthY, + bool GPUVMEnable, + unsigned int VMMPageSize, + unsigned int PTEBufferSizeInRequestsLuma, + unsigned int PDEProcessingBufIn64KBReqs, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + unsigned int *dpte_row_height, + unsigned int *meta_row_height); +static double CalculateTWait( + unsigned int PrefetchMode, + double DRAMClockChangeLatency, + double UrgentLatencyPixelDataOnly, + double SREnterPlusExitTime); +static double CalculateRemoteSurfaceFlipDelay( + struct display_mode_lib *mode_lib, + double VRatio, + double SwathWidth, + double Bpp, + double LineTime, + double XFCTSlvVupdateOffset, + double XFCTSlvVupdateWidth, + double XFCTSlvVreadyOffset, + double XFCXBUFLatencyTolerance, + double XFCFillBWOverhead, + double XFCSlvChunkSize, + double XFCBusTransportTime, + double TCalc, + double TWait, + double *SrcActiveDrainRate, + double *TInitXFill, + double *TslvChk); +static void CalculateActiveRowBandwidth( + bool GPUVMEnable, + enum source_format_class SourcePixelFormat, + double VRatio, + bool DCCEnable, + double LineTime, + unsigned int MetaRowByteLuma, + unsigned int MetaRowByteChroma, + unsigned int meta_row_height_luma, + unsigned int meta_row_height_chroma, + unsigned int PixelPTEBytesPerRowLuma, + unsigned int PixelPTEBytesPerRowChroma, + unsigned int dpte_row_height_luma, + unsigned int dpte_row_height_chroma, + double *meta_row_bw, + double *dpte_row_bw, + double *qual_row_bw); +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double UrgentExtraLatency, + double UrgentLatencyPixelDataOnly, + unsigned int GPUVMMaxPageTableLevels, + bool GPUVMEnable, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + unsigned int ImmediateFlipBytes, + double LineTime, + double VRatio, + double Tno_bw, + double PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + double qual_row_bw, + double *DestinationLinesToRequestVMInImmediateFlip, + double *DestinationLinesToRequestRowInImmediateFlip, + double *final_flip_bw, + bool *ImmediateFlipSupportedForPipe); +static double CalculateWriteBackDelay( + enum source_format_class WritebackPixelFormat, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackLumaHTaps, + unsigned int WritebackLumaVTaps, + unsigned int WritebackChromaHTaps, + unsigned int WritebackChromaVTaps, + unsigned int WritebackDestinationWidth); + +static void dml20_DisplayPipeConfiguration(struct display_mode_lib *mode_lib); +static void dml20_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( + struct display_mode_lib *mode_lib); + +void dml20_recalculate(struct display_mode_lib *mode_lib) +{ + ModeSupportAndSystemConfiguration(mode_lib); + mode_lib->vba.FabricAndDRAMBandwidth = dml_min( + mode_lib->vba.DRAMSpeed * mode_lib->vba.NumberOfChannels * mode_lib->vba.DRAMChannelWidth, + mode_lib->vba.FabricClock * mode_lib->vba.FabricDatapathToDCNDataReturn) / 1000.0; + PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib); + dml20_DisplayPipeConfiguration(mode_lib); + dml20_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(mode_lib); +} + +static double adjust_ReturnBW( + struct display_mode_lib *mode_lib, + double ReturnBW, + bool DCCEnabledAnyPlane, + double ReturnBandwidthToDCN) +{ + double CriticalCompression; + + if (DCCEnabledAnyPlane + && ReturnBandwidthToDCN + > mode_lib->vba.DCFCLK * mode_lib->vba.ReturnBusWidth / 4.0) + ReturnBW = + dml_min( + ReturnBW, + ReturnBandwidthToDCN * 4 + * (1.0 + - mode_lib->vba.UrgentLatencyPixelDataOnly + / ((mode_lib->vba.ROBBufferSizeInKByte + - mode_lib->vba.PixelChunkSizeInKByte) + * 1024 + / ReturnBandwidthToDCN + - mode_lib->vba.DCFCLK + * mode_lib->vba.ReturnBusWidth + / 4) + + mode_lib->vba.UrgentLatencyPixelDataOnly)); + + CriticalCompression = 2.0 * mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK + * mode_lib->vba.UrgentLatencyPixelDataOnly + / (ReturnBandwidthToDCN * mode_lib->vba.UrgentLatencyPixelDataOnly + + (mode_lib->vba.ROBBufferSizeInKByte + - mode_lib->vba.PixelChunkSizeInKByte) + * 1024); + + if (DCCEnabledAnyPlane && CriticalCompression > 1.0 && CriticalCompression < 4.0) + ReturnBW = + dml_min( + ReturnBW, + 4.0 * ReturnBandwidthToDCN + * (mode_lib->vba.ROBBufferSizeInKByte + - mode_lib->vba.PixelChunkSizeInKByte) + * 1024 + * mode_lib->vba.ReturnBusWidth + * mode_lib->vba.DCFCLK + * mode_lib->vba.UrgentLatencyPixelDataOnly + / dml_pow( + (ReturnBandwidthToDCN + * mode_lib->vba.UrgentLatencyPixelDataOnly + + (mode_lib->vba.ROBBufferSizeInKByte + - mode_lib->vba.PixelChunkSizeInKByte) + * 1024), + 2)); + + return ReturnBW; +} + +static unsigned int dscceComputeDelay( + unsigned int bpc, + double bpp, + unsigned int sliceWidth, + unsigned int numSlices, + enum output_format_class pixelFormat) +{ + // valid bpc = source bits per component in the set of {8, 10, 12} + // valid bpp = increments of 1/16 of a bit + // min = 6/7/8 in N420/N422/444, respectively + // max = such that compression is 1:1 + //valid sliceWidth = number of pixels per slice line, must be less than or equal to 5184/numSlices (or 4096/numSlices in 420 mode) + //valid numSlices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4} + //valid pixelFormat = pixel/color format in the set of {:N444_RGB, :S422, :N422, :N420} + + // fixed value + unsigned int rcModelSize = 8192; + + // N422/N420 operate at 2 pixels per clock + unsigned int pixelsPerClock, lstall, D, initalXmitDelay, w, s, ix, wx, p, l0, a, ax, l, + Delay, pixels; + + if (pixelFormat == dm_n422 || pixelFormat == dm_420) + pixelsPerClock = 2; + // #all other modes operate at 1 pixel per clock + else + pixelsPerClock = 1; + + //initial transmit delay as per PPS + initalXmitDelay = dml_round(rcModelSize / 2.0 / bpp / pixelsPerClock); + + //compute ssm delay + if (bpc == 8) + D = 81; + else if (bpc == 10) + D = 89; + else + D = 113; + + //divide by pixel per cycle to compute slice width as seen by DSC + w = sliceWidth / pixelsPerClock; + + //422 mode has an additional cycle of delay + if (pixelFormat == dm_s422) + s = 1; + else + s = 0; + + //main calculation for the dscce + ix = initalXmitDelay + 45; + wx = (w + 2) / 3; + p = 3 * wx - w; + l0 = ix / w; + a = ix + p * l0; + ax = (a + 2) / 3 + D + 6 + 1; + l = (ax + wx - 1) / wx; + if ((ix % w) == 0 && p != 0) + lstall = 1; + else + lstall = 0; + Delay = l * wx * (numSlices - 1) + ax + s + lstall + 22; + + //dsc processes 3 pixel containers per cycle and a container can contain 1 or 2 pixels + pixels = Delay * 3 * pixelsPerClock; + return pixels; +} + +static unsigned int dscComputeDelay(enum output_format_class pixelFormat) +{ + unsigned int Delay = 0; + + if (pixelFormat == dm_420) { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 0; + // dscc - input deserializer + Delay = Delay + 3; + // dscc gets pixels every other cycle + Delay = Delay + 2; + // dscc - input cdc fifo + Delay = Delay + 12; + // dscc gets pixels every other cycle + Delay = Delay + 13; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 7; + // dscc gets pixels every other cycle + Delay = Delay + 3; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output serializer + Delay = Delay + 1; + // sft + Delay = Delay + 1; + } else if (pixelFormat == dm_n422) { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 1; + // dscc - input deserializer + Delay = Delay + 5; + // dscc - input cdc fifo + Delay = Delay + 25; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 10; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output serializer + Delay = Delay + 1; + // sft + Delay = Delay + 1; + } else { + // sfr + Delay = Delay + 2; + // dsccif + Delay = Delay + 0; + // dscc - input deserializer + Delay = Delay + 3; + // dscc - input cdc fifo + Delay = Delay + 12; + // dscc - cdc uncertainty + Delay = Delay + 2; + // dscc - output cdc fifo + Delay = Delay + 7; + // dscc - output serializer + Delay = Delay + 1; + // dscc - cdc uncertainty + Delay = Delay + 2; + // sft + Delay = Delay + 1; + } + + return Delay; +} + +static bool CalculatePrefetchSchedule( + struct display_mode_lib *mode_lib, + double DPPCLK, + double DISPCLK, + double PixelClock, + double DCFCLKDeepSleep, + unsigned int DSCDelay, + unsigned int DPPPerPlane, + bool ScalerEnabled, + unsigned int NumberOfCursors, + double DPPCLKDelaySubtotal, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCFormater, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int ScalerRecoutWidth, + enum output_format_class OutputFormat, + unsigned int VBlank, + unsigned int HTotal, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int PageTableLevels, + bool GPUVMEnable, + bool DynamicMetadataEnable, + unsigned int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + bool DCCEnable, + double UrgentLatencyPixelDataOnly, + double UrgentExtraLatency, + double TCalc, + unsigned int PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + double PrefetchSourceLinesY, + unsigned int SwathWidthY, + double BytePerPixelDETY, + double VInitPreFillY, + unsigned int MaxNumSwathY, + double PrefetchSourceLinesC, + double BytePerPixelDETC, + double VInitPreFillC, + unsigned int MaxNumSwathC, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double TWait, + bool XFCEnabled, + double XFCRemoteSurfaceFlipDelay, + bool InterlaceEnable, + bool ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBW, + unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + double *Tno_bw, + unsigned int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix) +{ + bool MyError = false; + unsigned int DPPCycles, DISPCLKCycles; + double DSTTotalPixelsAfterScaler, TotalRepeaterDelayTime; + double Tdm, LineTime, Tsetup; + double dst_y_prefetch_equ; + double Tsw_oto; + double prefetch_bw_oto; + double Tvm_oto; + double Tr0_oto; + double Tpre_oto; + double dst_y_prefetch_oto; + double TimeForFetchingMetaPTE = 0; + double TimeForFetchingRowInVBlank = 0; + double LinesToRequestPrefetchPixelData = 0; + + if (ScalerEnabled) + DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCL; + else + DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCLLBOnly; + + DPPCycles = DPPCycles + DPPCLKDelayCNVCFormater + NumberOfCursors * DPPCLKDelayCNVCCursor; + + DISPCLKCycles = DISPCLKDelaySubtotal; + + if (DPPCLK == 0.0 || DISPCLK == 0.0) + return true; + + *DSTXAfterScaler = DPPCycles * PixelClock / DPPCLK + DISPCLKCycles * PixelClock / DISPCLK + + DSCDelay; + + if (DPPPerPlane > 1) + *DSTXAfterScaler = *DSTXAfterScaler + ScalerRecoutWidth; + + if (OutputFormat == dm_420 || (InterlaceEnable && ProgressiveToInterlaceUnitInOPP)) + *DSTYAfterScaler = 1; + else + *DSTYAfterScaler = 0; + + DSTTotalPixelsAfterScaler = ((double) (*DSTYAfterScaler * HTotal)) + *DSTXAfterScaler; + *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / HTotal, 1); + *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * HTotal)); + + *VUpdateOffsetPix = dml_ceil(HTotal / 4.0, 1); + TotalRepeaterDelayTime = MaxInterDCNTileRepeaters * (2.0 / DPPCLK + 3.0 / DISPCLK); + *VUpdateWidthPix = (14.0 / DCFCLKDeepSleep + 12.0 / DPPCLK + TotalRepeaterDelayTime) + * PixelClock; + + *VReadyOffsetPix = dml_max( + 150.0 / DPPCLK, + TotalRepeaterDelayTime + 20.0 / DCFCLKDeepSleep + 10.0 / DPPCLK) + * PixelClock; + + Tsetup = (double) (*VUpdateOffsetPix + *VUpdateWidthPix + *VReadyOffsetPix) / PixelClock; + + LineTime = (double) HTotal / PixelClock; + + if (DynamicMetadataEnable) { + double Tdmbf, Tdmec, Tdmsks; + + Tdm = dml_max(0.0, UrgentExtraLatency - TCalc); + Tdmbf = DynamicMetadataTransmittedBytes / 4.0 / DISPCLK; + Tdmec = LineTime; + if (DynamicMetadataLinesBeforeActiveRequired == 0) + Tdmsks = VBlank * LineTime / 2.0; + else + Tdmsks = DynamicMetadataLinesBeforeActiveRequired * LineTime; + if (InterlaceEnable && !ProgressiveToInterlaceUnitInOPP) + Tdmsks = Tdmsks / 2; + if (VStartup * LineTime + < Tsetup + TWait + UrgentExtraLatency + Tdmbf + Tdmec + Tdmsks) { + MyError = true; + *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata = (Tsetup + TWait + + UrgentExtraLatency + Tdmbf + Tdmec + Tdmsks) / LineTime; + } else + *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata = 0.0; + } else + Tdm = 0; + + if (GPUVMEnable) { + if (PageTableLevels == 4) + *Tno_bw = UrgentExtraLatency + UrgentLatencyPixelDataOnly; + else if (PageTableLevels == 3) + *Tno_bw = UrgentExtraLatency; + else + *Tno_bw = 0; + } else if (DCCEnable) + *Tno_bw = LineTime; + else + *Tno_bw = LineTime / 4; + + dst_y_prefetch_equ = VStartup - dml_max(TCalc + TWait, XFCRemoteSurfaceFlipDelay) / LineTime + - (Tsetup + Tdm) / LineTime + - (*DSTYAfterScaler + *DSTXAfterScaler / HTotal); + + Tsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; + + prefetch_bw_oto = (MetaRowByte + PixelPTEBytesPerRow + + PrefetchSourceLinesY * SwathWidthY * dml_ceil(BytePerPixelDETY, 1) + + PrefetchSourceLinesC * SwathWidthY / 2 * dml_ceil(BytePerPixelDETC, 2)) + / Tsw_oto; + + if (GPUVMEnable == true) { + Tvm_oto = + dml_max( + *Tno_bw + PDEAndMetaPTEBytesFrame / prefetch_bw_oto, + dml_max( + UrgentExtraLatency + + UrgentLatencyPixelDataOnly + * (PageTableLevels + - 1), + LineTime / 4.0)); + } else + Tvm_oto = LineTime / 4.0; + + if ((GPUVMEnable == true || DCCEnable == true)) { + Tr0_oto = dml_max( + (MetaRowByte + PixelPTEBytesPerRow) / prefetch_bw_oto, + dml_max(UrgentLatencyPixelDataOnly, dml_max(LineTime - Tvm_oto, LineTime / 4))); + } else + Tr0_oto = LineTime - Tvm_oto; + + Tpre_oto = Tvm_oto + Tr0_oto + Tsw_oto; + + dst_y_prefetch_oto = Tpre_oto / LineTime; + + if (dst_y_prefetch_oto < dst_y_prefetch_equ) + *DestinationLinesForPrefetch = dst_y_prefetch_oto; + else + *DestinationLinesForPrefetch = dst_y_prefetch_equ; + + *DestinationLinesForPrefetch = dml_floor(4.0 * (*DestinationLinesForPrefetch + 0.125), 1) + / 4; + + dml_print("DML: VStartup: %d\n", VStartup); + dml_print("DML: TCalc: %f\n", TCalc); + dml_print("DML: TWait: %f\n", TWait); + dml_print("DML: XFCRemoteSurfaceFlipDelay: %f\n", XFCRemoteSurfaceFlipDelay); + dml_print("DML: LineTime: %f\n", LineTime); + dml_print("DML: Tsetup: %f\n", Tsetup); + dml_print("DML: Tdm: %f\n", Tdm); + dml_print("DML: DSTYAfterScaler: %f\n", *DSTYAfterScaler); + dml_print("DML: DSTXAfterScaler: %f\n", *DSTXAfterScaler); + dml_print("DML: HTotal: %d\n", HTotal); + + *PrefetchBandwidth = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBW = 0; + if (*DestinationLinesForPrefetch > 1) { + *PrefetchBandwidth = (PDEAndMetaPTEBytesFrame + 2 * MetaRowByte + + 2 * PixelPTEBytesPerRow + + PrefetchSourceLinesY * SwathWidthY * dml_ceil(BytePerPixelDETY, 1) + + PrefetchSourceLinesC * SwathWidthY / 2 + * dml_ceil(BytePerPixelDETC, 2)) + / (*DestinationLinesForPrefetch * LineTime - *Tno_bw); + if (GPUVMEnable) { + TimeForFetchingMetaPTE = + dml_max( + *Tno_bw + + (double) PDEAndMetaPTEBytesFrame + / *PrefetchBandwidth, + dml_max( + UrgentExtraLatency + + UrgentLatencyPixelDataOnly + * (PageTableLevels + - 1), + LineTime / 4)); + } else { + if (NumberOfCursors > 0 || XFCEnabled) + TimeForFetchingMetaPTE = LineTime / 4; + else + TimeForFetchingMetaPTE = 0.0; + } + + if ((GPUVMEnable == true || DCCEnable == true)) { + TimeForFetchingRowInVBlank = + dml_max( + (MetaRowByte + PixelPTEBytesPerRow) + / *PrefetchBandwidth, + dml_max( + UrgentLatencyPixelDataOnly, + dml_max( + LineTime + - TimeForFetchingMetaPTE, + LineTime + / 4.0))); + } else { + if (NumberOfCursors > 0 || XFCEnabled) + TimeForFetchingRowInVBlank = LineTime - TimeForFetchingMetaPTE; + else + TimeForFetchingRowInVBlank = 0.0; + } + + *DestinationLinesToRequestVMInVBlank = dml_floor( + 4.0 * (TimeForFetchingMetaPTE / LineTime + 0.125), + 1) / 4.0; + + *DestinationLinesToRequestRowInVBlank = dml_floor( + 4.0 * (TimeForFetchingRowInVBlank / LineTime + 0.125), + 1) / 4.0; + + LinesToRequestPrefetchPixelData = + *DestinationLinesForPrefetch + - ((NumberOfCursors > 0 || GPUVMEnable + || DCCEnable) ? + (*DestinationLinesToRequestVMInVBlank + + *DestinationLinesToRequestRowInVBlank) : + 0.0); + + if (LinesToRequestPrefetchPixelData > 0) { + + *VRatioPrefetchY = (double) PrefetchSourceLinesY + / LinesToRequestPrefetchPixelData; + *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); + if ((SwathHeightY > 4) && (VInitPreFillY > 3)) { + if (LinesToRequestPrefetchPixelData > (VInitPreFillY - 3.0) / 2.0) { + *VRatioPrefetchY = + dml_max( + (double) PrefetchSourceLinesY + / LinesToRequestPrefetchPixelData, + (double) MaxNumSwathY + * SwathHeightY + / (LinesToRequestPrefetchPixelData + - (VInitPreFillY + - 3.0) + / 2.0)); + *VRatioPrefetchY = dml_max(*VRatioPrefetchY, 1.0); + } else { + MyError = true; + *VRatioPrefetchY = 0; + } + } + + *VRatioPrefetchC = (double) PrefetchSourceLinesC + / LinesToRequestPrefetchPixelData; + *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); + + if ((SwathHeightC > 4)) { + if (LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) { + *VRatioPrefetchC = + dml_max( + *VRatioPrefetchC, + (double) MaxNumSwathC + * SwathHeightC + / (LinesToRequestPrefetchPixelData + - (VInitPreFillC + - 3.0) + / 2.0)); + *VRatioPrefetchC = dml_max(*VRatioPrefetchC, 1.0); + } else { + MyError = true; + *VRatioPrefetchC = 0; + } + } + + *RequiredPrefetchPixDataBW = + DPPPerPlane + * ((double) PrefetchSourceLinesY + / LinesToRequestPrefetchPixelData + * dml_ceil( + BytePerPixelDETY, + 1) + + (double) PrefetchSourceLinesC + / LinesToRequestPrefetchPixelData + * dml_ceil( + BytePerPixelDETC, + 2) + / 2) + * SwathWidthY / LineTime; + } else { + MyError = true; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBW = 0; + } + + } else { + MyError = true; + } + + if (MyError) { + *PrefetchBandwidth = 0; + TimeForFetchingMetaPTE = 0; + TimeForFetchingRowInVBlank = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *DestinationLinesForPrefetch = 0; + LinesToRequestPrefetchPixelData = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBW = 0; + } + + return MyError; +} + +static double RoundToDFSGranularityUp(double Clock, double VCOSpeed) +{ + return VCOSpeed * 4 / dml_floor(VCOSpeed * 4 / Clock, 1); +} + +static double RoundToDFSGranularityDown(double Clock, double VCOSpeed) +{ + return VCOSpeed * 4 / dml_ceil(VCOSpeed * 4 / Clock, 1); +} + +static double CalculatePrefetchSourceLines( + struct display_mode_lib *mode_lib, + double VRatio, + double vtaps, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + unsigned int SwathHeight, + unsigned int ViewportYStart, + double *VInitPreFill, + unsigned int *MaxNumSwath) +{ + unsigned int MaxPartialSwath; + + if (ProgressiveToInterlaceUnitInOPP) + *VInitPreFill = dml_floor((VRatio + vtaps + 1) / 2.0, 1); + else + *VInitPreFill = dml_floor((VRatio + vtaps + 1 + Interlace * 0.5 * VRatio) / 2.0, 1); + + if (!mode_lib->vba.IgnoreViewportPositioning) { + + *MaxNumSwath = dml_ceil((*VInitPreFill - 1.0) / SwathHeight, 1) + 1.0; + + if (*VInitPreFill > 1.0) + MaxPartialSwath = (unsigned int) (*VInitPreFill - 2) % SwathHeight; + else + MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 2) + % SwathHeight; + MaxPartialSwath = dml_max(1U, MaxPartialSwath); + + } else { + + if (ViewportYStart != 0) + dml_print( + "WARNING DML: using viewport y position of 0 even though actual viewport y position is non-zero in prefetch source lines calculation\n"); + + *MaxNumSwath = dml_ceil(*VInitPreFill / SwathHeight, 1); + + if (*VInitPreFill > 1.0) + MaxPartialSwath = (unsigned int) (*VInitPreFill - 1) % SwathHeight; + else + MaxPartialSwath = (unsigned int) (*VInitPreFill + SwathHeight - 1) + % SwathHeight; + } + + return *MaxNumSwath * SwathHeight + MaxPartialSwath; +} + +static unsigned int CalculateVMAndRowBytes( + struct display_mode_lib *mode_lib, + bool DCCEnable, + unsigned int BlockHeight256Bytes, + unsigned int BlockWidth256Bytes, + enum source_format_class SourcePixelFormat, + unsigned int SurfaceTiling, + unsigned int BytePerPixel, + enum scan_direction_class ScanDirection, + unsigned int ViewportWidth, + unsigned int ViewportHeight, + unsigned int SwathWidth, + bool GPUVMEnable, + unsigned int VMMPageSize, + unsigned int PTEBufferSizeInRequestsLuma, + unsigned int PDEProcessingBufIn64KBReqs, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + unsigned int *dpte_row_height, + unsigned int *meta_row_height) +{ + unsigned int MetaRequestHeight; + unsigned int MetaRequestWidth; + unsigned int MetaSurfWidth; + unsigned int MetaSurfHeight; + unsigned int MPDEBytesFrame; + unsigned int MetaPTEBytesFrame; + unsigned int DCCMetaSurfaceBytes; + + unsigned int MacroTileSizeBytes; + unsigned int MacroTileHeight; + unsigned int DPDE0BytesFrame; + unsigned int ExtraDPDEBytesFrame; + unsigned int PDEAndMetaPTEBytesFrame; + + if (DCCEnable == true) { + MetaRequestHeight = 8 * BlockHeight256Bytes; + MetaRequestWidth = 8 * BlockWidth256Bytes; + if (ScanDirection == dm_horz) { + *meta_row_height = MetaRequestHeight; + MetaSurfWidth = dml_ceil((double) SwathWidth - 1, MetaRequestWidth) + + MetaRequestWidth; + *MetaRowByte = MetaSurfWidth * MetaRequestHeight * BytePerPixel / 256.0; + } else { + *meta_row_height = MetaRequestWidth; + MetaSurfHeight = dml_ceil((double) SwathWidth - 1, MetaRequestHeight) + + MetaRequestHeight; + *MetaRowByte = MetaSurfHeight * MetaRequestWidth * BytePerPixel / 256.0; + } + if (ScanDirection == dm_horz) { + DCCMetaSurfaceBytes = DCCMetaPitch + * (dml_ceil(ViewportHeight - 1, 64 * BlockHeight256Bytes) + + 64 * BlockHeight256Bytes) * BytePerPixel + / 256; + } else { + DCCMetaSurfaceBytes = DCCMetaPitch + * (dml_ceil( + (double) ViewportHeight - 1, + 64 * BlockHeight256Bytes) + + 64 * BlockHeight256Bytes) * BytePerPixel + / 256; + } + if (GPUVMEnable == true) { + MetaPTEBytesFrame = (dml_ceil( + (double) (DCCMetaSurfaceBytes - VMMPageSize) + / (8 * VMMPageSize), + 1) + 1) * 64; + MPDEBytesFrame = 128 * (mode_lib->vba.GPUVMMaxPageTableLevels - 1); + } else { + MetaPTEBytesFrame = 0; + MPDEBytesFrame = 0; + } + } else { + MetaPTEBytesFrame = 0; + MPDEBytesFrame = 0; + *MetaRowByte = 0; + } + + if (SurfaceTiling == dm_sw_linear || SurfaceTiling == dm_sw_gfx7_2d_thin_gl || SurfaceTiling == dm_sw_gfx7_2d_thin_lvp) { + MacroTileSizeBytes = 256; + MacroTileHeight = BlockHeight256Bytes; + } else if (SurfaceTiling == dm_sw_4kb_s || SurfaceTiling == dm_sw_4kb_s_x + || SurfaceTiling == dm_sw_4kb_d || SurfaceTiling == dm_sw_4kb_d_x) { + MacroTileSizeBytes = 4096; + MacroTileHeight = 4 * BlockHeight256Bytes; + } else if (SurfaceTiling == dm_sw_64kb_s || SurfaceTiling == dm_sw_64kb_s_t + || SurfaceTiling == dm_sw_64kb_s_x || SurfaceTiling == dm_sw_64kb_d + || SurfaceTiling == dm_sw_64kb_d_t || SurfaceTiling == dm_sw_64kb_d_x + || SurfaceTiling == dm_sw_64kb_r_x) { + MacroTileSizeBytes = 65536; + MacroTileHeight = 16 * BlockHeight256Bytes; + } else { + MacroTileSizeBytes = 262144; + MacroTileHeight = 32 * BlockHeight256Bytes; + } + *MacroTileWidth = MacroTileSizeBytes / BytePerPixel / MacroTileHeight; + + if (GPUVMEnable == true && mode_lib->vba.GPUVMMaxPageTableLevels > 1) { + if (ScanDirection == dm_horz) { + DPDE0BytesFrame = + 64 + * (dml_ceil( + ((Pitch + * (dml_ceil( + ViewportHeight + - 1, + MacroTileHeight) + + MacroTileHeight) + * BytePerPixel) + - MacroTileSizeBytes) + / (8 + * 2097152), + 1) + 1); + } else { + DPDE0BytesFrame = + 64 + * (dml_ceil( + ((Pitch + * (dml_ceil( + (double) SwathWidth + - 1, + MacroTileHeight) + + MacroTileHeight) + * BytePerPixel) + - MacroTileSizeBytes) + / (8 + * 2097152), + 1) + 1); + } + ExtraDPDEBytesFrame = 128 * (mode_lib->vba.GPUVMMaxPageTableLevels - 2); + } else { + DPDE0BytesFrame = 0; + ExtraDPDEBytesFrame = 0; + } + + PDEAndMetaPTEBytesFrame = MetaPTEBytesFrame + MPDEBytesFrame + DPDE0BytesFrame + + ExtraDPDEBytesFrame; + + if (GPUVMEnable == true) { + unsigned int PTERequestSize; + unsigned int PixelPTEReqHeight; + unsigned int PixelPTEReqWidth; + double FractionOfPTEReturnDrop; + unsigned int EffectivePDEProcessingBufIn64KBReqs; + + if (SurfaceTiling == dm_sw_linear) { + PixelPTEReqHeight = 1; + PixelPTEReqWidth = 8.0 * VMMPageSize / BytePerPixel; + PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } else if (MacroTileSizeBytes == 4096) { + PixelPTEReqHeight = MacroTileHeight; + PixelPTEReqWidth = 8 * *MacroTileWidth; + PTERequestSize = 64; + if (ScanDirection == dm_horz) + FractionOfPTEReturnDrop = 0; + else + FractionOfPTEReturnDrop = 7 / 8; + } else if (VMMPageSize == 4096 && MacroTileSizeBytes > 4096) { + PixelPTEReqHeight = 16 * BlockHeight256Bytes; + PixelPTEReqWidth = 16 * BlockWidth256Bytes; + PTERequestSize = 128; + FractionOfPTEReturnDrop = 0; + } else { + PixelPTEReqHeight = MacroTileHeight; + PixelPTEReqWidth = 8 * *MacroTileWidth; + PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } + + if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) + EffectivePDEProcessingBufIn64KBReqs = PDEProcessingBufIn64KBReqs / 2; + else + EffectivePDEProcessingBufIn64KBReqs = PDEProcessingBufIn64KBReqs; + + if (SurfaceTiling == dm_sw_linear) { + *dpte_row_height = + dml_min( + 128, + 1 + << (unsigned int) dml_floor( + dml_log2( + dml_min( + (double) PTEBufferSizeInRequestsLuma + * PixelPTEReqWidth, + EffectivePDEProcessingBufIn64KBReqs + * 65536.0 + / BytePerPixel) + / Pitch), + 1)); + *PixelPTEBytesPerRow = PTERequestSize + * (dml_ceil( + (double) (Pitch * *dpte_row_height - 1) + / PixelPTEReqWidth, + 1) + 1); + } else if (ScanDirection == dm_horz) { + *dpte_row_height = PixelPTEReqHeight; + *PixelPTEBytesPerRow = PTERequestSize + * (dml_ceil(((double) SwathWidth - 1) / PixelPTEReqWidth, 1) + + 1); + } else { + *dpte_row_height = dml_min(PixelPTEReqWidth, *MacroTileWidth); + *PixelPTEBytesPerRow = PTERequestSize + * (dml_ceil( + ((double) SwathWidth - 1) + / PixelPTEReqHeight, + 1) + 1); + } + if (*PixelPTEBytesPerRow * (1 - FractionOfPTEReturnDrop) + <= 64 * PTEBufferSizeInRequestsLuma) { + *PTEBufferSizeNotExceeded = true; + } else { + *PTEBufferSizeNotExceeded = false; + } + } else { + *PixelPTEBytesPerRow = 0; + *PTEBufferSizeNotExceeded = true; + } + + return PDEAndMetaPTEBytesFrame; +} + +static void dml20_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( + struct display_mode_lib *mode_lib) +{ + unsigned int j, k; + + mode_lib->vba.WritebackDISPCLK = 0.0; + mode_lib->vba.DISPCLKWithRamping = 0; + mode_lib->vba.DISPCLKWithoutRamping = 0; + mode_lib->vba.GlobalDPPCLK = 0.0; + + // dml_ml->vba.DISPCLK and dml_ml->vba.DPPCLK Calculation + // + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.WritebackEnable[k]) { + mode_lib->vba.WritebackDISPCLK = + dml_max( + mode_lib->vba.WritebackDISPCLK, + CalculateWriteBackDISPCLK( + mode_lib->vba.WritebackPixelFormat[k], + mode_lib->vba.PixelClock[k], + mode_lib->vba.WritebackHRatio[k], + mode_lib->vba.WritebackVRatio[k], + mode_lib->vba.WritebackLumaHTaps[k], + mode_lib->vba.WritebackLumaVTaps[k], + mode_lib->vba.WritebackChromaHTaps[k], + mode_lib->vba.WritebackChromaVTaps[k], + mode_lib->vba.WritebackDestinationWidth[k], + mode_lib->vba.HTotal[k], + mode_lib->vba.WritebackChromaLineBufferWidth)); + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.HRatio[k] > 1) { + mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput + * mode_lib->vba.HRatio[k] + / dml_ceil( + mode_lib->vba.htaps[k] + / 6.0, + 1)); + } else { + mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput); + } + + mode_lib->vba.DPPCLKUsingSingleDPPLuma = + mode_lib->vba.PixelClock[k] + * dml_max( + mode_lib->vba.vtaps[k] / 6.0 + * dml_min( + 1.0, + mode_lib->vba.HRatio[k]), + dml_max( + mode_lib->vba.HRatio[k] + * mode_lib->vba.VRatio[k] + / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k], + 1.0)); + + if ((mode_lib->vba.htaps[k] > 6 || mode_lib->vba.vtaps[k] > 6) + && mode_lib->vba.DPPCLKUsingSingleDPPLuma + < 2 * mode_lib->vba.PixelClock[k]) { + mode_lib->vba.DPPCLKUsingSingleDPPLuma = 2 * mode_lib->vba.PixelClock[k]; + } + + if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 + && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { + mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = 0.0; + mode_lib->vba.DPPCLKUsingSingleDPP[k] = + mode_lib->vba.DPPCLKUsingSingleDPPLuma; + } else { + if (mode_lib->vba.HRatio[k] > 1) { + mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = + dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput + * mode_lib->vba.HRatio[k] + / 2 + / dml_ceil( + mode_lib->vba.HTAPsChroma[k] + / 6.0, + 1.0)); + } else { + mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput); + } + mode_lib->vba.DPPCLKUsingSingleDPPChroma = + mode_lib->vba.PixelClock[k] + * dml_max( + mode_lib->vba.VTAPsChroma[k] + / 6.0 + * dml_min( + 1.0, + mode_lib->vba.HRatio[k] + / 2), + dml_max( + mode_lib->vba.HRatio[k] + * mode_lib->vba.VRatio[k] + / 4 + / mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k], + 1.0)); + + if ((mode_lib->vba.HTAPsChroma[k] > 6 || mode_lib->vba.VTAPsChroma[k] > 6) + && mode_lib->vba.DPPCLKUsingSingleDPPChroma + < 2 * mode_lib->vba.PixelClock[k]) { + mode_lib->vba.DPPCLKUsingSingleDPPChroma = 2 + * mode_lib->vba.PixelClock[k]; + } + + mode_lib->vba.DPPCLKUsingSingleDPP[k] = dml_max( + mode_lib->vba.DPPCLKUsingSingleDPPLuma, + mode_lib->vba.DPPCLKUsingSingleDPPChroma); + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.BlendingAndTiming[k] != k) + continue; + if (mode_lib->vba.ODMCombineEnabled[k]) { + mode_lib->vba.DISPCLKWithRamping = + dml_max( + mode_lib->vba.DISPCLKWithRamping, + mode_lib->vba.PixelClock[k] / 2 + * (1 + + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100) + * (1 + + mode_lib->vba.DISPCLKRampingMargin + / 100)); + mode_lib->vba.DISPCLKWithoutRamping = + dml_max( + mode_lib->vba.DISPCLKWithoutRamping, + mode_lib->vba.PixelClock[k] / 2 + * (1 + + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100)); + } else if (!mode_lib->vba.ODMCombineEnabled[k]) { + mode_lib->vba.DISPCLKWithRamping = + dml_max( + mode_lib->vba.DISPCLKWithRamping, + mode_lib->vba.PixelClock[k] + * (1 + + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100) + * (1 + + mode_lib->vba.DISPCLKRampingMargin + / 100)); + mode_lib->vba.DISPCLKWithoutRamping = + dml_max( + mode_lib->vba.DISPCLKWithoutRamping, + mode_lib->vba.PixelClock[k] + * (1 + + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100)); + } + } + + mode_lib->vba.DISPCLKWithRamping = dml_max( + mode_lib->vba.DISPCLKWithRamping, + mode_lib->vba.WritebackDISPCLK); + mode_lib->vba.DISPCLKWithoutRamping = dml_max( + mode_lib->vba.DISPCLKWithoutRamping, + mode_lib->vba.WritebackDISPCLK); + + ASSERT(mode_lib->vba.DISPCLKDPPCLKVCOSpeed != 0); + mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity = RoundToDFSGranularityUp( + mode_lib->vba.DISPCLKWithRamping, + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity = RoundToDFSGranularityUp( + mode_lib->vba.DISPCLKWithoutRamping, + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + mode_lib->vba.MaxDispclkRoundedToDFSGranularity = RoundToDFSGranularityDown( + mode_lib->vba.soc.clock_limits[mode_lib->vba.soc.num_states].dispclk_mhz, + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + if (mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity + > mode_lib->vba.MaxDispclkRoundedToDFSGranularity) { + mode_lib->vba.DISPCLK_calculated = + mode_lib->vba.DISPCLKWithoutRampingRoundedToDFSGranularity; + } else if (mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity + > mode_lib->vba.MaxDispclkRoundedToDFSGranularity) { + mode_lib->vba.DISPCLK_calculated = mode_lib->vba.MaxDispclkRoundedToDFSGranularity; + } else { + mode_lib->vba.DISPCLK_calculated = + mode_lib->vba.DISPCLKWithRampingRoundedToDFSGranularity; + } + DTRACE(" dispclk_mhz (calculated) = %f", mode_lib->vba.DISPCLK_calculated); + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.DPPPerPlane[k] == 0) { + mode_lib->vba.DPPCLK_calculated[k] = 0; + } else { + mode_lib->vba.DPPCLK_calculated[k] = mode_lib->vba.DPPCLKUsingSingleDPP[k] + / mode_lib->vba.DPPPerPlane[k] + * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100); + } + mode_lib->vba.GlobalDPPCLK = dml_max( + mode_lib->vba.GlobalDPPCLK, + mode_lib->vba.DPPCLK_calculated[k]); + } + mode_lib->vba.GlobalDPPCLK = RoundToDFSGranularityUp( + mode_lib->vba.GlobalDPPCLK, + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.DPPCLK_calculated[k] = mode_lib->vba.GlobalDPPCLK / 255 + * dml_ceil( + mode_lib->vba.DPPCLK_calculated[k] * 255 + / mode_lib->vba.GlobalDPPCLK, + 1); + DTRACE(" dppclk_mhz[%i] (calculated) = %f", k, mode_lib->vba.DPPCLK_calculated[k]); + } + + // Urgent Watermark + mode_lib->vba.DCCEnabledAnyPlane = false; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + if (mode_lib->vba.DCCEnable[k]) + mode_lib->vba.DCCEnabledAnyPlane = true; + + mode_lib->vba.ReturnBandwidthToDCN = dml_min( + mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK, + mode_lib->vba.FabricAndDRAMBandwidth * 1000) + * mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelDataOnly / 100; + + mode_lib->vba.ReturnBW = mode_lib->vba.ReturnBandwidthToDCN; + mode_lib->vba.ReturnBW = adjust_ReturnBW( + mode_lib, + mode_lib->vba.ReturnBW, + mode_lib->vba.DCCEnabledAnyPlane, + mode_lib->vba.ReturnBandwidthToDCN); + + // Let's do this calculation again?? + mode_lib->vba.ReturnBandwidthToDCN = dml_min( + mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLK, + mode_lib->vba.FabricAndDRAMBandwidth * 1000); + mode_lib->vba.ReturnBW = adjust_ReturnBW( + mode_lib, + mode_lib->vba.ReturnBW, + mode_lib->vba.DCCEnabledAnyPlane, + mode_lib->vba.ReturnBandwidthToDCN); + + DTRACE(" dcfclk_mhz = %f", mode_lib->vba.DCFCLK); + DTRACE(" return_bw_to_dcn = %f", mode_lib->vba.ReturnBandwidthToDCN); + DTRACE(" return_bus_bw = %f", mode_lib->vba.ReturnBW); + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + bool MainPlaneDoesODMCombine = false; + + if (mode_lib->vba.SourceScan[k] == dm_horz) + mode_lib->vba.SwathWidthSingleDPPY[k] = mode_lib->vba.ViewportWidth[k]; + else + mode_lib->vba.SwathWidthSingleDPPY[k] = mode_lib->vba.ViewportHeight[k]; + + if (mode_lib->vba.ODMCombineEnabled[k] == true) + MainPlaneDoesODMCombine = true; + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) + if (mode_lib->vba.BlendingAndTiming[k] == j + && mode_lib->vba.ODMCombineEnabled[j] == true) + MainPlaneDoesODMCombine = true; + + if (MainPlaneDoesODMCombine == true) + mode_lib->vba.SwathWidthY[k] = dml_min( + (double) mode_lib->vba.SwathWidthSingleDPPY[k], + dml_round( + mode_lib->vba.HActive[k] / 2.0 + * mode_lib->vba.HRatio[k])); + else { + if (mode_lib->vba.DPPPerPlane[k] == 0) { + mode_lib->vba.SwathWidthY[k] = 0; + } else { + mode_lib->vba.SwathWidthY[k] = mode_lib->vba.SwathWidthSingleDPPY[k] + / mode_lib->vba.DPPPerPlane[k]; + } + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { + mode_lib->vba.BytePerPixelDETY[k] = 8; + mode_lib->vba.BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { + mode_lib->vba.BytePerPixelDETY[k] = 4; + mode_lib->vba.BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { + mode_lib->vba.BytePerPixelDETY[k] = 2; + mode_lib->vba.BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8) { + mode_lib->vba.BytePerPixelDETY[k] = 1; + mode_lib->vba.BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { + mode_lib->vba.BytePerPixelDETY[k] = 1; + mode_lib->vba.BytePerPixelDETC[k] = 2; + } else { // dm_420_10 + mode_lib->vba.BytePerPixelDETY[k] = 4.0 / 3.0; + mode_lib->vba.BytePerPixelDETC[k] = 8.0 / 3.0; + } + } + + mode_lib->vba.TotalDataReadBandwidth = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.ReadBandwidthPlaneLuma[k] = mode_lib->vba.SwathWidthSingleDPPY[k] + * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + * mode_lib->vba.VRatio[k]; + mode_lib->vba.ReadBandwidthPlaneChroma[k] = mode_lib->vba.SwathWidthSingleDPPY[k] + / 2 * dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2) + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + * mode_lib->vba.VRatio[k] / 2; + DTRACE( + " read_bw[%i] = %fBps", + k, + mode_lib->vba.ReadBandwidthPlaneLuma[k] + + mode_lib->vba.ReadBandwidthPlaneChroma[k]); + mode_lib->vba.TotalDataReadBandwidth += mode_lib->vba.ReadBandwidthPlaneLuma[k] + + mode_lib->vba.ReadBandwidthPlaneChroma[k]; + } + + mode_lib->vba.TotalDCCActiveDPP = 0; + mode_lib->vba.TotalActiveDPP = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP + + mode_lib->vba.DPPPerPlane[k]; + if (mode_lib->vba.DCCEnable[k]) + mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP + + mode_lib->vba.DPPPerPlane[k]; + } + + mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency = + (mode_lib->vba.RoundTripPingLatencyCycles + 32) / mode_lib->vba.DCFCLK + + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelDataOnly + * mode_lib->vba.NumberOfChannels + / mode_lib->vba.ReturnBW; + + mode_lib->vba.LastPixelOfLineExtraWatermark = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + double DataFabricLineDeliveryTimeLuma, DataFabricLineDeliveryTimeChroma; + + if (mode_lib->vba.VRatio[k] <= 1.0) + mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k] = + (double) mode_lib->vba.SwathWidthY[k] + * mode_lib->vba.DPPPerPlane[k] + / mode_lib->vba.HRatio[k] + / mode_lib->vba.PixelClock[k]; + else + mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k] = + (double) mode_lib->vba.SwathWidthY[k] + / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] + / mode_lib->vba.DPPCLK[k]; + + DataFabricLineDeliveryTimeLuma = mode_lib->vba.SwathWidthSingleDPPY[k] + * mode_lib->vba.SwathHeightY[k] + * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) + / (mode_lib->vba.ReturnBW * mode_lib->vba.ReadBandwidthPlaneLuma[k] + / mode_lib->vba.TotalDataReadBandwidth); + mode_lib->vba.LastPixelOfLineExtraWatermark = dml_max( + mode_lib->vba.LastPixelOfLineExtraWatermark, + DataFabricLineDeliveryTimeLuma + - mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k]); + + if (mode_lib->vba.BytePerPixelDETC[k] == 0) + mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = 0.0; + else if (mode_lib->vba.VRatio[k] / 2.0 <= 1.0) + mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = + mode_lib->vba.SwathWidthY[k] / 2.0 + * mode_lib->vba.DPPPerPlane[k] + / (mode_lib->vba.HRatio[k] / 2.0) + / mode_lib->vba.PixelClock[k]; + else + mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k] = + mode_lib->vba.SwathWidthY[k] / 2.0 + / mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] + / mode_lib->vba.DPPCLK[k]; + + DataFabricLineDeliveryTimeChroma = mode_lib->vba.SwathWidthSingleDPPY[k] / 2.0 + * mode_lib->vba.SwathHeightC[k] + * dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2) + / (mode_lib->vba.ReturnBW + * mode_lib->vba.ReadBandwidthPlaneChroma[k] + / mode_lib->vba.TotalDataReadBandwidth); + mode_lib->vba.LastPixelOfLineExtraWatermark = + dml_max( + mode_lib->vba.LastPixelOfLineExtraWatermark, + DataFabricLineDeliveryTimeChroma + - mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k]); + } + + mode_lib->vba.UrgentExtraLatency = mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency + + (mode_lib->vba.TotalActiveDPP * mode_lib->vba.PixelChunkSizeInKByte + + mode_lib->vba.TotalDCCActiveDPP + * mode_lib->vba.MetaChunkSize) * 1024.0 + / mode_lib->vba.ReturnBW; + + if (mode_lib->vba.GPUVMEnable) + mode_lib->vba.UrgentExtraLatency += mode_lib->vba.TotalActiveDPP + * mode_lib->vba.PTEGroupSize / mode_lib->vba.ReturnBW; + + mode_lib->vba.UrgentWatermark = mode_lib->vba.UrgentLatencyPixelDataOnly + + mode_lib->vba.LastPixelOfLineExtraWatermark + + mode_lib->vba.UrgentExtraLatency; + + DTRACE(" urgent_extra_latency = %fus", mode_lib->vba.UrgentExtraLatency); + DTRACE(" wm_urgent = %fus", mode_lib->vba.UrgentWatermark); + + mode_lib->vba.UrgentLatency = mode_lib->vba.UrgentLatencyPixelDataOnly; + + mode_lib->vba.TotalActiveWriteback = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.WritebackEnable[k]) + mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + mode_lib->vba.ActiveWritebacksPerPlane[k]; + } + + if (mode_lib->vba.TotalActiveWriteback <= 1) + mode_lib->vba.WritebackUrgentWatermark = mode_lib->vba.WritebackLatency; + else + mode_lib->vba.WritebackUrgentWatermark = mode_lib->vba.WritebackLatency + + mode_lib->vba.WritebackChunkSize * 1024.0 / 32 + / mode_lib->vba.SOCCLK; + + DTRACE(" wm_wb_urgent = %fus", mode_lib->vba.WritebackUrgentWatermark); + + // NB P-State/DRAM Clock Change Watermark + mode_lib->vba.DRAMClockChangeWatermark = mode_lib->vba.DRAMClockChangeLatency + + mode_lib->vba.UrgentWatermark; + + DTRACE(" wm_pstate_change = %fus", mode_lib->vba.DRAMClockChangeWatermark); + + DTRACE(" calculating wb pstate watermark"); + DTRACE(" total wb outputs %d", mode_lib->vba.TotalActiveWriteback); + DTRACE(" socclk frequency %f Mhz", mode_lib->vba.SOCCLK); + + if (mode_lib->vba.TotalActiveWriteback <= 1) + mode_lib->vba.WritebackDRAMClockChangeWatermark = + mode_lib->vba.DRAMClockChangeLatency + + mode_lib->vba.WritebackLatency; + else + mode_lib->vba.WritebackDRAMClockChangeWatermark = + mode_lib->vba.DRAMClockChangeLatency + + mode_lib->vba.WritebackLatency + + mode_lib->vba.WritebackChunkSize * 1024.0 / 32 + / mode_lib->vba.SOCCLK; + + DTRACE(" wm_wb_pstate %fus", mode_lib->vba.WritebackDRAMClockChangeWatermark); + + // Stutter Efficiency + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.LinesInDETY[k] = mode_lib->vba.DETBufferSizeY[k] + / mode_lib->vba.BytePerPixelDETY[k] / mode_lib->vba.SwathWidthY[k]; + mode_lib->vba.LinesInDETYRoundedDownToSwath[k] = dml_floor( + mode_lib->vba.LinesInDETY[k], + mode_lib->vba.SwathHeightY[k]); + mode_lib->vba.FullDETBufferingTimeY[k] = + mode_lib->vba.LinesInDETYRoundedDownToSwath[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + / mode_lib->vba.VRatio[k]; + if (mode_lib->vba.BytePerPixelDETC[k] > 0) { + mode_lib->vba.LinesInDETC[k] = mode_lib->vba.DETBufferSizeC[k] + / mode_lib->vba.BytePerPixelDETC[k] + / (mode_lib->vba.SwathWidthY[k] / 2); + mode_lib->vba.LinesInDETCRoundedDownToSwath[k] = dml_floor( + mode_lib->vba.LinesInDETC[k], + mode_lib->vba.SwathHeightC[k]); + mode_lib->vba.FullDETBufferingTimeC[k] = + mode_lib->vba.LinesInDETCRoundedDownToSwath[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + / (mode_lib->vba.VRatio[k] / 2); + } else { + mode_lib->vba.LinesInDETC[k] = 0; + mode_lib->vba.LinesInDETCRoundedDownToSwath[k] = 0; + mode_lib->vba.FullDETBufferingTimeC[k] = 999999; + } + } + + mode_lib->vba.MinFullDETBufferingTime = 999999.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.FullDETBufferingTimeY[k] + < mode_lib->vba.MinFullDETBufferingTime) { + mode_lib->vba.MinFullDETBufferingTime = + mode_lib->vba.FullDETBufferingTimeY[k]; + mode_lib->vba.FrameTimeForMinFullDETBufferingTime = + (double) mode_lib->vba.VTotal[k] * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + } + if (mode_lib->vba.FullDETBufferingTimeC[k] + < mode_lib->vba.MinFullDETBufferingTime) { + mode_lib->vba.MinFullDETBufferingTime = + mode_lib->vba.FullDETBufferingTimeC[k]; + mode_lib->vba.FrameTimeForMinFullDETBufferingTime = + (double) mode_lib->vba.VTotal[k] * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + } + } + + mode_lib->vba.AverageReadBandwidthGBytePerSecond = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.DCCEnable[k]) { + mode_lib->vba.AverageReadBandwidthGBytePerSecond = + mode_lib->vba.AverageReadBandwidthGBytePerSecond + + mode_lib->vba.ReadBandwidthPlaneLuma[k] + / mode_lib->vba.DCCRate[k] + / 1000 + + mode_lib->vba.ReadBandwidthPlaneChroma[k] + / mode_lib->vba.DCCRate[k] + / 1000; + } else { + mode_lib->vba.AverageReadBandwidthGBytePerSecond = + mode_lib->vba.AverageReadBandwidthGBytePerSecond + + mode_lib->vba.ReadBandwidthPlaneLuma[k] + / 1000 + + mode_lib->vba.ReadBandwidthPlaneChroma[k] + / 1000; + } + if (mode_lib->vba.DCCEnable[k]) { + mode_lib->vba.AverageReadBandwidthGBytePerSecond = + mode_lib->vba.AverageReadBandwidthGBytePerSecond + + mode_lib->vba.ReadBandwidthPlaneLuma[k] + / 1000 / 256 + + mode_lib->vba.ReadBandwidthPlaneChroma[k] + / 1000 / 256; + } + if (mode_lib->vba.GPUVMEnable) { + mode_lib->vba.AverageReadBandwidthGBytePerSecond = + mode_lib->vba.AverageReadBandwidthGBytePerSecond + + mode_lib->vba.ReadBandwidthPlaneLuma[k] + / 1000 / 512 + + mode_lib->vba.ReadBandwidthPlaneChroma[k] + / 1000 / 512; + } + } + + mode_lib->vba.PartOfBurstThatFitsInROB = + dml_min( + mode_lib->vba.MinFullDETBufferingTime + * mode_lib->vba.TotalDataReadBandwidth, + mode_lib->vba.ROBBufferSizeInKByte * 1024 + * mode_lib->vba.TotalDataReadBandwidth + / (mode_lib->vba.AverageReadBandwidthGBytePerSecond + * 1000)); + mode_lib->vba.StutterBurstTime = mode_lib->vba.PartOfBurstThatFitsInROB + * (mode_lib->vba.AverageReadBandwidthGBytePerSecond * 1000) + / mode_lib->vba.TotalDataReadBandwidth / mode_lib->vba.ReturnBW + + (mode_lib->vba.MinFullDETBufferingTime + * mode_lib->vba.TotalDataReadBandwidth + - mode_lib->vba.PartOfBurstThatFitsInROB) + / (mode_lib->vba.DCFCLK * 64); + if (mode_lib->vba.TotalActiveWriteback == 0) { + mode_lib->vba.StutterEfficiencyNotIncludingVBlank = (1 + - (mode_lib->vba.SRExitTime + mode_lib->vba.StutterBurstTime) + / mode_lib->vba.MinFullDETBufferingTime) * 100; + } else { + mode_lib->vba.StutterEfficiencyNotIncludingVBlank = 0; + } + + mode_lib->vba.SmallestVBlank = 999999; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.SynchronizedVBlank || mode_lib->vba.NumberOfActivePlanes == 1) { + mode_lib->vba.VBlankTime = (double) (mode_lib->vba.VTotal[k] + - mode_lib->vba.VActive[k]) * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + } else { + mode_lib->vba.VBlankTime = 0; + } + mode_lib->vba.SmallestVBlank = dml_min( + mode_lib->vba.SmallestVBlank, + mode_lib->vba.VBlankTime); + } + + mode_lib->vba.StutterEfficiency = (mode_lib->vba.StutterEfficiencyNotIncludingVBlank / 100 + * (mode_lib->vba.FrameTimeForMinFullDETBufferingTime + - mode_lib->vba.SmallestVBlank) + + mode_lib->vba.SmallestVBlank) + / mode_lib->vba.FrameTimeForMinFullDETBufferingTime * 100; + + // dml_ml->vba.DCFCLK Deep Sleep + mode_lib->vba.DCFCLKDeepSleep = 8.0; + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; k++) { + if (mode_lib->vba.BytePerPixelDETC[k] > 0) { + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = + dml_max( + 1.1 * mode_lib->vba.SwathWidthY[k] + * dml_ceil( + mode_lib->vba.BytePerPixelDETY[k], + 1) / 32 + / mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k], + 1.1 * mode_lib->vba.SwathWidthY[k] / 2.0 + * dml_ceil( + mode_lib->vba.BytePerPixelDETC[k], + 2) / 32 + / mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k]); + } else + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = 1.1 * mode_lib->vba.SwathWidthY[k] + * dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1) / 64.0 + / mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k]; + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = dml_max( + mode_lib->vba.DCFCLKDeepSleepPerPlane[k], + mode_lib->vba.PixelClock[k] / 16.0); + mode_lib->vba.DCFCLKDeepSleep = dml_max( + mode_lib->vba.DCFCLKDeepSleep, + mode_lib->vba.DCFCLKDeepSleepPerPlane[k]); + + DTRACE( + " dcfclk_deepsleep_per_plane[%i] = %fMHz", + k, + mode_lib->vba.DCFCLKDeepSleepPerPlane[k]); + } + + DTRACE(" dcfclk_deepsleep_mhz = %fMHz", mode_lib->vba.DCFCLKDeepSleep); + + // Stutter Watermark + mode_lib->vba.StutterExitWatermark = mode_lib->vba.SRExitTime + + mode_lib->vba.LastPixelOfLineExtraWatermark + + mode_lib->vba.UrgentExtraLatency + 10 / mode_lib->vba.DCFCLKDeepSleep; + mode_lib->vba.StutterEnterPlusExitWatermark = mode_lib->vba.SREnterPlusExitTime + + mode_lib->vba.LastPixelOfLineExtraWatermark + + mode_lib->vba.UrgentExtraLatency; + + DTRACE(" wm_cstate_exit = %fus", mode_lib->vba.StutterExitWatermark); + DTRACE(" wm_cstate_enter_exit = %fus", mode_lib->vba.StutterEnterPlusExitWatermark); + + // Urgent Latency Supported + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.EffectiveDETPlusLBLinesLuma = + dml_floor( + mode_lib->vba.LinesInDETY[k] + + dml_min( + mode_lib->vba.LinesInDETY[k] + * mode_lib->vba.DPPCLK[k] + * mode_lib->vba.BytePerPixelDETY[k] + * mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] + / (mode_lib->vba.ReturnBW + / mode_lib->vba.DPPPerPlane[k]), + (double) mode_lib->vba.EffectiveLBLatencyHidingSourceLinesLuma), + mode_lib->vba.SwathHeightY[k]); + + mode_lib->vba.UrgentLatencySupportUsLuma = mode_lib->vba.EffectiveDETPlusLBLinesLuma + * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + / mode_lib->vba.VRatio[k] + - mode_lib->vba.EffectiveDETPlusLBLinesLuma + * mode_lib->vba.SwathWidthY[k] + * mode_lib->vba.BytePerPixelDETY[k] + / (mode_lib->vba.ReturnBW + / mode_lib->vba.DPPPerPlane[k]); + + if (mode_lib->vba.BytePerPixelDETC[k] > 0) { + mode_lib->vba.EffectiveDETPlusLBLinesChroma = + dml_floor( + mode_lib->vba.LinesInDETC[k] + + dml_min( + mode_lib->vba.LinesInDETC[k] + * mode_lib->vba.DPPCLK[k] + * mode_lib->vba.BytePerPixelDETC[k] + * mode_lib->vba.PSCL_THROUGHPUT_CHROMA[k] + / (mode_lib->vba.ReturnBW + / mode_lib->vba.DPPPerPlane[k]), + (double) mode_lib->vba.EffectiveLBLatencyHidingSourceLinesChroma), + mode_lib->vba.SwathHeightC[k]); + mode_lib->vba.UrgentLatencySupportUsChroma = + mode_lib->vba.EffectiveDETPlusLBLinesChroma + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + / (mode_lib->vba.VRatio[k] / 2) + - mode_lib->vba.EffectiveDETPlusLBLinesChroma + * (mode_lib->vba.SwathWidthY[k] + / 2) + * mode_lib->vba.BytePerPixelDETC[k] + / (mode_lib->vba.ReturnBW + / mode_lib->vba.DPPPerPlane[k]); + mode_lib->vba.UrgentLatencySupportUs[k] = dml_min( + mode_lib->vba.UrgentLatencySupportUsLuma, + mode_lib->vba.UrgentLatencySupportUsChroma); + } else { + mode_lib->vba.UrgentLatencySupportUs[k] = + mode_lib->vba.UrgentLatencySupportUsLuma; + } + } + + mode_lib->vba.MinUrgentLatencySupportUs = 999999; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.MinUrgentLatencySupportUs = dml_min( + mode_lib->vba.MinUrgentLatencySupportUs, + mode_lib->vba.UrgentLatencySupportUs[k]); + } + + // Non-Urgent Latency Tolerance + mode_lib->vba.NonUrgentLatencyTolerance = mode_lib->vba.MinUrgentLatencySupportUs + - mode_lib->vba.UrgentWatermark; + + // DSCCLK + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if ((mode_lib->vba.BlendingAndTiming[k] != k) || !mode_lib->vba.DSCEnabled[k]) { + mode_lib->vba.DSCCLK_calculated[k] = 0.0; + } else { + if (mode_lib->vba.OutputFormat[k] == dm_420 + || mode_lib->vba.OutputFormat[k] == dm_n422) + mode_lib->vba.DSCFormatFactor = 2; + else + mode_lib->vba.DSCFormatFactor = 1; + if (mode_lib->vba.ODMCombineEnabled[k]) + mode_lib->vba.DSCCLK_calculated[k] = + mode_lib->vba.PixelClockBackEnd[k] / 6 + / mode_lib->vba.DSCFormatFactor + / (1 + - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100); + else + mode_lib->vba.DSCCLK_calculated[k] = + mode_lib->vba.PixelClockBackEnd[k] / 3 + / mode_lib->vba.DSCFormatFactor + / (1 + - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100); + } + } + + // DSC Delay + // TODO + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + double bpp = mode_lib->vba.OutputBpp[k]; + unsigned int slices = mode_lib->vba.NumberOfDSCSlices[k]; + + if (mode_lib->vba.DSCEnabled[k] && bpp != 0) { + if (!mode_lib->vba.ODMCombineEnabled[k]) { + mode_lib->vba.DSCDelay[k] = + dscceComputeDelay( + mode_lib->vba.DSCInputBitPerComponent[k], + bpp, + dml_ceil( + (double) mode_lib->vba.HActive[k] + / mode_lib->vba.NumberOfDSCSlices[k], + 1), + slices, + mode_lib->vba.OutputFormat[k]) + + dscComputeDelay( + mode_lib->vba.OutputFormat[k]); + } else { + mode_lib->vba.DSCDelay[k] = + 2 + * (dscceComputeDelay( + mode_lib->vba.DSCInputBitPerComponent[k], + bpp, + dml_ceil( + (double) mode_lib->vba.HActive[k] + / mode_lib->vba.NumberOfDSCSlices[k], + 1), + slices / 2.0, + mode_lib->vba.OutputFormat[k]) + + dscComputeDelay( + mode_lib->vba.OutputFormat[k])); + } + mode_lib->vba.DSCDelay[k] = mode_lib->vba.DSCDelay[k] + * mode_lib->vba.PixelClock[k] + / mode_lib->vba.PixelClockBackEnd[k]; + } else { + mode_lib->vba.DSCDelay[k] = 0; + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) // NumberOfPlanes + if (j != k && mode_lib->vba.BlendingAndTiming[k] == j + && mode_lib->vba.DSCEnabled[j]) + mode_lib->vba.DSCDelay[k] = mode_lib->vba.DSCDelay[j]; + + // Prefetch + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + unsigned int PDEAndMetaPTEBytesFrameY; + unsigned int PixelPTEBytesPerRowY; + unsigned int MetaRowByteY; + unsigned int MetaRowByteC; + unsigned int PDEAndMetaPTEBytesFrameC; + unsigned int PixelPTEBytesPerRowC; + + Calculate256BBlockSizes( + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), + dml_ceil(mode_lib->vba.BytePerPixelDETC[k], 2), + &mode_lib->vba.BlockHeight256BytesY[k], + &mode_lib->vba.BlockHeight256BytesC[k], + &mode_lib->vba.BlockWidth256BytesY[k], + &mode_lib->vba.BlockWidth256BytesC[k]); + PDEAndMetaPTEBytesFrameY = CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + mode_lib->vba.BlockHeight256BytesY[k], + mode_lib->vba.BlockWidth256BytesY[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k], + mode_lib->vba.ViewportHeight[k], + mode_lib->vba.SwathWidthY[k], + mode_lib->vba.GPUVMEnable, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsLuma, + mode_lib->vba.PDEProcessingBufIn64KBReqs, + mode_lib->vba.PitchY[k], + mode_lib->vba.DCCMetaPitchY[k], + &mode_lib->vba.MacroTileWidthY[k], + &MetaRowByteY, + &PixelPTEBytesPerRowY, + &mode_lib->vba.PTEBufferSizeNotExceeded[mode_lib->vba.VoltageLevel][0], + &mode_lib->vba.dpte_row_height[k], + &mode_lib->vba.meta_row_height[k]); + mode_lib->vba.PrefetchSourceLinesY[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k], + mode_lib->vba.vtaps[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.ViewportYStartY[k], + &mode_lib->vba.VInitPreFillY[k], + &mode_lib->vba.MaxNumSwathY[k]); + + if ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_8)) { + PDEAndMetaPTEBytesFrameC = + CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + mode_lib->vba.BlockHeight256BytesC[k], + mode_lib->vba.BlockWidth256BytesC[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil( + mode_lib->vba.BytePerPixelDETC[k], + 2), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k] / 2, + mode_lib->vba.ViewportHeight[k] / 2, + mode_lib->vba.SwathWidthY[k] / 2, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsLuma, + mode_lib->vba.PDEProcessingBufIn64KBReqs, + mode_lib->vba.PitchC[k], + 0, + &mode_lib->vba.MacroTileWidthC[k], + &MetaRowByteC, + &PixelPTEBytesPerRowC, + &mode_lib->vba.PTEBufferSizeNotExceeded[mode_lib->vba.VoltageLevel][0], + &mode_lib->vba.dpte_row_height_chroma[k], + &mode_lib->vba.meta_row_height_chroma[k]); + mode_lib->vba.PrefetchSourceLinesC[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k] / 2, + mode_lib->vba.VTAPsChroma[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + mode_lib->vba.SwathHeightC[k], + mode_lib->vba.ViewportYStartC[k], + &mode_lib->vba.VInitPreFillC[k], + &mode_lib->vba.MaxNumSwathC[k]); + } else { + PixelPTEBytesPerRowC = 0; + PDEAndMetaPTEBytesFrameC = 0; + MetaRowByteC = 0; + mode_lib->vba.MaxNumSwathC[k] = 0; + mode_lib->vba.PrefetchSourceLinesC[k] = 0; + } + + mode_lib->vba.PixelPTEBytesPerRow[k] = PixelPTEBytesPerRowY + PixelPTEBytesPerRowC; + mode_lib->vba.PDEAndMetaPTEBytesFrame[k] = PDEAndMetaPTEBytesFrameY + + PDEAndMetaPTEBytesFrameC; + mode_lib->vba.MetaRowByte[k] = MetaRowByteY + MetaRowByteC; + + CalculateActiveRowBandwidth( + mode_lib->vba.GPUVMEnable, + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.VRatio[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + MetaRowByteY, + MetaRowByteC, + mode_lib->vba.meta_row_height[k], + mode_lib->vba.meta_row_height_chroma[k], + PixelPTEBytesPerRowY, + PixelPTEBytesPerRowC, + mode_lib->vba.dpte_row_height[k], + mode_lib->vba.dpte_row_height_chroma[k], + &mode_lib->vba.meta_row_bw[k], + &mode_lib->vba.dpte_row_bw[k], + &mode_lib->vba.qual_row_bw[k]); + } + + mode_lib->vba.TCalc = 24.0 / mode_lib->vba.DCFCLKDeepSleep; + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.BlendingAndTiming[k] == k) { + if (mode_lib->vba.WritebackEnable[k] == true) { + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = + mode_lib->vba.WritebackLatency + + CalculateWriteBackDelay( + mode_lib->vba.WritebackPixelFormat[k], + mode_lib->vba.WritebackHRatio[k], + mode_lib->vba.WritebackVRatio[k], + mode_lib->vba.WritebackLumaHTaps[k], + mode_lib->vba.WritebackLumaVTaps[k], + mode_lib->vba.WritebackChromaHTaps[k], + mode_lib->vba.WritebackChromaVTaps[k], + mode_lib->vba.WritebackDestinationWidth[k]) + / mode_lib->vba.DISPCLK; + } else + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = 0; + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { + if (mode_lib->vba.BlendingAndTiming[j] == k + && mode_lib->vba.WritebackEnable[j] == true) { + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = + dml_max( + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k], + mode_lib->vba.WritebackLatency + + CalculateWriteBackDelay( + mode_lib->vba.WritebackPixelFormat[j], + mode_lib->vba.WritebackHRatio[j], + mode_lib->vba.WritebackVRatio[j], + mode_lib->vba.WritebackLumaHTaps[j], + mode_lib->vba.WritebackLumaVTaps[j], + mode_lib->vba.WritebackChromaHTaps[j], + mode_lib->vba.WritebackChromaVTaps[j], + mode_lib->vba.WritebackDestinationWidth[j]) + / mode_lib->vba.DISPCLK); + } + } + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) + if (mode_lib->vba.BlendingAndTiming[k] == j) + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] = + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][j]; + + mode_lib->vba.VStartupLines = 13; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.MaxVStartupLines[k] = + mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k] + - dml_max( + 1.0, + dml_ceil( + mode_lib->vba.WritebackDelay[mode_lib->vba.VoltageLevel][k] + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1)); + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + mode_lib->vba.MaximumMaxVStartupLines = dml_max( + mode_lib->vba.MaximumMaxVStartupLines, + mode_lib->vba.MaxVStartupLines[k]); + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.cursor_bw[k] = 0.0; + for (j = 0; j < mode_lib->vba.NumberOfCursors[k]; ++j) + mode_lib->vba.cursor_bw[k] += mode_lib->vba.CursorWidth[k][j] + * mode_lib->vba.CursorBPP[k][j] / 8.0 + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + * mode_lib->vba.VRatio[k]; + } + + do { + double MaxTotalRDBandwidth = 0; + bool DestinationLineTimesForPrefetchLessThan2 = false; + bool VRatioPrefetchMoreThan4 = false; + bool prefetch_vm_bw_valid = true; + bool prefetch_row_bw_valid = true; + double TWait = CalculateTWait( + mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb], + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.SREnterPlusExitTime); + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.XFCEnabled[k] == true) { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = + CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + mode_lib->vba.SwathWidthY[k], + dml_ceil( + mode_lib->vba.BytePerPixelDETY[k], + 1), + mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k], + mode_lib->vba.XFCTSlvVupdateOffset, + mode_lib->vba.XFCTSlvVupdateWidth, + mode_lib->vba.XFCTSlvVreadyOffset, + mode_lib->vba.XFCXBUFLatencyTolerance, + mode_lib->vba.XFCFillBWOverhead, + mode_lib->vba.XFCSlvChunkSize, + mode_lib->vba.XFCBusTransportTime, + mode_lib->vba.TCalc, + TWait, + &mode_lib->vba.SrcActiveDrainRate, + &mode_lib->vba.TInitXFill, + &mode_lib->vba.TslvChk); + } else { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = 0; + } + mode_lib->vba.ErrorResult[k] = + CalculatePrefetchSchedule( + mode_lib, + mode_lib->vba.DPPCLK[k], + mode_lib->vba.DISPCLK, + mode_lib->vba.PixelClock[k], + mode_lib->vba.DCFCLKDeepSleep, + mode_lib->vba.DSCDelay[k], + mode_lib->vba.DPPPerPlane[k], + mode_lib->vba.ScalerEnabled[k], + mode_lib->vba.NumberOfCursors[k], + mode_lib->vba.DPPCLKDelaySubtotal, + mode_lib->vba.DPPCLKDelaySCL, + mode_lib->vba.DPPCLKDelaySCLLBOnly, + mode_lib->vba.DPPCLKDelayCNVCFormater, + mode_lib->vba.DPPCLKDelayCNVCCursor, + mode_lib->vba.DISPCLKDelaySubtotal, + (unsigned int) (mode_lib->vba.SwathWidthY[k] + / mode_lib->vba.HRatio[k]), + mode_lib->vba.OutputFormat[k], + mode_lib->vba.VTotal[k] + - mode_lib->vba.VActive[k], + mode_lib->vba.HTotal[k], + mode_lib->vba.MaxInterDCNTileRepeaters, + dml_min( + mode_lib->vba.VStartupLines, + mode_lib->vba.MaxVStartupLines[k]), + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.DynamicMetadataEnable[k], + mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], + mode_lib->vba.DynamicMetadataTransmittedBytes[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.UrgentExtraLatency, + mode_lib->vba.TCalc, + mode_lib->vba.PDEAndMetaPTEBytesFrame[k], + mode_lib->vba.MetaRowByte[k], + mode_lib->vba.PixelPTEBytesPerRow[k], + mode_lib->vba.PrefetchSourceLinesY[k], + mode_lib->vba.SwathWidthY[k], + mode_lib->vba.BytePerPixelDETY[k], + mode_lib->vba.VInitPreFillY[k], + mode_lib->vba.MaxNumSwathY[k], + mode_lib->vba.PrefetchSourceLinesC[k], + mode_lib->vba.BytePerPixelDETC[k], + mode_lib->vba.VInitPreFillC[k], + mode_lib->vba.MaxNumSwathC[k], + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.SwathHeightC[k], + TWait, + mode_lib->vba.XFCEnabled[k], + mode_lib->vba.XFCRemoteSurfaceFlipDelay, + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + &mode_lib->vba.DSTXAfterScaler[k], + &mode_lib->vba.DSTYAfterScaler[k], + &mode_lib->vba.DestinationLinesForPrefetch[k], + &mode_lib->vba.PrefetchBandwidth[k], + &mode_lib->vba.DestinationLinesToRequestVMInVBlank[k], + &mode_lib->vba.DestinationLinesToRequestRowInVBlank[k], + &mode_lib->vba.VRatioPrefetchY[k], + &mode_lib->vba.VRatioPrefetchC[k], + &mode_lib->vba.RequiredPrefetchPixDataBWLuma[k], + &mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + &mode_lib->vba.Tno_bw[k], + &mode_lib->vba.VUpdateOffsetPix[k], + &mode_lib->vba.VUpdateWidthPix[k], + &mode_lib->vba.VReadyOffsetPix[k]); + if (mode_lib->vba.BlendingAndTiming[k] == k) { + mode_lib->vba.VStartup[k] = dml_min( + mode_lib->vba.VStartupLines, + mode_lib->vba.MaxVStartupLines[k]); + if (mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata + != 0) { + mode_lib->vba.VStartup[k] = + mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata; + } + } else { + mode_lib->vba.VStartup[k] = + dml_min( + mode_lib->vba.VStartupLines, + mode_lib->vba.MaxVStartupLines[mode_lib->vba.BlendingAndTiming[k]]); + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + + if (mode_lib->vba.PDEAndMetaPTEBytesFrame[k] == 0) + mode_lib->vba.prefetch_vm_bw[k] = 0; + else if (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] > 0) { + mode_lib->vba.prefetch_vm_bw[k] = + (double) mode_lib->vba.PDEAndMetaPTEBytesFrame[k] + / (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + } else { + mode_lib->vba.prefetch_vm_bw[k] = 0; + prefetch_vm_bw_valid = false; + } + if (mode_lib->vba.MetaRowByte[k] + mode_lib->vba.PixelPTEBytesPerRow[k] + == 0) + mode_lib->vba.prefetch_row_bw[k] = 0; + else if (mode_lib->vba.DestinationLinesToRequestRowInVBlank[k] > 0) { + mode_lib->vba.prefetch_row_bw[k] = + (double) (mode_lib->vba.MetaRowByte[k] + + mode_lib->vba.PixelPTEBytesPerRow[k]) + / (mode_lib->vba.DestinationLinesToRequestRowInVBlank[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + } else { + mode_lib->vba.prefetch_row_bw[k] = 0; + prefetch_row_bw_valid = false; + } + + MaxTotalRDBandwidth = + MaxTotalRDBandwidth + mode_lib->vba.cursor_bw[k] + + dml_max( + mode_lib->vba.prefetch_vm_bw[k], + dml_max( + mode_lib->vba.prefetch_row_bw[k], + dml_max( + mode_lib->vba.ReadBandwidthPlaneLuma[k] + + mode_lib->vba.ReadBandwidthPlaneChroma[k], + mode_lib->vba.RequiredPrefetchPixDataBWLuma[k]) + + mode_lib->vba.meta_row_bw[k] + + mode_lib->vba.dpte_row_bw[k])); + + if (mode_lib->vba.DestinationLinesForPrefetch[k] < 2) + DestinationLineTimesForPrefetchLessThan2 = true; + if (mode_lib->vba.VRatioPrefetchY[k] > 4 + || mode_lib->vba.VRatioPrefetchC[k] > 4) + VRatioPrefetchMoreThan4 = true; + } + + if (MaxTotalRDBandwidth <= mode_lib->vba.ReturnBW && prefetch_vm_bw_valid + && prefetch_row_bw_valid && !VRatioPrefetchMoreThan4 + && !DestinationLineTimesForPrefetchLessThan2) + mode_lib->vba.PrefetchModeSupported = true; + else { + mode_lib->vba.PrefetchModeSupported = false; + dml_print( + "DML: CalculatePrefetchSchedule ***failed***. Bandwidth violation. Results are NOT valid\n"); + } + + if (mode_lib->vba.PrefetchModeSupported == true) { + double final_flip_bw[DC__NUM_DPP__MAX]; + unsigned int ImmediateFlipBytes[DC__NUM_DPP__MAX]; + double total_dcn_read_bw_with_flip = 0; + + mode_lib->vba.BandwidthAvailableForImmediateFlip = mode_lib->vba.ReturnBW; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.BandwidthAvailableForImmediateFlip = + mode_lib->vba.BandwidthAvailableForImmediateFlip + - mode_lib->vba.cursor_bw[k] + - dml_max( + mode_lib->vba.ReadBandwidthPlaneLuma[k] + + mode_lib->vba.ReadBandwidthPlaneChroma[k] + + mode_lib->vba.qual_row_bw[k], + mode_lib->vba.PrefetchBandwidth[k]); + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + ImmediateFlipBytes[k] = 0; + if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 + && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { + ImmediateFlipBytes[k] = + mode_lib->vba.PDEAndMetaPTEBytesFrame[k] + + mode_lib->vba.MetaRowByte[k] + + mode_lib->vba.PixelPTEBytesPerRow[k]; + } + } + mode_lib->vba.TotImmediateFlipBytes = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 + && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { + mode_lib->vba.TotImmediateFlipBytes = + mode_lib->vba.TotImmediateFlipBytes + + ImmediateFlipBytes[k]; + } + } + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + CalculateFlipSchedule( + mode_lib, + mode_lib->vba.UrgentExtraLatency, + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.BandwidthAvailableForImmediateFlip, + mode_lib->vba.TotImmediateFlipBytes, + mode_lib->vba.SourcePixelFormat[k], + ImmediateFlipBytes[k], + mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k], + mode_lib->vba.VRatio[k], + mode_lib->vba.Tno_bw[k], + mode_lib->vba.PDEAndMetaPTEBytesFrame[k], + mode_lib->vba.MetaRowByte[k], + mode_lib->vba.PixelPTEBytesPerRow[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.dpte_row_height[k], + mode_lib->vba.meta_row_height[k], + mode_lib->vba.qual_row_bw[k], + &mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip[k], + &mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip[k], + &final_flip_bw[k], + &mode_lib->vba.ImmediateFlipSupportedForPipe[k]); + } + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + total_dcn_read_bw_with_flip = + total_dcn_read_bw_with_flip + + mode_lib->vba.cursor_bw[k] + + dml_max( + mode_lib->vba.prefetch_vm_bw[k], + dml_max( + mode_lib->vba.prefetch_row_bw[k], + final_flip_bw[k] + + dml_max( + mode_lib->vba.ReadBandwidthPlaneLuma[k] + + mode_lib->vba.ReadBandwidthPlaneChroma[k], + mode_lib->vba.RequiredPrefetchPixDataBWLuma[k]))); + } + mode_lib->vba.ImmediateFlipSupported = true; + if (total_dcn_read_bw_with_flip > mode_lib->vba.ReturnBW) { + mode_lib->vba.ImmediateFlipSupported = false; + } + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.ImmediateFlipSupportedForPipe[k] == false) { + mode_lib->vba.ImmediateFlipSupported = false; + } + } + } else { + mode_lib->vba.ImmediateFlipSupported = false; + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.ErrorResult[k]) { + mode_lib->vba.PrefetchModeSupported = false; + dml_print( + "DML: CalculatePrefetchSchedule ***failed***. Prefetch schedule violation. Results are NOT valid\n"); + } + } + + mode_lib->vba.VStartupLines = mode_lib->vba.VStartupLines + 1; + } while (!((mode_lib->vba.PrefetchModeSupported + && (!mode_lib->vba.ImmediateFlipSupport + || mode_lib->vba.ImmediateFlipSupported)) + || mode_lib->vba.MaximumMaxVStartupLines < mode_lib->vba.VStartupLines)); + + //Display Pipeline Delivery Time in Prefetch + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.VRatioPrefetchY[k] <= 1) { + mode_lib->vba.DisplayPipeLineDeliveryTimeLumaPrefetch[k] = + mode_lib->vba.SwathWidthY[k] * mode_lib->vba.DPPPerPlane[k] + / mode_lib->vba.HRatio[k] + / mode_lib->vba.PixelClock[k]; + } else { + mode_lib->vba.DisplayPipeLineDeliveryTimeLumaPrefetch[k] = + mode_lib->vba.SwathWidthY[k] + / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] + / mode_lib->vba.DPPCLK[k]; + } + if (mode_lib->vba.BytePerPixelDETC[k] == 0) { + mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = 0; + } else { + if (mode_lib->vba.VRatioPrefetchC[k] <= 1) { + mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = + mode_lib->vba.SwathWidthY[k] + * mode_lib->vba.DPPPerPlane[k] + / mode_lib->vba.HRatio[k] + / mode_lib->vba.PixelClock[k]; + } else { + mode_lib->vba.DisplayPipeLineDeliveryTimeChromaPrefetch[k] = + mode_lib->vba.SwathWidthY[k] + / mode_lib->vba.PSCL_THROUGHPUT_LUMA[k] + / mode_lib->vba.DPPCLK[k]; + } + } + } + + // Min TTUVBlank + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb] == 0) { + mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = true; + mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = true; + mode_lib->vba.MinTTUVBlank[k] = dml_max( + mode_lib->vba.DRAMClockChangeWatermark, + dml_max( + mode_lib->vba.StutterEnterPlusExitWatermark, + mode_lib->vba.UrgentWatermark)); + } else if (mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb] == 1) { + mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = false; + mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = true; + mode_lib->vba.MinTTUVBlank[k] = dml_max( + mode_lib->vba.StutterEnterPlusExitWatermark, + mode_lib->vba.UrgentWatermark); + } else { + mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k] = false; + mode_lib->vba.AllowDRAMSelfRefreshDuringVBlank[k] = false; + mode_lib->vba.MinTTUVBlank[k] = mode_lib->vba.UrgentWatermark; + } + if (!mode_lib->vba.DynamicMetadataEnable[k]) + mode_lib->vba.MinTTUVBlank[k] = mode_lib->vba.TCalc + + mode_lib->vba.MinTTUVBlank[k]; + } + + // DCC Configuration + mode_lib->vba.ActiveDPPs = 0; + // NB P-State/DRAM Clock Change Support + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.ActiveDPPs = mode_lib->vba.ActiveDPPs + mode_lib->vba.DPPPerPlane[k]; + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + double EffectiveLBLatencyHidingY; + double EffectiveLBLatencyHidingC; + double DPPOutputBufferLinesY; + double DPPOutputBufferLinesC; + double DPPOPPBufferingY; + double MaxDETBufferingTimeY; + double ActiveDRAMClockChangeLatencyMarginY; + + mode_lib->vba.LBLatencyHidingSourceLinesY = + dml_min( + mode_lib->vba.MaxLineBufferLines, + (unsigned int) dml_floor( + (double) mode_lib->vba.LineBufferSize + / mode_lib->vba.LBBitPerPixel[k] + / (mode_lib->vba.SwathWidthY[k] + / dml_max( + mode_lib->vba.HRatio[k], + 1.0)), + 1)) - (mode_lib->vba.vtaps[k] - 1); + + mode_lib->vba.LBLatencyHidingSourceLinesC = + dml_min( + mode_lib->vba.MaxLineBufferLines, + (unsigned int) dml_floor( + (double) mode_lib->vba.LineBufferSize + / mode_lib->vba.LBBitPerPixel[k] + / (mode_lib->vba.SwathWidthY[k] + / 2.0 + / dml_max( + mode_lib->vba.HRatio[k] + / 2, + 1.0)), + 1)) + - (mode_lib->vba.VTAPsChroma[k] - 1); + + EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY + / mode_lib->vba.VRatio[k] + * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]); + + EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC + / (mode_lib->vba.VRatio[k] / 2) + * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]); + + if (mode_lib->vba.SwathWidthY[k] > 2 * mode_lib->vba.DPPOutputBufferPixels) { + DPPOutputBufferLinesY = mode_lib->vba.DPPOutputBufferPixels + / mode_lib->vba.SwathWidthY[k]; + } else if (mode_lib->vba.SwathWidthY[k] > mode_lib->vba.DPPOutputBufferPixels) { + DPPOutputBufferLinesY = 0.5; + } else { + DPPOutputBufferLinesY = 1; + } + + if (mode_lib->vba.SwathWidthY[k] / 2 > 2 * mode_lib->vba.DPPOutputBufferPixels) { + DPPOutputBufferLinesC = mode_lib->vba.DPPOutputBufferPixels + / (mode_lib->vba.SwathWidthY[k] / 2); + } else if (mode_lib->vba.SwathWidthY[k] / 2 > mode_lib->vba.DPPOutputBufferPixels) { + DPPOutputBufferLinesC = 0.5; + } else { + DPPOutputBufferLinesC = 1; + } + + DPPOPPBufferingY = (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + * (DPPOutputBufferLinesY + mode_lib->vba.OPPOutputBufferLines); + MaxDETBufferingTimeY = mode_lib->vba.FullDETBufferingTimeY[k] + + (mode_lib->vba.LinesInDETY[k] + - mode_lib->vba.LinesInDETYRoundedDownToSwath[k]) + / mode_lib->vba.SwathHeightY[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + + ActiveDRAMClockChangeLatencyMarginY = DPPOPPBufferingY + EffectiveLBLatencyHidingY + + MaxDETBufferingTimeY - mode_lib->vba.DRAMClockChangeWatermark; + + if (mode_lib->vba.ActiveDPPs > 1) { + ActiveDRAMClockChangeLatencyMarginY = + ActiveDRAMClockChangeLatencyMarginY + - (1 - 1 / (mode_lib->vba.ActiveDPPs - 1)) + * mode_lib->vba.SwathHeightY[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + } + + if (mode_lib->vba.BytePerPixelDETC[k] > 0) { + double DPPOPPBufferingC = (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + * (DPPOutputBufferLinesC + + mode_lib->vba.OPPOutputBufferLines); + double MaxDETBufferingTimeC = + mode_lib->vba.FullDETBufferingTimeC[k] + + (mode_lib->vba.LinesInDETC[k] + - mode_lib->vba.LinesInDETCRoundedDownToSwath[k]) + / mode_lib->vba.SwathHeightC[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + double ActiveDRAMClockChangeLatencyMarginC = DPPOPPBufferingC + + EffectiveLBLatencyHidingC + MaxDETBufferingTimeC + - mode_lib->vba.DRAMClockChangeWatermark; + + if (mode_lib->vba.ActiveDPPs > 1) { + ActiveDRAMClockChangeLatencyMarginC = + ActiveDRAMClockChangeLatencyMarginC + - (1 + - 1 + / (mode_lib->vba.ActiveDPPs + - 1)) + * mode_lib->vba.SwathHeightC[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]); + } + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( + ActiveDRAMClockChangeLatencyMarginY, + ActiveDRAMClockChangeLatencyMarginC); + } else { + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = + ActiveDRAMClockChangeLatencyMarginY; + } + + if (mode_lib->vba.WritebackEnable[k]) { + double WritebackDRAMClockChangeLatencyMargin; + + if (mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { + WritebackDRAMClockChangeLatencyMargin = + (double) (mode_lib->vba.WritebackInterfaceLumaBufferSize + + mode_lib->vba.WritebackInterfaceChromaBufferSize) + / (mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + * 4) + - mode_lib->vba.WritebackDRAMClockChangeWatermark; + } else if (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { + WritebackDRAMClockChangeLatencyMargin = + dml_min( + (double) mode_lib->vba.WritebackInterfaceLumaBufferSize + * 8.0 / 10, + 2.0 + * mode_lib->vba.WritebackInterfaceChromaBufferSize + * 8 / 10) + / (mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k])) + - mode_lib->vba.WritebackDRAMClockChangeWatermark; + } else { + WritebackDRAMClockChangeLatencyMargin = + dml_min( + (double) mode_lib->vba.WritebackInterfaceLumaBufferSize, + 2.0 + * mode_lib->vba.WritebackInterfaceChromaBufferSize) + / (mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k])) + - mode_lib->vba.WritebackDRAMClockChangeWatermark; + } + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], + WritebackDRAMClockChangeLatencyMargin); + } + } + + mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] + < mode_lib->vba.MinActiveDRAMClockChangeMargin) { + mode_lib->vba.MinActiveDRAMClockChangeMargin = + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; + } + } + + mode_lib->vba.MinActiveDRAMClockChangeLatencySupported = + mode_lib->vba.MinActiveDRAMClockChangeMargin + + mode_lib->vba.DRAMClockChangeLatency; + + if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) { + mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; + } else { + if (mode_lib->vba.SynchronizedVBlank || mode_lib->vba.NumberOfActivePlanes == 1) { + mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vblank; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (!mode_lib->vba.AllowDRAMClockChangeDuringVBlank[k]) { + mode_lib->vba.DRAMClockChangeSupport[0][0] = + dm_dram_clock_change_unsupported; + } + } + } else { + mode_lib->vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_unsupported; + } + } + for (k = 0; k <= mode_lib->vba.soc.num_states; k++) + for (j = 0; j < 2; j++) + mode_lib->vba.DRAMClockChangeSupport[k][j] = mode_lib->vba.DRAMClockChangeSupport[0][0]; + + //XFC Parameters: + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.XFCEnabled[k] == true) { + double TWait; + + mode_lib->vba.XFCSlaveVUpdateOffset[k] = mode_lib->vba.XFCTSlvVupdateOffset; + mode_lib->vba.XFCSlaveVupdateWidth[k] = mode_lib->vba.XFCTSlvVupdateWidth; + mode_lib->vba.XFCSlaveVReadyOffset[k] = mode_lib->vba.XFCTSlvVreadyOffset; + TWait = CalculateTWait( + mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb], + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.SREnterPlusExitTime); + mode_lib->vba.XFCRemoteSurfaceFlipDelay = CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + mode_lib->vba.SwathWidthY[k], + dml_ceil(mode_lib->vba.BytePerPixelDETY[k], 1), + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.XFCTSlvVupdateOffset, + mode_lib->vba.XFCTSlvVupdateWidth, + mode_lib->vba.XFCTSlvVreadyOffset, + mode_lib->vba.XFCXBUFLatencyTolerance, + mode_lib->vba.XFCFillBWOverhead, + mode_lib->vba.XFCSlvChunkSize, + mode_lib->vba.XFCBusTransportTime, + mode_lib->vba.TCalc, + TWait, + &mode_lib->vba.SrcActiveDrainRate, + &mode_lib->vba.TInitXFill, + &mode_lib->vba.TslvChk); + mode_lib->vba.XFCRemoteSurfaceFlipLatency[k] = + dml_floor( + mode_lib->vba.XFCRemoteSurfaceFlipDelay + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1); + mode_lib->vba.XFCTransferDelay[k] = + dml_ceil( + mode_lib->vba.XFCBusTransportTime + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1); + mode_lib->vba.XFCPrechargeDelay[k] = + dml_ceil( + (mode_lib->vba.XFCBusTransportTime + + mode_lib->vba.TInitXFill + + mode_lib->vba.TslvChk) + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1); + mode_lib->vba.InitFillLevel = mode_lib->vba.XFCXBUFLatencyTolerance + * mode_lib->vba.SrcActiveDrainRate; + mode_lib->vba.FinalFillMargin = + (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] + + mode_lib->vba.DestinationLinesToRequestRowInVBlank[k]) + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k] + * mode_lib->vba.SrcActiveDrainRate + + mode_lib->vba.XFCFillConstant; + mode_lib->vba.FinalFillLevel = mode_lib->vba.XFCRemoteSurfaceFlipDelay + * mode_lib->vba.SrcActiveDrainRate + + mode_lib->vba.FinalFillMargin; + mode_lib->vba.RemainingFillLevel = dml_max( + 0.0, + mode_lib->vba.FinalFillLevel - mode_lib->vba.InitFillLevel); + mode_lib->vba.TFinalxFill = mode_lib->vba.RemainingFillLevel + / (mode_lib->vba.SrcActiveDrainRate + * mode_lib->vba.XFCFillBWOverhead / 100); + mode_lib->vba.XFCPrefetchMargin[k] = + mode_lib->vba.XFCRemoteSurfaceFlipDelay + + mode_lib->vba.TFinalxFill + + (mode_lib->vba.DestinationLinesToRequestVMInVBlank[k] + + mode_lib->vba.DestinationLinesToRequestRowInVBlank[k]) + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + } else { + mode_lib->vba.XFCSlaveVUpdateOffset[k] = 0; + mode_lib->vba.XFCSlaveVupdateWidth[k] = 0; + mode_lib->vba.XFCSlaveVReadyOffset[k] = 0; + mode_lib->vba.XFCRemoteSurfaceFlipLatency[k] = 0; + mode_lib->vba.XFCPrechargeDelay[k] = 0; + mode_lib->vba.XFCTransferDelay[k] = 0; + mode_lib->vba.XFCPrefetchMargin[k] = 0; + } + } + { + unsigned int VStartupMargin = 0; + bool FirstMainPlane = true; + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.BlendingAndTiming[k] == k) { + unsigned int Margin = (mode_lib->vba.MaxVStartupLines[k] - mode_lib->vba.VStartup[k]) + * mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]; + + if (FirstMainPlane) { + VStartupMargin = Margin; + FirstMainPlane = false; + } else + VStartupMargin = dml_min(VStartupMargin, Margin); + } + + if (mode_lib->vba.UseMaximumVStartup) { + if (mode_lib->vba.VTotal_Max[k] == mode_lib->vba.VTotal[k]) { + //only use max vstart if it is not drr or lateflip. + mode_lib->vba.VStartup[k] = mode_lib->vba.MaxVStartupLines[mode_lib->vba.BlendingAndTiming[k]]; + } + } + } +} +} + +static void dml20_DisplayPipeConfiguration(struct display_mode_lib *mode_lib) +{ + double BytePerPixDETY; + double BytePerPixDETC; + double Read256BytesBlockHeightY; + double Read256BytesBlockHeightC; + double Read256BytesBlockWidthY; + double Read256BytesBlockWidthC; + double MaximumSwathHeightY; + double MaximumSwathHeightC; + double MinimumSwathHeightY; + double MinimumSwathHeightC; + double SwathWidth; + double SwathWidthGranularityY; + double SwathWidthGranularityC; + double RoundedUpMaxSwathSizeBytesY; + double RoundedUpMaxSwathSizeBytesC; + unsigned int j, k; + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + bool MainPlaneDoesODMCombine = false; + + if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { + BytePerPixDETY = 8; + BytePerPixDETC = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { + BytePerPixDETY = 4; + BytePerPixDETC = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { + BytePerPixDETY = 2; + BytePerPixDETC = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8) { + BytePerPixDETY = 1; + BytePerPixDETC = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { + BytePerPixDETY = 1; + BytePerPixDETC = 2; + } else { + BytePerPixDETY = 4.0 / 3.0; + BytePerPixDETC = 8.0 / 3.0; + } + + if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_8)) { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { + Read256BytesBlockHeightY = 1; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { + Read256BytesBlockHeightY = 4; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_16) { + Read256BytesBlockHeightY = 8; + } else { + Read256BytesBlockHeightY = 16; + } + Read256BytesBlockWidthY = 256 / dml_ceil(BytePerPixDETY, 1) + / Read256BytesBlockHeightY; + Read256BytesBlockHeightC = 0; + Read256BytesBlockWidthC = 0; + } else { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { + Read256BytesBlockHeightY = 1; + Read256BytesBlockHeightC = 1; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { + Read256BytesBlockHeightY = 16; + Read256BytesBlockHeightC = 8; + } else { + Read256BytesBlockHeightY = 8; + Read256BytesBlockHeightC = 8; + } + Read256BytesBlockWidthY = 256 / dml_ceil(BytePerPixDETY, 1) + / Read256BytesBlockHeightY; + Read256BytesBlockWidthC = 256 / dml_ceil(BytePerPixDETC, 2) + / Read256BytesBlockHeightC; + } + + if (mode_lib->vba.SourceScan[k] == dm_horz) { + MaximumSwathHeightY = Read256BytesBlockHeightY; + MaximumSwathHeightC = Read256BytesBlockHeightC; + } else { + MaximumSwathHeightY = Read256BytesBlockWidthY; + MaximumSwathHeightC = Read256BytesBlockWidthC; + } + + if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_8)) { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear + || (mode_lib->vba.SourcePixelFormat[k] == dm_444_64 + && (mode_lib->vba.SurfaceTiling[k] + == dm_sw_4kb_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_4kb_s_x + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s_t + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s_x + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_var_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_var_s_x) + && mode_lib->vba.SourceScan[k] == dm_horz)) { + MinimumSwathHeightY = MaximumSwathHeightY; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8 + && mode_lib->vba.SourceScan[k] != dm_horz) { + MinimumSwathHeightY = MaximumSwathHeightY; + } else { + MinimumSwathHeightY = MaximumSwathHeightY / 2.0; + } + MinimumSwathHeightC = MaximumSwathHeightC; + } else { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { + MinimumSwathHeightY = MaximumSwathHeightY; + MinimumSwathHeightC = MaximumSwathHeightC; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8 + && mode_lib->vba.SourceScan[k] == dm_horz) { + MinimumSwathHeightY = MaximumSwathHeightY / 2.0; + MinimumSwathHeightC = MaximumSwathHeightC; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10 + && mode_lib->vba.SourceScan[k] == dm_horz) { + MinimumSwathHeightC = MaximumSwathHeightC / 2.0; + MinimumSwathHeightY = MaximumSwathHeightY; + } else { + MinimumSwathHeightY = MaximumSwathHeightY; + MinimumSwathHeightC = MaximumSwathHeightC; + } + } + + if (mode_lib->vba.SourceScan[k] == dm_horz) { + SwathWidth = mode_lib->vba.ViewportWidth[k]; + } else { + SwathWidth = mode_lib->vba.ViewportHeight[k]; + } + + if (mode_lib->vba.ODMCombineEnabled[k] == true) { + MainPlaneDoesODMCombine = true; + } + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { + if (mode_lib->vba.BlendingAndTiming[k] == j + && mode_lib->vba.ODMCombineEnabled[j] == true) { + MainPlaneDoesODMCombine = true; + } + } + + if (MainPlaneDoesODMCombine == true) { + SwathWidth = dml_min( + SwathWidth, + mode_lib->vba.HActive[k] / 2.0 * mode_lib->vba.HRatio[k]); + } else { + if (mode_lib->vba.DPPPerPlane[k] == 0) + SwathWidth = 0; + else + SwathWidth = SwathWidth / mode_lib->vba.DPPPerPlane[k]; + } + + SwathWidthGranularityY = 256 / dml_ceil(BytePerPixDETY, 1) / MaximumSwathHeightY; + RoundedUpMaxSwathSizeBytesY = (dml_ceil( + (double) (SwathWidth - 1), + SwathWidthGranularityY) + SwathWidthGranularityY) * BytePerPixDETY + * MaximumSwathHeightY; + if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { + RoundedUpMaxSwathSizeBytesY = dml_ceil(RoundedUpMaxSwathSizeBytesY, 256) + + 256; + } + if (MaximumSwathHeightC > 0) { + SwathWidthGranularityC = 256.0 / dml_ceil(BytePerPixDETC, 2) + / MaximumSwathHeightC; + RoundedUpMaxSwathSizeBytesC = (dml_ceil( + (double) (SwathWidth / 2.0 - 1), + SwathWidthGranularityC) + SwathWidthGranularityC) + * BytePerPixDETC * MaximumSwathHeightC; + if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { + RoundedUpMaxSwathSizeBytesC = dml_ceil( + RoundedUpMaxSwathSizeBytesC, + 256) + 256; + } + } else + RoundedUpMaxSwathSizeBytesC = 0.0; + + if (RoundedUpMaxSwathSizeBytesY + RoundedUpMaxSwathSizeBytesC + <= mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0) { + mode_lib->vba.SwathHeightY[k] = MaximumSwathHeightY; + mode_lib->vba.SwathHeightC[k] = MaximumSwathHeightC; + } else { + mode_lib->vba.SwathHeightY[k] = MinimumSwathHeightY; + mode_lib->vba.SwathHeightC[k] = MinimumSwathHeightC; + } + + if (mode_lib->vba.SwathHeightC[k] == 0) { + mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte * 1024; + mode_lib->vba.DETBufferSizeC[k] = 0; + } else if (mode_lib->vba.SwathHeightY[k] <= mode_lib->vba.SwathHeightC[k]) { + mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte + * 1024.0 / 2; + mode_lib->vba.DETBufferSizeC[k] = mode_lib->vba.DETBufferSizeInKByte + * 1024.0 / 2; + } else { + mode_lib->vba.DETBufferSizeY[k] = mode_lib->vba.DETBufferSizeInKByte + * 1024.0 * 2 / 3; + mode_lib->vba.DETBufferSizeC[k] = mode_lib->vba.DETBufferSizeInKByte + * 1024.0 / 3; + } + } +} + +static double CalculateTWait( + unsigned int PrefetchMode, + double DRAMClockChangeLatency, + double UrgentLatencyPixelDataOnly, + double SREnterPlusExitTime) +{ + if (PrefetchMode == 0) { + return dml_max( + DRAMClockChangeLatency + UrgentLatencyPixelDataOnly, + dml_max(SREnterPlusExitTime, UrgentLatencyPixelDataOnly)); + } else if (PrefetchMode == 1) { + return dml_max(SREnterPlusExitTime, UrgentLatencyPixelDataOnly); + } else { + return UrgentLatencyPixelDataOnly; + } +} + +static double CalculateRemoteSurfaceFlipDelay( + struct display_mode_lib *mode_lib, + double VRatio, + double SwathWidth, + double Bpp, + double LineTime, + double XFCTSlvVupdateOffset, + double XFCTSlvVupdateWidth, + double XFCTSlvVreadyOffset, + double XFCXBUFLatencyTolerance, + double XFCFillBWOverhead, + double XFCSlvChunkSize, + double XFCBusTransportTime, + double TCalc, + double TWait, + double *SrcActiveDrainRate, + double *TInitXFill, + double *TslvChk) +{ + double TSlvSetup, AvgfillRate, result; + + *SrcActiveDrainRate = VRatio * SwathWidth * Bpp / LineTime; + TSlvSetup = XFCTSlvVupdateOffset + XFCTSlvVupdateWidth + XFCTSlvVreadyOffset; + *TInitXFill = XFCXBUFLatencyTolerance / (1 + XFCFillBWOverhead / 100); + AvgfillRate = *SrcActiveDrainRate * (1 + XFCFillBWOverhead / 100); + *TslvChk = XFCSlvChunkSize / AvgfillRate; + dml_print( + "DML::CalculateRemoteSurfaceFlipDelay: SrcActiveDrainRate: %f\n", + *SrcActiveDrainRate); + dml_print("DML::CalculateRemoteSurfaceFlipDelay: TSlvSetup: %f\n", TSlvSetup); + dml_print("DML::CalculateRemoteSurfaceFlipDelay: TInitXFill: %f\n", *TInitXFill); + dml_print("DML::CalculateRemoteSurfaceFlipDelay: AvgfillRate: %f\n", AvgfillRate); + dml_print("DML::CalculateRemoteSurfaceFlipDelay: TslvChk: %f\n", *TslvChk); + result = 2 * XFCBusTransportTime + TSlvSetup + TCalc + TWait + *TslvChk + *TInitXFill; // TODO: This doesn't seem to match programming guide + dml_print("DML::CalculateRemoteSurfaceFlipDelay: RemoteSurfaceFlipDelay: %f\n", result); + return result; +} + +static double CalculateWriteBackDelay( + enum source_format_class WritebackPixelFormat, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackLumaHTaps, + unsigned int WritebackLumaVTaps, + unsigned int WritebackChromaHTaps, + unsigned int WritebackChromaVTaps, + unsigned int WritebackDestinationWidth) +{ + double CalculateWriteBackDelay = + dml_max( + dml_ceil(WritebackLumaHTaps / 4.0, 1) / WritebackHRatio, + WritebackLumaVTaps * dml_ceil(1.0 / WritebackVRatio, 1) + * dml_ceil( + WritebackDestinationWidth + / 4.0, + 1) + + dml_ceil(1.0 / WritebackVRatio, 1) + * (dml_ceil( + WritebackLumaVTaps + / 4.0, + 1) + 4)); + + if (WritebackPixelFormat != dm_444_32) { + CalculateWriteBackDelay = + dml_max( + CalculateWriteBackDelay, + dml_max( + dml_ceil( + WritebackChromaHTaps + / 2.0, + 1) + / (2 + * WritebackHRatio), + WritebackChromaVTaps + * dml_ceil( + 1 + / (2 + * WritebackVRatio), + 1) + * dml_ceil( + WritebackDestinationWidth + / 2.0 + / 2.0, + 1) + + dml_ceil( + 1 + / (2 + * WritebackVRatio), + 1) + * (dml_ceil( + WritebackChromaVTaps + / 4.0, + 1) + + 4))); + } + return CalculateWriteBackDelay; +} + +static void CalculateActiveRowBandwidth( + bool GPUVMEnable, + enum source_format_class SourcePixelFormat, + double VRatio, + bool DCCEnable, + double LineTime, + unsigned int MetaRowByteLuma, + unsigned int MetaRowByteChroma, + unsigned int meta_row_height_luma, + unsigned int meta_row_height_chroma, + unsigned int PixelPTEBytesPerRowLuma, + unsigned int PixelPTEBytesPerRowChroma, + unsigned int dpte_row_height_luma, + unsigned int dpte_row_height_chroma, + double *meta_row_bw, + double *dpte_row_bw, + double *qual_row_bw) +{ + if (DCCEnable != true) { + *meta_row_bw = 0; + } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { + *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime) + + VRatio / 2 * MetaRowByteChroma + / (meta_row_height_chroma * LineTime); + } else { + *meta_row_bw = VRatio * MetaRowByteLuma / (meta_row_height_luma * LineTime); + } + + if (GPUVMEnable != true) { + *dpte_row_bw = 0; + } else if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { + *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime) + + VRatio / 2 * PixelPTEBytesPerRowChroma + / (dpte_row_height_chroma * LineTime); + } else { + *dpte_row_bw = VRatio * PixelPTEBytesPerRowLuma / (dpte_row_height_luma * LineTime); + } + + if ((SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10)) { + *qual_row_bw = *meta_row_bw + *dpte_row_bw; + } else { + *qual_row_bw = 0; + } +} + +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double UrgentExtraLatency, + double UrgentLatencyPixelDataOnly, + unsigned int GPUVMMaxPageTableLevels, + bool GPUVMEnable, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + unsigned int ImmediateFlipBytes, + double LineTime, + double VRatio, + double Tno_bw, + double PDEAndMetaPTEBytesFrame, + unsigned int MetaRowByte, + unsigned int PixelPTEBytesPerRow, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + double qual_row_bw, + double *DestinationLinesToRequestVMInImmediateFlip, + double *DestinationLinesToRequestRowInImmediateFlip, + double *final_flip_bw, + bool *ImmediateFlipSupportedForPipe) +{ + double min_row_time = 0.0; + + if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { + *DestinationLinesToRequestVMInImmediateFlip = 0.0; + *DestinationLinesToRequestRowInImmediateFlip = 0.0; + *final_flip_bw = qual_row_bw; + *ImmediateFlipSupportedForPipe = true; + } else { + double TimeForFetchingMetaPTEImmediateFlip; + double TimeForFetchingRowInVBlankImmediateFlip; + + if (GPUVMEnable == true) { + mode_lib->vba.ImmediateFlipBW[0] = BandwidthAvailableForImmediateFlip + * ImmediateFlipBytes / TotImmediateFlipBytes; + TimeForFetchingMetaPTEImmediateFlip = + dml_max( + Tno_bw + + PDEAndMetaPTEBytesFrame + / mode_lib->vba.ImmediateFlipBW[0], + dml_max( + UrgentExtraLatency + + UrgentLatencyPixelDataOnly + * (GPUVMMaxPageTableLevels + - 1), + LineTime / 4.0)); + } else { + TimeForFetchingMetaPTEImmediateFlip = 0; + } + + *DestinationLinesToRequestVMInImmediateFlip = dml_floor( + 4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime + 0.125), + 1) / 4.0; + + if ((GPUVMEnable == true || DCCEnable == true)) { + mode_lib->vba.ImmediateFlipBW[0] = BandwidthAvailableForImmediateFlip + * ImmediateFlipBytes / TotImmediateFlipBytes; + TimeForFetchingRowInVBlankImmediateFlip = dml_max( + (MetaRowByte + PixelPTEBytesPerRow) + / mode_lib->vba.ImmediateFlipBW[0], + dml_max(UrgentLatencyPixelDataOnly, LineTime / 4.0)); + } else { + TimeForFetchingRowInVBlankImmediateFlip = 0; + } + + *DestinationLinesToRequestRowInImmediateFlip = dml_floor( + 4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime + 0.125), + 1) / 4.0; + + if (GPUVMEnable == true) { + *final_flip_bw = + dml_max( + PDEAndMetaPTEBytesFrame + / (*DestinationLinesToRequestVMInImmediateFlip + * LineTime), + (MetaRowByte + PixelPTEBytesPerRow) + / (TimeForFetchingRowInVBlankImmediateFlip + * LineTime)); + } else if (MetaRowByte + PixelPTEBytesPerRow > 0) { + *final_flip_bw = (MetaRowByte + PixelPTEBytesPerRow) + / (TimeForFetchingRowInVBlankImmediateFlip * LineTime); + } else { + *final_flip_bw = 0; + } + + if (GPUVMEnable && !DCCEnable) + min_row_time = dpte_row_height * LineTime / VRatio; + else if (!GPUVMEnable && DCCEnable) + min_row_time = meta_row_height * LineTime / VRatio; + else + min_row_time = dml_min(dpte_row_height, meta_row_height) * LineTime + / VRatio; + + if (*DestinationLinesToRequestVMInImmediateFlip >= 8 + || *DestinationLinesToRequestRowInImmediateFlip >= 16 + || TimeForFetchingMetaPTEImmediateFlip + + 2 * TimeForFetchingRowInVBlankImmediateFlip + > min_row_time) + *ImmediateFlipSupportedForPipe = false; + else + *ImmediateFlipSupportedForPipe = true; + } +} + +static unsigned int TruncToValidBPP( + double DecimalBPP, + bool DSCEnabled, + enum output_encoder_class Output, + enum output_format_class Format, + unsigned int DSCInputBitPerComponent) +{ + if (Output == dm_hdmi) { + if (Format == dm_420) { + if (DecimalBPP >= 18) + return 18; + else if (DecimalBPP >= 15) + return 15; + else if (DecimalBPP >= 12) + return 12; + else + return BPP_INVALID; + } else if (Format == dm_444) { + if (DecimalBPP >= 36) + return 36; + else if (DecimalBPP >= 30) + return 30; + else if (DecimalBPP >= 24) + return 24; + else if (DecimalBPP >= 18) + return 18; + else + return BPP_INVALID; + } else { + if (DecimalBPP / 1.5 >= 24) + return 24; + else if (DecimalBPP / 1.5 >= 20) + return 20; + else if (DecimalBPP / 1.5 >= 16) + return 16; + else + return BPP_INVALID; + } + } else { + if (DSCEnabled) { + if (Format == dm_420) { + if (DecimalBPP < 6) + return BPP_INVALID; + else if (DecimalBPP >= 1.5 * DSCInputBitPerComponent - 1 / 16) + return 1.5 * DSCInputBitPerComponent - 1 / 16; + else + return dml_floor(16 * DecimalBPP, 1) / 16; + } else if (Format == dm_n422) { + if (DecimalBPP < 7) + return BPP_INVALID; + else if (DecimalBPP >= 2 * DSCInputBitPerComponent - 1 / 16) + return 2 * DSCInputBitPerComponent - 1 / 16; + else + return dml_floor(16 * DecimalBPP, 1) / 16; + } else { + if (DecimalBPP < 8) + return BPP_INVALID; + else if (DecimalBPP >= 3 * DSCInputBitPerComponent - 1 / 16) + return 3 * DSCInputBitPerComponent - 1 / 16; + else + return dml_floor(16 * DecimalBPP, 1) / 16; + } + } else if (Format == dm_420) { + if (DecimalBPP >= 18) + return 18; + else if (DecimalBPP >= 15) + return 15; + else if (DecimalBPP >= 12) + return 12; + else + return BPP_INVALID; + } else if (Format == dm_s422 || Format == dm_n422) { + if (DecimalBPP >= 24) + return 24; + else if (DecimalBPP >= 20) + return 20; + else if (DecimalBPP >= 16) + return 16; + else + return BPP_INVALID; + } else { + if (DecimalBPP >= 36) + return 36; + else if (DecimalBPP >= 30) + return 30; + else if (DecimalBPP >= 24) + return 24; + else if (DecimalBPP >= 18) + return 18; + else + return BPP_INVALID; + } + } +} + +void dml20_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib) +{ + struct vba_vars_st *locals = &mode_lib->vba; + + int i; + unsigned int j, k, m; + + /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/ + + /*Scale Ratio, taps Support Check*/ + + mode_lib->vba.ScaleRatioAndTapsSupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.ScalerEnabled[k] == false + && ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8) + || mode_lib->vba.HRatio[k] != 1.0 + || mode_lib->vba.htaps[k] != 1.0 + || mode_lib->vba.VRatio[k] != 1.0 + || mode_lib->vba.vtaps[k] != 1.0)) { + mode_lib->vba.ScaleRatioAndTapsSupport = false; + } else if (mode_lib->vba.vtaps[k] < 1.0 || mode_lib->vba.vtaps[k] > 8.0 + || mode_lib->vba.htaps[k] < 1.0 || mode_lib->vba.htaps[k] > 8.0 + || (mode_lib->vba.htaps[k] > 1.0 + && (mode_lib->vba.htaps[k] % 2) == 1) + || mode_lib->vba.HRatio[k] > mode_lib->vba.MaxHSCLRatio + || mode_lib->vba.VRatio[k] > mode_lib->vba.MaxVSCLRatio + || mode_lib->vba.HRatio[k] > mode_lib->vba.htaps[k] + || mode_lib->vba.VRatio[k] > mode_lib->vba.vtaps[k] + || (mode_lib->vba.SourcePixelFormat[k] != dm_444_64 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8 + && (mode_lib->vba.HRatio[k] / 2.0 + > mode_lib->vba.HTAPsChroma[k] + || mode_lib->vba.VRatio[k] / 2.0 + > mode_lib->vba.VTAPsChroma[k]))) { + mode_lib->vba.ScaleRatioAndTapsSupport = false; + } + } + /*Source Format, Pixel Format and Scan Support Check*/ + + mode_lib->vba.SourceFormatPixelAndScanSupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if ((mode_lib->vba.SurfaceTiling[k] == dm_sw_linear + && mode_lib->vba.SourceScan[k] != dm_horz) + || ((mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d + || mode_lib->vba.SurfaceTiling[k] == dm_sw_4kb_d_x + || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d + || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_t + || mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_d_x + || mode_lib->vba.SurfaceTiling[k] == dm_sw_var_d + || mode_lib->vba.SurfaceTiling[k] == dm_sw_var_d_x) + && mode_lib->vba.SourcePixelFormat[k] != dm_444_64) + || (mode_lib->vba.SurfaceTiling[k] == dm_sw_64kb_r_x + && (mode_lib->vba.SourcePixelFormat[k] == dm_mono_8 + || mode_lib->vba.SourcePixelFormat[k] + == dm_420_8 + || mode_lib->vba.SourcePixelFormat[k] + == dm_420_10)) + || (((mode_lib->vba.SurfaceTiling[k] == dm_sw_gfx7_2d_thin_gl + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_gfx7_2d_thin_lvp) + && !((mode_lib->vba.SourcePixelFormat[k] + == dm_444_64 + || mode_lib->vba.SourcePixelFormat[k] + == dm_444_32) + && mode_lib->vba.SourceScan[k] + == dm_horz + && mode_lib->vba.SupportGFX7CompatibleTilingIn32bppAnd64bpp + == true + && mode_lib->vba.DCCEnable[k] + == false)) + || (mode_lib->vba.DCCEnable[k] == true + && (mode_lib->vba.SurfaceTiling[k] + == dm_sw_linear + || mode_lib->vba.SourcePixelFormat[k] + == dm_420_8 + || mode_lib->vba.SourcePixelFormat[k] + == dm_420_10)))) { + mode_lib->vba.SourceFormatPixelAndScanSupport = false; + } + } + /*Bandwidth Support Check*/ + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.SourcePixelFormat[k] == dm_444_64) { + locals->BytePerPixelInDETY[k] = 8.0; + locals->BytePerPixelInDETC[k] = 0.0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { + locals->BytePerPixelInDETY[k] = 4.0; + locals->BytePerPixelInDETC[k] = 0.0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16 + || mode_lib->vba.SourcePixelFormat[k] == dm_mono_16) { + locals->BytePerPixelInDETY[k] = 2.0; + locals->BytePerPixelInDETC[k] = 0.0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_mono_8) { + locals->BytePerPixelInDETY[k] = 1.0; + locals->BytePerPixelInDETC[k] = 0.0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { + locals->BytePerPixelInDETY[k] = 1.0; + locals->BytePerPixelInDETC[k] = 2.0; + } else { + locals->BytePerPixelInDETY[k] = 4.0 / 3; + locals->BytePerPixelInDETC[k] = 8.0 / 3; + } + if (mode_lib->vba.SourceScan[k] == dm_horz) { + locals->SwathWidthYSingleDPP[k] = mode_lib->vba.ViewportWidth[k]; + } else { + locals->SwathWidthYSingleDPP[k] = mode_lib->vba.ViewportHeight[k]; + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->ReadBandwidthLuma[k] = locals->SwathWidthYSingleDPP[k] * dml_ceil(locals->BytePerPixelInDETY[k], 1.0) + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * mode_lib->vba.VRatio[k]; + locals->ReadBandwidthChroma[k] = locals->SwathWidthYSingleDPP[k] / 2 * dml_ceil(locals->BytePerPixelInDETC[k], 2.0) + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * mode_lib->vba.VRatio[k] / 2.0; + locals->ReadBandwidth[k] = locals->ReadBandwidthLuma[k] + locals->ReadBandwidthChroma[k]; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true + && mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { + locals->WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) * 4.0; + } else if (mode_lib->vba.WritebackEnable[k] == true + && mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { + locals->WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) * 3.0; + } else if (mode_lib->vba.WritebackEnable[k] == true) { + locals->WriteBandwidth[k] = mode_lib->vba.WritebackDestinationWidth[k] + * mode_lib->vba.WritebackDestinationHeight[k] + / (mode_lib->vba.WritebackSourceHeight[k] + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) * 1.5; + } else { + locals->WriteBandwidth[k] = 0.0; + } + } + mode_lib->vba.DCCEnabledInAnyPlane = false; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.DCCEnable[k] == true) { + mode_lib->vba.DCCEnabledInAnyPlane = true; + } + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + locals->FabricAndDRAMBandwidthPerState[i] = dml_min( + mode_lib->vba.DRAMSpeedPerState[i] * mode_lib->vba.NumberOfChannels + * mode_lib->vba.DRAMChannelWidth, + mode_lib->vba.FabricClockPerState[i] + * mode_lib->vba.FabricDatapathToDCNDataReturn) / 1000; + locals->ReturnBWToDCNPerState = dml_min(locals->ReturnBusWidth * locals->DCFCLKPerState[i], + locals->FabricAndDRAMBandwidthPerState[i] * 1000) + * locals->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelDataOnly / 100; + + locals->ReturnBWPerState[i] = locals->ReturnBWToDCNPerState; + + if (locals->DCCEnabledInAnyPlane == true && locals->ReturnBWToDCNPerState > locals->DCFCLKPerState[i] * locals->ReturnBusWidth / 4) { + locals->ReturnBWPerState[i] = dml_min(locals->ReturnBWPerState[i], + locals->ReturnBWToDCNPerState * 4 * (1 - locals->UrgentLatency / + ((locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024 + / (locals->ReturnBWToDCNPerState - locals->DCFCLKPerState[i] + * locals->ReturnBusWidth / 4) + locals->UrgentLatency))); + } + locals->CriticalPoint = 2 * locals->ReturnBusWidth * locals->DCFCLKPerState[i] * + locals->UrgentLatency / (locals->ReturnBWToDCNPerState * locals->UrgentLatency + + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024); + + if (locals->DCCEnabledInAnyPlane && locals->CriticalPoint > 1 && locals->CriticalPoint < 4) { + locals->ReturnBWPerState[i] = dml_min(locals->ReturnBWPerState[i], + 4 * locals->ReturnBWToDCNPerState * + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024 + * locals->ReturnBusWidth * locals->DCFCLKPerState[i] * locals->UrgentLatency / + dml_pow((locals->ReturnBWToDCNPerState * locals->UrgentLatency + + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024), 2)); + } + + locals->ReturnBWToDCNPerState = dml_min(locals->ReturnBusWidth * + locals->DCFCLKPerState[i], locals->FabricAndDRAMBandwidthPerState[i] * 1000); + + if (locals->DCCEnabledInAnyPlane == true && locals->ReturnBWToDCNPerState > locals->DCFCLKPerState[i] * locals->ReturnBusWidth / 4) { + locals->ReturnBWPerState[i] = dml_min(locals->ReturnBWPerState[i], + locals->ReturnBWToDCNPerState * 4 * (1 - locals->UrgentLatency / + ((locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024 + / (locals->ReturnBWToDCNPerState - locals->DCFCLKPerState[i] + * locals->ReturnBusWidth / 4) + locals->UrgentLatency))); + } + locals->CriticalPoint = 2 * locals->ReturnBusWidth * locals->DCFCLKPerState[i] * + locals->UrgentLatency / (locals->ReturnBWToDCNPerState * locals->UrgentLatency + + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024); + + if (locals->DCCEnabledInAnyPlane && locals->CriticalPoint > 1 && locals->CriticalPoint < 4) { + locals->ReturnBWPerState[i] = dml_min(locals->ReturnBWPerState[i], + 4 * locals->ReturnBWToDCNPerState * + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024 + * locals->ReturnBusWidth * locals->DCFCLKPerState[i] * locals->UrgentLatency / + dml_pow((locals->ReturnBWToDCNPerState * locals->UrgentLatency + + (locals->ROBBufferSizeInKByte - locals->PixelChunkSizeInKByte) * 1024), 2)); + } + } + /*Writeback Latency support check*/ + + mode_lib->vba.WritebackLatencySupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true) { + if (mode_lib->vba.WritebackPixelFormat[k] == dm_444_32) { + if (locals->WriteBandwidth[k] + > (mode_lib->vba.WritebackInterfaceLumaBufferSize + + mode_lib->vba.WritebackInterfaceChromaBufferSize) + / mode_lib->vba.WritebackLatency) { + mode_lib->vba.WritebackLatencySupport = false; + } + } else { + if (locals->WriteBandwidth[k] + > 1.5 + * dml_min( + mode_lib->vba.WritebackInterfaceLumaBufferSize, + 2.0 + * mode_lib->vba.WritebackInterfaceChromaBufferSize) + / mode_lib->vba.WritebackLatency) { + mode_lib->vba.WritebackLatencySupport = false; + } + } + } + } + /*Re-ordering Buffer Support Check*/ + + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + locals->UrgentRoundTripAndOutOfOrderLatencyPerState[i] = + (mode_lib->vba.RoundTripPingLatencyCycles + 32.0) / mode_lib->vba.DCFCLKPerState[i] + + locals->UrgentOutOfOrderReturnPerChannel * mode_lib->vba.NumberOfChannels / locals->ReturnBWPerState[i]; + if ((mode_lib->vba.ROBBufferSizeInKByte - mode_lib->vba.PixelChunkSizeInKByte) * 1024.0 / locals->ReturnBWPerState[i] + > locals->UrgentRoundTripAndOutOfOrderLatencyPerState[i]) { + locals->ROBSupport[i] = true; + } else { + locals->ROBSupport[i] = false; + } + } + /*Writeback Mode Support Check*/ + + mode_lib->vba.TotalNumberOfActiveWriteback = 0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true) { + if (mode_lib->vba.ActiveWritebacksPerPlane[k] == 0) + mode_lib->vba.ActiveWritebacksPerPlane[k] = 1; + mode_lib->vba.TotalNumberOfActiveWriteback = + mode_lib->vba.TotalNumberOfActiveWriteback + + mode_lib->vba.ActiveWritebacksPerPlane[k]; + } + } + mode_lib->vba.WritebackModeSupport = true; + if (mode_lib->vba.TotalNumberOfActiveWriteback > mode_lib->vba.MaxNumWriteback) { + mode_lib->vba.WritebackModeSupport = false; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true + && mode_lib->vba.Writeback10bpc420Supported != true + && mode_lib->vba.WritebackPixelFormat[k] == dm_420_10) { + mode_lib->vba.WritebackModeSupport = false; + } + } + /*Writeback Scale Ratio and Taps Support Check*/ + + mode_lib->vba.WritebackScaleRatioAndTapsSupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true) { + if (mode_lib->vba.WritebackLumaAndChromaScalingSupported == false + && (mode_lib->vba.WritebackHRatio[k] != 1.0 + || mode_lib->vba.WritebackVRatio[k] != 1.0)) { + mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; + } + if (mode_lib->vba.WritebackHRatio[k] > mode_lib->vba.WritebackMaxHSCLRatio + || mode_lib->vba.WritebackVRatio[k] + > mode_lib->vba.WritebackMaxVSCLRatio + || mode_lib->vba.WritebackHRatio[k] + < mode_lib->vba.WritebackMinHSCLRatio + || mode_lib->vba.WritebackVRatio[k] + < mode_lib->vba.WritebackMinVSCLRatio + || mode_lib->vba.WritebackLumaHTaps[k] + > mode_lib->vba.WritebackMaxHSCLTaps + || mode_lib->vba.WritebackLumaVTaps[k] + > mode_lib->vba.WritebackMaxVSCLTaps + || mode_lib->vba.WritebackHRatio[k] + > mode_lib->vba.WritebackLumaHTaps[k] + || mode_lib->vba.WritebackVRatio[k] + > mode_lib->vba.WritebackLumaVTaps[k] + || (mode_lib->vba.WritebackLumaHTaps[k] > 2.0 + && ((mode_lib->vba.WritebackLumaHTaps[k] % 2) + == 1)) + || (mode_lib->vba.WritebackPixelFormat[k] != dm_444_32 + && (mode_lib->vba.WritebackChromaHTaps[k] + > mode_lib->vba.WritebackMaxHSCLTaps + || mode_lib->vba.WritebackChromaVTaps[k] + > mode_lib->vba.WritebackMaxVSCLTaps + || 2.0 + * mode_lib->vba.WritebackHRatio[k] + > mode_lib->vba.WritebackChromaHTaps[k] + || 2.0 + * mode_lib->vba.WritebackVRatio[k] + > mode_lib->vba.WritebackChromaVTaps[k] + || (mode_lib->vba.WritebackChromaHTaps[k] > 2.0 + && ((mode_lib->vba.WritebackChromaHTaps[k] % 2) == 1))))) { + mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; + } + if (mode_lib->vba.WritebackVRatio[k] < 1.0) { + mode_lib->vba.WritebackLumaVExtra = + dml_max(1.0 - 2.0 / dml_ceil(1.0 / mode_lib->vba.WritebackVRatio[k], 1.0), 0.0); + } else { + mode_lib->vba.WritebackLumaVExtra = -1; + } + if ((mode_lib->vba.WritebackPixelFormat[k] == dm_444_32 + && mode_lib->vba.WritebackLumaVTaps[k] + > (mode_lib->vba.WritebackLineBufferLumaBufferSize + + mode_lib->vba.WritebackLineBufferChromaBufferSize) + / 3.0 + / mode_lib->vba.WritebackDestinationWidth[k] + - mode_lib->vba.WritebackLumaVExtra) + || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_8 + && mode_lib->vba.WritebackLumaVTaps[k] + > mode_lib->vba.WritebackLineBufferLumaBufferSize + * 8.0 / 10.0 / mode_lib->vba.WritebackDestinationWidth[k] + - mode_lib->vba.WritebackLumaVExtra) + || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10 + && mode_lib->vba.WritebackLumaVTaps[k] + > mode_lib->vba.WritebackLineBufferLumaBufferSize + * 8.0 / 10.0 + / mode_lib->vba.WritebackDestinationWidth[k] + - mode_lib->vba.WritebackLumaVExtra)) { + mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; + } + if (2.0 * mode_lib->vba.WritebackVRatio[k] < 1) { + mode_lib->vba.WritebackChromaVExtra = 0.0; + } else { + mode_lib->vba.WritebackChromaVExtra = -1; + } + if ((mode_lib->vba.WritebackPixelFormat[k] == dm_420_8 + && mode_lib->vba.WritebackChromaVTaps[k] + > mode_lib->vba.WritebackLineBufferChromaBufferSize + * 8.0 / 10.0 / mode_lib->vba.WritebackDestinationWidth[k] + - mode_lib->vba.WritebackChromaVExtra) + || (mode_lib->vba.WritebackPixelFormat[k] == dm_420_10 + && mode_lib->vba.WritebackChromaVTaps[k] + > mode_lib->vba.WritebackLineBufferChromaBufferSize + * 8.0 / 10.0 + / mode_lib->vba.WritebackDestinationWidth[k] + - mode_lib->vba.WritebackChromaVExtra)) { + mode_lib->vba.WritebackScaleRatioAndTapsSupport = false; + } + } + } + /*Maximum DISPCLK/DPPCLK Support check*/ + + mode_lib->vba.WritebackRequiredDISPCLK = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.WritebackEnable[k] == true) { + mode_lib->vba.WritebackRequiredDISPCLK = + dml_max( + mode_lib->vba.WritebackRequiredDISPCLK, + CalculateWriteBackDISPCLK( + mode_lib->vba.WritebackPixelFormat[k], + mode_lib->vba.PixelClock[k], + mode_lib->vba.WritebackHRatio[k], + mode_lib->vba.WritebackVRatio[k], + mode_lib->vba.WritebackLumaHTaps[k], + mode_lib->vba.WritebackLumaVTaps[k], + mode_lib->vba.WritebackChromaHTaps[k], + mode_lib->vba.WritebackChromaVTaps[k], + mode_lib->vba.WritebackDestinationWidth[k], + mode_lib->vba.HTotal[k], + mode_lib->vba.WritebackChromaLineBufferWidth)); + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.HRatio[k] > 1.0) { + locals->PSCL_FACTOR[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput + * mode_lib->vba.HRatio[k] + / dml_ceil( + mode_lib->vba.htaps[k] + / 6.0, + 1.0)); + } else { + locals->PSCL_FACTOR[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput); + } + if (locals->BytePerPixelInDETC[k] == 0.0) { + locals->PSCL_FACTOR_CHROMA[k] = 0.0; + locals->MinDPPCLKUsingSingleDPP[k] = + mode_lib->vba.PixelClock[k] + * dml_max3( + mode_lib->vba.vtaps[k] / 6.0 + * dml_min( + 1.0, + mode_lib->vba.HRatio[k]), + mode_lib->vba.HRatio[k] + * mode_lib->vba.VRatio[k] + / locals->PSCL_FACTOR[k], + 1.0); + if ((mode_lib->vba.htaps[k] > 6.0 || mode_lib->vba.vtaps[k] > 6.0) + && locals->MinDPPCLKUsingSingleDPP[k] + < 2.0 * mode_lib->vba.PixelClock[k]) { + locals->MinDPPCLKUsingSingleDPP[k] = 2.0 + * mode_lib->vba.PixelClock[k]; + } + } else { + if (mode_lib->vba.HRatio[k] / 2.0 > 1.0) { + locals->PSCL_FACTOR_CHROMA[k] = + dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput + * mode_lib->vba.HRatio[k] + / 2.0 + / dml_ceil( + mode_lib->vba.HTAPsChroma[k] + / 6.0, + 1.0)); + } else { + locals->PSCL_FACTOR_CHROMA[k] = dml_min( + mode_lib->vba.MaxDCHUBToPSCLThroughput, + mode_lib->vba.MaxPSCLToLBThroughput); + } + locals->MinDPPCLKUsingSingleDPP[k] = + mode_lib->vba.PixelClock[k] + * dml_max5( + mode_lib->vba.vtaps[k] / 6.0 + * dml_min( + 1.0, + mode_lib->vba.HRatio[k]), + mode_lib->vba.HRatio[k] + * mode_lib->vba.VRatio[k] + / locals->PSCL_FACTOR[k], + mode_lib->vba.VTAPsChroma[k] + / 6.0 + * dml_min( + 1.0, + mode_lib->vba.HRatio[k] + / 2.0), + mode_lib->vba.HRatio[k] + * mode_lib->vba.VRatio[k] + / 4.0 + / locals->PSCL_FACTOR_CHROMA[k], + 1.0); + if ((mode_lib->vba.htaps[k] > 6.0 || mode_lib->vba.vtaps[k] > 6.0 + || mode_lib->vba.HTAPsChroma[k] > 6.0 + || mode_lib->vba.VTAPsChroma[k] > 6.0) + && locals->MinDPPCLKUsingSingleDPP[k] + < 2.0 * mode_lib->vba.PixelClock[k]) { + locals->MinDPPCLKUsingSingleDPP[k] = 2.0 + * mode_lib->vba.PixelClock[k]; + } + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + Calculate256BBlockSizes( + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(locals->BytePerPixelInDETY[k], 1.0), + dml_ceil(locals->BytePerPixelInDETC[k], 2.0), + &locals->Read256BlockHeightY[k], + &locals->Read256BlockHeightC[k], + &locals->Read256BlockWidthY[k], + &locals->Read256BlockWidthC[k]); + if (mode_lib->vba.SourceScan[k] == dm_horz) { + locals->MaxSwathHeightY[k] = locals->Read256BlockHeightY[k]; + locals->MaxSwathHeightC[k] = locals->Read256BlockHeightC[k]; + } else { + locals->MaxSwathHeightY[k] = locals->Read256BlockWidthY[k]; + locals->MaxSwathHeightC[k] = locals->Read256BlockWidthC[k]; + } + if ((mode_lib->vba.SourcePixelFormat[k] == dm_444_64 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_32 + || mode_lib->vba.SourcePixelFormat[k] == dm_444_16 + || mode_lib->vba.SourcePixelFormat[k] == dm_mono_16 + || mode_lib->vba.SourcePixelFormat[k] == dm_mono_8)) { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear + || (mode_lib->vba.SourcePixelFormat[k] == dm_444_64 + && (mode_lib->vba.SurfaceTiling[k] + == dm_sw_4kb_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_4kb_s_x + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s_t + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_64kb_s_x + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_var_s + || mode_lib->vba.SurfaceTiling[k] + == dm_sw_var_s_x) + && mode_lib->vba.SourceScan[k] == dm_horz)) { + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k]; + } else { + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k] + / 2.0; + } + locals->MinSwathHeightC[k] = locals->MaxSwathHeightC[k]; + } else { + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k]; + locals->MinSwathHeightC[k] = locals->MaxSwathHeightC[k]; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8 + && mode_lib->vba.SourceScan[k] == dm_horz) { + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k] + / 2.0; + locals->MinSwathHeightC[k] = locals->MaxSwathHeightC[k]; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10 + && mode_lib->vba.SourceScan[k] == dm_horz) { + locals->MinSwathHeightC[k] = locals->MaxSwathHeightC[k] + / 2.0; + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k]; + } else { + locals->MinSwathHeightY[k] = locals->MaxSwathHeightY[k]; + locals->MinSwathHeightC[k] = locals->MaxSwathHeightC[k]; + } + } + if (mode_lib->vba.SurfaceTiling[k] == dm_sw_linear) { + mode_lib->vba.MaximumSwathWidthSupport = 8192.0; + } else { + mode_lib->vba.MaximumSwathWidthSupport = 5120.0; + } + mode_lib->vba.MaximumSwathWidthInDETBuffer = + dml_min( + mode_lib->vba.MaximumSwathWidthSupport, + mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0 + / (locals->BytePerPixelInDETY[k] + * locals->MinSwathHeightY[k] + + locals->BytePerPixelInDETC[k] + / 2.0 + * locals->MinSwathHeightC[k])); + if (locals->BytePerPixelInDETC[k] == 0.0) { + mode_lib->vba.MaximumSwathWidthInLineBuffer = + mode_lib->vba.LineBufferSize + * dml_max(mode_lib->vba.HRatio[k], 1.0) + / mode_lib->vba.LBBitPerPixel[k] + / (mode_lib->vba.vtaps[k] + + dml_max( + dml_ceil( + mode_lib->vba.VRatio[k], + 1.0) + - 2, + 0.0)); + } else { + mode_lib->vba.MaximumSwathWidthInLineBuffer = + dml_min( + mode_lib->vba.LineBufferSize + * dml_max( + mode_lib->vba.HRatio[k], + 1.0) + / mode_lib->vba.LBBitPerPixel[k] + / (mode_lib->vba.vtaps[k] + + dml_max( + dml_ceil( + mode_lib->vba.VRatio[k], + 1.0) + - 2, + 0.0)), + 2.0 * mode_lib->vba.LineBufferSize + * dml_max( + mode_lib->vba.HRatio[k] + / 2.0, + 1.0) + / mode_lib->vba.LBBitPerPixel[k] + / (mode_lib->vba.VTAPsChroma[k] + + dml_max( + dml_ceil( + mode_lib->vba.VRatio[k] + / 2.0, + 1.0) + - 2, + 0.0))); + } + locals->MaximumSwathWidth[k] = dml_min( + mode_lib->vba.MaximumSwathWidthInDETBuffer, + mode_lib->vba.MaximumSwathWidthInLineBuffer); + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (j = 0; j < 2; j++) { + mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown( + mode_lib->vba.MaxDispclk[i], + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown( + mode_lib->vba.MaxDppclk[i], + mode_lib->vba.DISPCLKDPPCLKVCOSpeed); + locals->RequiredDISPCLK[i][j] = 0.0; + locals->DISPCLK_DPPCLK_Support[i][j] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine = + mode_lib->vba.PixelClock[k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1.0 + mode_lib->vba.DISPCLKRampingMargin / 100.0); + if (mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine >= mode_lib->vba.MaxDispclk[i] + && i == mode_lib->vba.soc.num_states) + mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine = mode_lib->vba.PixelClock[k] + * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + + mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine = mode_lib->vba.PixelClock[k] / 2 + * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * (1 + mode_lib->vba.DISPCLKRampingMargin / 100.0); + if (mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine >= mode_lib->vba.MaxDispclk[i] + && i == mode_lib->vba.soc.num_states) + mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine = mode_lib->vba.PixelClock[k] / 2 + * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + if (mode_lib->vba.ODMCapability == false || mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine <= mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity) { + locals->ODMCombineEnablePerState[i][k] = false; + mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithoutODMCombine; + } else { + locals->ODMCombineEnablePerState[i][k] = true; + mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PlaneRequiredDISPCLKWithODMCombine; + } + if (locals->MinDPPCLKUsingSingleDPP[k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) <= mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity + && locals->SwathWidthYSingleDPP[k] <= locals->MaximumSwathWidth[k] + && locals->ODMCombineEnablePerState[i][k] == false) { + locals->NoOfDPP[i][j][k] = 1; + locals->RequiredDPPCLK[i][j][k] = + locals->MinDPPCLKUsingSingleDPP[k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } else { + locals->NoOfDPP[i][j][k] = 2; + locals->RequiredDPPCLK[i][j][k] = + locals->MinDPPCLKUsingSingleDPP[k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 2.0; + } + locals->RequiredDISPCLK[i][j] = dml_max( + locals->RequiredDISPCLK[i][j], + mode_lib->vba.PlaneRequiredDISPCLK); + if ((locals->MinDPPCLKUsingSingleDPP[k] / locals->NoOfDPP[i][j][k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + > mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity) + || (mode_lib->vba.PlaneRequiredDISPCLK > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity)) { + locals->DISPCLK_DPPCLK_Support[i][j] = false; + } + } + locals->TotalNumberOfActiveDPP[i][j] = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) + locals->TotalNumberOfActiveDPP[i][j] = locals->TotalNumberOfActiveDPP[i][j] + locals->NoOfDPP[i][j][k]; + if (j == 1) { + while (locals->TotalNumberOfActiveDPP[i][j] < mode_lib->vba.MaxNumDPP + && locals->TotalNumberOfActiveDPP[i][j] < 2 * mode_lib->vba.NumberOfActivePlanes) { + double BWOfNonSplitPlaneOfMaximumBandwidth; + unsigned int NumberOfNonSplitPlaneOfMaximumBandwidth; + + BWOfNonSplitPlaneOfMaximumBandwidth = 0; + NumberOfNonSplitPlaneOfMaximumBandwidth = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (locals->ReadBandwidth[k] > BWOfNonSplitPlaneOfMaximumBandwidth && locals->NoOfDPP[i][j][k] == 1) { + BWOfNonSplitPlaneOfMaximumBandwidth = locals->ReadBandwidth[k]; + NumberOfNonSplitPlaneOfMaximumBandwidth = k; + } + } + locals->NoOfDPP[i][j][NumberOfNonSplitPlaneOfMaximumBandwidth] = 2; + locals->RequiredDPPCLK[i][j][NumberOfNonSplitPlaneOfMaximumBandwidth] = + locals->MinDPPCLKUsingSingleDPP[NumberOfNonSplitPlaneOfMaximumBandwidth] + * (1 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100) / 2; + locals->TotalNumberOfActiveDPP[i][j] = locals->TotalNumberOfActiveDPP[i][j] + 1; + } + } + if (locals->TotalNumberOfActiveDPP[i][j] > mode_lib->vba.MaxNumDPP) { + locals->RequiredDISPCLK[i][j] = 0.0; + locals->DISPCLK_DPPCLK_Support[i][j] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->ODMCombineEnablePerState[i][k] = false; + if (locals->SwathWidthYSingleDPP[k] <= locals->MaximumSwathWidth[k]) { + locals->NoOfDPP[i][j][k] = 1; + locals->RequiredDPPCLK[i][j][k] = locals->MinDPPCLKUsingSingleDPP[k] + * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } else { + locals->NoOfDPP[i][j][k] = 2; + locals->RequiredDPPCLK[i][j][k] = locals->MinDPPCLKUsingSingleDPP[k] + * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) / 2.0; + } + if (i != mode_lib->vba.soc.num_states) { + mode_lib->vba.PlaneRequiredDISPCLK = + mode_lib->vba.PixelClock[k] + * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + * (1.0 + mode_lib->vba.DISPCLKRampingMargin / 100.0); + } else { + mode_lib->vba.PlaneRequiredDISPCLK = mode_lib->vba.PixelClock[k] + * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0); + } + locals->RequiredDISPCLK[i][j] = dml_max( + locals->RequiredDISPCLK[i][j], + mode_lib->vba.PlaneRequiredDISPCLK); + if (locals->MinDPPCLKUsingSingleDPP[k] / locals->NoOfDPP[i][j][k] * (1.0 + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) + > mode_lib->vba.MaxDppclkRoundedDownToDFSGranularity + || mode_lib->vba.PlaneRequiredDISPCLK > mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity) + locals->DISPCLK_DPPCLK_Support[i][j] = false; + } + locals->TotalNumberOfActiveDPP[i][j] = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) + locals->TotalNumberOfActiveDPP[i][j] = locals->TotalNumberOfActiveDPP[i][j] + locals->NoOfDPP[i][j][k]; + } + locals->RequiredDISPCLK[i][j] = dml_max( + locals->RequiredDISPCLK[i][j], + mode_lib->vba.WritebackRequiredDISPCLK); + if (mode_lib->vba.MaxDispclkRoundedDownToDFSGranularity + < mode_lib->vba.WritebackRequiredDISPCLK) { + locals->DISPCLK_DPPCLK_Support[i][j] = false; + } + } + } + /*Viewport Size Check*/ + + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + locals->ViewportSizeSupport[i] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->ODMCombineEnablePerState[i][k] == true) { + if (dml_min(locals->SwathWidthYSingleDPP[k], dml_round(mode_lib->vba.HActive[k] / 2.0 * mode_lib->vba.HRatio[k])) + > locals->MaximumSwathWidth[k]) { + locals->ViewportSizeSupport[i] = false; + } + } else { + if (locals->SwathWidthYSingleDPP[k] / 2.0 > locals->MaximumSwathWidth[k]) { + locals->ViewportSizeSupport[i] = false; + } + } + } + } + /*Total Available Pipes Support Check*/ + + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (j = 0; j < 2; j++) { + if (locals->TotalNumberOfActiveDPP[i][j] <= mode_lib->vba.MaxNumDPP) + locals->TotalAvailablePipesSupport[i][j] = true; + else + locals->TotalAvailablePipesSupport[i][j] = false; + } + } + /*Total Available OTG Support Check*/ + + mode_lib->vba.TotalNumberOfActiveOTG = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.BlendingAndTiming[k] == k) { + mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG + + 1.0; + } + } + if (mode_lib->vba.TotalNumberOfActiveOTG <= mode_lib->vba.MaxNumOTG) { + mode_lib->vba.NumberOfOTGSupport = true; + } else { + mode_lib->vba.NumberOfOTGSupport = false; + } + /*Display IO and DSC Support Check*/ + + mode_lib->vba.NonsupportedDSCInputBPC = false; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (!(mode_lib->vba.DSCInputBitPerComponent[k] == 12.0 + || mode_lib->vba.DSCInputBitPerComponent[k] == 10.0 + || mode_lib->vba.DSCInputBitPerComponent[k] == 8.0)) { + mode_lib->vba.NonsupportedDSCInputBPC = true; + } + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->RequiresDSC[i][k] = 0; + locals->RequiresFEC[i][k] = 0; + if (mode_lib->vba.BlendingAndTiming[k] == k) { + if (mode_lib->vba.Output[k] == dm_hdmi) { + locals->RequiresDSC[i][k] = 0; + locals->RequiresFEC[i][k] = 0; + locals->OutputBppPerState[i][k] = TruncToValidBPP( + dml_min(600.0, mode_lib->vba.PHYCLKPerState[i]) / mode_lib->vba.PixelClockBackEnd[k] * 24, + false, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + } else if (mode_lib->vba.Output[k] == dm_dp + || mode_lib->vba.Output[k] == dm_edp) { + if (mode_lib->vba.Output[k] == dm_edp) { + mode_lib->vba.EffectiveFECOverhead = 0.0; + } else { + mode_lib->vba.EffectiveFECOverhead = + mode_lib->vba.FECOverhead; + } + if (mode_lib->vba.PHYCLKPerState[i] >= 270.0) { + mode_lib->vba.Outbpp = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * 270.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + false, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + mode_lib->vba.OutbppDSC = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 270.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + true, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + if (mode_lib->vba.DSCEnabled[k] == true) { + locals->RequiresDSC[i][k] = true; + if (mode_lib->vba.Output[k] == dm_dp) { + locals->RequiresFEC[i][k] = true; + } else { + locals->RequiresFEC[i][k] = false; + } + mode_lib->vba.Outbpp = mode_lib->vba.OutbppDSC; + } else { + locals->RequiresDSC[i][k] = false; + locals->RequiresFEC[i][k] = false; + } + locals->OutputBppPerState[i][k] = mode_lib->vba.Outbpp; + } + if (mode_lib->vba.Outbpp == BPP_INVALID && mode_lib->vba.PHYCLKPerState[i] >= 540.0) { + mode_lib->vba.Outbpp = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * 540.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + false, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + mode_lib->vba.OutbppDSC = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 540.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + true, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + if (mode_lib->vba.DSCEnabled[k] == true) { + locals->RequiresDSC[i][k] = true; + if (mode_lib->vba.Output[k] == dm_dp) { + locals->RequiresFEC[i][k] = true; + } else { + locals->RequiresFEC[i][k] = false; + } + mode_lib->vba.Outbpp = mode_lib->vba.OutbppDSC; + } else { + locals->RequiresDSC[i][k] = false; + locals->RequiresFEC[i][k] = false; + } + locals->OutputBppPerState[i][k] = mode_lib->vba.Outbpp; + } + if (mode_lib->vba.Outbpp == BPP_INVALID + && mode_lib->vba.PHYCLKPerState[i] + >= 810.0) { + mode_lib->vba.Outbpp = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * 810.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + false, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + mode_lib->vba.OutbppDSC = TruncToValidBPP( + (1.0 - mode_lib->vba.Downspreading / 100.0) * (1.0 - mode_lib->vba.EffectiveFECOverhead / 100.0) * 810.0 + * mode_lib->vba.OutputLinkDPLanes[k] / mode_lib->vba.PixelClockBackEnd[k] * 8.0, + true, + mode_lib->vba.Output[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.DSCInputBitPerComponent[k]); + if (mode_lib->vba.DSCEnabled[k] == true || mode_lib->vba.Outbpp == BPP_INVALID) { + locals->RequiresDSC[i][k] = true; + if (mode_lib->vba.Output[k] == dm_dp) { + locals->RequiresFEC[i][k] = true; + } else { + locals->RequiresFEC[i][k] = false; + } + mode_lib->vba.Outbpp = mode_lib->vba.OutbppDSC; + } else { + locals->RequiresDSC[i][k] = false; + locals->RequiresFEC[i][k] = false; + } + locals->OutputBppPerState[i][k] = + mode_lib->vba.Outbpp; + } + } + } else { + locals->OutputBppPerState[i][k] = BPP_BLENDED_PIPE; + } + } + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + locals->DIOSupport[i] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->OutputBppPerState[i][k] == BPP_INVALID + || (mode_lib->vba.OutputFormat[k] == dm_420 + && mode_lib->vba.Interlace[k] == true + && mode_lib->vba.ProgressiveToInterlaceUnitInOPP == true)) { + locals->DIOSupport[i] = false; + } + } + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->DSCCLKRequiredMoreThanSupported[i] = false; + if (mode_lib->vba.BlendingAndTiming[k] == k) { + if ((mode_lib->vba.Output[k] == dm_dp + || mode_lib->vba.Output[k] == dm_edp)) { + if (mode_lib->vba.OutputFormat[k] == dm_420 + || mode_lib->vba.OutputFormat[k] + == dm_n422) { + mode_lib->vba.DSCFormatFactor = 2; + } else { + mode_lib->vba.DSCFormatFactor = 1; + } + if (locals->RequiresDSC[i][k] == true) { + if (locals->ODMCombineEnablePerState[i][k] + == true) { + if (mode_lib->vba.PixelClockBackEnd[k] / 6.0 / mode_lib->vba.DSCFormatFactor + > (1.0 - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * mode_lib->vba.MaxDSCCLK[i]) { + locals->DSCCLKRequiredMoreThanSupported[i] = + true; + } + } else { + if (mode_lib->vba.PixelClockBackEnd[k] / 3.0 / mode_lib->vba.DSCFormatFactor + > (1.0 - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading / 100.0) * mode_lib->vba.MaxDSCCLK[i]) { + locals->DSCCLKRequiredMoreThanSupported[i] = + true; + } + } + } + } + } + } + } + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + locals->NotEnoughDSCUnits[i] = false; + mode_lib->vba.TotalDSCUnitsRequired = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->RequiresDSC[i][k] == true) { + if (locals->ODMCombineEnablePerState[i][k] == true) { + mode_lib->vba.TotalDSCUnitsRequired = + mode_lib->vba.TotalDSCUnitsRequired + 2.0; + } else { + mode_lib->vba.TotalDSCUnitsRequired = + mode_lib->vba.TotalDSCUnitsRequired + 1.0; + } + } + } + if (mode_lib->vba.TotalDSCUnitsRequired > mode_lib->vba.NumberOfDSC) { + locals->NotEnoughDSCUnits[i] = true; + } + } + /*DSC Delay per state*/ + + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.BlendingAndTiming[k] != k) { + mode_lib->vba.slices = 0; + } else if (locals->RequiresDSC[i][k] == 0 + || locals->RequiresDSC[i][k] == false) { + mode_lib->vba.slices = 0; + } else if (mode_lib->vba.PixelClockBackEnd[k] > 3200.0) { + mode_lib->vba.slices = dml_ceil( + mode_lib->vba.PixelClockBackEnd[k] / 400.0, + 4.0); + } else if (mode_lib->vba.PixelClockBackEnd[k] > 1360.0) { + mode_lib->vba.slices = 8.0; + } else if (mode_lib->vba.PixelClockBackEnd[k] > 680.0) { + mode_lib->vba.slices = 4.0; + } else if (mode_lib->vba.PixelClockBackEnd[k] > 340.0) { + mode_lib->vba.slices = 2.0; + } else { + mode_lib->vba.slices = 1.0; + } + if (locals->OutputBppPerState[i][k] == BPP_BLENDED_PIPE + || locals->OutputBppPerState[i][k] == BPP_INVALID) { + mode_lib->vba.bpp = 0.0; + } else { + mode_lib->vba.bpp = locals->OutputBppPerState[i][k]; + } + if (locals->RequiresDSC[i][k] == true && mode_lib->vba.bpp != 0.0) { + if (locals->ODMCombineEnablePerState[i][k] == false) { + locals->DSCDelayPerState[i][k] = + dscceComputeDelay( + mode_lib->vba.DSCInputBitPerComponent[k], + mode_lib->vba.bpp, + dml_ceil( + mode_lib->vba.HActive[k] + / mode_lib->vba.slices, + 1.0), + mode_lib->vba.slices, + mode_lib->vba.OutputFormat[k]) + + dscComputeDelay( + mode_lib->vba.OutputFormat[k]); + } else { + locals->DSCDelayPerState[i][k] = + 2.0 * (dscceComputeDelay( + mode_lib->vba.DSCInputBitPerComponent[k], + mode_lib->vba.bpp, + dml_ceil(mode_lib->vba.HActive[k] / mode_lib->vba.slices, 1.0), + mode_lib->vba.slices / 2, + mode_lib->vba.OutputFormat[k]) + + dscComputeDelay(mode_lib->vba.OutputFormat[k])); + } + locals->DSCDelayPerState[i][k] = + locals->DSCDelayPerState[i][k] * mode_lib->vba.PixelClock[k] / mode_lib->vba.PixelClockBackEnd[k]; + } else { + locals->DSCDelayPerState[i][k] = 0.0; + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + for (m = 0; m <= mode_lib->vba.NumberOfActivePlanes - 1; m++) { + for (j = 0; j <= mode_lib->vba.NumberOfActivePlanes - 1; j++) { + if (mode_lib->vba.BlendingAndTiming[k] == m && locals->RequiresDSC[i][m] == true) + locals->DSCDelayPerState[i][k] = locals->DSCDelayPerState[i][m]; + } + } + } + } + + //Prefetch Check + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->ODMCombineEnablePerState[i][k] == true) + locals->SwathWidthYPerState[i][j][k] = dml_min(locals->SwathWidthYSingleDPP[k], dml_round(locals->HActive[k] / 2 * locals->HRatio[k])); + else + locals->SwathWidthYPerState[i][j][k] = locals->SwathWidthYSingleDPP[k] / locals->NoOfDPP[i][j][k]; + locals->SwathWidthGranularityY = 256 / dml_ceil(locals->BytePerPixelInDETY[k], 1) / locals->MaxSwathHeightY[k]; + locals->RoundedUpMaxSwathSizeBytesY = (dml_ceil(locals->SwathWidthYPerState[i][j][k] - 1, locals->SwathWidthGranularityY) + + locals->SwathWidthGranularityY) * locals->BytePerPixelInDETY[k] * locals->MaxSwathHeightY[k]; + if (locals->SourcePixelFormat[k] == dm_420_10) { + locals->RoundedUpMaxSwathSizeBytesY = dml_ceil(locals->RoundedUpMaxSwathSizeBytesY, 256) + 256; + } + if (locals->MaxSwathHeightC[k] > 0) { + locals->SwathWidthGranularityC = 256 / dml_ceil(locals->BytePerPixelInDETC[k], 2) / locals->MaxSwathHeightC[k]; + + locals->RoundedUpMaxSwathSizeBytesC = (dml_ceil(locals->SwathWidthYPerState[i][j][k] / 2 - 1, locals->SwathWidthGranularityC) + + locals->SwathWidthGranularityC) * locals->BytePerPixelInDETC[k] * locals->MaxSwathHeightC[k]; + } + if (locals->SourcePixelFormat[k] == dm_420_10) { + locals->RoundedUpMaxSwathSizeBytesC = dml_ceil(locals->RoundedUpMaxSwathSizeBytesC, 256) + 256; + } else { + locals->RoundedUpMaxSwathSizeBytesC = 0; + } + + if (locals->RoundedUpMaxSwathSizeBytesY + locals->RoundedUpMaxSwathSizeBytesC <= locals->DETBufferSizeInKByte * 1024 / 2) { + locals->SwathHeightYPerState[i][j][k] = locals->MaxSwathHeightY[k]; + locals->SwathHeightCPerState[i][j][k] = locals->MaxSwathHeightC[k]; + } else { + locals->SwathHeightYPerState[i][j][k] = locals->MinSwathHeightY[k]; + locals->SwathHeightCPerState[i][j][k] = locals->MinSwathHeightC[k]; + } + + if (locals->BytePerPixelInDETC[k] == 0) { + locals->LinesInDETLuma = locals->DETBufferSizeInKByte * 1024 / locals->BytePerPixelInDETY[k] / locals->SwathWidthYPerState[i][j][k]; + locals->LinesInDETChroma = 0; + } else if (locals->SwathHeightYPerState[i][j][k] <= locals->SwathHeightCPerState[i][j][k]) { + locals->LinesInDETLuma = locals->DETBufferSizeInKByte * 1024 / 2 / locals->BytePerPixelInDETY[k] / + locals->SwathWidthYPerState[i][j][k]; + locals->LinesInDETChroma = locals->DETBufferSizeInKByte * 1024 / 2 / locals->BytePerPixelInDETC[k] / (locals->SwathWidthYPerState[i][j][k] / 2); + } else { + locals->LinesInDETLuma = locals->DETBufferSizeInKByte * 1024 * 2 / 3 / locals->BytePerPixelInDETY[k] / locals->SwathWidthYPerState[i][j][k]; + locals->LinesInDETChroma = locals->DETBufferSizeInKByte * 1024 / 3 / locals->BytePerPixelInDETY[k] / (locals->SwathWidthYPerState[i][j][k] / 2); + } + + locals->EffectiveLBLatencyHidingSourceLinesLuma = dml_min(locals->MaxLineBufferLines, + dml_floor(locals->LineBufferSize / locals->LBBitPerPixel[k] / (locals->SwathWidthYPerState[i][j][k] + / dml_max(locals->HRatio[k], 1)), 1)) - (locals->vtaps[k] - 1); + + locals->EffectiveLBLatencyHidingSourceLinesChroma = dml_min(locals->MaxLineBufferLines, + dml_floor(locals->LineBufferSize / locals->LBBitPerPixel[k] + / (locals->SwathWidthYPerState[i][j][k] / 2 + / dml_max(locals->HRatio[k] / 2, 1)), 1)) - (locals->VTAPsChroma[k] - 1); + + locals->EffectiveDETLBLinesLuma = dml_floor(locals->LinesInDETLuma + dml_min( + locals->LinesInDETLuma * locals->RequiredDISPCLK[i][j] * locals->BytePerPixelInDETY[k] * + locals->PSCL_FACTOR[k] / locals->ReturnBWPerState[i], + locals->EffectiveLBLatencyHidingSourceLinesLuma), + locals->SwathHeightYPerState[i][j][k]); + + locals->EffectiveDETLBLinesChroma = dml_floor(locals->LinesInDETChroma + dml_min( + locals->LinesInDETChroma * locals->RequiredDISPCLK[i][j] * locals->BytePerPixelInDETC[k] * + locals->PSCL_FACTOR_CHROMA[k] / locals->ReturnBWPerState[i], + locals->EffectiveLBLatencyHidingSourceLinesChroma), + locals->SwathHeightCPerState[i][j][k]); + + if (locals->BytePerPixelInDETC[k] == 0) { + locals->UrgentLatencySupportUsPerState[i][j][k] = locals->EffectiveDETLBLinesLuma * (locals->HTotal[k] / locals->PixelClock[k]) + / locals->VRatio[k] - locals->EffectiveDETLBLinesLuma * locals->SwathWidthYPerState[i][j][k] * + dml_ceil(locals->BytePerPixelInDETY[k], 1) / (locals->ReturnBWPerState[i] / locals->NoOfDPP[i][j][k]); + } else { + locals->UrgentLatencySupportUsPerState[i][j][k] = dml_min( + locals->EffectiveDETLBLinesLuma * (locals->HTotal[k] / locals->PixelClock[k]) + / locals->VRatio[k] - locals->EffectiveDETLBLinesLuma * locals->SwathWidthYPerState[i][j][k] * + dml_ceil(locals->BytePerPixelInDETY[k], 1) / (locals->ReturnBWPerState[i] / locals->NoOfDPP[i][j][k]), + locals->EffectiveDETLBLinesChroma * (locals->HTotal[k] / locals->PixelClock[k]) / (locals->VRatio[k] / 2) - + locals->EffectiveDETLBLinesChroma * locals->SwathWidthYPerState[i][j][k] / 2 * + dml_ceil(locals->BytePerPixelInDETC[k], 2) / (locals->ReturnBWPerState[i] / locals->NoOfDPP[i][j][k])); + } + } + } + } + + for (i = 0; i <= locals->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + locals->UrgentLatencySupport[i][j] = true; + for (k = 0; k < locals->NumberOfActivePlanes; k++) { + if (locals->UrgentLatencySupportUsPerState[i][j][k] < locals->UrgentLatency) + locals->UrgentLatencySupport[i][j] = false; + } + } + } + + + /*Prefetch Check*/ + for (i = 0; i <= locals->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + locals->TotalNumberOfDCCActiveDPP[i][j] = 0; + for (k = 0; k < locals->NumberOfActivePlanes; k++) { + if (locals->DCCEnable[k] == true) { + locals->TotalNumberOfDCCActiveDPP[i][j] = + locals->TotalNumberOfDCCActiveDPP[i][j] + locals->NoOfDPP[i][j][k]; + } + } + } + } + + CalculateMinAndMaxPrefetchMode(locals->AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, &locals->MinPrefetchMode, &locals->MaxPrefetchMode); + + for (i = 0; i <= locals->soc.num_states; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < locals->NumberOfActivePlanes; k++) { + locals->NoOfDPPThisState[k] = locals->NoOfDPP[i][j][k]; + locals->RequiredDPPCLKThisState[k] = locals->RequiredDPPCLK[i][j][k]; + locals->SwathHeightYThisState[k] = locals->SwathHeightYPerState[i][j][k]; + locals->SwathHeightCThisState[k] = locals->SwathHeightCPerState[i][j][k]; + locals->SwathWidthYThisState[k] = locals->SwathWidthYPerState[i][j][k]; + mode_lib->vba.ProjectedDCFCLKDeepSleep = dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + mode_lib->vba.PixelClock[k] / 16.0); + if (mode_lib->vba.BytePerPixelInDETC[k] == 0.0) { + if (mode_lib->vba.VRatio[k] <= 1.0) { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETY[k], + 1.0) + / 64.0 + * mode_lib->vba.HRatio[k] + * mode_lib->vba.PixelClock[k] + / mode_lib->vba.NoOfDPP[i][j][k]); + } else { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETY[k], + 1.0) + / 64.0 + * mode_lib->vba.PSCL_FACTOR[k] + * mode_lib->vba.RequiredDPPCLK[i][j][k]); + } + } else { + if (mode_lib->vba.VRatio[k] <= 1.0) { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETY[k], + 1.0) + / 32.0 + * mode_lib->vba.HRatio[k] + * mode_lib->vba.PixelClock[k] + / mode_lib->vba.NoOfDPP[i][j][k]); + } else { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETY[k], + 1.0) + / 32.0 + * mode_lib->vba.PSCL_FACTOR[k] + * mode_lib->vba.RequiredDPPCLK[i][j][k]); + } + if (mode_lib->vba.VRatio[k] / 2.0 <= 1.0) { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETC[k], + 2.0) + / 32.0 + * mode_lib->vba.HRatio[k] + / 2.0 + * mode_lib->vba.PixelClock[k] + / mode_lib->vba.NoOfDPP[i][j][k]); + } else { + mode_lib->vba.ProjectedDCFCLKDeepSleep = + dml_max( + mode_lib->vba.ProjectedDCFCLKDeepSleep, + 1.1 + * dml_ceil( + mode_lib->vba.BytePerPixelInDETC[k], + 2.0) + / 32.0 + * mode_lib->vba.PSCL_FACTOR_CHROMA[k] + * mode_lib->vba.RequiredDPPCLK[i][j][k]); + } + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.PDEAndMetaPTEBytesPerFrameY = CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + mode_lib->vba.Read256BlockHeightY[k], + mode_lib->vba.Read256BlockWidthY[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(mode_lib->vba.BytePerPixelInDETY[k], 1.0), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k], + mode_lib->vba.ViewportHeight[k], + mode_lib->vba.SwathWidthYPerState[i][j][k], + mode_lib->vba.GPUVMEnable, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsLuma, + mode_lib->vba.PDEProcessingBufIn64KBReqs, + mode_lib->vba.PitchY[k], + mode_lib->vba.DCCMetaPitchY[k], + &mode_lib->vba.MacroTileWidthY[k], + &mode_lib->vba.MetaRowBytesY, + &mode_lib->vba.DPTEBytesPerRowY, + &mode_lib->vba.PTEBufferSizeNotExceededY[i][j][k], + &mode_lib->vba.dpte_row_height[k], + &mode_lib->vba.meta_row_height[k]); + mode_lib->vba.PrefetchLinesY[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k], + mode_lib->vba.vtaps[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + mode_lib->vba.SwathHeightYPerState[i][j][k], + mode_lib->vba.ViewportYStartY[k], + &mode_lib->vba.PrefillY[k], + &mode_lib->vba.MaxNumSwY[k]); + if ((mode_lib->vba.SourcePixelFormat[k] != dm_444_64 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8)) { + mode_lib->vba.PDEAndMetaPTEBytesPerFrameC = CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + mode_lib->vba.Read256BlockHeightY[k], + mode_lib->vba.Read256BlockWidthY[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(mode_lib->vba.BytePerPixelInDETC[k], 2.0), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k] / 2.0, + mode_lib->vba.ViewportHeight[k] / 2.0, + mode_lib->vba.SwathWidthYPerState[i][j][k] / 2.0, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsLuma, + mode_lib->vba.PDEProcessingBufIn64KBReqs, + mode_lib->vba.PitchC[k], + 0.0, + &mode_lib->vba.MacroTileWidthC[k], + &mode_lib->vba.MetaRowBytesC, + &mode_lib->vba.DPTEBytesPerRowC, + &mode_lib->vba.PTEBufferSizeNotExceededC[i][j][k], + &mode_lib->vba.dpte_row_height_chroma[k], + &mode_lib->vba.meta_row_height_chroma[k]); + mode_lib->vba.PrefetchLinesC[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k] / 2.0, + mode_lib->vba.VTAPsChroma[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + mode_lib->vba.SwathHeightCPerState[i][j][k], + mode_lib->vba.ViewportYStartC[k], + &mode_lib->vba.PrefillC[k], + &mode_lib->vba.MaxNumSwC[k]); + } else { + mode_lib->vba.PDEAndMetaPTEBytesPerFrameC = 0.0; + mode_lib->vba.MetaRowBytesC = 0.0; + mode_lib->vba.DPTEBytesPerRowC = 0.0; + locals->PrefetchLinesC[k] = 0.0; + locals->PTEBufferSizeNotExceededC[i][j][k] = true; + locals->PTEBufferSizeInRequestsForLuma = mode_lib->vba.PTEBufferSizeInRequestsLuma + mode_lib->vba.PTEBufferSizeInRequestsChroma; + } + locals->PDEAndMetaPTEBytesPerFrame[k] = + mode_lib->vba.PDEAndMetaPTEBytesPerFrameY + mode_lib->vba.PDEAndMetaPTEBytesPerFrameC; + locals->MetaRowBytes[k] = mode_lib->vba.MetaRowBytesY + mode_lib->vba.MetaRowBytesC; + locals->DPTEBytesPerRow[k] = mode_lib->vba.DPTEBytesPerRowY + mode_lib->vba.DPTEBytesPerRowC; + + CalculateActiveRowBandwidth( + mode_lib->vba.GPUVMEnable, + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.VRatio[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.MetaRowBytesY, + mode_lib->vba.MetaRowBytesC, + mode_lib->vba.meta_row_height[k], + mode_lib->vba.meta_row_height_chroma[k], + mode_lib->vba.DPTEBytesPerRowY, + mode_lib->vba.DPTEBytesPerRowC, + mode_lib->vba.dpte_row_height[k], + mode_lib->vba.dpte_row_height_chroma[k], + &mode_lib->vba.meta_row_bw[k], + &mode_lib->vba.dpte_row_bw[k], + &mode_lib->vba.qual_row_bw[k]); + } + mode_lib->vba.ExtraLatency = + mode_lib->vba.UrgentRoundTripAndOutOfOrderLatencyPerState[i] + + (mode_lib->vba.TotalNumberOfActiveDPP[i][j] + * mode_lib->vba.PixelChunkSizeInKByte + + mode_lib->vba.TotalNumberOfDCCActiveDPP[i][j] + * mode_lib->vba.MetaChunkSize) + * 1024.0 + / mode_lib->vba.ReturnBWPerState[i]; + if (mode_lib->vba.GPUVMEnable == true) { + mode_lib->vba.ExtraLatency = mode_lib->vba.ExtraLatency + + mode_lib->vba.TotalNumberOfActiveDPP[i][j] + * mode_lib->vba.PTEGroupSize + / mode_lib->vba.ReturnBWPerState[i]; + } + mode_lib->vba.TimeCalc = 24.0 / mode_lib->vba.ProjectedDCFCLKDeepSleep; + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.BlendingAndTiming[k] == k) { + if (mode_lib->vba.WritebackEnable[k] == true) { + locals->WritebackDelay[i][k] = mode_lib->vba.WritebackLatency + + CalculateWriteBackDelay( + mode_lib->vba.WritebackPixelFormat[k], + mode_lib->vba.WritebackHRatio[k], + mode_lib->vba.WritebackVRatio[k], + mode_lib->vba.WritebackLumaHTaps[k], + mode_lib->vba.WritebackLumaVTaps[k], + mode_lib->vba.WritebackChromaHTaps[k], + mode_lib->vba.WritebackChromaVTaps[k], + mode_lib->vba.WritebackDestinationWidth[k]) / locals->RequiredDISPCLK[i][j]; + } else { + locals->WritebackDelay[i][k] = 0.0; + } + for (m = 0; m <= mode_lib->vba.NumberOfActivePlanes - 1; m++) { + if (mode_lib->vba.BlendingAndTiming[m] == k + && mode_lib->vba.WritebackEnable[m] + == true) { + locals->WritebackDelay[i][k] = dml_max(locals->WritebackDelay[i][k], + mode_lib->vba.WritebackLatency + CalculateWriteBackDelay( + mode_lib->vba.WritebackPixelFormat[m], + mode_lib->vba.WritebackHRatio[m], + mode_lib->vba.WritebackVRatio[m], + mode_lib->vba.WritebackLumaHTaps[m], + mode_lib->vba.WritebackLumaVTaps[m], + mode_lib->vba.WritebackChromaHTaps[m], + mode_lib->vba.WritebackChromaVTaps[m], + mode_lib->vba.WritebackDestinationWidth[m]) / locals->RequiredDISPCLK[i][j]); + } + } + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + for (m = 0; m <= mode_lib->vba.NumberOfActivePlanes - 1; m++) { + if (mode_lib->vba.BlendingAndTiming[k] == m) { + locals->WritebackDelay[i][k] = locals->WritebackDelay[i][m]; + } + } + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + for (m = 0; m < locals->NumberOfCursors[k]; m++) + locals->cursor_bw[k] = locals->NumberOfCursors[k] * locals->CursorWidth[k][m] * locals->CursorBPP[k][m] + / 8 / (locals->HTotal[k] / locals->PixelClock[k]) * locals->VRatio[k]; + } + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->MaximumVStartup[k] = mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k] + - dml_max(1.0, dml_ceil(locals->WritebackDelay[i][k] / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]), 1.0)); + } + + mode_lib->vba.NextPrefetchMode = mode_lib->vba.MinPrefetchMode; + do { + mode_lib->vba.PrefetchMode[i][j] = mode_lib->vba.NextPrefetchMode; + mode_lib->vba.NextPrefetchMode = mode_lib->vba.NextPrefetchMode + 1; + + mode_lib->vba.TWait = CalculateTWait( + mode_lib->vba.PrefetchMode[i][j], + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.UrgentLatency, + mode_lib->vba.SREnterPlusExitTime); + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + + if (mode_lib->vba.XFCEnabled[k] == true) { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = + CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + locals->SwathWidthYPerState[i][j][k], + dml_ceil(locals->BytePerPixelInDETY[k], 1.0), + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.XFCTSlvVupdateOffset, + mode_lib->vba.XFCTSlvVupdateWidth, + mode_lib->vba.XFCTSlvVreadyOffset, + mode_lib->vba.XFCXBUFLatencyTolerance, + mode_lib->vba.XFCFillBWOverhead, + mode_lib->vba.XFCSlvChunkSize, + mode_lib->vba.XFCBusTransportTime, + mode_lib->vba.TimeCalc, + mode_lib->vba.TWait, + &mode_lib->vba.SrcActiveDrainRate, + &mode_lib->vba.TInitXFill, + &mode_lib->vba.TslvChk); + } else { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = 0.0; + } + mode_lib->vba.IsErrorResult[i][j][k] = + CalculatePrefetchSchedule( + mode_lib, + mode_lib->vba.RequiredDPPCLK[i][j][k], + mode_lib->vba.RequiredDISPCLK[i][j], + mode_lib->vba.PixelClock[k], + mode_lib->vba.ProjectedDCFCLKDeepSleep, + mode_lib->vba.DSCDelayPerState[i][k], + mode_lib->vba.NoOfDPP[i][j][k], + mode_lib->vba.ScalerEnabled[k], + mode_lib->vba.NumberOfCursors[k], + mode_lib->vba.DPPCLKDelaySubtotal, + mode_lib->vba.DPPCLKDelaySCL, + mode_lib->vba.DPPCLKDelaySCLLBOnly, + mode_lib->vba.DPPCLKDelayCNVCFormater, + mode_lib->vba.DPPCLKDelayCNVCCursor, + mode_lib->vba.DISPCLKDelaySubtotal, + mode_lib->vba.SwathWidthYPerState[i][j][k] + / mode_lib->vba.HRatio[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.VTotal[k] + - mode_lib->vba.VActive[k], + mode_lib->vba.HTotal[k], + mode_lib->vba.MaxInterDCNTileRepeaters, + mode_lib->vba.MaximumVStartup[k], + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.DynamicMetadataEnable[k], + mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], + mode_lib->vba.DynamicMetadataTransmittedBytes[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.ExtraLatency, + mode_lib->vba.TimeCalc, + mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k], + mode_lib->vba.MetaRowBytes[k], + mode_lib->vba.DPTEBytesPerRow[k], + mode_lib->vba.PrefetchLinesY[k], + mode_lib->vba.SwathWidthYPerState[i][j][k], + mode_lib->vba.BytePerPixelInDETY[k], + mode_lib->vba.PrefillY[k], + mode_lib->vba.MaxNumSwY[k], + mode_lib->vba.PrefetchLinesC[k], + mode_lib->vba.BytePerPixelInDETC[k], + mode_lib->vba.PrefillC[k], + mode_lib->vba.MaxNumSwC[k], + mode_lib->vba.SwathHeightYPerState[i][j][k], + mode_lib->vba.SwathHeightCPerState[i][j][k], + mode_lib->vba.TWait, + mode_lib->vba.XFCEnabled[k], + mode_lib->vba.XFCRemoteSurfaceFlipDelay, + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + mode_lib->vba.DSTXAfterScaler, + mode_lib->vba.DSTYAfterScaler, + &mode_lib->vba.LineTimesForPrefetch[k], + &mode_lib->vba.PrefetchBW[k], + &mode_lib->vba.LinesForMetaPTE[k], + &mode_lib->vba.LinesForMetaAndDPTERow[k], + &mode_lib->vba.VRatioPreY[i][j][k], + &mode_lib->vba.VRatioPreC[i][j][k], + &mode_lib->vba.RequiredPrefetchPixelDataBWLuma[i][j][k], + &mode_lib->vba.VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + &mode_lib->vba.Tno_bw[k], + &mode_lib->vba.VUpdateOffsetPix[k], + &mode_lib->vba.VUpdateWidthPix[k], + &mode_lib->vba.VReadyOffsetPix[k]); + } + mode_lib->vba.MaximumReadBandwidthWithoutPrefetch = 0.0; + mode_lib->vba.MaximumReadBandwidthWithPrefetch = 0.0; + locals->prefetch_vm_bw_valid = true; + locals->prefetch_row_bw_valid = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->PDEAndMetaPTEBytesPerFrame[k] == 0) + locals->prefetch_vm_bw[k] = 0; + else if (locals->LinesForMetaPTE[k] > 0) + locals->prefetch_vm_bw[k] = locals->PDEAndMetaPTEBytesPerFrame[k] + / (locals->LinesForMetaPTE[k] * locals->HTotal[k] / locals->PixelClock[k]); + else { + locals->prefetch_vm_bw[k] = 0; + locals->prefetch_vm_bw_valid = false; + } + if (locals->MetaRowBytes[k] + locals->DPTEBytesPerRow[k] == 0) + locals->prefetch_row_bw[k] = 0; + else if (locals->LinesForMetaAndDPTERow[k] > 0) + locals->prefetch_row_bw[k] = (locals->MetaRowBytes[k] + locals->DPTEBytesPerRow[k]) + / (locals->LinesForMetaAndDPTERow[k] * locals->HTotal[k] / locals->PixelClock[k]); + else { + locals->prefetch_row_bw[k] = 0; + locals->prefetch_row_bw_valid = false; + } + + mode_lib->vba.MaximumReadBandwidthWithoutPrefetch = mode_lib->vba.MaximumReadBandwidthWithPrefetch + + mode_lib->vba.cursor_bw[k] + mode_lib->vba.ReadBandwidth[k] + mode_lib->vba.meta_row_bw[k] + mode_lib->vba.dpte_row_bw[k]; + mode_lib->vba.MaximumReadBandwidthWithPrefetch = + mode_lib->vba.MaximumReadBandwidthWithPrefetch + + mode_lib->vba.cursor_bw[k] + + dml_max3( + mode_lib->vba.prefetch_vm_bw[k], + mode_lib->vba.prefetch_row_bw[k], + dml_max(mode_lib->vba.ReadBandwidth[k], + mode_lib->vba.RequiredPrefetchPixelDataBWLuma[i][j][k]) + + mode_lib->vba.meta_row_bw[k] + mode_lib->vba.dpte_row_bw[k]); + } + locals->BandwidthWithoutPrefetchSupported[i] = true; + if (mode_lib->vba.MaximumReadBandwidthWithoutPrefetch > locals->ReturnBWPerState[i]) { + locals->BandwidthWithoutPrefetchSupported[i] = false; + } + + locals->PrefetchSupported[i][j] = true; + if (mode_lib->vba.MaximumReadBandwidthWithPrefetch > locals->ReturnBWPerState[i]) { + locals->PrefetchSupported[i][j] = false; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->LineTimesForPrefetch[k] < 2.0 + || locals->LinesForMetaPTE[k] >= 8.0 + || locals->LinesForMetaAndDPTERow[k] >= 16.0 + || mode_lib->vba.IsErrorResult[i][j][k] == true) { + locals->PrefetchSupported[i][j] = false; + } + } + locals->VRatioInPrefetchSupported[i][j] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->VRatioPreY[i][j][k] > 4.0 + || locals->VRatioPreC[i][j][k] > 4.0 + || mode_lib->vba.IsErrorResult[i][j][k] == true) { + locals->VRatioInPrefetchSupported[i][j] = false; + } + } + } while ((locals->PrefetchSupported[i][j] != true || locals->VRatioInPrefetchSupported[i][j] != true) + && mode_lib->vba.NextPrefetchMode < mode_lib->vba.MaxPrefetchMode); + + if (mode_lib->vba.PrefetchSupported[i][j] == true + && mode_lib->vba.VRatioInPrefetchSupported[i][j] == true) { + mode_lib->vba.BandwidthAvailableForImmediateFlip = + mode_lib->vba.ReturnBWPerState[i]; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.BandwidthAvailableForImmediateFlip = + mode_lib->vba.BandwidthAvailableForImmediateFlip + - mode_lib->vba.cursor_bw[k] + - dml_max( + mode_lib->vba.ReadBandwidth[k] + mode_lib->vba.qual_row_bw[k], + mode_lib->vba.PrefetchBW[k]); + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.ImmediateFlipBytes[k] = 0.0; + if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 + && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { + mode_lib->vba.ImmediateFlipBytes[k] = + mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k] + + mode_lib->vba.MetaRowBytes[k] + + mode_lib->vba.DPTEBytesPerRow[k]; + } + } + mode_lib->vba.TotImmediateFlipBytes = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if ((mode_lib->vba.SourcePixelFormat[k] != dm_420_8 + && mode_lib->vba.SourcePixelFormat[k] != dm_420_10)) { + mode_lib->vba.TotImmediateFlipBytes = + mode_lib->vba.TotImmediateFlipBytes + + mode_lib->vba.ImmediateFlipBytes[k]; + } + } + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + CalculateFlipSchedule( + mode_lib, + mode_lib->vba.ExtraLatency, + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.BandwidthAvailableForImmediateFlip, + mode_lib->vba.TotImmediateFlipBytes, + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.ImmediateFlipBytes[k], + mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k], + mode_lib->vba.VRatio[k], + mode_lib->vba.Tno_bw[k], + mode_lib->vba.PDEAndMetaPTEBytesPerFrame[k], + mode_lib->vba.MetaRowBytes[k], + mode_lib->vba.DPTEBytesPerRow[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.dpte_row_height[k], + mode_lib->vba.meta_row_height[k], + mode_lib->vba.qual_row_bw[k], + &mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip[k], + &mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip[k], + &mode_lib->vba.final_flip_bw[k], + &mode_lib->vba.ImmediateFlipSupportedForPipe[k]); + } + mode_lib->vba.total_dcn_read_bw_with_flip = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.total_dcn_read_bw_with_flip = + mode_lib->vba.total_dcn_read_bw_with_flip + + mode_lib->vba.cursor_bw[k] + + dml_max3( + mode_lib->vba.prefetch_vm_bw[k], + mode_lib->vba.prefetch_row_bw[k], + mode_lib->vba.final_flip_bw[k] + + dml_max( + mode_lib->vba.ReadBandwidth[k], + mode_lib->vba.RequiredPrefetchPixelDataBWLuma[i][j][k])); + } + mode_lib->vba.ImmediateFlipSupportedForState[i][j] = true; + if (mode_lib->vba.total_dcn_read_bw_with_flip + > mode_lib->vba.ReturnBWPerState[i]) { + mode_lib->vba.ImmediateFlipSupportedForState[i][j] = false; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.ImmediateFlipSupportedForPipe[k] == false) { + mode_lib->vba.ImmediateFlipSupportedForState[i][j] = false; + } + } + } else { + mode_lib->vba.ImmediateFlipSupportedForState[i][j] = false; + } + } + } + + /*Vertical Active BW support*/ + mode_lib->vba.MaxTotalVActiveRDBandwidth = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; k++) + mode_lib->vba.MaxTotalVActiveRDBandwidth = mode_lib->vba.MaxTotalVActiveRDBandwidth + mode_lib->vba.ReadBandwidth[k]; + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + mode_lib->vba.MaxTotalVerticalActiveAvailableBandwidth[i] = dml_min(mode_lib->vba.ReturnBusWidth * + mode_lib->vba.DCFCLKPerState[i], mode_lib->vba.FabricAndDRAMBandwidthPerState[i] * 1000) * + mode_lib->vba.MaxAveragePercentOfIdealDRAMBWDisplayCanUseInNormalSystemOperation / 100; + if (mode_lib->vba.MaxTotalVActiveRDBandwidth <= mode_lib->vba.MaxTotalVerticalActiveAvailableBandwidth[i]) + mode_lib->vba.TotalVerticalActiveBandwidthSupport[i] = true; + else + mode_lib->vba.TotalVerticalActiveBandwidthSupport[i] = false; + } + + /*PTE Buffer Size Check*/ + + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + for (j = 0; j < 2; j++) { + locals->PTEBufferSizeNotExceeded[i][j] = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->PTEBufferSizeNotExceededY[i][j][k] == false + || locals->PTEBufferSizeNotExceededC[i][j][k] == false) { + locals->PTEBufferSizeNotExceeded[i][j] = false; + } + } + } + } + /*Cursor Support Check*/ + mode_lib->vba.CursorSupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + for (j = 0; j < 2; j++) { + if (mode_lib->vba.CursorWidth[k][j] > 0.0) { + if (dml_floor( + dml_floor( + mode_lib->vba.CursorBufferSize + - mode_lib->vba.CursorChunkSize, + mode_lib->vba.CursorChunkSize) * 1024.0 + / (mode_lib->vba.CursorWidth[k][j] + * mode_lib->vba.CursorBPP[k][j] + / 8.0), + 1.0) + * (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + / mode_lib->vba.VRatio[k] < mode_lib->vba.UrgentLatencyPixelDataOnly + || (mode_lib->vba.CursorBPP[k][j] == 64.0 + && mode_lib->vba.Cursor64BppSupport == false)) { + mode_lib->vba.CursorSupport = false; + } + } + } + } + /*Valid Pitch Check*/ + + mode_lib->vba.PitchSupport = true; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + locals->AlignedYPitch[k] = dml_ceil( + dml_max(mode_lib->vba.PitchY[k], mode_lib->vba.ViewportWidth[k]), + locals->MacroTileWidthY[k]); + if (locals->AlignedYPitch[k] > mode_lib->vba.PitchY[k]) { + mode_lib->vba.PitchSupport = false; + } + if (mode_lib->vba.DCCEnable[k] == true) { + locals->AlignedDCCMetaPitch[k] = dml_ceil( + dml_max( + mode_lib->vba.DCCMetaPitchY[k], + mode_lib->vba.ViewportWidth[k]), + 64.0 * locals->Read256BlockWidthY[k]); + } else { + locals->AlignedDCCMetaPitch[k] = mode_lib->vba.DCCMetaPitchY[k]; + } + if (locals->AlignedDCCMetaPitch[k] > mode_lib->vba.DCCMetaPitchY[k]) { + mode_lib->vba.PitchSupport = false; + } + if (mode_lib->vba.SourcePixelFormat[k] != dm_444_64 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_32 + && mode_lib->vba.SourcePixelFormat[k] != dm_444_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_16 + && mode_lib->vba.SourcePixelFormat[k] != dm_mono_8) { + locals->AlignedCPitch[k] = dml_ceil( + dml_max( + mode_lib->vba.PitchC[k], + mode_lib->vba.ViewportWidth[k] / 2.0), + locals->MacroTileWidthC[k]); + } else { + locals->AlignedCPitch[k] = mode_lib->vba.PitchC[k]; + } + if (locals->AlignedCPitch[k] > mode_lib->vba.PitchC[k]) { + mode_lib->vba.PitchSupport = false; + } + } + /*Mode Support, Voltage State and SOC Configuration*/ + + for (i = mode_lib->vba.soc.num_states; i >= 0; i--) { + for (j = 0; j < 2; j++) { + enum dm_validation_status status = DML_VALIDATION_OK; + + if (mode_lib->vba.ScaleRatioAndTapsSupport != true) { + status = DML_FAIL_SCALE_RATIO_TAP; + } else if (mode_lib->vba.SourceFormatPixelAndScanSupport != true) { + status = DML_FAIL_SOURCE_PIXEL_FORMAT; + } else if (locals->ViewportSizeSupport[i] != true) { + status = DML_FAIL_VIEWPORT_SIZE; + } else if (locals->DIOSupport[i] != true) { + status = DML_FAIL_DIO_SUPPORT; + } else if (locals->NotEnoughDSCUnits[i] != false) { + status = DML_FAIL_NOT_ENOUGH_DSC; + } else if (locals->DSCCLKRequiredMoreThanSupported[i] != false) { + status = DML_FAIL_DSC_CLK_REQUIRED; + } else if (locals->UrgentLatencySupport[i][j] != true) { + status = DML_FAIL_URGENT_LATENCY; + } else if (locals->ROBSupport[i] != true) { + status = DML_FAIL_REORDERING_BUFFER; + } else if (locals->DISPCLK_DPPCLK_Support[i][j] != true) { + status = DML_FAIL_DISPCLK_DPPCLK; + } else if (locals->TotalAvailablePipesSupport[i][j] != true) { + status = DML_FAIL_TOTAL_AVAILABLE_PIPES; + } else if (mode_lib->vba.NumberOfOTGSupport != true) { + status = DML_FAIL_NUM_OTG; + } else if (mode_lib->vba.WritebackModeSupport != true) { + status = DML_FAIL_WRITEBACK_MODE; + } else if (mode_lib->vba.WritebackLatencySupport != true) { + status = DML_FAIL_WRITEBACK_LATENCY; + } else if (mode_lib->vba.WritebackScaleRatioAndTapsSupport != true) { + status = DML_FAIL_WRITEBACK_SCALE_RATIO_TAP; + } else if (mode_lib->vba.CursorSupport != true) { + status = DML_FAIL_CURSOR_SUPPORT; + } else if (mode_lib->vba.PitchSupport != true) { + status = DML_FAIL_PITCH_SUPPORT; + } else if (locals->PrefetchSupported[i][j] != true) { + status = DML_FAIL_PREFETCH_SUPPORT; + } else if (locals->TotalVerticalActiveBandwidthSupport[i] != true) { + status = DML_FAIL_TOTAL_V_ACTIVE_BW; + } else if (locals->VRatioInPrefetchSupported[i][j] != true) { + status = DML_FAIL_V_RATIO_PREFETCH; + } else if (locals->PTEBufferSizeNotExceeded[i][j] != true) { + status = DML_FAIL_PTE_BUFFER_SIZE; + } else if (mode_lib->vba.NonsupportedDSCInputBPC != false) { + status = DML_FAIL_DSC_INPUT_BPC; + } + + if (status == DML_VALIDATION_OK) { + locals->ModeSupport[i][j] = true; + } else { + locals->ModeSupport[i][j] = false; + } + locals->ValidationStatus[i] = status; + } + } + { + unsigned int MaximumMPCCombine = 0; + mode_lib->vba.VoltageLevel = mode_lib->vba.soc.num_states + 1; + for (i = mode_lib->vba.VoltageOverrideLevel; i <= mode_lib->vba.soc.num_states; i++) { + if (locals->ModeSupport[i][0] == true || locals->ModeSupport[i][1] == true) { + mode_lib->vba.VoltageLevel = i; + if (locals->ModeSupport[i][1] == true && (locals->ModeSupport[i][0] == false + || mode_lib->vba.WhenToDoMPCCombine == dm_mpc_always_when_possible)) { + MaximumMPCCombine = 1; + } else { + MaximumMPCCombine = 0; + } + break; + } + } + mode_lib->vba.ImmediateFlipSupport = + locals->ImmediateFlipSupportedForState[mode_lib->vba.VoltageLevel][MaximumMPCCombine]; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.DPPPerPlane[k] = locals->NoOfDPP[mode_lib->vba.VoltageLevel][MaximumMPCCombine][k]; + locals->DPPCLK[k] = locals->RequiredDPPCLK[mode_lib->vba.VoltageLevel][MaximumMPCCombine][k]; + } + mode_lib->vba.DISPCLK = locals->RequiredDISPCLK[mode_lib->vba.VoltageLevel][MaximumMPCCombine]; + mode_lib->vba.maxMpcComb = MaximumMPCCombine; + } + mode_lib->vba.DCFCLK = mode_lib->vba.DCFCLKPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.DRAMSpeed = mode_lib->vba.DRAMSpeedPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.FabricClock = mode_lib->vba.FabricClockPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.SOCCLK = mode_lib->vba.SOCCLKPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.ReturnBW = locals->ReturnBWPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.FabricAndDRAMBandwidth = locals->FabricAndDRAMBandwidthPerState[mode_lib->vba.VoltageLevel]; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (mode_lib->vba.BlendingAndTiming[k] == k) { + mode_lib->vba.ODMCombineEnabled[k] = + locals->ODMCombineEnablePerState[mode_lib->vba.VoltageLevel][k]; + } else { + mode_lib->vba.ODMCombineEnabled[k] = 0; + } + mode_lib->vba.DSCEnabled[k] = + locals->RequiresDSC[mode_lib->vba.VoltageLevel][k]; + mode_lib->vba.OutputBpp[k] = + locals->OutputBppPerState[mode_lib->vba.VoltageLevel][k]; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.h new file mode 100644 index 000000000000..92b6805f4342 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20.h @@ -0,0 +1,32 @@ +/* + * 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 + * + */ + +#ifndef _DCN20_DISPLAY_MODE_VBA_H_ +#define _DCN20_DISPLAY_MODE_VBA_H_ + +void dml20_recalculate(struct display_mode_lib *mode_lib); +void dml20_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c new file mode 100644 index 000000000000..878bf4782ce6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.c @@ -0,0 +1,1701 @@ +/* + * 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 "../display_mode_lib.h" +#include "../display_mode_vba.h" +#include "display_rq_dlg_calc_20.h" + +// Function: dml20_rq_dlg_get_rq_params +// Calculate requestor related parameters that register definition agnostic +// (i.e. this layer does try to separate real values from register definition) +// Input: +// pipe_src_param - pipe source configuration (e.g. vp, pitch, etc.) +// Output: +// rq_param - values that can be used to setup RQ (e.g. swath_height, plane1_addr, etc.) +// +static void dml20_rq_dlg_get_rq_params( + struct display_mode_lib *mode_lib, + display_rq_params_st * rq_param, + const display_pipe_source_params_st pipe_src_param); + +// Function: dml20_rq_dlg_get_dlg_params +// Calculate deadline related parameters +// +static void dml20_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + display_dlg_regs_st *disp_dlg_regs, + display_ttu_regs_st *disp_ttu_regs, + const display_rq_dlg_params_st rq_dlg_param, + const display_dlg_sys_params_st dlg_sys_param, + const bool cstate_en, + const bool pstate_en); +/* + * NOTE: + * This file is gcc-parseable HW gospel, coming straight from HW engineers. + * + * It doesn't adhere to Linux kernel style and sometimes will do things in odd + * ways. Unless there is something clearly wrong with it the code should + * remain as-is as it provides us with a guarantee from HW that it is correct. + */ + +static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + double *refcyc_per_req_delivery_pre_cur, + double *refcyc_per_req_delivery_cur, + double refclk_freq_in_mhz, + double ref_freq_to_pix_freq, + double hscale_pixel_rate_l, + double hscl_ratio, + double vratio_pre_l, + double vratio_l, + unsigned int cur_width, + enum cursor_bpp cur_bpp); + +#include "../dml_inline_defs.h" + +static unsigned int get_bytes_per_element(enum source_format_class source_format, bool is_chroma) +{ + unsigned int ret_val = 0; + + if (source_format == dm_444_16) { + if (!is_chroma) + ret_val = 2; + } else if (source_format == dm_444_32) { + if (!is_chroma) + ret_val = 4; + } else if (source_format == dm_444_64) { + if (!is_chroma) + ret_val = 8; + } else if (source_format == dm_420_8) { + if (is_chroma) + ret_val = 2; + else + ret_val = 1; + } else if (source_format == dm_420_10) { + if (is_chroma) + ret_val = 4; + else + ret_val = 2; + } else if (source_format == dm_444_8) { + ret_val = 1; + } + return ret_val; +} + +static bool is_dual_plane(enum source_format_class source_format) +{ + bool ret_val = 0; + + if ((source_format == dm_420_8) || (source_format == dm_420_10)) + ret_val = 1; + + return ret_val; +} + +static double get_refcyc_per_delivery(struct display_mode_lib *mode_lib, + double refclk_freq_in_mhz, + double pclk_freq_in_mhz, + bool odm_combine, + unsigned int recout_width, + unsigned int hactive, + double vratio, + double hscale_pixel_rate, + unsigned int delivery_width, + unsigned int req_per_swath_ub) +{ + double refcyc_per_delivery = 0.0; + + if (vratio <= 1.0) { + if (odm_combine) + refcyc_per_delivery = (double) refclk_freq_in_mhz + * dml_min((double) recout_width, (double) hactive / 2.0) + / pclk_freq_in_mhz / (double) req_per_swath_ub; + else + refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) recout_width + / pclk_freq_in_mhz / (double) req_per_swath_ub; + } else { + refcyc_per_delivery = (double) refclk_freq_in_mhz * (double) delivery_width + / (double) hscale_pixel_rate / (double) req_per_swath_ub; + } + + dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); + dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); + dml_print("DML_DLG: %s: recout_width = %d\n", __func__, recout_width); + dml_print("DML_DLG: %s: vratio = %3.2f\n", __func__, vratio); + dml_print("DML_DLG: %s: req_per_swath_ub = %d\n", __func__, req_per_swath_ub); + dml_print("DML_DLG: %s: refcyc_per_delivery= %3.2f\n", __func__, refcyc_per_delivery); + + return refcyc_per_delivery; + +} + +static unsigned int get_blk_size_bytes(const enum source_macro_tile_size tile_size) +{ + if (tile_size == dm_256k_tile) + return (256 * 1024); + else if (tile_size == dm_64k_tile) + return (64 * 1024); + else + return (4 * 1024); +} + +static void extract_rq_sizing_regs(struct display_mode_lib *mode_lib, + display_data_rq_regs_st *rq_regs, + const display_data_rq_sizing_params_st rq_sizing) +{ + dml_print("DML_DLG: %s: rq_sizing param\n", __func__); + print__data_rq_sizing_params_st(mode_lib, rq_sizing); + + rq_regs->chunk_size = dml_log2(rq_sizing.chunk_bytes) - 10; + + if (rq_sizing.min_chunk_bytes == 0) + rq_regs->min_chunk_size = 0; + else + rq_regs->min_chunk_size = dml_log2(rq_sizing.min_chunk_bytes) - 8 + 1; + + rq_regs->meta_chunk_size = dml_log2(rq_sizing.meta_chunk_bytes) - 10; + if (rq_sizing.min_meta_chunk_bytes == 0) + rq_regs->min_meta_chunk_size = 0; + else + rq_regs->min_meta_chunk_size = dml_log2(rq_sizing.min_meta_chunk_bytes) - 6 + 1; + + rq_regs->dpte_group_size = dml_log2(rq_sizing.dpte_group_bytes) - 6; + rq_regs->mpte_group_size = dml_log2(rq_sizing.mpte_group_bytes) - 6; +} + +static void extract_rq_regs(struct display_mode_lib *mode_lib, + display_rq_regs_st *rq_regs, + const display_rq_params_st rq_param) +{ + unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; + unsigned int detile_buf_plane1_addr = 0; + + extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_l), rq_param.sizing.rq_l); + + rq_regs->rq_regs_l.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_l.dpte_row_height), + 1) - 3; + + if (rq_param.yuv420) { + extract_rq_sizing_regs(mode_lib, &(rq_regs->rq_regs_c), rq_param.sizing.rq_c); + rq_regs->rq_regs_c.pte_row_height_linear = dml_floor(dml_log2(rq_param.dlg.rq_c.dpte_row_height), + 1) - 3; + } + + rq_regs->rq_regs_l.swath_height = dml_log2(rq_param.dlg.rq_l.swath_height); + rq_regs->rq_regs_c.swath_height = dml_log2(rq_param.dlg.rq_c.swath_height); + + // FIXME: take the max between luma, chroma chunk size? + // okay for now, as we are setting chunk_bytes to 8kb anyways + if (rq_param.sizing.rq_l.chunk_bytes >= 32 * 1024) { //32kb + rq_regs->drq_expansion_mode = 0; + } else { + rq_regs->drq_expansion_mode = 2; + } + rq_regs->prq_expansion_mode = 1; + rq_regs->mrq_expansion_mode = 1; + rq_regs->crq_expansion_mode = 1; + + if (rq_param.yuv420) { + if ((double) rq_param.misc.rq_l.stored_swath_bytes + / (double) rq_param.misc.rq_c.stored_swath_bytes <= 1.5) { + detile_buf_plane1_addr = (detile_buf_size_in_bytes / 2.0 / 64.0); // half to chroma + } else { + detile_buf_plane1_addr = dml_round_to_multiple((unsigned int) ((2.0 * detile_buf_size_in_bytes) / 3.0), + 256, + 0) / 64.0; // 2/3 to chroma + } + } + rq_regs->plane1_base_address = detile_buf_plane1_addr; +} + +static void handle_det_buf_split(struct display_mode_lib *mode_lib, + display_rq_params_st *rq_param, + const display_pipe_source_params_st pipe_src_param) +{ + unsigned int total_swath_bytes = 0; + unsigned int swath_bytes_l = 0; + unsigned int swath_bytes_c = 0; + unsigned int full_swath_bytes_packed_l = 0; + unsigned int full_swath_bytes_packed_c = 0; + bool req128_l = 0; + bool req128_c = 0; + bool surf_linear = (pipe_src_param.sw_mode == dm_sw_linear); + bool surf_vert = (pipe_src_param.source_scan == dm_vert); + unsigned int log2_swath_height_l = 0; + unsigned int log2_swath_height_c = 0; + unsigned int detile_buf_size_in_bytes = mode_lib->ip.det_buffer_size_kbytes * 1024; + + full_swath_bytes_packed_l = rq_param->misc.rq_l.full_swath_bytes; + full_swath_bytes_packed_c = rq_param->misc.rq_c.full_swath_bytes; + + if (rq_param->yuv420_10bpc) { + full_swath_bytes_packed_l = dml_round_to_multiple(rq_param->misc.rq_l.full_swath_bytes * 2 / 3, + 256, + 1) + 256; + full_swath_bytes_packed_c = dml_round_to_multiple(rq_param->misc.rq_c.full_swath_bytes * 2 / 3, + 256, + 1) + 256; + } + + if (rq_param->yuv420) { + total_swath_bytes = 2 * full_swath_bytes_packed_l + 2 * full_swath_bytes_packed_c; + + if (total_swath_bytes <= detile_buf_size_in_bytes) { //full 256b request + req128_l = 0; + req128_c = 0; + swath_bytes_l = full_swath_bytes_packed_l; + swath_bytes_c = full_swath_bytes_packed_c; + } else { //128b request (for luma only for yuv420 8bpc) + req128_l = 1; + req128_c = 0; + swath_bytes_l = full_swath_bytes_packed_l / 2; + swath_bytes_c = full_swath_bytes_packed_c; + } + // Note: assumption, the config that pass in will fit into + // the detiled buffer. + } else { + total_swath_bytes = 2 * full_swath_bytes_packed_l; + + if (total_swath_bytes <= detile_buf_size_in_bytes) + req128_l = 0; + else + req128_l = 1; + + swath_bytes_l = total_swath_bytes; + swath_bytes_c = 0; + } + rq_param->misc.rq_l.stored_swath_bytes = swath_bytes_l; + rq_param->misc.rq_c.stored_swath_bytes = swath_bytes_c; + + if (surf_linear) { + log2_swath_height_l = 0; + log2_swath_height_c = 0; + } else if (!surf_vert) { + log2_swath_height_l = dml_log2(rq_param->misc.rq_l.blk256_height) - req128_l; + log2_swath_height_c = dml_log2(rq_param->misc.rq_c.blk256_height) - req128_c; + } else { + log2_swath_height_l = dml_log2(rq_param->misc.rq_l.blk256_width) - req128_l; + log2_swath_height_c = dml_log2(rq_param->misc.rq_c.blk256_width) - req128_c; + } + rq_param->dlg.rq_l.swath_height = 1 << log2_swath_height_l; + rq_param->dlg.rq_c.swath_height = 1 << log2_swath_height_c; + + dml_print("DML_DLG: %s: req128_l = %0d\n", __func__, req128_l); + dml_print("DML_DLG: %s: req128_c = %0d\n", __func__, req128_c); + dml_print("DML_DLG: %s: full_swath_bytes_packed_l = %0d\n", + __func__, + full_swath_bytes_packed_l); + dml_print("DML_DLG: %s: full_swath_bytes_packed_c = %0d\n", + __func__, + full_swath_bytes_packed_c); +} + +static void get_meta_and_pte_attr(struct display_mode_lib *mode_lib, + display_data_rq_dlg_params_st *rq_dlg_param, + display_data_rq_misc_params_st *rq_misc_param, + display_data_rq_sizing_params_st *rq_sizing_param, + unsigned int vp_width, + unsigned int vp_height, + unsigned int data_pitch, + unsigned int meta_pitch, + unsigned int source_format, + unsigned int tiling, + unsigned int macro_tile_size, + unsigned int source_scan, + unsigned int is_chroma) +{ + bool surf_linear = (tiling == dm_sw_linear); + bool surf_vert = (source_scan == dm_vert); + + unsigned int bytes_per_element; + unsigned int bytes_per_element_y = get_bytes_per_element((enum source_format_class)(source_format), + false); + unsigned int bytes_per_element_c = get_bytes_per_element((enum source_format_class)(source_format), + true); + + unsigned int blk256_width = 0; + unsigned int blk256_height = 0; + + unsigned int blk256_width_y = 0; + unsigned int blk256_height_y = 0; + unsigned int blk256_width_c = 0; + unsigned int blk256_height_c = 0; + unsigned int log2_bytes_per_element; + unsigned int log2_blk256_width; + unsigned int log2_blk256_height; + unsigned int blk_bytes; + unsigned int log2_blk_bytes; + unsigned int log2_blk_height; + unsigned int log2_blk_width; + unsigned int log2_meta_req_bytes; + unsigned int log2_meta_req_height; + unsigned int log2_meta_req_width; + unsigned int meta_req_width; + unsigned int meta_req_height; + unsigned int log2_meta_row_height; + unsigned int meta_row_width_ub; + unsigned int log2_meta_chunk_bytes; + unsigned int log2_meta_chunk_height; + + //full sized meta chunk width in unit of data elements + unsigned int log2_meta_chunk_width; + unsigned int log2_min_meta_chunk_bytes; + unsigned int min_meta_chunk_width; + unsigned int meta_chunk_width; + unsigned int meta_chunk_per_row_int; + unsigned int meta_row_remainder; + unsigned int meta_chunk_threshold; + unsigned int meta_blk_bytes; + unsigned int meta_blk_height; + unsigned int meta_blk_width; + unsigned int meta_surface_bytes; + unsigned int vmpg_bytes; + unsigned int meta_pte_req_per_frame_ub; + unsigned int meta_pte_bytes_per_frame_ub; + const unsigned int log2_vmpg_bytes = dml_log2(mode_lib->soc.vmm_page_size_bytes); + const unsigned int dpte_buf_in_pte_reqs = mode_lib->ip.dpte_buffer_size_in_pte_reqs_luma; + const unsigned int pde_proc_buffer_size_64k_reqs = + mode_lib->ip.pde_proc_buffer_size_64k_reqs; + + unsigned int log2_vmpg_height = 0; + unsigned int log2_vmpg_width = 0; + unsigned int log2_dpte_req_height_ptes = 0; + unsigned int log2_dpte_req_height = 0; + unsigned int log2_dpte_req_width = 0; + unsigned int log2_dpte_row_height_linear = 0; + unsigned int log2_dpte_row_height = 0; + unsigned int log2_dpte_group_width = 0; + unsigned int dpte_row_width_ub = 0; + unsigned int dpte_req_height = 0; + unsigned int dpte_req_width = 0; + unsigned int dpte_group_width = 0; + unsigned int log2_dpte_group_bytes = 0; + unsigned int log2_dpte_group_length = 0; + unsigned int pde_buf_entries; + bool yuv420 = (source_format == dm_420_8 || source_format == dm_420_10); + + Calculate256BBlockSizes((enum source_format_class)(source_format), + (enum dm_swizzle_mode)(tiling), + bytes_per_element_y, + bytes_per_element_c, + &blk256_height_y, + &blk256_height_c, + &blk256_width_y, + &blk256_width_c); + + if (!is_chroma) { + blk256_width = blk256_width_y; + blk256_height = blk256_height_y; + bytes_per_element = bytes_per_element_y; + } else { + blk256_width = blk256_width_c; + blk256_height = blk256_height_c; + bytes_per_element = bytes_per_element_c; + } + + log2_bytes_per_element = dml_log2(bytes_per_element); + + dml_print("DML_DLG: %s: surf_linear = %d\n", __func__, surf_linear); + dml_print("DML_DLG: %s: surf_vert = %d\n", __func__, surf_vert); + dml_print("DML_DLG: %s: blk256_width = %d\n", __func__, blk256_width); + dml_print("DML_DLG: %s: blk256_height = %d\n", __func__, blk256_height); + + log2_blk256_width = dml_log2((double) blk256_width); + log2_blk256_height = dml_log2((double) blk256_height); + blk_bytes = surf_linear ? + 256 : get_blk_size_bytes((enum source_macro_tile_size) macro_tile_size); + log2_blk_bytes = dml_log2((double) blk_bytes); + log2_blk_height = 0; + log2_blk_width = 0; + + // remember log rule + // "+" in log is multiply + // "-" in log is divide + // "/2" is like square root + // blk is vertical biased + if (tiling != dm_sw_linear) + log2_blk_height = log2_blk256_height + + dml_ceil((double) (log2_blk_bytes - 8) / 2.0, 1); + else + log2_blk_height = 0; // blk height of 1 + + log2_blk_width = log2_blk_bytes - log2_bytes_per_element - log2_blk_height; + + if (!surf_vert) { + rq_dlg_param->swath_width_ub = dml_round_to_multiple(vp_width - 1, blk256_width, 1) + + blk256_width; + rq_dlg_param->req_per_swath_ub = rq_dlg_param->swath_width_ub >> log2_blk256_width; + } else { + rq_dlg_param->swath_width_ub = dml_round_to_multiple(vp_height - 1, blk256_height, 1) + + blk256_height; + rq_dlg_param->req_per_swath_ub = rq_dlg_param->swath_width_ub >> log2_blk256_height; + } + + if (!surf_vert) + rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_height + * bytes_per_element; + else + rq_misc_param->full_swath_bytes = rq_dlg_param->swath_width_ub * blk256_width + * bytes_per_element; + + rq_misc_param->blk256_height = blk256_height; + rq_misc_param->blk256_width = blk256_width; + + // ------- + // meta + // ------- + log2_meta_req_bytes = 6; // meta request is 64b and is 8x8byte meta element + + // each 64b meta request for dcn is 8x8 meta elements and + // a meta element covers one 256b block of the the data surface. + log2_meta_req_height = log2_blk256_height + 3; // meta req is 8x8 byte, each byte represent 1 blk256 + log2_meta_req_width = log2_meta_req_bytes + 8 - log2_bytes_per_element + - log2_meta_req_height; + meta_req_width = 1 << log2_meta_req_width; + meta_req_height = 1 << log2_meta_req_height; + log2_meta_row_height = 0; + meta_row_width_ub = 0; + + // the dimensions of a meta row are meta_row_width x meta_row_height in elements. + // calculate upper bound of the meta_row_width + if (!surf_vert) { + log2_meta_row_height = log2_meta_req_height; + meta_row_width_ub = dml_round_to_multiple(vp_width - 1, meta_req_width, 1) + + meta_req_width; + rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_width; + } else { + log2_meta_row_height = log2_meta_req_width; + meta_row_width_ub = dml_round_to_multiple(vp_height - 1, meta_req_height, 1) + + meta_req_height; + rq_dlg_param->meta_req_per_row_ub = meta_row_width_ub / meta_req_height; + } + rq_dlg_param->meta_bytes_per_row_ub = rq_dlg_param->meta_req_per_row_ub * 64; + + rq_dlg_param->meta_row_height = 1 << log2_meta_row_height; + + log2_meta_chunk_bytes = dml_log2(rq_sizing_param->meta_chunk_bytes); + log2_meta_chunk_height = log2_meta_row_height; + + //full sized meta chunk width in unit of data elements + log2_meta_chunk_width = log2_meta_chunk_bytes + 8 - log2_bytes_per_element + - log2_meta_chunk_height; + log2_min_meta_chunk_bytes = dml_log2(rq_sizing_param->min_meta_chunk_bytes); + min_meta_chunk_width = 1 + << (log2_min_meta_chunk_bytes + 8 - log2_bytes_per_element + - log2_meta_chunk_height); + meta_chunk_width = 1 << log2_meta_chunk_width; + meta_chunk_per_row_int = (unsigned int) (meta_row_width_ub / meta_chunk_width); + meta_row_remainder = meta_row_width_ub % meta_chunk_width; + meta_chunk_threshold = 0; + meta_blk_bytes = 4096; + meta_blk_height = blk256_height * 64; + meta_blk_width = meta_blk_bytes * 256 / bytes_per_element / meta_blk_height; + meta_surface_bytes = meta_pitch + * (dml_round_to_multiple(vp_height - 1, meta_blk_height, 1) + meta_blk_height) + * bytes_per_element / 256; + vmpg_bytes = mode_lib->soc.vmm_page_size_bytes; + meta_pte_req_per_frame_ub = (dml_round_to_multiple(meta_surface_bytes - vmpg_bytes, + 8 * vmpg_bytes, + 1) + 8 * vmpg_bytes) / (8 * vmpg_bytes); + meta_pte_bytes_per_frame_ub = meta_pte_req_per_frame_ub * 64; //64B mpte request + rq_dlg_param->meta_pte_bytes_per_frame_ub = meta_pte_bytes_per_frame_ub; + + dml_print("DML_DLG: %s: meta_blk_height = %d\n", __func__, meta_blk_height); + dml_print("DML_DLG: %s: meta_blk_width = %d\n", __func__, meta_blk_width); + dml_print("DML_DLG: %s: meta_surface_bytes = %d\n", __func__, meta_surface_bytes); + dml_print("DML_DLG: %s: meta_pte_req_per_frame_ub = %d\n", + __func__, + meta_pte_req_per_frame_ub); + dml_print("DML_DLG: %s: meta_pte_bytes_per_frame_ub = %d\n", + __func__, + meta_pte_bytes_per_frame_ub); + + if (!surf_vert) + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_width; + else + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_height; + + if (meta_row_remainder <= meta_chunk_threshold) + rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 1; + else + rq_dlg_param->meta_chunks_per_row_ub = meta_chunk_per_row_int + 2; + + // ------ + // dpte + // ------ + if (surf_linear) { + log2_vmpg_height = 0; // one line high + } else { + log2_vmpg_height = (log2_vmpg_bytes - 8) / 2 + log2_blk256_height; + } + log2_vmpg_width = log2_vmpg_bytes - log2_bytes_per_element - log2_vmpg_height; + + // only 3 possible shapes for dpte request in dimensions of ptes: 8x1, 4x2, 2x4. + if (surf_linear) { //one 64B PTE request returns 8 PTEs + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_vmpg_width + 3; + log2_dpte_req_height = 0; + } else if (log2_blk_bytes == 12) { //4KB tile means 4kB page size + //one 64B req gives 8x1 PTEs for 4KB tile + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_blk_width + 3; + log2_dpte_req_height = log2_blk_height + 0; + } else if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) { // tile block >= 64KB + //two 64B reqs of 2x4 PTEs give 16 PTEs to cover 64KB + log2_dpte_req_height_ptes = 4; + log2_dpte_req_width = log2_blk256_width + 4; // log2_64KB_width + log2_dpte_req_height = log2_blk256_height + 4; // log2_64KB_height + } else { //64KB page size and must 64KB tile block + //one 64B req gives 8x1 PTEs for 64KB tile + log2_dpte_req_height_ptes = 0; + log2_dpte_req_width = log2_blk_width + 3; + log2_dpte_req_height = log2_blk_height + 0; + } + + // The dpte request dimensions in data elements is dpte_req_width x dpte_req_height + // log2_vmpg_width is how much 1 pte represent, now calculating how much a 64b pte req represent + // That depends on the pte shape (i.e. 8x1, 4x2, 2x4) + //log2_dpte_req_height = log2_vmpg_height + log2_dpte_req_height_ptes; + //log2_dpte_req_width = log2_vmpg_width + log2_dpte_req_width_ptes; + dpte_req_height = 1 << log2_dpte_req_height; + dpte_req_width = 1 << log2_dpte_req_width; + + // calculate pitch dpte row buffer can hold + // round the result down to a power of two. + pde_buf_entries = yuv420 ? (pde_proc_buffer_size_64k_reqs >> 1) : pde_proc_buffer_size_64k_reqs; + if (surf_linear) { + unsigned int dpte_row_height; + + log2_dpte_row_height_linear = dml_floor(dml_log2(dml_min(64 * 1024 * pde_buf_entries + / bytes_per_element, + dpte_buf_in_pte_reqs + * dpte_req_width) + / data_pitch), + 1); + + ASSERT(log2_dpte_row_height_linear >= 3); + + if (log2_dpte_row_height_linear > 7) + log2_dpte_row_height_linear = 7; + + log2_dpte_row_height = log2_dpte_row_height_linear; + // For linear, the dpte row is pitch dependent and the pte requests wrap at the pitch boundary. + // the dpte_row_width_ub is the upper bound of data_pitch*dpte_row_height in elements with this unique buffering. + dpte_row_height = 1 << log2_dpte_row_height; + dpte_row_width_ub = dml_round_to_multiple(data_pitch * dpte_row_height - 1, + dpte_req_width, + 1) + dpte_req_width; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; + } else { + // the upper bound of the dpte_row_width without dependency on viewport position follows. + // for tiled mode, row height is the same as req height and row store up to vp size upper bound + if (!surf_vert) { + log2_dpte_row_height = log2_dpte_req_height; + dpte_row_width_ub = dml_round_to_multiple(vp_width - 1, dpte_req_width, 1) + + dpte_req_width; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_width; + } else { + log2_dpte_row_height = + (log2_blk_width < log2_dpte_req_width) ? + log2_blk_width : log2_dpte_req_width; + dpte_row_width_ub = dml_round_to_multiple(vp_height - 1, dpte_req_height, 1) + + dpte_req_height; + rq_dlg_param->dpte_req_per_row_ub = dpte_row_width_ub / dpte_req_height; + } + } + if (log2_blk_bytes >= 16 && log2_vmpg_bytes == 12) // tile block >= 64KB + rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 128; //2*64B dpte request + else + rq_dlg_param->dpte_bytes_per_row_ub = rq_dlg_param->dpte_req_per_row_ub * 64; //64B dpte request + + rq_dlg_param->dpte_row_height = 1 << log2_dpte_row_height; + + // 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 + rq_sizing_param->dpte_group_bytes = 512; + else + //full size + rq_sizing_param->dpte_group_bytes = 2048; + + //since pte request size is 64byte, the number of data pte requests per full sized group is as follows. + log2_dpte_group_bytes = dml_log2(rq_sizing_param->dpte_group_bytes); + log2_dpte_group_length = log2_dpte_group_bytes - 6; //length in 64b requests + + // full sized data pte group width in elements + if (!surf_vert) + log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_width; + else + log2_dpte_group_width = log2_dpte_group_length + log2_dpte_req_height; + + //But if the tile block >=64KB and the page size is 4KB, then each dPTE request is 2*64B + if ((log2_blk_bytes >= 16) && (log2_vmpg_bytes == 12)) // tile block >= 64KB + log2_dpte_group_width = log2_dpte_group_width - 1; + + dpte_group_width = 1 << log2_dpte_group_width; + + // since dpte groups are only aligned to dpte_req_width and not dpte_group_width, + // the upper bound for the dpte groups per row is as follows. + rq_dlg_param->dpte_groups_per_row_ub = dml_ceil((double) dpte_row_width_ub / dpte_group_width, + 1); +} + +static void get_surf_rq_param(struct display_mode_lib *mode_lib, + display_data_rq_sizing_params_st *rq_sizing_param, + display_data_rq_dlg_params_st *rq_dlg_param, + display_data_rq_misc_params_st *rq_misc_param, + const display_pipe_source_params_st pipe_src_param, + bool is_chroma) +{ + bool mode_422 = 0; + unsigned int vp_width = 0; + unsigned int vp_height = 0; + unsigned int data_pitch = 0; + unsigned int meta_pitch = 0; + unsigned int ppe = mode_422 ? 2 : 1; + + // FIXME check if ppe apply for both luma and chroma in 422 case + if (is_chroma) { + vp_width = pipe_src_param.viewport_width_c / ppe; + vp_height = pipe_src_param.viewport_height_c; + data_pitch = pipe_src_param.data_pitch_c; + meta_pitch = pipe_src_param.meta_pitch_c; + } else { + vp_width = pipe_src_param.viewport_width / ppe; + vp_height = pipe_src_param.viewport_height; + data_pitch = pipe_src_param.data_pitch; + meta_pitch = pipe_src_param.meta_pitch; + } + + rq_sizing_param->chunk_bytes = 8192; + + if (rq_sizing_param->chunk_bytes == 64 * 1024) + rq_sizing_param->min_chunk_bytes = 0; + else + rq_sizing_param->min_chunk_bytes = 1024; + + rq_sizing_param->meta_chunk_bytes = 2048; + rq_sizing_param->min_meta_chunk_bytes = 256; + + rq_sizing_param->mpte_group_bytes = 2048; + + get_meta_and_pte_attr(mode_lib, + rq_dlg_param, + rq_misc_param, + rq_sizing_param, + vp_width, + vp_height, + data_pitch, + meta_pitch, + pipe_src_param.source_format, + pipe_src_param.sw_mode, + pipe_src_param.macro_tile_size, + pipe_src_param.source_scan, + is_chroma); +} + +static void dml20_rq_dlg_get_rq_params(struct display_mode_lib *mode_lib, + display_rq_params_st *rq_param, + const display_pipe_source_params_st pipe_src_param) +{ + // get param for luma surface + rq_param->yuv420 = pipe_src_param.source_format == dm_420_8 + || pipe_src_param.source_format == dm_420_10; + rq_param->yuv420_10bpc = pipe_src_param.source_format == dm_420_10; + + get_surf_rq_param(mode_lib, + &(rq_param->sizing.rq_l), + &(rq_param->dlg.rq_l), + &(rq_param->misc.rq_l), + pipe_src_param, + 0); + + if (is_dual_plane((enum source_format_class)(pipe_src_param.source_format))) { + // get param for chroma surface + get_surf_rq_param(mode_lib, + &(rq_param->sizing.rq_c), + &(rq_param->dlg.rq_c), + &(rq_param->misc.rq_c), + pipe_src_param, + 1); + } + + // calculate how to split the det buffer space between luma and chroma + handle_det_buf_split(mode_lib, rq_param, pipe_src_param); + print__rq_params_st(mode_lib, *rq_param); +} + +void dml20_rq_dlg_get_rq_reg(struct display_mode_lib *mode_lib, + display_rq_regs_st *rq_regs, + const display_pipe_params_st pipe_param) +{ + display_rq_params_st rq_param = {0}; + + memset(rq_regs, 0, sizeof(*rq_regs)); + dml20_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param.src); + extract_rq_regs(mode_lib, rq_regs, rq_param); + + print__rq_regs_st(mode_lib, *rq_regs); +} + +// Note: currently taken in as is. +// Nice to decouple code from hw register implement and extract code that are repeated for luma and chroma. +static void dml20_rq_dlg_get_dlg_params(struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + display_dlg_regs_st *disp_dlg_regs, + display_ttu_regs_st *disp_ttu_regs, + const display_rq_dlg_params_st rq_dlg_param, + const display_dlg_sys_params_st dlg_sys_param, + const bool cstate_en, + const bool pstate_en) +{ + const display_pipe_source_params_st *src = &e2e_pipe_param[pipe_idx].pipe.src; + const display_pipe_dest_params_st *dst = &e2e_pipe_param[pipe_idx].pipe.dest; + const display_output_params_st *dout = &e2e_pipe_param[pipe_idx].dout; + const display_clocks_and_cfg_st *clks = &e2e_pipe_param[pipe_idx].clks_cfg; + const scaler_ratio_depth_st *scl = &e2e_pipe_param[pipe_idx].pipe.scale_ratio_depth; + const scaler_taps_st *taps = &e2e_pipe_param[pipe_idx].pipe.scale_taps; + + // ------------------------- + // Section 1.15.2.1: OTG dependent Params + // ------------------------- + // Timing + unsigned int htotal = dst->htotal; +// unsigned int hblank_start = dst.hblank_start; // TODO: Remove + unsigned int hblank_end = dst->hblank_end; + unsigned int vblank_start = dst->vblank_start; + unsigned int vblank_end = dst->vblank_end; + unsigned int min_vblank = mode_lib->ip.min_vblank_lines; + + double dppclk_freq_in_mhz = clks->dppclk_mhz; + double dispclk_freq_in_mhz = clks->dispclk_mhz; + double refclk_freq_in_mhz = clks->refclk_mhz; + double pclk_freq_in_mhz = dst->pixel_rate_mhz; + bool interlaced = dst->interlaced; + + double ref_freq_to_pix_freq = refclk_freq_in_mhz / pclk_freq_in_mhz; + + double min_dcfclk_mhz; + double t_calc_us; + double min_ttu_vblank; + + double min_dst_y_ttu_vblank; + unsigned int dlg_vblank_start; + bool dual_plane; + bool mode_422; + unsigned int access_dir; + unsigned int vp_height_l; + unsigned int vp_width_l; + unsigned int vp_height_c; + unsigned int vp_width_c; + + // Scaling + unsigned int htaps_l; + unsigned int htaps_c; + double hratio_l; + double hratio_c; + double vratio_l; + double vratio_c; + bool scl_enable; + + double line_time_in_us; + // double vinit_l; + // double vinit_c; + // double vinit_bot_l; + // double vinit_bot_c; + + // unsigned int swath_height_l; + unsigned int swath_width_ub_l; + // unsigned int dpte_bytes_per_row_ub_l; + unsigned int dpte_groups_per_row_ub_l; + // unsigned int meta_pte_bytes_per_frame_ub_l; + // unsigned int meta_bytes_per_row_ub_l; + + // unsigned int swath_height_c; + unsigned int swath_width_ub_c; + // unsigned int dpte_bytes_per_row_ub_c; + unsigned int dpte_groups_per_row_ub_c; + + unsigned int meta_chunks_per_row_ub_l; + unsigned int meta_chunks_per_row_ub_c; + unsigned int vupdate_offset; + unsigned int vupdate_width; + unsigned int vready_offset; + + unsigned int dppclk_delay_subtotal; + unsigned int dispclk_delay_subtotal; + unsigned int pixel_rate_delay_subtotal; + + unsigned int vstartup_start; + unsigned int dst_x_after_scaler; + unsigned int dst_y_after_scaler; + double line_wait; + double dst_y_prefetch; + double dst_y_per_vm_vblank; + double dst_y_per_row_vblank; + double dst_y_per_vm_flip; + double dst_y_per_row_flip; + double min_dst_y_per_vm_vblank; + double min_dst_y_per_row_vblank; + double lsw; + double vratio_pre_l; + double vratio_pre_c; + unsigned int req_per_swath_ub_l; + unsigned int req_per_swath_ub_c; + unsigned int meta_row_height_l; + unsigned int meta_row_height_c; + unsigned int swath_width_pixels_ub_l; + unsigned int swath_width_pixels_ub_c; + unsigned int scaler_rec_in_width_l; + unsigned int scaler_rec_in_width_c; + unsigned int dpte_row_height_l; + unsigned int dpte_row_height_c; + double hscale_pixel_rate_l; + double hscale_pixel_rate_c; + double min_hratio_fact_l; + double min_hratio_fact_c; + double refcyc_per_line_delivery_pre_l; + double refcyc_per_line_delivery_pre_c; + double refcyc_per_line_delivery_l; + double refcyc_per_line_delivery_c; + + double refcyc_per_req_delivery_pre_l; + double refcyc_per_req_delivery_pre_c; + double refcyc_per_req_delivery_l; + double refcyc_per_req_delivery_c; + + unsigned int full_recout_width; + double xfc_transfer_delay; + double xfc_precharge_delay; + double xfc_remote_surface_flip_latency; + double xfc_dst_y_delta_drq_limit; + double xfc_prefetch_margin; + double refcyc_per_req_delivery_pre_cur0; + double refcyc_per_req_delivery_cur0; + double refcyc_per_req_delivery_pre_cur1; + double refcyc_per_req_delivery_cur1; + + memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs)); + memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs)); + + dml_print("DML_DLG: %s: cstate_en = %d\n", __func__, cstate_en); + dml_print("DML_DLG: %s: pstate_en = %d\n", __func__, pstate_en); + + dml_print("DML_DLG: %s: dppclk_freq_in_mhz = %3.2f\n", __func__, dppclk_freq_in_mhz); + dml_print("DML_DLG: %s: dispclk_freq_in_mhz = %3.2f\n", __func__, dispclk_freq_in_mhz); + dml_print("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, refclk_freq_in_mhz); + dml_print("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, pclk_freq_in_mhz); + dml_print("DML_DLG: %s: interlaced = %d\n", __func__, interlaced); + ASSERT(ref_freq_to_pix_freq < 4.0); + + disp_dlg_regs->ref_freq_to_pix_freq = + (unsigned int) (ref_freq_to_pix_freq * dml_pow(2, 19)); + disp_dlg_regs->refcyc_per_htotal = (unsigned int) (ref_freq_to_pix_freq * (double) htotal + * dml_pow(2, 8)); + disp_dlg_regs->dlg_vblank_end = interlaced ? (vblank_end / 2) : vblank_end; // 15 bits + disp_dlg_regs->refcyc_h_blank_end = (unsigned int) ((double) hblank_end + * (double) ref_freq_to_pix_freq); + ASSERT(disp_dlg_regs->refcyc_h_blank_end < (unsigned int) dml_pow(2, 13)); + + min_dcfclk_mhz = dlg_sys_param.deepsleep_dcfclk_mhz; + t_calc_us = get_tcalc(mode_lib, e2e_pipe_param, num_pipes); + min_ttu_vblank = get_min_ttu_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + + min_dst_y_ttu_vblank = min_ttu_vblank * pclk_freq_in_mhz / (double) htotal; + dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start; + + disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start + + min_dst_y_ttu_vblank) * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int) dml_pow(2, 18)); + + dml_print("DML_DLG: %s: min_dcfclk_mhz = %3.2f\n", + __func__, + min_dcfclk_mhz); + dml_print("DML_DLG: %s: min_ttu_vblank = %3.2f\n", + __func__, + min_ttu_vblank); + dml_print("DML_DLG: %s: min_dst_y_ttu_vblank = %3.2f\n", + __func__, + min_dst_y_ttu_vblank); + dml_print("DML_DLG: %s: t_calc_us = %3.2f\n", + __func__, + t_calc_us); + dml_print("DML_DLG: %s: disp_dlg_regs->min_dst_y_next_start = 0x%0x\n", + __func__, + disp_dlg_regs->min_dst_y_next_start); + dml_print("DML_DLG: %s: ref_freq_to_pix_freq = %3.2f\n", + __func__, + ref_freq_to_pix_freq); + + // ------------------------- + // Section 1.15.2.2: Prefetch, Active and TTU + // ------------------------- + // Prefetch Calc + // Source +// dcc_en = src.dcc; + dual_plane = is_dual_plane((enum source_format_class)(src->source_format)); + mode_422 = 0; // FIXME + access_dir = (src->source_scan == dm_vert); // vp access direction: horizontal or vertical accessed +// bytes_per_element_l = get_bytes_per_element(source_format_class(src.source_format), 0); +// bytes_per_element_c = get_bytes_per_element(source_format_class(src.source_format), 1); + vp_height_l = src->viewport_height; + vp_width_l = src->viewport_width; + vp_height_c = src->viewport_height_c; + vp_width_c = src->viewport_width_c; + + // Scaling + htaps_l = taps->htaps; + htaps_c = taps->htaps_c; + hratio_l = scl->hscl_ratio; + hratio_c = scl->hscl_ratio_c; + vratio_l = scl->vscl_ratio; + vratio_c = scl->vscl_ratio_c; + scl_enable = scl->scl_enable; + + line_time_in_us = (htotal / pclk_freq_in_mhz); +// vinit_l = scl.vinit; +// vinit_c = scl.vinit_c; +// vinit_bot_l = scl.vinit_bot; +// vinit_bot_c = scl.vinit_bot_c; + +// unsigned int swath_height_l = rq_dlg_param.rq_l.swath_height; + swath_width_ub_l = rq_dlg_param.rq_l.swath_width_ub; +// unsigned int dpte_bytes_per_row_ub_l = rq_dlg_param.rq_l.dpte_bytes_per_row_ub; + dpte_groups_per_row_ub_l = rq_dlg_param.rq_l.dpte_groups_per_row_ub; +// unsigned int meta_pte_bytes_per_frame_ub_l = rq_dlg_param.rq_l.meta_pte_bytes_per_frame_ub; +// unsigned int meta_bytes_per_row_ub_l = rq_dlg_param.rq_l.meta_bytes_per_row_ub; + +// unsigned int swath_height_c = rq_dlg_param.rq_c.swath_height; + swath_width_ub_c = rq_dlg_param.rq_c.swath_width_ub; + // dpte_bytes_per_row_ub_c = rq_dlg_param.rq_c.dpte_bytes_per_row_ub; + dpte_groups_per_row_ub_c = rq_dlg_param.rq_c.dpte_groups_per_row_ub; + + meta_chunks_per_row_ub_l = rq_dlg_param.rq_l.meta_chunks_per_row_ub; + meta_chunks_per_row_ub_c = rq_dlg_param.rq_c.meta_chunks_per_row_ub; + vupdate_offset = dst->vupdate_offset; + vupdate_width = dst->vupdate_width; + vready_offset = dst->vready_offset; + + dppclk_delay_subtotal = mode_lib->ip.dppclk_delay_subtotal; + dispclk_delay_subtotal = mode_lib->ip.dispclk_delay_subtotal; + + if (scl_enable) + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl; + else + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_scl_lb_only; + + dppclk_delay_subtotal += mode_lib->ip.dppclk_delay_cnvc_formatter + + src->num_cursors * mode_lib->ip.dppclk_delay_cnvc_cursor; + + if (dout->dsc_enable) { + double dsc_delay = get_dsc_delay(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + + dispclk_delay_subtotal += dsc_delay; + } + + pixel_rate_delay_subtotal = dppclk_delay_subtotal * pclk_freq_in_mhz / dppclk_freq_in_mhz + + dispclk_delay_subtotal * pclk_freq_in_mhz / dispclk_freq_in_mhz; + + vstartup_start = dst->vstartup_start; + if (interlaced) { + if (vstartup_start / 2.0 + - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal + <= vblank_end / 2.0) + disp_dlg_regs->vready_after_vcount0 = 1; + else + disp_dlg_regs->vready_after_vcount0 = 0; + } else { + if (vstartup_start + - (double) (vready_offset + vupdate_width + vupdate_offset) / htotal + <= vblank_end) + disp_dlg_regs->vready_after_vcount0 = 1; + else + disp_dlg_regs->vready_after_vcount0 = 0; + } + + // TODO: Where is this coming from? + if (interlaced) + vstartup_start = vstartup_start / 2; + + // TODO: What if this min_vblank doesn't match the value in the dml_config_settings.cpp? + if (vstartup_start >= min_vblank) { + dml_print("WARNING: DML_DLG: %s: vblank_start=%d vblank_end=%d\n", + __func__, + vblank_start, + vblank_end); + dml_print("WARNING: DML_DLG: %s: vstartup_start=%d should be less than min_vblank=%d\n", + __func__, + vstartup_start, + min_vblank); + min_vblank = vstartup_start + 1; + dml_print("WARNING: DML_DLG: %s: vstartup_start=%d should be less than min_vblank=%d\n", + __func__, + vstartup_start, + min_vblank); + } + + dst_x_after_scaler = get_dst_x_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + dst_y_after_scaler = get_dst_y_after_scaler(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + + dml_print("DML_DLG: %s: htotal = %d\n", __func__, htotal); + dml_print("DML_DLG: %s: pixel_rate_delay_subtotal = %d\n", + __func__, + pixel_rate_delay_subtotal); + dml_print("DML_DLG: %s: dst_x_after_scaler = %d\n", + __func__, + dst_x_after_scaler); + dml_print("DML_DLG: %s: dst_y_after_scaler = %d\n", + __func__, + dst_y_after_scaler); + + // Lwait + line_wait = mode_lib->soc.urgent_latency_us; + if (cstate_en) + line_wait = dml_max(mode_lib->soc.sr_enter_plus_exit_time_us, line_wait); + if (pstate_en) + line_wait = dml_max(mode_lib->soc.dram_clock_change_latency_us + + mode_lib->soc.urgent_latency_us, + line_wait); + line_wait = line_wait / line_time_in_us; + + dst_y_prefetch = get_dst_y_prefetch(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + dml_print("DML_DLG: %s: dst_y_prefetch (after rnd) = %3.2f\n", __func__, dst_y_prefetch); + + dst_y_per_vm_vblank = get_dst_y_per_vm_vblank(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx); + dst_y_per_row_vblank = get_dst_y_per_row_vblank(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx); + dst_y_per_vm_flip = get_dst_y_per_vm_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + dst_y_per_row_flip = get_dst_y_per_row_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + + min_dst_y_per_vm_vblank = 8.0; + min_dst_y_per_row_vblank = 16.0; + + // magic! + if (htotal <= 75) { + min_vblank = 300; + min_dst_y_per_vm_vblank = 100.0; + min_dst_y_per_row_vblank = 100.0; + } + + dml_print("DML_DLG: %s: dst_y_per_vm_vblank = %3.2f\n", __func__, dst_y_per_vm_vblank); + dml_print("DML_DLG: %s: dst_y_per_row_vblank = %3.2f\n", __func__, dst_y_per_row_vblank); + + ASSERT(dst_y_per_vm_vblank < min_dst_y_per_vm_vblank); + ASSERT(dst_y_per_row_vblank < min_dst_y_per_row_vblank); + + ASSERT(dst_y_prefetch > (dst_y_per_vm_vblank + dst_y_per_row_vblank)); + lsw = dst_y_prefetch - (dst_y_per_vm_vblank + dst_y_per_row_vblank); + + dml_print("DML_DLG: %s: lsw = %3.2f\n", __func__, lsw); + + vratio_pre_l = get_vratio_prefetch_l(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + vratio_pre_c = get_vratio_prefetch_c(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + + dml_print("DML_DLG: %s: vratio_pre_l=%3.2f\n", __func__, vratio_pre_l); + dml_print("DML_DLG: %s: vratio_pre_c=%3.2f\n", __func__, vratio_pre_c); + + // Active + req_per_swath_ub_l = rq_dlg_param.rq_l.req_per_swath_ub; + req_per_swath_ub_c = rq_dlg_param.rq_c.req_per_swath_ub; + meta_row_height_l = rq_dlg_param.rq_l.meta_row_height; + meta_row_height_c = rq_dlg_param.rq_c.meta_row_height; + swath_width_pixels_ub_l = 0; + swath_width_pixels_ub_c = 0; + scaler_rec_in_width_l = 0; + scaler_rec_in_width_c = 0; + dpte_row_height_l = rq_dlg_param.rq_l.dpte_row_height; + dpte_row_height_c = rq_dlg_param.rq_c.dpte_row_height; + + if (mode_422) { + swath_width_pixels_ub_l = swath_width_ub_l * 2; // *2 for 2 pixel per element + swath_width_pixels_ub_c = swath_width_ub_c * 2; + } else { + swath_width_pixels_ub_l = swath_width_ub_l * 1; + swath_width_pixels_ub_c = swath_width_ub_c * 1; + } + + hscale_pixel_rate_l = 0.; + hscale_pixel_rate_c = 0.; + min_hratio_fact_l = 1.0; + min_hratio_fact_c = 1.0; + + if (htaps_l <= 1) + min_hratio_fact_l = 2.0; + else if (htaps_l <= 6) { + if ((hratio_l * 2.0) > 4.0) + min_hratio_fact_l = 4.0; + else + min_hratio_fact_l = hratio_l * 2.0; + } else { + if (hratio_l > 4.0) + min_hratio_fact_l = 4.0; + else + min_hratio_fact_l = hratio_l; + } + + hscale_pixel_rate_l = min_hratio_fact_l * dppclk_freq_in_mhz; + + if (htaps_c <= 1) + min_hratio_fact_c = 2.0; + else if (htaps_c <= 6) { + if ((hratio_c * 2.0) > 4.0) + min_hratio_fact_c = 4.0; + else + min_hratio_fact_c = hratio_c * 2.0; + } else { + if (hratio_c > 4.0) + min_hratio_fact_c = 4.0; + else + min_hratio_fact_c = hratio_c; + } + + hscale_pixel_rate_c = min_hratio_fact_c * dppclk_freq_in_mhz; + + refcyc_per_line_delivery_pre_l = 0.; + refcyc_per_line_delivery_pre_c = 0.; + refcyc_per_line_delivery_l = 0.; + refcyc_per_line_delivery_c = 0.; + + refcyc_per_req_delivery_pre_l = 0.; + refcyc_per_req_delivery_pre_c = 0.; + refcyc_per_req_delivery_l = 0.; + refcyc_per_req_delivery_c = 0.; + + full_recout_width = 0; + // In ODM + if (src->is_hsplit) { + // This "hack" is only allowed (and valid) for MPC combine. In ODM + // combine, you MUST specify the full_recout_width...according to Oswin + if (dst->full_recout_width == 0 && !dst->odm_combine) { + dml_print("DML_DLG: %s: Warning: full_recout_width not set in hsplit mode\n", + __func__); + full_recout_width = dst->recout_width * 2; // assume half split for dcn1 + } else + full_recout_width = dst->full_recout_width; + } else + full_recout_width = dst->recout_width; + + // As of DCN2, mpc_combine and odm_combine are mutually exclusive + refcyc_per_line_delivery_pre_l = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_l, + hscale_pixel_rate_l, + swath_width_pixels_ub_l, + 1); // per line + + refcyc_per_line_delivery_l = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_l, + hscale_pixel_rate_l, + swath_width_pixels_ub_l, + 1); // per line + + dml_print("DML_DLG: %s: full_recout_width = %d\n", + __func__, + full_recout_width); + dml_print("DML_DLG: %s: hscale_pixel_rate_l = %3.2f\n", + __func__, + hscale_pixel_rate_l); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_l = %3.2f\n", + __func__, + refcyc_per_line_delivery_pre_l); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_l = %3.2f\n", + __func__, + refcyc_per_line_delivery_l); + + if (dual_plane) { + refcyc_per_line_delivery_pre_c = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_c, + hscale_pixel_rate_c, + swath_width_pixels_ub_c, + 1); // per line + + refcyc_per_line_delivery_c = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_c, + hscale_pixel_rate_c, + swath_width_pixels_ub_c, + 1); // per line + + dml_print("DML_DLG: %s: refcyc_per_line_delivery_pre_c = %3.2f\n", + __func__, + refcyc_per_line_delivery_pre_c); + dml_print("DML_DLG: %s: refcyc_per_line_delivery_c = %3.2f\n", + __func__, + refcyc_per_line_delivery_c); + } + + // TTU - Luma / Chroma + if (access_dir) { // vertical access + scaler_rec_in_width_l = vp_height_l; + scaler_rec_in_width_c = vp_height_c; + } else { + scaler_rec_in_width_l = vp_width_l; + scaler_rec_in_width_c = vp_width_c; + } + + refcyc_per_req_delivery_pre_l = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_l, + hscale_pixel_rate_l, + scaler_rec_in_width_l, + req_per_swath_ub_l); // per req + refcyc_per_req_delivery_l = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_l, + hscale_pixel_rate_l, + scaler_rec_in_width_l, + req_per_swath_ub_l); // per req + + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_l = %3.2f\n", + __func__, + refcyc_per_req_delivery_pre_l); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_l = %3.2f\n", + __func__, + refcyc_per_req_delivery_l); + + ASSERT(refcyc_per_req_delivery_pre_l < dml_pow(2, 13)); + ASSERT(refcyc_per_req_delivery_l < dml_pow(2, 13)); + + if (dual_plane) { + refcyc_per_req_delivery_pre_c = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_pre_c, + hscale_pixel_rate_c, + scaler_rec_in_width_c, + req_per_swath_ub_c); // per req + refcyc_per_req_delivery_c = get_refcyc_per_delivery(mode_lib, + refclk_freq_in_mhz, + pclk_freq_in_mhz, + dst->odm_combine, + full_recout_width, + dst->hactive, + vratio_c, + hscale_pixel_rate_c, + scaler_rec_in_width_c, + req_per_swath_ub_c); // per req + + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_c = %3.2f\n", + __func__, + refcyc_per_req_delivery_pre_c); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_c = %3.2f\n", + __func__, + refcyc_per_req_delivery_c); + + ASSERT(refcyc_per_req_delivery_pre_c < dml_pow(2, 13)); + ASSERT(refcyc_per_req_delivery_c < dml_pow(2, 13)); + } + + // XFC + xfc_transfer_delay = get_xfc_transfer_delay(mode_lib, e2e_pipe_param, num_pipes, pipe_idx); + xfc_precharge_delay = get_xfc_precharge_delay(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx); + xfc_remote_surface_flip_latency = get_xfc_remote_surface_flip_latency(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx); + xfc_dst_y_delta_drq_limit = xfc_remote_surface_flip_latency; + xfc_prefetch_margin = get_xfc_prefetch_margin(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx); + + // TTU - Cursor + refcyc_per_req_delivery_pre_cur0 = 0.0; + refcyc_per_req_delivery_cur0 = 0.0; + if (src->num_cursors > 0) { + calculate_ttu_cursor(mode_lib, + &refcyc_per_req_delivery_pre_cur0, + &refcyc_per_req_delivery_cur0, + refclk_freq_in_mhz, + ref_freq_to_pix_freq, + hscale_pixel_rate_l, + scl->hscl_ratio, + vratio_pre_l, + vratio_l, + src->cur0_src_width, + (enum cursor_bpp)(src->cur0_bpp)); + } + + refcyc_per_req_delivery_pre_cur1 = 0.0; + refcyc_per_req_delivery_cur1 = 0.0; + if (src->num_cursors > 1) { + calculate_ttu_cursor(mode_lib, + &refcyc_per_req_delivery_pre_cur1, + &refcyc_per_req_delivery_cur1, + refclk_freq_in_mhz, + ref_freq_to_pix_freq, + hscale_pixel_rate_l, + scl->hscl_ratio, + vratio_pre_l, + vratio_l, + src->cur1_src_width, + (enum cursor_bpp)(src->cur1_bpp)); + } + + // TTU - Misc + // all hard-coded + + // Assignment to register structures + disp_dlg_regs->dst_y_after_scaler = dst_y_after_scaler; // in terms of line + disp_dlg_regs->refcyc_x_after_scaler = dst_x_after_scaler * ref_freq_to_pix_freq; // in terms of refclk + ASSERT(disp_dlg_regs->refcyc_x_after_scaler < (unsigned int) dml_pow(2, 13)); + disp_dlg_regs->dst_y_prefetch = (unsigned int) (dst_y_prefetch * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_vm_vblank = (unsigned int) (dst_y_per_vm_vblank * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_row_vblank = (unsigned int) (dst_y_per_row_vblank * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_vm_flip = (unsigned int) (dst_y_per_vm_flip * dml_pow(2, 2)); + disp_dlg_regs->dst_y_per_row_flip = (unsigned int) (dst_y_per_row_flip * dml_pow(2, 2)); + + disp_dlg_regs->vratio_prefetch = (unsigned int) (vratio_pre_l * dml_pow(2, 19)); + disp_dlg_regs->vratio_prefetch_c = (unsigned int) (vratio_pre_c * dml_pow(2, 19)); + + disp_dlg_regs->refcyc_per_pte_group_vblank_l = + (unsigned int) (dst_y_per_row_vblank * (double) htotal + * ref_freq_to_pix_freq / (double) dpte_groups_per_row_ub_l); + ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_l < (unsigned int) dml_pow(2, 13)); + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_vblank_c = (unsigned int) (dst_y_per_row_vblank + * (double) htotal * ref_freq_to_pix_freq + / (double) dpte_groups_per_row_ub_c); + ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_c + < (unsigned int) dml_pow(2, 13)); + } + + disp_dlg_regs->refcyc_per_meta_chunk_vblank_l = + (unsigned int) (dst_y_per_row_vblank * (double) htotal + * ref_freq_to_pix_freq / (double) meta_chunks_per_row_ub_l); + ASSERT(disp_dlg_regs->refcyc_per_meta_chunk_vblank_l < (unsigned int) dml_pow(2, 13)); + + disp_dlg_regs->refcyc_per_meta_chunk_vblank_c = + disp_dlg_regs->refcyc_per_meta_chunk_vblank_l; // dcc for 4:2:0 is not supported in dcn1.0. assigned to be the same as _l for now + + disp_dlg_regs->refcyc_per_pte_group_flip_l = (unsigned int) (dst_y_per_row_flip * htotal + * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_l; + disp_dlg_regs->refcyc_per_meta_chunk_flip_l = (unsigned int) (dst_y_per_row_flip * htotal + * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_l; + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_flip_c = (unsigned int) (dst_y_per_row_flip + * htotal * ref_freq_to_pix_freq) / dpte_groups_per_row_ub_c; + disp_dlg_regs->refcyc_per_meta_chunk_flip_c = (unsigned int) (dst_y_per_row_flip + * htotal * ref_freq_to_pix_freq) / meta_chunks_per_row_ub_c; + } + + disp_dlg_regs->dst_y_per_pte_row_nom_l = (unsigned int) ((double) dpte_row_height_l + / (double) vratio_l * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->dst_y_per_pte_row_nom_l < (unsigned int) dml_pow(2, 17)); + + if (dual_plane) { + disp_dlg_regs->dst_y_per_pte_row_nom_c = (unsigned int) ((double) dpte_row_height_c + / (double) vratio_c * dml_pow(2, 2)); + if (disp_dlg_regs->dst_y_per_pte_row_nom_c >= (unsigned int) dml_pow(2, 17)) { + dml_print("DML_DLG: %s: Warning dst_y_per_pte_row_nom_c %u larger than supported by register format U15.2 %u\n", + __func__, + disp_dlg_regs->dst_y_per_pte_row_nom_c, + (unsigned int) dml_pow(2, 17) - 1); + } + } + + disp_dlg_regs->dst_y_per_meta_row_nom_l = (unsigned int) ((double) meta_row_height_l + / (double) vratio_l * dml_pow(2, 2)); + ASSERT(disp_dlg_regs->dst_y_per_meta_row_nom_l < (unsigned int) dml_pow(2, 17)); + + disp_dlg_regs->dst_y_per_meta_row_nom_c = disp_dlg_regs->dst_y_per_meta_row_nom_l; // TODO: dcc for 4:2:0 is not supported in dcn1.0. assigned to be the same as _l for now + + disp_dlg_regs->refcyc_per_pte_group_nom_l = (unsigned int) ((double) dpte_row_height_l + / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq + / (double) dpte_groups_per_row_ub_l); + if (disp_dlg_regs->refcyc_per_pte_group_nom_l >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_pte_group_nom_l = dml_pow(2, 23) - 1; + disp_dlg_regs->refcyc_per_meta_chunk_nom_l = (unsigned int) ((double) meta_row_height_l + / (double) vratio_l * (double) htotal * ref_freq_to_pix_freq + / (double) meta_chunks_per_row_ub_l); + if (disp_dlg_regs->refcyc_per_meta_chunk_nom_l >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_meta_chunk_nom_l = dml_pow(2, 23) - 1; + + if (dual_plane) { + disp_dlg_regs->refcyc_per_pte_group_nom_c = + (unsigned int) ((double) dpte_row_height_c / (double) vratio_c + * (double) htotal * ref_freq_to_pix_freq + / (double) dpte_groups_per_row_ub_c); + if (disp_dlg_regs->refcyc_per_pte_group_nom_c >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_pte_group_nom_c = dml_pow(2, 23) - 1; + + // TODO: Is this the right calculation? Does htotal need to be halved? + disp_dlg_regs->refcyc_per_meta_chunk_nom_c = + (unsigned int) ((double) meta_row_height_c / (double) vratio_c + * (double) htotal * ref_freq_to_pix_freq + / (double) meta_chunks_per_row_ub_c); + if (disp_dlg_regs->refcyc_per_meta_chunk_nom_c >= (unsigned int) dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_meta_chunk_nom_c = dml_pow(2, 23) - 1; + } + + disp_dlg_regs->refcyc_per_line_delivery_pre_l = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_l, + 1); + disp_dlg_regs->refcyc_per_line_delivery_l = (unsigned int) dml_floor(refcyc_per_line_delivery_l, + 1); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_l < (unsigned int) dml_pow(2, 13)); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_l < (unsigned int) dml_pow(2, 13)); + + disp_dlg_regs->refcyc_per_line_delivery_pre_c = (unsigned int) dml_floor(refcyc_per_line_delivery_pre_c, + 1); + disp_dlg_regs->refcyc_per_line_delivery_c = (unsigned int) dml_floor(refcyc_per_line_delivery_c, + 1); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_c < (unsigned int) dml_pow(2, 13)); + ASSERT(disp_dlg_regs->refcyc_per_line_delivery_c < (unsigned int) dml_pow(2, 13)); + + disp_dlg_regs->chunk_hdl_adjust_cur0 = 3; + disp_dlg_regs->dst_y_offset_cur0 = 0; + disp_dlg_regs->chunk_hdl_adjust_cur1 = 3; + disp_dlg_regs->dst_y_offset_cur1 = 0; + + disp_dlg_regs->xfc_reg_transfer_delay = xfc_transfer_delay; + disp_dlg_regs->xfc_reg_precharge_delay = xfc_precharge_delay; + disp_dlg_regs->xfc_reg_remote_surface_flip_latency = xfc_remote_surface_flip_latency; + disp_dlg_regs->xfc_reg_prefetch_margin = dml_ceil(xfc_prefetch_margin * refclk_freq_in_mhz, + 1); + + // slave has to have this value also set to off + if (src->xfc_enable && !src->xfc_slave) + disp_dlg_regs->dst_y_delta_drq_limit = dml_ceil(xfc_dst_y_delta_drq_limit, 1); + else + disp_dlg_regs->dst_y_delta_drq_limit = 0x7fff; // off + + disp_ttu_regs->refcyc_per_req_delivery_pre_l = (unsigned int) (refcyc_per_req_delivery_pre_l + * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_l = (unsigned int) (refcyc_per_req_delivery_l + * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_c = (unsigned int) (refcyc_per_req_delivery_pre_c + * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_c = (unsigned int) (refcyc_per_req_delivery_c + * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_cur0 = + (unsigned int) (refcyc_per_req_delivery_pre_cur0 * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_cur0 = (unsigned int) (refcyc_per_req_delivery_cur0 + * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_pre_cur1 = + (unsigned int) (refcyc_per_req_delivery_pre_cur1 * dml_pow(2, 10)); + disp_ttu_regs->refcyc_per_req_delivery_cur1 = (unsigned int) (refcyc_per_req_delivery_cur1 + * dml_pow(2, 10)); + disp_ttu_regs->qos_level_low_wm = 0; + ASSERT(disp_ttu_regs->qos_level_low_wm < dml_pow(2, 14)); + disp_ttu_regs->qos_level_high_wm = (unsigned int) (4.0 * (double) htotal + * ref_freq_to_pix_freq); + /*ASSERT(disp_ttu_regs->qos_level_high_wm < dml_pow(2, 14));*/ + + disp_ttu_regs->qos_level_flip = 14; + disp_ttu_regs->qos_level_fixed_l = 8; + disp_ttu_regs->qos_level_fixed_c = 8; + disp_ttu_regs->qos_level_fixed_cur0 = 8; + disp_ttu_regs->qos_ramp_disable_l = 0; + disp_ttu_regs->qos_ramp_disable_c = 0; + disp_ttu_regs->qos_ramp_disable_cur0 = 0; + + disp_ttu_regs->min_ttu_vblank = min_ttu_vblank * refclk_freq_in_mhz; + ASSERT(disp_ttu_regs->min_ttu_vblank < dml_pow(2, 24)); + + print__ttu_regs_st(mode_lib, *disp_ttu_regs); + print__dlg_regs_st(mode_lib, *disp_dlg_regs); +} + +void dml20_rq_dlg_get_dlg_reg(struct display_mode_lib *mode_lib, + display_dlg_regs_st *dlg_regs, + display_ttu_regs_st *ttu_regs, + display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support) +{ + display_rq_params_st rq_param = {0}; + display_dlg_sys_params_st dlg_sys_param = {0}; + + // Get watermark and Tex. + dlg_sys_param.t_urg_wm_us = get_wm_urgent(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.deepsleep_dcfclk_mhz = get_clk_dcf_deepsleep(mode_lib, + e2e_pipe_param, + num_pipes); + dlg_sys_param.t_extra_us = get_urgent_extra_latency(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.mem_trip_us = get_wm_memory_trip(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.t_mclk_wm_us = get_wm_dram_clock_change(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.t_sr_wm_us = get_wm_stutter_enter_exit(mode_lib, e2e_pipe_param, num_pipes); + dlg_sys_param.total_flip_bw = get_total_immediate_flip_bw(mode_lib, + e2e_pipe_param, + num_pipes); + dlg_sys_param.total_flip_bytes = get_total_immediate_flip_bytes(mode_lib, + e2e_pipe_param, + num_pipes); + dlg_sys_param.t_srx_delay_us = mode_lib->ip.dcfclk_cstate_latency + / dlg_sys_param.deepsleep_dcfclk_mhz; // TODO: Deprecated + + print__dlg_sys_params_st(mode_lib, dlg_sys_param); + + // system parameter calculation done + + dml_print("DML_DLG: Calculation for pipe[%d] start\n\n", pipe_idx); + dml20_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe.src); + dml20_rq_dlg_get_dlg_params(mode_lib, + e2e_pipe_param, + num_pipes, + pipe_idx, + dlg_regs, + ttu_regs, + rq_param.dlg, + dlg_sys_param, + cstate_en, + pstate_en); + dml_print("DML_DLG: Calculation for pipe[%d] end\n", pipe_idx); +} + +static void calculate_ttu_cursor(struct display_mode_lib *mode_lib, + double *refcyc_per_req_delivery_pre_cur, + double *refcyc_per_req_delivery_cur, + double refclk_freq_in_mhz, + double ref_freq_to_pix_freq, + double hscale_pixel_rate_l, + double hscl_ratio, + double vratio_pre_l, + double vratio_l, + unsigned int cur_width, + enum cursor_bpp cur_bpp) +{ + unsigned int cur_src_width = cur_width; + unsigned int cur_req_size = 0; + unsigned int cur_req_width = 0; + double cur_width_ub = 0.0; + double cur_req_per_width = 0.0; + double hactive_cur = 0.0; + + ASSERT(cur_src_width <= 256); + + *refcyc_per_req_delivery_pre_cur = 0.0; + *refcyc_per_req_delivery_cur = 0.0; + if (cur_src_width > 0) { + unsigned int cur_bit_per_pixel = 0; + + if (cur_bpp == dm_cur_2bit) { + cur_req_size = 64; // byte + cur_bit_per_pixel = 2; + } else { // 32bit + cur_bit_per_pixel = 32; + if (cur_src_width >= 1 && cur_src_width <= 16) + cur_req_size = 64; + else if (cur_src_width >= 17 && cur_src_width <= 31) + cur_req_size = 128; + else + cur_req_size = 256; + } + + cur_req_width = (double) cur_req_size / ((double) cur_bit_per_pixel / 8.0); + cur_width_ub = dml_ceil((double) cur_src_width / (double) cur_req_width, 1) + * (double) cur_req_width; + cur_req_per_width = cur_width_ub / (double) cur_req_width; + hactive_cur = (double) cur_src_width / hscl_ratio; // FIXME: oswin to think about what to do for cursor + + if (vratio_pre_l <= 1.0) { + *refcyc_per_req_delivery_pre_cur = hactive_cur * ref_freq_to_pix_freq + / (double) cur_req_per_width; + } else { + *refcyc_per_req_delivery_pre_cur = (double) refclk_freq_in_mhz + * (double) cur_src_width / hscale_pixel_rate_l + / (double) cur_req_per_width; + } + + ASSERT(*refcyc_per_req_delivery_pre_cur < dml_pow(2, 13)); + + if (vratio_l <= 1.0) { + *refcyc_per_req_delivery_cur = hactive_cur * ref_freq_to_pix_freq + / (double) cur_req_per_width; + } else { + *refcyc_per_req_delivery_cur = (double) refclk_freq_in_mhz + * (double) cur_src_width / hscale_pixel_rate_l + / (double) cur_req_per_width; + } + + dml_print("DML_DLG: %s: cur_req_width = %d\n", + __func__, + cur_req_width); + dml_print("DML_DLG: %s: cur_width_ub = %3.2f\n", + __func__, + cur_width_ub); + dml_print("DML_DLG: %s: cur_req_per_width = %3.2f\n", + __func__, + cur_req_per_width); + dml_print("DML_DLG: %s: hactive_cur = %3.2f\n", + __func__, + hactive_cur); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_pre_cur = %3.2f\n", + __func__, + *refcyc_per_req_delivery_pre_cur); + dml_print("DML_DLG: %s: refcyc_per_req_delivery_cur = %3.2f\n", + __func__, + *refcyc_per_req_delivery_cur); + + ASSERT(*refcyc_per_req_delivery_cur < dml_pow(2, 13)); + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h new file mode 100644 index 000000000000..8c86b63ddf07 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20.h @@ -0,0 +1,74 @@ +/* + * 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 + * + */ + +#ifndef __DML20_DISPLAY_RQ_DLG_CALC_H__ +#define __DML20_DISPLAY_RQ_DLG_CALC_H__ + +#include "../dml_common_defs.h" +#include "../display_rq_dlg_helpers.h" + +struct display_mode_lib; + + +// Function: dml_rq_dlg_get_rq_reg +// Main entry point for test to get the register values out of this DML class. +// This function calls <get_rq_param> and <extract_rq_regs> fucntions to calculate +// and then populate the rq_regs struct +// Input: +// pipe_src_param - pipe source configuration (e.g. vp, pitch, etc.) +// Output: +// rq_regs - struct that holds all the RQ registers field value. +// See also: <display_rq_regs_st> +void dml20_rq_dlg_get_rq_reg( + struct display_mode_lib *mode_lib, + display_rq_regs_st *rq_regs, + const display_pipe_params_st pipe_param); + + +// Function: dml_rq_dlg_get_dlg_reg +// Calculate and return DLG and TTU register struct given the system setting +// Output: +// dlg_regs - output DLG register struct +// ttu_regs - output DLG TTU register struct +// Input: +// e2e_pipe_param - "compacted" array of e2e pipe param struct +// num_pipes - num of active "pipe" or "route" +// pipe_idx - index that identifies the e2e_pipe_param that corresponding to this dlg +// cstate - 0: when calculate min_ttu_vblank it is assumed cstate is not required. 1: Normal mode, cstate is considered. +// Added for legacy or unrealistic timing tests. +void dml20_rq_dlg_get_dlg_reg( + struct display_mode_lib *mode_lib, + display_dlg_regs_st *dlg_regs, + display_ttu_regs_st *ttu_regs, + display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support); + +#endif 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 174c414e0982..0c2fab1e93b6 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 @@ -86,7 +86,8 @@ enum dm_swizzle_mode { dm_sw_gfx7_2d_thin_gl }; enum lb_depth { - dm_lb_10 = 0, dm_lb_8 = 1, dm_lb_6 = 2, dm_lb_12 = 3, dm_lb_16 + dm_lb_10 = 0, dm_lb_8 = 1, dm_lb_6 = 2, dm_lb_12 = 3, dm_lb_16 = 4, + dm_lb_19 = 5 }; enum voltage_state { dm_vmin = 0, dm_vmid = 1, dm_vnom = 2, dm_vmax = 3 @@ -130,6 +131,9 @@ enum dm_validation_status { DML_FAIL_DIO_SUPPORT, DML_FAIL_NOT_ENOUGH_DSC, DML_FAIL_DSC_CLK_REQUIRED, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + DML_FAIL_DSC_VALIDATION_FAILURE, +#endif DML_FAIL_URGENT_LATENCY, DML_FAIL_REORDERING_BUFFER, DML_FAIL_DISPCLK_DPPCLK, 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 80ffd7d958b2..91810c7d5cf5 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 @@ -25,6 +25,19 @@ #include "display_mode_lib.h" #include "dc_features.h" +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dcn20/display_mode_vba_20.h" +#include "dcn20/display_rq_dlg_calc_20.h" +#endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +const struct dml_funcs dml20_funcs = { + .validate = dml20_ModeSupportAndSystemConfigurationFull, + .recalculate = dml20_recalculate, + .rq_dlg_get_dlg_reg = dml20_rq_dlg_get_dlg_reg, + .rq_dlg_get_rq_reg = dml20_rq_dlg_get_rq_reg +}; +#endif void dml_init_instance(struct display_mode_lib *lib, const struct _vcs_dpi_soc_bounding_box_st *soc_bb, @@ -34,6 +47,15 @@ void dml_init_instance(struct display_mode_lib *lib, lib->soc = *soc_bb; lib->ip = *ip_params; lib->project = project; + switch (project) { +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + case DML_PROJECT_NAVI10: + lib->funcs = dml20_funcs; + break; +#endif + default: + break; + } } const char *dml_get_status_message(enum dm_validation_status 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 1b546dba34bd..5bf13d67f289 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 @@ -27,18 +27,50 @@ #include "dml_common_defs.h" -#include "dml1_display_rq_dlg_calc.h" +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#include "display_mode_vba.h" +#endif enum dml_project { DML_PROJECT_UNDEFINED, - DML_PROJECT_RAVEN1 + DML_PROJECT_RAVEN1, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + DML_PROJECT_NAVI10, +#endif +}; + +struct display_mode_lib; + +struct dml_funcs { + void (*rq_dlg_get_dlg_reg)( + struct display_mode_lib *mode_lib, + display_dlg_regs_st *dlg_regs, + display_ttu_regs_st *ttu_regs, + display_e2e_pipe_params_st *e2e_pipe_param, + const unsigned int num_pipes, + const unsigned int pipe_idx, + const bool cstate_en, + const bool pstate_en, + const bool vm_en, + const bool ignore_viewport_pos, + const bool immediate_flip_support); + void (*rq_dlg_get_rq_reg)( + struct display_mode_lib *mode_lib, + display_rq_regs_st *rq_regs, + const display_pipe_params_st pipe_param); + void (*recalculate)(struct display_mode_lib *mode_lib); + void (*validate)(struct display_mode_lib *mode_lib); }; struct display_mode_lib { struct _vcs_dpi_ip_params_st ip; struct _vcs_dpi_soc_bounding_box_st soc; enum dml_project project; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + struct vba_vars_st vba; +#endif struct dal_logger *logger; + struct dml_funcs funcs; }; void dml_init_instance(struct display_mode_lib *lib, 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 6cc59f138095..5678472546ab 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 @@ -57,6 +57,7 @@ struct _vcs_dpi_voltage_scaling_st { double dscclk_mhz; double dcfclk_mhz; double socclk_mhz; + double phyclk_d18_mhz; double dram_speed_mts; double fabricclk_mhz; double dispclk_mhz; @@ -97,6 +98,7 @@ struct _vcs_dpi_soc_bounding_box_st { unsigned int num_banks; unsigned int num_chans; unsigned int vmm_page_size_bytes; + unsigned int hostvm_min_page_size_bytes; double dram_clock_change_latency_us; double writeback_dram_clock_change_latency_us; unsigned int return_bus_width_bytes; @@ -135,6 +137,22 @@ struct _vcs_dpi_ip_params_st { unsigned int writeback_luma_buffer_size_kbytes; unsigned int writeback_chroma_buffer_size_kbytes; unsigned int writeback_chroma_line_buffer_width_pixels; + + unsigned int writeback_interface_buffer_size_kbytes; + unsigned int writeback_line_buffer_buffer_size; + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + unsigned int writeback_10bpc420_supported; + double writeback_max_hscl_ratio; + double writeback_max_vscl_ratio; + double writeback_min_hscl_ratio; + double writeback_min_vscl_ratio; + unsigned int writeback_max_hscl_taps; + unsigned int writeback_max_vscl_taps; + unsigned int writeback_line_buffer_luma_buffer_size; + unsigned int writeback_line_buffer_chroma_buffer_size; +#endif + unsigned int max_page_table_levels; unsigned int max_num_dpp; unsigned int max_num_otg; @@ -152,6 +170,13 @@ struct _vcs_dpi_ip_params_st { unsigned int max_hscl_taps; unsigned int max_vscl_taps; unsigned int xfc_supported; + unsigned int ptoi_supported; + unsigned int gfx7_compat_tiling_supported; + + bool odm_combine_4to1_supported; + bool dynamic_metadata_vm_enabled; + unsigned int max_num_hdmi_frl_outputs; + unsigned int xfc_fill_constant_bytes; double dispclk_ramp_margin_percent; double xfc_fill_bw_overhead_percent; @@ -218,6 +243,7 @@ struct _vcs_dpi_display_pipe_source_params_st { unsigned int hsplit_grp; unsigned char xfc_enable; unsigned char xfc_slave; + unsigned char immediate_flip; struct _vcs_dpi_display_xfc_params_st xfc_params; //for vstartuplines calculation freesync unsigned char v_total_min; @@ -225,6 +251,7 @@ struct _vcs_dpi_display_pipe_source_params_st { }; struct writeback_st { int wb_src_height; + int wb_src_width; int wb_dst_width; int wb_dst_height; int wb_pixel_format; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c new file mode 100644 index 000000000000..4d2a1262d9db --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -0,0 +1,839 @@ +/* + * 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. + * + * Authors: AMD + * + */ + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + +#include "display_mode_lib.h" +#include "display_mode_vba.h" +#include "dml_inline_defs.h" + +/* + * NOTE: + * This file is gcc-parsable HW gospel, coming straight from HW engineers. + * + * It doesn't adhere to Linux kernel style and sometimes will do things in odd + * ways. Unless there is something clearly wrong with it the code should + * remain as-is as it provides us with a guarantee from HW that it is correct. + */ + + +static void fetch_socbb_params(struct display_mode_lib *mode_lib); +static void fetch_ip_params(struct display_mode_lib *mode_lib); +static void fetch_pipe_params(struct display_mode_lib *mode_lib); +static void recalculate_params( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes); + +static unsigned int CursorBppEnumToBits(enum cursor_bpp ebpp); + +unsigned int dml_get_voltage_level( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes) +{ + bool need_recalculate = memcmp(&mode_lib->soc, &mode_lib->vba.soc, sizeof(mode_lib->vba.soc)) != 0 + || memcmp(&mode_lib->ip, &mode_lib->vba.ip, sizeof(mode_lib->vba.ip)) != 0 + || num_pipes != mode_lib->vba.cache_num_pipes + || memcmp(pipes, mode_lib->vba.cache_pipes, + sizeof(display_e2e_pipe_params_st) * num_pipes) != 0; + + mode_lib->vba.soc = mode_lib->soc; + mode_lib->vba.ip = mode_lib->ip; + memcpy(mode_lib->vba.cache_pipes, pipes, sizeof(*pipes) * num_pipes); + mode_lib->vba.cache_num_pipes = num_pipes; + + if (need_recalculate && pipes[0].clks_cfg.dppclk_mhz != 0) + mode_lib->funcs.recalculate(mode_lib); + else { + fetch_socbb_params(mode_lib); + fetch_ip_params(mode_lib); + fetch_pipe_params(mode_lib); + PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib); + } + mode_lib->funcs.validate(mode_lib); + + return mode_lib->vba.VoltageLevel; +} + +#define dml_get_attr_func(attr, var) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes) \ +{ \ + recalculate_params(mode_lib, pipes, num_pipes); \ + return var; \ +} + +dml_get_attr_func(clk_dcf_deepsleep, mode_lib->vba.DCFCLKDeepSleep); +dml_get_attr_func(wm_urgent, mode_lib->vba.UrgentWatermark); +dml_get_attr_func(wm_memory_trip, mode_lib->vba.UrgentLatency); +dml_get_attr_func(wm_writeback_urgent, mode_lib->vba.WritebackUrgentWatermark); +dml_get_attr_func(wm_stutter_exit, mode_lib->vba.StutterExitWatermark); +dml_get_attr_func(wm_stutter_enter_exit, mode_lib->vba.StutterEnterPlusExitWatermark); +dml_get_attr_func(wm_dram_clock_change, mode_lib->vba.DRAMClockChangeWatermark); +dml_get_attr_func(wm_writeback_dram_clock_change, mode_lib->vba.WritebackDRAMClockChangeWatermark); +dml_get_attr_func(wm_xfc_underflow, mode_lib->vba.UrgentWatermark); // xfc_underflow maps to urgent +dml_get_attr_func(stutter_efficiency, mode_lib->vba.StutterEfficiency); +dml_get_attr_func(stutter_efficiency_no_vblank, mode_lib->vba.StutterEfficiencyNotIncludingVBlank); +dml_get_attr_func(urgent_latency, mode_lib->vba.UrgentLatency); +dml_get_attr_func(urgent_extra_latency, mode_lib->vba.UrgentExtraLatency); +dml_get_attr_func(nonurgent_latency, mode_lib->vba.NonUrgentLatencyTolerance); +dml_get_attr_func( + dram_clock_change_latency, + mode_lib->vba.MinActiveDRAMClockChangeLatencySupported); +dml_get_attr_func(dispclk_calculated, mode_lib->vba.DISPCLK_calculated); +dml_get_attr_func(total_data_read_bw, mode_lib->vba.TotalDataReadBandwidth); +dml_get_attr_func(return_bw, mode_lib->vba.ReturnBW); +dml_get_attr_func(tcalc, mode_lib->vba.TCalc); +dml_get_attr_func(fraction_of_urgent_bandwidth, mode_lib->vba.FractionOfUrgentBandwidth); +dml_get_attr_func(fraction_of_urgent_bandwidth_imm_flip, mode_lib->vba.FractionOfUrgentBandwidthImmediateFlip); + +#define dml_get_pipe_attr_func(attr, var) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes, unsigned int which_pipe) \ +{\ + unsigned int which_plane; \ + recalculate_params(mode_lib, pipes, num_pipes); \ + which_plane = mode_lib->vba.pipe_plane[which_pipe]; \ + return var[which_plane]; \ +} + +dml_get_pipe_attr_func(dsc_delay, mode_lib->vba.DSCDelay); +dml_get_pipe_attr_func(dppclk_calculated, mode_lib->vba.DPPCLK_calculated); +dml_get_pipe_attr_func(dscclk_calculated, mode_lib->vba.DSCCLK_calculated); +dml_get_pipe_attr_func(min_ttu_vblank, mode_lib->vba.MinTTUVBlank); +dml_get_pipe_attr_func(vratio_prefetch_l, mode_lib->vba.VRatioPrefetchY); +dml_get_pipe_attr_func(vratio_prefetch_c, mode_lib->vba.VRatioPrefetchC); +dml_get_pipe_attr_func(dst_x_after_scaler, mode_lib->vba.DSTXAfterScaler); +dml_get_pipe_attr_func(dst_y_after_scaler, mode_lib->vba.DSTYAfterScaler); +dml_get_pipe_attr_func(dst_y_per_vm_vblank, mode_lib->vba.DestinationLinesToRequestVMInVBlank); +dml_get_pipe_attr_func(dst_y_per_row_vblank, mode_lib->vba.DestinationLinesToRequestRowInVBlank); +dml_get_pipe_attr_func(dst_y_prefetch, mode_lib->vba.DestinationLinesForPrefetch); +dml_get_pipe_attr_func(dst_y_per_vm_flip, mode_lib->vba.DestinationLinesToRequestVMInImmediateFlip); +dml_get_pipe_attr_func( + dst_y_per_row_flip, + mode_lib->vba.DestinationLinesToRequestRowInImmediateFlip); + +dml_get_pipe_attr_func(xfc_transfer_delay, mode_lib->vba.XFCTransferDelay); +dml_get_pipe_attr_func(xfc_precharge_delay, mode_lib->vba.XFCPrechargeDelay); +dml_get_pipe_attr_func(xfc_remote_surface_flip_latency, mode_lib->vba.XFCRemoteSurfaceFlipLatency); +dml_get_pipe_attr_func(xfc_prefetch_margin, mode_lib->vba.XFCPrefetchMargin); +dml_get_pipe_attr_func(refcyc_per_vm_group_vblank, mode_lib->vba.TimePerVMGroupVBlank); +dml_get_pipe_attr_func(refcyc_per_vm_group_flip, mode_lib->vba.TimePerVMGroupFlip); +dml_get_pipe_attr_func(refcyc_per_vm_req_vblank, mode_lib->vba.TimePerVMRequestVBlank); +dml_get_pipe_attr_func(refcyc_per_vm_req_flip, mode_lib->vba.TimePerVMRequestFlip); + +unsigned int get_vstartup_calculated( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes, + unsigned int which_pipe) +{ + unsigned int which_plane; + + recalculate_params(mode_lib, pipes, num_pipes); + which_plane = mode_lib->vba.pipe_plane[which_pipe]; + return mode_lib->vba.VStartup[which_plane]; +} + +double get_total_immediate_flip_bytes( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes) +{ + recalculate_params(mode_lib, pipes, num_pipes); + return mode_lib->vba.TotImmediateFlipBytes; +} + +double get_total_immediate_flip_bw( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes) +{ + unsigned int k; + double immediate_flip_bw = 0.0; + recalculate_params(mode_lib, pipes, num_pipes); + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + immediate_flip_bw += mode_lib->vba.ImmediateFlipBW[k]; + return immediate_flip_bw; +} + +double get_total_prefetch_bw( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes) +{ + unsigned int k; + double total_prefetch_bw = 0.0; + + recalculate_params(mode_lib, pipes, num_pipes); + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + total_prefetch_bw += mode_lib->vba.PrefetchBandwidth[k]; + return total_prefetch_bw; +} + +static void fetch_socbb_params(struct display_mode_lib *mode_lib) +{ + soc_bounding_box_st *soc = &mode_lib->vba.soc; + int i; + + // SOC Bounding Box Parameters + mode_lib->vba.ReturnBusWidth = soc->return_bus_width_bytes; + mode_lib->vba.NumberOfChannels = soc->num_chans; + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelDataOnly = + soc->pct_ideal_dram_sdp_bw_after_urgent_pixel_only; // there's always that one bastard variable that's so long it throws everything out of alignment! + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData = + soc->pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm; + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly = + soc->pct_ideal_dram_sdp_bw_after_urgent_vm_only; + mode_lib->vba.MaxAveragePercentOfIdealSDPPortBWDisplayCanUseInNormalSystemOperation = + soc->max_avg_sdp_bw_use_normal_percent; + mode_lib->vba.MaxAveragePercentOfIdealDRAMBWDisplayCanUseInNormalSystemOperation = + soc->max_avg_dram_bw_use_normal_percent; + mode_lib->vba.UrgentLatencyPixelDataOnly = soc->urgent_latency_pixel_data_only_us; + mode_lib->vba.UrgentLatencyPixelMixedWithVMData = soc->urgent_latency_pixel_mixed_with_vm_data_us; + mode_lib->vba.UrgentLatencyVMDataOnly = soc->urgent_latency_vm_data_only_us; + mode_lib->vba.RoundTripPingLatencyCycles = soc->round_trip_ping_latency_dcfclk_cycles; + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelDataOnly = + soc->urgent_out_of_order_return_per_channel_pixel_only_bytes; + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData = + soc->urgent_out_of_order_return_per_channel_pixel_and_vm_bytes; + mode_lib->vba.UrgentOutOfOrderReturnPerChannelVMDataOnly = + soc->urgent_out_of_order_return_per_channel_vm_only_bytes; + mode_lib->vba.WritebackLatency = soc->writeback_latency_us; + mode_lib->vba.SRExitTime = soc->sr_exit_time_us; + mode_lib->vba.SREnterPlusExitTime = soc->sr_enter_plus_exit_time_us; + mode_lib->vba.DRAMClockChangeLatency = soc->dram_clock_change_latency_us; + mode_lib->vba.Downspreading = soc->downspread_percent; + mode_lib->vba.DRAMChannelWidth = soc->dram_channel_width_bytes; // new! + mode_lib->vba.FabricDatapathToDCNDataReturn = soc->fabric_datapath_to_dcn_data_return_bytes; // new! + mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading = soc->dcn_downspread_percent; // new + mode_lib->vba.DISPCLKDPPCLKVCOSpeed = soc->dispclk_dppclk_vco_speed_mhz; // new + mode_lib->vba.VMMPageSize = soc->vmm_page_size_bytes; + mode_lib->vba.GPUVMMinPageSize = soc->vmm_page_size_bytes / 1024; + mode_lib->vba.HostVMMinPageSize = soc->hostvm_min_page_size_bytes / 1024; + // Set the voltage scaling clocks as the defaults. Most of these will + // be set to different values by the test + for (i = 0; i < mode_lib->vba.soc.num_states; i++) + if (soc->clock_limits[i].state == mode_lib->vba.VoltageLevel) + break; + + mode_lib->vba.DCFCLK = soc->clock_limits[i].dcfclk_mhz; + mode_lib->vba.SOCCLK = soc->clock_limits[i].socclk_mhz; + mode_lib->vba.DRAMSpeed = soc->clock_limits[i].dram_speed_mts; + mode_lib->vba.FabricClock = soc->clock_limits[i].fabricclk_mhz; + + mode_lib->vba.XFCBusTransportTime = soc->xfc_bus_transport_time_us; + mode_lib->vba.XFCXBUFLatencyTolerance = soc->xfc_xbuf_latency_tolerance_us; + mode_lib->vba.UseUrgentBurstBandwidth = soc->use_urgent_burst_bw; + + mode_lib->vba.SupportGFX7CompatibleTilingIn32bppAnd64bpp = false; + mode_lib->vba.WritebackLumaAndChromaScalingSupported = true; + mode_lib->vba.MaxHSCLRatio = 4; + mode_lib->vba.MaxVSCLRatio = 4; + mode_lib->vba.Cursor64BppSupport = true; + for (i = 0; i <= mode_lib->vba.soc.num_states; i++) { + mode_lib->vba.DCFCLKPerState[i] = soc->clock_limits[i].dcfclk_mhz; + mode_lib->vba.FabricClockPerState[i] = soc->clock_limits[i].fabricclk_mhz; + mode_lib->vba.SOCCLKPerState[i] = soc->clock_limits[i].socclk_mhz; + mode_lib->vba.PHYCLKPerState[i] = soc->clock_limits[i].phyclk_mhz; + mode_lib->vba.PHYCLKD18PerState[i] = soc->clock_limits[i].phyclk_d18_mhz; + mode_lib->vba.MaxDppclk[i] = soc->clock_limits[i].dppclk_mhz; + mode_lib->vba.MaxDSCCLK[i] = soc->clock_limits[i].dscclk_mhz; + mode_lib->vba.DRAMSpeedPerState[i] = soc->clock_limits[i].dram_speed_mts; + //mode_lib->vba.DRAMSpeedPerState[i] = soc->clock_limits[i].dram_speed_mhz; + mode_lib->vba.MaxDispclk[i] = soc->clock_limits[i].dispclk_mhz; + } +} + +static void fetch_ip_params(struct display_mode_lib *mode_lib) +{ + ip_params_st *ip = &mode_lib->vba.ip; + + // IP Parameters + mode_lib->vba.MaxNumDPP = ip->max_num_dpp; + mode_lib->vba.MaxNumOTG = ip->max_num_otg; + mode_lib->vba.MaxNumHDMIFRLOutputs = ip->max_num_hdmi_frl_outputs; + mode_lib->vba.MaxNumWriteback = ip->max_num_wb; + mode_lib->vba.CursorChunkSize = ip->cursor_chunk_size; + mode_lib->vba.CursorBufferSize = ip->cursor_buffer_size; + + mode_lib->vba.MaxDCHUBToPSCLThroughput = ip->max_dchub_pscl_bw_pix_per_clk; + mode_lib->vba.MaxPSCLToLBThroughput = ip->max_pscl_lb_bw_pix_per_clk; + mode_lib->vba.ROBBufferSizeInKByte = ip->rob_buffer_size_kbytes; + mode_lib->vba.DETBufferSizeInKByte = ip->det_buffer_size_kbytes; + mode_lib->vba.PixelChunkSizeInKByte = ip->pixel_chunk_size_kbytes; + mode_lib->vba.MetaChunkSize = ip->meta_chunk_size_kbytes; + mode_lib->vba.WritebackChunkSize = ip->writeback_chunk_size_kbytes; + mode_lib->vba.LineBufferSize = ip->line_buffer_size_bits; + mode_lib->vba.MaxLineBufferLines = ip->max_line_buffer_lines; + mode_lib->vba.PTEBufferSizeInRequestsLuma = ip->dpte_buffer_size_in_pte_reqs_luma; + mode_lib->vba.PTEBufferSizeInRequestsChroma = ip->dpte_buffer_size_in_pte_reqs_chroma; + mode_lib->vba.DPPOutputBufferPixels = ip->dpp_output_buffer_pixels; + mode_lib->vba.OPPOutputBufferLines = ip->opp_output_buffer_lines; + mode_lib->vba.MaxHSCLRatio = ip->max_hscl_ratio; + mode_lib->vba.MaxVSCLRatio = ip->max_vscl_ratio; + mode_lib->vba.WritebackInterfaceLumaBufferSize = ip->writeback_luma_buffer_size_kbytes * 1024; + mode_lib->vba.WritebackInterfaceChromaBufferSize = ip->writeback_chroma_buffer_size_kbytes * 1024; + + mode_lib->vba.WritebackInterfaceBufferSize = ip->writeback_interface_buffer_size_kbytes; + mode_lib->vba.WritebackLineBufferSize = ip->writeback_line_buffer_buffer_size; + mode_lib->vba.MinVoltageLevel = 0; + mode_lib->vba.MaxVoltageLevel = 5; + + mode_lib->vba.WritebackChromaLineBufferWidth = + ip->writeback_chroma_line_buffer_width_pixels; + mode_lib->vba.WritebackLineBufferLumaBufferSize = + ip->writeback_line_buffer_luma_buffer_size; + mode_lib->vba.WritebackLineBufferChromaBufferSize = + ip->writeback_line_buffer_chroma_buffer_size; + mode_lib->vba.Writeback10bpc420Supported = ip->writeback_10bpc420_supported; + mode_lib->vba.WritebackMaxHSCLRatio = ip->writeback_max_hscl_ratio; + mode_lib->vba.WritebackMaxVSCLRatio = ip->writeback_max_vscl_ratio; + mode_lib->vba.WritebackMinHSCLRatio = ip->writeback_min_hscl_ratio; + mode_lib->vba.WritebackMinVSCLRatio = ip->writeback_min_vscl_ratio; + mode_lib->vba.WritebackMaxHSCLTaps = ip->writeback_max_hscl_taps; + mode_lib->vba.WritebackMaxVSCLTaps = ip->writeback_max_vscl_taps; + mode_lib->vba.WritebackConfiguration = dm_normal; + mode_lib->vba.GPUVMMaxPageTableLevels = ip->gpuvm_max_page_table_levels; + mode_lib->vba.HostVMMaxNonCachedPageTableLevels = ip->hostvm_max_page_table_levels; + mode_lib->vba.HostVMMaxPageTableLevels = ip->hostvm_max_page_table_levels; + mode_lib->vba.HostVMCachedPageTableLevels = ip->hostvm_cached_page_table_levels; + mode_lib->vba.MaxInterDCNTileRepeaters = ip->max_inter_dcn_tile_repeaters; + mode_lib->vba.NumberOfDSC = ip->num_dsc; + mode_lib->vba.ODMCapability = ip->odm_capable; + mode_lib->vba.DISPCLKRampingMargin = ip->dispclk_ramp_margin_percent; + + mode_lib->vba.XFCSupported = ip->xfc_supported; + mode_lib->vba.XFCFillBWOverhead = ip->xfc_fill_bw_overhead_percent; + mode_lib->vba.XFCFillConstant = ip->xfc_fill_constant_bytes; + mode_lib->vba.DPPCLKDelaySubtotal = ip->dppclk_delay_subtotal; + mode_lib->vba.DPPCLKDelaySCL = ip->dppclk_delay_scl; + mode_lib->vba.DPPCLKDelaySCLLBOnly = ip->dppclk_delay_scl_lb_only; + mode_lib->vba.DPPCLKDelayCNVCFormater = ip->dppclk_delay_cnvc_formatter; + mode_lib->vba.DPPCLKDelayCNVCCursor = ip->dppclk_delay_cnvc_cursor; + mode_lib->vba.DISPCLKDelaySubtotal = ip->dispclk_delay_subtotal; + mode_lib->vba.DynamicMetadataVMEnabled = ip->dynamic_metadata_vm_enabled; + mode_lib->vba.ODMCombine4To1Supported = ip->odm_combine_4to1_supported; + mode_lib->vba.ProgressiveToInterlaceUnitInOPP = ip->ptoi_supported; + mode_lib->vba.PDEProcessingBufIn64KBReqs = ip->pde_proc_buffer_size_64k_reqs; + mode_lib->vba.PTEGroupSize = ip->pte_group_size_bytes; + mode_lib->vba.SupportGFX7CompatibleTilingIn32bppAnd64bpp = ip->gfx7_compat_tiling_supported; +} + +static void fetch_pipe_params(struct display_mode_lib *mode_lib) +{ + display_e2e_pipe_params_st *pipes = mode_lib->vba.cache_pipes; + ip_params_st *ip = &mode_lib->vba.ip; + + unsigned int OTGInstPlane[DC__NUM_DPP__MAX]; + unsigned int j, k; + bool PlaneVisited[DC__NUM_DPP__MAX]; + bool visited[DC__NUM_DPP__MAX]; + + // Convert Pipes to Planes + for (k = 0; k < mode_lib->vba.cache_num_pipes; ++k) + visited[k] = false; + + mode_lib->vba.NumberOfActivePlanes = 0; + for (j = 0; j < mode_lib->vba.cache_num_pipes; ++j) { + display_pipe_source_params_st *src = &pipes[j].pipe.src; + display_pipe_dest_params_st *dst = &pipes[j].pipe.dest; + scaler_ratio_depth_st *scl = &pipes[j].pipe.scale_ratio_depth; + scaler_taps_st *taps = &pipes[j].pipe.scale_taps; + display_output_params_st *dout = &pipes[j].dout; + display_clocks_and_cfg_st *clks = &pipes[j].clks_cfg; + + if (visited[j]) + continue; + visited[j] = true; + + mode_lib->vba.pipe_plane[j] = mode_lib->vba.NumberOfActivePlanes; + + mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes] = 1; + mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] = + (enum scan_direction_class) (src->source_scan); + mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_width; + mode_lib->vba.ViewportWidthChroma[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_width_c; + mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_height; + mode_lib->vba.ViewportHeightChroma[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_height_c; + mode_lib->vba.ViewportYStartY[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_y_y; + mode_lib->vba.ViewportYStartC[mode_lib->vba.NumberOfActivePlanes] = + src->viewport_y_c; + mode_lib->vba.PitchY[mode_lib->vba.NumberOfActivePlanes] = src->data_pitch; + mode_lib->vba.SurfaceHeightY[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height; + mode_lib->vba.PitchC[mode_lib->vba.NumberOfActivePlanes] = src->data_pitch_c; + mode_lib->vba.SurfaceHeightC[mode_lib->vba.NumberOfActivePlanes] = src->viewport_height_c; + mode_lib->vba.DCCMetaPitchY[mode_lib->vba.NumberOfActivePlanes] = src->meta_pitch; + mode_lib->vba.DCCMetaPitchC[mode_lib->vba.NumberOfActivePlanes] = src->meta_pitch_c; + mode_lib->vba.HRatio[mode_lib->vba.NumberOfActivePlanes] = scl->hscl_ratio; + mode_lib->vba.HRatioChroma[mode_lib->vba.NumberOfActivePlanes] = scl->hscl_ratio_c; + mode_lib->vba.VRatio[mode_lib->vba.NumberOfActivePlanes] = scl->vscl_ratio; + mode_lib->vba.VRatioChroma[mode_lib->vba.NumberOfActivePlanes] = scl->vscl_ratio_c; + mode_lib->vba.ScalerEnabled[mode_lib->vba.NumberOfActivePlanes] = scl->scl_enable; + mode_lib->vba.Interlace[mode_lib->vba.NumberOfActivePlanes] = dst->interlaced; + if (dst->interlaced && !ip->ptoi_supported) { + mode_lib->vba.VRatio[mode_lib->vba.NumberOfActivePlanes] *= 2.0; + mode_lib->vba.VRatioChroma[mode_lib->vba.NumberOfActivePlanes] *= 2.0; + } + mode_lib->vba.htaps[mode_lib->vba.NumberOfActivePlanes] = taps->htaps; + mode_lib->vba.vtaps[mode_lib->vba.NumberOfActivePlanes] = taps->vtaps; + mode_lib->vba.HTAPsChroma[mode_lib->vba.NumberOfActivePlanes] = taps->htaps_c; + mode_lib->vba.VTAPsChroma[mode_lib->vba.NumberOfActivePlanes] = taps->vtaps_c; + mode_lib->vba.HTotal[mode_lib->vba.NumberOfActivePlanes] = dst->htotal; + mode_lib->vba.VTotal[mode_lib->vba.NumberOfActivePlanes] = dst->vtotal; + mode_lib->vba.DCCEnable[mode_lib->vba.NumberOfActivePlanes] = + src->dcc_use_global ? + ip->dcc_supported : src->dcc && ip->dcc_supported; + mode_lib->vba.DCCRate[mode_lib->vba.NumberOfActivePlanes] = src->dcc_rate; + /* TODO: Needs to be set based on src->dcc_rate_luma/chroma */ + mode_lib->vba.DCCRateLuma[mode_lib->vba.NumberOfActivePlanes] = 0; + mode_lib->vba.DCCRateChroma[mode_lib->vba.NumberOfActivePlanes] = 0; + + mode_lib->vba.SourcePixelFormat[mode_lib->vba.NumberOfActivePlanes] = + (enum source_format_class) (src->source_format); + mode_lib->vba.HActive[mode_lib->vba.NumberOfActivePlanes] = dst->hactive; + mode_lib->vba.VActive[mode_lib->vba.NumberOfActivePlanes] = dst->vactive; + mode_lib->vba.SurfaceTiling[mode_lib->vba.NumberOfActivePlanes] = + (enum dm_swizzle_mode) (src->sw_mode); + mode_lib->vba.ScalerRecoutWidth[mode_lib->vba.NumberOfActivePlanes] = + dst->recout_width; // TODO: or should this be full_recout_width???...maybe only when in hsplit mode? + mode_lib->vba.ODMCombineEnabled[mode_lib->vba.NumberOfActivePlanes] = + dst->odm_combine; + mode_lib->vba.OutputFormat[mode_lib->vba.NumberOfActivePlanes] = + (enum output_format_class) (dout->output_format); + mode_lib->vba.Output[mode_lib->vba.NumberOfActivePlanes] = + (enum output_encoder_class) (dout->output_type); + + if (!dout->dsc_enable) + mode_lib->vba.ForcedOutputLinkBPP[mode_lib->vba.NumberOfActivePlanes] = dout->output_bpp; + else + mode_lib->vba.ForcedOutputLinkBPP[mode_lib->vba.NumberOfActivePlanes] = 0.0; + + mode_lib->vba.OutputLinkDPLanes[mode_lib->vba.NumberOfActivePlanes] = + dout->dp_lanes; + /* TODO: Needs to be set based on dout->audio.audio_sample_rate_khz/sample_layout */ + mode_lib->vba.AudioSampleRate[mode_lib->vba.NumberOfActivePlanes] = + 44.1 * 1000; + mode_lib->vba.AudioSampleLayout[mode_lib->vba.NumberOfActivePlanes] = + 1; + mode_lib->vba.DRAMClockChangeLatencyOverride = 0.0; + mode_lib->vba.DSCEnabled[mode_lib->vba.NumberOfActivePlanes] = dout->dsc_enable; + mode_lib->vba.NumberOfDSCSlices[mode_lib->vba.NumberOfActivePlanes] = + dout->dsc_slices; + mode_lib->vba.DSCInputBitPerComponent[mode_lib->vba.NumberOfActivePlanes] = + dout->output_bpc == 0 ? 12 : dout->output_bpc; + mode_lib->vba.WritebackEnable[mode_lib->vba.NumberOfActivePlanes] = dout->wb_enable; + mode_lib->vba.ActiveWritebacksPerPlane[mode_lib->vba.NumberOfActivePlanes] = + dout->num_active_wb; + mode_lib->vba.WritebackSourceHeight[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_src_height; + mode_lib->vba.WritebackSourceWidth[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_src_width; + mode_lib->vba.WritebackDestinationWidth[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_dst_width; + mode_lib->vba.WritebackDestinationHeight[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_dst_height; + mode_lib->vba.WritebackPixelFormat[mode_lib->vba.NumberOfActivePlanes] = + (enum source_format_class) (dout->wb.wb_pixel_format); + mode_lib->vba.WritebackHTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_htaps_luma; + mode_lib->vba.WritebackVTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_vtaps_luma; + mode_lib->vba.WritebackLumaHTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_htaps_luma; + mode_lib->vba.WritebackLumaVTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_vtaps_luma; + mode_lib->vba.WritebackChromaHTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_htaps_chroma; + mode_lib->vba.WritebackChromaVTaps[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_vtaps_chroma; + mode_lib->vba.WritebackHRatio[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_hratio; + mode_lib->vba.WritebackVRatio[mode_lib->vba.NumberOfActivePlanes] = + dout->wb.wb_vratio; + + mode_lib->vba.DynamicMetadataEnable[mode_lib->vba.NumberOfActivePlanes] = + src->dynamic_metadata_enable; + mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[mode_lib->vba.NumberOfActivePlanes] = + src->dynamic_metadata_lines_before_active; + mode_lib->vba.DynamicMetadataTransmittedBytes[mode_lib->vba.NumberOfActivePlanes] = + src->dynamic_metadata_xmit_bytes; + + mode_lib->vba.XFCEnabled[mode_lib->vba.NumberOfActivePlanes] = src->xfc_enable + && ip->xfc_supported; + mode_lib->vba.XFCSlvChunkSize = src->xfc_params.xfc_slv_chunk_size_bytes; + mode_lib->vba.XFCTSlvVupdateOffset = src->xfc_params.xfc_tslv_vupdate_offset_us; + mode_lib->vba.XFCTSlvVupdateWidth = src->xfc_params.xfc_tslv_vupdate_width_us; + mode_lib->vba.XFCTSlvVreadyOffset = src->xfc_params.xfc_tslv_vready_offset_us; + mode_lib->vba.PixelClock[mode_lib->vba.NumberOfActivePlanes] = dst->pixel_rate_mhz; + mode_lib->vba.PixelClockBackEnd[mode_lib->vba.NumberOfActivePlanes] = dst->pixel_rate_mhz; + mode_lib->vba.DPPCLK[mode_lib->vba.NumberOfActivePlanes] = clks->dppclk_mhz; + if (ip->is_line_buffer_bpp_fixed) + mode_lib->vba.LBBitPerPixel[mode_lib->vba.NumberOfActivePlanes] = + ip->line_buffer_fixed_bpp; + else { + unsigned int lb_depth; + + switch (scl->lb_depth) { + case dm_lb_6: + lb_depth = 18; + break; + case dm_lb_8: + lb_depth = 24; + break; + case dm_lb_10: + lb_depth = 30; + break; + case dm_lb_12: + lb_depth = 36; + break; + case dm_lb_16: + lb_depth = 48; + break; + case dm_lb_19: + lb_depth = 57; + break; + default: + lb_depth = 36; + } + mode_lib->vba.LBBitPerPixel[mode_lib->vba.NumberOfActivePlanes] = lb_depth; + } + mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes] = 0; + // The DML spreadsheet assumes that the two cursors utilize the same amount of bandwidth. We'll + // calculate things a little more accurately + for (k = 0; k < DC__NUM_CURSOR__MAX; ++k) { + switch (k) { + case 0: + mode_lib->vba.CursorBPP[mode_lib->vba.NumberOfActivePlanes][0] = + CursorBppEnumToBits( + (enum cursor_bpp) (src->cur0_bpp)); + mode_lib->vba.CursorWidth[mode_lib->vba.NumberOfActivePlanes][0] = + src->cur0_src_width; + if (src->cur0_src_width > 0) + mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes]++; + break; + case 1: + mode_lib->vba.CursorBPP[mode_lib->vba.NumberOfActivePlanes][1] = + CursorBppEnumToBits( + (enum cursor_bpp) (src->cur1_bpp)); + mode_lib->vba.CursorWidth[mode_lib->vba.NumberOfActivePlanes][1] = + src->cur1_src_width; + if (src->cur1_src_width > 0) + mode_lib->vba.NumberOfCursors[mode_lib->vba.NumberOfActivePlanes]++; + break; + default: + dml_print( + "ERROR: Number of cursors specified exceeds supported maximum\n") + ; + } + } + + OTGInstPlane[mode_lib->vba.NumberOfActivePlanes] = dst->otg_inst; + + if (j == 0) + mode_lib->vba.UseMaximumVStartup = dst->use_maximum_vstartup; + else + mode_lib->vba.UseMaximumVStartup = mode_lib->vba.UseMaximumVStartup + || dst->use_maximum_vstartup; + + if (dst->odm_combine && !src->is_hsplit) + dml_print( + "ERROR: ODM Combine is specified but is_hsplit has not be specified for pipe %i\n", + j); + + if (src->is_hsplit) { + for (k = j + 1; k < mode_lib->vba.cache_num_pipes; ++k) { + display_pipe_source_params_st *src_k = &pipes[k].pipe.src; + + if (src_k->is_hsplit && !visited[k] + && src->hsplit_grp == src_k->hsplit_grp) { + mode_lib->vba.pipe_plane[k] = + mode_lib->vba.NumberOfActivePlanes; + mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes]++; + if (mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] + == dm_horz) + mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] += + src_k->viewport_width; + else + mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] += + src_k->viewport_height; + + visited[k] = true; + } + } + } + + if (pipes[k].pipe.src.immediate_flip) + mode_lib->vba.ImmediateFlipSupport = true; + + mode_lib->vba.NumberOfActivePlanes++; + } + + // handle overlays through BlendingAndTiming + // BlendingAndTiming tells you which instance to look at to get timing, the so called 'master' + + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) + PlaneVisited[j] = false; + + for (j = 0; j < mode_lib->vba.NumberOfActivePlanes; ++j) { + for (k = j + 1; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (!PlaneVisited[k] && OTGInstPlane[j] == OTGInstPlane[k]) { + // doesn't matter, so choose the smaller one + mode_lib->vba.BlendingAndTiming[j] = j; + PlaneVisited[j] = true; + mode_lib->vba.BlendingAndTiming[k] = j; + PlaneVisited[k] = true; + } + } + + if (!PlaneVisited[j]) { + mode_lib->vba.BlendingAndTiming[j] = j; + PlaneVisited[j] = true; + } + } + + // TODO: ODMCombineEnabled => 2 * DPPPerPlane...actually maybe not since all pipes are specified + // Do we want the dscclk to automatically be halved? Guess not since the value is specified + + mode_lib->vba.SynchronizedVBlank = pipes[0].pipe.dest.synchronized_vblank_all_planes; + for (k = 1; k < mode_lib->vba.cache_num_pipes; ++k) + ASSERT(mode_lib->vba.SynchronizedVBlank == pipes[k].pipe.dest.synchronized_vblank_all_planes); + + mode_lib->vba.GPUVMEnable = false; + mode_lib->vba.HostVMEnable = false; + mode_lib->vba.OverrideGPUVMPageTableLevels = 0; + mode_lib->vba.OverrideHostVMPageTableLevels = 0; + + for (k = 0; k < mode_lib->vba.cache_num_pipes; ++k) { + mode_lib->vba.GPUVMEnable = mode_lib->vba.GPUVMEnable || !!pipes[k].pipe.src.gpuvm || !!pipes[k].pipe.src.vm; + mode_lib->vba.OverrideGPUVMPageTableLevels = + (pipes[k].pipe.src.gpuvm_levels_force_en + && mode_lib->vba.OverrideGPUVMPageTableLevels + < pipes[k].pipe.src.gpuvm_levels_force) ? + pipes[k].pipe.src.gpuvm_levels_force : + mode_lib->vba.OverrideGPUVMPageTableLevels; + + mode_lib->vba.HostVMEnable = mode_lib->vba.HostVMEnable || !!pipes[k].pipe.src.hostvm || !!pipes[k].pipe.src.vm; + mode_lib->vba.OverrideHostVMPageTableLevels = + (pipes[k].pipe.src.hostvm_levels_force_en + && mode_lib->vba.OverrideHostVMPageTableLevels + < pipes[k].pipe.src.hostvm_levels_force) ? + pipes[k].pipe.src.hostvm_levels_force : + mode_lib->vba.OverrideHostVMPageTableLevels; + } + + mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank = dm_try_to_allow_self_refresh_and_mclk_switch; + + if (mode_lib->vba.OverrideGPUVMPageTableLevels) + mode_lib->vba.GPUVMMaxPageTableLevels = mode_lib->vba.OverrideGPUVMPageTableLevels; + + if (mode_lib->vba.OverrideHostVMPageTableLevels) + mode_lib->vba.HostVMMaxPageTableLevels = mode_lib->vba.OverrideHostVMPageTableLevels; + + mode_lib->vba.GPUVMEnable = mode_lib->vba.GPUVMEnable && !!ip->gpuvm_enable; + mode_lib->vba.HostVMEnable = mode_lib->vba.HostVMEnable && !!ip->hostvm_enable; +} + +// in wm mode we pull the parameters needed from the display_e2e_pipe_params_st structs +// rather than working them out as in recalculate_ms +static void recalculate_params( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes) +{ + // This is only safe to use memcmp because there are non-POD types in struct display_mode_lib + if (memcmp(&mode_lib->soc, &mode_lib->vba.soc, sizeof(mode_lib->vba.soc)) != 0 + || memcmp(&mode_lib->ip, &mode_lib->vba.ip, sizeof(mode_lib->vba.ip)) != 0 + || num_pipes != mode_lib->vba.cache_num_pipes + || memcmp( + pipes, + mode_lib->vba.cache_pipes, + sizeof(display_e2e_pipe_params_st) * num_pipes) != 0) { + mode_lib->vba.soc = mode_lib->soc; + mode_lib->vba.ip = mode_lib->ip; + memcpy(mode_lib->vba.cache_pipes, pipes, sizeof(*pipes) * num_pipes); + mode_lib->vba.cache_num_pipes = num_pipes; + mode_lib->funcs.recalculate(mode_lib); + } +} + +bool Calculate256BBlockSizes( + enum source_format_class SourcePixelFormat, + enum dm_swizzle_mode SurfaceTiling, + unsigned int BytePerPixelY, + unsigned int BytePerPixelC, + unsigned int *BlockHeight256BytesY, + unsigned int *BlockHeight256BytesC, + unsigned int *BlockWidth256BytesY, + unsigned int *BlockWidth256BytesC) +{ + if ((SourcePixelFormat == dm_444_64 || SourcePixelFormat == dm_444_32 + || SourcePixelFormat == dm_444_16 || SourcePixelFormat == dm_444_8)) { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + } else if (SourcePixelFormat == dm_444_64) { + *BlockHeight256BytesY = 4; + } else if (SourcePixelFormat == dm_444_8) { + *BlockHeight256BytesY = 16; + } else { + *BlockHeight256BytesY = 8; + } + *BlockWidth256BytesY = 256 / BytePerPixelY / *BlockHeight256BytesY; + *BlockHeight256BytesC = 0; + *BlockWidth256BytesC = 0; + } else { + if (SurfaceTiling == dm_sw_linear) { + *BlockHeight256BytesY = 1; + *BlockHeight256BytesC = 1; + } else if (SourcePixelFormat == dm_420_8) { + *BlockHeight256BytesY = 16; + *BlockHeight256BytesC = 8; + } else { + *BlockHeight256BytesY = 8; + *BlockHeight256BytesC = 8; + } + *BlockWidth256BytesY = 256 / BytePerPixelY / *BlockHeight256BytesY; + *BlockWidth256BytesC = 256 / BytePerPixelC / *BlockHeight256BytesC; + } + return true; +} + +bool CalculateMinAndMaxPrefetchMode( + enum self_refresh_affinity AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, + unsigned int *MinPrefetchMode, + unsigned int *MaxPrefetchMode) +{ + if (AllowDRAMSelfRefreshOrDRAMClockChangeInVblank + == dm_neither_self_refresh_nor_mclk_switch) { + *MinPrefetchMode = 2; + *MaxPrefetchMode = 2; + return false; + } else if (AllowDRAMSelfRefreshOrDRAMClockChangeInVblank == dm_allow_self_refresh) { + *MinPrefetchMode = 1; + *MaxPrefetchMode = 1; + return false; + } else if (AllowDRAMSelfRefreshOrDRAMClockChangeInVblank + == dm_allow_self_refresh_and_mclk_switch) { + *MinPrefetchMode = 0; + *MaxPrefetchMode = 0; + return false; + } else if (AllowDRAMSelfRefreshOrDRAMClockChangeInVblank + == dm_try_to_allow_self_refresh_and_mclk_switch) { + *MinPrefetchMode = 0; + *MaxPrefetchMode = 2; + return false; + } + *MinPrefetchMode = 0; + *MaxPrefetchMode = 2; + return true; +} + +void PixelClockAdjustmentForProgressiveToInterlaceUnit(struct display_mode_lib *mode_lib) +{ + unsigned int k; + + //Progressive To Interlace Unit Effect + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.Interlace[k] == 1 + && mode_lib->vba.ProgressiveToInterlaceUnitInOPP == true) { + mode_lib->vba.PixelClock[k] = 2 * mode_lib->vba.PixelClockBackEnd[k]; + } + } +} + +static unsigned int CursorBppEnumToBits(enum cursor_bpp ebpp) +{ + switch (ebpp) { + case dm_cur_2bit: + return 2; + case dm_cur_32bit: + return 32; + case dm_cur_64bit: + return 64; + default: + return 0; + } +} + +void ModeSupportAndSystemConfiguration(struct display_mode_lib *mode_lib) +{ + soc_bounding_box_st *soc = &mode_lib->vba.soc; + unsigned int k; + unsigned int total_pipes = 0; + + mode_lib->vba.VoltageLevel = mode_lib->vba.cache_pipes[0].clks_cfg.voltage; + mode_lib->vba.ReturnBW = mode_lib->vba.ReturnBWPerState[mode_lib->vba.VoltageLevel]; + mode_lib->vba.FabricAndDRAMBandwidth = mode_lib->vba.FabricAndDRAMBandwidthPerState[mode_lib->vba.VoltageLevel]; + + fetch_socbb_params(mode_lib); + fetch_ip_params(mode_lib); + fetch_pipe_params(mode_lib); + + mode_lib->vba.DCFCLK = mode_lib->vba.cache_pipes[0].clks_cfg.dcfclk_mhz; + mode_lib->vba.SOCCLK = mode_lib->vba.cache_pipes[0].clks_cfg.socclk_mhz; + if (mode_lib->vba.cache_pipes[0].clks_cfg.dispclk_mhz > 0.0) + mode_lib->vba.DISPCLK = mode_lib->vba.cache_pipes[0].clks_cfg.dispclk_mhz; + else + mode_lib->vba.DISPCLK = soc->clock_limits[mode_lib->vba.VoltageLevel].dispclk_mhz; + + // Total Available Pipes Support Check + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) + total_pipes += mode_lib->vba.DPPPerPlane[k]; + ASSERT(total_pipes <= DC__NUM_DPP__MAX); +} + +double CalculateWriteBackDISPCLK( + enum source_format_class WritebackPixelFormat, + double PixelClock, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackLumaHTaps, + unsigned int WritebackLumaVTaps, + unsigned int WritebackChromaHTaps, + unsigned int WritebackChromaVTaps, + double WritebackDestinationWidth, + unsigned int HTotal, + unsigned int WritebackChromaLineBufferWidth) +{ + double CalculateWriteBackDISPCLK = 1.01 * PixelClock * dml_max( + dml_ceil(WritebackLumaHTaps / 4.0, 1) / WritebackHRatio, + dml_max((WritebackLumaVTaps * dml_ceil(1.0 / WritebackVRatio, 1) * dml_ceil(WritebackDestinationWidth / 4.0, 1) + + dml_ceil(WritebackDestinationWidth / 4.0, 1)) / (double) HTotal + dml_ceil(1.0 / WritebackVRatio, 1) + * (dml_ceil(WritebackLumaVTaps / 4.0, 1) + 4.0) / (double) HTotal, + dml_ceil(1.0 / WritebackVRatio, 1) * WritebackDestinationWidth / (double) HTotal)); + if (WritebackPixelFormat != dm_444_32) { + CalculateWriteBackDISPCLK = dml_max(CalculateWriteBackDISPCLK, 1.01 * PixelClock * dml_max( + dml_ceil(WritebackChromaHTaps / 2.0, 1) / (2 * WritebackHRatio), + dml_max((WritebackChromaVTaps * dml_ceil(1 / (2 * WritebackVRatio), 1) * dml_ceil(WritebackDestinationWidth / 2.0 / 2.0, 1) + + dml_ceil(WritebackDestinationWidth / 2.0 / WritebackChromaLineBufferWidth, 1)) / HTotal + + dml_ceil(1 / (2 * WritebackVRatio), 1) * (dml_ceil(WritebackChromaVTaps / 4.0, 1) + 4) / HTotal, + dml_ceil(1.0 / (2 * WritebackVRatio), 1) * WritebackDestinationWidth / 2.0 / HTotal))); + } + return CalculateWriteBackDISPCLK; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h new file mode 100644 index 000000000000..0347f74cda3a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -0,0 +1,854 @@ +/* + * 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. + * + * Authors: AMD + * + */ + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + +#ifndef __DML2_DISPLAY_MODE_VBA_H__ +#define __DML2_DISPLAY_MODE_VBA_H__ + +#include "dml_common_defs.h" + +struct display_mode_lib; + +void ModeSupportAndSystemConfiguration(struct display_mode_lib *mode_lib); + +#define dml_get_attr_decl(attr) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes) + +dml_get_attr_decl(clk_dcf_deepsleep); +dml_get_attr_decl(wm_urgent); +dml_get_attr_decl(wm_memory_trip); +dml_get_attr_decl(wm_writeback_urgent); +dml_get_attr_decl(wm_stutter_exit); +dml_get_attr_decl(wm_stutter_enter_exit); +dml_get_attr_decl(wm_dram_clock_change); +dml_get_attr_decl(wm_writeback_dram_clock_change); +dml_get_attr_decl(wm_xfc_underflow); +dml_get_attr_decl(stutter_efficiency_no_vblank); +dml_get_attr_decl(stutter_efficiency); +dml_get_attr_decl(urgent_latency); +dml_get_attr_decl(urgent_extra_latency); +dml_get_attr_decl(nonurgent_latency); +dml_get_attr_decl(dram_clock_change_latency); +dml_get_attr_decl(dispclk_calculated); +dml_get_attr_decl(total_data_read_bw); +dml_get_attr_decl(return_bw); +dml_get_attr_decl(tcalc); +dml_get_attr_decl(fraction_of_urgent_bandwidth); +dml_get_attr_decl(fraction_of_urgent_bandwidth_imm_flip); + +#define dml_get_pipe_attr_decl(attr) double get_##attr(struct display_mode_lib *mode_lib, const display_e2e_pipe_params_st *pipes, unsigned int num_pipes, unsigned int which_pipe) + +dml_get_pipe_attr_decl(dsc_delay); +dml_get_pipe_attr_decl(dppclk_calculated); +dml_get_pipe_attr_decl(dscclk_calculated); +dml_get_pipe_attr_decl(min_ttu_vblank); +dml_get_pipe_attr_decl(vratio_prefetch_l); +dml_get_pipe_attr_decl(vratio_prefetch_c); +dml_get_pipe_attr_decl(dst_x_after_scaler); +dml_get_pipe_attr_decl(dst_y_after_scaler); +dml_get_pipe_attr_decl(dst_y_per_vm_vblank); +dml_get_pipe_attr_decl(dst_y_per_row_vblank); +dml_get_pipe_attr_decl(dst_y_prefetch); +dml_get_pipe_attr_decl(dst_y_per_vm_flip); +dml_get_pipe_attr_decl(dst_y_per_row_flip); +dml_get_pipe_attr_decl(xfc_transfer_delay); +dml_get_pipe_attr_decl(xfc_precharge_delay); +dml_get_pipe_attr_decl(xfc_remote_surface_flip_latency); +dml_get_pipe_attr_decl(xfc_prefetch_margin); +dml_get_pipe_attr_decl(refcyc_per_vm_group_vblank); +dml_get_pipe_attr_decl(refcyc_per_vm_group_flip); +dml_get_pipe_attr_decl(refcyc_per_vm_req_vblank); +dml_get_pipe_attr_decl(refcyc_per_vm_req_flip); + +unsigned int get_vstartup_calculated( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes, + unsigned int which_pipe); + +double get_total_immediate_flip_bytes( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes); +double get_total_immediate_flip_bw( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes); +double get_total_prefetch_bw( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes); +unsigned int dml_get_voltage_level( + struct display_mode_lib *mode_lib, + const display_e2e_pipe_params_st *pipes, + unsigned int num_pipes); + +void PixelClockAdjustmentForProgressiveToInterlaceUnit(struct display_mode_lib *mode_lib); + +bool Calculate256BBlockSizes( + enum source_format_class SourcePixelFormat, + enum dm_swizzle_mode SurfaceTiling, + unsigned int BytePerPixelY, + unsigned int BytePerPixelC, + unsigned int *BlockHeight256BytesY, + unsigned int *BlockHeight256BytesC, + unsigned int *BlockWidth256BytesY, + unsigned int *BlockWidth256BytesC); + +struct vba_vars_st { + ip_params_st ip; + soc_bounding_box_st soc; + + int maxMpcComb; + bool UseMaximumVStartup; + + double WritebackDISPCLK; + double DPPCLKUsingSingleDPPLuma; + double DPPCLKUsingSingleDPPChroma; + double DISPCLKWithRamping; + double DISPCLKWithoutRamping; + double GlobalDPPCLK; + double DISPCLKWithRampingRoundedToDFSGranularity; + double DISPCLKWithoutRampingRoundedToDFSGranularity; + double MaxDispclkRoundedToDFSGranularity; + bool DCCEnabledAnyPlane; + double ReturnBandwidthToDCN; + unsigned int TotalActiveDPP; + unsigned int TotalDCCActiveDPP; + double UrgentRoundTripAndOutOfOrderLatency; + double StutterPeriod; + double FrameTimeForMinFullDETBufferingTime; + double AverageReadBandwidth; + double TotalRowReadBandwidth; + double PartOfBurstThatFitsInROB; + double StutterBurstTime; + unsigned int NextPrefetchMode; + double NextMaxVStartup; + double VBlankTime; + double SmallestVBlank; + double DCFCLKDeepSleepPerPlane[DC__NUM_DPP__MAX]; + double EffectiveDETPlusLBLinesLuma; + double EffectiveDETPlusLBLinesChroma; + double UrgentLatencySupportUsLuma; + double UrgentLatencySupportUsChroma; + unsigned int DSCFormatFactor; + + bool PrefetchModeSupported; + enum self_refresh_affinity AllowDRAMSelfRefreshOrDRAMClockChangeInVblank; // Mode Support only + double XFCRemoteSurfaceFlipDelay; + double TInitXFill; + double TslvChk; + double SrcActiveDrainRate; + bool ImmediateFlipSupported; + enum mpc_combine_affinity WhenToDoMPCCombine; // Mode Support only + + bool PrefetchERROR; + + unsigned int VStartupLines; + unsigned int ActiveDPPs; + unsigned int LBLatencyHidingSourceLinesY; + unsigned int LBLatencyHidingSourceLinesC; + double ActiveDRAMClockChangeLatencyMargin[DC__NUM_DPP__MAX]; + double MinActiveDRAMClockChangeMargin; + double InitFillLevel; + double FinalFillMargin; + double FinalFillLevel; + double RemainingFillLevel; + double TFinalxFill; + + // + // SOC Bounding Box Parameters + // + double SRExitTime; + double SREnterPlusExitTime; + double UrgentLatencyPixelDataOnly; + double UrgentLatencyPixelMixedWithVMData; + double UrgentLatencyVMDataOnly; + double UrgentLatency; // max of the above three + double WritebackLatency; + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelDataOnly; // Mode Support + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData; // Mode Support + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; // Mode Support + double MaxAveragePercentOfIdealSDPPortBWDisplayCanUseInNormalSystemOperation; // Mode Support + double MaxAveragePercentOfIdealDRAMBWDisplayCanUseInNormalSystemOperation; // Mode Support + double NumberOfChannels; + double DRAMChannelWidth; + double FabricDatapathToDCNDataReturn; + double ReturnBusWidth; + double Downspreading; + double DISPCLKDPPCLKDSCCLKDownSpreading; + double DISPCLKDPPCLKVCOSpeed; + double RoundTripPingLatencyCycles; + double UrgentOutOfOrderReturnPerChannel; + double UrgentOutOfOrderReturnPerChannelPixelDataOnly; + double UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData; + double UrgentOutOfOrderReturnPerChannelVMDataOnly; + unsigned int VMMPageSize; + double DRAMClockChangeLatency; + double XFCBusTransportTime; + bool UseUrgentBurstBandwidth; + double XFCXBUFLatencyTolerance; + + // + // IP Parameters + // + unsigned int ROBBufferSizeInKByte; + double DETBufferSizeInKByte; + double DETBufferSizeInTime; + unsigned int DPPOutputBufferPixels; + unsigned int OPPOutputBufferLines; + unsigned int PixelChunkSizeInKByte; + double ReturnBW; + bool GPUVMEnable; + bool HostVMEnable; + unsigned int GPUVMMaxPageTableLevels; + unsigned int HostVMMaxPageTableLevels; + unsigned int HostVMCachedPageTableLevels; + unsigned int OverrideGPUVMPageTableLevels; + unsigned int OverrideHostVMPageTableLevels; + unsigned int MetaChunkSize; + double MinPixelChunkSizeBytes; + double MinMetaChunkSizeBytes; + unsigned int WritebackChunkSize; + bool ODMCapability; + unsigned int NumberOfDSC; + unsigned int LineBufferSize; + unsigned int MaxLineBufferLines; + unsigned int WritebackInterfaceLumaBufferSize; + unsigned int WritebackInterfaceChromaBufferSize; + unsigned int WritebackChromaLineBufferWidth; + enum writeback_config WritebackConfiguration; + double MaxDCHUBToPSCLThroughput; + double MaxPSCLToLBThroughput; + unsigned int PTEBufferSizeInRequestsLuma; + unsigned int PTEBufferSizeInRequestsChroma; + double DISPCLKRampingMargin; + unsigned int MaxInterDCNTileRepeaters; + bool XFCSupported; + double XFCSlvChunkSize; + double XFCFillBWOverhead; + double XFCFillConstant; + double XFCTSlvVupdateOffset; + double XFCTSlvVupdateWidth; + double XFCTSlvVreadyOffset; + double DPPCLKDelaySubtotal; + double DPPCLKDelaySCL; + double DPPCLKDelaySCLLBOnly; + double DPPCLKDelayCNVCFormater; + double DPPCLKDelayCNVCCursor; + double DISPCLKDelaySubtotal; + bool ProgressiveToInterlaceUnitInOPP; + // Pipe/Plane Parameters + int VoltageLevel; + double FabricClock; + double DRAMSpeed; + double DISPCLK; + double SOCCLK; + double DCFCLK; + + unsigned int NumberOfActivePlanes; + unsigned int NumberOfDSCSlices[DC__NUM_DPP__MAX]; + unsigned int ViewportWidth[DC__NUM_DPP__MAX]; + unsigned int ViewportHeight[DC__NUM_DPP__MAX]; + unsigned int ViewportYStartY[DC__NUM_DPP__MAX]; + unsigned int ViewportYStartC[DC__NUM_DPP__MAX]; + unsigned int PitchY[DC__NUM_DPP__MAX]; + unsigned int PitchC[DC__NUM_DPP__MAX]; + double HRatio[DC__NUM_DPP__MAX]; + double VRatio[DC__NUM_DPP__MAX]; + unsigned int htaps[DC__NUM_DPP__MAX]; + unsigned int vtaps[DC__NUM_DPP__MAX]; + unsigned int HTAPsChroma[DC__NUM_DPP__MAX]; + unsigned int VTAPsChroma[DC__NUM_DPP__MAX]; + unsigned int HTotal[DC__NUM_DPP__MAX]; + unsigned int VTotal[DC__NUM_DPP__MAX]; + unsigned int VTotal_Max[DC__NUM_DPP__MAX]; + unsigned int VTotal_Min[DC__NUM_DPP__MAX]; + int DPPPerPlane[DC__NUM_DPP__MAX]; + double PixelClock[DC__NUM_DPP__MAX]; + double PixelClockBackEnd[DC__NUM_DPP__MAX]; + bool DCCEnable[DC__NUM_DPP__MAX]; + unsigned int DCCMetaPitchY[DC__NUM_DPP__MAX]; + unsigned int DCCMetaPitchC[DC__NUM_DPP__MAX]; + enum scan_direction_class SourceScan[DC__NUM_DPP__MAX]; + enum source_format_class SourcePixelFormat[DC__NUM_DPP__MAX]; + bool WritebackEnable[DC__NUM_DPP__MAX]; + unsigned int ActiveWritebacksPerPlane[DC__NUM_DPP__MAX]; + double WritebackDestinationWidth[DC__NUM_DPP__MAX]; + double WritebackDestinationHeight[DC__NUM_DPP__MAX]; + double WritebackSourceHeight[DC__NUM_DPP__MAX]; + enum source_format_class WritebackPixelFormat[DC__NUM_DPP__MAX]; + unsigned int WritebackLumaHTaps[DC__NUM_DPP__MAX]; + unsigned int WritebackLumaVTaps[DC__NUM_DPP__MAX]; + unsigned int WritebackChromaHTaps[DC__NUM_DPP__MAX]; + unsigned int WritebackChromaVTaps[DC__NUM_DPP__MAX]; + double WritebackHRatio[DC__NUM_DPP__MAX]; + double WritebackVRatio[DC__NUM_DPP__MAX]; + unsigned int HActive[DC__NUM_DPP__MAX]; + unsigned int VActive[DC__NUM_DPP__MAX]; + bool Interlace[DC__NUM_DPP__MAX]; + enum dm_swizzle_mode SurfaceTiling[DC__NUM_DPP__MAX]; + unsigned int ScalerRecoutWidth[DC__NUM_DPP__MAX]; + bool DynamicMetadataEnable[DC__NUM_DPP__MAX]; + int DynamicMetadataLinesBeforeActiveRequired[DC__NUM_DPP__MAX]; + unsigned int DynamicMetadataTransmittedBytes[DC__NUM_DPP__MAX]; + double DCCRate[DC__NUM_DPP__MAX]; + double AverageDCCCompressionRate; + bool ODMCombineEnabled[DC__NUM_DPP__MAX]; + double OutputBpp[DC__NUM_DPP__MAX]; + bool DSCEnabled[DC__NUM_DPP__MAX]; + unsigned int DSCInputBitPerComponent[DC__NUM_DPP__MAX]; + enum output_format_class OutputFormat[DC__NUM_DPP__MAX]; + enum output_encoder_class Output[DC__NUM_DPP__MAX]; + unsigned int BlendingAndTiming[DC__NUM_DPP__MAX]; + bool SynchronizedVBlank; + unsigned int NumberOfCursors[DC__NUM_DPP__MAX]; + unsigned int CursorWidth[DC__NUM_DPP__MAX][DC__NUM_CURSOR__MAX]; + unsigned int CursorBPP[DC__NUM_DPP__MAX][DC__NUM_CURSOR__MAX]; + bool XFCEnabled[DC__NUM_DPP__MAX]; + bool ScalerEnabled[DC__NUM_DPP__MAX]; + + // Intermediates/Informational + bool ImmediateFlipSupport; + double DETBufferSizeY[DC__NUM_DPP__MAX]; + double DETBufferSizeC[DC__NUM_DPP__MAX]; + unsigned int SwathHeightY[DC__NUM_DPP__MAX]; + unsigned int SwathHeightC[DC__NUM_DPP__MAX]; + unsigned int LBBitPerPixel[DC__NUM_DPP__MAX]; + double LastPixelOfLineExtraWatermark; + double TotalDataReadBandwidth; + unsigned int TotalActiveWriteback; + unsigned int EffectiveLBLatencyHidingSourceLinesLuma; + unsigned int EffectiveLBLatencyHidingSourceLinesChroma; + double BandwidthAvailableForImmediateFlip; + unsigned int PrefetchMode[DC__VOLTAGE_STATES + 1][2]; + unsigned int MinPrefetchMode; + unsigned int MaxPrefetchMode; + bool AnyLinesForVMOrRowTooLarge; + double MaxVStartup; + bool IgnoreViewportPositioning; + bool ErrorResult[DC__NUM_DPP__MAX]; + // + // Calculated dml_ml->vba.Outputs + // + double DCFCLKDeepSleep; + double UrgentWatermark; + double UrgentExtraLatency; + double WritebackUrgentWatermark; + double StutterExitWatermark; + double StutterEnterPlusExitWatermark; + double DRAMClockChangeWatermark; + double WritebackDRAMClockChangeWatermark; + double StutterEfficiency; + double StutterEfficiencyNotIncludingVBlank; + double NonUrgentLatencyTolerance; + double MinActiveDRAMClockChangeLatencySupported; + + // These are the clocks calcuated by the library but they are not actually + // used explicitly. They are fetched by tests and then possibly used. The + // ultimate values to use are the ones specified by the parameters to DML + double DISPCLK_calculated; + double DPPCLK_calculated[DC__NUM_DPP__MAX]; + + unsigned int VUpdateOffsetPix[DC__NUM_DPP__MAX]; + double VUpdateWidthPix[DC__NUM_DPP__MAX]; + double VReadyOffsetPix[DC__NUM_DPP__MAX]; + + unsigned int TotImmediateFlipBytes; + double TCalc; + + display_e2e_pipe_params_st cache_pipes[DC__NUM_DPP__MAX]; + unsigned int cache_num_pipes; + unsigned int pipe_plane[DC__NUM_DPP__MAX]; + + /* vba mode support */ + /*inputs*/ + bool SupportGFX7CompatibleTilingIn32bppAnd64bpp; + double MaxHSCLRatio; + double MaxVSCLRatio; + unsigned int MaxNumWriteback; + bool WritebackLumaAndChromaScalingSupported; + bool Cursor64BppSupport; + double DCFCLKPerState[DC__VOLTAGE_STATES + 1]; + double FabricClockPerState[DC__VOLTAGE_STATES + 1]; + double SOCCLKPerState[DC__VOLTAGE_STATES + 1]; + double PHYCLKPerState[DC__VOLTAGE_STATES + 1]; + double MaxDppclk[DC__VOLTAGE_STATES + 1]; + double MaxDSCCLK[DC__VOLTAGE_STATES + 1]; + double DRAMSpeedPerState[DC__VOLTAGE_STATES + 1]; + double MaxDispclk[DC__VOLTAGE_STATES + 1]; + int VoltageOverrideLevel; + + /*outputs*/ + bool ScaleRatioAndTapsSupport; + bool SourceFormatPixelAndScanSupport; + double TotalBandwidthConsumedGBytePerSecond; + bool DCCEnabledInAnyPlane; + bool WritebackLatencySupport; + bool WritebackModeSupport; + bool Writeback10bpc420Supported; + bool BandwidthSupport[DC__VOLTAGE_STATES + 1]; + unsigned int TotalNumberOfActiveWriteback; + double CriticalPoint; + double ReturnBWToDCNPerState; + bool IsErrorResult[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + bool prefetch_vm_bw_valid; + bool prefetch_row_bw_valid; + bool NumberOfOTGSupport; + bool NonsupportedDSCInputBPC; + bool WritebackScaleRatioAndTapsSupport; + bool CursorSupport; + bool PitchSupport; + enum dm_validation_status ValidationStatus[DC__VOLTAGE_STATES + 1]; + + double WritebackLineBufferLumaBufferSize; + double WritebackLineBufferChromaBufferSize; + double WritebackMinHSCLRatio; + double WritebackMinVSCLRatio; + double WritebackMaxHSCLRatio; + double WritebackMaxVSCLRatio; + double WritebackMaxHSCLTaps; + double WritebackMaxVSCLTaps; + unsigned int MaxNumDPP; + unsigned int MaxNumOTG; + double CursorBufferSize; + double CursorChunkSize; + unsigned int Mode; + double OutputLinkDPLanes[DC__NUM_DPP__MAX]; + double ForcedOutputLinkBPP[DC__NUM_DPP__MAX]; // Mode Support only + double ImmediateFlipBW[DC__NUM_DPP__MAX]; + double MaxMaxVStartup; + + double WritebackLumaVExtra; + double WritebackChromaVExtra; + double WritebackRequiredDISPCLK; + double MaximumSwathWidthSupport; + double MaximumSwathWidthInDETBuffer; + double MaximumSwathWidthInLineBuffer; + double MaxDispclkRoundedDownToDFSGranularity; + double MaxDppclkRoundedDownToDFSGranularity; + double PlaneRequiredDISPCLKWithoutODMCombine; + double PlaneRequiredDISPCLKWithODMCombine; + double PlaneRequiredDISPCLK; + double TotalNumberOfActiveOTG; + double FECOverhead; + double EffectiveFECOverhead; + double Outbpp; + unsigned int OutbppDSC; + double TotalDSCUnitsRequired; + double bpp; + unsigned int slices; + double SwathWidthGranularityY; + double RoundedUpMaxSwathSizeBytesY; + double SwathWidthGranularityC; + double RoundedUpMaxSwathSizeBytesC; + double EffectiveDETLBLinesLuma; + double EffectiveDETLBLinesChroma; + double ProjectedDCFCLKDeepSleep; + double PDEAndMetaPTEBytesPerFrameY; + double PDEAndMetaPTEBytesPerFrameC; + unsigned int MetaRowBytesY; + unsigned int MetaRowBytesC; + unsigned int DPTEBytesPerRowC; + unsigned int DPTEBytesPerRowY; + double ExtraLatency; + double TimeCalc; + double TWait; + double MaximumReadBandwidthWithPrefetch; + double MaximumReadBandwidthWithoutPrefetch; + double total_dcn_read_bw_with_flip; + double total_dcn_read_bw_with_flip_no_urgent_burst; + double FractionOfUrgentBandwidth; + double FractionOfUrgentBandwidthImmediateFlip; // Mode Support debugging output + + /* ms locals */ + double IdealSDPPortBandwidthPerState[DC__VOLTAGE_STATES + 1]; + unsigned int NoOfDPP[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + int NoOfDPPThisState[DC__NUM_DPP__MAX]; + bool ODMCombineEnablePerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + unsigned int SwathWidthYThisState[DC__NUM_DPP__MAX]; + unsigned int SwathHeightCPerState[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + unsigned int SwathHeightYThisState[DC__NUM_DPP__MAX]; + unsigned int SwathHeightCThisState[DC__NUM_DPP__MAX]; + double VRatioPreY[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double VRatioPreC[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double RequiredPrefetchPixelDataBWLuma[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double RequiredPrefetchPixelDataBWChroma[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double RequiredDPPCLK[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double RequiredDPPCLKThisState[DC__NUM_DPP__MAX]; + bool PTEBufferSizeNotExceededY[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + bool PTEBufferSizeNotExceededC[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + bool BandwidthWithoutPrefetchSupported[DC__VOLTAGE_STATES + 1]; + bool PrefetchSupported[DC__VOLTAGE_STATES + 1][2]; + bool VRatioInPrefetchSupported[DC__VOLTAGE_STATES + 1][2]; + double RequiredDISPCLK[DC__VOLTAGE_STATES + 1][2]; + bool DISPCLK_DPPCLK_Support[DC__VOLTAGE_STATES + 1][2]; + bool TotalAvailablePipesSupport[DC__VOLTAGE_STATES + 1][2]; + unsigned int TotalNumberOfActiveDPP[DC__VOLTAGE_STATES + 1][2]; + unsigned int TotalNumberOfDCCActiveDPP[DC__VOLTAGE_STATES + 1][2]; + bool ModeSupport[DC__VOLTAGE_STATES + 1][2]; + double ReturnBWPerState[DC__VOLTAGE_STATES + 1]; + bool DIOSupport[DC__VOLTAGE_STATES + 1]; + bool NotEnoughDSCUnits[DC__VOLTAGE_STATES + 1]; + bool DSCCLKRequiredMoreThanSupported[DC__VOLTAGE_STATES + 1]; + double UrgentRoundTripAndOutOfOrderLatencyPerState[DC__VOLTAGE_STATES + 1]; + bool ROBSupport[DC__VOLTAGE_STATES + 1]; + bool PTEBufferSizeNotExceeded[DC__VOLTAGE_STATES + 1][2]; + bool TotalVerticalActiveBandwidthSupport[DC__VOLTAGE_STATES + 1]; + double MaxTotalVerticalActiveAvailableBandwidth[DC__VOLTAGE_STATES + 1]; + double PrefetchBW[DC__NUM_DPP__MAX]; + double PDEAndMetaPTEBytesPerFrame[DC__NUM_DPP__MAX]; + double MetaRowBytes[DC__NUM_DPP__MAX]; + double DPTEBytesPerRow[DC__NUM_DPP__MAX]; + double PrefetchLinesY[DC__NUM_DPP__MAX]; + double PrefetchLinesC[DC__NUM_DPP__MAX]; + unsigned int MaxNumSwY[DC__NUM_DPP__MAX]; + unsigned int MaxNumSwC[DC__NUM_DPP__MAX]; + double PrefillY[DC__NUM_DPP__MAX]; + double PrefillC[DC__NUM_DPP__MAX]; + double LineTimesForPrefetch[DC__NUM_DPP__MAX]; + double LinesForMetaPTE[DC__NUM_DPP__MAX]; + double LinesForMetaAndDPTERow[DC__NUM_DPP__MAX]; + double MinDPPCLKUsingSingleDPP[DC__NUM_DPP__MAX]; + unsigned int SwathWidthYSingleDPP[DC__NUM_DPP__MAX]; + double BytePerPixelInDETY[DC__NUM_DPP__MAX]; + double BytePerPixelInDETC[DC__NUM_DPP__MAX]; + bool RequiresDSC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + unsigned int NumberOfDSCSlice[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + double RequiresFEC[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + double OutputBppPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + double DSCDelayPerState[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + bool ViewportSizeSupport[DC__VOLTAGE_STATES + 1]; + unsigned int Read256BlockHeightY[DC__NUM_DPP__MAX]; + unsigned int Read256BlockWidthY[DC__NUM_DPP__MAX]; + unsigned int Read256BlockHeightC[DC__NUM_DPP__MAX]; + unsigned int Read256BlockWidthC[DC__NUM_DPP__MAX]; + double MaxSwathHeightY[DC__NUM_DPP__MAX]; + double MaxSwathHeightC[DC__NUM_DPP__MAX]; + double MinSwathHeightY[DC__NUM_DPP__MAX]; + double MinSwathHeightC[DC__NUM_DPP__MAX]; + double ReadBandwidthLuma[DC__NUM_DPP__MAX]; + double ReadBandwidthChroma[DC__NUM_DPP__MAX]; + double ReadBandwidth[DC__NUM_DPP__MAX]; + double WriteBandwidth[DC__NUM_DPP__MAX]; + double PSCL_FACTOR[DC__NUM_DPP__MAX]; + double PSCL_FACTOR_CHROMA[DC__NUM_DPP__MAX]; + double MaximumVStartup[DC__NUM_DPP__MAX]; + unsigned int MacroTileWidthY[DC__NUM_DPP__MAX]; + unsigned int MacroTileWidthC[DC__NUM_DPP__MAX]; + double AlignedDCCMetaPitch[DC__NUM_DPP__MAX]; + double AlignedYPitch[DC__NUM_DPP__MAX]; + double AlignedCPitch[DC__NUM_DPP__MAX]; + double MaximumSwathWidth[DC__NUM_DPP__MAX]; + double cursor_bw[DC__NUM_DPP__MAX]; + double cursor_bw_pre[DC__NUM_DPP__MAX]; + double Tno_bw[DC__NUM_DPP__MAX]; + double prefetch_vmrow_bw[DC__NUM_DPP__MAX]; + double DestinationLinesToRequestVMInImmediateFlip[DC__NUM_DPP__MAX]; + double DestinationLinesToRequestRowInImmediateFlip[DC__NUM_DPP__MAX]; + double final_flip_bw[DC__NUM_DPP__MAX]; + bool ImmediateFlipSupportedForState[DC__VOLTAGE_STATES + 1][2]; + double WritebackDelay[DC__VOLTAGE_STATES + 1][DC__NUM_DPP__MAX]; + unsigned int vm_group_bytes[DC__NUM_DPP__MAX]; + long dpte_group_bytes[DC__NUM_DPP__MAX]; + unsigned int dpte_row_height[DC__NUM_DPP__MAX]; + unsigned int meta_req_height[DC__NUM_DPP__MAX]; + unsigned int meta_req_width[DC__NUM_DPP__MAX]; + unsigned int meta_row_height[DC__NUM_DPP__MAX]; + unsigned int meta_row_width[DC__NUM_DPP__MAX]; + unsigned int dpte_row_height_chroma[DC__NUM_DPP__MAX]; + unsigned int meta_req_height_chroma[DC__NUM_DPP__MAX]; + unsigned int meta_req_width_chroma[DC__NUM_DPP__MAX]; + unsigned int meta_row_height_chroma[DC__NUM_DPP__MAX]; + unsigned int meta_row_width_chroma[DC__NUM_DPP__MAX]; + bool ImmediateFlipSupportedForPipe[DC__NUM_DPP__MAX]; + double meta_row_bw[DC__NUM_DPP__MAX]; + double dpte_row_bw[DC__NUM_DPP__MAX]; + double DisplayPipeLineDeliveryTimeLuma[DC__NUM_DPP__MAX]; // WM + double DisplayPipeLineDeliveryTimeChroma[DC__NUM_DPP__MAX]; // WM + double DisplayPipeRequestDeliveryTimeLuma[DC__NUM_DPP__MAX]; + double DisplayPipeRequestDeliveryTimeChroma[DC__NUM_DPP__MAX]; + enum clock_change_support DRAMClockChangeSupport[DC__VOLTAGE_STATES + 1][2]; + double UrgentBurstFactorCursor[DC__NUM_DPP__MAX]; + double UrgentBurstFactorCursorPre[DC__NUM_DPP__MAX]; + double UrgentBurstFactorLuma[DC__NUM_DPP__MAX]; + double UrgentBurstFactorLumaPre[DC__NUM_DPP__MAX]; + double UrgentBurstFactorChroma[DC__NUM_DPP__MAX]; + double UrgentBurstFactorChromaPre[DC__NUM_DPP__MAX]; + + bool MPCCombine[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double SwathWidthCSingleDPP[DC__NUM_DPP__MAX]; + double MaximumSwathWidthInLineBufferLuma; + double MaximumSwathWidthInLineBufferChroma; + double MaximumSwathWidthLuma[DC__NUM_DPP__MAX]; + double MaximumSwathWidthChroma[DC__NUM_DPP__MAX]; + bool odm_combine_dummy[DC__NUM_DPP__MAX]; + double dummy1[DC__NUM_DPP__MAX]; + double dummy2[DC__NUM_DPP__MAX]; + double dummy3[DC__NUM_DPP__MAX]; + double dummy4[DC__NUM_DPP__MAX]; + double dummy5; + double dummy6; + double dummy7[DC__NUM_DPP__MAX]; + double dummy8[DC__NUM_DPP__MAX]; + unsigned int dummyinteger1ms[DC__NUM_DPP__MAX]; + unsigned int dummyinteger2ms[DC__NUM_DPP__MAX]; + unsigned int dummyinteger3[DC__NUM_DPP__MAX]; + unsigned int dummyinteger4; + unsigned int dummyinteger5; + unsigned int dummyinteger6; + unsigned int dummyinteger7; + unsigned int dummyinteger8; + unsigned int dummyinteger9; + unsigned int dummyinteger10; + unsigned int dummyinteger11; + unsigned int dummyinteger12; + bool dummysinglestring; + bool SingleDPPViewportSizeSupportPerPlane[DC__NUM_DPP__MAX]; + double PlaneRequiredDISPCLKWithODMCombine2To1; + double PlaneRequiredDISPCLKWithODMCombine4To1; + unsigned int TotalNumberOfSingleDPPPlanes[DC__VOLTAGE_STATES + 1][2]; + bool LinkDSCEnable; + bool ODMCombine4To1SupportCheckOK[DC__VOLTAGE_STATES + 1]; + bool ODMCombineEnableThisState[DC__NUM_DPP__MAX]; + unsigned int SwathWidthCThisState[DC__NUM_DPP__MAX]; + bool ViewportSizeSupportPerPlane[DC__NUM_DPP__MAX]; + double AlignedDCCMetaPitchY[DC__NUM_DPP__MAX]; + double AlignedDCCMetaPitchC[DC__NUM_DPP__MAX]; + + unsigned int NotEnoughUrgentLatencyHiding; + unsigned int NotEnoughUrgentLatencyHidingPre; + long PTEBufferSizeInRequestsForLuma; + + // Missing from VBA + long dpte_group_bytes_chroma; + unsigned int vm_group_bytes_chroma; + double dst_x_after_scaler; + double dst_y_after_scaler; + unsigned int VStartupRequiredWhenNotEnoughTimeForDynamicMetadata; + + /* perf locals*/ + double PrefetchBandwidth[DC__NUM_DPP__MAX]; + double VInitPreFillY[DC__NUM_DPP__MAX]; + double VInitPreFillC[DC__NUM_DPP__MAX]; + unsigned int MaxNumSwathY[DC__NUM_DPP__MAX]; + unsigned int MaxNumSwathC[DC__NUM_DPP__MAX]; + unsigned int VStartup[DC__NUM_DPP__MAX]; + double DSTYAfterScaler[DC__NUM_DPP__MAX]; + double DSTXAfterScaler[DC__NUM_DPP__MAX]; + bool AllowDRAMClockChangeDuringVBlank[DC__NUM_DPP__MAX]; + bool AllowDRAMSelfRefreshDuringVBlank[DC__NUM_DPP__MAX]; + double VRatioPrefetchY[DC__NUM_DPP__MAX]; + double VRatioPrefetchC[DC__NUM_DPP__MAX]; + double DestinationLinesForPrefetch[DC__NUM_DPP__MAX]; + double DestinationLinesToRequestVMInVBlank[DC__NUM_DPP__MAX]; + double DestinationLinesToRequestRowInVBlank[DC__NUM_DPP__MAX]; + double MinTTUVBlank[DC__NUM_DPP__MAX]; + double BytePerPixelDETY[DC__NUM_DPP__MAX]; + double BytePerPixelDETC[DC__NUM_DPP__MAX]; + unsigned int SwathWidthY[DC__NUM_DPP__MAX]; + unsigned int SwathWidthSingleDPPY[DC__NUM_DPP__MAX]; + double CursorRequestDeliveryTime[DC__NUM_DPP__MAX]; + double CursorRequestDeliveryTimePrefetch[DC__NUM_DPP__MAX]; + double ReadBandwidthPlaneLuma[DC__NUM_DPP__MAX]; + double ReadBandwidthPlaneChroma[DC__NUM_DPP__MAX]; + double DisplayPipeLineDeliveryTimeLumaPrefetch[DC__NUM_DPP__MAX]; + double DisplayPipeLineDeliveryTimeChromaPrefetch[DC__NUM_DPP__MAX]; + double DisplayPipeRequestDeliveryTimeLumaPrefetch[DC__NUM_DPP__MAX]; + double DisplayPipeRequestDeliveryTimeChromaPrefetch[DC__NUM_DPP__MAX]; + double PixelPTEBytesPerRow[DC__NUM_DPP__MAX]; + double PDEAndMetaPTEBytesFrame[DC__NUM_DPP__MAX]; + double MetaRowByte[DC__NUM_DPP__MAX]; + double PrefetchSourceLinesY[DC__NUM_DPP__MAX]; + double RequiredPrefetchPixDataBWLuma[DC__NUM_DPP__MAX]; + double RequiredPrefetchPixDataBWChroma[DC__NUM_DPP__MAX]; + double PrefetchSourceLinesC[DC__NUM_DPP__MAX]; + double PSCL_THROUGHPUT_LUMA[DC__NUM_DPP__MAX]; + double PSCL_THROUGHPUT_CHROMA[DC__NUM_DPP__MAX]; + double DSCCLK_calculated[DC__NUM_DPP__MAX]; + unsigned int DSCDelay[DC__NUM_DPP__MAX]; + unsigned int MaxVStartupLines[DC__NUM_DPP__MAX]; + double DPPCLKUsingSingleDPP[DC__NUM_DPP__MAX]; + double DPPCLK[DC__NUM_DPP__MAX]; + unsigned int DCCYMaxUncompressedBlock[DC__NUM_DPP__MAX]; + unsigned int DCCYMaxCompressedBlock[DC__NUM_DPP__MAX]; + unsigned int DCCYIndependent64ByteBlock[DC__NUM_DPP__MAX]; + double MaximumDCCCompressionYSurface[DC__NUM_DPP__MAX]; + unsigned int BlockHeight256BytesY[DC__NUM_DPP__MAX]; + unsigned int BlockHeight256BytesC[DC__NUM_DPP__MAX]; + unsigned int BlockWidth256BytesY[DC__NUM_DPP__MAX]; + unsigned int BlockWidth256BytesC[DC__NUM_DPP__MAX]; + double XFCSlaveVUpdateOffset[DC__NUM_DPP__MAX]; + double XFCSlaveVupdateWidth[DC__NUM_DPP__MAX]; + double XFCSlaveVReadyOffset[DC__NUM_DPP__MAX]; + double XFCTransferDelay[DC__NUM_DPP__MAX]; + double XFCPrechargeDelay[DC__NUM_DPP__MAX]; + double XFCRemoteSurfaceFlipLatency[DC__NUM_DPP__MAX]; + double XFCPrefetchMargin[DC__NUM_DPP__MAX]; + unsigned int dpte_row_width_luma_ub[DC__NUM_DPP__MAX]; + unsigned int dpte_row_width_chroma_ub[DC__NUM_DPP__MAX]; + double FullDETBufferingTimeY[DC__NUM_DPP__MAX]; // WM + double FullDETBufferingTimeC[DC__NUM_DPP__MAX]; // WM + double DST_Y_PER_PTE_ROW_NOM_L[DC__NUM_DPP__MAX]; + double DST_Y_PER_PTE_ROW_NOM_C[DC__NUM_DPP__MAX]; + double DST_Y_PER_META_ROW_NOM_L[DC__NUM_DPP__MAX]; + double TimePerMetaChunkNominal[DC__NUM_DPP__MAX]; + double TimePerMetaChunkVBlank[DC__NUM_DPP__MAX]; + double TimePerMetaChunkFlip[DC__NUM_DPP__MAX]; + unsigned int swath_width_luma_ub[DC__NUM_DPP__MAX]; + unsigned int swath_width_chroma_ub[DC__NUM_DPP__MAX]; + unsigned int PixelPTEReqWidthY[DC__NUM_DPP__MAX]; + unsigned int PixelPTEReqHeightY[DC__NUM_DPP__MAX]; + unsigned int PTERequestSizeY[DC__NUM_DPP__MAX]; + unsigned int PixelPTEReqWidthC[DC__NUM_DPP__MAX]; + unsigned int PixelPTEReqHeightC[DC__NUM_DPP__MAX]; + unsigned int PTERequestSizeC[DC__NUM_DPP__MAX]; + double time_per_pte_group_nom_luma[DC__NUM_DPP__MAX]; + double time_per_pte_group_nom_chroma[DC__NUM_DPP__MAX]; + double time_per_pte_group_vblank_luma[DC__NUM_DPP__MAX]; + double time_per_pte_group_vblank_chroma[DC__NUM_DPP__MAX]; + double time_per_pte_group_flip_luma[DC__NUM_DPP__MAX]; + double time_per_pte_group_flip_chroma[DC__NUM_DPP__MAX]; + double TimePerVMGroupVBlank[DC__NUM_DPP__MAX]; + double TimePerVMGroupFlip[DC__NUM_DPP__MAX]; + double TimePerVMRequestVBlank[DC__NUM_DPP__MAX]; + double TimePerVMRequestFlip[DC__NUM_DPP__MAX]; + unsigned int dpde0_bytes_per_frame_ub_l[DC__NUM_DPP__MAX]; + unsigned int meta_pte_bytes_per_frame_ub_l[DC__NUM_DPP__MAX]; + unsigned int dpde0_bytes_per_frame_ub_c[DC__NUM_DPP__MAX]; + unsigned int meta_pte_bytes_per_frame_ub_c[DC__NUM_DPP__MAX]; + double LinesToFinishSwathTransferStutterCriticalPlane; + unsigned int BytePerPixelYCriticalPlane; + double SwathWidthYCriticalPlane; + double LinesInDETY[DC__NUM_DPP__MAX]; + double LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX]; + + unsigned int SwathWidthSingleDPPC[DC__NUM_DPP__MAX]; + unsigned int SwathWidthC[DC__NUM_DPP__MAX]; + unsigned int BytePerPixelY[DC__NUM_DPP__MAX]; + unsigned int BytePerPixelC[DC__NUM_DPP__MAX]; + long dummyinteger1; + long dummyinteger2; + double FinalDRAMClockChangeLatency; + double Tdmdl_vm[DC__NUM_DPP__MAX]; + double Tdmdl[DC__NUM_DPP__MAX]; + unsigned int ThisVStartup; + bool WritebackAllowDRAMClockChangeEndPosition[DC__NUM_DPP__MAX]; + double DST_Y_PER_META_ROW_NOM_C[DC__NUM_DPP__MAX]; + double TimePerChromaMetaChunkNominal[DC__NUM_DPP__MAX]; + double TimePerChromaMetaChunkVBlank[DC__NUM_DPP__MAX]; + double TimePerChromaMetaChunkFlip[DC__NUM_DPP__MAX]; + unsigned int DCCCMaxUncompressedBlock[DC__NUM_DPP__MAX]; + unsigned int DCCCMaxCompressedBlock[DC__NUM_DPP__MAX]; + unsigned int DCCCIndependent64ByteBlock[DC__NUM_DPP__MAX]; + double VStartupMargin; + + /* Missing from VBA */ + unsigned int MaximumMaxVStartupLines; + double FabricAndDRAMBandwidth; + double LinesInDETLuma; + double LinesInDETChroma; + unsigned int ImmediateFlipBytes[DC__NUM_DPP__MAX]; + unsigned int LinesInDETC[DC__NUM_DPP__MAX]; + unsigned int LinesInDETCRoundedDownToSwath[DC__NUM_DPP__MAX]; + double UrgentLatencySupportUsPerState[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double UrgentLatencySupportUs[DC__NUM_DPP__MAX]; + double FabricAndDRAMBandwidthPerState[DC__VOLTAGE_STATES + 1]; + bool UrgentLatencySupport[DC__VOLTAGE_STATES + 1][2]; + unsigned int SwathWidthYPerState[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + unsigned int SwathHeightYPerState[DC__VOLTAGE_STATES + 1][2][DC__NUM_DPP__MAX]; + double qual_row_bw[DC__NUM_DPP__MAX]; + double prefetch_row_bw[DC__NUM_DPP__MAX]; + double prefetch_vm_bw[DC__NUM_DPP__MAX]; + + double PTEGroupSize; + unsigned int PDEProcessingBufIn64KBReqs; + + double MaxTotalVActiveRDBandwidth; + double MinUrgentLatencySupportUs; + double MinFullDETBufferingTime; + double AverageReadBandwidthGBytePerSecond; + bool FirstMainPlane; + + unsigned int ViewportWidthChroma[DC__NUM_DPP__MAX]; + unsigned int ViewportHeightChroma[DC__NUM_DPP__MAX]; + double HRatioChroma[DC__NUM_DPP__MAX]; + double VRatioChroma[DC__NUM_DPP__MAX]; + long WritebackSourceWidth[DC__NUM_DPP__MAX]; + + bool ModeIsSupported; + bool ODMCombine4To1Supported; + + unsigned int SurfaceHeightY[DC__NUM_DPP__MAX]; + unsigned int SurfaceHeightC[DC__NUM_DPP__MAX]; + unsigned int WritebackHTaps[DC__NUM_DPP__MAX]; + unsigned int WritebackVTaps[DC__NUM_DPP__MAX]; + bool DSCEnable[DC__NUM_DPP__MAX]; + + double DRAMClockChangeLatencyOverride; + + double GPUVMMinPageSize; + double HostVMMinPageSize; + + bool MPCCombineEnable[DC__NUM_DPP__MAX]; + unsigned int HostVMMaxNonCachedPageTableLevels; + bool DynamicMetadataVMEnabled; + double WritebackInterfaceBufferSize; + double WritebackLineBufferSize; + + double DCCRateLuma[DC__NUM_DPP__MAX]; + double DCCRateChroma[DC__NUM_DPP__MAX]; + + double PHYCLKD18PerState[DC__VOLTAGE_STATES + 1]; + int MinVoltageLevel; + int MaxVoltageLevel; + + bool WritebackSupportInterleaveAndUsingWholeBufferForASingleStream; + bool NumberOfHDMIFRLSupport; + unsigned int MaxNumHDMIFRLOutputs; + int AudioSampleRate[DC__NUM_DPP__MAX]; + int AudioSampleLayout[DC__NUM_DPP__MAX]; +}; + +bool CalculateMinAndMaxPrefetchMode( + enum self_refresh_affinity AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, + unsigned int *MinPrefetchMode, + unsigned int *MaxPrefetchMode); + +double CalculateWriteBackDISPCLK( + enum source_format_class WritebackPixelFormat, + double PixelClock, + double WritebackHRatio, + double WritebackVRatio, + unsigned int WritebackLumaHTaps, + unsigned int WritebackLumaVTaps, + unsigned int WritebackChromaHTaps, + unsigned int WritebackChromaVTaps, + double WritebackDestinationWidth, + unsigned int HTotal, + unsigned int WritebackChromaLineBufferWidth); + +#endif /* _DML2_DISPLAY_MODE_VBA_H_ */ +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h index e8ce08567cd8..eca140da13d8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h +++ b/drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h @@ -129,4 +129,12 @@ static inline unsigned int dml_round_to_multiple(unsigned int num, else return (num - remainder); } +static inline double dml_abs(double a) +{ + if (a > 0) + return a; + else + return (a*(-1)); +} + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile new file mode 100644 index 000000000000..e019cd9447e8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the 'dsc' sub-component of DAL. + +ifneq ($(call cc-option, -mpreferred-stack-boundary=4),) + cc_stack_align := -mpreferred-stack-boundary=4 +else ifneq ($(call cc-option, -mstack-alignment=16),) + cc_stack_align := -mstack-alignment=16 +endif + +dsc_ccflags := -mhard-float -msse $(cc_stack_align) + +CFLAGS_rc_calc.o := $(dsc_ccflags) +CFLAGS_rc_calc_dpi.o := $(dsc_ccflags) +CFLAGS_codec_main_amd.o := $(dsc_ccflags) +CFLAGS_dc_dsc.o := $(dsc_ccflags) + +DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o + +AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DSC) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c new file mode 100644 index 000000000000..ef5f84a144c3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -0,0 +1,858 @@ +/* + * Copyright 2019 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. + * + * Author: AMD + */ + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#include "dc.h" +#include "core_types.h" +#include "dsc.h" +#include <drm/drm_dp_helper.h> + +/* This module's internal functions */ + +static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int *buff_block_size) +{ + + switch (dpcd_buff_block_size) { + case DP_DSC_RC_BUF_BLK_SIZE_1: + *buff_block_size = 1024; + break; + case DP_DSC_RC_BUF_BLK_SIZE_4: + *buff_block_size = 4 * 1024; + break; + case DP_DSC_RC_BUF_BLK_SIZE_16: + *buff_block_size = 16 * 1024; + break; + case DP_DSC_RC_BUF_BLK_SIZE_64: + *buff_block_size = 64 * 1024; + break; + default: { + dm_error("%s: DPCD DSC buffer size not recognized.\n", __func__); + return false; + } + } + + return true; +} + + +static bool dsc_line_buff_depth_from_dpcd(int dpcd_line_buff_bit_depth, int *line_buff_bit_depth) +{ + if (0 <= dpcd_line_buff_bit_depth && dpcd_line_buff_bit_depth <= 7) + *line_buff_bit_depth = dpcd_line_buff_bit_depth + 9; + else if (dpcd_line_buff_bit_depth == 8) + *line_buff_bit_depth = 8; + else { + dm_error("%s: DPCD DSC buffer depth not recognized.\n", __func__); + return false; + } + + return true; +} + + +static bool dsc_throughput_from_dpcd(int dpcd_throughput, int *throughput) +{ + switch (dpcd_throughput) { + case DP_DSC_THROUGHPUT_MODE_0_UPSUPPORTED: + *throughput = 0; + break; + case DP_DSC_THROUGHPUT_MODE_0_170: + *throughput = 170; + break; + case DP_DSC_THROUGHPUT_MODE_0_340: + *throughput = 340; + break; + case DP_DSC_THROUGHPUT_MODE_0_400: + *throughput = 400; + break; + case DP_DSC_THROUGHPUT_MODE_0_450: + *throughput = 450; + break; + case DP_DSC_THROUGHPUT_MODE_0_500: + *throughput = 500; + break; + case DP_DSC_THROUGHPUT_MODE_0_550: + *throughput = 550; + break; + case DP_DSC_THROUGHPUT_MODE_0_600: + *throughput = 600; + break; + case DP_DSC_THROUGHPUT_MODE_0_650: + *throughput = 650; + break; + case DP_DSC_THROUGHPUT_MODE_0_700: + *throughput = 700; + break; + case DP_DSC_THROUGHPUT_MODE_0_750: + *throughput = 750; + break; + case DP_DSC_THROUGHPUT_MODE_0_800: + *throughput = 800; + break; + case DP_DSC_THROUGHPUT_MODE_0_850: + *throughput = 850; + break; + case DP_DSC_THROUGHPUT_MODE_0_900: + *throughput = 900; + break; + case DP_DSC_THROUGHPUT_MODE_0_950: + *throughput = 950; + break; + case DP_DSC_THROUGHPUT_MODE_0_1000: + *throughput = 1000; + break; + default: { + dm_error("%s: DPCD DSC throughput mode not recognized.\n", __func__); + return false; + } + } + + return true; +} + + +static bool dsc_bpp_increment_div_from_dpcd(int bpp_increment_dpcd, uint32_t *bpp_increment_div) +{ + + switch (bpp_increment_dpcd) { + case 0: + *bpp_increment_div = 16; + break; + case 1: + *bpp_increment_div = 8; + break; + case 2: + *bpp_increment_div = 4; + break; + case 3: + *bpp_increment_div = 2; + break; + case 4: + *bpp_increment_div = 1; + break; + default: { + dm_error("%s: DPCD DSC bits-per-pixel increment not recognized.\n", __func__); + return false; + } + } + + return true; +} + +static void get_dsc_enc_caps( + const struct dc *dc, + struct dsc_enc_caps *dsc_enc_caps, + int pixel_clock_100Hz) +{ + // This is a static HW query, so we can use any DSC + struct display_stream_compressor *dsc = dc->res_pool->dscs[0]; + + memset(dsc_enc_caps, 0, sizeof(struct dsc_enc_caps)); + if (dsc) + dsc->funcs->dsc_get_enc_caps(dsc_enc_caps, pixel_clock_100Hz); +} + +/* Returns 'false' if no intersection was found for at least one capablity. + * It also implicitly validates some sink caps against invalid value of zero. + */ +static bool intersect_dsc_caps( + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + const struct dsc_enc_caps *dsc_enc_caps, + enum dc_pixel_encoding pixel_encoding, + struct dsc_enc_caps *dsc_common_caps) +{ + int32_t max_slices; + int32_t total_sink_throughput; + + memset(dsc_common_caps, 0, sizeof(struct dsc_enc_caps)); + + dsc_common_caps->dsc_version = min(dsc_sink_caps->dsc_version, dsc_enc_caps->dsc_version); + if (!dsc_common_caps->dsc_version) + return false; + + dsc_common_caps->slice_caps.bits.NUM_SLICES_1 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_1 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_1; + dsc_common_caps->slice_caps.bits.NUM_SLICES_2 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_2 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_2; + dsc_common_caps->slice_caps.bits.NUM_SLICES_4 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_4 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_4; + dsc_common_caps->slice_caps.bits.NUM_SLICES_8 = dsc_sink_caps->slice_caps1.bits.NUM_SLICES_8 && dsc_enc_caps->slice_caps.bits.NUM_SLICES_8; + if (!dsc_common_caps->slice_caps.raw) + return false; + + dsc_common_caps->lb_bit_depth = min(dsc_sink_caps->lb_bit_depth, dsc_enc_caps->lb_bit_depth); + if (!dsc_common_caps->lb_bit_depth) + return false; + + dsc_common_caps->is_block_pred_supported = dsc_sink_caps->is_block_pred_supported && dsc_enc_caps->is_block_pred_supported; + + dsc_common_caps->color_formats.raw = dsc_sink_caps->color_formats.raw & dsc_enc_caps->color_formats.raw; + if (!dsc_common_caps->color_formats.raw) + return false; + + dsc_common_caps->color_depth.raw = dsc_sink_caps->color_depth.raw & dsc_enc_caps->color_depth.raw; + if (!dsc_common_caps->color_depth.raw) + return false; + + max_slices = 0; + if (dsc_common_caps->slice_caps.bits.NUM_SLICES_1) + max_slices = 1; + + if (dsc_common_caps->slice_caps.bits.NUM_SLICES_2) + max_slices = 2; + + if (dsc_common_caps->slice_caps.bits.NUM_SLICES_4) + max_slices = 4; + + total_sink_throughput = max_slices * dsc_sink_caps->throughput_mode_0_mps; + if (pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420) + total_sink_throughput = max_slices * dsc_sink_caps->throughput_mode_1_mps; + + dsc_common_caps->max_total_throughput_mps = min(total_sink_throughput, dsc_enc_caps->max_total_throughput_mps); + + dsc_common_caps->max_slice_width = min(dsc_sink_caps->max_slice_width, dsc_enc_caps->max_slice_width); + if (!dsc_common_caps->max_slice_width) + return false; + + dsc_common_caps->bpp_increment_div = min(dsc_sink_caps->bpp_increment_div, dsc_enc_caps->bpp_increment_div); + + // TODO DSC: Remove this workaround for N422 and 420 once it's fixed, or move it to get_dsc_encoder_caps() + if (pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420) + dsc_common_caps->bpp_increment_div = min(dsc_common_caps->bpp_increment_div, (uint32_t)8); + + return true; +} + +struct dc_dsc_policy { + bool use_min_slices_h; + int max_slices_h; // Maximum available if 0 + int num_slices_v; + int max_target_bpp; + int min_target_bpp; // Minimum target bits per pixel +}; + +static inline uint32_t dsc_div_by_10_round_up(uint32_t value) +{ + return (value + 9) / 10; +} + +static inline uint32_t calc_dsc_bpp_x16(uint32_t stream_bandwidth_kbps, uint32_t pix_clk_100hz, uint32_t bpp_increment_div) +{ + uint32_t dsc_target_bpp_x16; + float f_dsc_target_bpp; + float f_stream_bandwidth_100bps = stream_bandwidth_kbps * 10.0f; + uint32_t precision = bpp_increment_div; // bpp_increment_div is actually precision + + f_dsc_target_bpp = f_stream_bandwidth_100bps / pix_clk_100hz; + + // Round down to the nearest precision stop to bring it into DSC spec range + dsc_target_bpp_x16 = (uint32_t)(f_dsc_target_bpp * precision); + dsc_target_bpp_x16 = (dsc_target_bpp_x16 * 16) / precision; + + return dsc_target_bpp_x16; +} + +const struct dc_dsc_policy dsc_policy = { + .use_min_slices_h = true, // DSC Policy: Use minimum number of slices that fits the pixel clock + .max_slices_h = 0, // DSC Policy: Use max available slices (in our case 4 for or 8, depending on the mode) + /* DSC Policy: Number of vertical slices set to 2 for no particular reason. + * Seems small enough to not affect the quality too much, while still providing some error + * propagation control (which may also help debugging). + */ + .num_slices_v = 16, + .max_target_bpp = 16, + .min_target_bpp = 8, +}; + + +/* Get DSC bandwidth range based on [min_bpp, max_bpp] target bitrate range, and timing's pixel clock + * and uncompressed bandwidth. + */ +static void get_dsc_bandwidth_range( + const uint32_t min_bpp, + const uint32_t max_bpp, + const struct dsc_enc_caps *dsc_caps, + const struct dc_crtc_timing *timing, + struct dc_dsc_bw_range *range) +{ + /* native stream bandwidth */ + range->stream_kbps = dc_bandwidth_in_kbps_from_timing(timing); + + /* max dsc target bpp */ + range->max_kbps = dsc_div_by_10_round_up(max_bpp * timing->pix_clk_100hz); + range->max_target_bpp_x16 = max_bpp * 16; + if (range->max_kbps > range->stream_kbps) { + /* max dsc target bpp is capped to native bandwidth */ + range->max_kbps = range->stream_kbps; + range->max_target_bpp_x16 = calc_dsc_bpp_x16(range->stream_kbps, timing->pix_clk_100hz, dsc_caps->bpp_increment_div); + } + + /* min dsc target bpp */ + range->min_kbps = dsc_div_by_10_round_up(min_bpp * timing->pix_clk_100hz); + range->min_target_bpp_x16 = min_bpp * 16; + if (range->min_kbps > range->max_kbps) { + /* min dsc target bpp is capped to max dsc bandwidth*/ + range->min_kbps = range->max_kbps; + range->min_target_bpp_x16 = range->max_target_bpp_x16; + } +} + + +/* Decides if DSC should be used and calculates target bpp if it should, applying DSC policy. + * + * Returns: + * - 'true' if DSC was required by policy and was successfully applied + * - 'false' if DSC was not necessary (e.g. if uncompressed stream fits 'target_bandwidth_kbps'), + * or if it couldn't be applied based on DSC policy. + */ +static bool decide_dsc_target_bpp_x16( + const struct dc_dsc_policy *policy, + const struct dsc_enc_caps *dsc_common_caps, + const int target_bandwidth_kbps, + const struct dc_crtc_timing *timing, + int *target_bpp_x16) +{ + bool should_use_dsc = false; + struct dc_dsc_bw_range range; + + memset(&range, 0, sizeof(range)); + + get_dsc_bandwidth_range(policy->min_target_bpp, policy->max_target_bpp, + dsc_common_caps, timing, &range); + if (target_bandwidth_kbps >= range.stream_kbps) { + /* enough bandwidth without dsc */ + *target_bpp_x16 = 0; + should_use_dsc = false; + } else if (target_bandwidth_kbps >= range.max_kbps) { + /* use max target bpp allowed */ + *target_bpp_x16 = range.max_target_bpp_x16; + should_use_dsc = true; + } else if (target_bandwidth_kbps >= range.min_kbps) { + /* use target bpp that can take entire target bandwidth */ + *target_bpp_x16 = calc_dsc_bpp_x16(target_bandwidth_kbps, timing->pix_clk_100hz, dsc_common_caps->bpp_increment_div); + should_use_dsc = true; + } else { + /* not enough bandwidth to fulfill minimum requirement */ + *target_bpp_x16 = 0; + should_use_dsc = false; + } + + return should_use_dsc; +} + +#define MIN_AVAILABLE_SLICES_SIZE 4 + +static int get_available_dsc_slices(union dsc_enc_slice_caps slice_caps, int *available_slices) +{ + int idx = 0; + + memset(available_slices, -1, MIN_AVAILABLE_SLICES_SIZE); + + if (slice_caps.bits.NUM_SLICES_1) + available_slices[idx++] = 1; + + if (slice_caps.bits.NUM_SLICES_2) + available_slices[idx++] = 2; + + if (slice_caps.bits.NUM_SLICES_4) + available_slices[idx++] = 4; + + if (slice_caps.bits.NUM_SLICES_8) + available_slices[idx++] = 8; + + return idx; +} + + +static int get_max_dsc_slices(union dsc_enc_slice_caps slice_caps) +{ + int max_slices = 0; + int available_slices[MIN_AVAILABLE_SLICES_SIZE]; + int end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]); + + if (end_idx > 0) + max_slices = available_slices[end_idx - 1]; + + return max_slices; +} + + +// Increment sice number in available sice numbers stops if possible, or just increment if not +static int inc_num_slices(union dsc_enc_slice_caps slice_caps, int num_slices) +{ + // Get next bigger num slices available in common caps + int available_slices[MIN_AVAILABLE_SLICES_SIZE]; + int end_idx; + int i; + int new_num_slices = num_slices; + + end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]); + if (end_idx == 0) { + // No available slices found + new_num_slices++; + return new_num_slices; + } + + // Numbers of slices found - get the next bigger number + for (i = 0; i < end_idx; i++) { + if (new_num_slices < available_slices[i]) { + new_num_slices = available_slices[i]; + break; + } + } + + if (new_num_slices == num_slices) // No biger number of slices found + new_num_slices++; + + return new_num_slices; +} + + +// Decrement sice number in available sice numbers stops if possible, or just decrement if not. Stop at zero. +static int dec_num_slices(union dsc_enc_slice_caps slice_caps, int num_slices) +{ + // Get next bigger num slices available in common caps + int available_slices[MIN_AVAILABLE_SLICES_SIZE]; + int end_idx; + int i; + int new_num_slices = num_slices; + + end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]); + if (end_idx == 0 && new_num_slices > 0) { + // No numbers of slices found + new_num_slices++; + return new_num_slices; + } + + // Numbers of slices found - get the next smaller number + for (i = end_idx - 1; i >= 0; i--) { + if (new_num_slices > available_slices[i]) { + new_num_slices = available_slices[i]; + break; + } + } + + if (new_num_slices == num_slices) { + // No smaller number of slices found + new_num_slices--; + if (new_num_slices < 0) + new_num_slices = 0; + } + + return new_num_slices; +} + + +// Choose next bigger number of slices if the requested number of slices is not available +static int fit_num_slices_up(union dsc_enc_slice_caps slice_caps, int num_slices) +{ + // Get next bigger num slices available in common caps + int available_slices[MIN_AVAILABLE_SLICES_SIZE]; + int end_idx; + int i; + int new_num_slices = num_slices; + + end_idx = get_available_dsc_slices(slice_caps, &available_slices[0]); + if (end_idx == 0) { + // No available slices found + new_num_slices++; + return new_num_slices; + } + + // Numbers of slices found - get the equal or next bigger number + for (i = 0; i < end_idx; i++) { + if (new_num_slices <= available_slices[i]) { + new_num_slices = available_slices[i]; + break; + } + } + + return new_num_slices; +} + + +/* Attempts to set DSC configuration for the stream, applying DSC policy. + * Returns 'true' if successful or 'false' if not. + * + * Parameters: + * + * dsc_sink_caps - DSC sink decoder capabilities (from DPCD) + * + * dsc_enc_caps - DSC encoder capabilities + * + * target_bandwidth_kbps - Target bandwidth to fit the stream into. + * If 0, do not calculate target bpp. + * + * timing - The stream timing to fit into 'target_bandwidth_kbps' or apply + * maximum compression to, if 'target_badwidth == 0' + * + * dsc_cfg - DSC configuration to use if it was possible to come up with + * one for the given inputs. + * The target bitrate after DSC can be calculated by multiplying + * dsc_cfg.bits_per_pixel (in U6.4 format) by pixel rate, e.g. + * + * dsc_stream_bitrate_kbps = (int)ceil(timing->pix_clk_khz * dsc_cfg.bits_per_pixel / 16.0); + */ +static bool setup_dsc_config( + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + const struct dsc_enc_caps *dsc_enc_caps, + int target_bandwidth_kbps, + const struct dc_crtc_timing *timing, + struct dc_dsc_config *dsc_cfg) +{ + struct dsc_enc_caps dsc_common_caps; + int max_slices_h; + int min_slices_h; + int num_slices_h; + int pic_width; + int slice_width; + int target_bpp; + int sink_per_slice_throughput_mps; + int branch_max_throughput_mps = 0; + bool is_dsc_possible = false; + int num_slices_v; + int pic_height; + + memset(dsc_cfg, 0, sizeof(struct dc_dsc_config)); + + pic_width = timing->h_addressable + timing->h_border_left + timing->h_border_right; + pic_height = timing->v_addressable + timing->v_border_top + timing->v_border_bottom; + + if (!dsc_sink_caps->is_dsc_supported) + goto done; + + if (dsc_sink_caps->branch_max_line_width && dsc_sink_caps->branch_max_line_width < pic_width) + goto done; + + // Intersect decoder with encoder DSC caps and validate DSC settings + is_dsc_possible = intersect_dsc_caps(dsc_sink_caps, dsc_enc_caps, timing->pixel_encoding, &dsc_common_caps); + if (!is_dsc_possible) + goto done; + + if (target_bandwidth_kbps > 0) { + is_dsc_possible = decide_dsc_target_bpp_x16(&dsc_policy, &dsc_common_caps, target_bandwidth_kbps, timing, &target_bpp); + dsc_cfg->bits_per_pixel = target_bpp; + } + if (!is_dsc_possible) + goto done; + + sink_per_slice_throughput_mps = 0; + + // Validate available DSC settings against the mode timing + + // Validate color format (and pick up the throughput values) + dsc_cfg->ycbcr422_simple = false; + switch (timing->pixel_encoding) { + case PIXEL_ENCODING_RGB: + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.RGB; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_0_mps; + branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_0_mps; + break; + case PIXEL_ENCODING_YCBCR444: + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_444; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_0_mps; + branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_0_mps; + break; + case PIXEL_ENCODING_YCBCR422: + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_422; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_1_mps; + branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_1_mps; + if (!is_dsc_possible) { + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_SIMPLE_422; + dsc_cfg->ycbcr422_simple = is_dsc_possible; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_0_mps; + } + break; + case PIXEL_ENCODING_YCBCR420: + is_dsc_possible = (bool)dsc_common_caps.color_formats.bits.YCBCR_NATIVE_420; + sink_per_slice_throughput_mps = dsc_sink_caps->throughput_mode_1_mps; + branch_max_throughput_mps = dsc_sink_caps->branch_overall_throughput_1_mps; + break; + default: + is_dsc_possible = false; + } + + // Validate branch's maximum throughput + if (branch_max_throughput_mps && dsc_div_by_10_round_up(timing->pix_clk_100hz) > branch_max_throughput_mps * 1000) + is_dsc_possible = false; + + if (!is_dsc_possible) + goto done; + + // Color depth + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_8_BPC; + break; + case COLOR_DEPTH_101010: + is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_10_BPC; + break; + case COLOR_DEPTH_121212: + is_dsc_possible = (bool)dsc_common_caps.color_depth.bits.COLOR_DEPTH_12_BPC; + break; + default: + is_dsc_possible = false; + } + + if (!is_dsc_possible) + goto done; + + // DSC slicing + max_slices_h = get_max_dsc_slices(dsc_common_caps.slice_caps); + + while (max_slices_h > 0) { + if (pic_width % max_slices_h == 0) + break; + + max_slices_h = dec_num_slices(dsc_common_caps.slice_caps, max_slices_h); + } + + is_dsc_possible = (dsc_common_caps.max_slice_width > 0); + if (!is_dsc_possible) + goto done; + + min_slices_h = pic_width / dsc_common_caps.max_slice_width; + if (pic_width % dsc_common_caps.max_slice_width) + min_slices_h++; + + min_slices_h = fit_num_slices_up(dsc_common_caps.slice_caps, min_slices_h); + + while (min_slices_h <= max_slices_h) { + int pix_clk_per_slice_khz = dsc_div_by_10_round_up(timing->pix_clk_100hz) / min_slices_h; + if (pix_clk_per_slice_khz <= sink_per_slice_throughput_mps * 1000) + break; + + min_slices_h = inc_num_slices(dsc_common_caps.slice_caps, min_slices_h); + } + + if (pic_width % min_slices_h != 0) + min_slices_h = 0; // DSC TODO: Maybe try increasing the number of slices first? + + is_dsc_possible = (min_slices_h <= max_slices_h); + if (!is_dsc_possible) + goto done; + + if (dsc_policy.use_min_slices_h) { + if (min_slices_h > 0) + num_slices_h = min_slices_h; + else if (max_slices_h > 0) { // Fall back to max slices if min slices is not working out + if (dsc_policy.max_slices_h) + num_slices_h = min(dsc_policy.max_slices_h, max_slices_h); + else + num_slices_h = max_slices_h; + } else + is_dsc_possible = false; + } else { + if (max_slices_h > 0) { + if (dsc_policy.max_slices_h) + num_slices_h = min(dsc_policy.max_slices_h, max_slices_h); + else + num_slices_h = max_slices_h; + } else if (min_slices_h > 0) // Fall back to min slices if max slices is not possible + num_slices_h = min_slices_h; + else + is_dsc_possible = false; + } + + if (!is_dsc_possible) + goto done; + + dsc_cfg->num_slices_h = num_slices_h; + slice_width = pic_width / num_slices_h; + + // Vertical number of slices: start from policy and pick the first one that height is divisible by. + // For 4:2:0 make sure the slice height is divisible by 2 as well. + num_slices_v = dsc_policy.num_slices_v; + if (num_slices_v < 1) + num_slices_v = 1; + + while (num_slices_v >= 1) { + if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) { + int slice_height = pic_height / num_slices_v; + if (pic_height % num_slices_v == 0 && slice_height % 2 == 0) + break; + } else if (pic_height % num_slices_v == 0) + break; + + num_slices_v--; + } + + dsc_cfg->num_slices_v = num_slices_v; + + is_dsc_possible = slice_width <= dsc_common_caps.max_slice_width; + if (!is_dsc_possible) + goto done; + + // Final decission: can we do DSC or not? + if (is_dsc_possible) { + // Fill out the rest of DSC settings + dsc_cfg->block_pred_enable = dsc_common_caps.is_block_pred_supported; + dsc_cfg->linebuf_depth = dsc_common_caps.lb_bit_depth; + dsc_cfg->version_minor = (dsc_common_caps.dsc_version & 0xf0) >> 4; + } + +done: + if (!is_dsc_possible) + memset(dsc_cfg, 0, sizeof(struct dc_dsc_config)); + + return is_dsc_possible; +} + +bool dc_dsc_parse_dsc_dpcd(const uint8_t *dpcd_dsc_basic_data, const uint8_t *dpcd_dsc_ext_data, struct dsc_dec_dpcd_caps *dsc_sink_caps) +{ + if (!dpcd_dsc_basic_data) + return false; + + dsc_sink_caps->is_dsc_supported = (dpcd_dsc_basic_data[DP_DSC_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_DECOMPRESSION_IS_SUPPORTED) != 0; + if (!dsc_sink_caps->is_dsc_supported) + return false; + + dsc_sink_caps->dsc_version = dpcd_dsc_basic_data[DP_DSC_REV - DP_DSC_SUPPORT]; + + { + int buff_block_size; + int buff_size; + + if (!dsc_buff_block_size_from_dpcd(dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT], &buff_block_size)) + return false; + + buff_size = dpcd_dsc_basic_data[DP_DSC_RC_BUF_SIZE - DP_DSC_SUPPORT] + 1; + dsc_sink_caps->rc_buffer_size = buff_size * buff_block_size; + } + + dsc_sink_caps->slice_caps1.raw = dpcd_dsc_basic_data[DP_DSC_SLICE_CAP_1 - DP_DSC_SUPPORT]; + if (!dsc_line_buff_depth_from_dpcd(dpcd_dsc_basic_data[DP_DSC_LINE_BUF_BIT_DEPTH - DP_DSC_SUPPORT], &dsc_sink_caps->lb_bit_depth)) + return false; + + dsc_sink_caps->is_block_pred_supported = + (dpcd_dsc_basic_data[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT] & DP_DSC_BLK_PREDICTION_IS_SUPPORTED) != 0; + + dsc_sink_caps->edp_max_bits_per_pixel = + dpcd_dsc_basic_data[DP_DSC_MAX_BITS_PER_PIXEL_LOW - DP_DSC_SUPPORT] | + dpcd_dsc_basic_data[DP_DSC_MAX_BITS_PER_PIXEL_HI - DP_DSC_SUPPORT] << 8; + + dsc_sink_caps->color_formats.raw = dpcd_dsc_basic_data[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT]; + dsc_sink_caps->color_depth.raw = dpcd_dsc_basic_data[DP_DSC_DEC_COLOR_DEPTH_CAP - DP_DSC_SUPPORT]; + + { + int dpcd_throughput = dpcd_dsc_basic_data[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT]; + + if (!dsc_throughput_from_dpcd(dpcd_throughput & DP_DSC_THROUGHPUT_MODE_0_MASK, &dsc_sink_caps->throughput_mode_0_mps)) + return false; + + dpcd_throughput = (dpcd_throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> DP_DSC_THROUGHPUT_MODE_1_SHIFT; + if (!dsc_throughput_from_dpcd(dpcd_throughput, &dsc_sink_caps->throughput_mode_1_mps)) + return false; + } + + dsc_sink_caps->max_slice_width = dpcd_dsc_basic_data[DP_DSC_MAX_SLICE_WIDTH - DP_DSC_SUPPORT] * 320; + dsc_sink_caps->slice_caps2.raw = dpcd_dsc_basic_data[DP_DSC_SLICE_CAP_2 - DP_DSC_SUPPORT]; + + if (!dsc_bpp_increment_div_from_dpcd(dpcd_dsc_basic_data[DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT], &dsc_sink_caps->bpp_increment_div)) + return false; + + /* Extended caps */ + if (dpcd_dsc_ext_data == NULL) { // Extended DPCD DSC data can be null, e.g. because it doesn't apply to SST + dsc_sink_caps->branch_overall_throughput_0_mps = 0; + dsc_sink_caps->branch_overall_throughput_1_mps = 0; + dsc_sink_caps->branch_max_line_width = 0; + return true; + } + + dsc_sink_caps->branch_overall_throughput_0_mps = dpcd_dsc_ext_data[DP_DSC_BRANCH_OVERALL_THROUGHPUT_0 - DP_DSC_BRANCH_OVERALL_THROUGHPUT_0]; + if (dsc_sink_caps->branch_overall_throughput_0_mps == 0) + dsc_sink_caps->branch_overall_throughput_0_mps = 0; + else if (dsc_sink_caps->branch_overall_throughput_0_mps == 1) + dsc_sink_caps->branch_overall_throughput_0_mps = 680; + else { + dsc_sink_caps->branch_overall_throughput_0_mps *= 50; + dsc_sink_caps->branch_overall_throughput_0_mps += 600; + } + + dsc_sink_caps->branch_overall_throughput_1_mps = dpcd_dsc_ext_data[DP_DSC_BRANCH_OVERALL_THROUGHPUT_1 - DP_DSC_BRANCH_OVERALL_THROUGHPUT_0]; + if (dsc_sink_caps->branch_overall_throughput_1_mps == 0) + dsc_sink_caps->branch_overall_throughput_1_mps = 0; + else if (dsc_sink_caps->branch_overall_throughput_1_mps == 1) + dsc_sink_caps->branch_overall_throughput_1_mps = 680; + else { + dsc_sink_caps->branch_overall_throughput_1_mps *= 50; + dsc_sink_caps->branch_overall_throughput_1_mps += 600; + } + + dsc_sink_caps->branch_max_line_width = dpcd_dsc_ext_data[DP_DSC_BRANCH_MAX_LINE_WIDTH - DP_DSC_BRANCH_OVERALL_THROUGHPUT_0] * 320; + ASSERT(dsc_sink_caps->branch_max_line_width == 0 || dsc_sink_caps->branch_max_line_width >= 5120); + + return true; +} + + +/* If DSC is possbile, get DSC bandwidth range based on [min_bpp, max_bpp] target bitrate range and + * timing's pixel clock and uncompressed bandwidth. + * If DSC is not possible, leave '*range' untouched. + */ +bool dc_dsc_compute_bandwidth_range( + const struct dc *dc, + const uint32_t min_bpp, + const uint32_t max_bpp, + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + const struct dc_crtc_timing *timing, + struct dc_dsc_bw_range *range) +{ + bool is_dsc_possible = false; + struct dsc_enc_caps dsc_enc_caps; + struct dsc_enc_caps dsc_common_caps; + struct dc_dsc_config config; + + get_dsc_enc_caps(dc, &dsc_enc_caps, timing->pix_clk_100hz); + + is_dsc_possible = intersect_dsc_caps(dsc_sink_caps, &dsc_enc_caps, + timing->pixel_encoding, &dsc_common_caps); + + if (is_dsc_possible) + is_dsc_possible = setup_dsc_config(dsc_sink_caps, + &dsc_enc_caps, + 0, + timing, &config); + + if (is_dsc_possible) + get_dsc_bandwidth_range(min_bpp, max_bpp, &dsc_common_caps, timing, range); + + return is_dsc_possible; +} + +bool dc_dsc_compute_config( + const struct dc *dc, + const struct dsc_dec_dpcd_caps *dsc_sink_caps, + uint32_t target_bandwidth_kbps, + const struct dc_crtc_timing *timing, + struct dc_dsc_config *dsc_cfg) +{ + bool is_dsc_possible = false; + struct dsc_enc_caps dsc_enc_caps; + + get_dsc_enc_caps(dc, &dsc_enc_caps, timing->pix_clk_100hz); + is_dsc_possible = setup_dsc_config(dsc_sink_caps, + &dsc_enc_caps, + target_bandwidth_kbps, + timing, dsc_cfg); + return is_dsc_possible; +} +#endif /* CONFIG_DRM_AMD_DC_DSC_SUPPORT */ diff --git a/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c b/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c new file mode 100644 index 000000000000..67089765780b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2018 Intel Corp + * + * Author: + * Manasi Navare <manasi.d.navare@intel.com> + */ + +/* DC versions of linux includes */ +#include <include/drm_dsc_dc.h> + +#define EXPORT_SYMBOL(symbol) /* nothing */ +#define BUILD_BUG_ON(cond) /* nothing */ +#define DIV_ROUND_UP(a, b) (((b) + (a) - 1) / (b)) +#define ERANGE -1 +#define DRM_DEBUG_KMS(msg) /* nothing */ +#define cpu_to_be16(__x) little_to_big(__x) + +static unsigned short little_to_big(int data) +{ + /* Swap lower and upper byte. DMCU uses big endian format. */ + return (0xff & (data >> 8)) + ((data & 0xff) << 8); +} + +/* + * Everything below this comment was copied directly from drm_dsc.c. + * Only the functions needed in DC are included. + * Please keep this file synced with upstream. + */ + +/** + * DOC: dsc helpers + * + * These functions contain some common logic and helpers to deal with VESA + * Display Stream Compression standard required for DSC on Display Port/eDP or + * MIPI display interfaces. + */ + +/** + * drm_dsc_pps_payload_pack() - Populates the DSC PPS + * + * @pps_payload: + * Bitwise struct for DSC Picture Parameter Set. This is defined + * by &struct drm_dsc_picture_parameter_set + * @dsc_cfg: + * DSC Configuration data filled by driver as defined by + * &struct drm_dsc_config + * + * DSC source device sends a picture parameter set (PPS) containing the + * information required by the sink to decode the compressed frame. Driver + * populates the DSC PPS struct using the DSC configuration parameters in + * the order expected by the DSC Display Sink device. For the DSC, the sink + * device expects the PPS payload in big endian format for fields + * that span more than 1 byte. + */ +void drm_dsc_pps_payload_pack(struct drm_dsc_picture_parameter_set *pps_payload, + const struct drm_dsc_config *dsc_cfg) +{ + int i; + + /* Protect against someone accidently changing struct size */ + BUILD_BUG_ON(sizeof(*pps_payload) != + DP_SDP_PPS_HEADER_PAYLOAD_BYTES_MINUS_1 + 1); + + memset(pps_payload, 0, sizeof(*pps_payload)); + + /* PPS 0 */ + pps_payload->dsc_version = + dsc_cfg->dsc_version_minor | + dsc_cfg->dsc_version_major << DSC_PPS_VERSION_MAJOR_SHIFT; + + /* PPS 1, 2 is 0 */ + + /* PPS 3 */ + pps_payload->pps_3 = + dsc_cfg->line_buf_depth | + dsc_cfg->bits_per_component << DSC_PPS_BPC_SHIFT; + + /* PPS 4 */ + pps_payload->pps_4 = + ((dsc_cfg->bits_per_pixel & DSC_PPS_BPP_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT) | + dsc_cfg->vbr_enable << DSC_PPS_VBR_EN_SHIFT | + dsc_cfg->simple_422 << DSC_PPS_SIMPLE422_SHIFT | + dsc_cfg->convert_rgb << DSC_PPS_CONVERT_RGB_SHIFT | + dsc_cfg->block_pred_enable << DSC_PPS_BLOCK_PRED_EN_SHIFT; + + /* PPS 5 */ + pps_payload->bits_per_pixel_low = + (dsc_cfg->bits_per_pixel & DSC_PPS_LSB_MASK); + + /* + * The DSC panel expects the PPS packet to have big endian format + * for data spanning 2 bytes. Use a macro cpu_to_be16() to convert + * to big endian format. If format is little endian, it will swap + * bytes to convert to Big endian else keep it unchanged. + */ + + /* PPS 6, 7 */ + pps_payload->pic_height = cpu_to_be16(dsc_cfg->pic_height); + + /* PPS 8, 9 */ + pps_payload->pic_width = cpu_to_be16(dsc_cfg->pic_width); + + /* PPS 10, 11 */ + pps_payload->slice_height = cpu_to_be16(dsc_cfg->slice_height); + + /* PPS 12, 13 */ + pps_payload->slice_width = cpu_to_be16(dsc_cfg->slice_width); + + /* PPS 14, 15 */ + pps_payload->chunk_size = cpu_to_be16(dsc_cfg->slice_chunk_size); + + /* PPS 16 */ + pps_payload->initial_xmit_delay_high = + ((dsc_cfg->initial_xmit_delay & + DSC_PPS_INIT_XMIT_DELAY_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT); + + /* PPS 17 */ + pps_payload->initial_xmit_delay_low = + (dsc_cfg->initial_xmit_delay & DSC_PPS_LSB_MASK); + + /* PPS 18, 19 */ + pps_payload->initial_dec_delay = + cpu_to_be16(dsc_cfg->initial_dec_delay); + + /* PPS 20 is 0 */ + + /* PPS 21 */ + pps_payload->initial_scale_value = + dsc_cfg->initial_scale_value; + + /* PPS 22, 23 */ + pps_payload->scale_increment_interval = + cpu_to_be16(dsc_cfg->scale_increment_interval); + + /* PPS 24 */ + pps_payload->scale_decrement_interval_high = + ((dsc_cfg->scale_decrement_interval & + DSC_PPS_SCALE_DEC_INT_HIGH_MASK) >> + DSC_PPS_MSB_SHIFT); + + /* PPS 25 */ + pps_payload->scale_decrement_interval_low = + (dsc_cfg->scale_decrement_interval & DSC_PPS_LSB_MASK); + + /* PPS 26[7:0], PPS 27[7:5] RESERVED */ + + /* PPS 27 */ + pps_payload->first_line_bpg_offset = + dsc_cfg->first_line_bpg_offset; + + /* PPS 28, 29 */ + pps_payload->nfl_bpg_offset = + cpu_to_be16(dsc_cfg->nfl_bpg_offset); + + /* PPS 30, 31 */ + pps_payload->slice_bpg_offset = + cpu_to_be16(dsc_cfg->slice_bpg_offset); + + /* PPS 32, 33 */ + pps_payload->initial_offset = + cpu_to_be16(dsc_cfg->initial_offset); + + /* PPS 34, 35 */ + pps_payload->final_offset = cpu_to_be16(dsc_cfg->final_offset); + + /* PPS 36 */ + pps_payload->flatness_min_qp = dsc_cfg->flatness_min_qp; + + /* PPS 37 */ + pps_payload->flatness_max_qp = dsc_cfg->flatness_max_qp; + + /* PPS 38, 39 */ + pps_payload->rc_model_size = + cpu_to_be16(DSC_RC_MODEL_SIZE_CONST); + + /* PPS 40 */ + pps_payload->rc_edge_factor = DSC_RC_EDGE_FACTOR_CONST; + + /* PPS 41 */ + pps_payload->rc_quant_incr_limit0 = + dsc_cfg->rc_quant_incr_limit0; + + /* PPS 42 */ + pps_payload->rc_quant_incr_limit1 = + dsc_cfg->rc_quant_incr_limit1; + + /* PPS 43 */ + pps_payload->rc_tgt_offset = DSC_RC_TGT_OFFSET_LO_CONST | + DSC_RC_TGT_OFFSET_HI_CONST << DSC_PPS_RC_TGT_OFFSET_HI_SHIFT; + + /* PPS 44 - 57 */ + for (i = 0; i < DSC_NUM_BUF_RANGES - 1; i++) + pps_payload->rc_buf_thresh[i] = + dsc_cfg->rc_buf_thresh[i]; + + /* PPS 58 - 87 */ + /* + * For DSC sink programming the RC Range parameter fields + * are as follows: Min_qp[15:11], max_qp[10:6], offset[5:0] + */ + for (i = 0; i < DSC_NUM_BUF_RANGES; i++) { + pps_payload->rc_range_parameters[i] = + ((dsc_cfg->rc_range_params[i].range_min_qp << + DSC_PPS_RC_RANGE_MINQP_SHIFT) | + (dsc_cfg->rc_range_params[i].range_max_qp << + DSC_PPS_RC_RANGE_MAXQP_SHIFT) | + (dsc_cfg->rc_range_params[i].range_bpg_offset)); + pps_payload->rc_range_parameters[i] = + cpu_to_be16(pps_payload->rc_range_parameters[i]); + } + + /* PPS 88 */ + pps_payload->native_422_420 = dsc_cfg->native_422 | + dsc_cfg->native_420 << DSC_PPS_NATIVE_420_SHIFT; + + /* PPS 89 */ + pps_payload->second_line_bpg_offset = + dsc_cfg->second_line_bpg_offset; + + /* PPS 90, 91 */ + pps_payload->nsl_bpg_offset = + cpu_to_be16(dsc_cfg->nsl_bpg_offset); + + /* PPS 92, 93 */ + pps_payload->second_line_offset_adj = + cpu_to_be16(dsc_cfg->second_line_offset_adj); + + /* PPS 94 - 127 are O */ +} +EXPORT_SYMBOL(drm_dsc_pps_payload_pack); + +/** + * drm_dsc_compute_rc_parameters() - Write rate control + * parameters to the dsc configuration defined in + * &struct drm_dsc_config in accordance with the DSC 1.2 + * specification. Some configuration fields must be present + * beforehand. + * + * @vdsc_cfg: + * DSC Configuration data partially filled by driver + */ +int drm_dsc_compute_rc_parameters(struct drm_dsc_config *vdsc_cfg) +{ + unsigned long groups_per_line = 0; + unsigned long groups_total = 0; + unsigned long num_extra_mux_bits = 0; + unsigned long slice_bits = 0; + unsigned long hrd_delay = 0; + unsigned long final_scale = 0; + unsigned long rbs_min = 0; + + if (vdsc_cfg->native_420 || vdsc_cfg->native_422) { + /* Number of groups used to code each line of a slice */ + groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width / 2, + DSC_RC_PIXELS_PER_GROUP); + + /* chunksize in Bytes */ + vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width / 2 * + vdsc_cfg->bits_per_pixel, + (8 * 16)); + } else { + /* Number of groups used to code each line of a slice */ + groups_per_line = DIV_ROUND_UP(vdsc_cfg->slice_width, + DSC_RC_PIXELS_PER_GROUP); + + /* chunksize in Bytes */ + vdsc_cfg->slice_chunk_size = DIV_ROUND_UP(vdsc_cfg->slice_width * + vdsc_cfg->bits_per_pixel, + (8 * 16)); + } + + if (vdsc_cfg->convert_rgb) + num_extra_mux_bits = 3 * (vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + - 2); + else if (vdsc_cfg->native_422) + num_extra_mux_bits = 4 * vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + + 3 * (4 * vdsc_cfg->bits_per_component) - 2; + else + num_extra_mux_bits = 3 * vdsc_cfg->mux_word_size + + (4 * vdsc_cfg->bits_per_component + 4) + + 2 * (4 * vdsc_cfg->bits_per_component) - 2; + /* Number of bits in one Slice */ + slice_bits = 8 * vdsc_cfg->slice_chunk_size * vdsc_cfg->slice_height; + + while ((num_extra_mux_bits > 0) && + ((slice_bits - num_extra_mux_bits) % vdsc_cfg->mux_word_size)) + num_extra_mux_bits--; + + if (groups_per_line < vdsc_cfg->initial_scale_value - 8) + vdsc_cfg->initial_scale_value = groups_per_line + 8; + + /* scale_decrement_interval calculation according to DSC spec 1.11 */ + if (vdsc_cfg->initial_scale_value > 8) + vdsc_cfg->scale_decrement_interval = groups_per_line / + (vdsc_cfg->initial_scale_value - 8); + else + vdsc_cfg->scale_decrement_interval = DSC_SCALE_DECREMENT_INTERVAL_MAX; + + vdsc_cfg->final_offset = vdsc_cfg->rc_model_size - + (vdsc_cfg->initial_xmit_delay * + vdsc_cfg->bits_per_pixel + 8) / 16 + num_extra_mux_bits; + + if (vdsc_cfg->final_offset >= vdsc_cfg->rc_model_size) { + DRM_DEBUG_KMS("FinalOfs < RcModelSze for this InitialXmitDelay\n"); + return -ERANGE; + } + + final_scale = (vdsc_cfg->rc_model_size * 8) / + (vdsc_cfg->rc_model_size - vdsc_cfg->final_offset); + if (vdsc_cfg->slice_height > 1) + /* + * NflBpgOffset is 16 bit value with 11 fractional bits + * hence we multiply by 2^11 for preserving the + * fractional part + */ + vdsc_cfg->nfl_bpg_offset = DIV_ROUND_UP((vdsc_cfg->first_line_bpg_offset << 11), + (vdsc_cfg->slice_height - 1)); + else + vdsc_cfg->nfl_bpg_offset = 0; + + /* 2^16 - 1 */ + if (vdsc_cfg->nfl_bpg_offset > 65535) { + DRM_DEBUG_KMS("NflBpgOffset is too large for this slice height\n"); + return -ERANGE; + } + + /* Number of groups used to code the entire slice */ + groups_total = groups_per_line * vdsc_cfg->slice_height; + + /* slice_bpg_offset is 16 bit value with 11 fractional bits */ + vdsc_cfg->slice_bpg_offset = DIV_ROUND_UP(((vdsc_cfg->rc_model_size - + vdsc_cfg->initial_offset + + num_extra_mux_bits) << 11), + groups_total); + + if (final_scale > 9) { + /* + * ScaleIncrementInterval = + * finaloffset/((NflBpgOffset + SliceBpgOffset)*8(finalscale - 1.125)) + * as (NflBpgOffset + SliceBpgOffset) has 11 bit fractional value, + * we need divide by 2^11 from pstDscCfg values + */ + vdsc_cfg->scale_increment_interval = + (vdsc_cfg->final_offset * (1 << 11)) / + ((vdsc_cfg->nfl_bpg_offset + + vdsc_cfg->slice_bpg_offset) * + (final_scale - 9)); + } else { + /* + * If finalScaleValue is less than or equal to 9, a value of 0 should + * be used to disable the scale increment at the end of the slice + */ + vdsc_cfg->scale_increment_interval = 0; + } + + if (vdsc_cfg->scale_increment_interval > 65535) { + DRM_DEBUG_KMS("ScaleIncrementInterval is large for slice height\n"); + return -ERANGE; + } + + /* + * DSC spec mentions that bits_per_pixel specifies the target + * bits/pixel (bpp) rate that is used by the encoder, + * in steps of 1/16 of a bit per pixel + */ + rbs_min = vdsc_cfg->rc_model_size - vdsc_cfg->initial_offset + + DIV_ROUND_UP(vdsc_cfg->initial_xmit_delay * + vdsc_cfg->bits_per_pixel, 16) + + groups_per_line * vdsc_cfg->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP((rbs_min * 16), vdsc_cfg->bits_per_pixel); + vdsc_cfg->rc_bits = (hrd_delay * vdsc_cfg->bits_per_pixel) / 16; + vdsc_cfg->initial_dec_delay = hrd_delay - vdsc_cfg->initial_xmit_delay; + + return 0; +} +EXPORT_SYMBOL(drm_dsc_compute_rc_parameters); diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h new file mode 100644 index 000000000000..020ad8f685ea --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h @@ -0,0 +1,54 @@ +#if defined(CONFIG_DRM_AMD_DC_DCN2_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. + * + * Authors: AMD + * + */ +#ifndef __DSCC_TYPES_H__ +#define __DSCC_TYPES_H__ + +#include <drm/drm_dsc.h> + +#ifndef NUM_BUF_RANGES +#define NUM_BUF_RANGES 15 +#endif + +struct dsc_pps_rc_range { + int range_min_qp; + int range_max_qp; + int range_bpg_offset; +}; + +struct dsc_parameters { + struct drm_dsc_config pps; + + /* Additional parameters for register programming */ + uint32_t bytes_per_pixel; /* In u3.28 format */ + uint32_t rc_buffer_model_size; +}; + +int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params); + +#endif + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h new file mode 100644 index 000000000000..f66d006eac5d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/qp_tables.h @@ -0,0 +1,706 @@ +#if defined(CONFIG_DRM_AMD_DC_DCN2_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. + * + * Authors: AMD + * + */ + + +const qp_table qp_table_422_10bpc_min = { + { 6, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} }, + { 6.5, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 8, 9, 9, 9, 12, 16} }, + { 7, { 0, 4, 5, 6, 6, 6, 6, 7, 7, 7, 9, 9, 9, 11, 15} }, + { 7.5, { 0, 2, 4, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11, 15} }, + { 8, { 0, 2, 3, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 11, 14} }, + { 8.5, { 0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 14} }, + { 9, { 0, 2, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 11, 13} }, + { 9.5, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 13} }, + { 10, { 0, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12} }, + {10.5, { 0, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 11, 12} }, + { 11, { 0, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11} }, + {11.5, { 0, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 10, 11} }, + { 12, { 0, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10} }, + {12.5, { 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} }, + { 13, { 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 6, 6, 8, 8, 9} }, + {13.5, { 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 6, 7, 8, 9} }, + { 14, { 0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 7, 8} }, + {14.5, { 0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8} }, + { 15, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6, 6, 6, 8} }, + {15.5, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 7} }, + { 16, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7} }, + {16.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6} }, + { 17, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 6} }, + {17.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} }, + { 18, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 5} }, + {18.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 5} }, + { 19, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 4} }, + {19.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 4} }, + { 20, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 3} } +}; + + +const qp_table qp_table_444_8bpc_max = { + { 6, { 4, 6, 8, 8, 9, 9, 9, 10, 11, 12, 12, 12, 12, 13, 15} }, + { 6.5, { 4, 6, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 12, 13, 15} }, + { 7, { 4, 5, 7, 7, 8, 8, 8, 9, 10, 11, 11, 12, 12, 13, 14} }, + { 7.5, { 4, 5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 11, 12, 13, 14} }, + { 8, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, + { 8.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, + { 9, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 13} }, + { 9.5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 13} }, + { 10, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} }, + {10.5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 10, 11, 12} }, + { 11, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11} }, + {11.5, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} }, + { 12, { 2, 3, 4, 5, 6, 6, 7, 8, 8, 9, 9, 9, 9, 10, 11} }, + {12.5, { 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} }, + { 13, { 1, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 10} }, + {13.5, { 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10} }, + { 14, { 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} }, + {14.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9} }, + { 15, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} }, + {15.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} }, + { 16, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8} }, + {16.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8} }, + { 17, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 8} }, + {17.5, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 8} }, + { 18, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7} }, + {18.5, { 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 7} }, + { 19, { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6} }, + {19.5, { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6} }, + { 20, { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 6} }, + {20.5, { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 6} }, + { 21, { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} }, + {21.5, { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} }, + { 22, { 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} }, + {22.5, { 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} }, + { 23, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4} }, + {23.5, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4} }, + { 24, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4} } +}; + + +const qp_table qp_table_420_12bpc_max = { + { 4, {11, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 21, 22} }, + { 4.5, {10, 11, 12, 13, 14, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, + { 5, { 9, 11, 12, 13, 14, 15, 15, 16, 17, 17, 18, 18, 19, 20, 21} }, + { 5.5, { 8, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 19, 20} }, + { 6, { 6, 9, 11, 12, 13, 14, 15, 16, 16, 17, 17, 17, 17, 18, 19} }, + { 6.5, { 6, 8, 10, 11, 11, 13, 14, 15, 15, 16, 16, 17, 17, 18, 19} }, + { 7, { 5, 7, 9, 10, 10, 12, 13, 14, 14, 15, 16, 16, 17, 17, 18} }, + { 7.5, { 5, 7, 8, 9, 9, 11, 12, 13, 14, 14, 15, 15, 16, 16, 17} }, + { 8, { 4, 6, 7, 8, 8, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17} }, + { 8.5, { 3, 6, 6, 7, 7, 10, 11, 12, 13, 13, 14, 14, 15, 15, 16} }, + { 9, { 3, 5, 6, 7, 7, 10, 11, 12, 12, 13, 13, 14, 14, 14, 15} }, + { 9.5, { 2, 5, 6, 6, 7, 9, 10, 11, 12, 12, 13, 13, 13, 14, 15} }, + { 10, { 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 15} }, + {10.5, { 2, 3, 5, 5, 6, 7, 8, 9, 11, 11, 12, 12, 12, 12, 14} }, + { 11, { 1, 3, 4, 5, 6, 6, 7, 9, 10, 11, 11, 11, 12, 12, 13} }, + {11.5, { 1, 2, 3, 4, 5, 6, 6, 8, 9, 10, 10, 11, 11, 11, 13} }, + { 12, { 1, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 10, 12} }, + {12.5, { 1, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 10, 11} }, + { 13, { 1, 1, 1, 2, 4, 4, 6, 6, 7, 8, 8, 9, 9, 9, 11} }, + {13.5, { 1, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 8, 9, 11} }, + { 14, { 1, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} }, + {14.5, { 0, 1, 1, 1, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} }, + { 15, { 0, 1, 1, 1, 1, 2, 3, 3, 5, 5, 5, 6, 6, 7, 9} }, + {15.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8} }, + { 16, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 7} }, + {16.5, { 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 7} }, + { 17, { 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 6} }, + {17.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6} }, + { 18, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 5} } +}; + + +const qp_table qp_table_444_10bpc_min = { + { 6, { 0, 4, 7, 7, 9, 9, 9, 9, 9, 10, 10, 10, 10, 12, 18} }, + { 6.5, { 0, 4, 6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 12, 18} }, + { 7, { 0, 4, 6, 6, 8, 8, 8, 8, 8, 9, 9, 10, 10, 12, 17} }, + { 7.5, { 0, 4, 6, 6, 7, 8, 8, 8, 8, 8, 9, 9, 10, 12, 17} }, + { 8, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 8, 9, 9, 9, 12, 16} }, + { 8.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 8, 9, 9, 9, 12, 16} }, + { 9, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, + { 9.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, + { 10, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 15} }, + {10.5, { 0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 15} }, + { 11, { 0, 3, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} }, + {11.5, { 0, 3, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} }, + { 12, { 0, 2, 4, 4, 6, 6, 7, 7, 7, 7, 9, 9, 9, 11, 14} }, + {12.5, { 0, 2, 4, 4, 6, 6, 7, 7, 7, 7, 8, 9, 9, 11, 14} }, + { 13, { 0, 2, 4, 4, 5, 6, 7, 7, 7, 7, 8, 9, 9, 11, 13} }, + {13.5, { 0, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9, 9, 11, 13} }, + { 14, { 0, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 11, 13} }, + {14.5, { 0, 2, 3, 4, 5, 5, 6, 6, 6, 7, 7, 8, 9, 11, 12} }, + { 15, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 11, 12} }, + {15.5, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 11, 12} }, + { 16, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 8, 10, 11} }, + {16.5, { 0, 1, 2, 3, 4, 5, 5, 6, 6, 6, 7, 8, 8, 10, 11} }, + { 17, { 0, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8, 9, 11} }, + {17.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 11} }, + { 18, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} }, + {18.5, { 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, 10} }, + { 19, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9} }, + {19.5, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9} }, + { 20, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 9} }, + {20.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 9} }, + { 21, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6, 6, 7, 9} }, + {21.5, { 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 6, 6, 7, 8} }, + { 22, { 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 8} }, + {22.5, { 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} }, + { 23, { 0, 0, 1, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 7} }, + {23.5, { 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 5, 5, 5, 5, 7} }, + { 24, { 0, 0, 0, 1, 1, 2, 3, 3, 3, 3, 4, 4, 4, 5, 7} }, + {24.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 7} }, + { 25, { 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} }, + {25.5, { 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} }, + { 26, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 5} }, + {26.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 5} }, + { 27, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} }, + {27.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} }, + { 28, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 4} }, + {28.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 4} }, + { 29, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3} }, + {29.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3} }, + { 30, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} } +}; + + +const qp_table qp_table_420_8bpc_max = { + { 4, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 13, 14} }, + { 4.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, + { 5, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 12, 13} }, + { 5.5, { 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12} }, + { 6, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} }, + { 6.5, { 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} }, + { 7, { 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10} }, + { 7.5, { 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9} }, + { 8, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} }, + { 8.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8} }, + { 9, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7} }, + { 9.5, { 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} }, + { 10, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6} }, + {10.5, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} }, + { 11, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5} }, + {11.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 5} }, + { 12, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4} } +}; + + +const qp_table qp_table_444_8bpc_min = { + { 6, { 0, 1, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 6, 9, 14} }, + { 6.5, { 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 9, 14} }, + { 7, { 0, 0, 2, 2, 4, 4, 4, 4, 4, 5, 5, 6, 6, 9, 13} }, + { 7.5, { 0, 0, 2, 2, 3, 4, 4, 4, 4, 4, 5, 5, 6, 9, 13} }, + { 8, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 4, 5, 5, 5, 8, 12} }, + { 8.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 4, 5, 5, 5, 8, 12} }, + { 9, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12} }, + { 9.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12} }, + { 10, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, + {10.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, + { 11, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} }, + {11.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} }, + { 12, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} }, + {12.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 4, 5, 5, 7, 10} }, + { 13, { 0, 0, 1, 1, 2, 3, 3, 3, 3, 3, 4, 5, 5, 7, 9} }, + {13.5, { 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} }, + { 14, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 5, 5, 7, 9} }, + {14.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 7, 8} }, + { 15, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} }, + {15.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} }, + { 16, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} }, + {16.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} }, + { 17, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} }, + {17.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} }, + { 18, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} }, + {18.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} }, + { 19, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5} }, + {19.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5} }, + { 20, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5} }, + {20.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 5} }, + { 21, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} }, + {21.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} }, + { 22, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} }, + {22.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} }, + { 23, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} }, + {23.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} }, + { 24, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3} } +}; + + +const qp_table qp_table_444_12bpc_min = { + { 6, { 0, 5, 11, 11, 13, 13, 13, 13, 13, 14, 14, 14, 14, 17, 22} }, + { 6.5, { 0, 5, 10, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 17, 22} }, + { 7, { 0, 5, 10, 10, 12, 12, 12, 12, 12, 13, 13, 14, 14, 17, 21} }, + { 7.5, { 0, 5, 9, 10, 11, 12, 12, 12, 12, 12, 13, 13, 14, 17, 21} }, + { 8, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 12, 13, 13, 13, 16, 20} }, + { 8.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 12, 13, 13, 13, 16, 20} }, + { 9, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, + { 9.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, + { 10, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, + {10.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, + { 11, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + {11.5, { 0, 4, 8, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + { 12, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + {12.5, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + { 13, { 0, 4, 7, 8, 9, 11, 11, 11, 11, 11, 13, 13, 13, 15, 17} }, + {13.5, { 0, 3, 6, 7, 9, 10, 10, 11, 11, 11, 12, 13, 13, 15, 17} }, + { 14, { 0, 3, 5, 6, 9, 9, 9, 10, 11, 11, 12, 13, 13, 15, 17} }, + {14.5, { 0, 2, 5, 6, 8, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + { 15, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + {15.5, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + { 16, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 11, 12, 12, 14, 15} }, + {16.5, { 0, 2, 3, 5, 7, 8, 9, 10, 11, 11, 11, 12, 12, 14, 15} }, + { 17, { 0, 2, 3, 5, 5, 6, 9, 9, 10, 10, 11, 11, 12, 13, 15} }, + {17.5, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 15} }, + { 18, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 14} }, + {18.5, { 0, 2, 3, 5, 5, 6, 8, 9, 10, 10, 11, 11, 12, 13, 14} }, + { 19, { 0, 1, 2, 4, 5, 5, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + {19.5, { 0, 1, 2, 4, 5, 5, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + { 20, { 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 9, 10, 10, 11, 13} }, + {20.5, { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11, 13} }, + { 21, { 0, 1, 2, 3, 4, 5, 5, 7, 7, 8, 9, 10, 10, 11, 13} }, + {21.5, { 0, 1, 2, 3, 3, 4, 5, 7, 7, 8, 9, 10, 10, 11, 12} }, + { 22, { 0, 0, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 12} }, + {22.5, { 0, 0, 1, 3, 3, 4, 5, 6, 7, 8, 9, 9, 9, 10, 11} }, + { 23, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 7, 9, 9, 9, 9, 11} }, + {23.5, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 7, 9, 9, 9, 9, 11} }, + { 24, { 0, 0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 8, 9, 11} }, + {24.5, { 0, 0, 1, 2, 3, 4, 4, 6, 6, 7, 8, 8, 8, 9, 11} }, + { 25, { 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 8, 10} }, + {25.5, { 0, 0, 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 8, 10} }, + { 26, { 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 7, 7, 9} }, + {26.5, { 0, 0, 1, 2, 2, 3, 4, 5, 5, 5, 7, 7, 7, 7, 9} }, + { 27, { 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} }, + {27.5, { 0, 0, 1, 1, 2, 2, 4, 4, 4, 5, 6, 7, 7, 7, 9} }, + { 28, { 0, 0, 0, 1, 1, 2, 3, 4, 4, 4, 6, 6, 6, 7, 9} }, + {28.5, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 8} }, + { 29, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8} }, + {29.5, { 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7} }, + { 30, { 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 5, 5, 5, 5, 7} }, + {30.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 7} }, + { 31, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 4, 5, 7} }, + {31.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} }, + { 32, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6} }, + {32.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 6} }, + { 33, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} }, + {33.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 5} }, + { 34, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 5} }, + {34.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 5} }, + { 35, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} }, + {35.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 4} }, + { 36, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3} } +}; + + +const qp_table qp_table_420_12bpc_min = { + { 4, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21} }, + { 4.5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, + { 5, { 0, 4, 8, 9, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 20} }, + { 5.5, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, + { 6, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + { 6.5, { 0, 4, 6, 8, 9, 10, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + { 7, { 0, 3, 5, 7, 9, 10, 10, 11, 11, 11, 13, 13, 13, 15, 17} }, + { 7.5, { 0, 3, 5, 7, 8, 9, 10, 10, 11, 11, 12, 13, 13, 15, 16} }, + { 8, { 0, 2, 4, 6, 7, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + { 8.5, { 0, 2, 4, 6, 6, 9, 9, 10, 11, 11, 12, 12, 13, 14, 15} }, + { 9, { 0, 2, 4, 6, 6, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14} }, + { 9.5, { 0, 2, 4, 5, 6, 8, 8, 9, 10, 10, 11, 12, 12, 13, 14} }, + { 10, { 0, 2, 3, 5, 6, 7, 8, 8, 9, 10, 10, 12, 12, 12, 14} }, + {10.5, { 0, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 11, 11, 13} }, + { 11, { 0, 2, 3, 4, 5, 5, 6, 8, 8, 9, 9, 10, 11, 11, 12} }, + {11.5, { 0, 1, 2, 3, 4, 5, 5, 7, 8, 8, 9, 10, 10, 10, 12} }, + { 12, { 0, 0, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 11} }, + {12.5, { 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 10} }, + { 13, { 0, 0, 0, 1, 3, 3, 5, 5, 6, 7, 7, 8, 8, 8, 10} }, + {13.5, { 0, 0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 7, 8, 10} }, + { 14, { 0, 0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 7, 9} }, + {14.5, { 0, 0, 0, 0, 1, 2, 3, 3, 4, 4, 5, 6, 6, 6, 8} }, + { 15, { 0, 0, 0, 0, 0, 1, 2, 2, 4, 4, 4, 5, 5, 6, 8} }, + {15.5, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7} }, + { 16, { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 6} }, + {16.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6} }, + { 17, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 5} }, + {17.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 5} }, + { 18, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 4} } +}; + + +const qp_table qp_table_422_12bpc_min = { + { 6, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} }, + { 6.5, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 16, 20} }, + { 7, { 0, 4, 9, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, + { 7.5, { 0, 4, 8, 10, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 19} }, + { 8, { 0, 4, 7, 8, 10, 11, 11, 11, 11, 11, 13, 13, 13, 15, 18} }, + { 8.5, { 0, 3, 6, 8, 9, 10, 10, 11, 11, 11, 12, 13, 13, 15, 18} }, + { 9, { 0, 3, 5, 8, 9, 10, 10, 10, 11, 11, 12, 13, 13, 15, 17} }, + { 9.5, { 0, 3, 5, 7, 8, 9, 10, 10, 11, 11, 12, 13, 13, 15, 17} }, + { 10, { 0, 2, 4, 6, 7, 9, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + {10.5, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 13, 13, 15, 16} }, + { 11, { 0, 2, 4, 6, 7, 8, 9, 10, 11, 11, 12, 12, 13, 14, 15} }, + {11.5, { 0, 2, 4, 6, 7, 7, 9, 9, 10, 11, 11, 12, 12, 14, 15} }, + { 12, { 0, 2, 4, 6, 6, 6, 8, 8, 9, 9, 11, 11, 12, 13, 14} }, + {12.5, { 0, 1, 4, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 13, 14} }, + { 13, { 0, 1, 3, 4, 5, 5, 7, 8, 8, 9, 10, 10, 11, 12, 13} }, + {13.5, { 0, 1, 3, 3, 4, 5, 7, 7, 8, 8, 10, 10, 10, 12, 13} }, + { 14, { 0, 0, 2, 3, 4, 5, 6, 6, 7, 7, 9, 10, 10, 11, 12} }, + {14.5, { 0, 0, 1, 3, 4, 4, 6, 6, 6, 7, 9, 9, 9, 11, 12} }, + { 15, { 0, 0, 1, 3, 3, 4, 5, 6, 6, 6, 8, 9, 9, 10, 12} }, + {15.5, { 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 8, 8, 8, 10, 11} }, + { 16, { 0, 0, 1, 2, 3, 4, 5, 5, 6, 6, 8, 8, 8, 9, 11} }, + {16.5, { 0, 0, 0, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7, 9, 10} }, + { 17, { 0, 0, 0, 1, 2, 2, 4, 4, 4, 5, 6, 6, 6, 8, 10} }, + {17.5, { 0, 0, 0, 1, 2, 2, 3, 4, 4, 4, 5, 6, 6, 8, 9} }, + { 18, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 9} }, + {18.5, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 3, 5, 5, 5, 7, 9} }, + { 19, { 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 8} }, + {19.5, { 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 6, 8} }, + { 20, { 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 7} }, + {20.5, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 7} }, + { 21, { 0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 6} }, + {21.5, { 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 6} }, + { 22, { 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 6} }, + {22.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 5} }, + { 23, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 5} }, + {23.5, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 4} }, + { 24, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 4} } +}; + + +const qp_table qp_table_422_12bpc_max = { + { 6, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, + { 6.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, + { 7, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} }, + { 7.5, { 9, 10, 12, 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 20} }, + { 8, { 6, 9, 10, 12, 14, 15, 15, 16, 16, 17, 17, 17, 17, 18, 19} }, + { 8.5, { 6, 8, 9, 11, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 19} }, + { 9, { 5, 7, 8, 10, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 18} }, + { 9.5, { 5, 7, 7, 9, 10, 12, 12, 13, 14, 14, 15, 15, 16, 17, 18} }, + { 10, { 4, 6, 6, 8, 9, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} }, + {10.5, { 4, 6, 6, 8, 9, 10, 11, 12, 13, 13, 14, 15, 15, 16, 17} }, + { 11, { 4, 5, 6, 8, 9, 10, 11, 12, 13, 13, 14, 14, 15, 15, 16} }, + {11.5, { 3, 5, 6, 8, 9, 9, 11, 11, 12, 13, 13, 14, 14, 15, 16} }, + { 12, { 3, 5, 6, 8, 8, 8, 10, 10, 11, 11, 13, 13, 14, 14, 15} }, + {12.5, { 3, 4, 6, 7, 8, 8, 9, 10, 10, 11, 12, 13, 13, 14, 15} }, + { 13, { 2, 4, 5, 6, 7, 7, 9, 10, 10, 11, 12, 12, 13, 13, 14} }, + {13.5, { 2, 4, 5, 5, 6, 7, 9, 9, 10, 10, 12, 12, 12, 13, 14} }, + { 14, { 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 11, 12, 12, 12, 13} }, + {14.5, { 2, 3, 3, 5, 6, 6, 8, 8, 8, 9, 11, 11, 11, 12, 13} }, + { 15, { 2, 3, 3, 5, 5, 6, 7, 8, 8, 8, 10, 11, 11, 11, 13} }, + {15.5, { 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 10, 10, 10, 11, 12} }, + { 16, { 2, 2, 3, 4, 5, 6, 7, 7, 8, 8, 10, 10, 10, 10, 12} }, + {16.5, { 1, 2, 2, 4, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 11} }, + { 17, { 1, 1, 2, 3, 4, 4, 6, 6, 6, 7, 8, 8, 8, 9, 11} }, + {17.5, { 1, 1, 2, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8, 9, 10} }, + { 18, { 1, 1, 1, 2, 3, 3, 5, 5, 5, 6, 7, 7, 8, 8, 10} }, + {18.5, { 1, 1, 1, 2, 3, 3, 5, 5, 5, 5, 7, 7, 7, 8, 10} }, + { 19, { 1, 1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 7, 9} }, + {19.5, { 1, 1, 1, 2, 2, 2, 4, 5, 5, 5, 6, 6, 6, 7, 9} }, + { 20, { 1, 1, 1, 2, 2, 2, 4, 5, 5, 5, 6, 6, 6, 6, 8} }, + {20.5, { 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 8} }, + { 21, { 0, 0, 0, 1, 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 7} }, + {21.5, { 0, 0, 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 7} }, + { 22, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 7} }, + {22.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 6} }, + { 23, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6} }, + {23.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5} }, + { 24, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 5} } +}; + + +const qp_table qp_table_444_12bpc_max = { + { 6, {12, 14, 16, 16, 17, 17, 17, 18, 19, 20, 20, 20, 20, 21, 23} }, + { 6.5, {12, 14, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 20, 21, 23} }, + { 7, {12, 13, 15, 15, 16, 16, 16, 17, 18, 19, 19, 20, 20, 21, 22} }, + { 7.5, {12, 13, 14, 15, 15, 16, 16, 17, 18, 18, 19, 19, 20, 21, 22} }, + { 8, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, + { 8.5, {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21} }, + { 9, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 21} }, + { 9.5, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 21} }, + { 10, {11, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 19, 19, 20} }, + {10.5, {10, 12, 13, 14, 15, 15, 15, 16, 17, 17, 18, 18, 18, 19, 20} }, + { 11, { 9, 11, 13, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 19} }, + {11.5, { 9, 11, 13, 14, 15, 15, 15, 16, 16, 17, 17, 17, 17, 18, 19} }, + { 12, { 6, 9, 12, 13, 14, 14, 15, 16, 16, 17, 17, 17, 17, 18, 19} }, + {12.5, { 6, 9, 12, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 19} }, + { 13, { 5, 9, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 17, 18} }, + {13.5, { 5, 8, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 18} }, + { 14, { 5, 8, 10, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 18} }, + {14.5, { 4, 7, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 17} }, + { 15, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} }, + {15.5, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17} }, + { 16, { 4, 7, 9, 10, 10, 11, 11, 12, 13, 13, 13, 14, 14, 15, 16} }, + {16.5, { 4, 5, 7, 8, 10, 11, 11, 12, 13, 13, 13, 14, 14, 15, 16} }, + { 17, { 4, 5, 7, 8, 8, 9, 11, 11, 12, 12, 12, 13, 13, 14, 16} }, + {17.5, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 16} }, + { 18, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 15} }, + {18.5, { 3, 5, 7, 8, 8, 9, 10, 11, 12, 12, 12, 13, 13, 14, 15} }, + { 19, { 3, 4, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 14} }, + {19.5, { 3, 4, 6, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 14} }, + { 20, { 2, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11, 11, 12, 14} }, + {20.5, { 2, 3, 5, 5, 7, 8, 8, 8, 9, 10, 10, 11, 11, 12, 14} }, + { 21, { 2, 3, 5, 5, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 14} }, + {21.5, { 2, 3, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13} }, + { 22, { 2, 2, 4, 5, 6, 6, 7, 7, 8, 9, 10, 10, 10, 11, 13} }, + {22.5, { 2, 2, 4, 5, 5, 6, 7, 7, 8, 9, 10, 10, 10, 11, 12} }, + { 23, { 2, 2, 4, 5, 5, 6, 7, 7, 7, 8, 10, 10, 10, 10, 12} }, + {23.5, { 2, 2, 3, 5, 5, 6, 7, 7, 7, 8, 10, 10, 10, 10, 12} }, + { 24, { 2, 2, 3, 4, 4, 5, 7, 7, 7, 8, 9, 9, 9, 10, 12} }, + {24.5, { 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 9, 9, 10, 12} }, + { 25, { 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 9, 9, 11} }, + {25.5, { 1, 1, 3, 3, 4, 5, 6, 6, 7, 7, 8, 9, 9, 9, 11} }, + { 26, { 1, 1, 3, 3, 3, 4, 5, 6, 6, 7, 8, 8, 8, 8, 10} }, + {26.5, { 1, 1, 2, 3, 3, 4, 5, 6, 6, 6, 8, 8, 8, 8, 10} }, + { 27, { 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 10} }, + {27.5, { 1, 1, 2, 2, 3, 3, 5, 5, 5, 6, 7, 8, 8, 8, 10} }, + { 28, { 0, 1, 1, 2, 2, 3, 4, 5, 5, 5, 7, 7, 7, 8, 10} }, + {28.5, { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} }, + { 29, { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 9} }, + {29.5, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8} }, + { 30, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 6, 6, 6, 6, 8} }, + {30.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8} }, + { 31, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6, 8} }, + {31.5, { 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8} }, + { 32, { 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 7} }, + {32.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 5, 7} }, + { 33, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} }, + {33.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} }, + { 34, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 6} }, + {34.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 3, 3, 3, 4, 6} }, + { 35, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} }, + {35.5, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 5} }, + { 36, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 4} } +}; + + +const qp_table qp_table_420_8bpc_min = { + { 4, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 13} }, + { 4.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, + { 5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, + { 5.5, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, + { 6, { 0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} }, + { 6.5, { 0, 0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 5, 7, 10} }, + { 7, { 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} }, + { 7.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 7, 8} }, + { 8, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} }, + { 8.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} }, + { 9, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6} }, + { 9.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} }, + { 10, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5} }, + {10.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 5} }, + { 11, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4} }, + {11.5, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4} }, + { 12, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3} } +}; + + +const qp_table qp_table_422_8bpc_min = { + { 6, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, + { 6.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 8, 12} }, + { 7, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, + { 7.5, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 11} }, + { 8, { 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 10} }, + { 8.5, { 0, 0, 1, 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 7, 10} }, + { 9, { 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 7, 9} }, + { 9.5, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9} }, + { 10, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} }, + {10.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 8} }, + { 11, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} }, + {11.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7} }, + { 12, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6} }, + {12.5, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6} }, + { 13, { 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5} }, + {13.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 5} }, + { 14, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4} }, + {14.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4} }, + { 15, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 4} }, + {15.5, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} }, + { 16, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3} } +}; + + +const qp_table qp_table_422_10bpc_max = { + { 6, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, + { 6.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, + { 7, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} }, + { 7.5, { 5, 6, 8, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 16} }, + { 8, { 4, 6, 7, 9, 10, 11, 11, 12, 12, 13, 13, 13, 13, 14, 15} }, + { 8.5, { 4, 5, 6, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15} }, + { 9, { 3, 4, 5, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14} }, + { 9.5, { 3, 4, 4, 6, 6, 8, 8, 9, 10, 10, 11, 11, 12, 13, 14} }, + { 10, { 2, 3, 3, 5, 5, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + {10.5, { 2, 3, 3, 5, 5, 6, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + { 11, { 2, 3, 3, 5, 5, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12} }, + {11.5, { 2, 3, 3, 5, 5, 5, 7, 7, 8, 9, 9, 10, 10, 11, 12} }, + { 12, { 2, 3, 3, 5, 5, 5, 7, 7, 8, 8, 9, 9, 10, 10, 11} }, + {12.5, { 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 11} }, + { 13, { 1, 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10} }, + {13.5, { 1, 2, 3, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 10} }, + { 14, { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 8, 8, 8, 9} }, + {14.5, { 1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 7, 7, 7, 8, 9} }, + { 15, { 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7, 7, 7, 9} }, + {15.5, { 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 8} }, + { 16, { 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6, 8} }, + {16.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7} }, + { 17, { 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 7} }, + {17.5, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6} }, + { 18, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 6} }, + {18.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 6} }, + { 19, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 5} }, + {19.5, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 5} }, + { 20, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 4} } +}; + + +const qp_table qp_table_420_10bpc_max = { + { 4, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 17, 18} }, + { 4.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, + { 5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 16, 17} }, + { 5.5, { 6, 7, 8, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 15, 16} }, + { 6, { 4, 6, 8, 9, 10, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15} }, + { 6.5, { 4, 5, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 13, 14, 15} }, + { 7, { 3, 4, 6, 7, 7, 8, 9, 10, 10, 11, 12, 12, 13, 13, 14} }, + { 7.5, { 3, 4, 5, 6, 6, 7, 8, 9, 10, 10, 11, 11, 12, 12, 13} }, + { 8, { 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + { 8.5, { 1, 3, 3, 4, 4, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12} }, + { 9, { 1, 3, 3, 4, 4, 6, 7, 8, 8, 9, 9, 10, 10, 10, 11} }, + { 9.5, { 1, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 9, 9, 10, 11} }, + { 10, { 1, 2, 3, 3, 4, 4, 5, 6, 7, 8, 8, 9, 9, 9, 11} }, + {10.5, { 1, 1, 3, 3, 3, 4, 5, 5, 7, 7, 8, 8, 8, 8, 10} }, + { 11, { 0, 1, 2, 3, 3, 3, 4, 5, 6, 7, 7, 7, 8, 8, 9} }, + {11.5, { 0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 6, 7, 7, 7, 9} }, + { 12, { 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 6, 8} }, + {12.5, { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7} }, + { 13, { 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 7} }, + {13.5, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 6} }, + { 14, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} }, + {14.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 5} }, + { 15, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 5} } +}; + + +const qp_table qp_table_420_10bpc_min = { + { 4, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 17} }, + { 4.5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, + { 5, { 0, 4, 4, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 12, 16} }, + { 5.5, { 0, 3, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15} }, + { 6, { 0, 2, 3, 4, 6, 7, 7, 7, 7, 7, 9, 9, 9, 11, 14} }, + { 6.5, { 0, 2, 3, 4, 5, 6, 6, 7, 7, 7, 8, 9, 9, 11, 14} }, + { 7, { 0, 2, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 11, 13} }, + { 7.5, { 0, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 11, 12} }, + { 8, { 0, 2, 3, 4, 4, 5, 5, 6, 6, 7, 8, 8, 9, 11, 12} }, + { 8.5, { 0, 2, 2, 3, 3, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11} }, + { 9, { 0, 2, 2, 3, 3, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10} }, + { 9.5, { 0, 2, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 10} }, + { 10, { 0, 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 8, 8, 8, 10} }, + {10.5, { 0, 0, 2, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 9} }, + { 11, { 0, 0, 1, 2, 2, 2, 3, 4, 4, 5, 5, 6, 7, 7, 8} }, + {11.5, { 0, 0, 0, 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 8} }, + { 12, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 7} }, + {12.5, { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 6} }, + { 13, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} }, + {13.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 3, 5} }, + { 14, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} }, + {14.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 4} }, + { 15, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 4} } +}; + + +const qp_table qp_table_444_10bpc_max = { + { 6, { 8, 10, 12, 12, 13, 13, 13, 14, 15, 16, 16, 16, 16, 17, 19} }, + { 6.5, { 8, 10, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 16, 17, 19} }, + { 7, { 8, 9, 11, 11, 12, 12, 12, 13, 14, 15, 15, 16, 16, 17, 18} }, + { 7.5, { 8, 9, 10, 11, 11, 12, 12, 13, 14, 14, 15, 15, 16, 17, 18} }, + { 8, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, + { 8.5, { 8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17} }, + { 9, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 17} }, + { 9.5, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 17} }, + { 10, { 7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16} }, + {10.5, { 6, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 14, 15, 16} }, + { 11, { 5, 7, 9, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15} }, + {11.5, { 5, 7, 9, 10, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 15} }, + { 12, { 4, 6, 8, 9, 10, 10, 11, 12, 12, 13, 13, 13, 13, 14, 15} }, + {12.5, { 4, 6, 8, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15} }, + { 13, { 3, 6, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 14} }, + {13.5, { 3, 5, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14} }, + { 14, { 3, 5, 6, 7, 8, 8, 8, 9, 10, 10, 11, 12, 12, 12, 14} }, + {14.5, { 2, 4, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13} }, + { 15, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + {15.5, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13} }, + { 16, { 2, 4, 5, 6, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 12} }, + {16.5, { 2, 3, 4, 5, 6, 7, 7, 8, 9, 9, 9, 10, 10, 11, 12} }, + { 17, { 2, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 12} }, + {17.5, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 12} }, + { 18, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 11} }, + {18.5, { 1, 3, 4, 5, 5, 6, 6, 7, 8, 8, 8, 9, 9, 10, 11} }, + { 19, { 1, 2, 3, 4, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9, 10} }, + {19.5, { 1, 2, 3, 4, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9, 10} }, + { 20, { 1, 2, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 8, 10} }, + {20.5, { 1, 2, 3, 3, 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 10} }, + { 21, { 1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 7, 8, 10} }, + {21.5, { 1, 2, 3, 3, 3, 3, 4, 5, 5, 5, 6, 7, 7, 8, 9} }, + { 22, { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 9} }, + {22.5, { 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8} }, + { 23, { 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 8} }, + {23.5, { 1, 1, 1, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6, 8} }, + { 24, { 1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 6, 8} }, + {24.5, { 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 8} }, + { 25, { 0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 7} }, + {25.5, { 0, 0, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 7} }, + { 26, { 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 6} }, + {26.5, { 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 6} }, + { 27, { 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 6} }, + {27.5, { 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 6} }, + { 28, { 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 5} }, + {28.5, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 5} }, + { 29, { 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4} }, + {29.5, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4} }, + { 30, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 4} } +}; + + +const qp_table qp_table_422_8bpc_max = { + { 6, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, + { 6.5, { 4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13} }, + { 7, { 3, 4, 5, 6, 7, 7, 7, 8, 9, 9, 10, 10, 11, 11, 12} }, + { 7.5, { 3, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12} }, + { 8, { 2, 4, 5, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 11} }, + { 8.5, { 2, 3, 4, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11} }, + { 9, { 1, 2, 3, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10} }, + { 9.5, { 1, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 10} }, + { 10, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} }, + {10.5, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9} }, + { 11, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8} }, + {11.5, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8} }, + { 12, { 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7} }, + {12.5, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7} }, + { 13, { 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6} }, + {13.5, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 6} }, + { 14, { 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5} }, + {14.5, { 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 5} }, + { 15, { 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 5} }, + {15.5, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} }, + { 16, { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4} } +}; + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c new file mode 100644 index 000000000000..ca51e83f8764 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c @@ -0,0 +1,258 @@ +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) + +/* + * 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. + * + * Authors: AMD + * + */ + +#include "os_types.h" +#include "rc_calc.h" +#include "qp_tables.h" + +#define table_hash(mode, bpc, max_min) ((mode << 16) | (bpc << 8) | max_min) + +#define MODE_SELECT(val444, val422, val420) \ + (cm == CM_444 || cm == CM_RGB) ? (val444) : (cm == CM_422 ? (val422) : (val420)) + + +#define TABLE_CASE(mode, bpc, max) case (table_hash(mode, BPC_##bpc, max)): \ + table = qp_table_##mode##_##bpc##bpc_##max; \ + table_size = sizeof(qp_table_##mode##_##bpc##bpc_##max)/sizeof(*qp_table_##mode##_##bpc##bpc_##max); \ + break + + +void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc, enum max_min max_min, float bpp) +{ + int mode = MODE_SELECT(444, 422, 420); + int sel = table_hash(mode, bpc, max_min); + int table_size = 0; + int index; + const struct qp_entry *table = 0L; + + // alias enum + enum { min = MM_MIN, max = MM_MAX }; + switch (sel) { + TABLE_CASE(444, 8, max); + TABLE_CASE(444, 8, min); + TABLE_CASE(444, 10, max); + TABLE_CASE(444, 10, min); + TABLE_CASE(444, 12, max); + TABLE_CASE(444, 12, min); + TABLE_CASE(422, 8, max); + TABLE_CASE(422, 8, min); + TABLE_CASE(422, 10, max); + TABLE_CASE(422, 10, min); + TABLE_CASE(422, 12, max); + TABLE_CASE(422, 12, min); + TABLE_CASE(420, 8, max); + TABLE_CASE(420, 8, min); + TABLE_CASE(420, 10, max); + TABLE_CASE(420, 10, min); + TABLE_CASE(420, 12, max); + TABLE_CASE(420, 12, min); + } + + if (table == 0) + return; + + index = (bpp - table[0].bpp) * 2; + + /* requested size is bigger than the table */ + if (index >= table_size) { + dm_error("ERROR: Requested rc_calc to find a bpp entry that exceeds the table size\n"); + return; + } + + memcpy(qps, table[index].qps, sizeof(qp_set)); +} + +double dsc_roundf(double num) +{ + if (num < 0.0) + num = num - 0.5; + else + num = num + 0.5; + + return (int)(num); +} + +double dsc_ceil(double num) +{ + double retval = (int)num; + + if (retval != num && num > 0) + retval = num + 1; + + return (int)retval; +} + +void get_ofs_set(qp_set ofs, enum colour_mode mode, float bpp) +{ + int *p = ofs; + + if (mode == CM_444 || mode == CM_RGB) { + *p++ = (bpp <= 6) ? (0) : ((((bpp >= 8) && (bpp <= 12))) ? (2) : ((bpp >= 15) ? (10) : ((((bpp > 6) && (bpp < 8))) ? (0 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (2 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); + *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (8) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (8 / 3.0)))))); + *p++ = (bpp <= 6) ? (-2) : ((((bpp >= 8) && (bpp <= 12))) ? (0) : ((bpp >= 15) ? (6) : ((((bpp > 6) && (bpp < 8))) ? (-2 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (0 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 6) ? (-4) : ((((bpp >= 8) && (bpp <= 12))) ? (-2) : ((bpp >= 15) ? (4) : ((((bpp > 6) && (bpp < 8))) ? (-4 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-2 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 6) ? (-6) : ((((bpp >= 8) && (bpp <= 12))) ? (-4) : ((bpp >= 15) ? (2) : ((((bpp > 6) && (bpp < 8))) ? (-6 + dsc_roundf((bpp - 6) * (2 / 2.0))) : (-4 + dsc_roundf((bpp - 12) * (6 / 3.0)))))); + *p++ = (bpp <= 12) ? (-6) : ((bpp >= 15) ? (0) : (-6 + dsc_roundf((bpp - 12) * (6 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-2) : (-8 + dsc_roundf((bpp - 12) * (6 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-4) : (-8 + dsc_roundf((bpp - 12) * (4 / 3.0)))); + *p++ = (bpp <= 12) ? (-8) : ((bpp >= 15) ? (-6) : (-8 + dsc_roundf((bpp - 12) * (2 / 3.0)))); + *p++ = (bpp <= 12) ? (-10) : ((bpp >= 15) ? (-8) : (-10 + dsc_roundf((bpp - 12) * (2 / 3.0)))); + *p++ = -10; + *p++ = (bpp <= 6) ? (-12) : ((bpp >= 8) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } else if (mode == CM_422) { + *p++ = (bpp <= 8) ? (2) : ((bpp >= 10) ? (10) : (2 + dsc_roundf((bpp - 8) * (8 / 2.0)))); + *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (8) : (0 + dsc_roundf((bpp - 8) * (8 / 2.0)))); + *p++ = (bpp <= 8) ? (0) : ((bpp >= 10) ? (6) : (0 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-2) : ((bpp >= 10) ? (4) : (-2 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-4) : ((bpp >= 10) ? (2) : (-4 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-6) : ((bpp >= 10) ? (0) : (-6 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-2) : (-8 + dsc_roundf((bpp - 8) * (6 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-4) : (-8 + dsc_roundf((bpp - 8) * (4 / 2.0)))); + *p++ = (bpp <= 8) ? (-8) : ((bpp >= 10) ? (-6) : (-8 + dsc_roundf((bpp - 8) * (2 / 2.0)))); + *p++ = (bpp <= 8) ? (-10) : ((bpp >= 10) ? (-8) : (-10 + dsc_roundf((bpp - 8) * (2 / 2.0)))); + *p++ = -10; + *p++ = (bpp <= 6) ? (-12) : ((bpp >= 7) ? (-10) : (-12 + dsc_roundf((bpp - 6) * (2.0 / 1)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } else { + *p++ = (bpp <= 6) ? (2) : ((bpp >= 8) ? (10) : (2 + dsc_roundf((bpp - 6) * (8 / 2.0)))); + *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (8) : (0 + dsc_roundf((bpp - 6) * (8 / 2.0)))); + *p++ = (bpp <= 6) ? (0) : ((bpp >= 8) ? (6) : (0 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-2) : ((bpp >= 8) ? (4) : (-2 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-4) : ((bpp >= 8) ? (2) : (-4 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-6) : ((bpp >= 8) ? (0) : (-6 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-2) : (-8 + dsc_roundf((bpp - 6) * (6 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-4) : (-8 + dsc_roundf((bpp - 6) * (4 / 2.0)))); + *p++ = (bpp <= 6) ? (-8) : ((bpp >= 8) ? (-6) : (-8 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = (bpp <= 6) ? (-10) : ((bpp >= 8) ? (-8) : (-10 + dsc_roundf((bpp - 6) * (2 / 2.0)))); + *p++ = -10; + *p++ = (bpp <= 4) ? (-12) : ((bpp >= 5) ? (-10) : (-12 + dsc_roundf((bpp - 4) * (2 / 1.0)))); + *p++ = -12; + *p++ = -12; + *p++ = -12; + } +} + +int median3(int a, int b, int c) +{ + if (a > b) + swap(a, b); + if (b > c) + swap(b, c); + if (a > b) + swap(b, c); + + return b; +} + +void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_comp bpc, float bpp, int slice_width, int slice_height, int minor_version) +{ + float bpp_group; + float initial_xmit_delay_factor; + int source_bpp; + int padding_pixels; + int i; + + rc->rc_quant_incr_limit0 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->rc_quant_incr_limit1 = ((bpc == BPC_8) ? 11 : (bpc == BPC_10 ? 15 : 19)) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + + bpp_group = MODE_SELECT(bpp, bpp * 2.0, bpp * 2.0); + + switch (cm) { + case CM_420: + rc->initial_fullness_offset = (bpp >= 6) ? (2048) : ((bpp <= 4) ? (6144) : ((((bpp > 4) && (bpp <= 5))) ? (6144 - dsc_roundf((bpp - 4) * (512))) : (5632 - dsc_roundf((bpp - 5) * (3584))))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 3) - (3 * bpp_group))); + rc->second_line_bpg_offset = median3(0, 12, (int)((3 * bpc * 3) - (3 * bpp_group))); + break; + case CM_422: + rc->initial_fullness_offset = (bpp >= 8) ? (2048) : ((bpp <= 7) ? (5632) : (5632 - dsc_roundf((bpp - 7) * (3584)))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)((3 * bpc * 4) - (3 * bpp_group))); + rc->second_line_bpg_offset = 0; + break; + case CM_444: + case CM_RGB: + rc->initial_fullness_offset = (bpp >= 12) ? (2048) : ((bpp <= 8) ? (6144) : ((((bpp > 8) && (bpp <= 10))) ? (6144 - dsc_roundf((bpp - 8) * (512 / 2))) : (5632 - dsc_roundf((bpp - 10) * (3584 / 2))))); + rc->first_line_bpg_offset = median3(0, (12 + (int) (0.09 * min(34, slice_height - 8))), (int)(((3 * bpc + (cm == CM_444 ? 0 : 2)) * 3) - (3 * bpp_group))); + rc->second_line_bpg_offset = 0; + break; + } + + initial_xmit_delay_factor = (cm == CM_444 || cm == CM_RGB) ? 1.0 : 2.0; + rc->initial_xmit_delay = dsc_roundf(8192.0/2.0/bpp/initial_xmit_delay_factor); + + if (cm == CM_422 || cm == CM_420) + slice_width /= 2; + + padding_pixels = ((slice_width % 3) != 0) ? (3 - (slice_width % 3)) * (rc->initial_xmit_delay / slice_width) : 0; + if (3 * bpp_group >= (((rc->initial_xmit_delay + 2) / 3) * (3 + (cm == CM_422)))) { + if ((rc->initial_xmit_delay + padding_pixels) % 3 == 1) + rc->initial_xmit_delay++; + } + + source_bpp = MODE_SELECT(bpc * 3, bpc * 2, bpc * 1.5); + + rc->flatness_min_qp = ((bpc == BPC_8) ? (3) : ((bpc == BPC_10) ? (7) : (11))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->flatness_max_qp = ((bpc == BPC_8) ? (12) : ((bpc == BPC_10) ? (16) : (20))) - ((minor_version == 1 && cm == CM_444) ? 1 : 0); + rc->flatness_det_thresh = 2 << (bpc - 8); + + get_qp_set(rc->qp_min, cm, bpc, MM_MIN, bpp); + get_qp_set(rc->qp_max, cm, bpc, MM_MAX, bpp); + if (cm == CM_444 && minor_version == 1) { + for (i = 0; i < QP_SET_SIZE; ++i) { + rc->qp_min[i] = rc->qp_min[i] > 0 ? rc->qp_min[i] - 1 : 0; + rc->qp_max[i] = rc->qp_max[i] > 0 ? rc->qp_max[i] - 1 : 0; + } + } + get_ofs_set(rc->ofs, cm, bpp); + + /* fixed parameters */ + rc->rc_model_size = 8192; + rc->rc_edge_factor = 6; + rc->rc_tgt_offset_hi = 3; + rc->rc_tgt_offset_lo = 3; + + rc->rc_buf_thresh[0] = 896; + rc->rc_buf_thresh[1] = 1792; + rc->rc_buf_thresh[2] = 2688; + rc->rc_buf_thresh[3] = 3584; + rc->rc_buf_thresh[4] = 4480; + rc->rc_buf_thresh[5] = 5376; + rc->rc_buf_thresh[6] = 6272; + rc->rc_buf_thresh[7] = 6720; + rc->rc_buf_thresh[8] = 7168; + rc->rc_buf_thresh[9] = 7616; + rc->rc_buf_thresh[10] = 7744; + rc->rc_buf_thresh[11] = 7872; + rc->rc_buf_thresh[12] = 8000; + rc->rc_buf_thresh[13] = 8064; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h new file mode 100644 index 000000000000..f1d6e793bc61 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc.h @@ -0,0 +1,85 @@ +#if defined(CONFIG_DRM_AMD_DC_DCN2_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. + * + * Authors: AMD + * + */ + +#ifndef __RC_CALC_H__ +#define __RC_CALC_H__ + + +#define QP_SET_SIZE 15 + +typedef int qp_set[QP_SET_SIZE]; + +struct rc_params { + int rc_quant_incr_limit0; + int rc_quant_incr_limit1; + int initial_fullness_offset; + int initial_xmit_delay; + int first_line_bpg_offset; + int second_line_bpg_offset; + int flatness_min_qp; + int flatness_max_qp; + int flatness_det_thresh; + qp_set qp_min; + qp_set qp_max; + qp_set ofs; + int rc_model_size; + int rc_edge_factor; + int rc_tgt_offset_hi; + int rc_tgt_offset_lo; + int rc_buf_thresh[QP_SET_SIZE - 1]; +}; + +enum colour_mode { + CM_RGB, /* 444 RGB */ + CM_444, /* 444 YUV or simple 422 */ + CM_422, /* native 422 */ + CM_420 /* native 420 */ +}; + +enum bits_per_comp { + BPC_8 = 8, + BPC_10 = 10, + BPC_12 = 12 +}; + +enum max_min { + MM_MIN = 0, + MM_MAX = 1 +}; + +struct qp_entry { + float bpp; + const qp_set qps; +}; + +typedef struct qp_entry qp_table[]; + +void calc_rc_params(struct rc_params *rc, enum colour_mode cm, enum bits_per_comp bpc, float bpp, int slice_width, int slice_height, int minor_version); + +#endif + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c new file mode 100644 index 000000000000..73172fd0b529 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c @@ -0,0 +1,147 @@ +#if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) +/* + * Copyright 2012-17 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 "os_types.h" +#include <drm/drm_dsc.h> +#include "dscc_types.h" +#include "rc_calc.h" + +double dsc_ceil(double num); + +static void copy_pps_fields(struct drm_dsc_config *to, const struct drm_dsc_config *from) +{ + to->line_buf_depth = from->line_buf_depth; + to->bits_per_component = from->bits_per_component; + to->convert_rgb = from->convert_rgb; + to->slice_width = from->slice_width; + to->slice_height = from->slice_height; + to->simple_422 = from->simple_422; + to->native_422 = from->native_422; + to->native_420 = from->native_420; + to->pic_width = from->pic_width; + to->pic_height = from->pic_height; + to->rc_tgt_offset_high = from->rc_tgt_offset_high; + to->rc_tgt_offset_low = from->rc_tgt_offset_low; + to->bits_per_pixel = from->bits_per_pixel; + to->rc_edge_factor = from->rc_edge_factor; + to->rc_quant_incr_limit1 = from->rc_quant_incr_limit1; + to->rc_quant_incr_limit0 = from->rc_quant_incr_limit0; + to->initial_xmit_delay = from->initial_xmit_delay; + to->initial_dec_delay = from->initial_dec_delay; + to->block_pred_enable = from->block_pred_enable; + to->first_line_bpg_offset = from->first_line_bpg_offset; + to->second_line_bpg_offset = from->second_line_bpg_offset; + to->initial_offset = from->initial_offset; + memcpy(&to->rc_buf_thresh, &from->rc_buf_thresh, sizeof(from->rc_buf_thresh)); + memcpy(&to->rc_range_params, &from->rc_range_params, sizeof(from->rc_range_params)); + to->rc_model_size = from->rc_model_size; + to->flatness_min_qp = from->flatness_min_qp; + to->flatness_max_qp = from->flatness_max_qp; + to->initial_scale_value = from->initial_scale_value; + to->scale_decrement_interval = from->scale_decrement_interval; + to->scale_increment_interval = from->scale_increment_interval; + to->nfl_bpg_offset = from->nfl_bpg_offset; + to->nsl_bpg_offset = from->nsl_bpg_offset; + to->slice_bpg_offset = from->slice_bpg_offset; + to->final_offset = from->final_offset; + to->vbr_enable = from->vbr_enable; + to->slice_chunk_size = from->slice_chunk_size; + to->second_line_offset_adj = from->second_line_offset_adj; + to->dsc_version_minor = from->dsc_version_minor; +} + +static void copy_rc_to_cfg(struct drm_dsc_config *dsc_cfg, const struct rc_params *rc) +{ + int i; + + dsc_cfg->rc_quant_incr_limit0 = rc->rc_quant_incr_limit0; + dsc_cfg->rc_quant_incr_limit1 = rc->rc_quant_incr_limit1; + dsc_cfg->initial_offset = rc->initial_fullness_offset; + dsc_cfg->initial_xmit_delay = rc->initial_xmit_delay; + dsc_cfg->first_line_bpg_offset = rc->first_line_bpg_offset; + dsc_cfg->second_line_bpg_offset = rc->second_line_bpg_offset; + dsc_cfg->flatness_min_qp = rc->flatness_min_qp; + dsc_cfg->flatness_max_qp = rc->flatness_max_qp; + for (i = 0; i < QP_SET_SIZE; ++i) { + dsc_cfg->rc_range_params[i].range_min_qp = rc->qp_min[i]; + dsc_cfg->rc_range_params[i].range_max_qp = rc->qp_max[i]; + /* Truncate 8-bit signed value to 6-bit signed value */ + dsc_cfg->rc_range_params[i].range_bpg_offset = 0x3f & rc->ofs[i]; + } + dsc_cfg->rc_model_size = rc->rc_model_size; + dsc_cfg->rc_edge_factor = rc->rc_edge_factor; + dsc_cfg->rc_tgt_offset_high = rc->rc_tgt_offset_hi; + dsc_cfg->rc_tgt_offset_low = rc->rc_tgt_offset_lo; + + for (i = 0; i < QP_SET_SIZE - 1; ++i) + dsc_cfg->rc_buf_thresh[i] = rc->rc_buf_thresh[i]; +} + +int dscc_compute_dsc_parameters(const struct drm_dsc_config *pps, struct dsc_parameters *dsc_params) +{ + enum colour_mode mode = pps->convert_rgb ? CM_RGB : + (pps->simple_422 ? CM_444 : + (pps->native_422 ? CM_422 : + pps->native_420 ? CM_420 : CM_444)); + enum bits_per_comp bpc = (pps->bits_per_component == 8) ? BPC_8 : + (pps->bits_per_component == 10) ? BPC_10 : BPC_12; + float bpp = ((float) pps->bits_per_pixel / 16.0); + int slice_width = pps->slice_width; + int slice_height = pps->slice_height; + int ret; + struct rc_params rc; + struct drm_dsc_config dsc_cfg; + + double d_bytes_per_pixel = dsc_ceil(bpp * slice_width / 8.0) / slice_width; + + // TODO: Make sure the formula for calculating this is precise (ceiling vs. floor, and at what point they should be applied) + if (pps->native_422 || pps->native_420) + d_bytes_per_pixel /= 2; + + dsc_params->bytes_per_pixel = (uint32_t)dsc_ceil(d_bytes_per_pixel * 0x10000000); + + /* in native_422 or native_420 modes, the bits_per_pixel is double the target bpp + * (the latter is what calc_rc_params expects) + */ + if (pps->native_422 || pps->native_420) + bpp /= 2.0; + + calc_rc_params(&rc, mode, bpc, bpp, slice_width, slice_height, pps->dsc_version_minor); + dsc_params->pps = *pps; + dsc_params->pps.initial_scale_value = 8 * rc.rc_model_size / (rc.rc_model_size - rc.initial_fullness_offset); + + copy_pps_fields(&dsc_cfg, &dsc_params->pps); + copy_rc_to_cfg(&dsc_cfg, &rc); + + dsc_cfg.mux_word_size = dsc_params->pps.bits_per_component <= 10 ? 48 : 64; + + ret = drm_dsc_compute_rc_parameters(&dsc_cfg); + + copy_pps_fields(&dsc_params->pps, &dsc_cfg); + dsc_params->rc_buffer_model_size = dsc_cfg.rc_bits; + return ret; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index 562ee189d780..c3d92878875d 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -70,6 +70,17 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN10) endif ############################################################################### +# DCN 2 +############################################################################### +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +GPIO_DCN20 = hw_translate_dcn20.o hw_factory_dcn20.o + +AMD_DAL_GPIO_DCN20 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn20/,$(GPIO_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN20) +endif + +############################################################################### # Diagnostics on FPGA ############################################################################### GPIO_DIAG_FPGA = hw_translate_diag.o hw_factory_diag.o diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c new file mode 100644 index 000000000000..abd76d855375 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.c @@ -0,0 +1,212 @@ +/* + * Copyright 2013-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 + * + */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dm_services.h" +#include "include/gpio_types.h" +#include "../hw_factory.h" + + +#include "../hw_gpio.h" +#include "../hw_ddc.h" +#include "../hw_hpd.h" + +#include "hw_factory_dcn20.h" + + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "navi10_ip_offset.h" + + +#include "reg_helper.h" +#include "../hpd_regs.h" +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +#define block HPD +#define reg_num 0 + +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + + + +#define REG(reg_name)\ + BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name + +#define SF_HPD(reg_name, field_name, post_fix)\ + .field_name = HPD0_ ## reg_name ## __ ## field_name ## post_fix + +#define REGI(reg_name, block, id)\ + BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +/* macros to expend register list macro defined in HW object header file + * end *********************/ + + + +#define hpd_regs(id) \ +{\ + HPD_REG_LIST(id)\ +} + +static const struct hpd_registers hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5), +}; + +static const struct hpd_sh_mask hpd_shift = { + HPD_MASK_SH_LIST(__SHIFT) +}; + +static const struct hpd_sh_mask hpd_mask = { + HPD_MASK_SH_LIST(_MASK) +}; + +#include "../ddc_regs.h" + + /* set field name */ +#define SF_DDC(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +static const struct ddc_registers ddc_data_regs_dcn[] = { + ddc_data_regs_dcn2(1), + ddc_data_regs_dcn2(2), + ddc_data_regs_dcn2(3), + ddc_data_regs_dcn2(4), + ddc_data_regs_dcn2(5), + ddc_data_regs_dcn2(6), +}; + +static const struct ddc_registers ddc_clk_regs_dcn[] = { + ddc_clk_regs_dcn2(1), + ddc_clk_regs_dcn2(2), + ddc_clk_regs_dcn2(3), + ddc_clk_regs_dcn2(4), + ddc_clk_regs_dcn2(5), + ddc_clk_regs_dcn2(6), +}; + +static const struct ddc_sh_mask ddc_shift[] = { + DDC_MASK_SH_LIST_DCN2(__SHIFT, 1), + DDC_MASK_SH_LIST_DCN2(__SHIFT, 2), + DDC_MASK_SH_LIST_DCN2(__SHIFT, 3), + DDC_MASK_SH_LIST_DCN2(__SHIFT, 4), + DDC_MASK_SH_LIST_DCN2(__SHIFT, 5), + DDC_MASK_SH_LIST_DCN2(__SHIFT, 6) +}; + +static const struct ddc_sh_mask ddc_mask[] = { + DDC_MASK_SH_LIST_DCN2(_MASK, 1), + DDC_MASK_SH_LIST_DCN2(_MASK, 2), + DDC_MASK_SH_LIST_DCN2(_MASK, 3), + DDC_MASK_SH_LIST_DCN2(_MASK, 4), + DDC_MASK_SH_LIST_DCN2(_MASK, 5), + DDC_MASK_SH_LIST_DCN2(_MASK, 6) +}; + +static void define_ddc_registers( + struct hw_gpio_pin *pin, + uint32_t en) +{ + struct hw_ddc *ddc = HW_DDC_FROM_BASE(pin); + + switch (pin->id) { + case GPIO_ID_DDC_DATA: + ddc->regs = &ddc_data_regs_dcn[en]; + ddc->base.regs = &ddc_data_regs_dcn[en].gpio; + break; + case GPIO_ID_DDC_CLOCK: + ddc->regs = &ddc_clk_regs_dcn[en]; + ddc->base.regs = &ddc_clk_regs_dcn[en].gpio; + break; + default: + ASSERT_CRITICAL(false); + return; + } + + ddc->shifts = &ddc_shift[en]; + ddc->masks = &ddc_mask[en]; + +} + +static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) +{ + struct hw_hpd *hpd = HW_HPD_FROM_BASE(pin); + + hpd->regs = &hpd_regs[en]; + hpd->shifts = &hpd_shift; + hpd->masks = &hpd_mask; + hpd->base.regs = &hpd_regs[en].gpio; +} + + +/* fucntion table */ +static const struct hw_factory_funcs funcs = { + .create_ddc_data = dal_hw_ddc_create, + .create_ddc_clock = dal_hw_ddc_create, + .create_generic = NULL, + .create_hpd = dal_hw_hpd_create, + .create_sync = NULL, + .create_gsl = NULL, + .define_hpd_registers = define_hpd_registers, + .define_ddc_registers = define_ddc_registers +}; +/* + * dal_hw_factory_dcn10_init + * + * @brief + * Initialize HW factory function pointers and pin info + * + * @param + * struct hw_factory *factory - [out] struct of function pointers + */ +void dal_hw_factory_dcn20_init(struct hw_factory *factory) +{ + /*TODO check ASIC CAPs*/ + factory->number_of_pins[GPIO_ID_DDC_DATA] = 8; + factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8; + factory->number_of_pins[GPIO_ID_GENERIC] = 4; + factory->number_of_pins[GPIO_ID_HPD] = 6; + factory->number_of_pins[GPIO_ID_GPIO_PAD] = 28; + factory->number_of_pins[GPIO_ID_VIP_PAD] = 0; + factory->number_of_pins[GPIO_ID_SYNC] = 0; + factory->number_of_pins[GPIO_ID_GSL] = 0;/*add this*/ + + factory->funcs = &funcs; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h new file mode 100644 index 000000000000..43a4ce7aa3bf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_factory_dcn20.h @@ -0,0 +1,33 @@ +/* + * 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 + * + */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#ifndef __DAL_HW_FACTORY_DCN20_H__ +#define __DAL_HW_FACTORY_DCN20_H__ + +/* Initialize HW factory function pointers and pin info */ +void dal_hw_factory_dcn20_init(struct hw_factory *factory); + +#endif /* __DAL_HW_FACTORY_DCN20_H__ */ +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c new file mode 100644 index 000000000000..b393cc13298a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c @@ -0,0 +1,382 @@ +/* + * 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 + * + */ + +/* + * Pre-requisites: headers required by header of this unit + */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "hw_translate_dcn20.h" + +#include "dm_services.h" +#include "include/gpio_types.h" +#include "../hw_translate.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 */ + +/* DCN */ +#define block HPD +#define reg_num 0 + +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#undef REG +#define REG(reg_name)\ + BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name +#define SF_HPD(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + + +/* macros to expend register list macro defined in HW object header file + * end *********************/ + + +static bool offset_to_id( + uint32_t offset, + uint32_t mask, + enum gpio_id *id, + uint32_t *en) +{ + switch (offset) { + /* GENERIC */ + case REG(DC_GENERICA): + *id = GPIO_ID_GENERIC; + switch (mask) { + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: + *en = GPIO_GENERIC_A; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: + *en = GPIO_GENERIC_B; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: + *en = GPIO_GENERIC_C; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: + *en = GPIO_GENERIC_D; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: + *en = GPIO_GENERIC_E; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: + *en = GPIO_GENERIC_F; + return true; + case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: + *en = GPIO_GENERIC_G; + return true; + default: + ASSERT_CRITICAL(false); + return false; + } + break; + /* HPD */ + case REG(DC_GPIO_HPD_A): + *id = GPIO_ID_HPD; + switch (mask) { + case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: + *en = GPIO_HPD_1; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: + *en = GPIO_HPD_2; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: + *en = GPIO_HPD_3; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: + *en = GPIO_HPD_4; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: + *en = GPIO_HPD_5; + return true; + case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: + *en = GPIO_HPD_6; + return true; + default: + ASSERT_CRITICAL(false); + return false; + } + break; + /* REG(DC_GPIO_GENLK_MASK */ + case REG(DC_GPIO_GENLK_A): + *id = GPIO_ID_GSL; + switch (mask) { + case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: + *en = GPIO_GSL_GENLOCK_CLOCK; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: + *en = GPIO_GSL_GENLOCK_VSYNC; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: + *en = GPIO_GSL_SWAPLOCK_A; + return true; + case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: + *en = GPIO_GSL_SWAPLOCK_B; + return true; + default: + ASSERT_CRITICAL(false); + return false; + } + break; + /* DDC */ + /* we don't care about the GPIO_ID for DDC + * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK + * directly in the create method */ + case REG(DC_GPIO_DDC1_A): + *en = GPIO_DDC_LINE_DDC1; + return true; + case REG(DC_GPIO_DDC2_A): + *en = GPIO_DDC_LINE_DDC2; + return true; + case REG(DC_GPIO_DDC3_A): + *en = GPIO_DDC_LINE_DDC3; + return true; + case REG(DC_GPIO_DDC4_A): + *en = GPIO_DDC_LINE_DDC4; + return true; + case REG(DC_GPIO_DDC5_A): + *en = GPIO_DDC_LINE_DDC5; + return true; + case REG(DC_GPIO_DDC6_A): + *en = GPIO_DDC_LINE_DDC6; + return true; + case REG(DC_GPIO_DDCVGA_A): + *en = GPIO_DDC_LINE_DDC_VGA; + return true; + +// case REG(DC_GPIO_I2CPAD_A): not exit +// case REG(DC_GPIO_PWRSEQ_A): +// case REG(DC_GPIO_PAD_STRENGTH_1): +// case REG(DC_GPIO_PAD_STRENGTH_2): +// case REG(DC_GPIO_DEBUG): + /* UNEXPECTED */ + default: +// case REG(DC_GPIO_SYNCA_A): not exist + ASSERT_CRITICAL(false); + return false; + } +} + +static bool id_to_offset( + enum gpio_id id, + uint32_t en, + struct gpio_pin_info *info) +{ + bool result = true; + + switch (id) { + case GPIO_ID_DDC_DATA: + info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; + switch (en) { + case GPIO_DDC_LINE_DDC1: + info->offset = REG(DC_GPIO_DDC1_A); + break; + case GPIO_DDC_LINE_DDC2: + info->offset = REG(DC_GPIO_DDC2_A); + break; + case GPIO_DDC_LINE_DDC3: + info->offset = REG(DC_GPIO_DDC3_A); + break; + case GPIO_DDC_LINE_DDC4: + info->offset = REG(DC_GPIO_DDC4_A); + break; + case GPIO_DDC_LINE_DDC5: + info->offset = REG(DC_GPIO_DDC5_A); + break; + case GPIO_DDC_LINE_DDC6: + info->offset = REG(DC_GPIO_DDC6_A); + break; + case GPIO_DDC_LINE_DDC_VGA: + info->offset = REG(DC_GPIO_DDCVGA_A); + break; + case GPIO_DDC_LINE_I2C_PAD: + default: + ASSERT_CRITICAL(false); + result = false; + } + break; + case GPIO_ID_DDC_CLOCK: + info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; + switch (en) { + case GPIO_DDC_LINE_DDC1: + info->offset = REG(DC_GPIO_DDC1_A); + break; + case GPIO_DDC_LINE_DDC2: + info->offset = REG(DC_GPIO_DDC2_A); + break; + case GPIO_DDC_LINE_DDC3: + info->offset = REG(DC_GPIO_DDC3_A); + break; + case GPIO_DDC_LINE_DDC4: + info->offset = REG(DC_GPIO_DDC4_A); + break; + case GPIO_DDC_LINE_DDC5: + info->offset = REG(DC_GPIO_DDC5_A); + break; + case GPIO_DDC_LINE_DDC6: + info->offset = REG(DC_GPIO_DDC6_A); + break; + case GPIO_DDC_LINE_DDC_VGA: + info->offset = REG(DC_GPIO_DDCVGA_A); + break; + case GPIO_DDC_LINE_I2C_PAD: + default: + ASSERT_CRITICAL(false); + result = false; + } + break; + case GPIO_ID_GENERIC: + info->offset = REG(DC_GPIO_GENERIC_A); + switch (en) { + case GPIO_GENERIC_A: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; + break; + case GPIO_GENERIC_B: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; + break; + case GPIO_GENERIC_C: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; + break; + case GPIO_GENERIC_D: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; + break; + case GPIO_GENERIC_E: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; + break; + case GPIO_GENERIC_F: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; + break; + case GPIO_GENERIC_G: + info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; + break; + default: + ASSERT_CRITICAL(false); + result = false; + } + break; + case GPIO_ID_HPD: + info->offset = REG(DC_GPIO_HPD_A); + switch (en) { + case GPIO_HPD_1: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; + break; + case GPIO_HPD_2: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; + break; + case GPIO_HPD_3: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; + break; + case GPIO_HPD_4: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; + break; + case GPIO_HPD_5: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; + break; + case GPIO_HPD_6: + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; + break; + default: + ASSERT_CRITICAL(false); + result = false; + } + break; + case GPIO_ID_GSL: + switch (en) { + case GPIO_GSL_GENLOCK_CLOCK: + /*not implmented*/ + ASSERT_CRITICAL(false); + result = false; + break; + case GPIO_GSL_GENLOCK_VSYNC: + /*not implmented*/ + ASSERT_CRITICAL(false); + result = false; + break; + case GPIO_GSL_SWAPLOCK_A: + /*not implmented*/ + ASSERT_CRITICAL(false); + result = false; + break; + case GPIO_GSL_SWAPLOCK_B: + /*not implmented*/ + ASSERT_CRITICAL(false); + result = false; + + break; + default: + ASSERT_CRITICAL(false); + result = false; + } + break; + case GPIO_ID_SYNC: + case GPIO_ID_VIP_PAD: + default: + ASSERT_CRITICAL(false); + result = false; + } + + if (result) { + info->offset_y = info->offset + 2; + info->offset_en = info->offset + 1; + info->offset_mask = info->offset - 1; + + info->mask_y = info->mask; + info->mask_en = info->mask; + info->mask_mask = info->mask; + } + + return result; +} + +/* function table */ +static const struct hw_translate_funcs funcs = { + .offset_to_id = offset_to_id, + .id_to_offset = id_to_offset, +}; + +/* + * dal_hw_translate_dcn10_init + * + * @brief + * Initialize Hw translate function pointers. + * + * @param + * struct hw_translate *tr - [out] struct of function pointers + * + */ +void dal_hw_translate_dcn20_init(struct hw_translate *tr) +{ + tr->funcs = &funcs; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h new file mode 100644 index 000000000000..01f52c7bed86 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.h @@ -0,0 +1,35 @@ +/* + * 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 + * + */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#ifndef __DAL_HW_TRANSLATE_DCN20_H__ +#define __DAL_HW_TRANSLATE_DCN20_H__ + +struct hw_translate; + +/* Initialize Hw translate function pointers */ +void dal_hw_translate_dcn20_init(struct hw_translate *tr); + +#endif /* __DAL_HW_TRANSLATE_DCN20_H__ */ +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h index bf40725f982f..f91e85b04956 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h @@ -48,6 +48,14 @@ DDC_GPIO_REG_LIST(cd,id),\ .ddc_setup = REG(DC_I2C_DDC ## id ## _SETUP) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + #define DDC_REG_LIST_DCN2(cd, id) \ + DDC_GPIO_REG_LIST(cd, id),\ + .ddc_setup = REG(DC_I2C_DDC ## id ## _SETUP),\ + .phy_aux_cntl = REG(PHY_AUX_CNTL), \ + .dc_gpio_aux_ctrl_5 = REG(DC_GPIO_AUX_CTRL_5) +#endif + #define DDC_GPIO_VGA_REG_LIST_ENTRY(type,cd)\ .type ## _reg = REG(DC_GPIO_DDCVGA_ ## type),\ .type ## _mask = DC_GPIO_DDCVGA_ ## type ## __DC_GPIO_DDCVGA ## cd ## _ ## type ## _MASK,\ @@ -82,6 +90,13 @@ DDC_GPIO_I2C_REG_LIST(cd),\ .ddc_setup = 0 +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define DDC_I2C_REG_LIST_DCN2(cd) \ + DDC_GPIO_I2C_REG_LIST(cd),\ + .ddc_setup = 0,\ + .phy_aux_cntl = REG(PHY_AUX_CNTL), \ + .dc_gpio_aux_ctrl_5 = REG(DC_GPIO_AUX_CTRL_5) +#endif #define DDC_MASK_SH_LIST_COMMON(mask_sh) \ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\ SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_ENABLE, mask_sh),\ @@ -95,10 +110,22 @@ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SDA_PD_DIS, mask_sh),\ SF_DDC(DC_GPIO_I2CPAD_MASK, DC_GPIO_SCL_PD_DIS, mask_sh) +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define DDC_MASK_SH_LIST_DCN2(mask_sh, cd) \ + {DDC_MASK_SH_LIST_COMMON(mask_sh),\ + 0,\ + 0,\ + (PHY_AUX_CNTL__AUX## cd ##_PAD_RXSEL## mask_sh),\ + (DC_GPIO_AUX_CTRL_5__DDC_PAD## cd ##_I2CMODE## mask_sh)} +#endif struct ddc_registers { struct gpio_registers gpio; uint32_t ddc_setup; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint32_t phy_aux_cntl; + uint32_t dc_gpio_aux_ctrl_5; +#endif }; struct ddc_sh_mask { @@ -113,6 +140,11 @@ struct ddc_sh_mask { /* i2cpad_mask */ uint32_t DC_GPIO_SDA_PD_DIS; uint32_t DC_GPIO_SCL_PD_DIS; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + //phy_aux_cntl + uint32_t AUX_PAD_RXSEL; + uint32_t DDC_PAD_I2CMODE; +#endif }; @@ -148,6 +180,27 @@ struct ddc_sh_mask { {\ DDC_I2C_REG_LIST(SCL)\ } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define ddc_data_regs_dcn2(id) \ +{\ + DDC_REG_LIST_DCN2(DATA, id)\ +} + +#define ddc_clk_regs_dcn2(id) \ +{\ + DDC_REG_LIST_DCN2(CLK, id)\ +} + +#define ddc_i2c_data_regs_dcn2 \ +{\ + DDC_I2C_REG_LIST_DCN2(SDA)\ +} + +#define ddc_i2c_clk_regs_dcn2 \ +{\ + DDC_REG_LIST_DCN2(SCL)\ +} +#endif #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_GPIO_DDC_REGS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c index 240cdd8d9689..408857d19c84 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c @@ -147,6 +147,15 @@ static enum gpio_result set_config( AUX_PAD1_MODE, 0); } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { + REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 1); + } + //set DC_IO_aux_rxsel = 2'b01 + if (ddc->regs->phy_aux_cntl != 0) { + REG_UPDATE(phy_aux_cntl, AUX_PAD_RXSEL, 1); + } +#endif return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_MODE_AUX: /* set the AUX pad mode */ @@ -154,6 +163,12 @@ static enum gpio_result set_config( REG_SET(gpio.MASK_reg, regval, AUX_PAD1_MODE, 1); } +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { + REG_UPDATE(dc_gpio_aux_ctrl_5, + DDC_PAD_I2CMODE, 0); + } +#endif return GPIO_RESULT_OK; case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index a15aca47342c..78f528f92907 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -48,6 +48,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_factory_dcn10.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dcn20/hw_factory_dcn20.h" +#endif #include "diagnostics/hw_factory_diag.h" @@ -91,6 +94,12 @@ bool dal_hw_factory_init( return true; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case DCN_VERSION_2_0: + dal_hw_factory_dcn20_init(factory); + return true; +#endif + default: ASSERT_CRITICAL(false); return false; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 77615146b96e..c35fe201d335 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -46,6 +46,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_translate_dcn10.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dcn20/hw_translate_dcn20.h" +#endif #include "diagnostics/hw_translate_diag.h" @@ -81,10 +84,17 @@ bool dal_hw_translate_init( return true; #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: + case DCN_VERSION_1_01: dal_hw_translate_dcn10_init(translate); return true; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case DCN_VERSION_2_0: + dal_hw_translate_dcn20_init(translate); + return true; +#endif + default: BREAK_TO_DEBUGGER(); return false; 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 8dca3b7700e5..0a094d7c9380 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -43,7 +43,12 @@ enum dc_status { DC_FAIL_BANDWIDTH_VALIDATE = 13, /* BW and Watermark validation */ DC_FAIL_SCALING = 14, DC_FAIL_DP_LINK_TRAINING = 15, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + DC_FAIL_DSC_VALIDATE = 16, + DC_NO_DSC_RESOURCE = 17, +#endif DC_FAIL_UNSUPPORTED_1 = 18, + DC_ERROR_UNEXPECTED = -1 }; 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 80709c9343c1..c89393c19232 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -36,6 +36,10 @@ #if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "mpc.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#include "dwb.h" +#include "mcif_wb.h" +#endif #define MAX_CLOCK_SOURCES 7 @@ -99,6 +103,11 @@ struct resource_funcs { struct dc_state *context, bool fast_validate); + int (*populate_dml_pipes)( + struct dc *dc, + struct resource_context *res_ctx, + display_e2e_pipe_params_st *pipes); + enum dc_status (*validate_global)( struct dc *dc, struct dc_state *context); @@ -126,6 +135,18 @@ struct resource_funcs { struct resource_context *res_ctx, const struct resource_pool *pool, struct dc_stream_state *stream); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*populate_dml_writeback_from_context)( + struct dc *dc, + struct resource_context *res_ctx, + display_e2e_pipe_params_st *pipes); + + void (*set_mcif_arb_params)( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt); +#endif }; @@ -154,6 +175,20 @@ struct resource_pool { struct dce_i2c_sw *sw_i2cs[MAX_PIPES]; bool i2c_hw_buffer_in_use; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dwbc *dwbc[MAX_DWB_PIPES]; + struct mcif_wb *mcif_wb[MAX_DWB_PIPES]; + struct { + unsigned int gsl_0:1; + unsigned int gsl_1:1; + unsigned int gsl_2:1; + } gsl_groups; +#endif + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct display_stream_compressor *dscs[MAX_PIPES]; +#endif + unsigned int pipe_count; unsigned int underlay_pipe_index; unsigned int stream_enc_count; @@ -164,7 +199,11 @@ struct resource_pool { unsigned int dchub_ref_clock_inKhz; } ref_clocks; unsigned int timing_generator_count; + unsigned int mpcc_count; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + unsigned int writeback_pipe_count; +#endif /* * reserved clock source for DP */ @@ -189,10 +228,15 @@ struct resource_pool { struct dcn_fe_bandwidth { int dppclk_khz; + }; struct stream_resource { struct output_pixel_processor *opp; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct display_stream_compressor *dsc; + int dscclk_khz; +#endif struct timing_generator *tg; struct stream_encoder *stream_enc; struct audio *audio; @@ -201,6 +245,12 @@ struct stream_resource { struct encoder_info_frame encoder_info_frame; struct abm *abm; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* There are only (num_pipes+1)/2 groups. 0 means unassigned, + * otherwise it's using group number 'gsl_group-1' + */ + uint8_t gsl_group; +#endif }; struct plane_resource { @@ -257,6 +307,10 @@ struct pipe_ctx { struct _vcs_dpi_display_pipe_dest_params_st pipe_dlg_param; #endif union pipe_update_flags update_flags; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + struct dwbc *dwbc; + struct mcif_wb *mcif_wb; +#endif }; struct resource_context { @@ -265,6 +319,9 @@ struct resource_context { bool is_audio_acquired[MAX_PIPES]; uint8_t clock_source_ref_count[MAX_CLOCK_SOURCES]; uint8_t dp_clock_source_ref_count; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + bool is_dsc_acquired[MAX_PIPES]; +#endif }; struct dce_bw_output { @@ -284,9 +341,18 @@ struct dce_bw_output { int blackout_recovery_time_us; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dcn_bw_writeback { + struct mcif_arb_params mcif_wb_arb[MAX_DWB_PIPES]; +}; +#endif + struct dcn_bw_output { struct dc_clocks clk; struct dcn_watermark_set watermarks; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dcn_bw_writeback bw_writeback; +#endif }; union bw_output { diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index a37255c757e0..2d95eff94239 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -62,4 +62,11 @@ bool is_dp_active_dongle(const struct dc_link *link); void dp_enable_mst_on_sink(struct dc_link *link, bool enable); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +void dp_set_fec_ready(struct dc_link *link, bool ready); +void dp_set_fec_enable(struct dc_link *link, bool enable); +bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); +bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx); +#endif + #endif /* __DC_LINK_DP_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index 721e13135e76..36ebd5bc7863 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -53,8 +53,6 @@ struct clk_mgr_funcs { void (*enable_pme_wa) (struct clk_mgr *clk_mgr); }; -void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr_base); - struct clk_mgr { struct dc_context *ctx; struct clk_mgr_funcs *funcs; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h index 6e189b1283aa..0835ac041acf 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr_internal.h @@ -27,6 +27,7 @@ #define __DAL_CLK_MGR_INTERNAL_H__ #include "clk_mgr.h" +#include "dc.h" /* * only thing needed from here is MEMORY_TYPE_MULTIPLIER_CZ, which is also @@ -34,6 +35,29 @@ */ #include "resource.h" + +/* Starting DID for each range */ +enum dentist_base_divider_id { + DENTIST_BASE_DID_1 = 0x08, + DENTIST_BASE_DID_2 = 0x40, + DENTIST_BASE_DID_3 = 0x60, + DENTIST_BASE_DID_4 = 0x7e, + DENTIST_MAX_DID = 0x7f +}; + +/* Starting point and step size for each divider range.*/ +enum dentist_divider_range { + DENTIST_DIVIDER_RANGE_1_START = 8, /* 2.00 */ + DENTIST_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */ + DENTIST_DIVIDER_RANGE_2_START = 64, /* 16.00 */ + DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ + DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ + DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */ + DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */ + DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 +}; + /* *************************************************************************************** ****************** Clock Manager Private Macros and Defines *************************** @@ -65,6 +89,18 @@ #define CLK_COMMON_REG_LIST_DCN_BASE() \ SR(DENTIST_DISPCLK_CNTL) +#define VBIOS_SMU_MSG_BOX_REG_LIST_RV() \ + .MP1_SMN_C2PMSG_91 = mmMP1_SMN_C2PMSG_91, \ + .MP1_SMN_C2PMSG_83 = mmMP1_SMN_C2PMSG_83, \ + .MP1_SMN_C2PMSG_67 = mmMP1_SMN_C2PMSG_67 + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#define CLK_REG_LIST_NV10() \ + SR(DENTIST_DISPCLK_CNTL), \ + CLK_SRI(CLK3_CLK_PLL_REQ, CLK3, 0), \ + CLK_SRI(CLK3_CLK2_DFS_CNTL, CLK3, 0) +#endif + #define CLK_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -82,6 +118,17 @@ CLK_SF(MP1_SMN_C2PMSG_83, CONTENT, mask_sh),\ CLK_SF(MP1_SMN_C2PMSG_91, CONTENT, mask_sh), +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#define CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh) \ + CLK_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, mask_sh),\ + CLK_SF(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, mask_sh) + +#define CLK_MASK_SH_LIST_NV10(mask_sh) \ + CLK_COMMON_MASK_SH_LIST_DCN20_BASE(mask_sh),\ + CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_int, mask_sh),\ + CLK_SF(CLK3_0_CLK3_CLK_PLL_REQ, FbMult_frac, mask_sh) +#endif #define CLK_REG_FIELD_LIST(type) \ type DPREFCLK_SRC_SEL; \ @@ -94,21 +141,46 @@ ****************** Clock Manager Private Structures *********************************** *************************************************************************************** */ +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#define CLK20_REG_FIELD_LIST(type) \ + type DENTIST_DPPCLK_WDIVIDER; \ + type DENTIST_DPPCLK_CHG_DONE; \ + type FbMult_int; \ + type FbMult_frac; +#endif -struct clk_mgr_registers { - uint32_t DPREFCLK_CNTL; - uint32_t DENTIST_DISPCLK_CNTL; - -}; +#define VBIOS_SMU_REG_FIELD_LIST(type) \ + type CONTENT; struct clk_mgr_shift { CLK_REG_FIELD_LIST(uint8_t) +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + CLK20_REG_FIELD_LIST(uint8_t) +#endif + VBIOS_SMU_REG_FIELD_LIST(uint32_t) }; struct clk_mgr_mask { CLK_REG_FIELD_LIST(uint32_t) +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + CLK20_REG_FIELD_LIST(uint32_t) +#endif + VBIOS_SMU_REG_FIELD_LIST(uint32_t) }; +struct clk_mgr_registers { + uint32_t DPREFCLK_CNTL; + uint32_t DENTIST_DISPCLK_CNTL; + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + uint32_t CLK3_CLK2_DFS_CNTL; + uint32_t CLK3_CLK_PLL_REQ; +#endif + + uint32_t MP1_SMN_C2PMSG_67; + uint32_t MP1_SMN_C2PMSG_83; + uint32_t MP1_SMN_C2PMSG_91; +}; struct state_dependent_clocks { int display_clk_khz; @@ -202,6 +274,12 @@ static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_cl return ((safe_to_lower && calc_clk < cur_clk) || calc_clk > cur_clk); } +static inline bool should_update_pstate_support(bool safe_to_lower, bool calc_support, bool cur_support) +{ + // Whenever we are transitioning pstate support, we always want to notify prior to committing state + return (calc_support != cur_support) ? !safe_to_lower : false; +} + int clk_mgr_helper_get_active_display_cnt( struct dc *dc, struct dc_state *context); 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 93667e8b23b3..959f5b654611 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -52,11 +52,69 @@ struct dcn_hubbub_wm { struct dcn_hubbub_wm_set sets[4]; }; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +enum dcn_hubbub_page_table_depth { + DCN_PAGE_TABLE_DEPTH_1_LEVEL, + DCN_PAGE_TABLE_DEPTH_2_LEVEL, + DCN_PAGE_TABLE_DEPTH_3_LEVEL, + DCN_PAGE_TABLE_DEPTH_4_LEVEL +}; + +enum dcn_hubbub_page_table_block_size { + DCN_PAGE_TABLE_BLOCK_SIZE_4KB, + DCN_PAGE_TABLE_BLOCK_SIZE_64KB +}; + +struct dcn_hubbub_phys_addr_config { + struct { + uint64_t fb_top; + uint64_t fb_offset; + uint64_t fb_base; + uint64_t agp_top; + uint64_t agp_bot; + uint64_t agp_base; + } system_aperture; + + struct { + uint64_t page_table_start_addr; + uint64_t page_table_end_addr; + uint64_t page_table_base_addr; + } gart_config; +}; + +struct dcn_hubbub_virt_addr_config { + uint64_t page_table_start_addr; + uint64_t page_table_end_addr; + enum dcn_hubbub_page_table_block_size page_table_block_size; + enum dcn_hubbub_page_table_depth page_table_depth; + uint64_t page_table_base_addr; +}; + +struct hubbub_addr_config { + struct dcn_hubbub_phys_addr_config pa_config; + struct dcn_hubbub_virt_addr_config va_config; + struct { + uint64_t aperture_check_fault; + uint64_t generic_fault; + } default_addrs; +}; + +#endif struct hubbub_funcs { void (*update_dchub)( struct hubbub *hubbub, struct dchub_init_data *dh_data); +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + int (*init_dchub_sys_ctx)( + struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config); + void (*init_vm_ctx)( + struct hubbub *hubbub, + struct dcn_hubbub_virt_addr_config *va_config, + int vmid); + +#endif bool (*get_dcc_compression_cap)(struct hubbub *hubbub, const struct dc_dcc_surface_param *input, struct dc_surface_dcc_cap *output); 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 b55c5a2e56e2..60c671fcf186 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -36,7 +36,13 @@ struct dpp { struct dpp_caps *caps; struct pwl_params regamma_params; struct pwl_params degamma_params; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct dpp_cursor_attributes cur_attr; +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct pwl_params shaper_params; +#endif }; struct dpp_input_csc_matrix { @@ -49,6 +55,34 @@ struct dpp_grph_csc_adjustment { enum graphics_gamut_adjust_type gamut_adjust_type; }; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +struct cnv_color_keyer_params { + int color_keyer_en; + int color_keyer_mode; + int color_keyer_alpha_low; + int color_keyer_alpha_high; + int color_keyer_red_low; + int color_keyer_red_high; + int color_keyer_green_low; + int color_keyer_green_high; + int color_keyer_blue_low; + int color_keyer_blue_high; +}; + +/* new for dcn2: set the 8bit alpha values based on the 2 bit alpha + *ALPHA_2BIT_LUT. ALPHA_2BIT_LUT0 default: 0b00000000 + *ALPHA_2BIT_LUT. ALPHA_2BIT_LUT1 default: 0b01010101 + *ALPHA_2BIT_LUT. ALPHA_2BIT_LUT2 default: 0b10101010 + *ALPHA_2BIT_LUT. ALPHA_2BIT_LUT3 default: 0b11111111 + */ +struct cnv_alpha_2bit_lut { + int lut0; + int lut1; + int lut2; + int lut3; +}; +#endif + struct dcn_dpp_state { uint32_t is_enabled; uint32_t igam_lut_mode; @@ -155,7 +189,12 @@ struct dpp_funcs { enum surface_pixel_format format, enum expansion_mode mode, struct dc_csc_transform input_csc_color_matrix, +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + enum dc_color_space input_color_space, + struct cnv_alpha_2bit_lut *alpha_2bit_lut); +#else enum dc_color_space input_color_space); +#endif void (*dpp_full_bypass)(struct dpp *dpp_base); @@ -184,6 +223,20 @@ struct dpp_funcs { bool dppclk_div, bool enable); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + bool (*dpp_program_blnd_lut)( + struct dpp *dpp, + const struct pwl_params *params); + bool (*dpp_program_shaper_lut)( + struct dpp *dpp, + const struct pwl_params *params); + bool (*dpp_program_3dlut)( + struct dpp *dpp, + struct tetrahedral_params *params); + void (*dpp_cnv_set_alpha_keyer)( + struct dpp *dpp_base, + struct cnv_color_keyer_params *color_keyer); +#endif }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h new file mode 100644 index 000000000000..c905d020b59e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h @@ -0,0 +1,101 @@ +/* + * 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. + * + * Authors: AMD + * + */ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#ifndef __DAL_DSC_H__ +#define __DAL_DSC_H__ + +#include "dc_dsc.h" +#include "dc_hw_types.h" +#include "dc_dp_types.h" + +/* Input parameters for configuring DSC from the outside of DSC */ +struct dsc_config { + uint32_t pic_width; + uint32_t pic_height; + enum dc_pixel_encoding pixel_encoding; + enum dc_color_depth color_depth; /* Bits per component */ + struct dc_dsc_config dc_dsc_cfg; +}; + + +/* Output parameters for configuring DSC-related part of OPTC */ +struct dsc_optc_config { + uint32_t slice_width; /* Slice width in pixels */ + uint32_t bytes_per_pixel; /* Bytes per pixel in u3.28 format */ + bool is_pixel_format_444; /* 'true' if pixel format is 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4)' */ +}; + + +struct dcn_dsc_state { + uint32_t dsc_clock_en; + uint32_t dsc_slice_width; + uint32_t dsc_bytes_per_pixel; +}; + + +/* DSC encoder capabilities + * They differ from the DPCD DSC caps because they are based on AMD DSC encoder caps. + */ +union dsc_enc_slice_caps { + struct { + uint8_t NUM_SLICES_1 : 1; + uint8_t NUM_SLICES_2 : 1; + uint8_t NUM_SLICES_3 : 1; /* This one is not per DSC spec, but our encoder supports it */ + uint8_t NUM_SLICES_4 : 1; + uint8_t NUM_SLICES_8 : 1; + } bits; + uint8_t raw; +}; + +struct dsc_enc_caps { + uint8_t dsc_version; + union dsc_enc_slice_caps slice_caps; + int32_t lb_bit_depth; + bool is_block_pred_supported; + union dsc_color_formats color_formats; + union dsc_color_depth color_depth; + int32_t max_total_throughput_mps; /* Maximum total throughput with all the slices combined */ + int32_t max_slice_width; + uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */ +}; + +struct display_stream_compressor { + const struct dsc_funcs *funcs; + struct dc_context *ctx; + int inst; +}; + +struct dsc_funcs { + void (*dsc_get_enc_caps)(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz); + void (*dsc_read_state)(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); + bool (*dsc_validate_stream)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); + void (*dsc_set_config)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg, uint8_t *dsc_packed_pps); + void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe); + void (*dsc_disable)(struct display_stream_compressor *dsc); +}; + +#endif +#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h new file mode 100644 index 000000000000..a3409294ae0c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h @@ -0,0 +1,180 @@ +/* Copyright 2012-17 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 __DC_DWBC_H__ +#define __DC_DWBC_H__ + +#include "dc_hw_types.h" + + +#define DWB_SW_V2 1 +#define DWB_MCIF_BUF_COUNT 4 + +/* forward declaration of mcif_wb struct */ +struct mcif_wb; + +enum dce_version; + +enum dwb_sw_version { + dwb_ver_1_0 = 1, + dwb_ver_2_0 = 2, +}; + +enum dwb_source { + dwb_src_scl = 0, /* for DCE7x/9x, DCN won't support. */ + dwb_src_blnd, /* for DCE7x/9x */ + dwb_src_fmt, /* for DCE7x/9x */ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + dwb_src_otg0 = 0x100, /* for DCN1.x/DCN2.x, register: mmDWB_SOURCE_SELECT */ + dwb_src_otg1, /* for DCN1.x/DCN2.x */ + dwb_src_otg2, /* for DCN1.x/DCN2.x */ + dwb_src_otg3, /* for DCN1.x/DCN2.x */ +#else + dwb_src_otg0 = 0x100, /* for DCN1.x, register: mmDWB_SOURCE_SELECT */ + dwb_src_otg1, /* for DCN1.x */ + dwb_src_otg2, /* for DCN1.x */ + dwb_src_otg3, /* for DCN1.x */ +#endif + dwb_src_mpc0 = 0x200, /* for DCN2, register: mmMPC_DWB0_MUX, mmMPC_DWB1_MUX, mmMPC_DWB2_MUX */ + dwb_src_mpc1, /* for DCN2 */ + dwb_src_mpc2, /* for DCN2 */ + dwb_src_mpc3, /* for DCN2 */ + dwb_src_mpc4, /* for DCN2 */ +}; + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +/* DCN1.x, DCN2.x support 2 pipes */ +#else +/* DCN1.x supports 2 pipes */ +#endif +enum dwb_pipe { + dwb_pipe0 = 0, +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) + dwb_pipe1, +#endif + dwb_pipe_max_num, +}; + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +enum dwb_frame_capture_enable { + DWB_FRAME_CAPTURE_DISABLE = 0, + DWB_FRAME_CAPTURE_ENABLE = 1, +}; + +enum wbscl_coef_filter_type_sel { + WBSCL_COEF_LUMA_VERT_FILTER = 0, + WBSCL_COEF_CHROMA_VERT_FILTER = 1, + WBSCL_COEF_LUMA_HORZ_FILTER = 2, + WBSCL_COEF_CHROMA_HORZ_FILTER = 3 +}; + +#endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dwb_warmup_params { + bool warmup_en; /* false: normal mode, true: enable pattern generator */ + bool warmup_mode; /* false: 420, true: 444 */ + bool warmup_depth; /* false: 8bit, true: 10bit */ + int warmup_data; /* Data to be sent by pattern generator (same for each pixel component) */ + int warmup_width; /* Pattern width (pixels) */ + int warmup_height; /* Pattern height (lines) */ +}; +#endif + +struct dwb_caps { + enum dce_version hw_version; /* DCN engine version. */ + enum dwb_sw_version sw_version; /* DWB sw implementation version. */ + unsigned int reserved[6]; /* Reserved for future use, MUST BE 0. */ + unsigned int adapter_id; + unsigned int num_pipes; /* number of DWB pipes */ + struct { + unsigned int support_dwb :1; + unsigned int support_ogam :1; + unsigned int support_wbscl :1; + unsigned int support_ocsc :1; + unsigned int support_stereo :1; + } caps; + unsigned int reserved2[9]; /* Reserved for future use, MUST BE 0. */ +}; + +struct dwbc { + const struct dwbc_funcs *funcs; + struct dc_context *ctx; + int inst; + struct mcif_wb *mcif; + bool status; + int inputSrcSelect; + bool dwb_output_black; + enum dc_transfer_func_predefined tf; + enum dc_color_space output_color_space; + bool dwb_is_efc_transition; + bool dwb_is_drc; + int wb_src_plane_inst;/*hubp, mpcc, inst*/ + bool update_privacymask; + uint32_t mask_id; + +}; + +struct dwbc_funcs { + bool (*get_caps)( + struct dwbc *dwbc, + struct dwb_caps *caps); + + bool (*enable)( + struct dwbc *dwbc, + struct dc_dwb_params *params); + + bool (*disable)(struct dwbc *dwbc); + + bool (*update)( + struct dwbc *dwbc, + struct dc_dwb_params *params); + + bool (*is_enabled)( + struct dwbc *dwbc); + + void (*set_stereo)( + struct dwbc *dwbc, + struct dwb_stereo_params *stereo_params); + + void (*set_new_content)( + struct dwbc *dwbc, + bool is_new_content); + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + + void (*set_warmup)( + struct dwbc *dwbc, + struct dwb_warmup_params *warmup_params); + +#endif + + bool (*get_dwb_status)( + struct dwbc *dwbc); + void (*dwb_set_scaler)( + struct dwbc *dwbc, + struct dc_dwb_params *params); +}; + +#endif 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 455df4999797..51bff8717cc9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -28,6 +28,8 @@ #include "mem_input.h" +#define OPP_ID_INVALID 0xf + enum cursor_pitch { CURSOR_PITCH_64_PIXELS = 0, @@ -36,6 +38,9 @@ enum cursor_pitch { }; enum cursor_lines_per_chunk { +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + CURSOR_LINE_PER_CHUNK_1 = 0, /* new for DCN2 */ +#endif CURSOR_LINE_PER_CHUNK_2 = 1, CURSOR_LINE_PER_CHUNK_4, CURSOR_LINE_PER_CHUNK_8, @@ -78,8 +83,7 @@ struct hubp_funcs { bool (*hubp_program_surface_flip_and_addr)( struct hubp *hubp, const struct dc_plane_address *address, - bool flip_immediate, - uint8_t vmid); + bool flip_immediate); void (*hubp_program_pte_vm)( struct hubp *hubp, @@ -132,6 +136,28 @@ struct hubp_funcs { unsigned int (*hubp_get_underflow_status)(struct hubp *hubp); void (*hubp_init)(struct hubp *hubp); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*dmdata_set_attributes)( + struct hubp *hubp, + const struct dc_dmdata_attributes *attr); + + void (*dmdata_load)( + struct hubp *hubp, + uint32_t dmdata_sw_size, + const uint32_t *dmdata_sw_data); + bool (*dmdata_status_done)(struct hubp *hubp); + void (*hubp_enable_tripleBuffer)( + struct hubp *hubp, + bool enable); + + bool (*hubp_is_triplebuffer_enabled)( + struct hubp *hubp); + + void (*hubp_set_flip_control_surface_gsl)( + struct hubp *hubp, + bool enable); +#endif + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index 4c8e2c6fb6db..8759ec03aede 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -35,6 +35,9 @@ ******************************************************************************/ #define MAX_PIPES 6 +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define MAX_DWB_PIPES 1 +#endif struct gamma_curve { uint32_t offset; @@ -77,6 +80,37 @@ struct pwl_result_data { uint32_t delta_blue_reg; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dc_rgb { + uint32_t red; + uint32_t green; + uint32_t blue; +}; + +struct tetrahedral_17x17x17 { + struct dc_rgb lut0[1229]; + struct dc_rgb lut1[1228]; + struct dc_rgb lut2[1228]; + struct dc_rgb lut3[1228]; +}; +struct tetrahedral_9x9x9 { + struct dc_rgb lut0[183]; + struct dc_rgb lut1[182]; + struct dc_rgb lut2[182]; + struct dc_rgb lut3[182]; +}; + +struct tetrahedral_params { + union { + struct tetrahedral_17x17x17 tetrahedral_17; + struct tetrahedral_9x9x9 tetrahedral_9; + }; + bool use_tetrahedral_9; + bool use_12bits; + +}; +#endif + /* arr_curve_points - regamma regions/segments specification * arr_points - beginning and end point specified separately (only one on DCE) * corner_points - beginning and end point for all 3 colors (DCN) @@ -160,6 +194,14 @@ enum opp_regamma { OPP_REGAMMA_USER }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +enum optc_dsc_mode { + OPTC_DSC_DISABLED = 0, + OPTC_DSC_ENABLED_444 = 1, /* 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4) */ + OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED = 2 /* Native 4:2:2 or 4:2:0 */ +}; +#endif + struct dc_bias_and_scale { uint16_t scale_red; uint16_t bias_red; @@ -181,7 +223,12 @@ enum test_pattern_mode { TEST_PATTERN_MODE_VERTICALBARS, TEST_PATTERN_MODE_HORIZONTALBARS, TEST_PATTERN_MODE_SINGLERAMP_RGB, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + TEST_PATTERN_MODE_DUALRAMP_RGB, + TEST_PATTERN_MODE_XR_BIAS_RGB +#else TEST_PATTERN_MODE_DUALRAMP_RGB +#endif }; enum test_pattern_color_format { @@ -203,7 +250,8 @@ enum controller_dp_test_pattern { CONTROLLER_DP_TEST_PATTERN_RESERVED_8, CONTROLLER_DP_TEST_PATTERN_RESERVED_9, CONTROLLER_DP_TEST_PATTERN_RESERVED_A, - CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA, + CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR }; enum dc_lut_mode { 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 ca162079a41b..e5e8640a9ef3 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 @@ -113,9 +113,26 @@ struct link_encoder { struct encoder_feature_support features; enum transmitter transmitter; enum hpd_source_id hpd_source; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + bool usbc_combo_phy; +#endif }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +struct link_enc_state { + + uint32_t dphy_fec_en; + uint32_t dphy_fec_ready_shadow; + uint32_t dphy_fec_active_status; + +}; +#endif + struct link_encoder_funcs { +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + void (*read_state)( + struct link_encoder *enc, struct link_enc_state *s); +#endif bool (*validate_output_with_stream)( struct link_encoder *enc, const struct dc_stream_state *stream); void (*hw_init)(struct link_encoder *enc); @@ -156,6 +173,16 @@ struct link_encoder_funcs { bool (*is_dig_enabled)(struct link_encoder *enc); unsigned int (*get_dig_frontend)(struct link_encoder *enc); void (*destroy)(struct link_encoder **enc); + +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*fec_set_enable)(struct link_encoder *enc, + bool enable); + + void (*fec_set_ready)(struct link_encoder *enc, + bool ready); + + bool (*fec_is_active)(struct link_encoder *enc); +#endif }; #endif /* LINK_ENCODER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h new file mode 100644 index 000000000000..a5c8d92fc5c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mcif_wb.h @@ -0,0 +1,105 @@ +/* Copyright 2012-17 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 __DC_MCIF_WB_H__ +#define __DC_MCIF_WB_H__ + +#include "dc_hw_types.h" + + +enum mmhubbub_wbif_mode { + PACKED_444 = 0, + PACKED_444_FP16 = 1, + PLANAR_420_8BPC = 2, + PLANAR_420_10BPC = 3 +}; + +struct mcif_arb_params { + + unsigned int time_per_pixel; + unsigned int cli_watermark[4]; + unsigned int pstate_watermark[4]; + unsigned int arbitration_slice; + unsigned int slice_lines; + unsigned int max_scaled_time; +}; + +struct mcif_irq_params { + unsigned int sw_int_en; + unsigned int sw_slice_int_en; + unsigned int sw_overrun_int_en; + unsigned int vce_int_en; + unsigned int vce_slice_int_en; +}; + + +/* / - mcif_wb_frame_dump_info is the info of the dumping WB data */ +struct mcif_wb_frame_dump_info { + unsigned int size; + unsigned int width; + unsigned int height; + unsigned int luma_pitch; + unsigned int chroma_pitch; + enum dwb_scaler_mode format; +}; + +struct mcif_wb { + const struct mcif_wb_funcs *funcs; + struct dc_context *ctx; + int inst; +}; + +struct mcif_wb_funcs { + + void (*enable_mcif)(struct mcif_wb *mcif_wb); + + void (*disable_mcif)(struct mcif_wb *mcif_wb); + + void (*config_mcif_buf)( + struct mcif_wb *mcif_wb, + struct mcif_buf_params *params, + unsigned int dest_height); + + void (*config_mcif_arb)( + struct mcif_wb *mcif_wb, + struct mcif_arb_params *params); + + void (*config_mcif_irq)( + struct mcif_wb *mcif_wb, + struct mcif_irq_params *params); + + void (*dump_frame)( + struct mcif_wb *mcif_wb, + struct mcif_buf_params *mcif_params, + enum dwb_scaler_mode out_format, + unsigned int dest_width, + unsigned int dest_height, + struct mcif_wb_frame_dump_info *dump_info, + unsigned char *luma_buffer, + unsigned char *chroma_buffer, + unsigned char *dest_luma_buffer, + unsigned char *dest_chroma_buffer); +}; + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h index caf74e3c836f..45b94e319cd4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -31,6 +31,10 @@ #define MAX_MPCC 6 #define MAX_OPP 6 +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define MAX_DWB 1 +#endif + enum mpc_output_csc_mode { MPC_OUTPUT_CSC_DISABLE = 0, MPC_OUTPUT_CSC_COEF_A, @@ -62,6 +66,14 @@ struct mpcc_blnd_cfg { int global_alpha; bool overlap_only; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + /* MPCC top/bottom gain settings */ + int bottom_gain_mode; + int background_color_bpc; + int top_gain; + int bottom_inside_gain; + int bottom_outside_gain; +#endif }; struct mpcc_sm_cfg { @@ -78,6 +90,17 @@ struct mpcc_sm_cfg { int force_next_field_polarity; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct mpc_denorm_clamp { + int clamp_max_r_cr; + int clamp_min_r_cr; + int clamp_max_g_y; + int clamp_min_g_y; + int clamp_max_b_cb; + int clamp_min_b_cb; +}; +#endif + /* * MPCC connection and blending configuration for a single MPCC instance. * This struct is used as a node in an MPC tree. @@ -103,6 +126,9 @@ struct mpc { struct dc_context *ctx; struct mpcc mpcc_array[MAX_MPCC]; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + struct pwl_params blender_params; +#endif }; struct mpcc_state { @@ -200,6 +226,32 @@ struct mpc_funcs { struct mpc *mpc, struct mpc_tree *tree); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*set_denorm)(struct mpc *mpc, + int opp_id, + enum dc_color_depth output_depth); + + void (*set_denorm_clamp)( + struct mpc *mpc, + int opp_id, + struct mpc_denorm_clamp denorm_clamp); + + void (*set_output_csc)(struct mpc *mpc, + int opp_id, + const uint16_t *regval, + enum mpc_output_csc_mode ocsc_mode); + + void (*set_ocsc_default)(struct mpc *mpc, + int opp_id, + enum dc_color_space color_space, + enum mpc_output_csc_mode ocsc_mode); + + void (*set_output_gamma)( + struct mpc *mpc, + int mpcc_id, + const struct pwl_params *params); +#endif + }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h index d974d9e18612..5d8a7bcccc6f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -262,6 +262,9 @@ struct oppbuf_params { enum oppbuf_display_segmentation mso_segmentation; uint32_t mso_overlap_pixel_num; uint32_t pixel_repetition; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + uint32_t num_segment_padded_pixels; +#endif }; struct opp_funcs { @@ -301,6 +304,32 @@ struct opp_funcs { struct output_pixel_processor *opp, bool enable); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*opp_set_disp_pattern_generator)( + struct output_pixel_processor *opp, + enum controller_dp_test_pattern test_pattern, + enum dc_color_depth color_depth, + const struct tg_color *solid_color, + int width, + int height); + + bool (*dpg_is_blanked)( + struct output_pixel_processor *opp); + + void (*opp_convert_pti)( + struct output_pixel_processor *opp, + bool enable, + bool polarity); + + void (*opp_dpg_set_blank_color)( + struct output_pixel_processor *opp, + const struct tg_color *color); + + void (*opp_program_left_edge_extra_pixel)( + struct output_pixel_processor *opp, + bool count); +#endif + }; #endif 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 74db1d82fa35..ed7d9588b309 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 @@ -65,11 +65,20 @@ struct audio_clock_info { uint32_t cts_48khz; }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +enum dynamic_metadata_mode { + dmdata_dp, + dmdata_hdmi, + dmdata_dolby_vision +}; +#endif + struct encoder_info_frame { /* auxiliary video information */ struct dc_info_packet avi; struct dc_info_packet gamut; struct dc_info_packet vendor; + struct dc_info_packet hfvsif; /* source product description */ struct dc_info_packet spd; /* video stream configuration */ @@ -81,6 +90,9 @@ struct encoder_info_frame { struct encoder_unblank_param { struct dc_link_settings link_settings; struct dc_crtc_timing timing; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + bool odm; +#endif }; struct encoder_set_dp_phy_pattern_param { @@ -97,7 +109,22 @@ struct stream_encoder { enum engine_id id; }; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +struct enc_state { + uint32_t dsc_mode; // DISABLED 0; 1 or 2 indicate enabled state. + uint32_t dsc_slice_width; + uint32_t sec_gsp_pps_line_num; + uint32_t vbid6_line_reference; + uint32_t vbid6_line_num; + uint32_t sec_gsp_pps_enable; + uint32_t sec_stream_enable; +}; +#endif + struct stream_encoder_funcs { + #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s); + #endif void (*dp_set_stream_attribute)( struct stream_encoder *enc, struct dc_crtc_timing *crtc_timing, @@ -184,6 +211,25 @@ struct stream_encoder_funcs { struct stream_encoder *enc, int tg_inst); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + void (*dp_set_dsc_config)( + struct stream_encoder *enc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width, + uint8_t *dsc_packed_pps); +#endif + + void (*set_dynamic_metadata)(struct stream_encoder *enc, + bool enable, + uint32_t hubp_requestor_id, + enum dynamic_metadata_mode dmdata_mode); + + void (*dp_set_odm_combine)( + struct stream_encoder *enc, + bool odm_combine); +#endif }; #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 a89d0cf59cca..5e93bc0e8ff9 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 @@ -188,6 +188,12 @@ struct timing_generator_funcs { void (*unlock)(struct timing_generator *tg); void (*lock)(struct timing_generator *tg); void (*lock_global)(struct timing_generator *tg); + void (*lock_doublebuffer_disable)(struct timing_generator *tg); + void (*lock_doublebuffer_enable)(struct timing_generator *tg); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void(*triplebuffer_unlock)(struct timing_generator *tg); + void(*triplebuffer_lock)(struct timing_generator *tg); +#endif void (*enable_reset_trigger)(struct timing_generator *tg, int source_tg_inst); void (*enable_crtc_reset)(struct timing_generator *tg, @@ -224,6 +230,16 @@ struct timing_generator_funcs { bool (*is_optc_underflow_occurred)(struct timing_generator *tg); void (*clear_optc_underflow)(struct timing_generator *tg); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*set_dwb_source)(struct timing_generator *optc, + uint32_t dwb_pipe_inst); + + void (*get_optc_source)(struct timing_generator *optc, + uint32_t *num_of_input_segments, + uint32_t *seg0_src_sel, + uint32_t *seg1_src_sel); +#endif + /** * Configure CRCs for the given timing generator. Return false if TG is * not on. @@ -243,6 +259,22 @@ struct timing_generator_funcs { void (*set_vtg_params)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + void (*set_dsc_config)(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width); +#endif + void (*set_odm_bypass)(struct timing_generator *tg, const struct dc_crtc_timing *dc_crtc_timing); + void (*set_odm_combine)(struct timing_generator *tg, int combine_opp_id, + int mpcc_hactive, enum dc_pixel_encoding pixel_encoding); + void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params); + void (*set_gsl_source_select)(struct timing_generator *optc, + int group_idx, + uint32_t gsl_ready_signal); +#endif }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h index 037beb0a2a27..76de0e4284e0 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/vmid.h @@ -44,6 +44,7 @@ struct dcn_vmid_page_table_config { uint64_t page_table_end_addr; enum dcn_hubbub_page_table_depth depth; enum dcn_hubbub_page_table_block_size block_size; + uint64_t page_table_base_addr; }; #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 eb1c12ed026a..4d56d48a3179 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -65,11 +65,19 @@ struct dce_hwseq { struct pipe_ctx; struct dc_state; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +struct dc_stream_status; +struct dc_writeback_info; +#endif struct dchub_init_data; struct dc_static_screen_events; struct resource_pool; struct resource_context; struct stream_resource; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +struct dc_phy_addr_space_config; +struct dc_virtual_addr_space_config; +#endif struct hw_sequencer_funcs { @@ -102,6 +110,16 @@ struct hw_sequencer_funcs { uint16_t *matrix, int opp_id); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*program_triplebuffer)( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + bool enableTripleBuffer); + void (*set_flip_control_gsl)( + struct pipe_ctx *pipe_ctx, + bool flip_immediate); +#endif + void (*update_plane_addr)( const struct dc *dc, struct pipe_ctx *pipe_ctx); @@ -114,6 +132,17 @@ struct hw_sequencer_funcs { struct dce_hwseq *hws, struct dchub_init_data *dh_data); +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + int (*init_sys_ctx)( + struct dce_hwseq *hws, + struct dc *dc, + struct dc_phy_addr_space_config *pa_config); + void (*init_vm_ctx)( + struct dce_hwseq *hws, + struct dc *dc, + struct dc_virtual_addr_space_config *va_config, + int vmid); +#endif void (*update_mpcc)( struct dc *dc, struct pipe_ctx *pipe_ctx); @@ -181,6 +210,7 @@ struct hw_sequencer_funcs { struct dc *dc, struct pipe_ctx *pipe, bool lock); + void (*pipe_control_lock_global)( struct dc *dc, struct pipe_ctx *pipe, @@ -197,6 +227,13 @@ struct hw_sequencer_funcs { struct dc *dc, struct dc_state *context); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + bool (*update_bandwidth)( + struct dc *dc, + struct dc_state *context); + bool (*dmdata_status_done)(struct pipe_ctx *pipe_ctx); +#endif + void (*set_drr)(struct pipe_ctx **pipe_ctx, int num_pipes, int vmin, int vmax); @@ -240,7 +277,23 @@ struct hw_sequencer_funcs { void (*setup_periodic_interrupt)(struct pipe_ctx *pipe_ctx, enum vline_select vline); void (*setup_vupdate_interrupt)(struct pipe_ctx *pipe_ctx); + bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + void (*update_odm)(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx); + void (*program_all_writeback_pipes_in_tree)( + struct dc *dc, + const struct dc_stream_state *stream, + struct dc_state *context); + void (*update_writeback)(struct dc *dc, + const struct dc_stream_status *stream_status, + struct dc_writeback_info *wb_info); + void (*enable_writeback)(struct dc *dc, + const struct dc_stream_status *stream_status, + struct dc_writeback_info *wb_info); + void (*disable_writeback)(struct dc *dc, + unsigned int dwb_pipe_inst); +#endif }; void color_space_to_black_color( diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 08915b737799..47f81072d7e9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -44,6 +44,12 @@ struct resource_caps { int num_pll; int num_dwb; int num_ddc; +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + int num_vmid; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + int num_dsc; +#endif +#endif }; struct resource_straps { diff --git a/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h index 193407f76a80..8bfcef0a3675 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/vm_helper.h @@ -28,29 +28,21 @@ #include "dc_types.h" -#define MAX_VMID 16 #define MAX_HUBP 6 struct vmid_usage { - uint16_t vmid_usage[2]; + int vmid_usage[2]; }; 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]; }; -uint8_t get_vmid_for_ptb( - struct vm_helper *vm_helper, - int64_t ptb, - uint8_t pipe_idx); +void vm_helper_mark_vmid_used(struct vm_helper *vm_helper, unsigned int pos, uint8_t hubp_idx); -void init_vm_helper( +void vm_helper_init( struct vm_helper *vm_helper, - unsigned int num_vmid, - unsigned int num_hubp); + unsigned int num_vmid); #endif /* DC_INC_VM_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index 498515aad4a5..ad87c2f093e2 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -67,3 +67,13 @@ AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN1) endif +############################################################################### +# DCN 20 +############################################################################### +ifdef CONFIG_DRM_AMD_DC_DCN2_0 +IRQ_DCN2 = irq_service_dcn20.o + +AMD_DAL_IRQ_DCN2 = $(addprefix $(AMDDALPATH)/dc/irq/dcn20/,$(IRQ_DCN2)) + +AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN2) +endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c index ebf483e3f098..cc8e7dedccce 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c @@ -38,7 +38,7 @@ #include "irq_service_dcn10.h" -#include "ivsrcid/irqsrcs_dcn_1_0.h" +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" enum dc_irq_source to_dal_irq_source_dcn10( struct irq_service *irq_service, diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c new file mode 100644 index 000000000000..3cc0f2a1f77c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c @@ -0,0 +1,375 @@ +/* + * 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 <linux/slab.h> + +#include "dm_services.h" + +#include "include/logger_interface.h" + +#include "../dce110/irq_service_dce110.h" + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "navi10_ip_offset.h" + + +#include "irq_service_dcn20.h" + +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" + +enum dc_irq_source to_dal_irq_source_dcn20( + struct irq_service *irq_service, + uint32_t src_id, + uint32_t ext_id) +{ + switch (src_id) { + case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK1; + case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK2; + case DCN_1_0__SRCID__DC_D3_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK3; + case DCN_1_0__SRCID__DC_D4_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK4; + case DCN_1_0__SRCID__DC_D5_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK5; + case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP: + return DC_IRQ_SOURCE_VBLANK6; + case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP1; + case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP2; + case DCN_1_0__SRCID__HUBP2_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP3; + case DCN_1_0__SRCID__HUBP3_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP4; + case DCN_1_0__SRCID__HUBP4_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP5; + case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT: + return DC_IRQ_SOURCE_PFLIP6; + case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE1; + case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE2; + case DCN_1_0__SRCID__OTG2_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE3; + case DCN_1_0__SRCID__OTG3_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE4; + case DCN_1_0__SRCID__OTG4_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE5; + case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT: + return DC_IRQ_SOURCE_VUPDATE6; + + case DCN_1_0__SRCID__DC_HPD1_INT: + /* generic src_id for all HPD and HPDRX interrupts */ + switch (ext_id) { + case DCN_1_0__CTXID__DC_HPD1_INT: + return DC_IRQ_SOURCE_HPD1; + case DCN_1_0__CTXID__DC_HPD2_INT: + return DC_IRQ_SOURCE_HPD2; + case DCN_1_0__CTXID__DC_HPD3_INT: + return DC_IRQ_SOURCE_HPD3; + case DCN_1_0__CTXID__DC_HPD4_INT: + return DC_IRQ_SOURCE_HPD4; + case DCN_1_0__CTXID__DC_HPD5_INT: + return DC_IRQ_SOURCE_HPD5; + case DCN_1_0__CTXID__DC_HPD6_INT: + return DC_IRQ_SOURCE_HPD6; + case DCN_1_0__CTXID__DC_HPD1_RX_INT: + return DC_IRQ_SOURCE_HPD1RX; + case DCN_1_0__CTXID__DC_HPD2_RX_INT: + return DC_IRQ_SOURCE_HPD2RX; + case DCN_1_0__CTXID__DC_HPD3_RX_INT: + return DC_IRQ_SOURCE_HPD3RX; + case DCN_1_0__CTXID__DC_HPD4_RX_INT: + return DC_IRQ_SOURCE_HPD4RX; + case DCN_1_0__CTXID__DC_HPD5_RX_INT: + return DC_IRQ_SOURCE_HPD5RX; + case DCN_1_0__CTXID__DC_HPD6_RX_INT: + return DC_IRQ_SOURCE_HPD6RX; + default: + return DC_IRQ_SOURCE_INVALID; + } + break; + + default: + return DC_IRQ_SOURCE_INVALID; + } +} + +static bool hpd_ack( + struct irq_service *irq_service, + const struct irq_source_info *info) +{ + uint32_t addr = info->status_reg; + uint32_t value = dm_read_reg(irq_service->ctx, addr); + uint32_t current_status = + get_reg_field_value( + value, + HPD0_DC_HPD_INT_STATUS, + DC_HPD_SENSE_DELAYED); + + dal_irq_service_ack_generic(irq_service, info); + + value = dm_read_reg(irq_service->ctx, info->enable_reg); + + set_reg_field_value( + value, + current_status ? 0 : 1, + HPD0_DC_HPD_INT_CONTROL, + DC_HPD_INT_POLARITY); + + dm_write_reg(irq_service->ctx, info->enable_reg, value); + + return true; +} + +static const struct irq_source_info_funcs hpd_irq_info_funcs = { + .set = NULL, + .ack = hpd_ack +}; + +static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs pflip_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +static const struct irq_source_info_funcs vblank_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +/* compile time expand base address. */ +#define BASE(seg) \ + BASE_INNER(seg) + + +#define SRI(reg_name, block, id)\ + BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + + +#define IRQ_REG_ENTRY(block, reg_num, reg1, mask1, reg2, mask2)\ + .enable_reg = SRI(reg1, block, reg_num),\ + .enable_mask = \ + block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ + .enable_value = {\ + block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\ + ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \ + },\ + .ack_reg = SRI(reg2, block, reg_num),\ + .ack_mask = \ + block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\ + .ack_value = \ + block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \ + + + +#define hpd_int_entry(reg_num)\ + [DC_IRQ_SOURCE_HPD1 + reg_num] = {\ + IRQ_REG_ENTRY(HPD, reg_num,\ + DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\ + DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\ + .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\ + .funcs = &hpd_irq_info_funcs\ + } + +#define hpd_rx_int_entry(reg_num)\ + [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\ + IRQ_REG_ENTRY(HPD, reg_num,\ + DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\ + DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\ + .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\ + .funcs = &hpd_rx_irq_info_funcs\ + } +#define pflip_int_entry(reg_num)\ + [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\ + IRQ_REG_ENTRY(HUBPREQ, reg_num,\ + DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\ + DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\ + .funcs = &pflip_irq_info_funcs\ + } + +#define vupdate_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\ + .funcs = &vblank_irq_info_funcs\ + } + +#define vblank_int_entry(reg_num)\ + [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ + IRQ_REG_ENTRY(OTG, reg_num,\ + OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\ + .funcs = &vblank_irq_info_funcs\ + } + +#define dummy_irq_entry() \ + {\ + .funcs = &dummy_irq_info_funcs\ + } + +#define i2c_int_entry(reg_num) \ + [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry() + +#define dp_sink_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry() + +#define gpio_pad_int_entry(reg_num) \ + [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry() + +#define dc_underflow_int_entry(reg_num) \ + [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() + +static const struct irq_source_info_funcs dummy_irq_info_funcs = { + .set = dal_irq_service_dummy_set, + .ack = dal_irq_service_dummy_ack +}; + +static const struct irq_source_info +irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = { + [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(), + hpd_int_entry(0), + hpd_int_entry(1), + hpd_int_entry(2), + hpd_int_entry(3), + hpd_int_entry(4), + hpd_int_entry(5), + hpd_rx_int_entry(0), + hpd_rx_int_entry(1), + hpd_rx_int_entry(2), + hpd_rx_int_entry(3), + hpd_rx_int_entry(4), + hpd_rx_int_entry(5), + i2c_int_entry(1), + i2c_int_entry(2), + i2c_int_entry(3), + i2c_int_entry(4), + i2c_int_entry(5), + i2c_int_entry(6), + dp_sink_int_entry(1), + dp_sink_int_entry(2), + dp_sink_int_entry(3), + dp_sink_int_entry(4), + dp_sink_int_entry(5), + dp_sink_int_entry(6), + [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(), + pflip_int_entry(0), + pflip_int_entry(1), + pflip_int_entry(2), + pflip_int_entry(3), + [DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(), + [DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(), + [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(), + gpio_pad_int_entry(0), + gpio_pad_int_entry(1), + gpio_pad_int_entry(2), + gpio_pad_int_entry(3), + gpio_pad_int_entry(4), + gpio_pad_int_entry(5), + gpio_pad_int_entry(6), + gpio_pad_int_entry(7), + gpio_pad_int_entry(8), + gpio_pad_int_entry(9), + gpio_pad_int_entry(10), + gpio_pad_int_entry(11), + gpio_pad_int_entry(12), + gpio_pad_int_entry(13), + gpio_pad_int_entry(14), + gpio_pad_int_entry(15), + gpio_pad_int_entry(16), + gpio_pad_int_entry(17), + gpio_pad_int_entry(18), + gpio_pad_int_entry(19), + gpio_pad_int_entry(20), + gpio_pad_int_entry(21), + gpio_pad_int_entry(22), + gpio_pad_int_entry(23), + gpio_pad_int_entry(24), + gpio_pad_int_entry(25), + gpio_pad_int_entry(26), + gpio_pad_int_entry(27), + gpio_pad_int_entry(28), + gpio_pad_int_entry(29), + gpio_pad_int_entry(30), + dc_underflow_int_entry(1), + dc_underflow_int_entry(2), + dc_underflow_int_entry(3), + dc_underflow_int_entry(4), + dc_underflow_int_entry(5), + dc_underflow_int_entry(6), + [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), + [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), + vupdate_int_entry(0), + vupdate_int_entry(1), + vupdate_int_entry(2), + vupdate_int_entry(3), + vupdate_int_entry(4), + vupdate_int_entry(5), + vblank_int_entry(0), + vblank_int_entry(1), + vblank_int_entry(2), + vblank_int_entry(3), + vblank_int_entry(4), + vblank_int_entry(5), +}; + +static const struct irq_service_funcs irq_service_funcs_dcn20 = { + .to_dal_irq_source = to_dal_irq_source_dcn20 +}; + +static void construct( + struct irq_service *irq_service, + struct irq_service_init_data *init_data) +{ + dal_irq_service_construct(irq_service, init_data); + + irq_service->info = irq_source_info_dcn20; + irq_service->funcs = &irq_service_funcs_dcn20; +} + +struct irq_service *dal_irq_service_dcn20_create( + struct irq_service_init_data *init_data) +{ + struct irq_service *irq_service = kzalloc(sizeof(*irq_service), + GFP_KERNEL); + + if (!irq_service) + return NULL; + + construct(irq_service, init_data); + return irq_service; +} diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h new file mode 100644 index 000000000000..aee4b37999f1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h @@ -0,0 +1,34 @@ +/* + * 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 + * + */ + +#ifndef __DAL_IRQ_SERVICE_DCN20_H__ +#define __DAL_IRQ_SERVICE_DCN20_H__ + +#include "../irq_service.h" + +struct irq_service *dal_irq_service_dcn20_create( + struct irq_service_init_data *init_data); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c index 484047155aae..c9a6dd878d9b 100644 --- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c @@ -77,7 +77,22 @@ static void virtual_audio_mute_control( struct stream_encoder *enc, bool mute) {} +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +static void virtual_enc_dp_set_odm_combine( + struct stream_encoder *enc, + bool odm_combine) +{} +#endif +#endif + static const struct stream_encoder_funcs virtual_str_enc_funcs = { +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .dp_set_odm_combine = + virtual_enc_dp_set_odm_combine, +#endif +#endif .dp_set_stream_attribute = virtual_stream_encoder_dp_set_stream_attribute, .hdmi_set_stream_attribute = diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h index b302ff3180a4..887e6a8597c4 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -147,6 +147,12 @@ #define FAMILY_RV 142 /* DCN 1*/ +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + +#define FAMILY_NV 143 /* DCN 2*/ + +#endif + /* * ASIC chip ID */ diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h index dabdbc0999d4..1e3ce4d847ae 100644 --- a/drivers/gpu/drm/amd/display/include/dal_types.h +++ b/drivers/gpu/drm/amd/display/include/dal_types.h @@ -46,6 +46,9 @@ enum dce_version { DCE_VERSION_MAX, DCN_VERSION_1_0, DCN_VERSION_1_01, +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + DCN_VERSION_2_0, +#endif DCN_VERSION_MAX }; diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index d96550d6434d..ea8d445816b8 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -63,6 +63,12 @@ #define DC_LOG_IF_TRACE(...) pr_debug("[IF_TRACE]:"__VA_ARGS__) #define DC_LOG_PERF_TRACE(...) DRM_DEBUG_KMS(__VA_ARGS__) #define DC_LOG_RETIMER_REDRIVER(...) DRM_DEBUG_KMS(__VA_ARGS__) +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT +#define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__) +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN3_0) || defined(CONFIG_DRM_AMD_DC_DCN2_0) +#define DC_LOG_DWB(...) DRM_DEBUG_KMS(__VA_ARGS__) +#endif struct dal_logger; @@ -107,6 +113,10 @@ enum dc_log_type { LOG_PERF_TRACE, LOG_DISPLAYSTATS, LOG_HDMI_RETIMER_REDRIVER, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + LOG_DSC, +#endif + LOG_DWB, LOG_SECTION_TOTAL_COUNT }; 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 b31af9be41eb..88898935a5e6 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -1572,15 +1572,14 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, output_tf->tf == TRANSFER_FUNCTION_SRGB) { if (ramp == NULL) return true; - if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) || + if ((ramp->is_logical_identity) || (!mapUserRamp && ramp->type == GAMMA_RGB_256)) return true; } output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - if (ramp && ramp->type != GAMMA_CS_TFM_1D && - (mapUserRamp || ramp->type != GAMMA_RGB_256)) { + if (ramp && (mapUserRamp || ramp->type != GAMMA_RGB_256)) { rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*rgb_user), GFP_KERNEL); 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 b711e7e6c204..b45f7d65e76a 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_shared.h @@ -45,5 +45,65 @@ enum vrr_packet_type { PACKET_TYPE_VTEM }; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) +union lut3d_control_flags { + unsigned int raw; + struct { + unsigned int do_chroma_scale :1; + unsigned int spec_version :3; + unsigned int use_zero_display_black :1; + unsigned int use_zero_source_black :1; + unsigned int force_display_black :6; + unsigned int apply_display_gamma :1; + unsigned int exp_shaper_max :6; + unsigned int unity_3dlut :1; + unsigned int bypass_3dlut :1; + unsigned int use_3dlut :1; + unsigned int less_than_dcip3 :1; + unsigned int override_lum :1; + unsigned int use_gamut_map_lib :1; + unsigned int chromatic_adaptation_src :1; + unsigned int chromatic_adaptation_dst :1; + unsigned int do_blender_lut_degamma :1; + unsigned int reseved :4; + } bits; +}; + +enum tm_show_option_internal { + tm_show_option_internal_single_file = 0,/*flags2 not in use*/ + tm_show_option_internal_duplicate_file, /*use flags2*/ + tm_show_option_internal_duplicate_sidebyside/*use flags2*/ +}; + +enum lut3d_control_gamut_map { + lut3d_control_gamut_map_none = 0, + lut3d_control_gamut_map_tonemap, + lut3d_control_gamut_map_chto, + lut3d_control_gamut_map_chso, + lut3d_control_gamut_map_chci +}; + +enum lut3d_control_rotation_mode { + lut3d_control_rotation_mode_none = 0, + lut3d_control_rotation_mode_hue, + lut3d_control_rotation_mode_cc, + lut3d_control_rotation_mode_hue_cc +}; + +struct lut3d_settings { + unsigned char version; + union lut3d_control_flags flags; + union lut3d_control_flags flags2; + enum tm_show_option_internal option; + unsigned int min_lum;/*multiplied by 100*/ + unsigned int max_lum; + unsigned int min_lum2; + unsigned int max_lum2; + enum lut3d_control_gamut_map map; + enum lut3d_control_rotation_mode rotation; + enum lut3d_control_gamut_map map2; + enum lut3d_control_rotation_mode rotation2; +}; +#endif #endif /* MOD_SHARED_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_vmid.h b/drivers/gpu/drm/amd/display/modules/inc/mod_vmid.h new file mode 100644 index 000000000000..a3787fdf0c08 --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_vmid.h @@ -0,0 +1,46 @@ +/* + * Copyright 2019 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 MOD_VMID_H_ +#define MOD_VMID_H_ + +#define MAX_VMID 16 + +#include "dc.h" + +struct mod_vmid { + int dummy; +}; + +uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb); +void mod_vmid_reset(struct mod_vmid *mod_vmid); +struct mod_vmid *mod_vmid_create( + struct dc *dc, + unsigned int num_vmid, + struct dc_virtual_addr_space_config *va_config); + +void mod_vmid_destroy(struct mod_vmid *mod_vmid); + +#endif /* MOD_VMID_H_ */ diff --git a/drivers/gpu/drm/amd/display/modules/power/Makefile b/drivers/gpu/drm/amd/display/modules/power/Makefile index 87851f892a52..9d1b22d35ece 100644 --- a/drivers/gpu/drm/amd/display/modules/power/Makefile +++ b/drivers/gpu/drm/amd/display/modules/power/Makefile @@ -28,4 +28,4 @@ MOD_POWER = power_helpers.o AMD_DAL_MOD_POWER = $(addprefix $(AMDDALPATH)/modules/power/,$(MOD_POWER)) #$(info ************ DAL POWER MODULE MAKEFILE ************) -AMD_DISPLAY_FILES += $(AMD_DAL_MOD_POWER)
\ No newline at end of file +AMD_DISPLAY_FILES += $(AMD_DAL_MOD_POWER) diff --git a/drivers/gpu/drm/amd/display/modules/vmid/vmid.c b/drivers/gpu/drm/amd/display/modules/vmid/vmid.c new file mode 100644 index 000000000000..f0a153704f6e --- /dev/null +++ b/drivers/gpu/drm/amd/display/modules/vmid/vmid.c @@ -0,0 +1,167 @@ +/* + * Copyright 2019 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 "mod_vmid.h" + +struct core_vmid { + struct mod_vmid public; + struct dc *dc; + + unsigned int num_vmid; + unsigned int num_vmids_available; + uint64_t ptb_assigned_to_vmid[MAX_VMID]; + struct dc_virtual_addr_space_config base_config; +}; + +#define MOD_VMID_TO_CORE(mod_vmid)\ + container_of(mod_vmid, struct core_vmid, public) + +static void add_ptb_to_table(struct core_vmid *core_vmid, unsigned int vmid, uint64_t ptb) +{ + core_vmid->ptb_assigned_to_vmid[vmid] = ptb; + core_vmid->num_vmids_available--; +} + +static void clear_entry_from_vmid_table(struct core_vmid *core_vmid, unsigned int vmid) +{ + core_vmid->ptb_assigned_to_vmid[vmid] = 0; + core_vmid->num_vmids_available++; +} + +static void evict_vmids(struct core_vmid *core_vmid) +{ + int i; + uint16_t ord = dc_get_vmid_use_vector(core_vmid->dc); + + // At this point any positions with value 0 are unused vmids, evict them + for (i = 1; i < core_vmid->num_vmid; i++) { + if (ord & (1u << i)) + clear_entry_from_vmid_table(core_vmid, i); + } +} + +// Return value of -1 indicates vmid table unitialized or ptb dne in the table +static int get_existing_vmid_for_ptb(struct core_vmid *core_vmid, uint64_t ptb) +{ + int i; + + for (i = 0; i < core_vmid->num_vmid; i++) { + if (core_vmid->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 core_vmid *core_vmid) +{ + int i; + + for (i = 1; i < core_vmid->num_vmid; i++) { + if (core_vmid->ptb_assigned_to_vmid[i] == 0) + return i; + } + + return -1; +} + +uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb) +{ + struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); + unsigned int vmid = 0; + + // Physical address gets vmid 0 + if (ptb == 0) + return 0; + + vmid = get_existing_vmid_for_ptb(core_vmid, ptb); + + if (vmid == -1) { + struct dc_virtual_addr_space_config va_config = core_vmid->base_config; + + va_config.page_table_base_addr = ptb; + + if (core_vmid->num_vmids_available == 0) + evict_vmids(core_vmid); + + vmid = get_next_available_vmid(core_vmid); + add_ptb_to_table(core_vmid, vmid, ptb); + + dc_setup_vm_context(core_vmid->dc, &va_config, vmid); + } + + return vmid; +} + +void mod_vmid_reset(struct mod_vmid *mod_vmid) +{ + struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); + + core_vmid->num_vmids_available = core_vmid->num_vmid - 1; + memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID); +} + +struct mod_vmid *mod_vmid_create( + struct dc *dc, + unsigned int num_vmid, + struct dc_virtual_addr_space_config *va_config) +{ + struct core_vmid *core_vmid; + + if (num_vmid <= 1) + goto fail_no_vm_ctx; + + if (dc == NULL) + goto fail_dc_null; + + core_vmid = kzalloc(sizeof(struct core_vmid), GFP_KERNEL); + + if (core_vmid == NULL) + goto fail_alloc_context; + + core_vmid->dc = dc; + core_vmid->num_vmid = num_vmid; + core_vmid->num_vmids_available = num_vmid - 1; + core_vmid->base_config = *va_config; + + memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID); + + return &core_vmid->public; + +fail_no_vm_ctx: +fail_alloc_context: +fail_dc_null: + return NULL; +} + +void mod_vmid_destroy(struct mod_vmid *mod_vmid) +{ + if (mod_vmid != NULL) { + struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid); + + kfree(core_vmid); + } +} |