diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-19 16:24:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-19 16:24:24 -0700 |
commit | 574cc4539762561d96b456dbc0544d8898bd4c6e (patch) | |
tree | 07d84db8cf9fd30cbde6f539ce3a3f6116593e41 /drivers/gpu/drm/amd/display | |
parent | 3c2edc36a77420d8be05d656019dbc8c31535992 (diff) | |
parent | 945b584c94f8c665b2df3834a8a6a8faf256cd5f (diff) | |
download | linux-574cc4539762561d96b456dbc0544d8898bd4c6e.tar.gz linux-574cc4539762561d96b456dbc0544d8898bd4c6e.tar.bz2 linux-574cc4539762561d96b456dbc0544d8898bd4c6e.zip |
Merge tag 'drm-next-2019-09-18' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie:
"This is the main pull request for 5.4-rc1 merge window. I don't think
there is anything outstanding so next week should just be fixes, but
we'll see if I missed anything. I landed some fixes earlier in the
week but got delayed writing summary and sending it out, due to a mix
of sick kid and jetlag!
There are some fixes pending, but I'd rather get the main merge out of
the way instead of delaying it longer.
It's also pretty large in commit count and new amd header file size.
The largest thing is four new amdgpu products (navi12/14, arcturus and
renoir APU support).
Otherwise it's pretty much lots of work across the board, i915 has
started landing tigerlake support, lots of icelake fixes and lots of
locking reworking for future gpu support, lots of header file rework
(drmP.h is nearly gone), some old legacy hacks (DRM_WAIT_ON) have been
put into the places they are needed.
uapi:
- content protection type property for HDCP
core:
- rework include dependencies
- lots of drmP.h removals
- link rate calculation robustness fix
- make fb helper map only when required
- add connector->DDC adapter link
- DRM_WAIT_ON removed
- drop DRM_AUTH usage from drivers
dma-buf:
- reservation object fence helper
dma-fence:
- shrink dma_fence struct
- merge signal functions
- store timestamps in dma_fence
- selftests
ttm:
- embed drm_get_object struct into ttm_buffer_object
- release_notify callback
bridges:
- sii902x - audio graph card support
- tc358767 - aux data handling rework
- ti-snd64dsi86 - debugfs support, DSI mode flags support
panels:
- Support for GiantPlus GPM940B0, Sharp LQ070Y3DG3B, Ortustech
COM37H3M, Novatek NT39016, Sharp LS020B1DD01D, Raydium RM67191, Boe
Himax8279d, Sharp LD-D5116Z01B
- TI nspire, NEC NL8048HL11, LG Philips LB035Q02, Sharp LS037V7DW01,
Sony ACX565AKM, Toppoly TD028TTEC1 Toppoly TD043MTEA1
i915:
- Initial tigerlake platform support
- Locking simplification work, general all over refactoring.
- Selftests
- HDCP debug info improvements
- DSI properties
- Icelake display PLL fixes, colorspace fixes, bandwidth fixes, DSI
suspend/resume
- GuC fixes
- Perf fixes
- ElkhartLake enablement
- DP MST fixes
- GVT - command parser enhancements
amdgpu:
- add wipe memory on release flag for buffer creation
- Navi12/14 support (may be marked experimental)
- Arcturus support
- Renoir APU support
- mclk DPM for Navi
- DC display fixes
- Raven scatter/gather support
- RAS support for GFX
- Navi12 + Arcturus power features
- GPU reset for Picasso
- smu11 i2c controller support
amdkfd:
- navi12/14 support
- Arcturus support
radeon:
- kexec fix
nouveau:
- improved display color management
- detect lack of GPU power cables
vmwgfx:
- evicition priority support
- remove unused security feature
msm:
- msm8998 display support
- better async commit support for cursor updates
etnaviv:
- per-process address space support
- performance counter fixes
- softpin support
mcde:
- DCS transfers fix
exynos:
- drmP.h cleanup
lima:
- reduce logging
kirin:
- misc clenaups
komeda:
- dual-link support
- DT memory regions
hisilicon:
- misc fixes
imx:
- IPUv3 image converter fixes
- 32-bit RGB V4L2 pixel format support
ingenic:
- more support for panel related cases
mgag200:
- cursor support fix
panfrost:
- export GPU features register to userspace
- gpu heap allocations
- per-fd address space support
pl111:
- CLD pads wiring support removed from DT
rockchip:
- rework to use DRM PSR helpers
- fix bug in VOP_WIN_GET macro
- DSI DT binding rework
sun4i:
- improve support for color encoding and range
- DDC enabled GPIO
tinydrm:
- rework SPI support
- improve MIPI-DBI support
- moved to drm/tiny
vkms:
- rework CRC tracking
dw-hdmi:
- get_eld and i2s improvements
gm12u320:
- misc fixes
meson:
- global code cleanup
- vpu feature detect
omap:
- alpha/pixel blend mode properties
rcar-du:
- misc fixes"
* tag 'drm-next-2019-09-18' of git://anongit.freedesktop.org/drm/drm: (2112 commits)
drm/nouveau/bar/gm20b: Avoid BAR1 teardown during init
drm/nouveau: Fix ordering between TTM and GEM release
drm/nouveau/prime: Extend DMA reservation object lock
drm/nouveau: Fix fallout from reservation object rework
drm/nouveau/kms/nv50-: Don't create MSTMs for eDP connectors
drm/i915: Use NOEVICT for first pass on attemping to pin a GGTT mmap
drm/i915: to make vgpu ppgtt notificaiton as atomic operation
drm/i915: Flush the existing fence before GGTT read/write
drm/i915: Hold irq-off for the entire fake lock period
drm/i915/gvt: update RING_START reg of vGPU when the context is submitted to i915
drm/i915/gvt: update vgpu workload head pointer correctly
drm/mcde: Fix DSI transfers
drm/msm: Use the correct dma_sync calls harder
drm/msm: remove unlikely() from WARN_ON() conditions
drm/msm/dsi: Fix return value check for clk_get_parent
drm/msm: add atomic traces
drm/msm/dpu: async commit support
drm/msm: async commit support
drm/msm: split power control from prepare/complete_commit
drm/msm: add kms->flush_commit()
...
Diffstat (limited to 'drivers/gpu/drm/amd/display')
197 files changed, 26716 insertions, 3200 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index f954bf61af28..71991a28a775 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -26,6 +26,14 @@ config DRM_AMD_DC_DCN2_0 Choose this option if you want to have Navi support for display engine +config DRM_AMD_DC_DCN2_1 + bool "DCN 2.1 family" + depends on DRM_AMD_DC && X86 + depends on DRM_AMD_DC_DCN2_0 + help + Choose this option if you want to have + Renoir support for display engine + config DRM_AMD_DC_DSC_SUPPORT bool "DSC support" default y 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 45be7a2132bb..e1b09bb432bd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -688,12 +688,15 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) */ if (adev->flags & AMD_IS_APU && adev->asic_type >= CHIP_CARRIZO && - adev->asic_type < CHIP_RAVEN) + adev->asic_type <= CHIP_RAVEN) init_data.flags.gpu_vm_support = true; if (amdgpu_dc_feature_mask & DC_FBC_MASK) init_data.flags.fbc_support = true; + if (amdgpu_dc_feature_mask & DC_MULTI_MON_PP_MCLK_SWITCH_MASK) + init_data.flags.multi_mon_pp_mclk_switch = true; + init_data.flags.power_down_display_on_boot = true; #ifdef CONFIG_DRM_AMD_DC_DCN2_0 @@ -809,6 +812,9 @@ static int load_dmcu_fw(struct amdgpu_device *adev) case CHIP_VEGA12: case CHIP_VEGA20: case CHIP_NAVI10: + case CHIP_NAVI14: + case CHIP_NAVI12: + case CHIP_RENOIR: return 0; case CHIP_RAVEN: if (ASICREV_IS_PICASSO(adev->external_rev_id)) @@ -2358,7 +2364,12 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: #if defined(CONFIG_DRM_AMD_DC_DCN2_0) + case CHIP_NAVI12: case CHIP_NAVI10: + case CHIP_NAVI14: +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case CHIP_RENOIR: #endif if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -2428,8 +2439,7 @@ static ssize_t s3_debug_store(struct device *device, { int ret; int s3_state; - struct pci_dev *pdev = to_pci_dev(device); - struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct drm_device *drm_dev = dev_get_drvdata(device); struct amdgpu_device *adev = drm_dev->dev_private; ret = kstrtoint(buf, 0, &s3_state); @@ -2515,10 +2525,23 @@ static int dm_early_init(void *handle) #endif #if defined(CONFIG_DRM_AMD_DC_DCN2_0) case CHIP_NAVI10: + case CHIP_NAVI12: adev->mode_info.num_crtc = 6; adev->mode_info.num_hpd = 6; adev->mode_info.num_dig = 6; break; + case CHIP_NAVI14: + adev->mode_info.num_crtc = 5; + adev->mode_info.num_hpd = 5; + adev->mode_info.num_dig = 5; + break; +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case CHIP_RENOIR: + adev->mode_info.num_crtc = 4; + adev->mode_info.num_hpd = 4; + adev->mode_info.num_dig = 4; + break; #endif default: DRM_ERROR("Unsupported ASIC type: 0x%X\n", adev->asic_type); @@ -2665,7 +2688,7 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, const enum surface_pixel_format format, const enum dc_rotation_angle rotation, - const union plane_size *plane_size, + const struct plane_size *plane_size, const union dc_tiling_info *tiling_info, const uint64_t info, struct dc_plane_dcc_param *dcc, @@ -2691,8 +2714,8 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev, return -EINVAL; input.format = format; - input.surface_size.width = plane_size->grph.surface_size.width; - input.surface_size.height = plane_size->grph.surface_size.height; + input.surface_size.width = plane_size->surface_size.width; + input.surface_size.height = plane_size->surface_size.height; input.swizzle_mode = tiling_info->gfx9.swizzle; if (rotation == ROTATION_ANGLE_0 || rotation == ROTATION_ANGLE_180) @@ -2710,9 +2733,9 @@ fill_plane_dcc_attributes(struct amdgpu_device *adev, return -EINVAL; dcc->enable = 1; - dcc->grph.meta_pitch = + dcc->meta_pitch = AMDGPU_TILING_GET(info, DCC_PITCH_MAX) + 1; - dcc->grph.independent_64b_blks = i64b; + dcc->independent_64b_blks = i64b; dcc_address = get_dcc_address(afb->address, info); address->grph.meta_addr.low_part = lower_32_bits(dcc_address); @@ -2728,7 +2751,7 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, const enum dc_rotation_angle rotation, const uint64_t tiling_flags, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, struct dc_plane_dcc_param *dcc, struct dc_plane_address *address) { @@ -2741,11 +2764,11 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, memset(address, 0, sizeof(*address)); if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - plane_size->grph.surface_size.x = 0; - plane_size->grph.surface_size.y = 0; - plane_size->grph.surface_size.width = fb->width; - plane_size->grph.surface_size.height = fb->height; - plane_size->grph.surface_pitch = + plane_size->surface_size.x = 0; + plane_size->surface_size.y = 0; + plane_size->surface_size.width = fb->width; + plane_size->surface_size.height = fb->height; + plane_size->surface_pitch = fb->pitches[0] / fb->format->cpp[0]; address->type = PLN_ADDR_TYPE_GRAPHICS; @@ -2754,20 +2777,20 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, } else if (format < SURFACE_PIXEL_FORMAT_INVALID) { uint64_t chroma_addr = afb->address + fb->offsets[1]; - plane_size->video.luma_size.x = 0; - plane_size->video.luma_size.y = 0; - plane_size->video.luma_size.width = fb->width; - plane_size->video.luma_size.height = fb->height; - plane_size->video.luma_pitch = + plane_size->surface_size.x = 0; + plane_size->surface_size.y = 0; + plane_size->surface_size.width = fb->width; + plane_size->surface_size.height = fb->height; + plane_size->surface_pitch = fb->pitches[0] / fb->format->cpp[0]; - plane_size->video.chroma_size.x = 0; - plane_size->video.chroma_size.y = 0; + plane_size->chroma_size.x = 0; + plane_size->chroma_size.y = 0; /* TODO: set these based on surface format */ - plane_size->video.chroma_size.width = fb->width / 2; - plane_size->video.chroma_size.height = fb->height / 2; + plane_size->chroma_size.width = fb->width / 2; + plane_size->chroma_size.height = fb->height / 2; - plane_size->video.chroma_pitch = + plane_size->chroma_pitch = fb->pitches[1] / fb->format->cpp[1]; address->type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE; @@ -2814,6 +2837,11 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev, adev->asic_type == CHIP_VEGA20 || #if defined(CONFIG_DRM_AMD_DC_DCN2_0) adev->asic_type == CHIP_NAVI10 || + adev->asic_type == CHIP_NAVI14 || + adev->asic_type == CHIP_NAVI12 || +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + adev->asic_type == CHIP_RENOIR || #endif adev->asic_type == CHIP_RAVEN) { /* Fill GFX9 params */ @@ -2995,6 +3023,8 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev, plane_info->visible = true; plane_info->stereo_format = PLANE_STEREO_FORMAT_NONE; + plane_info->layer_index = 0; + ret = fill_plane_color_attributes(plane_state, plane_info->format, &plane_info->color_space); if (ret) @@ -3060,6 +3090,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, dc_plane_state->global_alpha = plane_info.global_alpha; dc_plane_state->global_alpha_value = plane_info.global_alpha_value; dc_plane_state->dcc = plane_info.dcc; + dc_plane_state->layer_index = plane_info.layer_index; // Always returns 0 /* * Always set input transfer function, since plane state is refreshed @@ -3503,6 +3534,10 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, bool scale = dm_state ? (dm_state->scaling != RMX_OFF) : false; int mode_refresh; int preferred_refresh = 0; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + struct dsc_dec_dpcd_caps dsc_caps; + uint32_t link_bandwidth_kbps; +#endif struct dc_sink *sink = NULL; if (aconnector == NULL) { @@ -3575,17 +3610,23 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, &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; */ + stream->timing.flags.DSC = 0; + + if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { + dc_dsc_parse_dsc_dpcd(aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_ext_caps.raw, + &dsc_caps); + link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, + dc_link_get_link_cap(aconnector->dc_link)); + + if (dsc_caps.is_dsc_supported) + if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc, + &dsc_caps, + link_bandwidth_kbps, + &stream->timing, + &stream->timing.dsc_cfg)) + stream->timing.flags.DSC = 1; + } #endif update_stream_scaling_settings(&mode, dm_state, stream); @@ -3669,7 +3710,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) state->abm_level = cur->abm_level; state->vrr_supported = cur->vrr_supported; state->freesync_config = cur->freesync_config; - state->crc_enabled = cur->crc_enabled; + state->crc_src = cur->crc_src; state->cm_has_degamma = cur->cm_has_degamma; state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; @@ -3739,6 +3780,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .atomic_destroy_state = dm_crtc_destroy_state, .set_crc_source = amdgpu_dm_crtc_set_crc_source, .verify_crc_source = amdgpu_dm_crtc_verify_crc_source, + .get_crc_sources = amdgpu_dm_crtc_get_crc_sources, .enable_vblank = dm_enable_vblank, .disable_vblank = dm_disable_vblank, }; @@ -4458,7 +4500,7 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane, } if (plane->type != DRM_PLANE_TYPE_CURSOR) - domain = amdgpu_display_supported_domains(adev); + domain = amdgpu_display_supported_domains(adev, rbo->flags); else domain = AMDGPU_GEM_DOMAIN_VRAM; @@ -4548,20 +4590,10 @@ static int dm_plane_atomic_check(struct drm_plane *plane, static int dm_plane_atomic_async_check(struct drm_plane *plane, struct drm_plane_state *new_plane_state) { - struct drm_plane_state *old_plane_state = - drm_atomic_get_old_plane_state(new_plane_state->state, plane); - /* Only support async updates on cursor planes. */ if (plane->type != DRM_PLANE_TYPE_CURSOR) return -EINVAL; - /* - * DRM calls prepare_fb and cleanup_fb on new_plane_state for - * async commits so don't allow fb changes. - */ - if (old_plane_state->fb != new_plane_state->fb) - return -EINVAL; - return 0; } @@ -5705,11 +5737,11 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, * deadlock during GPU reset when this fence will not signal * but we hold reservation lock for the BO. */ - r = reservation_object_wait_timeout_rcu(abo->tbo.resv, true, + r = dma_resv_wait_timeout_rcu(abo->tbo.base.resv, true, false, msecs_to_jiffies(5000)); if (unlikely(r <= 0)) - DRM_ERROR("Waiting for fences timed out or interrupted!"); + DRM_ERROR("Waiting for fences timed out!"); /* * TODO This might fail and hence better not used, wait @@ -5733,8 +5765,14 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].plane_info = &bundle->plane_infos[planes_count]; + /* + * Only allow immediate flips for fast updates that don't + * change FB pitch, DCC state, rotation or mirroing. + */ bundle->flip_addrs[planes_count].flip_immediate = - (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0; + (crtc->state->pageflip_flags & + DRM_MODE_PAGE_FLIP_ASYNC) != 0 && + acrtc_state->update_type == UPDATE_TYPE_FAST; timestamp_ns = ktime_get_ns(); bundle->flip_addrs[planes_count].flip_timestamp_in_us = div_u64(timestamp_ns, 1000); @@ -5979,6 +6017,7 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev, struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; int i; + enum amdgpu_dm_pipe_crc_source source; for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { @@ -6004,9 +6043,11 @@ static void amdgpu_dm_enable_crtc_interrupts(struct drm_device *dev, #ifdef CONFIG_DEBUG_FS /* The stream has changed so CRC capture needs to re-enabled. */ - if (dm_new_crtc_state->crc_enabled) { - dm_new_crtc_state->crc_enabled = false; - amdgpu_dm_crtc_set_crc_source(crtc, "auto"); + source = dm_new_crtc_state->crc_src; + if (amdgpu_dm_is_valid_crc_source(source)) { + amdgpu_dm_crtc_configure_crc_source( + crtc, dm_new_crtc_state, + dm_new_crtc_state->crc_src); } #endif } @@ -6057,23 +6098,8 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev, if (dm_old_crtc_state->interrupts_enabled && (!dm_new_crtc_state->interrupts_enabled || - drm_atomic_crtc_needs_modeset(new_crtc_state))) { - /* - * Drop the extra vblank reference added by CRC - * capture if applicable. - */ - if (dm_new_crtc_state->crc_enabled) - drm_crtc_vblank_put(crtc); - - /* - * Only keep CRC capture enabled if there's - * still a stream for the CRTC. - */ - if (!dm_new_crtc_state->stream) - dm_new_crtc_state->crc_enabled = false; - + drm_atomic_crtc_needs_modeset(new_crtc_state))) manage_dm_interrupts(adev, acrtc, false); - } } /* * Add check here for SoC's that support hardware cursor plane, to @@ -7045,6 +7071,12 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, continue; for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, j) { + const struct amdgpu_framebuffer *amdgpu_fb = + to_amdgpu_framebuffer(new_plane_state->fb); + struct dc_plane_info plane_info; + struct dc_flip_addrs flip_addr; + uint64_t tiling_flags; + new_plane_crtc = new_plane_state->crtc; old_plane_crtc = old_plane_state->crtc; new_dm_plane_state = to_dm_plane_state(new_plane_state); @@ -7088,6 +7120,24 @@ dm_determine_update_type_for_commit(struct amdgpu_display_manager *dm, updates[num_plane].scaling_info = &scaling_info; + if (amdgpu_fb) { + ret = get_fb_info(amdgpu_fb, &tiling_flags); + if (ret) + goto cleanup; + + memset(&flip_addr, 0, sizeof(flip_addr)); + + ret = fill_dc_plane_info_and_addr( + dm->adev, new_plane_state, tiling_flags, + &plane_info, + &flip_addr.address); + if (ret) + goto cleanup; + + updates[num_plane].plane_info = &plane_info; + updates[num_plane].flip_addr = &flip_addr; + } + num_plane++; } @@ -7284,6 +7334,26 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (ret) goto fail; + if (state->legacy_cursor_update) { + /* + * This is a fast cursor update coming from the plane update + * helper, check if it can be done asynchronously for better + * performance. + */ + state->async_update = + !drm_atomic_helper_async_check(dev, state); + + /* + * Skip the remaining global validation if this is an async + * update. Cursor updates can be done without affecting + * state or bandwidth calcs and this avoids the performance + * penalty of locking the private state object and + * allocating a new dc_state. + */ + if (state->async_update) + return 0; + } + /* Check scaling and underscan changes*/ /* TODO Removed scaling changes validation due to inability to commit * new stream into context w\o causing full reset. Need to @@ -7336,13 +7406,37 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, ret = -EINVAL; goto fail; } - } else if (state->legacy_cursor_update) { + } else { /* - * This is a fast cursor update coming from the plane update - * helper, check if it can be done asynchronously for better - * performance. + * The commit is a fast update. Fast updates shouldn't change + * the DC context, affect global validation, and can have their + * commit work done in parallel with other commits not touching + * the same resource. If we have a new DC context as part of + * the DM atomic state from validation we need to free it and + * retain the existing one instead. */ - state->async_update = !drm_atomic_helper_async_check(dev, state); + struct dm_atomic_state *new_dm_state, *old_dm_state; + + new_dm_state = dm_atomic_get_new_state(state); + old_dm_state = dm_atomic_get_old_state(state); + + if (new_dm_state && old_dm_state) { + if (new_dm_state->context) + dc_release_state(new_dm_state->context); + + new_dm_state->context = old_dm_state->context; + + if (old_dm_state->context) + dc_retain_state(old_dm_state->context); + } + } + + /* Store the overall update type for use later in atomic check. */ + for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) { + struct dm_crtc_state *dm_new_crtc_state = + to_dm_crtc_state(new_crtc_state); + + dm_new_crtc_state->update_type = (int)overall_update_type; } /* Must be success */ 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 b89cbbfcc0e9..c8c525a2b505 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -50,6 +50,7 @@ #include "irq_types.h" #include "signal_types.h" +#include "amdgpu_dm_crc.h" /* Forward declarations */ struct amdgpu_device; @@ -309,11 +310,12 @@ struct dm_crtc_state { bool cm_has_degamma; bool cm_is_degamma_srgb; + int update_type; int active_planes; bool interrupts_enabled; int crc_skip_count; - bool crc_enabled; + enum amdgpu_dm_pipe_crc_source crc_src; bool freesync_timing_changed; bool freesync_vrr_info_changed; @@ -380,19 +382,6 @@ void dm_restore_drm_connector_state(struct drm_device *dev, void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, struct edid *edid); -/* amdgpu_dm_crc.c */ -#ifdef CONFIG_DEBUG_FS -int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name); -int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, - const char *src_name, - size_t *values_cnt); -void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); -#else -#define amdgpu_dm_crtc_set_crc_source NULL -#define amdgpu_dm_crtc_verify_crc_source NULL -#define amdgpu_dm_crtc_handle_crc_irq(x) -#endif - #define MAX_COLOR_LUT_ENTRIES 4096 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index bc67e6502733..a549c7c717dd 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -30,23 +30,57 @@ #include "amdgpu_dm.h" #include "dc.h" -enum amdgpu_dm_pipe_crc_source { - AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0, - AMDGPU_DM_PIPE_CRC_SOURCE_AUTO, - AMDGPU_DM_PIPE_CRC_SOURCE_MAX, - AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1, +static const char *const pipe_crc_sources[] = { + "none", + "crtc", + "crtc dither", + "dprx", + "dprx dither", + "auto", }; static enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source) { if (!source || !strcmp(source, "none")) return AMDGPU_DM_PIPE_CRC_SOURCE_NONE; - if (!strcmp(source, "auto")) - return AMDGPU_DM_PIPE_CRC_SOURCE_AUTO; + if (!strcmp(source, "auto") || !strcmp(source, "crtc")) + return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC; + if (!strcmp(source, "dprx")) + return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX; + if (!strcmp(source, "crtc dither")) + return AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER; + if (!strcmp(source, "dprx dither")) + return AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER; return AMDGPU_DM_PIPE_CRC_SOURCE_INVALID; } +static bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src) +{ + return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC) || + (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER); +} + +static bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src) +{ + return (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX) || + (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER); +} + +static bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src) +{ + return (src == AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER) || + (src == AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER) || + (src == AMDGPU_DM_PIPE_CRC_SOURCE_NONE); +} + +const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc, + size_t *count) +{ + *count = ARRAY_SIZE(pipe_crc_sources); + return pipe_crc_sources; +} + int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, size_t *values_cnt) @@ -63,14 +97,52 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, return 0; } -int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) +int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, + struct dm_crtc_state *dm_crtc_state, + enum amdgpu_dm_pipe_crc_source source) { struct amdgpu_device *adev = crtc->dev->dev_private; - struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state); - struct dc_stream_state *stream_state = crtc_state->stream; - bool enable; + struct dc_stream_state *stream_state = dm_crtc_state->stream; + bool enable = amdgpu_dm_is_valid_crc_source(source); + int ret = 0; + /* Configuration will be deferred to stream enable. */ + if (!stream_state) + return 0; + + mutex_lock(&adev->dm.dc_lock); + + /* Enable CRTC CRC generation if necessary. */ + if (dm_is_crc_source_crtc(source)) { + if (!dc_stream_configure_crc(stream_state->ctx->dc, + stream_state, enable, enable)) { + ret = -EINVAL; + goto unlock; + } + } + + /* Configure dithering */ + if (!dm_need_crc_dither(source)) + dc_stream_set_dither_option(stream_state, DITHER_OPTION_TRUN8); + else + dc_stream_set_dither_option(stream_state, + DITHER_OPTION_DEFAULT); + +unlock: + mutex_unlock(&adev->dm.dc_lock); + + return ret; +} + +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) +{ enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); + struct drm_crtc_commit *commit; + struct dm_crtc_state *crtc_state; + struct drm_dp_aux *aux = NULL; + bool enable = false; + bool enabled = false; + int ret = 0; if (source < 0) { DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", @@ -78,41 +150,124 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) return -EINVAL; } - if (!stream_state) { - DRM_ERROR("No stream state for CRTC%d\n", crtc->index); - return -EINVAL; - } + ret = drm_modeset_lock(&crtc->mutex, NULL); + if (ret) + return ret; - enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO); + spin_lock(&crtc->commit_lock); + commit = list_first_entry_or_null(&crtc->commit_list, + struct drm_crtc_commit, commit_entry); + if (commit) + drm_crtc_commit_get(commit); + spin_unlock(&crtc->commit_lock); - mutex_lock(&adev->dm.dc_lock); - if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state, - enable, enable)) { - mutex_unlock(&adev->dm.dc_lock); - return -EINVAL; + if (commit) { + /* + * Need to wait for all outstanding programming to complete + * in commit tail since it can modify CRC related fields and + * hardware state. Since we're holding the CRTC lock we're + * guaranteed that no other commit work can be queued off + * before we modify the state below. + */ + ret = wait_for_completion_interruptible_timeout( + &commit->hw_done, 10 * HZ); + if (ret) + goto cleanup; } - /* When enabling CRC, we should also disable dithering. */ - dc_stream_set_dither_option(stream_state, - enable ? DITHER_OPTION_TRUN8 - : DITHER_OPTION_DEFAULT); + enable = amdgpu_dm_is_valid_crc_source(source); + crtc_state = to_dm_crtc_state(crtc->state); - mutex_unlock(&adev->dm.dc_lock); + /* + * USER REQ SRC | CURRENT SRC | BEHAVIOR + * ----------------------------- + * None | None | Do nothing + * None | CRTC | Disable CRTC CRC, set default to dither + * None | DPRX | Disable DPRX CRC, need 'aux', set default to dither + * None | CRTC DITHER | Disable CRTC CRC + * None | DPRX DITHER | Disable DPRX CRC, need 'aux' + * CRTC | XXXX | Enable CRTC CRC, no dither + * DPRX | XXXX | Enable DPRX CRC, need 'aux', no dither + * CRTC DITHER | XXXX | Enable CRTC CRC, set dither + * DPRX DITHER | XXXX | Enable DPRX CRC, need 'aux', set dither + */ + if (dm_is_crc_source_dprx(source) || + (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && + dm_is_crc_source_dprx(crtc_state->crc_src))) { + struct amdgpu_dm_connector *aconn = NULL; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (!connector->state || connector->state->crtc != crtc) + continue; + + aconn = to_amdgpu_dm_connector(connector); + break; + } + drm_connector_list_iter_end(&conn_iter); + + if (!aconn) { + DRM_DEBUG_DRIVER("No amd connector matching CRTC-%d\n", crtc->index); + ret = -EINVAL; + goto cleanup; + } + + aux = &aconn->dm_dp_aux.aux; + + if (!aux) { + DRM_DEBUG_DRIVER("No dp aux for amd connector\n"); + ret = -EINVAL; + goto cleanup; + } + } + + if (amdgpu_dm_crtc_configure_crc_source(crtc, crtc_state, source)) { + ret = -EINVAL; + goto cleanup; + } /* * Reading the CRC requires the vblank interrupt handler to be * enabled. Keep a reference until CRC capture stops. */ - if (!crtc_state->crc_enabled && enable) - drm_crtc_vblank_get(crtc); - else if (crtc_state->crc_enabled && !enable) + enabled = amdgpu_dm_is_valid_crc_source(crtc_state->crc_src); + if (!enabled && enable) { + ret = drm_crtc_vblank_get(crtc); + if (ret) + goto cleanup; + + if (dm_is_crc_source_dprx(source)) { + if (drm_dp_start_crc(aux, crtc)) { + DRM_DEBUG_DRIVER("dp start crc failed\n"); + ret = -EINVAL; + goto cleanup; + } + } + } else if (enabled && !enable) { drm_crtc_vblank_put(crtc); + if (dm_is_crc_source_dprx(source)) { + if (drm_dp_stop_crc(aux)) { + DRM_DEBUG_DRIVER("dp stop crc failed\n"); + ret = -EINVAL; + goto cleanup; + } + } + } - crtc_state->crc_enabled = enable; + crtc_state->crc_src = source; /* Reset crc_skipped on dm state */ crtc_state->crc_skip_count = 0; - return 0; + +cleanup: + if (commit) + drm_crtc_commit_put(commit); + + drm_modeset_unlock(&crtc->mutex); + + return ret; } /** @@ -135,7 +290,7 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc) stream_state = crtc_state->stream; /* Early return if CRC capture is not enabled. */ - if (!crtc_state->crc_enabled) + if (!amdgpu_dm_is_valid_crc_source(crtc_state->crc_src)) return; /* @@ -149,10 +304,12 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc) return; } - if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state, - &crcs[0], &crcs[1], &crcs[2])) - return; + if (dm_is_crc_source_crtc(crtc_state->crc_src)) { + if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state, + &crcs[0], &crcs[1], &crcs[2])) + return; - drm_crtc_add_crc_entry(crtc, true, - drm_crtc_accurate_vblank_count(crtc), crcs); + drm_crtc_add_crc_entry(crtc, true, + drm_crtc_accurate_vblank_count(crtc), crcs); + } } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h new file mode 100644 index 000000000000..f7d731797d3f --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -0,0 +1,67 @@ +/* + * 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 AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ +#define AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ + +struct drm_crtc; +struct dm_crtc_state; + +enum amdgpu_dm_pipe_crc_source { + AMDGPU_DM_PIPE_CRC_SOURCE_NONE = 0, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC_DITHER, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER, + AMDGPU_DM_PIPE_CRC_SOURCE_MAX, + AMDGPU_DM_PIPE_CRC_SOURCE_INVALID = -1, +}; + +static inline bool amdgpu_dm_is_valid_crc_source(enum amdgpu_dm_pipe_crc_source source) +{ + return (source > AMDGPU_DM_PIPE_CRC_SOURCE_NONE) && + (source < AMDGPU_DM_PIPE_CRC_SOURCE_MAX); +} + +/* amdgpu_dm_crc.c */ +#ifdef CONFIG_DEBUG_FS +int amdgpu_dm_crtc_configure_crc_source(struct drm_crtc *crtc, + struct dm_crtc_state *dm_crtc_state, + enum amdgpu_dm_pipe_crc_source source); +int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name); +int amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, + const char *src_name, + size_t *values_cnt); +const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc, + size_t *count); +void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc); +#else +#define amdgpu_dm_crtc_set_crc_source NULL +#define amdgpu_dm_crtc_verify_crc_source NULL +#define amdgpu_dm_crtc_get_crc_sources NULL +#define amdgpu_dm_crtc_handle_crc_irq(x) +#endif + +#endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */ 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 36a1d794b4af..f3dfb2887ae0 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 @@ -1053,9 +1053,33 @@ static int target_backlight_read(struct seq_file *m, void *data) return 0; } +static int mst_topo(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct amdgpu_dm_connector *aconnector; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + + seq_printf(m, "\nMST topology for connector %d\n", aconnector->connector_id); + drm_dp_mst_dump_topology(m, &aconnector->mst_mgr); + } + drm_connector_list_iter_end(&conn_iter); + + return 0; +} + static const struct drm_info_list amdgpu_dm_debugfs_list[] = { {"amdgpu_current_backlight_pwm", ¤t_backlight_read}, {"amdgpu_target_backlight_pwm", &target_backlight_read}, + {"amdgpu_mst_topology", &mst_topo}, }; /* 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 a0ed0154a9f0..ee1dc75f5ddc 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 @@ -548,7 +548,9 @@ bool dm_helpers_dp_write_dsc_enable( bool enable ) { - return false; + uint8_t enable_dsc = enable ? 1 : 0; + + return dm_helpers_dp_write_dpcd(ctx, stream->sink->link, DP_DSC_ENABLE, &enable_dsc, 1); } #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 6e205ee36ac3..16218a202b59 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -156,6 +156,26 @@ dm_dp_mst_connector_destroy(struct drm_connector *connector) kfree(amdgpu_dm_connector); } +static int +amdgpu_dm_mst_connector_late_register(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + struct drm_dp_mst_port *port = amdgpu_dm_connector->port; + + return drm_dp_mst_connector_late_register(connector, port); +} + +static void +amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + struct drm_dp_mst_port *port = amdgpu_dm_connector->port; + + drm_dp_mst_connector_early_unregister(connector, port); +} + static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { .detect = dm_dp_mst_detect, .fill_modes = drm_helper_probe_single_connector_modes, @@ -164,7 +184,9 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .atomic_set_property = amdgpu_dm_connector_atomic_set_property, - .atomic_get_property = amdgpu_dm_connector_atomic_get_property + .atomic_get_property = amdgpu_dm_connector_atomic_get_property, + .late_register = amdgpu_dm_mst_connector_late_register, + .early_unregister = amdgpu_dm_mst_connector_early_unregister, }; static int dm_dp_mst_get_modes(struct drm_connector *connector) @@ -388,7 +410,7 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm, struct amdgpu_dm_connector *aconnector) { aconnector->dm_dp_aux.aux.name = "dmdc"; - aconnector->dm_dp_aux.aux.dev = dm->adev->dev; + aconnector->dm_dp_aux.aux.dev = aconnector->base.kdev; aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer; aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc; 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 592fa499c9f8..f4cfa0caeba8 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 @@ -151,18 +151,31 @@ 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 + enum smu_clk_type smu_clk_type = SMU_CLK_COUNT; - 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), - }; + switch (dm_pp_clk_type) { + case DM_PP_CLOCK_TYPE_DISPLAY_CLK: + smu_clk_type = SMU_DISPCLK; + break; + case DM_PP_CLOCK_TYPE_ENGINE_CLK: + smu_clk_type = SMU_GFXCLK; + break; + case DM_PP_CLOCK_TYPE_MEMORY_CLK: + smu_clk_type = SMU_MCLK; + break; + case DM_PP_CLOCK_TYPE_DCEFCLK: + smu_clk_type = SMU_DCEFCLK; + break; + case DM_PP_CLOCK_TYPE_SOCCLK: + smu_clk_type = SMU_SOCCLK; + break; + default: + DRM_ERROR("DM_PPLIB: invalid clock type: %d!\n", + dm_pp_clk_type); + break; + } - return dc_clk_type_map[dm_pp_clk_type]; + return smu_clk_type; } static enum amd_pp_clock_type dc_to_pp_clock_type( @@ -334,7 +347,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_smu_clock_type(clk_type), + dc_to_pp_clock_type(clk_type), &pp_clks)) { get_default_clock_levels(clk_type, dc_clks); return true; @@ -419,7 +432,7 @@ bool dm_pp_get_clock_levels_by_type_with_latency( return false; } else if (adev->smu.ppt_funcs && adev->smu.ppt_funcs->get_clock_by_type_with_latency) { if (smu_get_clock_by_type_with_latency(&adev->smu, - dc_to_pp_clock_type(clk_type), + dc_to_smu_clock_type(clk_type), &pp_clks)) return false; } @@ -801,6 +814,19 @@ enum pp_smu_status pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) return PP_SMU_RESULT_OK; } +enum pp_smu_status pp_nv_set_pstate_handshake_support( + struct pp_smu *pp, BOOLEAN pstate_handshake_supported) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct smu_context *smu = &adev->smu; + + if (smu_display_disable_memory_clock_switch(smu, !pstate_handshake_supported)) + 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) { @@ -916,6 +942,7 @@ void dm_pp_get_funcs( 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; + funcs->nv_funcs.set_pstate_handshake_support = pp_nv_set_pstate_handshake_support; break; #endif default: diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 55ce5b657390..627982cb15d2 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -37,6 +37,9 @@ endif ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml endif +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +DC_LIBS += dcn21 +endif DC_LIBS += dce120 diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c index 461eef1de124..221e0f56389f 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser.c @@ -2796,8 +2796,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .get_device_tag = bios_parser_get_device_tag, - .get_firmware_info = bios_parser_get_firmware_info, - .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info, .get_ss_entry_number = bios_parser_get_ss_entry_number, @@ -2922,6 +2920,7 @@ static bool bios_parser_construct( dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version); bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base); + bp->base.fw_info_valid = bios_parser_get_firmware_info(&bp->base, &bp->base.fw_info) == BP_RESULT_OK; return true; } 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 6aa2e56dfb67..dff65c0fe82f 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1881,8 +1881,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .get_device_tag = bios_parser_get_device_tag, - .get_firmware_info = bios_parser_get_firmware_info, - .get_spread_spectrum_info = bios_parser_get_spread_spectrum_info, .get_ss_entry_number = bios_parser_get_ss_entry_number, @@ -1998,6 +1996,7 @@ static bool bios_parser_construct( dal_bios_parser_init_cmd_tbl_helper2(&bp->cmd_helper, dce_version); bp->base.integrated_info = bios_parser_create_integrated_info(&bp->base); + bp->base.fw_info_valid = bios_parser_get_firmware_info(&bp->base, &bp->base.fw_info) == BP_RESULT_OK; return true; } 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 f9439dfc7b75..db153ddf0fee 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 @@ -67,6 +67,11 @@ 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_1) + case DCN_VERSION_2_1: + *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/bios/dce110/command_table_helper_dce110.c b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c index ca24154468c7..11bf247bb180 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c @@ -153,38 +153,10 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id) static uint8_t dig_encoder_sel_to_atom(enum engine_id id) { - uint8_t atom_dig_encoder_sel = 0; - - switch (id) { - case ENGINE_ID_DIGA: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL; - break; - case ENGINE_ID_DIGB: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL; - break; - case ENGINE_ID_DIGC: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL; - break; - case ENGINE_ID_DIGD: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL; - break; - case ENGINE_ID_DIGE: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL; - break; - case ENGINE_ID_DIGF: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL; - break; - case ENGINE_ID_DIGG: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGG_SEL; - break; - case ENGINE_ID_UNKNOWN: - /* No DIG_FRONT is associated to DIG_BACKEND */ - atom_dig_encoder_sel = 0; - break; - default: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL; - break; - } + /* On any ASIC after DCE80, we manually program the DIG_FE + * selection (see connect_dig_be_to_fe function of the link + * encoder), so translation should always return 0 (no FE). + */ return 0; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c index 0237ae575068..755b6e33140a 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c @@ -150,38 +150,10 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id) static uint8_t dig_encoder_sel_to_atom(enum engine_id id) { - uint8_t atom_dig_encoder_sel = 0; - - switch (id) { - case ENGINE_ID_DIGA: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; - break; - case ENGINE_ID_DIGB: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGB_SEL; - break; - case ENGINE_ID_DIGC: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGC_SEL; - break; - case ENGINE_ID_DIGD: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGD_SEL; - break; - case ENGINE_ID_DIGE: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGE_SEL; - break; - case ENGINE_ID_DIGF: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGF_SEL; - break; - case ENGINE_ID_DIGG: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGG_SEL; - break; - case ENGINE_ID_UNKNOWN: - /* No DIG_FRONT is associated to DIG_BACKEND */ - atom_dig_encoder_sel = 0; - break; - default: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; - break; - } + /* On any ASIC after DCE80, we manually program the DIG_FE + * selection (see connect_dig_be_to_fe function of the link + * encoder), so translation should always return 0 (no FE). + */ return 0; } diff --git a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c index 452034f83e4c..06b4f7fa4a50 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c +++ b/drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c @@ -150,38 +150,10 @@ static uint8_t hpd_sel_to_atom(enum hpd_source_id id) static uint8_t dig_encoder_sel_to_atom(enum engine_id id) { - uint8_t atom_dig_encoder_sel = 0; - - switch (id) { - case ENGINE_ID_DIGA: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; - break; - case ENGINE_ID_DIGB: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGB_SEL; - break; - case ENGINE_ID_DIGC: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGC_SEL; - break; - case ENGINE_ID_DIGD: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGD_SEL; - break; - case ENGINE_ID_DIGE: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGE_SEL; - break; - case ENGINE_ID_DIGF: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGF_SEL; - break; - case ENGINE_ID_DIGG: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGG_SEL; - break; - case ENGINE_ID_UNKNOWN: - /* No DIG_FRONT is associated to DIG_BACKEND */ - atom_dig_encoder_sel = 0; - break; - default: - atom_dig_encoder_sel = ATOM_TRANMSITTER_V6__DIGA_SEL; - break; - } + /* On any ASIC after DCE80, we manually program the DIG_FE + * selection (see connect_dig_be_to_fe function of the link + * encoder), so translation should always return 0 (no FE). + */ return 0; } diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 95f332ee3e7e..16614d73a5fc 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -32,6 +32,10 @@ endif calcs_ccflags := -mhard-float -msse $(cc_stack_align) +ifdef CONFIG_CC_IS_CLANG +calcs_ccflags += -msse2 +endif + CFLAGS_dcn_calcs.o := $(calcs_ccflags) CFLAGS_dcn_calc_auto.o := $(calcs_ccflags) CFLAGS_dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c index 7108d51a9c5b..a1d49256fab7 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c @@ -25,6 +25,7 @@ #include <linux/slab.h> +#include "resource.h" #include "dm_services.h" #include "dce_calcs.h" #include "dc.h" @@ -2852,7 +2853,7 @@ static void populate_initial_data( data->src_height[num_displays * 2 + j] = bw_int_to_fixed(pipe[i].bottom_pipe->plane_res.scl_data.viewport.height); data->src_width[num_displays * 2 + j] = bw_int_to_fixed(pipe[i].bottom_pipe->plane_res.scl_data.viewport.width); data->pitch_in_pixels[num_displays * 2 + j] = bw_int_to_fixed( - pipe[i].bottom_pipe->plane_state->plane_size.grph.surface_pitch); + pipe[i].bottom_pipe->plane_state->plane_size.surface_pitch); data->h_taps[num_displays * 2 + j] = bw_int_to_fixed(pipe[i].bottom_pipe->plane_res.scl_data.taps.h_taps); data->v_taps[num_displays * 2 + j] = bw_int_to_fixed(pipe[i].bottom_pipe->plane_res.scl_data.taps.v_taps); data->h_scale_ratio[num_displays * 2 + j] = fixed31_32_to_bw_fixed( @@ -2977,6 +2978,32 @@ static void populate_initial_data( data->number_of_displays = num_displays; } +static bool all_displays_in_sync(const struct pipe_ctx pipe[], + int pipe_count) +{ + const struct pipe_ctx *active_pipes[MAX_PIPES]; + int i, num_active_pipes = 0; + + for (i = 0; i < pipe_count; i++) { + if (!pipe[i].stream || pipe[i].top_pipe) + continue; + + active_pipes[num_active_pipes++] = &pipe[i]; + } + + if (!num_active_pipes) + return false; + + for (i = 1; i < num_active_pipes; ++i) { + if (!resource_are_streams_timing_synchronizable( + active_pipes[0]->stream, active_pipes[i]->stream)) { + return false; + } + } + + return true; +} + /** * Return: * true - Display(s) configuration supported. @@ -2998,8 +3025,10 @@ bool bw_calcs(struct dc_context *ctx, populate_initial_data(pipe, pipe_count, data); - /*TODO: this should be taken out calcs output and assigned during timing sync for pplib use*/ - calcs_output->all_displays_in_sync = false; + if (ctx->dc->config.multi_mon_pp_mclk_switch) + calcs_output->all_displays_in_sync = all_displays_in_sync(pipe, pipe_count); + else + calcs_output->all_displays_in_sync = false; if (data->number_of_displays != 0) { uint8_t yclk_lvl, sclk_lvl; 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 38365dd911a3..383f4f8db8f4 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c @@ -329,7 +329,7 @@ static void pipe_ctx_to_e2e_pipe_params ( dcc_support_pixel_format(pipe->plane_state->format, &bpe) ? 1 : 0; } input->src.dcc_rate = 1; - input->src.meta_pitch = pipe->plane_state->dcc.grph.meta_pitch; + input->src.meta_pitch = pipe->plane_state->dcc.meta_pitch; input->src.source_scan = dm_horz; input->src.sw_mode = pipe->plane_state->tiling_info.gfx9.swizzle; @@ -705,6 +705,13 @@ static void hack_bounding_box(struct dcn_bw_internal_vars *v, hack_force_pipe_split(v, context->streams[0]->timing.pix_clk_100hz); } + +unsigned int get_highest_allowed_voltage_level(uint32_t hw_internal_rev) +{ + /* we are ok with all levels */ + return 4; +} + bool dcn_validate_bandwidth( struct dc *dc, struct dc_state *context, @@ -732,6 +739,7 @@ bool dcn_validate_bandwidth( memset(v, 0, sizeof(*v)); kernel_fpu_begin(); + v->sr_exit_time = dc->dcn_soc->sr_exit_time; v->sr_enter_plus_exit_time = dc->dcn_soc->sr_enter_plus_exit_time; v->urgent_latency = dc->dcn_soc->urgent_latency; @@ -1268,7 +1276,7 @@ bool dcn_validate_bandwidth( PERFORMANCE_TRACE_END(); BW_VAL_TRACE_FINISH(); - if (bw_limit_pass && v->voltage_level != 5) + if (bw_limit_pass && v->voltage_level <= get_highest_allowed_voltage_level(dc->ctx->asic_id.hw_internal_rev)) return true; else return false; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile index 003c27767e9c..b864869cc7e3 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile @@ -85,3 +85,13 @@ AMD_DAL_CLK_MGR_DCN20 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn20/,$(CLK_MGR_DC AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN20) endif +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +############################################################################### +# DCN21 +############################################################################### +CLK_MGR_DCN21 = rn_clk_mgr.o rn_clk_mgr_vbios_smu.o + +AMD_DAL_CLK_MGR_DCN21 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn21/,$(CLK_MGR_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN21) +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 6b8fc5cbabb8..c43797bea413 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 @@ -37,6 +37,9 @@ #include "dcn10/rv1_clk_mgr.h" #include "dcn10/rv2_clk_mgr.h" #include "dcn20/dcn20_clk_mgr.h" +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#include "dcn21/rn_clk_mgr.h" +#endif int clk_mgr_helper_get_active_display_cnt( @@ -108,6 +111,12 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p #if defined(CONFIG_DRM_AMD_DC_DCN1_0) case FAMILY_RV: +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) { + rn_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg); + break; + } +#endif /* DCN2_1 */ if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) { rv2_clk_mgr_construct(ctx, clk_mgr, pp_smu); break; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c index 814450fefffa..c5c8c4901eed 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c @@ -273,18 +273,12 @@ static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce) { struct dc_debug_options *debug = &clk_mgr_dce->base.ctx->dc->debug; struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios; - struct integrated_info info = { { { 0 } } }; - struct dc_firmware_info fw_info = { { 0 } }; int i; if (bp->integrated_info) - info = *bp->integrated_info; - - clk_mgr_dce->dentist_vco_freq_khz = info.dentist_vco_freq; + clk_mgr_dce->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; if (clk_mgr_dce->dentist_vco_freq_khz == 0) { - bp->funcs->get_firmware_info(bp, &fw_info); - clk_mgr_dce->dentist_vco_freq_khz = - fw_info.smu_gpu_pll_output_freq; + clk_mgr_dce->dentist_vco_freq_khz = bp->fw_info.smu_gpu_pll_output_freq; if (clk_mgr_dce->dentist_vco_freq_khz == 0) clk_mgr_dce->dentist_vco_freq_khz = 3600000; } @@ -317,9 +311,10 @@ static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce) /*Do not allow bad VBIOS/SBIOS to override with invalid values, * check for > 100MHz*/ - if (info.disp_clk_voltage[i].max_supported_clk >= 100000) - clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz = - info.disp_clk_voltage[i].max_supported_clk; + if (bp->integrated_info) + if (bp->integrated_info->disp_clk_voltage[i].max_supported_clk >= 100000) + clk_mgr_dce->max_clks_by_state[clk_state].display_clk_khz = + bp->integrated_info->disp_clk_voltage[i].max_supported_clk; } if (!debug->disable_dfs_bypass && bp->integrated_info) 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 caf8a4a4e442..47f529ce280a 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 @@ -34,6 +34,11 @@ #include "rv1_clk_mgr_vbios_smu.h" #include "rv1_clk_mgr_clk.h" +void rv1_init_clocks(struct clk_mgr *clk_mgr) +{ + memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); +} + static int rv1_determine_dppclk_threshold(struct clk_mgr_internal *clk_mgr, struct dc_clocks *new_clocks) { bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; @@ -232,6 +237,7 @@ static void rv1_enable_pme_wa(struct clk_mgr *clk_mgr_base) } static struct clk_mgr_funcs rv1_clk_funcs = { + .init_clocks = rv1_init_clocks, .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .update_clocks = rv1_update_clocks, .enable_pme_wa = rv1_enable_pme_wa, @@ -246,7 +252,6 @@ void rv1_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_ { struct dc_debug_options *debug = &ctx->dc->debug; struct dc_bios *bp = ctx->dc_bios; - struct dc_firmware_info fw_info = { { 0 } }; clk_mgr->base.ctx = ctx; clk_mgr->pp_smu = pp_smu; @@ -262,9 +267,8 @@ void rv1_clk_mgr_construct(struct dc_context *ctx, struct clk_mgr_internal *clk_ if (bp->integrated_info) clk_mgr->dentist_vco_freq_khz = bp->integrated_info->dentist_vco_freq; - if (clk_mgr->dentist_vco_freq_khz == 0) { - bp->funcs->get_firmware_info(bp, &fw_info); - clk_mgr->dentist_vco_freq_khz = fw_info.smu_gpu_pll_output_freq; + if (bp->fw_info_valid && clk_mgr->dentist_vco_freq_khz == 0) { + clk_mgr->dentist_vco_freq_khz = bp->fw_info.smu_gpu_pll_output_freq; if (clk_mgr->dentist_vco_freq_khz == 0) clk_mgr->dentist_vco_freq_khz = 3600000; } 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 index 50bfb5921de0..3e8ac303bd52 100644 --- 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 @@ -26,8 +26,6 @@ #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" @@ -106,7 +104,6 @@ void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, { 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; @@ -116,28 +113,75 @@ void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, 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); + clk_mgr->dccg, dpp_inst, dppclk_khz, false); } } -void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr) +static void update_global_dpp_clk(struct clk_mgr_internal *clk_mgr, unsigned int khz) { 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; + * clk_mgr->dentist_vco_freq_khz / 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); } +static void update_display_clk(struct clk_mgr_internal *clk_mgr, unsigned int khz) +{ + int disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR + * clk_mgr->dentist_vco_freq_khz / khz; + + uint32_t dispclk_wdivider = dentist_get_did_from_divider(disp_divider); + + REG_UPDATE(DENTIST_DISPCLK_CNTL, + DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider); +} + +static void request_voltage_and_program_disp_clk(struct clk_mgr *clk_mgr_base, unsigned int khz) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc *dc = clk_mgr_base->ctx->dc; + struct pp_smu_funcs_nv *pp_smu = NULL; + bool going_up = clk_mgr->base.clks.dispclk_khz < khz; + + if (dc->res_pool->pp_smu) + pp_smu = &dc->res_pool->pp_smu->nv_funcs; + + clk_mgr->base.clks.dispclk_khz = khz; + + if (going_up && 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_display_clk(clk_mgr, khz); + + if (!going_up && 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); +} + +static void request_voltage_and_program_global_dpp_clk(struct clk_mgr *clk_mgr_base, unsigned int khz) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dc *dc = clk_mgr_base->ctx->dc; + struct pp_smu_funcs_nv *pp_smu = NULL; + bool going_up = clk_mgr->base.clks.dppclk_khz < khz; + + if (dc->res_pool->pp_smu) + pp_smu = &dc->res_pool->pp_smu->nv_funcs; + + clk_mgr->base.clks.dppclk_khz = khz; + clk_mgr->dccg->ref_dppclk = khz; + + if (going_up && 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_global_dpp_clk(clk_mgr, khz); + + if (!going_up && 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); +} void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, @@ -148,12 +192,21 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, 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; + bool force_reset = false; + int i; + if (dc->work_arounds.skip_clock_update) + return; + + if (clk_mgr_base->clks.dispclk_khz == 0 || + dc->debug.force_clock_mode & 0x1) { + //this is from resume or boot up, if forced_clock cfg option used, we bypass program dispclk and DPPCLK, but need set them for S3. + force_reset = true; + //force_clock_mode 0x1: force reset the clock even it is the same clock as long as it is in Passive level. + } 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; @@ -172,6 +225,7 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, 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); @@ -196,10 +250,13 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, } 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.prev_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); } + clk_mgr_base->clks.prev_p_state_change_support = 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; @@ -207,35 +264,48 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, 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 (dc->config.forced_clocks == false) { + // First update display clock + if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) + request_voltage_and_program_disp_clk(clk_mgr_base, 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_PIXELCLK, clk_mgr_base->clks.dppclk_khz / 1000); + // Updating DPP clock requires some more logic + if (!safe_to_lower) { + // For pre-programming, we need to make sure any DPP clock that will go up has to go up - update_dppclk = true; - } + // First raise the global reference if needed + if (new_clocks->dppclk_khz > clk_mgr_base->clks.dppclk_khz) + request_voltage_and_program_global_dpp_clk(clk_mgr_base, new_clocks->dppclk_khz); - 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); + // Then raise any dividers that need raising + for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { + int dpp_inst, dppclk_khz; - 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); + 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, true); + } } 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); + // For post-programming, we can lower ref clk if needed, and unconditionally set all the DTOs + + if (new_clocks->dppclk_khz < clk_mgr_base->clks.dppclk_khz) + request_voltage_and_program_global_dpp_clk(clk_mgr_base, new_clocks->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, false); + } } } if (update_dispclk && @@ -303,6 +373,7 @@ void dcn2_init_clocks(struct clk_mgr *clk_mgr) memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); // Assumption is that boot state always supports pstate clk_mgr->clks.p_state_change_support = true; + clk_mgr->clks.prev_p_state_change_support = true; } void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base) @@ -318,11 +389,32 @@ void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base) } } +void dcn2_get_clock(struct clk_mgr *clk_mgr, + struct dc_state *context, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg) +{ + + if (clock_type == DC_CLOCK_TYPE_DISPCLK) { + clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz; + clock_cfg->min_clock_khz = DCN_MINIMUM_DISPCLK_Khz; + clock_cfg->current_clock_khz = clk_mgr->clks.dispclk_khz; + clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dispclk_khz; + } + if (clock_type == DC_CLOCK_TYPE_DPPCLK) { + clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz; + clock_cfg->min_clock_khz = DCN_MINIMUM_DPPCLK_Khz; + clock_cfg->current_clock_khz = clk_mgr->clks.dppclk_khz; + clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dppclk_khz; + } +} + 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 + .enable_pme_wa = dcn2_enable_pme_wa, + .get_clock = dcn2_get_clock, }; 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 index 5661a5a89847..ac31a9787305 100644 --- 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 @@ -45,4 +45,9 @@ void dcn20_clk_mgr_construct(struct dc_context *ctx, uint32_t dentist_get_did_from_divider(int divider); +void dcn2_get_clock(struct clk_mgr *clk_mgr, + struct dc_state *context, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); + #endif //__DCN20_CLK_MGR_H__ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c new file mode 100644 index 000000000000..787f94d815f4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c @@ -0,0 +1,590 @@ +/* + * 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 "rn_clk_mgr.h" + + +#include "dce100/dce_clk_mgr.h" +#include "rn_clk_mgr_vbios_smu.h" +#include "reg_helper.h" +#include "core_types.h" +#include "dm_helpers.h" + +#include "atomfirmware.h" +#include "clk/clk_10_0_2_offset.h" +#include "clk/clk_10_0_2_sh_mask.h" +#include "renoir_ip_offset.h" + + +/* Constants */ + +#define LPDDR_MEM_RETRAIN_LATENCY 4.977 /* Number obtained from LPDDR4 Training Counter Requirement doc */ + +/* Macros */ + +#define REG(reg_name) \ + (CLK_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) + +void rn_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; + 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 (display_count == 0) + enter_display_off = true; + + if (enter_display_off == safe_to_lower) { + rn_vbios_smu_set_display_count(clk_mgr, 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; + rn_vbios_smu_set_phyclk(clk_mgr, clk_mgr_base->clks.phyclk_khz); + } + + 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; + rn_vbios_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); + } + + 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; + rn_vbios_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); + } + + 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; + 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; + rn_vbios_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); + + update_dispclk = true; + } + + if (dpp_clock_lowered) { + // if clock is being lowered, increase DTO before lowering refclk + dcn20_update_clocks_update_dpp_dto(clk_mgr, context); + rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); + } else { + // if clock is being raised, increase refclk before lowering DTO + if (update_dppclk || update_dispclk) + rn_vbios_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); + 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); + } +} + + +static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) +{ + /* get FbMult value */ + struct fixed31_32 pll_req; + unsigned int fbmult_frac_val = 0; + unsigned int fbmult_int_val = 0; + + + /* + * Register value of fbmult is in 8.16 format, we are converting to 31.32 + * to leverage the fix point operations available in driver + */ + + REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/ + REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */ + + pll_req = dc_fixpt_from_int(fbmult_int_val); + + /* + * since fractional part is only 16 bit in register definition but is 32 bit + * in our fix point definiton, need to shift left by 16 to obtain correct value + */ + pll_req.value |= fbmult_frac_val << 16; + + /* multiply by REFCLK period */ + pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz); + + /* integer part is now VCO frequency in kHz */ + return dc_fixpt_floor(pll_req); +} + +static void rn_dump_clk_registers_internal(struct rn_clk_internal *internal, struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + + internal->CLK1_CLK3_CURRENT_CNT = REG_READ(CLK1_CLK3_CURRENT_CNT); + internal->CLK1_CLK3_BYPASS_CNTL = REG_READ(CLK1_CLK3_BYPASS_CNTL); + + internal->CLK1_CLK3_DS_CNTL = REG_READ(CLK1_CLK3_DS_CNTL); //dcf deep sleep divider + internal->CLK1_CLK3_ALLOW_DS = REG_READ(CLK1_CLK3_ALLOW_DS); + + internal->CLK1_CLK1_CURRENT_CNT = REG_READ(CLK1_CLK1_CURRENT_CNT); + internal->CLK1_CLK1_BYPASS_CNTL = REG_READ(CLK1_CLK1_BYPASS_CNTL); + + internal->CLK1_CLK2_CURRENT_CNT = REG_READ(CLK1_CLK2_CURRENT_CNT); + internal->CLK1_CLK2_BYPASS_CNTL = REG_READ(CLK1_CLK2_BYPASS_CNTL); + + internal->CLK1_CLK0_CURRENT_CNT = REG_READ(CLK1_CLK0_CURRENT_CNT); + internal->CLK1_CLK0_BYPASS_CNTL = REG_READ(CLK1_CLK0_BYPASS_CNTL); +} + +/* This function collect raw clk register values */ +static void rn_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, + struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) +{ + struct rn_clk_internal internal = {0}; + char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"}; + unsigned int chars_printed = 0; + unsigned int remaining_buffer = log_info->bufSize; + + rn_dump_clk_registers_internal(&internal, clk_mgr_base); + + regs_and_bypass->dcfclk = internal.CLK1_CLK3_CURRENT_CNT / 10; + regs_and_bypass->dcf_deep_sleep_divider = internal.CLK1_CLK3_DS_CNTL / 10; + regs_and_bypass->dcf_deep_sleep_allow = internal.CLK1_CLK3_ALLOW_DS; + regs_and_bypass->dprefclk = internal.CLK1_CLK2_CURRENT_CNT / 10; + regs_and_bypass->dispclk = internal.CLK1_CLK0_CURRENT_CNT / 10; + regs_and_bypass->dppclk = internal.CLK1_CLK1_CURRENT_CNT / 10; + + regs_and_bypass->dppclk_bypass = internal.CLK1_CLK1_BYPASS_CNTL & 0x0007; + if (regs_and_bypass->dppclk_bypass < 0 || regs_and_bypass->dppclk_bypass > 4) + regs_and_bypass->dppclk_bypass = 0; + regs_and_bypass->dcfclk_bypass = internal.CLK1_CLK3_BYPASS_CNTL & 0x0007; + if (regs_and_bypass->dcfclk_bypass < 0 || regs_and_bypass->dcfclk_bypass > 4) + regs_and_bypass->dcfclk_bypass = 0; + regs_and_bypass->dispclk_bypass = internal.CLK1_CLK0_BYPASS_CNTL & 0x0007; + if (regs_and_bypass->dispclk_bypass < 0 || regs_and_bypass->dispclk_bypass > 4) + regs_and_bypass->dispclk_bypass = 0; + regs_and_bypass->dprefclk_bypass = internal.CLK1_CLK2_BYPASS_CNTL & 0x0007; + if (regs_and_bypass->dprefclk_bypass < 0 || regs_and_bypass->dprefclk_bypass > 4) + regs_and_bypass->dprefclk_bypass = 0; + + if (log_info->enabled) { + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n"); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dcfclk,%d,%d,%d,%s\n", + regs_and_bypass->dcfclk, + regs_and_bypass->dcf_deep_sleep_divider, + regs_and_bypass->dcf_deep_sleep_allow, + bypass_clks[(int) regs_and_bypass->dcfclk_bypass]); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dprefclk,%d,N/A,N/A,%s\n", + regs_and_bypass->dprefclk, + bypass_clks[(int) regs_and_bypass->dprefclk_bypass]); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "dispclk,%d,N/A,N/A,%s\n", + regs_and_bypass->dispclk, + bypass_clks[(int) regs_and_bypass->dispclk_bypass]); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + //split + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "SPLIT\n"); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + // REGISTER VALUES + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "reg_name,value,clk_type\n"); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n", + internal.CLK1_CLK3_CURRENT_CNT); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n", + internal.CLK1_CLK3_DS_CNTL); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n", + internal.CLK1_CLK3_ALLOW_DS); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n", + internal.CLK1_CLK2_CURRENT_CNT); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_CURRENT_CNT,%d,dispclk\n", + internal.CLK1_CLK0_CURRENT_CNT); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_CURRENT_CNT,%d,dppclk\n", + internal.CLK1_CLK1_CURRENT_CNT); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n", + internal.CLK1_CLK3_BYPASS_CNTL); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n", + internal.CLK1_CLK2_BYPASS_CNTL); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n", + internal.CLK1_CLK0_BYPASS_CNTL); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + + chars_printed = snprintf_count(log_info->pBuf, remaining_buffer, "CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n", + internal.CLK1_CLK1_BYPASS_CNTL); + remaining_buffer -= chars_printed; + *log_info->sum_chars_printed += chars_printed; + log_info->pBuf += chars_printed; + } +} + +/* This function produce translated logical clk state values*/ +void rn_get_clk_states(struct clk_mgr *clk_mgr_base, struct clk_states *s) +{ + struct clk_state_registers_and_bypass sb = { 0 }; + struct clk_log_info log_info = { 0 }; + + rn_dump_clk_registers(&sb, clk_mgr_base, &log_info); + + s->dprefclk_khz = sb.dprefclk; +} + +void rn_enable_pme_wa(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + + rn_vbios_smu_enable_pme_wa(clk_mgr); +} + +static struct clk_mgr_funcs dcn21_funcs = { + .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, + .update_clocks = rn_update_clocks, + .init_clocks = dcn2_init_clocks, + .enable_pme_wa = rn_enable_pme_wa, + /* .dump_clk_registers = rn_dump_clk_registers */ +}; + +struct clk_bw_params rn_bw_params = { + .vram_type = Ddr4MemType, + .num_channels = 1, + .clk_table = { + .entries = { + { + .voltage = 0, + .dcfclk_mhz = 400, + .fclk_mhz = 400, + .memclk_mhz = 800, + .socclk_mhz = 0, + }, + { + .voltage = 0, + .dcfclk_mhz = 483, + .fclk_mhz = 800, + .memclk_mhz = 1600, + .socclk_mhz = 0, + }, + { + .voltage = 0, + .dcfclk_mhz = 602, + .fclk_mhz = 1067, + .memclk_mhz = 1067, + .socclk_mhz = 0, + }, + { + .voltage = 0, + .dcfclk_mhz = 738, + .fclk_mhz = 1333, + .memclk_mhz = 1600, + .socclk_mhz = 0, + }, + }, + + .num_entries = 4, + }, + + .wm_table = { + .entries = { + { + .wm_inst = WM_A, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 23.84, + .valid = true, + }, + { + .wm_inst = WM_B, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 23.84, + .valid = true, + }, + { + .wm_inst = WM_C, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 23.84, + .valid = true, + }, + { + .wm_inst = WM_D, + .wm_type = WM_TYPE_PSTATE_CHG, + .pstate_latency_us = 23.84, + .valid = true, + }, + }, + } +}; + +void build_watermark_ranges(struct clk_bw_params *bw_params, struct pp_smu_wm_range_sets *ranges) +{ + int i, num_valid_sets; + + num_valid_sets = 0; + + for (i = 0; i < WM_SET_COUNT; i++) { + /* skip empty entries, the smu array has no holes*/ + if (!bw_params->wm_table.entries[i].valid) + continue; + + ranges->reader_wm_sets[num_valid_sets].wm_inst = bw_params->wm_table.entries[i].wm_inst; + ranges->reader_wm_sets[num_valid_sets].wm_type = bw_params->wm_table.entries[i].wm_type;; + /* We will not select WM based on dcfclk, so leave it as unconstrained */ + ranges->reader_wm_sets[num_valid_sets].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges->reader_wm_sets[num_valid_sets].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + /* fclk wil be used to select WM*/ + + if (ranges->reader_wm_sets[num_valid_sets].wm_type == WM_TYPE_PSTATE_CHG) { + if (i == 0) + ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = 0; + else { + /* add 1 to make it non-overlapping with next lvl */ + ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = bw_params->clk_table.entries[i - 1].fclk_mhz + 1; + } + ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = bw_params->clk_table.entries[i].fclk_mhz; + + } else { + /* unconstrained for memory retraining */ + ranges->reader_wm_sets[num_valid_sets].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges->reader_wm_sets[num_valid_sets].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* Modify previous watermark range to cover up to max */ + ranges->reader_wm_sets[num_valid_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + } + num_valid_sets++; + } + + ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ + ranges->num_reader_wm_sets = num_valid_sets; + + /* modify the min and max to make sure we cover the whole range*/ + ranges->reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + 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_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges->reader_wm_sets[ranges->num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* This is for writeback only, does not matter currently as no writeback support*/ + ranges->num_writer_wm_sets = 1; + ranges->writer_wm_sets[0].wm_inst = WM_A; + 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; + +} + +void clk_mgr_helper_populate_bw_params(struct clk_bw_params *bw_params, struct dpm_clocks *clock_table, struct hw_asic_id *asic_id) +{ + int i; + + ASSERT(PP_SMU_NUM_FCLK_DPM_LEVELS <= MAX_NUM_DPM_LVL); + + for (i = 0; i < PP_SMU_NUM_FCLK_DPM_LEVELS; i++) { + if (clock_table->FClocks[i].Freq == 0) + break; + + bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i].Freq; + bw_params->clk_table.entries[i].fclk_mhz = clock_table->FClocks[i].Freq; + bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemClocks[i].Freq; + bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i].Freq; + bw_params->clk_table.entries[i].voltage = clock_table->FClocks[i].Vol; + } + bw_params->clk_table.num_entries = i; + + bw_params->vram_type = asic_id->vram_type; + bw_params->num_channels = asic_id->vram_width / DDR4_DRAM_WIDTH; + + for (i = 0; i < WM_SET_COUNT; i++) { + bw_params->wm_table.entries[i].wm_inst = i; + + if (clock_table->FClocks[i].Freq == 0) { + bw_params->wm_table.entries[i].valid = false; + continue; + } + + bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; + bw_params->wm_table.entries[i].valid = true; + } + + if (bw_params->vram_type == LpDdr4MemType) { + /* + * WM set D will be re-purposed for memory retraining + */ + bw_params->wm_table.entries[WM_D].pstate_latency_us = LPDDR_MEM_RETRAIN_LATENCY; + bw_params->wm_table.entries[WM_D].wm_inst = WM_D; + bw_params->wm_table.entries[WM_D].wm_type = WM_TYPE_RETRAINING; + bw_params->wm_table.entries[WM_D].valid = true; + } + +} + +void rn_clk_mgr_construct( + struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg) +{ + struct dc_debug_options *debug = &ctx->dc->debug; + struct dpm_clocks clock_table = { 0 }; + struct clk_state_registers_and_bypass s = { 0 }; + + clk_mgr->base.ctx = ctx; + clk_mgr->base.funcs = &dcn21_funcs; + + clk_mgr->pp_smu = pp_smu; + + 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->dfs_ref_freq_khz = 48000; + + clk_mgr->smu_ver = rn_vbios_smu_get_smu_version(clk_mgr); + + if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { + dcn21_funcs.update_clocks = dcn2_update_clocks_fpga; + clk_mgr->dentist_vco_freq_khz = 3600000; + clk_mgr->base.dprefclk_khz = 600000; + } else { + struct clk_log_info log_info = {0}; + + /* TODO: Check we get what we expect during bringup */ + clk_mgr->dentist_vco_freq_khz = get_vco_frequency_from_reg(clk_mgr); + + /* 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 = 3600000; + + rn_dump_clk_registers(&s, &clk_mgr->base, &log_info); + clk_mgr->base.dprefclk_khz = s.dprefclk; + + if (clk_mgr->base.dprefclk_khz != 600000) { + clk_mgr->base.dprefclk_khz = 600000; + ASSERT(1); //TODO: Renoir follow up. + } + + /* in case we don't get a value from the register, use default */ + if (clk_mgr->base.dprefclk_khz == 0) + clk_mgr->base.dprefclk_khz = 600000; + } + + dce_clock_read_ss_info(clk_mgr); + + clk_mgr->base.bw_params = &rn_bw_params; + + if (pp_smu) { + pp_smu->rn_funcs.get_dpm_clock_table(&pp_smu->rn_funcs.pp_smu, &clock_table); + clk_mgr_helper_populate_bw_params(clk_mgr->base.bw_params, &clock_table, &ctx->asic_id); + } + + /* + * Notify SMU which set of WM should be selected for different ranges of fclk + * On Renoir there is a maximumum of 4 DF pstates supported, could be less + * depending on DDR speed and fused maximum fclk. + */ + if (!debug->disable_pplib_wm_range) { + struct pp_smu_wm_range_sets ranges = {0}; + + build_watermark_ranges(clk_mgr->base.bw_params, &ranges); + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + if (pp_smu && pp_smu->rn_funcs.set_wm_ranges) + pp_smu->rn_funcs.set_wm_ranges(&pp_smu->rn_funcs.pp_smu, &ranges); + } + + /* enable powerfeatures when displaycount goes to 0 */ + if (!debug->disable_48mhz_pwrdwn) + rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(clk_mgr); +} + diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h new file mode 100644 index 000000000000..aadec06fde10 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.h @@ -0,0 +1,39 @@ +/* + * 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 __RN_CLK_MGR_H__ +#define __RN_CLK_MGR_H__ + +struct rn_clk_registers { + uint32_t CLK1_CLK0_CURRENT_CNT; /* DPREFCLK */ +}; + + +void rn_clk_mgr_construct(struct dc_context *ctx, + struct clk_mgr_internal *clk_mgr, + struct pp_smu_funcs *pp_smu, + struct dccg *dccg); + +#endif //__RN_CLK_MGR_H__ diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c new file mode 100644 index 000000000000..50984c1811bb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c @@ -0,0 +1,200 @@ +/* + * Copyright 2012-16 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "core_types.h" +#include "clk_mgr_internal.h" +#include "reg_helper.h" + +#include "renoir_ip_offset.h" + +#include "mp/mp_12_0_0_offset.h" +#include "mp/mp_12_0_0_sh_mask.h" + +#define REG(reg_name) \ + (MP1_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) + +#define FN(reg_name, field) \ + FD(reg_name##__##field) + +#define VBIOSSMC_MSG_TestMessage 0x1 +#define VBIOSSMC_MSG_GetSmuVersion 0x2 +#define VBIOSSMC_MSG_PowerUpGfx 0x3 +#define VBIOSSMC_MSG_SetDispclkFreq 0x4 +#define VBIOSSMC_MSG_SetDprefclkFreq 0x5 +#define VBIOSSMC_MSG_PowerDownGfx 0x6 +#define VBIOSSMC_MSG_SetDppclkFreq 0x7 +#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x8 +#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x9 +#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0xA +#define VBIOSSMC_MSG_GetFclkFrequency 0xB +#define VBIOSSMC_MSG_SetDisplayCount 0xC +#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0xD +#define VBIOSSMC_MSG_UpdatePmeRestore 0xE + +int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param) +{ + /* First clear response register */ + REG_WRITE(MP1_SMN_C2PMSG_91, 0); + + /* Set the parameter register for the SMU message, unit is Mhz */ + REG_WRITE(MP1_SMN_C2PMSG_83, param); + + /* Trigger the message transaction by writing the message ID */ + REG_WRITE(MP1_SMN_C2PMSG_67, msg_id); + + REG_WAIT(MP1_SMN_C2PMSG_91, CONTENT, 1, 10, 200000); + + /* Actual dispclk set is returned in the parameter register */ + return REG_READ(MP1_SMN_C2PMSG_83); +} + +int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr) +{ + return rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_GetSmuVersion, + 0); +} + + +int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz) +{ + int actual_dispclk_set_mhz = -1; + struct dc *core_dc = clk_mgr->base.ctx->dc; + struct dmcu *dmcu = core_dc->res_pool->dmcu; + uint32_t clk = requested_dispclk_khz / 1000; + + if (clk <= 100) + clk = 101; + + /* Unit of SMU msg parameter is Mhz */ + actual_dispclk_set_mhz = rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDispclkFreq, + clk); + + if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { + if (clk_mgr->dfs_bypass_disp_clk != actual_dispclk_set_mhz) + dmcu->funcs->set_psr_wait_loop(dmcu, + actual_dispclk_set_mhz / 7); + } + } + + return actual_dispclk_set_mhz * 1000; +} + +int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr) +{ + int actual_dprefclk_set_mhz = -1; + + actual_dprefclk_set_mhz = rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDprefclkFreq, + clk_mgr->base.dprefclk_khz / 1000); + + /* TODO: add code for programing DP DTO, currently this is down by command table */ + + return actual_dprefclk_set_mhz * 1000; +} + +int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz) +{ + int actual_dcfclk_set_mhz = -1; + + if (clk_mgr->smu_ver < 0xFFFFFFFF) + return actual_dcfclk_set_mhz; + + actual_dcfclk_set_mhz = rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetHardMinDcfclkByFreq, + requested_dcfclk_khz / 1000); + + return actual_dcfclk_set_mhz * 1000; +} + +int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz) +{ + int actual_min_ds_dcfclk_mhz = -1; + + if (clk_mgr->smu_ver < 0xFFFFFFFF) + return actual_min_ds_dcfclk_mhz; + + actual_min_ds_dcfclk_mhz = rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetMinDeepSleepDcfclk, + requested_min_ds_dcfclk_khz / 1000); + + return actual_min_ds_dcfclk_mhz * 1000; +} + +void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz) +{ + rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetPhyclkVoltageByFreq, + requested_phyclk_khz / 1000); +} + +int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz) +{ + int actual_dppclk_set_mhz = -1; + + uint32_t clk = requested_dpp_khz / 1000; + + if (clk <= 100) + clk = 101; + + actual_dppclk_set_mhz = rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDppclkFreq, + clk); + + return actual_dppclk_set_mhz * 1000; +} + +void rn_vbios_smu_set_display_count(struct clk_mgr_internal *clk_mgr, int display_count) +{ + rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_SetDisplayCount, + display_count); +} + +void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr) +{ + rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown, + 0); +} + +void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) +{ + rn_vbios_smu_send_msg_with_param( + clk_mgr, + VBIOSSMC_MSG_UpdatePmeRestore, + 0); +} diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h new file mode 100644 index 000000000000..da3a49487c6d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.h @@ -0,0 +1,40 @@ +/* + * 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_RN_CLK_MGR_VBIOS_SMU_H_ +#define DAL_DC_RN_CLK_MGR_VBIOS_SMU_H_ + +int rn_vbios_smu_get_smu_version(struct clk_mgr_internal *clk_mgr); +int rn_vbios_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz); +int rn_vbios_smu_set_dprefclk(struct clk_mgr_internal *clk_mgr); +int rn_vbios_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz); +int rn_vbios_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz); +void rn_vbios_smu_set_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz); +int rn_vbios_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz); +void rn_vbios_smu_set_display_count(struct clk_mgr_internal *clk_mgr, int display_count); +void rn_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr); +void rn_vbios_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr); + +#endif /* DAL_DC_DCN10_RV1_CLK_MGR_VBIOS_SMU_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index cbc480a33376..5d1adeda4d90 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -181,13 +181,25 @@ static bool create_links( link = link_create(&link_init_params); if (link) { - if (dc->config.edp_not_connected && - link->connector_signal == SIGNAL_TYPE_EDP) { - link_destroy(&link); - } else { + bool should_destory_link = false; + + if (link->connector_signal == SIGNAL_TYPE_EDP) { + if (dc->config.edp_not_connected) + should_destory_link = true; + else if (dc->debug.remove_disconnect_edp) { + enum dc_connection_type type; + dc_link_detect_sink(link, &type); + if (type == dc_connection_none) + should_destory_link = true; + } + } + + if (!should_destory_link) { dc->links[dc->link_count] = link; link->dc = dc; ++dc->link_count; + } else { + link_destroy(&link); } } } @@ -279,7 +291,9 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc, dc->hwss.set_drr(&pipe, 1, adjust->v_total_min, - adjust->v_total_max); + adjust->v_total_max, + adjust->v_total_mid, + adjust->v_total_mid_frame_num); ret = true; } @@ -675,6 +689,11 @@ static bool construct(struct dc *dc, if (!dc->clk_mgr) goto fail; +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + if (dc->res_pool->funcs->update_bw_bounding_box) + dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params); +#endif + /* Creation of current_state must occur after dc->dml * is initialized in dc_create_resource_pool because * on creation it copies the contents of dc->dml @@ -948,7 +967,7 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, { struct timing_generator *tg; struct dc_link *link = sink->link; - unsigned int inst; + unsigned int enc_inst, tg_inst; /* Check for enabled DIG to identify enabled display */ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) @@ -960,13 +979,22 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, * current implementation always map 1-to-1, so this code makes * the same assumption and doesn't check OTG source. */ - inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + enc_inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); /* Instance should be within the range of the pool */ - if (inst >= dc->res_pool->pipe_count) + if (enc_inst >= dc->res_pool->pipe_count) + return false; + + if (enc_inst >= dc->res_pool->stream_enc_count) + return false; + + tg_inst = dc->res_pool->stream_enc[enc_inst]->funcs->dig_source_otg( + dc->res_pool->stream_enc[enc_inst]); + + if (tg_inst >= dc->res_pool->timing_generator_count) return false; - tg = dc->res_pool->timing_generators[inst]; + tg = dc->res_pool->timing_generators[tg_inst]; if (!tg->funcs->is_matching_timing) return false; @@ -979,10 +1007,11 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc, dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz( dc->res_pool->dp_clock_source, - inst, &pix_clk_100hz); + tg_inst, &pix_clk_100hz); if (crtc_timing->pix_clk_100hz != pix_clk_100hz) return false; + } return true; @@ -1065,7 +1094,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c if (result != DC_OK) return result; - if (context->stream_count > 1) { + if (context->stream_count > 1 && !dc->debug.disable_timing_sync) { enable_timing_multisync(dc, context); program_timing_sync(dc, context); } @@ -1208,6 +1237,12 @@ struct dc_state *dc_copy_state(struct dc_state *src_ctx) if (cur_pipe->bottom_pipe) cur_pipe->bottom_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; + if (cur_pipe->prev_odm_pipe) + cur_pipe->prev_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; + + if (cur_pipe->next_odm_pipe) + cur_pipe->next_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; + } for (i = 0; i < new_ctx->stream_count; i++) { @@ -1239,6 +1274,55 @@ void dc_release_state(struct dc_state *context) kref_put(&context->refcount, dc_state_free); } +bool dc_set_generic_gpio_for_stereo(bool enable, + struct gpio_service *gpio_service) +{ + enum gpio_result gpio_result = GPIO_RESULT_NON_SPECIFIC_ERROR; + struct gpio_pin_info pin_info; + struct gpio *generic; + struct gpio_generic_mux_config *config = kzalloc(sizeof(struct gpio_generic_mux_config), + GFP_KERNEL); + + if (!config) + return false; + pin_info = dal_gpio_get_generic_pin_info(gpio_service, GPIO_ID_GENERIC, 0); + + if (pin_info.mask == 0xFFFFFFFF || pin_info.offset == 0xFFFFFFFF) { + kfree(config); + return false; + } else { + generic = dal_gpio_service_create_generic_mux( + gpio_service, + pin_info.offset, + pin_info.mask); + } + + if (!generic) { + kfree(config); + return false; + } + + gpio_result = dal_gpio_open(generic, GPIO_MODE_OUTPUT); + + config->enable_output_from_mux = enable; + config->mux_select = GPIO_SIGNAL_SOURCE_PASS_THROUGH_STEREO_SYNC; + + if (gpio_result == GPIO_RESULT_OK) + gpio_result = dal_mux_setup_config(generic, config); + + if (gpio_result == GPIO_RESULT_OK) { + dal_gpio_close(generic); + dal_gpio_destroy_generic_mux(&generic); + kfree(config); + return true; + } else { + dal_gpio_close(generic); + dal_gpio_destroy_generic_mux(&generic); + kfree(config); + return false; + } +} + static bool is_surface_in_context( const struct dc_state *context, const struct dc_plane_state *plane_state) @@ -1305,8 +1389,8 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa } if (u->plane_info->dcc.enable != u->surface->dcc.enable - || u->plane_info->dcc.grph.independent_64b_blks != u->surface->dcc.grph.independent_64b_blks - || u->plane_info->dcc.grph.meta_pitch != u->surface->dcc.grph.meta_pitch) { + || u->plane_info->dcc.independent_64b_blks != u->surface->dcc.independent_64b_blks + || u->plane_info->dcc.meta_pitch != u->surface->dcc.meta_pitch) { update_flags->bits.dcc_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED); } @@ -1320,9 +1404,9 @@ static enum surface_update_type get_plane_info_update_type(const struct dc_surfa elevate_update_type(&update_type, UPDATE_TYPE_FULL); } - if (u->plane_info->plane_size.grph.surface_pitch != u->surface->plane_size.grph.surface_pitch - || u->plane_info->plane_size.video.luma_pitch != u->surface->plane_size.video.luma_pitch - || u->plane_info->plane_size.video.chroma_pitch != u->surface->plane_size.video.chroma_pitch) { + if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch + || u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch + || u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) { update_flags->bits.plane_size_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED); } @@ -1542,6 +1626,9 @@ enum surface_update_type dc_check_update_surfaces_for_stream( for (i = 0; i < surface_count; i++) updates[i].surface->update_flags.raw = 0xFFFFFFFF; + if (type == UPDATE_TYPE_FAST && memcmp(&dc->current_state->bw_ctx.bw.dcn.clk, &dc->clk_mgr->clks, offsetof(struct dc_clocks, prev_p_state_change_support)) != 0) + dc->optimized_required = true; + return type; } @@ -1618,6 +1705,8 @@ static void copy_surface_update_to_plane( srf_update->plane_info->dcc; surface->sdr_white_level = srf_update->plane_info->sdr_white_level; + surface->layer_index = + srf_update->plane_info->layer_index; } if (srf_update->gamma && @@ -1784,9 +1873,7 @@ static void commit_planes_do_stream_update(struct dc *dc, for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - if (!pipe_ctx->top_pipe && - pipe_ctx->stream && - pipe_ctx->stream == stream) { + if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) { if (stream_update->periodic_interrupt0 && dc->hwss.setup_periodic_interrupt) @@ -1812,7 +1899,7 @@ static void commit_planes_do_stream_update(struct dc *dc, 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); + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; #endif resource_build_bit_depth_reduction_params(pipe_ctx->stream, &pipe_ctx->stream->bit_depth_params); @@ -1820,10 +1907,12 @@ static void commit_planes_do_stream_update(struct dc *dc, &stream->bit_depth_params, &stream->clamping); #if defined(CONFIG_DRM_AMD_DC_DCN2_0) - if (odm_pipe) + while (odm_pipe) { odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp, &stream->bit_depth_params, &stream->clamping); + odm_pipe = odm_pipe->next_odm_pipe; + } #endif } @@ -1840,13 +1929,21 @@ static void commit_planes_do_stream_update(struct dc *dc, if (stream_update->dpms_off) { dc->hwss.pipe_control_lock(dc, pipe_ctx, true); + if (*stream_update->dpms_off) { - core_link_disable_stream(pipe_ctx, KEEP_ACQUIRED_RESOURCE); + core_link_disable_stream(pipe_ctx); + /* for dpms, keep acquired resources*/ + if (pipe_ctx->stream_res.audio && !dc->debug.az_endpoint_mute_only) + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + dc->hwss.optimize_bandwidth(dc, dc->current_state); } else { - dc->hwss.prepare_bandwidth(dc, dc->current_state); + if (!dc->optimize_seamless_boot) + dc->hwss.prepare_bandwidth(dc, dc->current_state); + core_link_enable_stream(dc->current_state, pipe_ctx); } + dc->hwss.pipe_control_lock(dc, pipe_ctx, false); } @@ -1936,6 +2033,7 @@ static void commit_planes_for_stream(struct dc *dc, struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; if (!pipe_ctx->top_pipe && + !pipe_ctx->prev_odm_pipe && pipe_ctx->stream && pipe_ctx->stream == stream) { struct dc_stream_status *stream_status = NULL; @@ -2050,7 +2148,7 @@ void dc_commit_updates_for_stream(struct dc *dc, enum surface_update_type update_type; struct dc_state *context; struct dc_context *dc_ctx = dc->ctx; - int i, j; + int i; stream_status = dc_stream_get_status(stream); context = dc->current_state; @@ -2088,16 +2186,6 @@ void dc_commit_updates_for_stream(struct dc *dc, copy_surface_update_to_plane(surface, &srf_updates[i]); - if (update_type >= UPDATE_TYPE_MED) { - for (j = 0; j < dc->res_pool->pipe_count; j++) { - struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; - - if (pipe_ctx->plane_state != surface) - continue; - - resource_build_scaling_params(pipe_ctx); - } - } } copy_stream_update_to_stream(dc, context, stream, stream_update); @@ -2187,6 +2275,14 @@ void dc_set_power_state( dc_resource_state_construct(dc, dc->current_state); dc->hwss.init_hw(dc); + +#ifdef CONFIG_DRM_AMD_DC_DCN2_0 + if (dc->hwss.init_sys_ctx != NULL && + dc->vm_pa_config.valid) { + dc->hwss.init_sys_ctx(dc->hwseq, dc, &dc->vm_pa_config); + } +#endif + break; default: ASSERT(dc->current_state->stream_count == 0); @@ -2387,3 +2483,14 @@ void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx info->fClock = (unsigned int)state->bw_ctx.bw.dcn.clk.fclk_khz; info->phyClock = (unsigned int)state->bw_ctx.bw.dcn.clk.phyclk_khz; } +enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping) +{ + if (dc->hwss.set_clock) + return dc->hwss.set_clock(dc, clock_type, clk_khz, stepping); + return DC_ERROR_UNEXPECTED; +} +void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg) +{ + if (dc->hwss.get_clock) + dc->hwss.get_clock(dc, clock_type, clock_cfg); +} diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index 5903e7822f98..b9227d5de3a3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -115,16 +115,16 @@ void pre_surface_trace( plane_state->clip_rect.height); SURFACE_TRACE( - "plane_state->plane_size.grph.surface_size.x = %d;\n" - "plane_state->plane_size.grph.surface_size.y = %d;\n" - "plane_state->plane_size.grph.surface_size.width = %d;\n" - "plane_state->plane_size.grph.surface_size.height = %d;\n" - "plane_state->plane_size.grph.surface_pitch = %d;\n", - plane_state->plane_size.grph.surface_size.x, - plane_state->plane_size.grph.surface_size.y, - plane_state->plane_size.grph.surface_size.width, - plane_state->plane_size.grph.surface_size.height, - plane_state->plane_size.grph.surface_pitch); + "plane_state->plane_size.surface_size.x = %d;\n" + "plane_state->plane_size.surface_size.y = %d;\n" + "plane_state->plane_size.surface_size.width = %d;\n" + "plane_state->plane_size.surface_size.height = %d;\n" + "plane_state->plane_size.surface_pitch = %d;\n", + plane_state->plane_size.surface_size.x, + plane_state->plane_size.surface_size.y, + plane_state->plane_size.surface_size.width, + plane_state->plane_size.surface_size.height, + plane_state->plane_size.surface_pitch); SURFACE_TRACE( @@ -202,20 +202,20 @@ void update_surface_trace( SURFACE_TRACE( "plane_info->color_space = %d;\n" "plane_info->format = %d;\n" - "plane_info->plane_size.grph.surface_pitch = %d;\n" - "plane_info->plane_size.grph.surface_size.height = %d;\n" - "plane_info->plane_size.grph.surface_size.width = %d;\n" - "plane_info->plane_size.grph.surface_size.x = %d;\n" - "plane_info->plane_size.grph.surface_size.y = %d;\n" + "plane_info->plane_size.surface_pitch = %d;\n" + "plane_info->plane_size.surface_size.height = %d;\n" + "plane_info->plane_size.surface_size.width = %d;\n" + "plane_info->plane_size.surface_size.x = %d;\n" + "plane_info->plane_size.surface_size.y = %d;\n" "plane_info->rotation = %d;\n" "plane_info->stereo_format = %d;\n", update->plane_info->color_space, update->plane_info->format, - update->plane_info->plane_size.grph.surface_pitch, - update->plane_info->plane_size.grph.surface_size.height, - update->plane_info->plane_size.grph.surface_size.width, - update->plane_info->plane_size.grph.surface_size.x, - update->plane_info->plane_size.grph.surface_size.y, + update->plane_info->plane_size.surface_pitch, + update->plane_info->plane_size.surface_size.height, + update->plane_info->plane_size.surface_size.width, + update->plane_info->plane_size.surface_size.x, + update->plane_info->plane_size.surface_size.y, update->plane_info->rotation, update->plane_info->stereo_format); 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 355b4ba12796..ca20b150afcc 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -45,10 +45,6 @@ #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) @@ -684,6 +680,56 @@ static bool is_same_edid(struct dc_edid *old_edid, struct dc_edid *new_edid) return (memcmp(old_edid->raw_edid, new_edid->raw_edid, new_edid->length) == 0); } +bool wait_for_alt_mode(struct dc_link *link) +{ + + /** + * something is terribly wrong if time out is > 200ms. (5Hz) + * 500 microseconds * 400 tries us 200 ms + **/ + unsigned int sleep_time_in_microseconds = 500; + unsigned int tries_allowed = 400; + bool is_in_alt_mode; + unsigned long long enter_timestamp; + unsigned long long finish_timestamp; + unsigned long long time_taken_in_ns; + int tries_taken; + + DC_LOGGER_INIT(link->ctx->logger); + + if (link->link_enc->funcs->is_in_alt_mode == NULL) + return true; + + is_in_alt_mode = link->link_enc->funcs->is_in_alt_mode(link->link_enc); + DC_LOG_WARNING("DP Alt mode state on HPD: %d\n", is_in_alt_mode); + + if (is_in_alt_mode) + return true; + + enter_timestamp = dm_get_timestamp(link->ctx); + + for (tries_taken = 0; tries_taken < tries_allowed; tries_taken++) { + udelay(sleep_time_in_microseconds); + /* ask the link if alt mode is enabled, if so return ok */ + if (link->link_enc->funcs->is_in_alt_mode(link->link_enc)) { + + finish_timestamp = dm_get_timestamp(link->ctx); + time_taken_in_ns = dm_get_elapse_time_in_ns( + link->ctx, finish_timestamp, enter_timestamp); + DC_LOG_WARNING("Alt mode entered finished after %llu ms\n", + div_u64(time_taken_in_ns, 1000000)); + return true; + } + + } + finish_timestamp = dm_get_timestamp(link->ctx); + time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, + enter_timestamp); + DC_LOG_WARNING("Alt mode has timed out after %llu ms\n", + div_u64(time_taken_in_ns, 1000000)); + return false; +} + /** * dc_link_detect() - Detect if a sink is attached to a given link * @@ -772,6 +818,15 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) } case SIGNAL_TYPE_DISPLAY_PORT: { + /* wa HPD high coming too early*/ + if (link->link_enc->features.flags.bits.DP_IS_USB_C == 1) { + + /* if alt mode times out, return false */ + if (wait_for_alt_mode(link) == false) { + return false; + } + } + if (!detect_dp( link, &sink_caps, @@ -795,16 +850,9 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) dc_sink_release(prev_sink); } else { /* Empty dongle plug in */ - for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { - int fail_count = 0; - - dp_verify_link_cap(link, - &link->reported_link_cap, - &fail_count); - - if (fail_count == 0) - break; - } + dp_verify_link_cap_with_retries(link, + &link->reported_link_cap, + LINK_TRAINING_MAX_VERIFY_RETRY); } return true; } @@ -908,17 +956,9 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason) */ /* deal with non-mst cases */ - for (i = 0; i < LINK_TRAINING_MAX_VERIFY_RETRY; i++) { - int fail_count = 0; - - dp_verify_link_cap(link, - &link->reported_link_cap, - &fail_count); - - if (fail_count == 0) - break; - } - + dp_verify_link_cap_with_retries(link, + &link->reported_link_cap, + LINK_TRAINING_MAX_VERIFY_RETRY); } else { // If edid is the same, then discard new sink and revert back to original sink if (same_edid) { @@ -1188,6 +1228,9 @@ static bool construct( link->ctx = dc_ctx; link->link_index = init_params->link_index; + memset(&link->preferred_training_settings, 0, sizeof(struct dc_link_training_overrides)); + memset(&link->preferred_link_setting, 0, sizeof(struct dc_link_settings)); + link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { @@ -1384,57 +1427,6 @@ void link_destroy(struct dc_link **link) *link = NULL; } -static void dpcd_configure_panel_mode( - struct dc_link *link, - enum dp_panel_mode panel_mode) -{ - union dpcd_edp_config edp_config_set; - bool panel_mode_edp = false; - DC_LOGGER_INIT(link->ctx->logger); - - memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config)); - - if (DP_PANEL_MODE_DEFAULT != panel_mode) { - - switch (panel_mode) { - case DP_PANEL_MODE_EDP: - case DP_PANEL_MODE_SPECIAL: - panel_mode_edp = true; - break; - - default: - break; - } - - /*set edp panel mode in receiver*/ - core_link_read_dpcd( - link, - DP_EDP_CONFIGURATION_SET, - &edp_config_set.raw, - sizeof(edp_config_set.raw)); - - if (edp_config_set.bits.PANEL_MODE_EDP - != panel_mode_edp) { - enum ddc_result result = DDC_RESULT_UNKNOWN; - - edp_config_set.bits.PANEL_MODE_EDP = - panel_mode_edp; - result = core_link_write_dpcd( - link, - DP_EDP_CONFIGURATION_SET, - &edp_config_set.raw, - sizeof(edp_config_set.raw)); - - ASSERT(result == DDC_RESULT_SUCESSFULL); - } - } - DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " - "eDP panel mode enabled: %d \n", - link->link_index, - link->dpcd_caps.panel_mode_edp, - panel_mode_edp); -} - static void enable_stream_features(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; @@ -1466,6 +1458,19 @@ static enum dc_status enable_link_dp( struct dc_link *link = stream->link; struct dc_link_settings link_settings = {0}; enum dp_panel_mode panel_mode; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool fec_enable; +#endif + int i; + bool apply_seamless_boot_optimization = false; + + // check for seamless boot + for (i = 0; i < state->stream_count; i++) { + if (state->streams[i]->apply_seamless_boot_optimization) { + apply_seamless_boot_optimization = true; + break; + } + } /* get link settings for video mode timing */ decide_link_settings(stream, &link_settings); @@ -1487,7 +1492,8 @@ static enum dc_status enable_link_dp( pipe_ctx->stream_res.pix_clk_params.requested_sym_clk = link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ; - state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false); + if (!apply_seamless_boot_optimization) + state->clk_mgr->funcs->update_clocks(state->clk_mgr, state, false); dp_enable_link_phy( link, @@ -1502,18 +1508,19 @@ static enum dc_status enable_link_dp( } panel_mode = dp_get_panel_mode(link); - dpcd_configure_panel_mode(link, panel_mode); + dp_set_panel_mode(link, panel_mode); skip_video_pattern = true; 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 (link->aux_access_disabled) { + dc_link_dp_perform_link_training_skip_aux(link, &link_settings); - if (perform_link_training_with_retries( + link->cur_link_settings = link_settings; + status = DC_OK; + } else if (perform_link_training_with_retries( link, &link_settings, skip_video_pattern, @@ -1525,7 +1532,12 @@ static enum dc_status enable_link_dp( status = DC_FAIL_DP_LINK_TRAINING; #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - dp_set_fec_enable(link, true); + if (link->preferred_training_settings.fec_enable != NULL) + fec_enable = *link->preferred_training_settings.fec_enable; + else + fec_enable = true; + + dp_set_fec_enable(link, fec_enable); #endif return status; } @@ -2755,21 +2767,27 @@ void core_link_enable_stream( CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, COLOR_DEPTH_UNDEFINED); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (pipe_ctx->stream->timing.flags.DSC) { + 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 core_dc->hwss.enable_stream(pipe_ctx); - 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); + /* Set DPS PPS SDP (AKA "info frames") */ + if (pipe_ctx->stream->timing.flags.DSC) { + if (dc_is_dp_signal(pipe_ctx->stream->signal) || + dc_is_virtual_signal(pipe_ctx->stream->signal)) + dp_set_dsc_pps_sdp(pipe_ctx, true); } #endif + + if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + allocate_mst_payload(pipe_ctx); + core_dc->hwss.unblank_stream(pipe_ctx, &pipe_ctx->stream->link->cur_link_settings); @@ -2786,7 +2804,7 @@ void core_link_enable_stream( #endif } -void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) +void core_link_disable_stream(struct pipe_ctx *pipe_ctx) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; struct dc_stream_state *stream = pipe_ctx->stream; @@ -2821,13 +2839,13 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option) write_i2c_redriver_setting(pipe_ctx, false); } } - core_dc->hwss.disable_stream(pipe_ctx, option); + core_dc->hwss.disable_stream(pipe_ctx); 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); + if (pipe_ctx->stream->timing.flags.DSC) { + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + dp_set_dsc_enable(pipe_ctx, false); } #endif } @@ -2836,7 +2854,7 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) { struct dc *core_dc = pipe_ctx->stream->ctx->dc; - if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A) + if (!dc_is_hdmi_signal(pipe_ctx->stream->signal)) return; core_dc->hwss.set_avmute(pipe_ctx, enable); @@ -2999,8 +3017,10 @@ void dc_link_set_preferred_link_settings(struct dc *dc, for (i = 0; i < MAX_PIPES; i++) { pipe = &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe->stream && pipe->stream->link) { - if (pipe->stream->link == link) + if (pipe->stream->link == link) { + link_stream = pipe->stream; break; + } } } @@ -3008,20 +3028,40 @@ void dc_link_set_preferred_link_settings(struct dc *dc, if (i == MAX_PIPES) return; - link_stream = link->dc->current_state->res_ctx.pipe_ctx[i].stream; - /* Cannot retrain link if backend is off */ if (link_stream->dpms_off) return; - if (link_stream) - decide_link_settings(link_stream, &store_settings); + decide_link_settings(link_stream, &store_settings); if ((store_settings.lane_count != LANE_COUNT_UNKNOWN) && (store_settings.link_rate != LINK_RATE_UNKNOWN)) dp_retrain_link_dp_test(link, &store_settings, false); } +void dc_link_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain) +{ + if (lt_overrides != NULL) + link->preferred_training_settings = *lt_overrides; + else + memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings)); + + if (link_setting != NULL) { + link->preferred_link_setting = *link_setting; + } else { + link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; + link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN; + } + + /* Retrain now, or wait until next stream update to apply */ + if (skip_immediate_retrain == false) + dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); +} + void dc_link_enable_hpd(const struct dc_link *link) { dc_link_dp_enable_hpd(link); @@ -3032,7 +3072,6 @@ void dc_link_disable_hpd(const struct dc_link *link) dc_link_dp_disable_hpd(link); } - void dc_link_set_test_pattern(struct dc_link *link, enum dp_test_pattern test_pattern, const struct link_training_settings *p_link_settings, 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 e6da8506128b..505967b48e14 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 @@ -294,7 +294,7 @@ static uint32_t defer_delay_converter_wa( { struct dc_link *link = ddc->link; - if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_4 && + if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 && !memcmp(link->dpcd_caps.branch_dev_name, DP_DVI_CONVERTER_ID_4, sizeof(link->dpcd_caps.branch_dev_name))) 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 2c7aaed907b9..f5742719b5d9 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -49,7 +49,7 @@ static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_a, struct dc_link_settings link_setting_b); -static void wait_for_training_aux_rd_interval( +static uint32_t get_training_aux_rd_interval( struct dc_link *link, uint32_t default_wait_in_micro_secs) { @@ -68,15 +68,21 @@ static void wait_for_training_aux_rd_interval( sizeof(training_rd_interval)); if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) - default_wait_in_micro_secs = - training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; + default_wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000; } - udelay(default_wait_in_micro_secs); + return default_wait_in_micro_secs; +} + +static void wait_for_training_aux_rd_interval( + struct dc_link *link, + uint32_t wait_in_micro_secs) +{ + udelay(wait_in_micro_secs); DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", __func__, - default_wait_in_micro_secs); + wait_in_micro_secs); } static void dpcd_set_training_pattern( @@ -95,27 +101,27 @@ 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) +static enum dc_dp_training_pattern get_supported_tp(struct dc_link *link) { - enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2; + enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_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; + highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3; if (features->flags.bits.IS_TPS4_CAPABLE) - highest_tp = HW_DP_TRAINING_PATTERN_4; + highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4; if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED && - highest_tp >= HW_DP_TRAINING_PATTERN_4) - return HW_DP_TRAINING_PATTERN_4; + highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4) + return DP_TRAINING_PATTERN_SEQUENCE_4; if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED && - highest_tp >= HW_DP_TRAINING_PATTERN_3) - return HW_DP_TRAINING_PATTERN_3; + highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3) + return DP_TRAINING_PATTERN_SEQUENCE_3; - return HW_DP_TRAINING_PATTERN_2; + return DP_TRAINING_PATTERN_SEQUENCE_2; } static void dpcd_set_link_settings( @@ -126,7 +132,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; + enum dc_dp_training_pattern dp_tr_pattern; downspread.raw = (uint8_t) (lt_settings->link_settings.link_spread); @@ -134,21 +140,21 @@ static void dpcd_set_link_settings( lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; - lane_count_set.bits.ENHANCED_FRAMING = 1; - + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; 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) { + dp_tr_pattern = get_supported_tp(link); + + if (dp_tr_pattern != DP_TRAINING_PATTERN_SEQUENCE_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)); + &downspread.raw, sizeof(downspread)); core_link_write_dpcd(link, DP_LANE_COUNT_SET, - &lane_count_set.raw, 1); + &lane_count_set.raw, 1); if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 && lt_settings->link_settings.use_link_rate_set == true) { @@ -162,46 +168,47 @@ static void dpcd_set_link_settings( } if (rate) { - DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", __func__, DP_LINK_BW_SET, lt_settings->link_settings.link_rate, DP_LANE_COUNT_SET, lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); } else { - DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x\n %x spread = %x\n", + DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n", __func__, DP_LINK_RATE_SET, lt_settings->link_settings.link_rate_set, DP_LANE_COUNT_SET, lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); } - } static enum dpcd_training_patterns - hw_training_pattern_to_dpcd_training_pattern( + dc_dp_training_pattern_to_dpcd_training_pattern( struct dc_link *link, - enum hw_dp_training_pattern pattern) + enum dc_dp_training_pattern pattern) { enum dpcd_training_patterns dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; switch (pattern) { - case HW_DP_TRAINING_PATTERN_1: + case DP_TRAINING_PATTERN_SEQUENCE_1: dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; break; - case HW_DP_TRAINING_PATTERN_2: + case DP_TRAINING_PATTERN_SEQUENCE_2: dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; break; - case HW_DP_TRAINING_PATTERN_3: + case DP_TRAINING_PATTERN_SEQUENCE_3: dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; break; - case HW_DP_TRAINING_PATTERN_4: + case DP_TRAINING_PATTERN_SEQUENCE_4: dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; break; default: @@ -212,13 +219,12 @@ static enum dpcd_training_patterns } return dpcd_tr_pattern; - } static void dpcd_set_lt_pattern_and_lane_settings( struct dc_link *link, const struct link_training_settings *lt_settings, - enum hw_dp_training_pattern pattern) + enum dc_dp_training_pattern pattern) { union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } }; const uint32_t dpcd_base_lt_offset = @@ -233,7 +239,7 @@ static void dpcd_set_lt_pattern_and_lane_settings( * DpcdAddress_TrainingPatternSet *****************************************************************/ dpcd_pattern.v1_4.TRAINING_PATTERN_SET = - hw_training_pattern_to_dpcd_training_pattern(link, pattern); + dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern); dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset] = dpcd_pattern.raw; @@ -346,12 +352,20 @@ static void update_drive_settings( { uint32_t lane; for (lane = 0; lane < src.link_settings.lane_count; lane++) { - dest->lane_settings[lane].VOLTAGE_SWING = - src.lane_settings[lane].VOLTAGE_SWING; - dest->lane_settings[lane].PRE_EMPHASIS = - src.lane_settings[lane].PRE_EMPHASIS; - dest->lane_settings[lane].POST_CURSOR2 = - src.lane_settings[lane].POST_CURSOR2; + if (dest->voltage_swing == NULL) + dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING; + else + dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing; + + if (dest->pre_emphasis == NULL) + dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS; + else + dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis; + + if (dest->post_cursor2 == NULL) + dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2; + else + dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2; } } @@ -754,15 +768,15 @@ static enum link_training_result perform_channel_equalization_sequence( struct link_training_settings *lt_settings) { struct link_training_settings req_settings; - enum hw_dp_training_pattern hw_tr_pattern; + enum dc_dp_training_pattern tr_pattern; uint32_t retries_ch_eq; enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; union lane_align_status_updated dpcd_lane_status_updated = { {0} }; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = { { {0} } }; - hw_tr_pattern = get_supported_tp(link); + tr_pattern = lt_settings->pattern_for_eq; - dp_set_hw_training_pattern(link, hw_tr_pattern); + dp_set_hw_training_pattern(link, tr_pattern); for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; retries_ch_eq++) { @@ -776,12 +790,12 @@ static enum link_training_result perform_channel_equalization_sequence( dpcd_set_lt_pattern_and_lane_settings( link, lt_settings, - hw_tr_pattern); + tr_pattern); else dpcd_set_lane_settings(link, lt_settings); /* 3. wait for receiver to lock-on*/ - wait_for_training_aux_rd_interval(link, 400); + wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time); /* 4. Read lane status and requested * drive settings as set by the sink*/ @@ -817,27 +831,16 @@ static enum link_training_result perform_clock_recovery_sequence( { uint32_t retries_cr; uint32_t retry_count; - uint32_t lane; struct link_training_settings req_settings; - enum dc_lane_count lane_count = - lt_settings->link_settings.lane_count; - enum hw_dp_training_pattern hw_tr_pattern = HW_DP_TRAINING_PATTERN_1; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1; union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; union lane_align_status_updated dpcd_lane_status_updated; retries_cr = 0; retry_count = 0; - /* initial drive setting (VS/PE/PC2)*/ - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { - lt_settings->lane_settings[lane].VOLTAGE_SWING = - VOLTAGE_SWING_LEVEL0; - lt_settings->lane_settings[lane].PRE_EMPHASIS = - PRE_EMPHASIS_DISABLED; - lt_settings->lane_settings[lane].POST_CURSOR2 = - POST_CURSOR2_DISABLED; - } - dp_set_hw_training_pattern(link, hw_tr_pattern); + dp_set_hw_training_pattern(link, tr_pattern); /* najeeb - The synaptics MST hub can put the LT in * infinite loop by switching the VS @@ -845,7 +848,7 @@ static enum link_training_result perform_clock_recovery_sequence( /* between level 0 and level 1 continuously, here * we try for CR lock for LinkTrainingMaxCRRetry count*/ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && - (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); memset(&dpcd_lane_status_updated, '\0', @@ -863,7 +866,7 @@ static enum link_training_result perform_clock_recovery_sequence( dpcd_set_lt_pattern_and_lane_settings( link, lt_settings, - hw_tr_pattern); + tr_pattern); else dpcd_set_lane_settings( link, @@ -872,7 +875,7 @@ static enum link_training_result perform_clock_recovery_sequence( /* 3. wait receiver to lock-on*/ wait_for_training_aux_rd_interval( link, - 100); + lt_settings->cr_pattern_time); /* 4. Read lane status and requested drive * settings as set by the sink @@ -939,7 +942,7 @@ static inline enum link_training_result perform_link_training_int( * TPS4 must be used instead of POST_LT_ADJ_REQ. */ if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 || - get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4) + get_supported_tp(link) == DP_TRAINING_PATTERN_SEQUENCE_4) return status; if (status == LINK_TRAINING_SUCCESS && @@ -947,7 +950,7 @@ static inline enum link_training_result perform_link_training_int( status = LINK_TRAINING_LQA_FAIL; lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count; - lane_count_set.bits.ENHANCED_FRAMING = 1; + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; core_link_write_dpcd( @@ -959,24 +962,29 @@ static inline enum link_training_result perform_link_training_int( return status; } -enum link_training_result dc_link_dp_perform_link_training( - struct dc_link *link, +static void initialize_training_settings( + struct dc_link *link, const struct dc_link_settings *link_setting, - bool skip_video_pattern) + const struct dc_link_training_overrides *overrides, + struct link_training_settings *lt_settings) { - enum link_training_result status = LINK_TRAINING_SUCCESS; + uint32_t lane; - char *link_rate = "Unknown"; - char *lt_result = "Unknown"; + memset(lt_settings, '\0', sizeof(struct link_training_settings)); - struct link_training_settings lt_settings; + /* Initialize link settings */ + lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set; + lt_settings->link_settings.link_rate_set = link_setting->link_rate_set; - memset(<_settings, '\0', sizeof(lt_settings)); + if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN) + lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate; + else + lt_settings->link_settings.link_rate = link_setting->link_rate; - lt_settings.link_settings.link_rate = link_setting->link_rate; - lt_settings.link_settings.lane_count = link_setting->lane_count; - lt_settings.link_settings.use_link_rate_set = link_setting->use_link_rate_set; - lt_settings.link_settings.link_rate_set = link_setting->link_rate_set; + if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN) + lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count; + else + lt_settings->link_settings.lane_count = link_setting->lane_count; /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/ @@ -987,31 +995,75 @@ enum link_training_result dc_link_dp_perform_link_training( * LINK_SPREAD_05_DOWNSPREAD_30KHZ : * LINK_SPREAD_DISABLED; */ + /* Initialize link spread */ if (link->dp_ss_off) - lt_settings.link_settings.link_spread = LINK_SPREAD_DISABLED; + lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED; + else if (overrides->downspread != NULL) + lt_settings->link_settings.link_spread + = *overrides->downspread + ? LINK_SPREAD_05_DOWNSPREAD_30KHZ + : LINK_SPREAD_DISABLED; else - lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ; + lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ; - /* 1. set link rate, lane count and spread*/ - dpcd_set_link_settings(link, <_settings); + /* Initialize lane settings overrides */ + if (overrides->voltage_swing != NULL) + lt_settings->voltage_swing = overrides->voltage_swing; - /* 2. perform link training (set link training done - * to false is done as well)*/ - status = perform_clock_recovery_sequence(link, <_settings); - if (status == LINK_TRAINING_SUCCESS) { - status = perform_channel_equalization_sequence(link, - <_settings); - } + if (overrides->pre_emphasis != NULL) + lt_settings->pre_emphasis = overrides->pre_emphasis; - if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { - status = perform_link_training_int(link, - <_settings, - status); + if (overrides->post_cursor2 != NULL) + lt_settings->post_cursor2 = overrides->post_cursor2; + + /* Initialize lane settings (VS/PE/PC2) */ + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) { + lt_settings->lane_settings[lane].VOLTAGE_SWING = + lt_settings->voltage_swing != NULL ? + *lt_settings->voltage_swing : + VOLTAGE_SWING_LEVEL0; + lt_settings->lane_settings[lane].PRE_EMPHASIS = + lt_settings->pre_emphasis != NULL ? + *lt_settings->pre_emphasis + : PRE_EMPHASIS_DISABLED; + lt_settings->lane_settings[lane].POST_CURSOR2 = + lt_settings->post_cursor2 != NULL ? + *lt_settings->post_cursor2 + : POST_CURSOR2_DISABLED; } - /* 6. print status message*/ - switch (lt_settings.link_settings.link_rate) { + /* Initialize training timings */ + if (overrides->cr_pattern_time != NULL) + lt_settings->cr_pattern_time = *overrides->cr_pattern_time; + else + lt_settings->cr_pattern_time = get_training_aux_rd_interval(link, 100); + + if (overrides->eq_pattern_time != NULL) + lt_settings->eq_pattern_time = *overrides->eq_pattern_time; + else + lt_settings->eq_pattern_time = get_training_aux_rd_interval(link, 400); + + if (overrides->pattern_for_eq != NULL) + lt_settings->pattern_for_eq = *overrides->pattern_for_eq; + else + lt_settings->pattern_for_eq = get_supported_tp(link); + + if (overrides->enhanced_framing != NULL) + lt_settings->enhanced_framing = *overrides->enhanced_framing; + else + lt_settings->enhanced_framing = 1; +} + +static void print_status_message( + struct dc_link *link, + const struct link_training_settings *lt_settings, + enum link_training_result status) +{ + char *link_rate = "Unknown"; + char *lt_result = "Unknown"; + char *lt_spread = "Disabled"; + switch (lt_settings->link_settings.link_rate) { case LINK_RATE_LOW: link_rate = "RBR"; break; @@ -1057,13 +1109,122 @@ enum link_training_result dc_link_dp_perform_link_training( break; } + switch (lt_settings->link_settings.link_spread) { + case LINK_SPREAD_DISABLED: + lt_spread = "Disabled"; + break; + case LINK_SPREAD_05_DOWNSPREAD_30KHZ: + lt_spread = "0.5% 30KHz"; + break; + case LINK_SPREAD_05_DOWNSPREAD_33KHZ: + lt_spread = "0.5% 33KHz"; + break; + default: + break; + } + /* Connectivity log: link training */ - CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d", - link_rate, - lt_settings.link_settings.lane_count, - lt_result, - lt_settings.lane_settings[0].VOLTAGE_SWING, - lt_settings.lane_settings[0].PRE_EMPHASIS); + CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s", + link_rate, + lt_settings->link_settings.lane_count, + lt_result, + lt_settings->lane_settings[0].VOLTAGE_SWING, + lt_settings->lane_settings[0].PRE_EMPHASIS, + lt_spread); +} + +bool dc_link_dp_perform_link_training_skip_aux( + struct dc_link *link, + const struct dc_link_settings *link_setting) +{ + struct link_training_settings lt_settings; + enum dc_dp_training_pattern pattern_for_cr = DP_TRAINING_PATTERN_SEQUENCE_1; + + initialize_training_settings( + link, + link_setting, + &link->preferred_training_settings, + <_settings); + + /* 1. Perform_clock_recovery_sequence. */ + + /* transmit training pattern for clock recovery */ + dp_set_hw_training_pattern(link, pattern_for_cr); + + /* call HWSS to set lane settings*/ + dp_set_hw_lane_settings(link, <_settings); + + /* wait receiver to lock-on*/ + wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time); + + /* 2. Perform_channel_equalization_sequence. */ + + /* transmit training pattern for channel equalization. */ + dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq); + + /* call HWSS to set lane settings*/ + dp_set_hw_lane_settings(link, <_settings); + + /* wait receiver to lock-on. */ + wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time); + + /* 3. Perform_link_training_int. */ + + /* Mainlink output idle pattern. */ + dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0); + + print_status_message(link, <_settings, LINK_TRAINING_SUCCESS); + + return true; +} + +enum link_training_result dc_link_dp_perform_link_training( + struct dc_link *link, + const struct dc_link_settings *link_setting, + bool skip_video_pattern) +{ + enum link_training_result status = LINK_TRAINING_SUCCESS; + struct link_training_settings lt_settings; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool fec_enable; +#endif + + initialize_training_settings( + link, + link_setting, + &link->preferred_training_settings, + <_settings); + + /* 1. set link rate, lane count and spread. */ + dpcd_set_link_settings(link, <_settings); + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (link->preferred_training_settings.fec_enable != NULL) + fec_enable = *link->preferred_training_settings.fec_enable; + else + fec_enable = true; + + dp_set_fec_ready(link, fec_enable); +#endif + + + /* 2. perform link training (set link training done + * to false is done as well) + */ + status = perform_clock_recovery_sequence(link, <_settings); + if (status == LINK_TRAINING_SUCCESS) { + status = perform_channel_equalization_sequence(link, + <_settings); + } + + if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) { + status = perform_link_training_int(link, + <_settings, + status); + } + + /* 6. print status message*/ + print_status_message(link, <_settings, status); if (status != LINK_TRAINING_SUCCESS) link->ctx->dc->debug_data.ltFailCount++; @@ -1071,7 +1232,6 @@ enum link_training_result dc_link_dp_perform_link_training( return status; } - bool perform_link_training_with_retries( struct dc_link *link, const struct dc_link_settings *link_setting, @@ -1096,6 +1256,146 @@ bool perform_link_training_with_retries( return false; } +static enum clock_source_id get_clock_source_id(struct dc_link *link) +{ + enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED; + struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source; + + if (dp_cs != NULL) { + dp_cs_id = dp_cs->id; + } else { + /* + * dp clock source is not initialized for some reason. + * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used + */ + ASSERT(dp_cs); + } + + return dp_cs_id; +} + +static void set_dp_mst_mode(struct dc_link *link, bool mst_enable) +{ + if (mst_enable == false && + link->type == dc_connection_mst_branch) { + /* Disable MST on link. Use only local sink. */ + dp_disable_link_phy_mst(link, link->connector_signal); + + link->type = dc_connection_single; + link->local_sink = link->remote_sinks[0]; + link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; + } else if (mst_enable == true && + link->type == dc_connection_single && + link->remote_sinks[0] != NULL) { + /* Re-enable MST on link. */ + dp_disable_link_phy(link, link->connector_signal); + dp_enable_mst_on_sink(link, true); + + link->type = dc_connection_mst_branch; + link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST; + } +} + +bool dc_link_dp_sync_lt_begin(struct dc_link *link) +{ + /* Begin Sync LT. During this time, + * DPCD:600h must not be powered down. + */ + link->sync_lt_in_progress = true; + + /*Clear any existing preferred settings.*/ + memset(&link->preferred_training_settings, 0, + sizeof(struct dc_link_training_overrides)); + memset(&link->preferred_link_setting, 0, + sizeof(struct dc_link_settings)); + + return true; +} + +enum link_training_result dc_link_dp_sync_lt_attempt( + struct dc_link *link, + struct dc_link_settings *link_settings, + struct dc_link_training_overrides *lt_overrides) +{ + struct link_training_settings lt_settings; + enum link_training_result lt_status = LINK_TRAINING_SUCCESS; + enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT; + enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool fec_enable = false; +#endif + + initialize_training_settings( + link, + link_settings, + lt_overrides, + <_settings); + + /* Setup MST Mode */ + if (lt_overrides->mst_enable) + set_dp_mst_mode(link, *lt_overrides->mst_enable); + + /* Disable link */ + dp_disable_link_phy(link, link->connector_signal); + + /* Enable link */ + dp_cs_id = get_clock_source_id(link); + dp_enable_link_phy(link, link->connector_signal, + dp_cs_id, link_settings); + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + /* Set FEC enable */ + fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable; + dp_set_fec_ready(link, fec_enable); +#endif + + if (lt_overrides->alternate_scrambler_reset) { + if (*lt_overrides->alternate_scrambler_reset) + panel_mode = DP_PANEL_MODE_EDP; + else + panel_mode = DP_PANEL_MODE_DEFAULT; + } else + panel_mode = dp_get_panel_mode(link); + + dp_set_panel_mode(link, panel_mode); + + /* Attempt to train with given link training settings */ + + /* Set link rate, lane count and spread. */ + dpcd_set_link_settings(link, <_settings); + + /* 2. perform link training (set link training done + * to false is done as well) + */ + lt_status = perform_clock_recovery_sequence(link, <_settings); + if (lt_status == LINK_TRAINING_SUCCESS) { + lt_status = perform_channel_equalization_sequence(link, + <_settings); + } + + /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/ + /* 4. print status message*/ + print_status_message(link, <_settings, lt_status); + + return lt_status; +} + +bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down) +{ + /* If input parameter is set, shut down phy. + * Still shouldn't turn off dp_receiver (DPCD:600h) + */ + if (link_down == true) { + dp_disable_link_phy(link, link->connector_signal); +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + dp_set_fec_ready(link, false); +#endif + } + + link->sync_lt_in_progress = false; + return true; +} + static struct dc_link_settings get_max_link_cap(struct dc_link *link) { /* Set Default link settings */ @@ -1250,7 +1550,6 @@ bool dp_verify_link_cap( bool success; bool skip_link_training; bool skip_video_pattern; - struct clock_source *dp_cs; enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL; enum link_training_result status; union hpd_irq_data irq_data; @@ -1274,17 +1573,7 @@ bool dp_verify_link_cap( /* disable PHY done possible by BIOS, will be done by driver itself */ dp_disable_link_phy(link, link->connector_signal); - dp_cs = link->dc->res_pool->dp_clock_source; - - if (dp_cs) - dp_cs_id = dp_cs->id; - else { - /* - * dp clock source is not initialized for some reason. - * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used - */ - ASSERT(dp_cs); - } + dp_cs_id = get_clock_source_id(link); /* link training starts with the maximum common settings * supported by both sink and ASIC. @@ -1354,6 +1643,33 @@ bool dp_verify_link_cap( return success; } +bool dp_verify_link_cap_with_retries( + struct dc_link *link, + struct dc_link_settings *known_limit_link_setting, + int attempts) +{ + uint8_t i = 0; + bool success = false; + + for (i = 0; i < attempts; i++) { + int fail_count = 0; + enum dc_connection_type type; + + memset(&link->verified_link_cap, 0, + sizeof(struct dc_link_settings)); + if (!dc_link_detect_sink(link, &type)) { + break; + } else if (dp_verify_link_cap(link, + &link->reported_link_cap, + &fail_count) && fail_count == 0) { + success = true; + break; + } + msleep(10); + } + return success; +} + static struct dc_link_settings get_common_supported_link_settings( struct dc_link_settings link_setting_a, struct dc_link_settings link_setting_b) @@ -2156,6 +2472,11 @@ bool is_mst_supported(struct dc_link *link) union dpcd_rev rev; union mstm_cap cap; + if (link->preferred_training_settings.mst_enable && + *link->preferred_training_settings.mst_enable == false) { + return false; + } + rev.raw = 0; cap.raw = 0; @@ -2363,13 +2684,13 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) { switch (link->dpcd_caps.branch_dev_id) { - /* Some active dongles (DP-VGA, DP-DLDVI converters) power down + /* 0010FA active dongles (DP-VGA, DP-DLDVI converters) power down * all internal circuits including AUX communication preventing * reading DPCD table and EDID (spec violation). * Encoder will skip DP RX power down on disable_output to * keep receiver powered all the time.*/ - case DP_BRANCH_DEVICE_ID_1: - case DP_BRANCH_DEVICE_ID_4: + case DP_BRANCH_DEVICE_ID_0010FA: + case DP_BRANCH_DEVICE_ID_0080E1: link->wa_flags.dp_keep_receiver_powered = true; break; @@ -2774,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link, 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); + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; - if (bot_odm_pipe) { - struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp; + width /= opp_cnt; - bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, ¶ms); - width /= 2; - bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp, + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; + + odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); + odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp, controller_test_pattern, color_depth, NULL, @@ -2810,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link, 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); + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; - if (bot_odm_pipe) { - struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp; + width /= opp_cnt; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct output_pixel_processor *odm_opp = 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, + odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); + odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, color_depth, NULL, @@ -2858,7 +3188,7 @@ bool dc_link_dp_set_test_pattern( memset(&training_pattern, 0, sizeof(training_pattern)); for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream->link == link) { + if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) { pipe_ctx = &pipes[i]; break; } @@ -3007,6 +3337,105 @@ void dp_enable_mst_on_sink(struct dc_link *link, bool enable) core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1); } +void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) +{ + union dpcd_edp_config edp_config_set; + bool panel_mode_edp = false; + + memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config)); + + if (panel_mode != DP_PANEL_MODE_DEFAULT) { + + switch (panel_mode) { + case DP_PANEL_MODE_EDP: + case DP_PANEL_MODE_SPECIAL: + panel_mode_edp = true; + break; + + default: + break; + } + + /*set edp panel mode in receiver*/ + core_link_read_dpcd( + link, + DP_EDP_CONFIGURATION_SET, + &edp_config_set.raw, + sizeof(edp_config_set.raw)); + + if (edp_config_set.bits.PANEL_MODE_EDP + != panel_mode_edp) { + enum ddc_result result = DDC_RESULT_UNKNOWN; + + edp_config_set.bits.PANEL_MODE_EDP = + panel_mode_edp; + result = core_link_write_dpcd( + link, + DP_EDP_CONFIGURATION_SET, + &edp_config_set.raw, + sizeof(edp_config_set.raw)); + + ASSERT(result == DDC_RESULT_SUCESSFULL); + } + } + DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " + "eDP panel mode enabled: %d \n", + link->link_index, + link->dpcd_caps.panel_mode_edp, + panel_mode_edp); +} + +enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) +{ + /* We need to explicitly check that connector + * is not DP. Some Travis_VGA get reported + * by video bios as DP. + */ + if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) { + + switch (link->dpcd_caps.branch_dev_id) { + case DP_BRANCH_DEVICE_ID_0022B9: + /* alternate scrambler reset is required for Travis + * for the case when external chip does not + * provide sink device id, alternate scrambler + * scheme will be overriden later by querying + * Encoder features + */ + if (strncmp( + link->dpcd_caps.branch_dev_name, + DP_VGA_LVDS_CONVERTER_ID_2, + sizeof( + link->dpcd_caps. + branch_dev_name)) == 0) { + return DP_PANEL_MODE_SPECIAL; + } + break; + case DP_BRANCH_DEVICE_ID_00001A: + /* alternate scrambler reset is required for Travis + * for the case when external chip does not provide + * sink device id, alternate scrambler scheme will + * be overriden later by querying Encoder feature + */ + if (strncmp(link->dpcd_caps.branch_dev_name, + DP_VGA_LVDS_CONVERTER_ID_3, + sizeof( + link->dpcd_caps. + branch_dev_name)) == 0) { + return DP_PANEL_MODE_SPECIAL; + } + break; + default: + break; + } + } + + if (link->dpcd_caps.panel_mode_edp) { + return DP_PANEL_MODE_EDP; + } + + return DP_PANEL_MODE_DEFAULT; +} + #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT void dp_set_fec_ready(struct dc_link *link, bool ready) { @@ -3024,7 +3453,7 @@ void dp_set_fec_ready(struct dc_link *link, bool ready) 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) { + if (ready) { fec_config = 1; if (core_link_write_dpcd(link, DP_FEC_CONFIGURATION, @@ -3033,9 +3462,11 @@ void dp_set_fec_ready(struct dc_link *link, bool ready) link_enc->funcs->fec_set_ready(link_enc, true); link->fec_state = dc_link_fec_ready; } else { + link->link_enc->funcs->fec_set_ready(link->link_enc, false); + link->fec_state = dc_link_fec_not_ready; dm_error("dpcd write failed to set fec_ready"); } - } else if (link->fec_state == dc_link_fec_ready && !ready) { + } else if (link->fec_state == dc_link_fec_ready) { fec_config = 0; core_link_write_dpcd(link, DP_FEC_CONFIGURATION, 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 2d019e1f6135..79438c4f1e20 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 @@ -25,10 +25,11 @@ enum dc_status core_link_read_dpcd( uint8_t *data, uint32_t size) { - if (!dm_helpers_dp_read_dpcd(link->ctx, - link, - address, data, size)) - return DC_ERROR_UNEXPECTED; + if (!link->aux_access_disabled && + !dm_helpers_dp_read_dpcd(link->ctx, + link, address, data, size)) { + return DC_ERROR_UNEXPECTED; + } return DC_OK; } @@ -39,10 +40,11 @@ enum dc_status core_link_write_dpcd( const uint8_t *data, uint32_t size) { - if (!dm_helpers_dp_write_dpcd(link->ctx, - link, - address, data, size)) - return DC_ERROR_UNEXPECTED; + if (!link->aux_access_disabled && + !dm_helpers_dp_write_dpcd(link->ctx, + link, address, data, size)) { + return DC_ERROR_UNEXPECTED; + } return DC_OK; } @@ -53,6 +55,9 @@ void dp_receiver_power_ctrl(struct dc_link *link, bool on) state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3; + if (link->sync_lt_in_progress) + return; + core_link_write_dpcd(link, DP_SET_POWER, &state, sizeof(state)); } @@ -160,6 +165,10 @@ bool edp_receiver_ready_T7(struct dc_link *link) break; udelay(25); //MAx T7 is 50ms } while (++tries < 300); + + if (link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0) + udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000); + return result; } @@ -203,21 +212,21 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal) bool dp_set_hw_training_pattern( struct dc_link *link, - enum hw_dp_training_pattern pattern) + enum dc_dp_training_pattern pattern) { enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED; switch (pattern) { - case HW_DP_TRAINING_PATTERN_1: + case DP_TRAINING_PATTERN_SEQUENCE_1: test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1; break; - case HW_DP_TRAINING_PATTERN_2: + case DP_TRAINING_PATTERN_SEQUENCE_2: test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2; break; - case HW_DP_TRAINING_PATTERN_3: + case DP_TRAINING_PATTERN_SEQUENCE_3: test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3; break; - case HW_DP_TRAINING_PATTERN_4: + case DP_TRAINING_PATTERN_SEQUENCE_4: test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; break; default: @@ -239,46 +248,6 @@ void dp_set_hw_lane_settings( encoder->funcs->dp_set_lane_settings(encoder, link_settings); } -enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) -{ - /* We need to explicitly check that connector - * is not DP. Some Travis_VGA get reported - * by video bios as DP. - */ - if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) { - - switch (link->dpcd_caps.branch_dev_id) { - case DP_BRANCH_DEVICE_ID_2: - if (strncmp( - link->dpcd_caps.branch_dev_name, - DP_VGA_LVDS_CONVERTER_ID_2, - sizeof( - link->dpcd_caps. - branch_dev_name)) == 0) { - return DP_PANEL_MODE_SPECIAL; - } - break; - case DP_BRANCH_DEVICE_ID_3: - if (strncmp(link->dpcd_caps.branch_dev_name, - DP_VGA_LVDS_CONVERTER_ID_3, - sizeof( - link->dpcd_caps. - branch_dev_name)) == 0) { - return DP_PANEL_MODE_SPECIAL; - } - break; - default: - break; - } - } - - if (link->dpcd_caps.panel_mode_edp) { - return DP_PANEL_MODE_EDP; - } - - return DP_PANEL_MODE_DEFAULT; -} - void dp_set_hw_test_pattern( struct dc_link *link, enum dp_test_pattern test_pattern, @@ -306,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && - !pipes[i].top_pipe && + !pipes[i].top_pipe && !pipes[i].prev_odm_pipe && pipes[i].stream->link != NULL && pipes[i].stream_res.stream_enc != NULL) { udelay(100); @@ -320,7 +289,9 @@ void dp_retrain_link_dp_test(struct dc_link *link, dp_receiver_power_ctrl(link, false); - link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE); + link->dc->hwss.disable_stream(&pipes[i]); + if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only) + (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio); link->link_enc->funcs->disable_output( link->link_enc, @@ -373,10 +344,22 @@ void dp_retrain_link_dp_test(struct dc_link *link, 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); + uint32_t precision = 1 << 28; + uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision; + uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision; + uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod; + + /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC + * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is + * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal + */ + ll_bytes_per_pix_fraq *= 10000000; + ll_bytes_per_pix_fraq /= precision; + + DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)", + config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq); + DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444); + DC_LOG_DSC("\tslice_width %d", config->slice_width); } static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) @@ -392,55 +375,62 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool 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 +/* The stream with these settings can be sent (unblanked) only 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) +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); + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; 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_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt; 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; + ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0); + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; - 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_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc; + + odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg); + odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst); + } + dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; + dsc_cfg.pic_width *= opp_cnt; 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) + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); + dsc_optc_config_log(dsc, &dsc_optc_cfg); 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]); + dsc_optc_cfg.slice_width); + + /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */ + } /* Enable DSC in OPTC */ + DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst); + dsc_optc_config_log(dsc, &dsc_optc_cfg); pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg, optc_dsc_mode, dsc_optc_cfg.bytes_per_pixel, @@ -452,15 +442,18 @@ static void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) OPTC_DSC_DISABLED, 0, 0); /* disable DSC in stream encoder */ - if (!IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + if (dc_is_dp_signal(stream->signal) && !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); + OPTC_DSC_DISABLED, 0, 0); + + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( + pipe_ctx->stream_res.stream_enc, false, NULL); } /* disable DSC block */ pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); - if (odm_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); } } @@ -489,6 +482,47 @@ out: return result; } +bool dp_set_dsc_pps_sdp(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; + + if (!pipe_ctx->stream->timing.flags.DSC || !dsc) + return false; + + if (enable) { + struct dsc_config dsc_cfg; + 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; + + DC_LOG_DSC(" "); + dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]); + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id); + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( + pipe_ctx->stream_res.stream_enc, + true, + &dsc_packed_pps[0]); + } + } else { + /* disable DSC PPS in stream encoder */ + if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(core_dc->ctx->dce_environment)) { + pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet( + pipe_ctx->stream_res.stream_enc, false, NULL); + } + } + + return true; +} + + bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx) { struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc; @@ -499,8 +533,8 @@ bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx) return false; dp_set_dsc_on_stream(pipe_ctx, true); + dp_set_dsc_pps_sdp(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 2ceaab4fb5de..8f70295179ff 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -52,6 +52,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/dcn20_resource.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#include "dcn21/dcn21_resource.h" +#endif #include "dce120/dce120_resource.h" #define DC_LOGGER_INIT(logger) @@ -101,6 +104,10 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) dc_version = DCN_VERSION_1_0; if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev)) dc_version = DCN_VERSION_1_01; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + if (ASICREV_IS_RENOIR(asic_id.hw_internal_rev)) + dc_version = DCN_VERSION_2_1; +#endif break; #endif @@ -168,17 +175,20 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc, res_pool = dcn20_create_resource_pool(init_data, dc); break; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case DCN_VERSION_2_1: + res_pool = dcn21_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) { + if (res_pool != NULL) { + if (dc->ctx->dc_bios->fw_info_valid) { res_pool->ref_clocks.xtalin_clock_inKhz = - fw_info.pll_info.crystal_frequency; + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; /* initialize with firmware data first, no all * ASIC have DCCG SW component. FPGA or * simulation need initialization of @@ -265,12 +275,10 @@ bool resource_construct( DC_ERR("DC: failed to create audio!\n"); return false; } - if (!aud->funcs->endpoint_valid(aud)) { aud->funcs->destroy(&aud); break; } - pool->audios[i] = aud; pool->audio_count++; } @@ -940,7 +948,14 @@ static void calculate_inits_and_adj_vp(struct pipe_ctx *pipe_ctx) data->inits.v_c_bot = dc_fixpt_add(data->inits.v_c, data->ratios.vert_c); } +static bool are_rect_integer_multiples(struct rect src, struct rect dest) +{ + if (dest.width >= src.width && dest.width % src.width == 0 && + dest.height >= src.height && dest.height % src.height == 0) + return true; + return false; +} bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) { const struct dc_plane_state *plane_state = pipe_ctx->plane_state; @@ -983,6 +998,15 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx) if (pipe_ctx->plane_res.dpp != NULL) res = pipe_ctx->plane_res.dpp->funcs->dpp_get_optimal_number_of_taps( pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality); + + if (res && + plane_state->scaling_quality.integer_scaling && + are_rect_integer_multiples(pipe_ctx->plane_res.scl_data.viewport, + pipe_ctx->plane_res.scl_data.recout)) { + pipe_ctx->plane_res.scl_data.taps.v_taps = 1; + pipe_ctx->plane_res.scl_data.taps.h_taps = 1; + } + if (!res) { /* Try 24 bpp linebuffer */ pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_24BPP; @@ -1103,25 +1127,21 @@ struct pipe_ctx *resource_get_head_pipe_for_stream( struct dc_stream_state *stream) { int i; + for (i = 0; i < MAX_PIPES; i++) { - if (res_ctx->pipe_ctx[i].stream == stream && - !res_ctx->pipe_ctx[i].top_pipe) { + if (res_ctx->pipe_ctx[i].stream == stream + && !res_ctx->pipe_ctx[i].top_pipe + && !res_ctx->pipe_ctx[i].prev_odm_pipe) return &res_ctx->pipe_ctx[i]; - break; - } } return NULL; } -static struct pipe_ctx *resource_get_tail_pipe_for_stream( +static struct pipe_ctx *resource_get_tail_pipe( struct resource_context *res_ctx, - struct dc_stream_state *stream) + struct pipe_ctx *head_pipe) { - struct pipe_ctx *head_pipe, *tail_pipe; - head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); - - if (!head_pipe) - return NULL; + struct pipe_ctx *tail_pipe; tail_pipe = head_pipe->bottom_pipe; @@ -1137,31 +1157,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream( * A free_pipe for a stream is defined here as a pipe * that has no surface attached yet */ -static struct pipe_ctx *acquire_free_pipe_for_stream( +static struct pipe_ctx *acquire_free_pipe_for_head( struct dc_state *context, const struct resource_pool *pool, - struct dc_stream_state *stream) + struct pipe_ctx *head_pipe) { int i; struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *head_pipe = NULL; - - /* Find head pipe, which has the back end set up*/ - - head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); - - if (!head_pipe) { - ASSERT(0); - return NULL; - } - if (!head_pipe->plane_state) return head_pipe; /* Re-use pipe already acquired for this stream if available*/ for (i = pool->pipe_count - 1; i >= 0; i--) { - if (res_ctx->pipe_ctx[i].stream == stream && + if (res_ctx->pipe_ctx[i].stream == head_pipe->stream && !res_ctx->pipe_ctx[i].plane_state) { return &res_ctx->pipe_ctx[i]; } @@ -1175,8 +1184,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( if (!pool->funcs->acquire_idle_pipe_for_layer) return NULL; - return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream); - + return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream); } #if defined(CONFIG_DRM_AMD_DC_DCN1_0) @@ -1190,7 +1198,7 @@ static int acquire_first_split_pipe( for (i = 0; i < pool->pipe_count; i++) { struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i]; - if (split_pipe->top_pipe && !dc_res_is_odm_head_pipe(split_pipe) && + if (split_pipe->top_pipe && split_pipe->top_pipe->plane_state == split_pipe->plane_state) { split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; if (split_pipe->bottom_pipe) @@ -1251,39 +1259,41 @@ bool dc_add_plane_to_context( return false; } - tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); - ASSERT(tail_pipe); + /* retain new surface, but only once per stream */ + dc_plane_state_retain(plane_state); - free_pipe = acquire_free_pipe_for_stream(context, pool, stream); + while (head_pipe) { + tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe); + ASSERT(tail_pipe); -#if defined(CONFIG_DRM_AMD_DC_DCN1_0) - if (!free_pipe) { - int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); - if (pipe_idx >= 0) - free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; - } -#endif - if (!free_pipe) - return false; + free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe); - /* retain new surfaces */ - dc_plane_state_retain(plane_state); - free_pipe->plane_state = plane_state; - - if (head_pipe != free_pipe) { - free_pipe->stream_res.tg = tail_pipe->stream_res.tg; - free_pipe->stream_res.abm = tail_pipe->stream_res.abm; - free_pipe->stream_res.opp = tail_pipe->stream_res.opp; - free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; - free_pipe->stream_res.audio = tail_pipe->stream_res.audio; - free_pipe->clock_source = tail_pipe->clock_source; - free_pipe->top_pipe = tail_pipe; - tail_pipe->bottom_pipe = free_pipe; - } else if (free_pipe->bottom_pipe && free_pipe->bottom_pipe->plane_state == NULL) { - ASSERT(free_pipe->bottom_pipe->stream_res.opp != free_pipe->stream_res.opp); - free_pipe->bottom_pipe->plane_state = plane_state; - } + #if defined(CONFIG_DRM_AMD_DC_DCN1_0) + if (!free_pipe) { + int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); + if (pipe_idx >= 0) + free_pipe = &context->res_ctx.pipe_ctx[pipe_idx]; + } + #endif + if (!free_pipe) { + dc_plane_state_release(plane_state); + return false; + } + free_pipe->plane_state = plane_state; + + if (head_pipe != free_pipe) { + free_pipe->stream_res.tg = tail_pipe->stream_res.tg; + free_pipe->stream_res.abm = tail_pipe->stream_res.abm; + free_pipe->stream_res.opp = tail_pipe->stream_res.opp; + free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; + free_pipe->stream_res.audio = tail_pipe->stream_res.audio; + free_pipe->clock_source = tail_pipe->clock_source; + free_pipe->top_pipe = tail_pipe; + tail_pipe->bottom_pipe = free_pipe; + } + head_pipe = head_pipe->next_odm_pipe; + } /* assign new surfaces*/ stream_status->plane_states[stream_status->plane_count] = plane_state; @@ -1292,35 +1302,6 @@ bool dc_add_plane_to_context( return true; } -struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe; - - /* ODM should only be updated once per otg */ - if (pipe_ctx->top_pipe) - return NULL; - - while (bottom_pipe) { - if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp) - break; - bottom_pipe = bottom_pipe->bottom_pipe; - } - - return bottom_pipe; -} - -bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx) -{ - struct pipe_ctx *top_pipe = pipe_ctx->top_pipe; - - if (!top_pipe) - return false; - if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp) - return false; - - return true; -} - bool dc_remove_plane_from_context( const struct dc *dc, struct dc_stream_state *stream, @@ -1347,12 +1328,6 @@ bool dc_remove_plane_from_context( struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; if (pipe_ctx->plane_state == plane_state) { - if (dc_res_is_odm_head_pipe(pipe_ctx)) { - pipe_ctx->plane_state = NULL; - pipe_ctx->bottom_pipe = NULL; - continue; - } - if (pipe_ctx->top_pipe) pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; @@ -1367,13 +1342,10 @@ bool dc_remove_plane_from_context( * For head pipe detach surfaces from pipe for tail * pipe just zero it out */ - if (!pipe_ctx->top_pipe) { + if (!pipe_ctx->top_pipe) pipe_ctx->plane_state = NULL; - if (!dc_res_get_odm_bottom_pipe(pipe_ctx)) - pipe_ctx->bottom_pipe = NULL; - } else { + else memset(pipe_ctx, 0, sizeof(*pipe_ctx)); - } } } @@ -1659,24 +1631,25 @@ static struct audio *find_first_free_audio( const struct resource_pool *pool, enum engine_id id) { - int i; - for (i = 0; i < pool->audio_count; i++) { + int i, available_audio_count; + + available_audio_count = pool->audio_count; + + for (i = 0; i < available_audio_count; i++) { if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) { /*we have enough audio endpoint, find the matching inst*/ if (id != i) continue; - return pool->audios[i]; } } - /* use engine id to find free audio */ - if ((id < pool->audio_count) && (res_ctx->is_audio_acquired[id] == false)) { + /* use engine id to find free audio */ + if ((id < available_audio_count) && (res_ctx->is_audio_acquired[id] == false)) { return pool->audios[id]; } - /*not found the matching one, first come first serve*/ - for (i = 0; i < pool->audio_count; i++) { + for (i = 0; i < available_audio_count; i++) { if (res_ctx->is_audio_acquired[i] == false) { return pool->audios[i]; } @@ -1736,50 +1709,45 @@ enum dc_status dc_remove_stream_from_ctx( { int i; struct dc_context *dc_ctx = dc->ctx; - struct pipe_ctx *del_pipe = NULL; + struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream); + struct pipe_ctx *odm_pipe; - /* Release primary pipe */ - for (i = 0; i < MAX_PIPES; i++) { - if (new_ctx->res_ctx.pipe_ctx[i].stream == stream && - !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { - struct pipe_ctx *odm_pipe = - dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]); + if (!del_pipe) { + DC_ERROR("Pipe not found for stream %p !\n", stream); + return DC_ERROR_UNEXPECTED; + } - del_pipe = &new_ctx->res_ctx.pipe_ctx[i]; + odm_pipe = del_pipe->next_odm_pipe; - ASSERT(del_pipe->stream_res.stream_enc); - update_stream_engine_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.stream_enc, - false); + /* Release primary pipe */ + ASSERT(del_pipe->stream_res.stream_enc); + update_stream_engine_usage( + &new_ctx->res_ctx, + dc->res_pool, + del_pipe->stream_res.stream_enc, + false); - if (del_pipe->stream_res.audio) - update_audio_usage( - &new_ctx->res_ctx, - dc->res_pool, - del_pipe->stream_res.audio, - false); + if (del_pipe->stream_res.audio) + update_audio_usage( + &new_ctx->res_ctx, + dc->res_pool, + del_pipe->stream_res.audio, + false); - resource_unreference_clock_source(&new_ctx->res_ctx, - dc->res_pool, - del_pipe->clock_source); + resource_unreference_clock_source(&new_ctx->res_ctx, + dc->res_pool, + del_pipe->clock_source); - if (dc->res_pool->funcs->remove_stream_from_ctx) - dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); + if (dc->res_pool->funcs->remove_stream_from_ctx) + dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); - memset(del_pipe, 0, sizeof(*del_pipe)); - if (odm_pipe) - memset(odm_pipe, 0, sizeof(*odm_pipe)); + while (odm_pipe) { + struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; - break; - } - } - - if (!del_pipe) { - DC_ERROR("Pipe not found for stream %p !\n", stream); - return DC_ERROR_UNEXPECTED; + memset(odm_pipe, 0, sizeof(*odm_pipe)); + odm_pipe = next_odm_pipe; } + memset(del_pipe, 0, sizeof(*del_pipe)); for (i = 0; i < new_ctx->stream_count; i++) if (new_ctx->streams[i] == stream) @@ -1880,7 +1848,7 @@ static int acquire_resource_from_hw_enabled_state( struct dc_stream_state *stream) { struct dc_link *link = stream->link; - unsigned int inst; + unsigned int inst, tg_inst; /* Check for enabled DIG to identify enabled display */ if (!link->link_enc->funcs->is_dig_enabled(link->link_enc)) @@ -1892,28 +1860,37 @@ static int acquire_resource_from_hw_enabled_state( * current implementation always map 1-to-1, so this code makes * the same assumption and doesn't check OTG source. */ - inst = link->link_enc->funcs->get_dig_frontend(link->link_enc) - 1; + inst = link->link_enc->funcs->get_dig_frontend(link->link_enc); /* Instance should be within the range of the pool */ if (inst >= pool->pipe_count) return -1; - if (!res_ctx->pipe_ctx[inst].stream) { - struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[inst]; + if (inst >= pool->stream_enc_count) + return -1; + + tg_inst = pool->stream_enc[inst]->funcs->dig_source_otg(pool->stream_enc[inst]); - pipe_ctx->stream_res.tg = pool->timing_generators[inst]; - pipe_ctx->plane_res.mi = pool->mis[inst]; - pipe_ctx->plane_res.hubp = pool->hubps[inst]; - pipe_ctx->plane_res.ipp = pool->ipps[inst]; - pipe_ctx->plane_res.xfm = pool->transforms[inst]; - pipe_ctx->plane_res.dpp = pool->dpps[inst]; - pipe_ctx->stream_res.opp = pool->opps[inst]; - if (pool->dpps[inst]) - pipe_ctx->plane_res.mpcc_inst = pool->dpps[inst]->inst; - pipe_ctx->pipe_idx = inst; + if (tg_inst >= pool->timing_generator_count) + return false; + + if (!res_ctx->pipe_ctx[tg_inst].stream) { + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst]; + + pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst]; + pipe_ctx->plane_res.mi = pool->mis[tg_inst]; + pipe_ctx->plane_res.hubp = pool->hubps[tg_inst]; + pipe_ctx->plane_res.ipp = pool->ipps[tg_inst]; + pipe_ctx->plane_res.xfm = pool->transforms[tg_inst]; + pipe_ctx->plane_res.dpp = pool->dpps[tg_inst]; + pipe_ctx->stream_res.opp = pool->opps[tg_inst]; + + if (pool->dpps[tg_inst]) + pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst; + pipe_ctx->pipe_idx = tg_inst; pipe_ctx->stream = stream; - return inst; + return tg_inst; } return -1; @@ -2475,6 +2452,12 @@ void dc_resource_state_copy_construct( if (cur_pipe->bottom_pipe) cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; + + if (cur_pipe->next_odm_pipe) + cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; + + if (cur_pipe->prev_odm_pipe) + cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; } for (i = 0; i < dst_ctx->stream_count; i++) { 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 352862370390..bf1d7bb90e0f 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -566,6 +566,7 @@ 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) { @@ -597,6 +598,14 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc, struct hubp *hubp; int i; + /* Dynamic metadata is only supported on HDMI or DP */ + if (!dc_is_hdmi_signal(stream->signal) && !dc_is_dp_signal(stream->signal)) + return false; + + /* Check hardware support */ + if (!dc->hwss.program_dmdata_engine) + return false; + for (i = 0; i < MAX_PIPES; i++) { pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe_ctx->stream == stream) @@ -612,23 +621,7 @@ bool dc_stream_set_dynamic_metadata(struct dc *dc, pipe_ctx->stream->dmdata_address = attr->address; - if (pipe_ctx->stream_res.stream_enc && - 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); - } + dc->hwss.program_dmdata_engine(pipe_ctx); if (hubp->funcs->dmdata_set_attributes != NULL && pipe_ctx->stream->dmdata_address.quad_part != 0) { 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 f40e4fd52fa2..b9d6a5bd8522 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -60,7 +60,6 @@ static void construct(struct dc_context *ctx, struct dc_plane_state *plane_state 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) { @@ -279,7 +278,7 @@ struct dc_3dlut *dc_create_3dlut_func(void) goto alloc_fail; kref_init(&lut->refcount); - lut->initialized = false; + lut->state.raw = 0; return lut; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e513028faefa..a82352a87808 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.35" +#define DC_VER "3.2.48" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -121,6 +121,7 @@ struct dc_caps { struct dc_bug_wa { bool no_connect_phy_config; bool dedcn20_305_wa; + bool skip_clock_update; }; #endif @@ -219,7 +220,7 @@ struct dc_config { bool power_down_display_on_boot; bool edp_not_connected; bool forced_clocks; - + bool multi_mon_pp_mclk_switch; }; enum visual_confirm { @@ -252,7 +253,10 @@ enum wm_report_mode { struct dc_clocks { int dispclk_khz; int max_supported_dppclk_khz; + int max_supported_dispclk_khz; int dppclk_khz; + int bw_dppclk_khz; /*a copy of dppclk_khz*/ + int bw_dispclk_khz; int dcfclk_khz; int socclk_khz; int dcfclk_deep_sleep_khz; @@ -260,6 +264,12 @@ struct dc_clocks { int phyclk_khz; int dramclk_khz; bool p_state_change_support; + + /* + * Elements below are not compared for the purposes of + * optimization required + */ + bool prev_p_state_change_support; }; struct dc_bw_validation_profile { @@ -341,6 +351,7 @@ struct dc_debug_options { bool disable_pplib_wm_range; enum wm_report_mode pplib_wm_report_mode; unsigned int min_disp_clk_khz; + unsigned int min_dpp_clk_khz; int sr_exit_time_dpm0_ns; int sr_enter_plus_exit_time_dpm0_ns; int sr_exit_time_ns; @@ -367,6 +378,7 @@ struct dc_debug_options { bool scl_reset_length10; bool hdmi20_disable; bool skip_detection_link_training; + bool remove_disconnect_edp; unsigned int force_odm_combine; //bit vector based on otg inst unsigned int force_fclk_khz; bool disable_tri_buf; @@ -374,10 +386,18 @@ struct dc_debug_options { #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT bool disable_fec; #endif +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + bool disable_48mhz_pwrdwn; +#endif /* This forces a hard min on the DCFCLK requested to SMU/PP * watermarks are not affected. */ unsigned int force_min_dcfclk_mhz; + bool disable_timing_sync; +#if defined(CONFIG_DRM_AMD_DC_DCN2_0) + bool cm_in_bypass; +#endif + int force_clock_mode;/*every mode change.*/ }; struct dc_debug_data { @@ -406,6 +426,7 @@ struct dc_phy_addr_space_config { } gart_config; bool valid; + uint64_t page_table_default_page_addr; }; struct dc_virtual_addr_space_config { @@ -597,9 +618,12 @@ enum dc_transfer_func_predefined { TRANSFER_FUNCTION_UNITY, TRANSFER_FUNCTION_HLG, TRANSFER_FUNCTION_HLG12, - TRANSFER_FUNCTION_GAMMA22 + TRANSFER_FUNCTION_GAMMA22, + TRANSFER_FUNCTION_GAMMA24, + TRANSFER_FUNCTION_GAMMA26 }; + struct dc_transfer_func { struct kref refcount; enum dc_transfer_func_type type; @@ -615,12 +639,26 @@ struct dc_transfer_func { #if defined(CONFIG_DRM_AMD_DC_DCN2_0) +union dc_3dlut_state { + struct { + uint32_t initialized:1; /*if 3dlut is went through color module for initialization */ + uint32_t rmu_idx_valid:1; /*if mux settings are valid*/ + uint32_t rmu_mux_num:3; /*index of mux to use*/ + uint32_t mpc_rmu0_mux:4; /*select mpcc on mux, one of the following : mpcc0, mpcc1, mpcc2, mpcc3*/ + uint32_t mpc_rmu1_mux:4; + uint32_t mpc_rmu2_mux:4; + uint32_t reserved:15; + } bits; + uint32_t raw; +}; + struct dc_3dlut { struct kref refcount; struct tetrahedral_params lut_3d; uint32_t hdr_multiplier; - bool initialized; + bool initialized; /*remove after diag fix*/ + union dc_3dlut_state state; struct dc_context *ctx; }; #endif @@ -682,7 +720,7 @@ struct dc_plane_state { struct rect dst_rect; struct rect clip_rect; - union plane_size plane_size; + struct plane_size plane_size; union dc_tiling_info tiling_info; struct dc_plane_dcc_param dcc; @@ -716,6 +754,7 @@ struct dc_plane_state { bool visible; bool flip_immediate; bool horizontal_mirror; + int layer_index; union surface_update_flags update_flags; /* private to DC core */ @@ -731,7 +770,7 @@ struct dc_plane_state { }; struct dc_plane_info { - union plane_size plane_size; + struct plane_size plane_size; union dc_tiling_info tiling_info; struct dc_plane_dcc_param dcc; enum surface_pixel_format format; @@ -745,6 +784,7 @@ struct dc_plane_info { bool global_alpha; int global_alpha_value; bool input_csc_enabled; + int layer_index; }; struct dc_scaling_info { @@ -834,6 +874,9 @@ enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *pla void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx *info); +bool dc_set_generic_gpio_for_stereo(bool enable, + struct gpio_service *gpio_service); + /* * fast_validate: we return after determining if we can support the new state, * but before we populate the programming info @@ -1020,6 +1063,8 @@ unsigned int dc_get_target_backlight_pwm(struct dc *dc); bool dc_is_dmcu_initialized(struct dc *dc); +enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping); +void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg); #if defined(CONFIG_DRM_AMD_DC_DSC_SUPPORT) /******************************************************************************* * DSC Interfaces diff --git a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h index 78c3b300ec45..b1dd0d60d98e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_bios_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_bios_types.h @@ -61,9 +61,6 @@ struct dc_vbios_funcs { struct graphics_object_id connector_object_id, uint32_t device_tag_index, struct connector_device_tag_info *info); - enum bp_result (*get_firmware_info)( - struct dc_bios *bios, - struct dc_firmware_info *info); enum bp_result (*get_spread_spectrum_info)( struct dc_bios *bios, enum as_signal_type signal, @@ -152,6 +149,8 @@ struct dc_bios { struct dc_context *ctx; const struct bios_registers *regs; struct integrated_info *integrated_info; + struct dc_firmware_info fw_info; + bool fw_info_valid; }; #endif /* DC_BIOS_TYPES_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 dfcec4d3e9c0..ef79a686e4c2 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -90,6 +90,13 @@ enum dc_post_cursor2 { POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3, }; +enum dc_dp_training_pattern { + DP_TRAINING_PATTERN_SEQUENCE_1 = 0, + DP_TRAINING_PATTERN_SEQUENCE_2, + DP_TRAINING_PATTERN_SEQUENCE_3, + DP_TRAINING_PATTERN_SEQUENCE_4, +}; + struct dc_link_settings { enum dc_lane_count lane_count; enum dc_link_rate link_rate; @@ -109,6 +116,23 @@ struct dc_link_training_settings { struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; }; +struct dc_link_training_overrides { + enum dc_voltage_swing *voltage_swing; + enum dc_pre_emphasis *pre_emphasis; + enum dc_post_cursor2 *post_cursor2; + + uint16_t *cr_pattern_time; + uint16_t *eq_pattern_time; + enum dc_dp_training_pattern *pattern_for_eq; + + enum dc_link_spread *downspread; + bool *alternate_scrambler_reset; + bool *enhanced_framing; + bool *mst_enable; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + bool *fec_enable; +#endif +}; union dpcd_rev { struct { 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 22db5682aa6c..0b8700a8a94a 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -115,42 +115,40 @@ struct rect { int height; }; -union plane_size { - /* Grph or Video will be selected - * based on format above: - * Use Video structure if - * format >= DalPixelFormat_VideoBegin - * else use Grph structure +struct plane_size { + /* Graphic surface pitch in pixels. + * In LINEAR_GENERAL mode, pitch + * is 32 pixel aligned. */ - struct { - struct rect surface_size; - /* Graphic surface pitch in pixels. - * In LINEAR_GENERAL mode, pitch - * is 32 pixel aligned. - */ - int surface_pitch; - } grph; + int surface_pitch; + int chroma_pitch; + struct rect surface_size; + struct rect chroma_size; - struct { - struct rect luma_size; - /* Graphic surface pitch in pixels. - * In LINEAR_GENERAL mode, pitch is - * 32 pixel aligned. - */ - int luma_pitch; + union { + struct { + struct rect surface_size; + int surface_pitch; + } grph; - struct rect chroma_size; - /* Graphic surface pitch in pixels. - * In LINEAR_GENERAL mode, pitch is - * 32 pixel aligned. - */ - int chroma_pitch; - } video; + struct { + struct rect luma_size; + int luma_pitch; + struct rect chroma_size; + int chroma_pitch; + } video; + }; }; struct dc_plane_dcc_param { bool enable; + int meta_pitch; + bool independent_64b_blks; + + int meta_pitch_c; + bool independent_64b_blks_c; + union { struct { int meta_pitch; @@ -482,7 +480,6 @@ struct dc_gamma { * 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*/ @@ -519,7 +516,8 @@ union dc_cursor_attribute_flags { uint32_t INVERT_PIXEL_DATA:1; uint32_t ZERO_EXPANSION:1; uint32_t MIN_MAX_INVERT:1; - uint32_t RESERVED:25; + uint32_t ENABLE_CURSOR_DEGAMMA:1; + uint32_t RESERVED:24; } bits; uint32_t value; }; @@ -615,6 +613,7 @@ struct scaling_taps { uint32_t h_taps; uint32_t v_taps_c; uint32_t h_taps_c; + bool integer_scaling; }; enum dc_timing_standard { @@ -758,6 +757,8 @@ struct crtc_trigger_info { struct dc_crtc_timing_adjust { uint32_t v_total_min; uint32_t v_total_max; + uint32_t v_total_mid; + uint32_t v_total_mid_frame_num; }; #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 6f0b80111e58..9ea75db3484e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -83,6 +83,8 @@ struct dc_link { bool is_hpd_filter_disabled; bool dp_ss_off; bool link_state_valid; + bool aux_access_disabled; + bool sync_lt_in_progress; /* caps is the same as reported_link_cap. link_traing use * reported_link_cap. Will clean up. TODO @@ -92,6 +94,7 @@ struct dc_link { struct dc_link_settings cur_link_settings; struct dc_lane_settings cur_lane_setting; struct dc_link_settings preferred_link_setting; + struct dc_link_training_overrides preferred_training_settings; uint8_t ddc_hw_inst; @@ -217,11 +220,24 @@ void dc_link_dp_set_drive_settings( struct dc_link *link, struct link_training_settings *lt_settings); +bool dc_link_dp_perform_link_training_skip_aux( + struct dc_link *link, + const struct dc_link_settings *link_setting); + enum link_training_result dc_link_dp_perform_link_training( struct dc_link *link, const struct dc_link_settings *link_setting, bool skip_video_pattern); +bool dc_link_dp_sync_lt_begin(struct dc_link *link); + +enum link_training_result dc_link_dp_sync_lt_attempt( + struct dc_link *link, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_settings); + +bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down); + void dc_link_dp_enable_hpd(const struct dc_link *link); void dc_link_dp_disable_hpd(const struct dc_link *link); @@ -251,6 +267,11 @@ void dc_link_perform_link_training(struct dc *dc, void dc_link_set_preferred_link_settings(struct dc *dc, struct dc_link_settings *link_setting, struct dc_link *link); +void dc_link_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain); void dc_link_enable_hpd(const struct dc_link *link); void dc_link_disable_hpd(const struct dc_link *link); void dc_link_set_test_pattern(struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 6eabb6491a3d..b273735b6a3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -202,6 +202,7 @@ struct dc_panel_patch { unsigned int dppowerup_delay; unsigned int extra_t12_ms; unsigned int extra_delay_backlight_off; + unsigned int extra_t7_ms; }; struct dc_edid_caps { @@ -725,6 +726,19 @@ struct AsicStateEx { unsigned int phyClock; }; + +enum dc_clock_type { + DC_CLOCK_TYPE_DISPCLK = 0, + DC_CLOCK_TYPE_DPPCLK = 1, +}; + +struct dc_clock_config { + uint32_t max_clock_khz; + uint32_t min_clock_khz; + uint32_t bw_requirequired_clock_khz; + uint32_t current_clock_khz;/*current clock in use*/ +}; + #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT /* DSC DPCD capabilities */ union dsc_slice_caps1 { 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 4a10a5d22c90..5a35495bc11d 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -145,20 +145,20 @@ static void check_audio_bandwidth_hdmi( if (channel_count > 2) { /* Based on HDMI spec 1.3 Table 7.5 */ - if ((crtc_info->requested_pixel_clock <= 27000) && + if ((crtc_info->requested_pixel_clock_100Hz <= 270000) && (crtc_info->v_active <= 576) && !(crtc_info->interlaced) && !(crtc_info->pixel_repetition == 2 || crtc_info->pixel_repetition == 4)) { limit_freq_to_48_khz = true; - } else if ((crtc_info->requested_pixel_clock <= 27000) && + } else if ((crtc_info->requested_pixel_clock_100Hz <= 270000) && (crtc_info->v_active <= 576) && (crtc_info->interlaced) && (crtc_info->pixel_repetition == 2)) { limit_freq_to_88_2_khz = true; - } else if ((crtc_info->requested_pixel_clock <= 54000) && + } else if ((crtc_info->requested_pixel_clock_100Hz <= 540000) && (crtc_info->v_active <= 576) && !(crtc_info->interlaced)) { limit_freq_to_174_4_khz = true; @@ -613,6 +613,8 @@ void dce_aud_az_configure( AZ_REG_WRITE(AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1, value); + DC_LOG_HW_AUDIO("\n\tAUDIO:az_configure: index: %u data, 0x%x, displayName %s: \n", + audio->inst, value, audio_info->display_name); /* *write the port ID: @@ -737,8 +739,8 @@ void dce_aud_az_configure( /* search pixel clock value for Azalia HDMI Audio */ static void get_azalia_clock_info_hdmi( - uint32_t crtc_pixel_clock_in_khz, - uint32_t actual_pixel_clock_in_khz, + uint32_t crtc_pixel_clock_100hz, + uint32_t actual_pixel_clock_100Hz, struct azalia_clock_info *azalia_clock_info) { /* audio_dto_phase= 24 * 10,000; @@ -749,11 +751,11 @@ static void get_azalia_clock_info_hdmi( /* audio_dto_module = PCLKFrequency * 10,000; * [khz] -> [100Hz] */ azalia_clock_info->audio_dto_module = - actual_pixel_clock_in_khz * 10; + actual_pixel_clock_100Hz; } static void get_azalia_clock_info_dp( - uint32_t requested_pixel_clock_in_khz, + uint32_t requested_pixel_clock_100Hz, const struct audio_pll_info *pll_info, struct azalia_clock_info *azalia_clock_info) { @@ -792,15 +794,15 @@ void dce_aud_wall_dto_setup( /* calculate DTO settings */ get_azalia_clock_info_hdmi( - crtc_info->requested_pixel_clock, - crtc_info->calculated_pixel_clock, + crtc_info->requested_pixel_clock_100Hz, + crtc_info->calculated_pixel_clock_100Hz, &clock_info); - DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock = %d"\ - "calculated_pixel_clock =%d\n"\ + DC_LOG_HW_AUDIO("\n%s:Input::requested_pixel_clock_100Hz = %d"\ + "calculated_pixel_clock_100Hz =%d\n"\ "audio_dto_module = %d audio_dto_phase =%d \n\n", __func__,\ - crtc_info->requested_pixel_clock,\ - crtc_info->calculated_pixel_clock,\ + crtc_info->requested_pixel_clock_100Hz,\ + crtc_info->calculated_pixel_clock_100Hz,\ clock_info.audio_dto_module,\ clock_info.audio_dto_phase); @@ -833,7 +835,7 @@ void dce_aud_wall_dto_setup( calculate DTO settings */ get_azalia_clock_info_dp( - crtc_info->requested_pixel_clock, + crtc_info->requested_pixel_clock_100Hz, pll_info, &clock_info); @@ -922,7 +924,6 @@ static const struct audio_funcs funcs = { .az_configure = dce_aud_az_configure, .destroy = dce_aud_destroy, }; - void dce_aud_destroy(struct audio **audio) { struct dce_audio *aud = DCE_AUD(*audio); @@ -936,7 +937,7 @@ struct audio *dce_audio_create( unsigned int inst, const struct dce_audio_registers *reg, const struct dce_audio_shift *shifts, - const struct dce_aduio_mask *masks + const struct dce_audio_mask *masks ) { struct dce_audio *audio = kzalloc(sizeof(*audio), GFP_KERNEL); @@ -953,7 +954,6 @@ struct audio *dce_audio_create( audio->regs = reg; audio->shifts = shifts; audio->masks = masks; - return &audio->base; } 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 a0d5724aab31..1392fab0860b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.h @@ -101,7 +101,7 @@ struct dce_audio_shift { uint32_t DCCG_AUDIO_DTO1_USE_512FBR_DTO; }; -struct dce_aduio_mask { +struct dce_audio_mask { uint32_t AZALIA_ENDPOINT_REG_INDEX; uint32_t AZALIA_ENDPOINT_REG_DATA; @@ -125,7 +125,7 @@ struct dce_audio { struct audio base; const struct dce_audio_registers *regs; const struct dce_audio_shift *shifts; - const struct dce_aduio_mask *masks; + const struct dce_audio_mask *masks; }; struct audio *dce_audio_create( @@ -133,7 +133,7 @@ struct audio *dce_audio_create( unsigned int inst, const struct dce_audio_registers *reg, const struct dce_audio_shift *shifts, - const struct dce_aduio_mask *masks); + const struct dce_audio_mask *masks); void dce_aud_destroy(struct audio **audio); diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index f2295e780031..c3f9f4185ce8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -30,6 +30,7 @@ #include "core_types.h" #include "dce_aux.h" #include "dce/dce_11_0_sh_mask.h" +#include "dm_event_log.h" #define CTX \ aux110->base.ctx @@ -252,6 +253,8 @@ static void submit_channel_request( } REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1); + EVENT_LOG_AUX_REQ(engine->ddc->pin_data->en, EVENT_LOG_AUX_ORIGIN_NATIVE, + request->action, request->address, request->length, request->data); } static int read_channel_reply(struct dce_aux *engine, uint32_t size, @@ -480,9 +483,13 @@ int dce_aux_transfer_raw(struct ddc_service *ddc, *operation_result = get_channel_status(aux_engine, &returned_bytes); if (*operation_result == AUX_CHANNEL_OPERATION_SUCCEEDED) { - read_channel_reply(aux_engine, payload->length, + int bytes_replied = 0; + bytes_replied = read_channel_reply(aux_engine, payload->length, payload->data, payload->reply, &status); + EVENT_LOG_AUX_REP(aux_engine->ddc->pin_data->en, + EVENT_LOG_AUX_ORIGIN_NATIVE, *payload->reply, + bytes_replied, payload->data); res = returned_bytes; } else { res = -1; 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 5fae77e201d5..f787a6b94781 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 @@ -1061,7 +1061,8 @@ static bool dcn20_program_pix_clk( 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 + .get_pix_clk_dividers = dce112_get_pix_clk_dividers, + .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz }; #endif @@ -1234,37 +1235,36 @@ static bool calc_pll_max_vco_construct( struct calc_pll_clock_source_init_data *init_data) { uint32_t i; - struct dc_firmware_info fw_info = { { 0 } }; + struct dc_firmware_info *fw_info; if (calc_pll_cs == NULL || init_data == NULL || init_data->bp == NULL) return false; - if (init_data->bp->funcs->get_firmware_info( - init_data->bp, - &fw_info) != BP_RESULT_OK) + if (!init_data->bp->fw_info_valid) return false; + fw_info = &init_data->bp->fw_info; calc_pll_cs->ctx = init_data->ctx; - calc_pll_cs->ref_freq_khz = fw_info.pll_info.crystal_frequency; + calc_pll_cs->ref_freq_khz = fw_info->pll_info.crystal_frequency; calc_pll_cs->min_vco_khz = - fw_info.pll_info.min_output_pxl_clk_pll_frequency; + fw_info->pll_info.min_output_pxl_clk_pll_frequency; calc_pll_cs->max_vco_khz = - fw_info.pll_info.max_output_pxl_clk_pll_frequency; + fw_info->pll_info.max_output_pxl_clk_pll_frequency; if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0) calc_pll_cs->max_pll_input_freq_khz = init_data->max_override_input_pxl_clk_pll_freq_khz; else calc_pll_cs->max_pll_input_freq_khz = - fw_info.pll_info.max_input_pxl_clk_pll_frequency; + fw_info->pll_info.max_input_pxl_clk_pll_frequency; if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0) calc_pll_cs->min_pll_input_freq_khz = init_data->min_override_input_pxl_clk_pll_freq_khz; else calc_pll_cs->min_pll_input_freq_khz = - fw_info.pll_info.min_input_pxl_clk_pll_frequency; + fw_info->pll_info.min_input_pxl_clk_pll_frequency; calc_pll_cs->min_pix_clock_pll_post_divider = init_data->min_pix_clk_pll_post_divider; @@ -1316,7 +1316,6 @@ bool dce110_clk_src_construct( const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_mask *cs_mask) { - struct dc_firmware_info fw_info = { { 0 } }; struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi; struct calc_pll_clock_source_init_data calc_pll_cs_init_data; @@ -1329,14 +1328,12 @@ bool dce110_clk_src_construct( clk_src->cs_shift = cs_shift; clk_src->cs_mask = cs_mask; - if (clk_src->bios->funcs->get_firmware_info( - clk_src->bios, &fw_info) != BP_RESULT_OK) { + if (!clk_src->bios->fw_info_valid) { ASSERT_CRITICAL(false); goto unexpected_failure; } - clk_src->ext_clk_khz = - fw_info.external_clock_source_frequency_for_dp; + clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp; /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */ calc_pll_cs_init_data.bp = bios; @@ -1376,7 +1373,7 @@ bool dce110_clk_src_construct( FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM; calc_pll_cs_init_data_hdmi.ctx = ctx; - clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency; + clk_src->ref_freq_khz = clk_src->bios->fw_info.pll_info.crystal_frequency; if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL) return true; @@ -1419,8 +1416,6 @@ bool dce112_clk_src_construct( const struct dce110_clk_src_shift *cs_shift, const struct dce110_clk_src_mask *cs_mask) { - struct dc_firmware_info fw_info = { { 0 } }; - clk_src->base.ctx = ctx; clk_src->bios = bios; clk_src->base.id = id; @@ -1430,13 +1425,12 @@ bool dce112_clk_src_construct( clk_src->cs_shift = cs_shift; clk_src->cs_mask = cs_mask; - if (clk_src->bios->funcs->get_firmware_info( - clk_src->bios, &fw_info) != BP_RESULT_OK) { + if (!clk_src->bios->fw_info_valid) { ASSERT_CRITICAL(false); return false; } - clk_src->ext_clk_khz = fw_info.external_clock_source_frequency_for_dp; + clk_src->ext_clk_khz = clk_src->bios->fw_info.external_clock_source_frequency_for_dp; return true; } 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 adae03b1f3a7..43c1bf60b83c 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 @@ -78,6 +78,23 @@ SRII(PIXEL_RATE_CNTL, OTG, 5) #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define CS_COMMON_REG_LIST_DCN2_1(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(MODULO, DP_DTO, 0),\ + SRII(MODULO, DP_DTO, 1),\ + SRII(MODULO, DP_DTO, 2),\ + SRII(MODULO, DP_DTO, 3),\ + SRII(PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3) +#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),\ 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 cb0a037b1c4a..ac04d77058f0 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h @@ -62,6 +62,10 @@ SRII(BLND_CONTROL, BLND, 4), \ SRII(BLND_CONTROL, BLND, 5) +#define HSWEQ_DCN_PIXEL_RATE_REG_LIST(blk, inst) \ + SRII(PIXEL_RATE_CNTL, blk, inst), \ + SRII(PHYPLL_PIXEL_RATE_CNTL, blk, inst) + #define HWSEQ_PIXEL_RATE_REG_LIST(blk) \ SRII(PIXEL_RATE_CNTL, blk, 0), \ SRII(PIXEL_RATE_CNTL, blk, 1), \ @@ -151,7 +155,10 @@ SR(DCCG_GATE_DISABLE_CNTL2), \ SR(DCFCLK_CNTL),\ SR(DCFCLK_CNTL), \ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL) + + +#define MMHUB_DCN_REG_LIST()\ /* todo: get these from GVM instead of reading registers ourselves */\ MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32),\ MMHUB_SR(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32),\ @@ -166,10 +173,14 @@ MMHUB_SR(MC_VM_SYSTEM_APERTURE_LOW_ADDR),\ MMHUB_SR(MC_VM_SYSTEM_APERTURE_HIGH_ADDR) + #define HWSEQ_DCN1_REG_LIST()\ HWSEQ_DCN_REG_LIST(), \ - HWSEQ_PIXEL_RATE_REG_LIST(OTG), \ - HWSEQ_PHYPLL_REG_LIST(OTG), \ + MMHUB_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ SR(DCHUBBUB_SDPIF_FB_BASE),\ SR(DCHUBBUB_SDPIF_FB_OFFSET),\ SR(DCHUBBUB_SDPIF_AGP_BASE),\ @@ -202,8 +213,12 @@ #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), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 4), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 5), \ SR(MICROSECOND_TIME_BASE_DIV), \ SR(MILLISECOND_TIME_BASE_DIV), \ SR(DISPCLK_FREQ_CHANGE_CNTL), \ @@ -227,8 +242,8 @@ SR(DOMAIN7_PG_CONFIG), \ SR(DOMAIN8_PG_CONFIG), \ SR(DOMAIN9_PG_CONFIG), \ - SR(DOMAIN10_PG_CONFIG), \ - SR(DOMAIN11_PG_CONFIG), \ +/* SR(DOMAIN10_PG_CONFIG), Navi1x HUBP5 not powergate-able*/\ +/* SR(DOMAIN11_PG_CONFIG), Navi1x DPP5 is not powergate-able */\ SR(DOMAIN16_PG_CONFIG), \ SR(DOMAIN17_PG_CONFIG), \ SR(DOMAIN18_PG_CONFIG), \ @@ -263,6 +278,59 @@ BL_REG_LIST() #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define HWSEQ_DCN21_REG_LIST()\ + HWSEQ_DCN_REG_LIST(), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 0), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 1), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 2), \ + HSWEQ_DCN_PIXEL_RATE_REG_LIST(OTG, 3), \ + MMHUB_DCN_REG_LIST(), \ + 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(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_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(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_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 */ @@ -401,36 +469,34 @@ struct dce_hwseq_registers { HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh),\ HWS_SF1(blk, PHYPLL_PIXEL_RATE_CNTL, PIXEL_RATE_PLL_SOURCE, mask_sh) +#define HWSEQ_LVTMA_MASK_SH_LIST(mask_sh)\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh),\ + HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + #define HWSEQ_DCE8_MASK_SH_LIST(mask_sh)\ .DCFE_CLOCK_ENABLE = CRTC_DCFE_CLOCK_CONTROL__CRTC_DCFE_CLOCK_ENABLE ## mask_sh, \ HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_V_UPDATE_LOCK, mask_sh),\ HWS_SF(BLND_, V_UPDATE_LOCK, BLND_SCL_V_UPDATE_LOCK, mask_sh),\ HWS_SF(BLND_, V_UPDATE_LOCK, BLND_DCP_GRPH_SURF_V_UPDATE_LOCK, mask_sh),\ HWS_SF(BLND_, CONTROL, BLND_MODE, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ + HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) #define HWSEQ_DCE10_MASK_SH_LIST(mask_sh)\ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE_),\ HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND_),\ - HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_), \ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ + HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) #define HWSEQ_DCE11_MASK_SH_LIST(mask_sh)\ HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ SF(DCFEV_CLOCK_CONTROL, DCFEV_CLOCK_ENABLE, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_) #define HWSEQ_DCE112_MASK_SH_LIST(mask_sh)\ HWSEQ_DCE10_MASK_SH_LIST(mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh),\ HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_) #define HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh)\ @@ -438,18 +504,15 @@ struct dce_hwseq_registers { SF(DCHUB_FB_LOCATION, FB_BASE, mask_sh),\ SF(DCHUB_AGP_BASE, AGP_BASE, mask_sh),\ SF(DCHUB_AGP_BOT, AGP_BOT, mask_sh),\ - SF(DCHUB_AGP_TOP, AGP_TOP, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + SF(DCHUB_AGP_TOP, AGP_TOP, mask_sh) #define HWSEQ_DCE12_MASK_SH_LIST(mask_sh)\ HWSEQ_DCEF_MASK_SH_LIST(mask_sh, DCFE0_DCFE_),\ HWSEQ_BLND_MASK_SH_LIST(mask_sh, BLND0_BLND_),\ HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, CRTC0_),\ HWSEQ_PHYPLL_MASK_SH_LIST(mask_sh, CRTC0_),\ - HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + HWSEQ_GFX9_DCHUB_MASK_SH_LIST(mask_sh),\ + HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) #define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\ HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\ @@ -512,10 +575,7 @@ struct dce_hwseq_registers { HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\ HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_DIGON_OVRD, mask_sh), \ - HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh) + HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define HWSEQ_DCN2_MASK_SH_LIST(mask_sh)\ @@ -576,6 +636,49 @@ struct dce_hwseq_registers { 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), \ + HWSEQ_LVTMA_MASK_SH_LIST(mask_sh) +#endif + +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define HWSEQ_DCN21_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(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, PAGE_DIRECTORY_ENTRY_HI32, mask_sh),\ + HWS_SF(, MMVM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, PAGE_DIRECTORY_ENTRY_LO32, 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(, 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(, 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(, 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(, 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 @@ -612,9 +715,9 @@ struct dce_hwseq_registers { type ENABLE_L1_TLB;\ type SYSTEM_ACCESS_MODE;\ type LVTMA_BLON;\ - type LVTMA_PWRSEQ_TARGET_STATE_R;\ type LVTMA_DIGON;\ - type LVTMA_DIGON_OVRD; + type LVTMA_DIGON_OVRD;\ + type LVTMA_PWRSEQ_TARGET_STATE_R; #define HWSEQ_DCN_REG_FIELD_LIST(type) \ type HUBP_VTG_SEL; \ @@ -696,7 +799,8 @@ struct dce_hwseq_registers { type D2VGA_MODE_ENABLE; \ type D3VGA_MODE_ENABLE; \ type D4VGA_MODE_ENABLE; \ - type AZALIA_AUDIO_DTO_MODULE; + type AZALIA_AUDIO_DTO_MODULE;\ + type HPO_HDMISTREAMCLK_GATE_DIS; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) 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 a9061aaf1562..aad7b52165be 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 @@ -25,6 +25,7 @@ #include <linux/delay.h> +#include "resource.h" #include "dce_i2c.h" #include "dce_i2c_hw.h" #include "reg_helper.h" @@ -99,17 +100,6 @@ static uint32_t get_hw_buffer_available_size( dce_i2c_hw->buffer_used_bytes; } -uint32_t get_reference_clock( - struct dc_bios *bios) -{ - struct dc_firmware_info info = { { 0 } }; - - if (bios->funcs->get_firmware_info(bios, &info) != BP_RESULT_OK) - return 0; - - return info.pll_info.crystal_frequency; -} - static uint32_t get_speed( const struct dce_i2c_hw *dce_i2c_hw) { @@ -401,7 +391,7 @@ struct dce_i2c_hw *acquire_i2c_hw_engine( if (ddc->hw_info.hw_supported) { enum gpio_ddc_line line = dal_ddc_get_line(ddc); - if (line < pool->pipe_count) + if (line < pool->res_cap->num_ddc) dce_i2c_hw = pool->hw_i2cs[line]; } @@ -632,7 +622,7 @@ void dce_i2c_hw_construct( { dce_i2c_hw->ctx = ctx; dce_i2c_hw->engine_id = engine_id; - dce_i2c_hw->reference_frequency = get_reference_clock(ctx->dc_bios) >> 1; + dce_i2c_hw->reference_frequency = (ctx->dc_bios->fw_info.pll_info.crystal_frequency) >> 1; dce_i2c_hw->regs = regs; dce_i2c_hw->shifts = shifts; dce_i2c_hw->masks = masks; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c index a24a2bda8656..1488ffddf4e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c @@ -391,10 +391,10 @@ static void program_tiling( static void program_size_and_rotation( struct dce_mem_input *dce_mi, enum dc_rotation_angle rotation, - const union plane_size *plane_size) + const struct plane_size *plane_size) { - const struct rect *in_rect = &plane_size->grph.surface_size; - struct rect hw_rect = plane_size->grph.surface_size; + const struct rect *in_rect = &plane_size->surface_size; + struct rect hw_rect = plane_size->surface_size; const uint32_t rotation_angles[ROTATION_ANGLE_COUNT] = { [ROTATION_ANGLE_0] = 0, [ROTATION_ANGLE_90] = 1, @@ -423,7 +423,7 @@ static void program_size_and_rotation( GRPH_Y_END, hw_rect.height); REG_SET(GRPH_PITCH, 0, - GRPH_PITCH, plane_size->grph.surface_pitch); + GRPH_PITCH, plane_size->surface_pitch); REG_SET(HW_ROTATION, 0, GRPH_ROTATION_ANGLE, rotation_angles[rotation]); @@ -505,7 +505,7 @@ static void dce_mi_program_surface_config( struct mem_input *mi, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror) diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index 5e2b4d47c548..6ed922a3c1cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -1038,6 +1038,24 @@ static void dce110_stream_encoder_set_avmute( } +static void dce110_reset_hdmi_stream_attribute( + struct stream_encoder *enc) +{ + struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); + if (enc110->se_mask->HDMI_DATA_SCRAMBLE_EN) + REG_UPDATE_5(HDMI_CONTROL, + HDMI_PACKET_GEN_VERSION, 1, + HDMI_KEEPOUT_MODE, 1, + HDMI_DEEP_COLOR_ENABLE, 0, + HDMI_DATA_SCRAMBLE_EN, 0, + HDMI_CLOCK_CHANNEL_RATE, 0); + else + REG_UPDATE_3(HDMI_CONTROL, + HDMI_PACKET_GEN_VERSION, 1, + HDMI_KEEPOUT_MODE, 1, + HDMI_DEEP_COLOR_ENABLE, 0); +} + #define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000 #define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1 @@ -1251,13 +1269,13 @@ static uint32_t calc_max_audio_packets_per_line( static void get_audio_clock_info( enum dc_color_depth color_depth, - uint32_t crtc_pixel_clock_in_khz, - uint32_t actual_pixel_clock_in_khz, + uint32_t crtc_pixel_clock_100Hz, + uint32_t actual_pixel_clock_100Hz, struct audio_clock_info *audio_clock_info) { const struct audio_clock_info *clock_info; uint32_t index; - uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_in_khz / 10; + uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_100Hz / 100; uint32_t audio_array_size; switch (color_depth) { @@ -1294,16 +1312,16 @@ static void get_audio_clock_info( } /* not found */ - if (actual_pixel_clock_in_khz == 0) - actual_pixel_clock_in_khz = crtc_pixel_clock_in_khz; + if (actual_pixel_clock_100Hz == 0) + actual_pixel_clock_100Hz = crtc_pixel_clock_100Hz; /* See HDMI spec the table entry under * pixel clock of "Other". */ audio_clock_info->pixel_clock_in_10khz = - actual_pixel_clock_in_khz / 10; - audio_clock_info->cts_32khz = actual_pixel_clock_in_khz; - audio_clock_info->cts_44khz = actual_pixel_clock_in_khz; - audio_clock_info->cts_48khz = actual_pixel_clock_in_khz; + actual_pixel_clock_100Hz / 100; + audio_clock_info->cts_32khz = actual_pixel_clock_100Hz / 10; + audio_clock_info->cts_44khz = actual_pixel_clock_100Hz / 10; + audio_clock_info->cts_48khz = actual_pixel_clock_100Hz / 10; audio_clock_info->n_32khz = 4096; audio_clock_info->n_44khz = 6272; @@ -1369,14 +1387,14 @@ static void dce110_se_setup_hdmi_audio( /* Program audio clock sample/regeneration parameters */ get_audio_clock_info(crtc_info->color_depth, - crtc_info->requested_pixel_clock, - crtc_info->calculated_pixel_clock, + crtc_info->requested_pixel_clock_100Hz, + crtc_info->calculated_pixel_clock_100Hz, &audio_clock_info); DC_LOG_HW_AUDIO( - "\n%s:Input::requested_pixel_clock = %d" \ - "calculated_pixel_clock = %d \n", __func__, \ - crtc_info->requested_pixel_clock, \ - crtc_info->calculated_pixel_clock); + "\n%s:Input::requested_pixel_clock_100Hz = %d" \ + "calculated_pixel_clock_100Hz = %d \n", __func__, \ + crtc_info->requested_pixel_clock_100Hz, \ + crtc_info->calculated_pixel_clock_100Hz); /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */ REG_UPDATE(HDMI_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz); @@ -1584,6 +1602,17 @@ static void dig_connect_to_otg( REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst); } +static unsigned int dig_source_otg( + struct stream_encoder *enc) +{ + uint32_t tg_inst = 0; + struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc); + + REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst); + + return tg_inst; +} + static const struct stream_encoder_funcs dce110_str_enc_funcs = { .dp_set_stream_attribute = dce110_stream_encoder_dp_set_stream_attribute, @@ -1618,6 +1647,8 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = { .setup_stereo_sync = setup_stereo_sync, .set_avmute = dce110_stream_encoder_set_avmute, .dig_connect_to_otg = dig_connect_to_otg, + .hdmi_reset_stream_attribute = dce110_reset_hdmi_stream_attribute, + .dig_source_otg = dig_source_otg, }; void dce110_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c index 6248c8455314..afc61055eca1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c @@ -304,7 +304,7 @@ static const struct dce_audio_shift audio_shift = { AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -910,7 +910,6 @@ static bool construct( { unsigned int i; struct dc_context *ctx = dc->ctx; - struct dc_firmware_info info; struct dc_bios *bp; ctx->dc_bios->regs = &bios_regs; @@ -921,8 +920,7 @@ static bool construct( bp = ctx->dc_bios; - if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) && - info.external_clock_source_frequency_for_dp != 0) { + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { pool->base.dp_clock_source = dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); 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 fafb4b470140..01a924bf477a 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 @@ -667,29 +667,7 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx) link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, pipe_ctx->stream_res.stream_enc->id, true); - /* 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); + link->dc->hwss.update_info_frame(pipe_ctx); /* enable early control to avoid corruption on DP monitor*/ active_total_with_borders = @@ -753,7 +731,7 @@ static enum bp_result link_transmitter_control( * @brief * eDP only. */ -void hwss_edp_wait_for_hpd_ready( +void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up) { @@ -821,7 +799,7 @@ void hwss_edp_wait_for_hpd_ready( } } -void hwss_edp_power_control( +void dce110_edp_power_control( struct dc_link *link, bool power_up) { @@ -903,7 +881,7 @@ void hwss_edp_power_control( * @brief * eDP only. Control the backlight of the eDP panel */ -void hwss_edp_backlight_control( +void dce110_edp_backlight_control( struct dc_link *link, bool enable) { @@ -1003,7 +981,7 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx) } } -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx) { struct dc *dc; struct pp_smu_funcs *pp_smu = NULL; @@ -1026,24 +1004,13 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) if (dc->res_pool->pp_smu) pp_smu = dc->res_pool->pp_smu; - if (option != KEEP_ACQUIRED_RESOURCE || - !dc->debug.az_endpoint_mute_only) - /*only disalbe az_endpoint if power down or free*/ - pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); - if (dc_is_dp_signal(pipe_ctx->stream->signal)) pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable( pipe_ctx->stream_res.stream_enc); else pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable( pipe_ctx->stream_res.stream_enc); - /*don't free audio if it is from retrain or internal disable stream*/ - if (option == FREE_ACQUIRED_RESOURCE && dc->caps.dynamic_audio == true) { - /*we have to dynamic arbitrate the audio endpoints*/ - /*we free the resource, need reset is_audio_acquired*/ - update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, pipe_ctx->stream_res.audio, false); - pipe_ctx->stream_res.audio = 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*/ clk_mgr->funcs->enable_pme_wa(clk_mgr); @@ -1056,21 +1023,24 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option) } } -void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option) +void dce110_disable_stream(struct pipe_ctx *pipe_ctx) { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; struct dc *dc = pipe_ctx->stream->ctx->dc; - if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) { pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets( pipe_ctx->stream_res.stream_enc); + pipe_ctx->stream_res.stream_enc->funcs->hdmi_reset_stream_attribute( + pipe_ctx->stream_res.stream_enc); + } if (dc_is_dp_signal(pipe_ctx->stream->signal)) pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets( pipe_ctx->stream_res.stream_enc); - dc->hwss.disable_audio_stream(pipe_ctx, option); + dc->hwss.disable_audio_stream(pipe_ctx); link->link_enc->funcs->connect_dig_be_to_fe( link->link_enc, @@ -1174,27 +1144,27 @@ static void build_audio_output( stream->timing.flags.INTERLACE; audio_output->crtc_info.refresh_rate = - (stream->timing.pix_clk_100hz*10000)/ + (stream->timing.pix_clk_100hz*100)/ (stream->timing.h_total*stream->timing.v_total); audio_output->crtc_info.color_depth = stream->timing.display_color_depth; - audio_output->crtc_info.requested_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10; + audio_output->crtc_info.requested_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; - audio_output->crtc_info.calculated_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10; + audio_output->crtc_info.calculated_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz; /*for HDMI, audio ACR is with deep color ratio factor*/ if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && - audio_output->crtc_info.requested_pixel_clock == - (stream->timing.pix_clk_100hz / 10)) { + audio_output->crtc_info.requested_pixel_clock_100Hz == + (stream->timing.pix_clk_100hz)) { if (pipe_ctx->stream_res.pix_clk_params.pixel_encoding == PIXEL_ENCODING_YCBCR420) { - audio_output->crtc_info.requested_pixel_clock = - audio_output->crtc_info.requested_pixel_clock/2; - audio_output->crtc_info.calculated_pixel_clock = - pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/20; + audio_output->crtc_info.requested_pixel_clock_100Hz = + audio_output->crtc_info.requested_pixel_clock_100Hz/2; + audio_output->crtc_info.calculated_pixel_clock_100Hz = + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz/2; } } @@ -1360,7 +1330,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( 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); + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; #endif if (dc->hwss.disable_stream_gating) { @@ -1428,7 +1398,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( &stream->bit_depth_params, &stream->clamping); #if defined(CONFIG_DRM_AMD_DC_DCN2_0) - if (odm_pipe) { + while (odm_pipe) { odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion( odm_pipe->stream_res.opp, COLOR_SPACE_YCBCR601, @@ -1439,6 +1409,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( odm_pipe->stream_res.opp, &stream->bit_depth_params, &stream->clamping); + odm_pipe = odm_pipe->next_odm_pipe; } #endif @@ -1748,7 +1719,8 @@ void dce110_set_safe_displaymarks( ******************************************************************************/ static void set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, int vmin, int vmax) + int num_pipes, unsigned int vmin, unsigned int vmax, + unsigned int vmid, unsigned int vmid_frame_number) { int i = 0; struct drr_params params = {0}; @@ -1932,8 +1904,25 @@ static void dce110_reset_hw_ctx_wrap( /* Disable if new stream is null. O/w, if stream is * disabled already, no need to disable again. */ - if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) - core_link_disable_stream(pipe_ctx_old, FREE_ACQUIRED_RESOURCE); + if (!pipe_ctx->stream || !pipe_ctx->stream->dpms_off) { + core_link_disable_stream(pipe_ctx_old); + + /* free acquired resources*/ + if (pipe_ctx_old->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx_old->stream_res.audio->funcs-> + az_disable(pipe_ctx_old->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx_old->stream_res.audio, false); + pipe_ctx_old->stream_res.audio = NULL; + } + } + } pipe_ctx_old->stream_res.tg->funcs->set_blank(pipe_ctx_old->stream_res.tg, true); if (!hwss_wait_for_blank_complete(pipe_ctx_old->stream_res.tg)) { @@ -2098,7 +2087,7 @@ enum dc_status dce110_apply_ctx_to_hw( if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) continue; - if (pipe_ctx->top_pipe) + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) continue; status = apply_single_controller_ctx_to_hw( @@ -2777,9 +2766,9 @@ static const struct hw_sequencer_funcs dce110_funcs = { .setup_stereo = NULL, .set_avmute = dce110_set_avmute, .wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect, - .edp_backlight_control = hwss_edp_backlight_control, - .edp_power_control = hwss_edp_power_control, - .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .set_cursor_position = dce110_set_cursor_position, .set_cursor_attribute = dce110_set_cursor_attribute }; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h index cd3e36d52a52..2f9b7dbdf415 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h @@ -42,7 +42,7 @@ enum dc_status dce110_apply_ctx_to_hw( void dce110_enable_stream(struct pipe_ctx *pipe_ctx); -void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option); +void dce110_disable_stream(struct pipe_ctx *pipe_ctx); void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); @@ -50,7 +50,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx, void dce110_blank_stream(struct pipe_ctx *pipe_ctx); void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx); -void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx, int option); +void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx); void dce110_update_info_frame(struct pipe_ctx *pipe_ctx); @@ -73,15 +73,15 @@ void dce110_optimize_bandwidth( void dp_receiver_power_ctrl(struct dc_link *link, bool on); -void hwss_edp_power_control( +void dce110_edp_power_control( struct dc_link *link, bool power_up); -void hwss_edp_backlight_control( +void dce110_edp_backlight_control( struct dc_link *link, bool enable); -void hwss_edp_wait_for_hpd_ready( +void dce110_edp_wait_for_hpd_ready( struct dc_link *link, bool power_up); diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index 9b9fc3d96c07..d54172d88f5f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -229,26 +229,26 @@ static void program_tiling( static void program_size_and_rotation( struct dce_mem_input *mem_input110, enum dc_rotation_angle rotation, - const union plane_size *plane_size) + const struct plane_size *plane_size) { uint32_t value = 0; - union plane_size local_size = *plane_size; + struct plane_size local_size = *plane_size; if (rotation == ROTATION_ANGLE_90 || rotation == ROTATION_ANGLE_270) { - swap(local_size.video.luma_size.x, - local_size.video.luma_size.y); - swap(local_size.video.luma_size.width, - local_size.video.luma_size.height); - swap(local_size.video.chroma_size.x, - local_size.video.chroma_size.y); - swap(local_size.video.chroma_size.width, - local_size.video.chroma_size.height); + swap(local_size.surface_size.x, + local_size.surface_size.y); + swap(local_size.surface_size.width, + local_size.surface_size.height); + swap(local_size.chroma_size.x, + local_size.chroma_size.y); + swap(local_size.chroma_size.width, + local_size.chroma_size.height); } value = 0; - set_reg_field_value(value, local_size.video.luma_pitch, + set_reg_field_value(value, local_size.surface_pitch, UNP_GRPH_PITCH_L, GRPH_PITCH_L); dm_write_reg( @@ -257,7 +257,7 @@ static void program_size_and_rotation( value); value = 0; - set_reg_field_value(value, local_size.video.chroma_pitch, + set_reg_field_value(value, local_size.chroma_pitch, UNP_GRPH_PITCH_C, GRPH_PITCH_C); dm_write_reg( mem_input110->base.ctx, @@ -297,8 +297,8 @@ static void program_size_and_rotation( value); value = 0; - set_reg_field_value(value, local_size.video.luma_size.x + - local_size.video.luma_size.width, + set_reg_field_value(value, local_size.surface_size.x + + local_size.surface_size.width, UNP_GRPH_X_END_L, GRPH_X_END_L); dm_write_reg( mem_input110->base.ctx, @@ -306,8 +306,8 @@ static void program_size_and_rotation( value); value = 0; - set_reg_field_value(value, local_size.video.chroma_size.x + - local_size.video.chroma_size.width, + set_reg_field_value(value, local_size.chroma_size.x + + local_size.chroma_size.width, UNP_GRPH_X_END_C, GRPH_X_END_C); dm_write_reg( mem_input110->base.ctx, @@ -315,8 +315,8 @@ static void program_size_and_rotation( value); value = 0; - set_reg_field_value(value, local_size.video.luma_size.y + - local_size.video.luma_size.height, + set_reg_field_value(value, local_size.surface_size.y + + local_size.surface_size.height, UNP_GRPH_Y_END_L, GRPH_Y_END_L); dm_write_reg( mem_input110->base.ctx, @@ -324,8 +324,8 @@ static void program_size_and_rotation( value); value = 0; - set_reg_field_value(value, local_size.video.chroma_size.y + - local_size.video.chroma_size.height, + set_reg_field_value(value, local_size.chroma_size.y + + local_size.chroma_size.height, UNP_GRPH_Y_END_C, GRPH_Y_END_C); dm_write_reg( mem_input110->base.ctx, @@ -637,7 +637,7 @@ void dce_mem_input_v_program_surface_config( struct mem_input *mem_input, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizotal_mirror) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c index 764329264c3b..c66fe170e1e8 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c @@ -331,7 +331,7 @@ static const struct dce_audio_shift audio_shift = { AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -1274,7 +1274,6 @@ static bool construct( { unsigned int i; struct dc_context *ctx = dc->ctx; - struct dc_firmware_info info; struct dc_bios *bp; ctx->dc_bios->regs = &bios_regs; @@ -1300,8 +1299,7 @@ static bool construct( bp = ctx->dc_bios; - if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) && - info.external_clock_source_frequency_for_dp != 0) { + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { pool->base.dp_clock_source = dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c index c6136e0ed1a4..3ac4c7e73050 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c @@ -337,7 +337,7 @@ static const struct dce_audio_shift audio_shift = { AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { AUD_COMMON_MASK_SH_LIST(_MASK) }; 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 4a6ba3173a5a..7d08154e9662 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c @@ -352,7 +352,7 @@ static const struct dce_audio_shift audio_shift = { DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) }; diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c index 860a524ebcfa..4625df9f9fd2 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c @@ -322,7 +322,7 @@ static const struct dce_audio_shift audio_shift = { AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -876,7 +876,6 @@ static bool dce80_construct( { unsigned int i; struct dc_context *ctx = dc->ctx; - struct dc_firmware_info info; struct dc_bios *bp; ctx->dc_bios->regs = &bios_regs; @@ -902,8 +901,7 @@ static bool dce80_construct( bp = ctx->dc_bios; - if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) && - info.external_clock_source_frequency_for_dp != 0) { + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { pool->base.dp_clock_source = dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); @@ -1075,7 +1073,6 @@ static bool dce81_construct( { unsigned int i; struct dc_context *ctx = dc->ctx; - struct dc_firmware_info info; struct dc_bios *bp; ctx->dc_bios->regs = &bios_regs; @@ -1101,8 +1098,7 @@ static bool dce81_construct( bp = ctx->dc_bios; - if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) && - info.external_clock_source_frequency_for_dp != 0) { + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { pool->base.dp_clock_source = dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); @@ -1274,7 +1270,6 @@ static bool dce83_construct( { unsigned int i; struct dc_context *ctx = dc->ctx; - struct dc_firmware_info info; struct dc_bios *bp; ctx->dc_bios->regs = &bios_regs; @@ -1300,8 +1295,7 @@ static bool dce83_construct( bp = ctx->dc_bios; - if ((bp->funcs->get_firmware_info(bp, &info) == BP_RESULT_OK) && - info.external_clock_source_frequency_for_dp != 0) { + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { pool->base.dp_clock_source = dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c index 7469333a2c8a..01c7e30b9ce1 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -343,8 +343,8 @@ bool cm_helper_translate_curve_to_hw_format( region_start = -MAX_LOW_POINT; region_end = NUMBER_REGIONS - MAX_LOW_POINT; } else { - /* 10 segments - * segment is from 2^-10 to 2^0 + /* 11 segments + * segment is from 2^-10 to 2^1 * There are less than 256 points, for optimization */ seg_distr[0] = 3; @@ -357,9 +357,10 @@ bool cm_helper_translate_curve_to_hw_format( seg_distr[7] = 4; seg_distr[8] = 4; seg_distr[9] = 4; + seg_distr[10] = 1; region_start = -10; - region_end = 0; + region_end = 1; } for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) 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 b95ec73fcae3..d8b2da18db39 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -426,8 +426,9 @@ void dpp1_cnv_setup ( void dpp1_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format) + struct dc_cursor_attributes *cursor_attributes) { + enum dc_cursor_color_format color_format = cursor_attributes->color_format; struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); REG_UPDATE_2(CURSOR0_CONTROL, @@ -456,6 +457,19 @@ void dpp1_set_cursor_position( int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y; uint32_t cur_en = pos->enable ? 1 : 0; + // Cursor width/height and hotspots need to be rotated for offset calculation + if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) { + swap(width, height); + if (param->rotation == ROTATION_ANGLE_90) { + src_x_offset = pos->x - pos->y_hotspot - param->viewport.x; + src_y_offset = pos->y - pos->x_hotspot - param->viewport.y; + } + } else if (param->rotation == ROTATION_ANGLE_180) { + src_x_offset = pos->x - param->viewport.x; + src_y_offset = pos->y - param->viewport.y; + } + + if (src_x_offset >= (int)param->viewport.width) cur_en = 0; /* not visible beyond right edge*/ 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 8a5517eebb7c..e2c613611ac9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -1368,7 +1368,7 @@ enum dcn10_input_csc_select { void dpp1_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format); + struct dc_cursor_attributes *cursor_attributes); void dpp1_set_cursor_position( struct dpp *dpp_base, 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 a780057e2dbc..a02c10e23e0d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -104,7 +104,7 @@ void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow) DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, !allow); } -bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubbub) +bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubbub) { struct dcn10_hubbub *hubbub1 = TO_DCN10_HUBBUB(hubbub); uint32_t enable = 0; @@ -945,6 +945,8 @@ static const struct hubbub_funcs hubbub1_funcs = { .get_dcc_compression_cap = hubbub1_get_dcc_compression_cap, .wm_read_state = hubbub1_wm_read_state, .program_watermarks = hubbub1_program_watermarks, + .is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled, + .allow_self_refresh_control = hubbub1_allow_self_refresh_control, }; void hubbub1_construct(struct hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h index 7c2559c9ae23..69d903d68661 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -119,6 +119,28 @@ struct dcn_hubbub_registers { uint32_t DCN_VM_AGP_BOT; uint32_t DCN_VM_AGP_TOP; uint32_t DCN_VM_AGP_BASE; + uint32_t DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB; + uint32_t DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_A; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_B; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_C; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_NOM_D; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C; + uint32_t DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D; + uint32_t DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A; + uint32_t DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B; + uint32_t DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C; + uint32_t DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D; + uint32_t DCHUBBUB_ARB_HOSTVM_CNTL; + uint32_t DCHVM_CTRL0; + uint32_t DCHVM_MEM_CTRL; + uint32_t DCHVM_CLK_CTRL; + uint32_t DCHVM_RIOMMU_CTRL0; + uint32_t DCHVM_RIOMMU_STAT0; +#endif }; /* set field name */ @@ -196,7 +218,9 @@ struct dcn_hubbub_registers { type DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A;\ type DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B;\ type DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C;\ - type DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D + type DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D;\ + type DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB;\ + type DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB #define HUBBUB_STUTTER_REG_FIELD_LIST(type) \ type DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A;\ @@ -208,15 +232,68 @@ struct dcn_hubbub_registers { type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C;\ type DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define HUBBUB_HVM_REG_FIELD_LIST(type) \ + type DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD;\ + type DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A;\ + type DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B;\ + type DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C;\ + type DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_B;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_C;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_D;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C;\ + type DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D;\ + type DCHUBBUB_ARB_FRAC_URG_BW_NOM_A;\ + type DCHUBBUB_ARB_FRAC_URG_BW_NOM_B;\ + type DCHUBBUB_ARB_FRAC_URG_BW_NOM_C;\ + type DCHUBBUB_ARB_FRAC_URG_BW_NOM_D;\ + type DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A;\ + type DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B;\ + type DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C;\ + type DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D;\ + type DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A;\ + type DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B;\ + type DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C;\ + type DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D;\ + type DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD;\ + type HOSTVM_INIT_REQ; \ + type HVM_GPUVMRET_PWR_REQ_DIS; \ + type HVM_GPUVMRET_FORCE_REQ; \ + type HVM_GPUVMRET_POWER_STATUS; \ + type HVM_DISPCLK_R_GATE_DIS; \ + type HVM_DISPCLK_G_GATE_DIS; \ + type HVM_DCFCLK_R_GATE_DIS; \ + type HVM_DCFCLK_G_GATE_DIS; \ + type TR_REQ_REQCLKREQ_MODE; \ + type TW_RSP_COMPCLKREQ_MODE; \ + type HOSTVM_PREFETCH_REQ; \ + type HOSTVM_POWERSTATUS; \ + type RIOMMU_ACTIVE; \ + type HOSTVM_PREFETCH_DONE +#endif struct dcn_hubbub_shift { DCN_HUBBUB_REG_FIELD_LIST(uint8_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint8_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + HUBBUB_HVM_REG_FIELD_LIST(uint8_t); +#endif }; struct dcn_hubbub_mask { DCN_HUBBUB_REG_FIELD_LIST(uint32_t); HUBBUB_STUTTER_REG_FIELD_LIST(uint32_t); +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + HUBBUB_HVM_REG_FIELD_LIST(uint32_t); +#endif }; struct dc; @@ -247,7 +324,7 @@ void hubbub1_program_watermarks( void hubbub1_allow_self_refresh_control(struct hubbub *hubbub, bool allow); -bool hububu1_is_allow_self_refresh_enabled(struct hubbub *hubub); +bool hubbub1_is_allow_self_refresh_enabled(struct hubbub *hubub); void hubbub1_toggle_watermark_change_req( struct hubbub *hubbub); 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 934bacc0c6ad..001db49e4bb2 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -163,7 +163,7 @@ void hubp1_program_tiling( void hubp1_program_size( struct hubp *hubp, enum surface_pixel_format format, - const union plane_size *plane_size, + const struct plane_size *plane_size, struct dc_plane_dcc_param *dcc) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); @@ -173,16 +173,16 @@ void hubp1_program_size( * 444 or 420 luma */ if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END) { - ASSERT(plane_size->video.chroma_pitch != 0); + ASSERT(plane_size->chroma_pitch != 0); /* Chroma pitch zero can cause system hang! */ - pitch = plane_size->video.luma_pitch - 1; - meta_pitch = dcc->video.meta_pitch_l - 1; - pitch_c = plane_size->video.chroma_pitch - 1; - meta_pitch_c = dcc->video.meta_pitch_c - 1; + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; + pitch_c = plane_size->chroma_pitch - 1; + meta_pitch_c = dcc->meta_pitch_c - 1; } else { - pitch = plane_size->grph.surface_pitch - 1; - meta_pitch = dcc->grph.meta_pitch - 1; + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; pitch_c = 0; meta_pitch_c = 0; } @@ -509,7 +509,7 @@ bool hubp1_program_surface_flip_and_addr( } void hubp1_dcc_control(struct hubp *hubp, bool enable, - bool independent_64b_blks) + enum hubp_ind_block_size independent_64b_blks) { uint32_t dcc_en = enable ? 1 : 0; uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0; @@ -526,13 +526,13 @@ void hubp1_program_surface_config( struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, unsigned int compat_level) { - hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); + hubp1_dcc_control(hubp, dcc->enable, dcc->independent_64b_blks); hubp1_program_tiling(hubp, tiling_info, format); hubp1_program_size(hubp, format, plane_size, dcc); hubp1_program_rotation(hubp, rotation, horizontal_mirror); @@ -843,7 +843,7 @@ void min_set_viewport( PRI_VIEWPORT_Y_START_C, viewport_c->y); } -void hubp1_read_state(struct hubp *hubp) +void hubp1_read_state_common(struct hubp *hubp) { struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); struct dcn_hubp_state *s = &hubp1->state; @@ -859,24 +859,6 @@ void hubp1_read_state(struct hubp *hubp) PRQ_EXPANSION_MODE, &rq_regs->prq_expansion_mode, MRQ_EXPANSION_MODE, &rq_regs->mrq_expansion_mode, CRQ_EXPANSION_MODE, &rq_regs->crq_expansion_mode); - REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, - CHUNK_SIZE, &rq_regs->rq_regs_l.chunk_size, - MIN_CHUNK_SIZE, &rq_regs->rq_regs_l.min_chunk_size, - META_CHUNK_SIZE, &rq_regs->rq_regs_l.meta_chunk_size, - MIN_META_CHUNK_SIZE, &rq_regs->rq_regs_l.min_meta_chunk_size, - DPTE_GROUP_SIZE, &rq_regs->rq_regs_l.dpte_group_size, - MPTE_GROUP_SIZE, &rq_regs->rq_regs_l.mpte_group_size, - SWATH_HEIGHT, &rq_regs->rq_regs_l.swath_height, - PTE_ROW_HEIGHT_LINEAR, &rq_regs->rq_regs_l.pte_row_height_linear); - REG_GET_8(DCHUBP_REQ_SIZE_CONFIG_C, - CHUNK_SIZE_C, &rq_regs->rq_regs_c.chunk_size, - MIN_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_chunk_size, - META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.meta_chunk_size, - MIN_META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_meta_chunk_size, - DPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.dpte_group_size, - MPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.mpte_group_size, - SWATH_HEIGHT_C, &rq_regs->rq_regs_c.swath_height, - PTE_ROW_HEIGHT_LINEAR_C, &rq_regs->rq_regs_c.pte_row_height_linear); /* DLG - Per hubp */ REG_GET_2(BLANK_OFFSET_0, @@ -1030,8 +1012,38 @@ void hubp1_read_state(struct hubp *hubp) REG_GET_2(DCN_TTU_QOS_WM, QoS_LEVEL_LOW_WM, &s->qos_level_low_wm, QoS_LEVEL_HIGH_WM, &s->qos_level_high_wm); + } +void hubp1_read_state(struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + struct dcn_hubp_state *s = &hubp1->state; + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + hubp1_read_state_common(hubp); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, + CHUNK_SIZE, &rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, &rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, &rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, &rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, &rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, &rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, &rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, &rq_regs->rq_regs_l.pte_row_height_linear); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG_C, + CHUNK_SIZE_C, &rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, &rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, &rq_regs->rq_regs_c.pte_row_height_linear); + +} enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch) { enum cursor_pitch hw_pitch; 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 31c8fdd3206c..cb20d10288c0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -125,8 +125,6 @@ SRI(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, HUBPREQ, id),\ SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, HUBPREQ, id),\ SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, HUBPREQ, id),\ - SR(DCHUBBUB_SDPIF_FB_BASE),\ - SR(DCHUBBUB_SDPIF_FB_OFFSET),\ SRI(CURSOR_SETTINS, HUBPREQ, id), \ SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR, id), \ SRI(CURSOR_SURFACE_ADDRESS, CURSOR, id), \ @@ -226,14 +224,6 @@ uint32_t DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB; \ uint32_t DCN_VM_SYSTEM_APERTURE_LOW_ADDR; \ uint32_t DCN_VM_SYSTEM_APERTURE_HIGH_ADDR; \ - uint32_t DCHUBBUB_SDPIF_FB_BASE; \ - uint32_t DCHUBBUB_SDPIF_FB_OFFSET; \ - uint32_t DCN_VM_FB_LOCATION_TOP; \ - uint32_t DCN_VM_FB_LOCATION_BASE; \ - uint32_t DCN_VM_FB_OFFSET; \ - uint32_t DCN_VM_AGP_BASE; \ - uint32_t DCN_VM_AGP_BOT; \ - uint32_t DCN_VM_AGP_TOP; \ uint32_t CURSOR_SETTINS; \ uint32_t CURSOR_SETTINGS; \ uint32_t CURSOR_SURFACE_ADDRESS_HIGH; \ @@ -249,7 +239,8 @@ .field_name = reg_name ## __ ## field_name ## post_fix /* Mask/shift struct generation macro for all ASICs (including those with reduced functionality) */ -#define HUBP_MASK_SH_LIST_DCN_COMMON(mask_sh)\ +/*1.x, 2.x, and 3.x*/ +#define HUBP_MASK_SH_LIST_DCN_SHARE_COMMON(mask_sh)\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ @@ -265,7 +256,6 @@ HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, MAX_COMPRESSED_FRAGS, mask_sh),\ HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, SW_MODE, mask_sh),\ HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, META_LINEAR, mask_sh),\ - HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh),\ HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, PIPE_ALIGNED, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH, mask_sh),\ HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, META_PITCH, mask_sh),\ @@ -372,12 +362,17 @@ HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_RAMP_DISABLE, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL1, REFCYC_PER_REQ_DELIVERY_PRE, mask_sh),\ HUBP_SF(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, mask_sh) - -#define HUBP_MASK_SH_LIST_DCN(mask_sh)\ - HUBP_MASK_SH_LIST_DCN_COMMON(mask_sh),\ +/*2.x and 1.x only*/ +#define HUBP_MASK_SH_LIST_DCN_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN_SHARE_COMMON(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MPTE_GROUP_SIZE, mask_sh),\ HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MPTE_GROUP_SIZE_C, mask_sh) +/*2.x and 1.x only*/ +#define HUBP_MASK_SH_LIST_DCN(mask_sh)\ + HUBP_MASK_SH_LIST_DCN_COMMON(mask_sh) + /* Mask/shift struct generation macro for ASICs with VM */ #define HUBP_MASK_SH_LIST_DCN_VM(mask_sh)\ HUBP_SF(HUBPREQ0_NOM_PARAMETERS_0, DST_Y_PER_PTE_ROW_NOM_L, mask_sh),\ @@ -412,8 +407,6 @@ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, MC_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, mask_sh),\ - HUBP_SF(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh),\ - HUBP_SF(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mask_sh),\ HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mask_sh),\ @@ -434,7 +427,7 @@ HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) -#define DCN_HUBP_REG_FIELD_LIST(type) \ +#define DCN_HUBP_REG_FIELD_BASE_LIST(type) \ type HUBP_BLANK_EN;\ type HUBP_DISABLE;\ type HUBP_TTU_DISABLE;\ @@ -459,7 +452,6 @@ 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;\ @@ -589,18 +581,6 @@ type MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB;\ type MC_VM_SYSTEM_APERTURE_LOW_ADDR;\ type MC_VM_SYSTEM_APERTURE_HIGH_ADDR;\ - type SDPIF_FB_TOP;\ - type SDPIF_FB_BASE;\ - type SDPIF_FB_OFFSET;\ - type SDPIF_AGP_BASE;\ - type SDPIF_AGP_BOT;\ - type SDPIF_AGP_TOP;\ - type FB_TOP;\ - type FB_BASE;\ - type FB_OFFSET;\ - type AGP_BASE;\ - type AGP_BOT;\ - type AGP_TOP;\ type DCN_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM;\ type DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB;\ type DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB;\ @@ -632,6 +612,10 @@ type CURSOR_DST_X_OFFSET; \ type OUTPUT_FP +#define DCN_HUBP_REG_FIELD_LIST(type) \ + DCN_HUBP_REG_FIELD_BASE_LIST(type);\ + type ALPHA_PLANE_EN + struct dcn_mi_registers { HUBP_COMMON_REG_VARIABLE_LIST; }; @@ -677,7 +661,7 @@ void hubp1_program_surface_config( struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, @@ -699,7 +683,7 @@ void hubp1_program_pixel_format( void hubp1_program_size( struct hubp *hubp, enum surface_pixel_format format, - const union plane_size *plane_size, + const struct plane_size *plane_size, struct dc_plane_dcc_param *dcc); void hubp1_program_rotation( @@ -714,7 +698,7 @@ void hubp1_program_tiling( void hubp1_dcc_control(struct hubp *hubp, bool enable, - bool independent_64b_blks); + enum hubp_ind_block_size independent_64b_blks); #ifdef CONFIG_DRM_AMD_DC_DCN2_0 bool hubp1_program_surface_flip_and_addr( @@ -760,5 +744,6 @@ void hubp1_vready_workaround(struct hubp *hubp, struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest); void hubp1_init(struct hubp *hubp); +void hubp1_read_state_common(struct hubp *hubp); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 2118ea21d7e9..60123db7ba02 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 @@ -438,7 +438,7 @@ bool dcn10_did_underflow_occur(struct dc *dc, struct pipe_ctx *pipe_ctx) return false; } -static void enable_power_gating_plane( +static void dcn10_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -460,7 +460,7 @@ static void enable_power_gating_plane( REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); } -static void disable_vga( +static void dcn10_disable_vga( struct dce_hwseq *hws) { unsigned int in_vga1_mode = 0; @@ -493,7 +493,7 @@ static void disable_vga( REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1); } -static void dpp_pg_control( +static void dcn10_dpp_pg_control( struct dce_hwseq *hws, unsigned int dpp_inst, bool power_on) @@ -545,7 +545,7 @@ static void dpp_pg_control( } } -static void hubp_pg_control( +static void dcn10_hubp_pg_control( struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -605,8 +605,8 @@ static void power_on_plane( if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, plane_id, true); - hubp_pg_control(hws, plane_id, true); + hws->ctx->dc->hwss.dpp_pg_control(hws, plane_id, true); + hws->ctx->dc->hwss.hubp_pg_control(hws, plane_id, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); DC_LOG_DEBUG( @@ -627,7 +627,7 @@ static void undo_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hubp_pg_control(hws, 0, false); + dc->hwss.hubp_pg_control(hws, 0, false); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -656,7 +656,7 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - hubp_pg_control(hws, 0, true); + dc->hwss.hubp_pg_control(hws, 0, true); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -664,10 +664,23 @@ static void apply_DEGVIDCN10_253_wa(struct dc *dc) hws->wa_state.DEGVIDCN10_253_applied = true; } -static void bios_golden_init(struct dc *dc) +static void dcn10_bios_golden_init(struct dc *dc) { struct dc_bios *bp = dc->ctx->dc_bios; int i; + bool allow_self_fresh_force_enable = true; + + if (dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled) + allow_self_fresh_force_enable = + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub); + + + /* WA for making DF sleep when idle after resume from S0i3. + * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by + * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 + * before calling command table and it changed to 1 after, + * it should be set back to 0. + */ /* initialize dcn global */ bp->funcs->enable_disp_power_gating(bp, @@ -678,6 +691,12 @@ static void bios_golden_init(struct dc *dc) bp->funcs->enable_disp_power_gating(bp, CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); } + + if (dc->res_pool->hubbub->funcs->allow_self_refresh_control) + if (allow_self_fresh_force_enable == false && + dc->res_pool->hubbub->funcs->is_allow_self_refresh_enabled(dc->res_pool->hubbub)) + dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub, true); + } static void false_optc_underflow_wa( @@ -702,7 +721,8 @@ static void false_optc_underflow_wa( dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); } - tg->funcs->set_blank_data_double_buffer(tg, true); + if (tg->funcs->set_blank_data_double_buffer) + tg->funcs->set_blank_data_double_buffer(tg, true); if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) tg->funcs->clear_optc_underflow(tg); @@ -808,11 +828,23 @@ static void dcn10_reset_back_end_for_pipe( 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); + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } } - } /* by upper caller loop, parent pipe: pipe0, will be reset last. @@ -823,6 +855,9 @@ static void dcn10_reset_back_end_for_pipe( 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_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); } for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -968,7 +1003,7 @@ void hwss1_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) dcn10_verify_allow_pstate_change_high(dc); } -static void plane_atomic_power_down(struct dc *dc, +static void dcn10_plane_atomic_power_down(struct dc *dc, struct dpp *dpp, struct hubp *hubp) { @@ -978,8 +1013,8 @@ static void plane_atomic_power_down(struct dc *dc, if (REG(DC_IP_REQUEST_CNTL)) { REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - dpp_pg_control(hws, dpp->inst, false); - hubp_pg_control(hws, hubp->inst, false); + dc->hwss.dpp_pg_control(hws, dpp->inst, false); + dc->hwss.hubp_pg_control(hws, hubp->inst, false); dpp->funcs->dpp_reset(dpp); REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0); @@ -991,7 +1026,7 @@ static void plane_atomic_power_down(struct dc *dc, /* disable HW used by plane. * note: cannot disable until disconnect is complete */ -static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +static void dcn10_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; @@ -1011,7 +1046,7 @@ static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - plane_atomic_power_down(dc, + dc->hwss.plane_atomic_power_down(dc, pipe_ctx->plane_res.dpp, pipe_ctx->plane_res.hubp); @@ -1030,7 +1065,7 @@ static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated) return; - plane_atomic_disable(dc, pipe_ctx); + dc->hwss.plane_atomic_disable(dc, pipe_ctx); apply_DEGVIDCN10_253_wa(dc); @@ -1065,15 +1100,27 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) * command table. */ if (tg->funcs->is_tg_enabled(tg)) { - tg->funcs->lock(tg); - tg->funcs->set_blank(tg, true); - hwss_wait_for_blank_complete(tg); + if (dc->hwss.init_blank != NULL) { + dc->hwss.init_blank(dc, tg); + tg->funcs->lock(tg); + } else { + tg->funcs->lock(tg); + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } } } - /* Cannot reset the MPC mux if seamless boot */ - if (!can_apply_seamless_boot) - dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + /* Cannot reset the MPC mux if seamless boot */ + if (pipe_ctx->stream != NULL && can_apply_seamless_boot) + continue; + + dc->res_pool->mpc->funcs->mpc_init_single_inst( + dc->res_pool->mpc, i); + } for (i = 0; i < dc->res_pool->pipe_count; i++) { struct timing_generator *tg = dc->res_pool->timing_generators[i]; @@ -1111,12 +1158,12 @@ static void dcn10_init_pipes(struct dc *dc, struct dc_state *context) 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]; - hwss1_plane_atomic_disconnect(dc, pipe_ctx); + dc->hwss.plane_atomic_disconnect(dc, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - dcn10_disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; @@ -1132,8 +1179,17 @@ static void dcn10_init_hw(struct dc *dc) 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; + + if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) + dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); + + // Initialize the dccg + if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->dccg_init) + dc->res_pool->dccg->funcs->dccg_init(res_pool->dccg); if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(REFCLK_CNTL, 0); REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); REG_WRITE(DIO_MEM_PWR_CTRL, 0); @@ -1147,31 +1203,40 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - enable_power_gating_plane(dc->hwseq, true); + //Enable ability to power gate / don't force power on permanently + dc->hwss.enable_power_gating_plane(hws, true); - /* end of FPGA. Below if real ASIC */ return; } - if (!dcb->funcs->is_accelerated_mode(dcb)) { - bool allow_self_fresh_force_enable = - hububu1_is_allow_self_refresh_enabled( - dc->res_pool->hubbub); + if (!dcb->funcs->is_accelerated_mode(dcb)) + dc->hwss.disable_vga(dc->hwseq); - bios_golden_init(dc); + dc->hwss.bios_golden_init(dc); + if (dc->ctx->dc_bios->fw_info_valid) { + res_pool->ref_clocks.xtalin_clock_inKhz = + dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency; - /* WA for making DF sleep when idle after resume from S0i3. - * DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE is set to 1 by - * command table, if DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE = 0 - * before calling command table and it changed to 1 after, - * it should be set back to 0. - */ - if (allow_self_fresh_force_enable == false && - hububu1_is_allow_self_refresh_enabled(dc->res_pool->hubbub)) - hubbub1_allow_self_refresh_control(dc->res_pool->hubbub, true); + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + if (res_pool->dccg && res_pool->hubbub) { - disable_vga(dc->hwseq); - } + (res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg, + dc->ctx->dc_bios->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); for (i = 0; i < dc->link_count; i++) { /* Power up AND update implementation according to the @@ -1188,6 +1253,13 @@ static void dcn10_init_hw(struct dc *dc) link->link_status.link_active = true; } + /* Power gate DSCs */ +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + for (i = 0; i < res_pool->res_cap->num_dsc; i++) + if (dc->hwss.dsc_pg_control != NULL) + dc->hwss.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); +#endif + /* If taking control over from VBIOS, we may want to optimize our first * mode set, so we need to skip powering down pipes until we know which * pipes we want to use. @@ -1198,8 +1270,8 @@ static void dcn10_init_hw(struct dc *dc) dc->hwss.init_pipes(dc, dc->current_state); } - for (i = 0; i < dc->res_pool->audio_count; i++) { - struct audio *audio = dc->res_pool->audios[i]; + for (i = 0; i < res_pool->audio_count; i++) { + struct audio *audio = res_pool->audios[i]; audio->funcs->hw_init(audio); } @@ -1227,9 +1299,7 @@ static void dcn10_init_hw(struct dc *dc) REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); } - enable_power_gating_plane(dc->hwseq, true); - - memset(&dc->clk_mgr->clks, 0, sizeof(dc->clk_mgr->clks)); + dc->hwss.enable_power_gating_plane(dc->hwseq, true); } static void dcn10_reset_hw_ctx_wrap( @@ -1366,6 +1436,34 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, return result; } +#define MAX_NUM_HW_POINTS 0x200 + +static void log_tf(struct dc_context *ctx, + struct dc_transfer_func *tf, uint32_t hw_points_num) +{ + // DC_LOG_GAMMA is default logging of all hw points + // DC_LOG_ALL_GAMMA logs all points, not only hw points + // DC_LOG_ALL_TF_POINTS logs all channels of the tf + int i = 0; + + DC_LOGGER_INIT(ctx->logger); + DC_LOG_GAMMA("Gamma Correction TF"); + DC_LOG_ALL_GAMMA("Logging all tf points..."); + DC_LOG_ALL_TF_CHANNELS("Logging all channels..."); + + for (i = 0; i < hw_points_num; i++) { + DC_LOG_GAMMA("R\t%d\t%llu\n", i, tf->tf_pts.red[i].value); + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu\n", i, tf->tf_pts.green[i].value); + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu\n", i, tf->tf_pts.blue[i].value); + } + + for (i = hw_points_num; i < MAX_NUM_HW_POINTS; i++) { + DC_LOG_ALL_GAMMA("R\t%d\t%llu\n", i, tf->tf_pts.red[i].value); + DC_LOG_ALL_TF_CHANNELS("G\t%d\t%llu\n", i, tf->tf_pts.green[i].value); + DC_LOG_ALL_TF_CHANNELS("B\t%d\t%llu\n", i, tf->tf_pts.blue[i].value); + } +} + static bool dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, const struct dc_stream_state *stream) @@ -1394,6 +1492,13 @@ dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, } else dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); + if (stream != NULL && stream->ctx != NULL && + stream->out_transfer_func != NULL) { + log_tf(stream->ctx, + stream->out_transfer_func, + dpp->regamma_params.hw_points_num); + } + return true; } @@ -1786,7 +1891,7 @@ static void dcn10_enable_plane( } } -static void program_gamut_remap(struct pipe_ctx *pipe_ctx) +static void dcn10_program_gamut_remap(struct pipe_ctx *pipe_ctx) { int i = 0; struct dpp_grph_csc_adjustment adjust; @@ -1804,6 +1909,36 @@ static void program_gamut_remap(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); } + +static bool dcn10_is_rear_mpo_fix_required(struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace) +{ + if (pipe_ctx->plane_state && pipe_ctx->plane_state->layer_index > 0 && is_rgb_cspace(colorspace)) { + if (pipe_ctx->top_pipe) { + struct pipe_ctx *top = pipe_ctx->top_pipe; + + while (top->top_pipe) + top = top->top_pipe; // Traverse to top pipe_ctx + if (top->plane_state && top->plane_state->layer_index == 0) + return true; // Front MPO plane not hidden + } + } + return false; +} + +static void dcn10_set_csc_adjustment_rgb_mpo_fix(struct pipe_ctx *pipe_ctx, uint16_t *matrix) +{ + // Override rear plane RGB bias to fix MPO brightness + uint16_t rgb_bias = matrix[3]; + + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = 0; + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + matrix[3] = rgb_bias; + matrix[7] = rgb_bias; + matrix[11] = rgb_bias; +} + static void dcn10_program_output_csc(struct dc *dc, struct pipe_ctx *pipe_ctx, enum dc_color_space colorspace, @@ -1811,8 +1946,25 @@ static void dcn10_program_output_csc(struct dc *dc, int opp_id) { if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { - if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) - pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) { + + /* MPO is broken with RGB colorspaces when OCSC matrix + * brightness offset >= 0 on DCN1 due to OCSC before MPC + * Blending adds offsets from front + rear to rear plane + * + * Fix is to set RGB bias to 0 on rear plane, top plane + * black value pixels add offset instead of rear + front + */ + + int16_t rgb_bias = matrix[3]; + // matrix[3/7/11] are all the same offset value + + if (rgb_bias > 0 && dcn10_is_rear_mpo_fix_required(pipe_ctx, colorspace)) { + dcn10_set_csc_adjustment_rgb_mpo_fix(pipe_ctx, matrix); + } else { + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + } + } } else { if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); @@ -2132,7 +2284,7 @@ void update_dchubp_dpp( struct hubp *hubp = pipe_ctx->plane_res.hubp; struct dpp *dpp = pipe_ctx->plane_res.dpp; struct dc_plane_state *plane_state = pipe_ctx->plane_state; - union plane_size size = plane_state->plane_size; + struct plane_size size = plane_state->plane_size; unsigned int compat_level = 0; /* depends on DML calculation, DPP clock value may change dynamically */ @@ -2152,7 +2304,8 @@ void update_dchubp_dpp( dc->res_pool->dccg->funcs->update_dpp_dto( dc->res_pool->dccg, dpp->inst, - pipe_ctx->plane_res.bw.dppclk_khz); + pipe_ctx->plane_res.bw.dppclk_khz, + false); else dc->clk_mgr->clks.dppclk_khz = should_divided_by_2 ? dc->clk_mgr->clks.dispclk_khz / 2 : @@ -2178,7 +2331,7 @@ void update_dchubp_dpp( &pipe_ctx->ttu_regs); } - size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; + size.surface_size = pipe_ctx->plane_res.scl_data.viewport; if (plane_state->update_flags.bits.full_update || plane_state->update_flags.bits.bpp_change) @@ -2216,7 +2369,7 @@ void update_dchubp_dpp( if (plane_state->update_flags.bits.full_update) { /*gamut remap*/ - program_gamut_remap(pipe_ctx); + dc->hwss.program_gamut_remap(pipe_ctx); dc->hwss.program_output_csc(dc, pipe_ctx, @@ -2388,7 +2541,7 @@ struct pipe_ctx *find_top_pipe_for_stream( if (pipe_ctx->stream != stream) continue; - if (!pipe_ctx->top_pipe) + if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe) return pipe_ctx; } return NULL; @@ -2453,7 +2606,7 @@ static void dcn10_apply_ctx_for_surface( 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) - dcn10_disable_plane(dc, old_pipe_ctx); + dc->hwss.disable_plane(dc, old_pipe_ctx); } if ((!pipe_ctx->plane_state || @@ -2501,7 +2654,7 @@ static void dcn10_apply_ctx_for_surface( for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) - dcn10_disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); for (i = 0; i < dc->res_pool->pipe_count; i++) if (removed_pipe[i]) { @@ -2593,8 +2746,9 @@ static void dcn10_optimize_bandwidth( dcn10_verify_allow_pstate_change_high(dc); } -static void set_drr(struct pipe_ctx **pipe_ctx, - int num_pipes, int vmin, int vmax) +static void dcn10_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, unsigned int vmin, unsigned int vmax, + unsigned int vmid, unsigned int vmid_frame_number) { int i = 0; struct drr_params params = {0}; @@ -2603,6 +2757,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx, params.vertical_total_max = vmax; params.vertical_total_min = vmin; + params.vertical_total_mid = vmid; + params.vertical_total_mid_frame_num = vmid_frame_number; /* TODO: If multiple pipes are to be supported, you need * some GSL stuff. Static screen triggers may be programmed differently @@ -2618,7 +2774,7 @@ static void set_drr(struct pipe_ctx **pipe_ctx, } } -static void get_position(struct pipe_ctx **pipe_ctx, +static void dcn10_get_position(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position) { @@ -2630,7 +2786,7 @@ static void get_position(struct pipe_ctx **pipe_ctx, pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); } -static void set_static_screen_control(struct pipe_ctx **pipe_ctx, +static void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx, int num_pipes, const struct dc_static_screen_events *events) { unsigned int i; @@ -2692,6 +2848,13 @@ static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) dcn10_config_stereo_parameters(stream, &flags); + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { + if (!dc_set_generic_gpio_for_stereo(true, dc->ctx->gpio_service)) + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); + } else { + dc_set_generic_gpio_for_stereo(false, dc->ctx->gpio_service); + } + pipe_ctx->stream_res.opp->funcs->opp_program_stereo( pipe_ctx->stream_res.opp, flags.PROGRAM_STEREO == 1 ? true:false, @@ -2782,14 +2945,10 @@ static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) { - if (hws->ctx->dc->res_pool->hubbub != NULL) { - struct hubp *hubp = hws->ctx->dc->res_pool->hubps[0]; + struct hubbub *hubbub = hws->ctx->dc->res_pool->hubbub; - if (hubp->funcs->hubp_update_dchub) - hubp->funcs->hubp_update_dchub(hubp, dh_data); - else - hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); - } + /* In DCN, this programming sequence is owned by the hubbub */ + hubbub->funcs->update_dchub(hubbub, dh_data); } static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) @@ -2820,6 +2979,40 @@ static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx) == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) pos_cpy.enable = false; + // Swap axis and mirror horizontally + if (param.rotation == ROTATION_ANGLE_90) { + uint32_t temp_x = pos_cpy.x; + pos_cpy.x = pipe_ctx->plane_res.scl_data.viewport.width - + (pos_cpy.y - pipe_ctx->plane_res.scl_data.viewport.x) + pipe_ctx->plane_res.scl_data.viewport.x; + pos_cpy.y = temp_x; + } + // Swap axis and mirror vertically + else if (param.rotation == ROTATION_ANGLE_270) { + uint32_t temp_y = pos_cpy.y; + if (pos_cpy.x > pipe_ctx->plane_res.scl_data.viewport.height) { + pos_cpy.x = pos_cpy.x - pipe_ctx->plane_res.scl_data.viewport.height; + pos_cpy.y = pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.x; + } else { + pos_cpy.y = 2 * pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.x; + } + pos_cpy.x = temp_y; + } + // Mirror horizontally and vertically + else if (param.rotation == ROTATION_ANGLE_180) { + if (pos_cpy.x >= pipe_ctx->plane_res.scl_data.viewport.width + pipe_ctx->plane_res.scl_data.viewport.x) { + pos_cpy.x = 2 * pipe_ctx->plane_res.scl_data.viewport.width + - pos_cpy.x + 2 * pipe_ctx->plane_res.scl_data.viewport.x; + } else { + uint32_t temp_x = pos_cpy.x; + pos_cpy.x = 2 * pipe_ctx->plane_res.scl_data.viewport.x - pos_cpy.x; + if (temp_x >= pipe_ctx->plane_res.scl_data.viewport.x + (int)hubp->curs_attr.width + || pos_cpy.x <= (int)hubp->curs_attr.width + pipe_ctx->plane_state->src_rect.x) { + pos_cpy.x = temp_x + pipe_ctx->plane_res.scl_data.viewport.width; + } + } + pos_cpy.y = pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y; + } + hubp->funcs->set_cursor_position(hubp, &pos_cpy, ¶m); dpp->funcs->set_cursor_position(dpp, &pos_cpy, ¶m, hubp->curs_attr.width, hubp->curs_attr.height); } @@ -2831,7 +3024,7 @@ static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx) pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes( pipe_ctx->plane_res.hubp, attributes); pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes( - pipe_ctx->plane_res.dpp, attributes->color_format); + pipe_ctx->plane_res.dpp, attributes); } static void dcn10_set_cursor_sdr_white_level(struct pipe_ctx *pipe_ctx) @@ -3062,9 +3255,59 @@ static void dcn10_send_immediate_sdp_message(struct pipe_ctx *pipe_ctx, sdp_message_size); } } +static enum dc_status dcn10_set_clock(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, + uint32_t stepping) +{ + struct dc_state *context = dc->current_state; + struct dc_clock_config clock_cfg = {0}; + struct dc_clocks *current_clocks = &context->bw_ctx.bw.dcn.clk; + + if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, + context, clock_type, &clock_cfg); + + if (!dc->clk_mgr->funcs->get_clock) + return DC_FAIL_UNSUPPORTED_1; + + if (clk_khz > clock_cfg.max_clock_khz) + return DC_FAIL_CLK_EXCEED_MAX; + + if (clk_khz < clock_cfg.min_clock_khz) + return DC_FAIL_CLK_BELOW_MIN; + + if (clk_khz < clock_cfg.bw_requirequired_clock_khz) + return DC_FAIL_CLK_BELOW_CFG_REQUIRED; + + /*update internal request clock for update clock use*/ + if (clock_type == DC_CLOCK_TYPE_DISPCLK) + current_clocks->dispclk_khz = clk_khz; + else if (clock_type == DC_CLOCK_TYPE_DPPCLK) + current_clocks->dppclk_khz = clk_khz; + else + return DC_ERROR_UNEXPECTED; + + if (dc->clk_mgr && dc->clk_mgr->funcs->update_clocks) + dc->clk_mgr->funcs->update_clocks(dc->clk_mgr, + context, true); + return DC_OK; + +} + +static void dcn10_get_clock(struct dc *dc, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg) +{ + struct dc_state *context = dc->current_state; + + if (dc->clk_mgr && dc->clk_mgr->funcs->get_clock) + dc->clk_mgr->funcs->get_clock(dc->clk_mgr, context, clock_type, clock_cfg); + +} static const struct hw_sequencer_funcs dcn10_funcs = { - .program_gamut_remap = program_gamut_remap, + .program_gamut_remap = dcn10_program_gamut_remap, .init_hw = dcn10_init_hw, .init_pipes = dcn10_init_pipes, .apply_ctx_to_hw = dce110_apply_ctx_to_hw, @@ -3097,18 +3340,18 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .optimize_bandwidth = dcn10_optimize_bandwidth, .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, .enable_stream_timing = dcn10_enable_stream_timing, - .set_drr = set_drr, - .get_position = get_position, - .set_static_screen_control = set_static_screen_control, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, .setup_stereo = dcn10_setup_stereo, .set_avmute = dce110_set_avmute, .log_hw_state = dcn10_log_hw_state, .get_hw_state = dcn10_get_hw_state, .clear_status_bits = dcn10_clear_status_bits, .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = hwss_edp_backlight_control, - .edp_power_control = hwss_edp_power_control, - .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, .set_cursor_position = dcn10_set_cursor_position, .set_cursor_attribute = dcn10_set_cursor_attribute, .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, @@ -3116,7 +3359,18 @@ static const struct hw_sequencer_funcs dcn10_funcs = { .enable_stream_gating = NULL, .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = NULL, + .disable_vga = dcn10_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn10_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn10_enable_power_gating_plane, + .dpp_pg_control = dcn10_dpp_pg_control, + .hubp_pg_control = dcn10_hubp_pg_control, + .dsc_pg_control = NULL, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 6e47444109d7..7f4766e45dff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -45,7 +45,7 @@ #include "dcn10_cm_common.h" #include "clk_mgr.h" -static unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...) +unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...) { unsigned int ret_vsnprintf; unsigned int chars_printed; diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c index 549d423a01f6..1a37c90e9d43 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 @@ -89,6 +89,7 @@ static const struct link_encoder_funcs dcn10_lnk_enc_funcs = { .disable_hpd = dcn10_link_encoder_disable_hpd, .is_dig_enabled = dcn10_is_dig_enabled, .get_dig_frontend = dcn10_get_dig_frontend, + .get_dig_mode = dcn10_get_dig_mode, .destroy = dcn10_link_encoder_destroy }; @@ -446,6 +447,46 @@ static uint8_t get_frontend_source( } } +unsigned int dcn10_get_dig_frontend(struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + int32_t value; + enum engine_id result; + + REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value); + + switch (value) { + case DCN10_DIG_FE_SOURCE_SELECT_DIGA: + result = ENGINE_ID_DIGA; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGB: + result = ENGINE_ID_DIGB; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGC: + result = ENGINE_ID_DIGC; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGD: + result = ENGINE_ID_DIGD; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGE: + result = ENGINE_ID_DIGE; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGF: + result = ENGINE_ID_DIGF; + break; + case DCN10_DIG_FE_SOURCE_SELECT_DIGG: + result = ENGINE_ID_DIGG; + break; + default: + // invalid source select DIG + ASSERT(false); + result = ENGINE_ID_UNKNOWN; + } + + return result; + +} + void enc1_configure_encoder( struct dcn10_link_encoder *enc10, const struct dc_link_settings *link_settings) @@ -501,15 +542,6 @@ bool dcn10_is_dig_enabled(struct link_encoder *enc) return value; } -unsigned int dcn10_get_dig_frontend(struct link_encoder *enc) -{ - struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); - uint32_t value; - - REG_GET(DIG_BE_CNTL, DIG_FE_SOURCE_SELECT, &value); - return value; -} - static void link_encoder_disable(struct dcn10_link_encoder *enc10) { /* reset training pattern */ @@ -1366,3 +1398,25 @@ void dcn10_aux_initialize(struct dcn10_link_encoder *enc10) AUX_REG_UPDATE(AUX_DPHY_RX_CONTROL0, AUX_RX_RECEIVE_WINDOW, 0); } + +enum signal_type dcn10_get_dig_mode( + struct link_encoder *enc) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + uint32_t value; + REG_GET(DIG_BE_CNTL, DIG_MODE, &value); + switch (value) { + case 1: + return SIGNAL_TYPE_DISPLAY_PORT; + case 2: + return SIGNAL_TYPE_DVI_SINGLE_LINK; + case 3: + return SIGNAL_TYPE_HDMI_TYPE_A; + case 5: + return SIGNAL_TYPE_DISPLAY_PORT_MST; + default: + return SIGNAL_TYPE_NONE; + } + return SIGNAL_TYPE_NONE; +} + 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 33b2af1a181c..8bf5f0f2301d 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 @@ -337,6 +337,7 @@ struct dcn10_link_enc_registers { type RDPCS_TX_FIFO_ERROR_MASK;\ type RDPCS_DPALT_DISABLE_TOGGLE_MASK;\ type RDPCS_DPALT_4LANE_TOGGLE_MASK;\ + type RDPCS_PHY_DPALT_DISABLE;\ type RDPCS_PHY_DPALT_DISABLE_ACK;\ type RDPCS_PHY_DP_MPLLB_V2I;\ type RDPCS_PHY_DP_MPLLB_FREQ_VCO;\ @@ -514,4 +515,6 @@ unsigned int dcn10_get_dig_frontend(struct link_encoder *enc); void dcn10_aux_initialize(struct dcn10_link_encoder *enc10); +enum signal_type dcn10_get_dig_mode( + struct link_encoder *enc); #endif /* __DC_LINK_ENCODER__DCN10_H__ */ 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 0bca011ed7c9..8b2f29f6dabd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -211,7 +211,7 @@ struct mpcc *mpc1_insert_plane( } else { new_mpcc->mpcc_bot = NULL; REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); - REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH); + REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY); } REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id); REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id); @@ -364,6 +364,24 @@ void mpc1_mpc_init(struct mpc *mpc) } } +void mpc1_mpc_init_single_inst(struct mpc *mpc, unsigned int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + int opp_id; + + REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id); + + REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf); + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); + REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf); + + mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id); + + if (opp_id < MAX_OPP && REG(MUX[opp_id])) + REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf); +} + + void mpc1_init_mpcc_list_from_hw( struct mpc *mpc, struct mpc_tree *tree) @@ -433,6 +451,7 @@ static const struct mpc_funcs dcn10_mpc_funcs = { .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc1_mpc_init, + .mpc_init_single_inst = mpc1_mpc_init_single_inst, .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp, .wait_for_idle = mpc1_assert_idle_mpcc, .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect, diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h index d3d16c4cbea3..962a68e322ee 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h @@ -149,6 +149,10 @@ void mpc1_remove_mpcc( void mpc1_mpc_init( struct mpc *mpc); +void mpc1_mpc_init_single_inst( + struct mpc *mpc, + unsigned int mpcc_id); + void mpc1_assert_idle_mpcc( struct mpc *mpc, int id); 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 a546c2bc9129..e74a07d03fde 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -154,7 +154,7 @@ void optc1_program_timing( uint32_t h_sync_polarity, v_sync_polarity; uint32_t start_point = 0; uint32_t field_num = 0; - uint32_t h_div_2; + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; struct optc *optc1 = DCN10TG_FROM_TG(optc); @@ -285,10 +285,11 @@ void optc1_program_timing( * of stereo handled in explicit call */ - h_div_2 = optc1_is_two_pixels_per_containter(&patched_crtc_timing); - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_BY2, h_div_2 || optc1->comb_opp_id != 0xf); + if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2) + h_div = H_TIMING_DIV_BY2; + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_BY2, h_div); } void optc1_set_vtg_params(struct timing_generator *optc, @@ -824,6 +825,9 @@ void optc1_program_manual_trigger(struct timing_generator *optc) REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, MANUAL_FLOW_CONTROL, 1); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 0); } @@ -846,6 +850,18 @@ void optc1_set_drr( params->vertical_total_max > 0 && params->vertical_total_min > 0) { + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + REG_SET(OTG_V_TOTAL_MAX, 0, OTG_V_TOTAL_MAX, params->vertical_total_max - 1); @@ -1513,7 +1529,6 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_v_blank_interlace = 5; optc1->min_h_sync_width = 8; optc1->min_v_sync_width = 1; - optc1->comb_opp_id = 0xf; } #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT 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 02599eb92ca6..83575599672e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -54,6 +54,7 @@ SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ SRI(OTG_STEREO_STATUS, OTG, inst),\ SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MID, OTG, inst),\ SRI(OTG_V_TOTAL_MIN, OTG, inst),\ SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ SRI(OTG_TRIGA_CNTL, OTG, inst),\ @@ -125,6 +126,7 @@ struct dcn_optc_registers { uint32_t OTG_3D_STRUCTURE_CONTROL; uint32_t OTG_STEREO_STATUS; uint32_t OTG_V_TOTAL_MAX; + uint32_t OTG_V_TOTAL_MID; uint32_t OTG_V_TOTAL_MIN; uint32_t OTG_V_TOTAL_CONTROL; uint32_t OTG_TRIGA_CNTL; @@ -214,12 +216,15 @@ struct dcn_optc_registers { SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MID, OTG_V_TOTAL_MID, mask_sh),\ SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_FRAME_NUM, mask_sh),\ SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ @@ -348,9 +353,12 @@ struct dcn_optc_registers { type OTG_3D_STRUCTURE_V_UPDATE_MODE;\ type OTG_3D_STRUCTURE_STEREO_SEL_OVR;\ type OTG_V_TOTAL_MAX;\ + type OTG_V_TOTAL_MID;\ type OTG_V_TOTAL_MIN;\ type OTG_V_TOTAL_MIN_SEL;\ type OTG_V_TOTAL_MAX_SEL;\ + type OTG_VTOTAL_MID_REPLACING_MAX_EN;\ + type OTG_VTOTAL_MID_FRAME_NUM;\ type OTG_FORCE_LOCK_ON_EVENT;\ type OTG_SET_V_TOTAL_MIN_MASK_EN;\ type OTG_SET_V_TOTAL_MIN_MASK;\ @@ -494,7 +502,7 @@ struct optc { const struct dcn_optc_shift *tg_shift; const struct dcn_optc_mask *tg_mask; - int comb_opp_id; + int opp_count; uint32_t max_h_total; uint32_t max_v_total; @@ -539,6 +547,10 @@ struct dcn_otg_state { void optc1_read_otg_state(struct optc *optc1, struct dcn_otg_state *s); +bool optc1_is_matching_timing( + struct timing_generator *tg, + const struct dc_crtc_timing *otg_timing); + bool optc1_validate_timing( struct timing_generator *optc, const struct dc_crtc_timing *timing); 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 a12530a3ab9c..5a89e462e7cc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -270,7 +270,7 @@ static const struct dce_audio_shift audio_shift = { DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -1416,6 +1416,14 @@ static bool construct( pool->base.pp_smu = dcn10_pp_smu_create(ctx); + /* + * Right now SMU/PPLIB and DAL all have the AZ D3 force PME notification * + * implemented. So AZ D3 should work.For issue 197007. * + */ + if (pool->base.pp_smu != NULL + && pool->base.pp_smu->rv_funcs.set_pme_wa_enable != NULL) + dc->debug.az_endpoint_mute_only = false; + if (!dc->debug.disable_pplib_clock_request) dcn_bw_update_from_pplib(dc); dcn_bw_sync_calcs_and_dml(dc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c index b9ffbf6b58ff..9aa258f3550b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c @@ -512,11 +512,12 @@ void enc1_stream_encoder_hdmi_set_stream_attribute( enc1_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing); /* setup HDMI engine */ - REG_UPDATE_5(HDMI_CONTROL, + REG_UPDATE_6(HDMI_CONTROL, HDMI_PACKET_GEN_VERSION, 1, HDMI_KEEPOUT_MODE, 1, HDMI_DEEP_COLOR_ENABLE, 0, HDMI_DATA_SCRAMBLE_EN, 0, + HDMI_NO_EXTRA_NULL_PACKET_FILLED, 1, HDMI_CLOCK_CHANNEL_RATE, 0); @@ -1003,6 +1004,19 @@ void enc1_stream_encoder_set_avmute( REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, value); } +void enc1_reset_hdmi_stream_attribute( + struct stream_encoder *enc) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + REG_UPDATE_5(HDMI_CONTROL, + HDMI_PACKET_GEN_VERSION, 1, + HDMI_KEEPOUT_MODE, 1, + HDMI_DEEP_COLOR_ENABLE, 0, + HDMI_DATA_SCRAMBLE_EN, 0, + HDMI_CLOCK_CHANNEL_RATE, 0); +} + #define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000 #define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1 @@ -1196,13 +1210,13 @@ static union audio_cea_channels speakers_to_channels( void get_audio_clock_info( enum dc_color_depth color_depth, - uint32_t crtc_pixel_clock_in_khz, - uint32_t actual_pixel_clock_in_khz, + uint32_t crtc_pixel_clock_100Hz, + uint32_t actual_pixel_clock_100Hz, struct audio_clock_info *audio_clock_info) { const struct audio_clock_info *clock_info; uint32_t index; - uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_in_khz / 10; + uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_100Hz / 100; uint32_t audio_array_size; switch (color_depth) { @@ -1239,16 +1253,16 @@ void get_audio_clock_info( } /* not found */ - if (actual_pixel_clock_in_khz == 0) - actual_pixel_clock_in_khz = crtc_pixel_clock_in_khz; + if (actual_pixel_clock_100Hz == 0) + actual_pixel_clock_100Hz = crtc_pixel_clock_100Hz; /* See HDMI spec the table entry under * pixel clock of "Other". */ audio_clock_info->pixel_clock_in_10khz = - actual_pixel_clock_in_khz / 10; - audio_clock_info->cts_32khz = actual_pixel_clock_in_khz; - audio_clock_info->cts_44khz = actual_pixel_clock_in_khz; - audio_clock_info->cts_48khz = actual_pixel_clock_in_khz; + actual_pixel_clock_100Hz / 100; + audio_clock_info->cts_32khz = actual_pixel_clock_100Hz / 10; + audio_clock_info->cts_44khz = actual_pixel_clock_100Hz / 10; + audio_clock_info->cts_48khz = actual_pixel_clock_100Hz / 10; audio_clock_info->n_32khz = 4096; audio_clock_info->n_44khz = 6272; @@ -1308,14 +1322,14 @@ static void enc1_se_setup_hdmi_audio( /* Program audio clock sample/regeneration parameters */ get_audio_clock_info(crtc_info->color_depth, - crtc_info->requested_pixel_clock, - crtc_info->calculated_pixel_clock, + crtc_info->requested_pixel_clock_100Hz, + crtc_info->calculated_pixel_clock_100Hz, &audio_clock_info); DC_LOG_HW_AUDIO( - "\n%s:Input::requested_pixel_clock = %d" \ - "calculated_pixel_clock = %d \n", __func__, \ - crtc_info->requested_pixel_clock, \ - crtc_info->calculated_pixel_clock); + "\n%s:Input::requested_pixel_clock_100Hz = %d" \ + "calculated_pixel_clock_100Hz = %d \n", __func__, \ + crtc_info->requested_pixel_clock_100Hz, \ + crtc_info->calculated_pixel_clock_100Hz); /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */ REG_UPDATE(HDMI_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz); @@ -1528,6 +1542,17 @@ void enc1_dig_connect_to_otg( REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst); } +unsigned int enc1_dig_source_otg( + struct stream_encoder *enc) +{ + uint32_t tg_inst = 0; + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); + + REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst); + + return tg_inst; +} + static const struct stream_encoder_funcs dcn10_str_enc_funcs = { .dp_set_stream_attribute = enc1_stream_encoder_dp_set_stream_attribute, @@ -1562,6 +1587,8 @@ static const struct stream_encoder_funcs dcn10_str_enc_funcs = { .setup_stereo_sync = enc1_setup_stereo_sync, .set_avmute = enc1_stream_encoder_set_avmute, .dig_connect_to_otg = enc1_dig_connect_to_otg, + .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, + .dig_source_otg = enc1_dig_source_otg, }; void dcn10_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h index bc2b4af9543b..a512cbea00d1 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 @@ -89,7 +89,8 @@ SRI(DP_VID_STREAM_CNTL, DP, id), \ SRI(DP_VID_TIMING, DP, id), \ SRI(DP_SEC_AUD_N, DP, id), \ - SRI(DP_SEC_TIMESTAMP, DP, id) + SRI(DP_SEC_TIMESTAMP, DP, id), \ + SRI(DIG_CLOCK_PATTERN, DIG, id) #define SE_DCN_REG_LIST(id)\ SE_COMMON_DCN_REG_LIST(id) @@ -170,6 +171,7 @@ struct dcn10_stream_enc_registers { uint32_t HDMI_METADATA_PACKET_CONTROL; uint32_t DP_SEC_FRAMING4; #endif + uint32_t DIG_CLOCK_PATTERN; }; @@ -189,6 +191,7 @@ struct dcn10_stream_enc_registers { SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, mask_sh),\ SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, mask_sh),\ SE_SF(DIG0_HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN, mask_sh),\ + SE_SF(DIG0_HDMI_CONTROL, HDMI_NO_EXTRA_NULL_PACKET_FILLED, mask_sh),\ SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, mask_sh),\ SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND, mask_sh),\ SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, mask_sh),\ @@ -297,7 +300,8 @@ struct dcn10_stream_enc_registers { SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_VHEIGHT, mask_sh),\ SE_SF(DIG0_HDMI_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\ SE_SF(DP0_DP_VID_TIMING, DP_VID_N_MUL, mask_sh),\ - SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh) + SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh),\ + SE_SF(DIG0_DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, mask_sh) #define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\ SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh) @@ -374,6 +378,7 @@ struct dcn10_stream_enc_registers { type HDMI_GC_SEND;\ type HDMI_NULL_SEND;\ type HDMI_DATA_SCRAMBLE_EN;\ + type HDMI_NO_EXTRA_NULL_PACKET_FILLED;\ type HDMI_AUDIO_INFO_SEND;\ type AFMT_AUDIO_INFO_UPDATE;\ type HDMI_AUDIO_INFO_LINE;\ @@ -458,7 +463,8 @@ struct dcn10_stream_enc_registers { type HDMI_DB_DISABLE;\ type DP_VID_N_MUL;\ type DP_VID_M_DOUBLE_VALUE_EN;\ - type DIG_SOURCE_SELECT + type DIG_SOURCE_SELECT;\ + type DIG_CLOCK_PATTERN #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #define SE_REG_FIELD_LIST_DCN2_0(type) \ @@ -592,6 +598,9 @@ void enc1_dig_connect_to_otg( struct stream_encoder *enc, int tg_inst); +unsigned int enc1_dig_source_otg( + struct stream_encoder *enc); + void enc1_stream_encoder_set_stream_attribute_helper( struct dcn10_stream_encoder *enc1, struct dc_crtc_timing *crtc_timing); @@ -605,8 +614,11 @@ void enc1_se_enable_dp_audio( void get_audio_clock_info( enum dc_color_depth color_depth, - uint32_t crtc_pixel_clock_in_khz, - uint32_t actual_pixel_clock_in_khz, + uint32_t crtc_pixel_clock_100Hz, + uint32_t actual_pixel_clock_100Hz, struct audio_clock_info *audio_clock_info); +void enc1_reset_hdmi_stream_attribute( + struct stream_encoder *enc); + #endif /* __DC_STREAM_ENCODER_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index e9721a906592..f57a3b281408 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -18,6 +18,10 @@ endif CFLAGS_dcn20_resource.o := -mhard-float -msse $(cc_stack_align) +ifdef CONFIG_CC_IS_CLANG +CFLAGS_dcn20_resource.o += -msse2 +endif + 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 index 31aa6ee5cd5b..16476ed25536 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.c @@ -44,12 +44,16 @@ #define DC_LOGGER \ dccg->ctx->logger -void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) +void dccg2_update_dpp_dto(struct dccg *dccg, + int dpp_inst, + int req_dppclk, + bool reduce_divider_only) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); if (dccg->ref_dppclk && req_dppclk) { int ref_dppclk = dccg->ref_dppclk; + int current_phase, current_modulo; ASSERT(req_dppclk <= ref_dppclk); /* need to clamp to 8 bits */ @@ -61,9 +65,28 @@ void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk) 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_GET_2(DPPCLK_DTO_PARAM[dpp_inst], + DPPCLK0_DTO_PHASE, ¤t_phase, + DPPCLK0_DTO_MODULO, ¤t_modulo); + + if (reduce_divider_only) { + // requested phase/modulo greater than current + if (req_dppclk * current_modulo >= current_phase * ref_dppclk) { + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, req_dppclk, + DPPCLK0_DTO_MODULO, ref_dppclk); + } else { + REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0, + DPPCLK0_DTO_PHASE, current_phase, + DPPCLK0_DTO_MODULO, current_modulo); + } + } else { + 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 { diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index 2205cb0204e7..74a074a873cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -97,7 +97,7 @@ struct dcn_dccg { const struct dccg_mask *dccg_mask; }; -void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk); +void dccg2_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk, bool raise_divider_only); void dccg2_get_dccg_ref_freq(struct dccg *dccg, unsigned int xtalin_freq_inKhz, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c index 9bc5dd23d297..2f5aade1e882 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c @@ -72,6 +72,21 @@ void dpp20_read_state(struct dpp *dpp_base, } } +void dpp2_power_on_obuf( + struct dpp *dpp_base, + bool power_on) +{ + struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); + + REG_UPDATE(CM_MEM_PWR_CTRL, SHARED_MEM_PWR_DIS, power_on == true ? 1:0); + + REG_UPDATE(OBUF_MEM_PWR_CTRL, + OBUF_MEM_PWR_FORCE, power_on == true ? 0:1); + + REG_UPDATE(DSCL_MEM_PWR_CTRL, + LUT_MEM_PWR_FORCE, power_on == true ? 0:1); +} + void dpp2_dummy_program_input_lut( struct dpp *dpp_base, const struct dc_gamma *gamma) @@ -227,6 +242,7 @@ static void dpp2_cnv_setup ( CUR0_ENABLE, 0); } + dpp2_power_on_obuf(dpp_base, true); } @@ -326,14 +342,18 @@ void dpp2_cnv_set_alpha_keyer( void dpp2_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format) + struct dc_cursor_attributes *cursor_attributes) { + enum dc_cursor_color_format color_format = cursor_attributes->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; + color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) { + if (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) { + cur_rom_en = 1; + } + } REG_UPDATE_3(CURSOR0_CONTROL, CUR0_MODE, color_format, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h index 59b67ed57c19..290b2854bd2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.h @@ -162,7 +162,9 @@ 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) + SRI(CURSOR_CONTROL, CURSOR0_, id),\ + SRI(OBUF_MEM_PWR_CTRL, DSCL, id),\ + SRI(DSCL_MEM_PWR_CTRL, DSCL, id) #define TF_REG_LIST_SH_MASK_DCN20(mask_sh)\ TF_REG_LIST_SH_MASK_DCN(mask_sh), \ @@ -554,7 +556,9 @@ 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) + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ROM_EN, mask_sh),\ + TF_SF(DSCL0_OBUF_MEM_PWR_CTRL, OBUF_MEM_PWR_FORCE, mask_sh),\ + TF_SF(DSCL0_DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, mask_sh) #define TF_REG_FIELD_LIST_DCN2_0(type) \ TF_REG_FIELD_LIST(type) \ @@ -585,7 +589,9 @@ type COLOR_KEYER_BLUE_HIGH; \ type CUR0_PIX_INV_MODE; \ type CUR0_PIXEL_ALPHA_MOD_EN; \ - type CUR0_ROM_EN + type CUR0_ROM_EN;\ + type OBUF_MEM_PWR_FORCE;\ + type LUT_MEM_PWR_FORCE struct dcn2_dpp_shift { TF_REG_FIELD_LIST_DCN2_0(uint8_t); @@ -609,7 +615,9 @@ struct dcn2_dpp_mask { uint32_t COLOR_KEYER_ALPHA; \ uint32_t COLOR_KEYER_RED; \ uint32_t COLOR_KEYER_GREEN; \ - uint32_t COLOR_KEYER_BLUE + uint32_t COLOR_KEYER_BLUE; \ + uint32_t OBUF_MEM_PWR_CTRL;\ + uint32_t DSCL_MEM_PWR_CTRL struct dcn2_dpp_registers { DPP_DCN2_REG_VARIABLE_LIST; @@ -668,7 +676,7 @@ void dscl2_calc_lb_num_partitions( void dpp2_set_cursor_attributes( struct dpp *dpp_base, - enum dc_cursor_color_format color_format); + struct dc_cursor_attributes *cursor_attributes); void dpp2_dummy_program_input_lut( struct dpp *dpp_base, @@ -695,4 +703,7 @@ bool dpp2_construct(struct dcn20_dpp *dpp2, const struct dcn2_dpp_shift *tf_shift, const struct dcn2_dpp_mask *tf_mask); +void dpp2_power_on_obuf( + struct dpp *dpp_base, + bool power_on); #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 index e28b8e7bedf5..2d112c316424 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp_cm.c @@ -52,7 +52,12 @@ static void dpp2_enable_cm_block( { struct dcn20_dpp *dpp = TO_DCN20_DPP(dpp_base); - REG_UPDATE(CM_CONTROL, CM_BYPASS, 0); + unsigned int cm_bypass_mode = 0; + //Temp, put CM in bypass mode + if (dpp_base->ctx->dc->debug.cm_in_bypass) + cm_bypass_mode = 1; + + REG_UPDATE(CM_CONTROL, CM_BYPASS, cm_bypass_mode); } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c index ffd0014ec3b5..1b419407af94 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c @@ -29,7 +29,7 @@ #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, +static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals, 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); @@ -42,7 +42,8 @@ static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock 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); + struct dsc_optc_config *dsc_optc_cfg); +static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_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); @@ -51,6 +52,7 @@ const struct dsc_funcs dcn20_dsc_funcs = { .dsc_read_state = dsc2_read_state, .dsc_validate_stream = dsc2_validate_stream, .dsc_set_config = dsc2_set_config, + .dsc_get_packed_pps = dsc2_get_packed_pps, .dsc_enable = dsc2_enable, .dsc_disable = dsc2_disable, }; @@ -116,8 +118,8 @@ static void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock 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_SIMPLE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; @@ -162,40 +164,61 @@ static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_ds static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg) { struct dsc_optc_config dsc_optc_cfg; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - if (dsc_cfg->pic_width > TO_DCN20_DSC(dsc)->max_image_width) + if (dsc_cfg->pic_width > dsc20->max_image_width) return false; - return dsc_prepare_config(dsc, dsc_cfg, &dsc_optc_cfg); + return dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, &dsc_optc_cfg); } -static void dsc_config_log(struct display_stream_compressor *dsc, - const struct dsc_config *config) +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, + DC_LOG_DSC("\tnum_slices_h %d", config->dc_dsc_cfg.num_slices_h); + DC_LOG_DSC("\tnum_slices_v %d", config->dc_dsc_cfg.num_slices_v); + DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", config->dc_dsc_cfg.bits_per_pixel, - config->color_depth); + config->dc_dsc_cfg.bits_per_pixel / 16, + ((config->dc_dsc_cfg.bits_per_pixel % 16) * 10000) / 16); + DC_LOG_DSC("\tcolor_depth %d", 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) + struct dsc_optc_config *dsc_optc_cfg) { bool is_config_ok; struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + DC_LOG_DSC(" "); + DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst); dsc_config_log(dsc, dsc_cfg); - is_config_ok = dsc_prepare_config(dsc, dsc_cfg, dsc_optc_cfg); + is_config_ok = dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, 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); + DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); dsc_log_pps(dsc, &dsc20->reg_vals.pps); dsc_write_to_registers(dsc, &dsc20->reg_vals); } +static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps) +{ + bool is_config_ok; + struct dsc_reg_values dsc_reg_vals; + struct dsc_optc_config dsc_optc_cfg; + + DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); + dsc_config_log(dsc, dsc_cfg); + DC_LOG_DSC("DSC Picture Parameter Set (PPS):"); + is_config_ok = dsc_prepare_config(dsc_cfg, &dsc_reg_vals, &dsc_optc_cfg); + ASSERT(is_config_ok); + drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc_reg_vals.pps); + dsc_log_pps(dsc, &dsc_reg_vals.pps); + + return is_config_ok; +} + + static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) { struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); @@ -232,7 +255,6 @@ static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_co 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); @@ -282,13 +304,11 @@ static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_co } } -static bool dsc_prepare_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, +static bool dsc_prepare_config(const struct dsc_config *dsc_cfg, struct dsc_reg_values *dsc_reg_vals, 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); @@ -302,7 +322,7 @@ static bool dsc_prepare_config(struct display_stream_compressor *dsc, const stru 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 || + if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_h || !(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: @@ -315,54 +335,54 @@ static bool dsc_prepare_config(struct display_stream_compressor *dsc, const stru return false; } - dsc_init_reg_values(&dsc20->reg_vals); + dsc_init_reg_values(dsc_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; + dsc_reg_vals->pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); + dsc_reg_vals->num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_reg_vals->num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; + dsc_reg_vals->pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; + dsc_reg_vals->pps.pic_width = dsc_cfg->pic_width; + dsc_reg_vals->pps.pic_height = dsc_cfg->pic_height; + dsc_reg_vals->pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); + dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; + dsc_reg_vals->pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; + dsc_reg_vals->alternate_ich_encoding_en = dsc_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; + dsc_reg_vals->pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_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)) { + ASSERT(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); + if (!(dsc_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; + dsc_reg_vals->bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; + if (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32; else - dsc20->reg_vals.pps.bits_per_pixel = dsc20->reg_vals.bpp_x32 >> 1; + dsc_reg_vals->pps.bits_per_pixel = dsc_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); + dsc_reg_vals->pps.convert_rgb = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ? 1 : 0; + dsc_reg_vals->pps.native_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); + dsc_reg_vals->pps.native_420 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420); + dsc_reg_vals->pps.simple_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422); - if (dscc_compute_dsc_parameters(&dsc20->reg_vals.pps, &dsc_params)) { + if (dscc_compute_dsc_parameters(&dsc_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_update_from_dsc_parameters(dsc_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; + dsc_optc_cfg->slice_width = dsc_reg_vals->pps.slice_width; + dsc_optc_cfg->is_pixel_format_444 = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB || + dsc_reg_vals->pixel_format == DSC_PIXFMT_YCBCR444 || + dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; return true; } @@ -427,6 +447,8 @@ static void dsc_init_reg_values(struct dsc_reg_values *reg_vals) { int i; + memset(reg_vals, 0, sizeof(struct dsc_reg_values)); + /* Non-PPS values */ reg_vals->dsc_clock_enable = 1; reg_vals->dsc_clock_gating_disable = 0; @@ -436,7 +458,7 @@ static void dsc_init_reg_values(struct dsc_reg_values *reg_vals) 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->disable_ich = 0;*/ reg_vals->dsc_dbg_en = 0; for (i = 0; i < 4; i++) @@ -518,9 +540,11 @@ static void dsc_write_to_registers(struct display_stream_compressor *dsc, const 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, + REG_SET(DSCC_CONFIG1, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size); + /*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); + 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], diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h index 168865a16288..4e2fb38390a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h @@ -103,7 +103,7 @@ 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_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), \ @@ -278,7 +278,7 @@ 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_DISABLE_ICH;*/ \ type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \ type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \ type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c index 6e2dbd03f9bf..b83c022e2c6f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.c @@ -26,6 +26,7 @@ #include "dcn20_hubbub.h" #include "reg_helper.h" +#include "clk_mgr.h" #define REG(reg)\ hubbub1->regs->reg @@ -379,6 +380,11 @@ int hubbub2_init_dchub_sys_ctx(struct hubbub *hubbub, REG_SET(DCN_VM_AGP_BASE, 0, AGP_BASE, pa_config->system_aperture.agp_base >> 24); + REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0, + DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, (pa_config->page_table_default_page_addr >> 44) & 0xF); + REG_SET(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0, + DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, (pa_config->page_table_default_page_addr >> 12) & 0xFFFFFFFF); + if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) { 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; @@ -397,54 +403,67 @@ void hubbub2_update_dchub(struct hubbub *hubbub, { struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); - if (REG(DCHUBBUB_SDPIF_FB_TOP) == 0) { - ASSERT(false); - /*should not come here*/ + if (REG(DCN_VM_FB_LOCATION_TOP) == 0) 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); + 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)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, - SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + /*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); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, - SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + /*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); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, - SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + - dh_data->zfb_size_in_byte - 1) >> 22); + /*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 (done by VBIOS on AsicInit table)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, - SDPIF_AGP_BASE, 0); + /*Should not touch FB LOCATION (should be done by VBIOS)*/ - REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, - SDPIF_AGP_BOT, 0X03FFFF); + /*This field defines the 24 MSBs, bits [47:24] of the 48 bit AGP Base*/ + REG_UPDATE(DCN_VM_AGP_BASE, + AGP_BASE, 0); - REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, - SDPIF_AGP_TOP, 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; @@ -553,6 +572,16 @@ static void hubbub2_program_watermarks( */ hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + + /* + * There's a special case when going from p-state support to p-state unsupported + * here we are going to LOWER watermarks to go to dummy p-state only, but this has + * to be done prepare_bandwidth, not optimize + */ + if (hubbub1->base.ctx->dc->clk_mgr->clks.prev_p_state_change_support == true && + hubbub1->base.ctx->dc->clk_mgr->clks.p_state_change_support == false) + safe_to_lower = true; + hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, @@ -571,7 +600,7 @@ static const struct hubbub_funcs hubbub2_funcs = { .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, + .program_watermarks = hubbub2_program_watermarks }; void hubbub2_construct(struct dcn20_hubbub *hubbub, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h index a7b6ca26a9ad..626117d3b4e9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubbub.h @@ -29,13 +29,21 @@ #include "dcn10/dcn10_hubbub.h" #include "dcn20_vmid.h" +#define HUBBUB_REG_LIST_DCN20_COMMON()\ + HUBBUB_REG_LIST_DCN_COMMON(), \ + 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 TO_DCN20_HUBBUB(hubbub)\ container_of(hubbub, struct dcn20_hubbub, base) -#define HUBBUB_REG_LIST_DCN20(id)\ +#define HUBBUB_REG_LIST_DCN20_COMMON()\ 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),\ @@ -44,6 +52,14 @@ SR(DCN_VM_AGP_TOP),\ SR(DCN_VM_AGP_BASE) +#define HUBBUB_REG_LIST_DCN20(id)\ + HUBBUB_REG_LIST_DCN20_COMMON(), \ + HUBBUB_SR_WATERMARK_REG_LIST(), \ + HUBBUB_VM_REG_LIST(),\ + SR(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB),\ + SR(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB) + + #define HUBBUB_MASK_SH_LIST_DCN20(mask_sh)\ HUBBUB_MASK_SH_LIST_DCN_COMMON(mask_sh), \ HUBBUB_MASK_SH_LIST_STUTTER(mask_sh), \ @@ -53,7 +69,9 @@ 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) + HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh), \ + HUBBUB_SF(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_MSB, mask_sh), \ + HUBBUB_SF(DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, DCN_VM_PROTECTION_FAULT_DEFAULT_ADDR_LSB, mask_sh) struct dcn20_hubbub { struct hubbub base; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c index d3f7dd374d50..69e2aae42394 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c @@ -40,81 +40,6 @@ #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) { @@ -156,7 +81,85 @@ void hubp2_program_deadline( { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - hubp1_program_deadline(hubp, dlg_attr, ttu_attr); + /* DLG - Per hubp */ + REG_SET_2(BLANK_OFFSET_0, 0, + REFCYC_H_BLANK_END, dlg_attr->refcyc_h_blank_end, + DLG_V_BLANK_END, dlg_attr->dlg_vblank_end); + + REG_SET(BLANK_OFFSET_1, 0, + MIN_DST_Y_NEXT_START, dlg_attr->min_dst_y_next_start); + + REG_SET(DST_DIMENSIONS, 0, + REFCYC_PER_HTOTAL, dlg_attr->refcyc_per_htotal); + + REG_SET_2(DST_AFTER_SCALER, 0, + REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); + + REG_SET(REF_FREQ_TO_PIX_FREQ, 0, + REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_SET(VBLANK_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); + + if (REG(NOM_PARAMETERS_0)) + REG_SET(NOM_PARAMETERS_0, 0, + DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); + + if (REG(NOM_PARAMETERS_1)) + REG_SET(NOM_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_NOM_L, dlg_attr->refcyc_per_pte_group_nom_l); + + REG_SET(NOM_PARAMETERS_4, 0, + DST_Y_PER_META_ROW_NOM_L, dlg_attr->dst_y_per_meta_row_nom_l); + + REG_SET(NOM_PARAMETERS_5, 0, + REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); + + REG_SET_2(PER_LINE_DELIVERY, 0, + REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); + + REG_SET(VBLANK_PARAMETERS_2, 0, + REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); + + if (REG(NOM_PARAMETERS_2)) + REG_SET(NOM_PARAMETERS_2, 0, + DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); + + if (REG(NOM_PARAMETERS_3)) + REG_SET(NOM_PARAMETERS_3, 0, + REFCYC_PER_PTE_GROUP_NOM_C, dlg_attr->refcyc_per_pte_group_nom_c); + + REG_SET(NOM_PARAMETERS_6, 0, + DST_Y_PER_META_ROW_NOM_C, dlg_attr->dst_y_per_meta_row_nom_c); + + REG_SET(NOM_PARAMETERS_7, 0, + REFCYC_PER_META_CHUNK_NOM_C, dlg_attr->refcyc_per_meta_chunk_nom_c); + + /* TTU - per hubp */ + REG_SET_2(DCN_TTU_QOS_WM, 0, + QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + + REG_SET_3(DCN_SURF0_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); + + REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); + + REG_SET_3(DCN_CUR0_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_cur0, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_cur0); REG_SET(FLIP_PARAMETERS_1, 0, REFCYC_PER_PTE_GROUP_FLIP_L, dlg_attr->refcyc_per_pte_group_flip_l); @@ -184,6 +187,39 @@ void hubp2_vready_at_or_After_vsync(struct hubp *hubp, REG_UPDATE(DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, value); } +void hubp2_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, rq_regs->plane1_base_address); + REG_SET_4(DCN_EXPANSION_MODE, 0, + DRQ_EXPANSION_MODE, rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, rq_regs->crq_expansion_mode); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG, 0, + CHUNK_SIZE, rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, rq_regs->rq_regs_l.pte_row_height_linear); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG_C, 0, + CHUNK_SIZE_C, rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, rq_regs->rq_regs_c.pte_row_height_linear); +} + static void hubp2_setup( struct hubp *hubp, struct _vcs_dpi_display_dlg_regs_st *dlg_attr, @@ -196,7 +232,7 @@ static void hubp2_setup( */ hubp2_vready_at_or_After_vsync(hubp, pipe_dest); - hubp1_program_requestor(hubp, rq_regs); + hubp2_program_requestor(hubp, rq_regs); hubp2_program_deadline(hubp, dlg_attr, ttu_attr); } @@ -283,11 +319,205 @@ static void hubp2_program_tiling( PIPE_ALIGNED, 0); } +void hubp2_program_size( + struct hubp *hubp, + enum surface_pixel_format format, + const struct plane_size *plane_size, + struct dc_plane_dcc_param *dcc) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t pitch, meta_pitch, pitch_c, meta_pitch_c; + bool use_pitch_c = false; + + /* Program data and meta surface pitch (calculation from addrlib) + * 444 or 420 luma + */ + use_pitch_c = format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END; + if (use_pitch_c) { + ASSERT(plane_size->chroma_pitch != 0); + /* Chroma pitch zero can cause system hang! */ + + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; + pitch_c = plane_size->chroma_pitch - 1; + meta_pitch_c = dcc->meta_pitch_c - 1; + } else { + pitch = plane_size->surface_pitch - 1; + meta_pitch = dcc->meta_pitch - 1; + pitch_c = 0; + meta_pitch_c = 0; + } + + if (!dcc->enable) { + meta_pitch = 0; + meta_pitch_c = 0; + } + + REG_UPDATE_2(DCSURF_SURFACE_PITCH, + PITCH, pitch, META_PITCH, meta_pitch); + + use_pitch_c = format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN; + if (use_pitch_c) + REG_UPDATE_2(DCSURF_SURFACE_PITCH_C, + PITCH_C, pitch_c, META_PITCH_C, meta_pitch_c); +} + +void hubp2_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + bool horizontal_mirror) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t mirror; + + + if (horizontal_mirror) + mirror = 1; + else + mirror = 0; + + /* Program rotation angle and horz mirror - no mirror */ + if (rotation == ROTATION_ANGLE_0) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 0, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_90) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 1, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_180) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 2, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_270) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 3, + H_MIRROR_EN, mirror); +} + +void hubp2_dcc_control(struct hubp *hubp, bool enable, + enum hubp_ind_block_size independent_64b_blks) +{ + uint32_t dcc_en = enable ? 1 : 0; + uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE_4(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, dcc_en, + PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk, + SECONDARY_SURFACE_DCC_EN, dcc_en, + SECONDARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk); +} + +void hubp2_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t red_bar = 3; + uint32_t blue_bar = 2; + + /* swap for ABGR format */ + if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { + red_bar = 2; + blue_bar = 3; + } + + REG_UPDATE_2(HUBPRET_CONTROL, + CROSSBAR_SRC_CB_B, blue_bar, + CROSSBAR_SRC_CR_R, red_bar); + + /* Mapping is same as ipp programming (cnvc) */ + + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 1); + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 3); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 8); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 10); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 22); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/ + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 24); + break; + + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 65); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 64); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 67); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 66); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888: + 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; + } + + /* don't see the need of program the xbar in DCN 1.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, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, @@ -295,11 +525,11 @@ void hubp2_program_surface_config( { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); - hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); + hubp2_dcc_control(hubp, dcc->enable, dcc->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); + hubp2_program_size(hubp, format, plane_size, dcc); + hubp2_program_rotation(hubp, rotation, horizontal_mirror); + hubp2_program_pixel_format(hubp, format); } enum cursor_lines_per_chunk hubp2_get_lines_per_chunk( @@ -652,28 +882,388 @@ void hubp2_set_flip_control_surface_gsl(struct hubp *hubp, bool enable) REG_UPDATE(DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, enable ? 1 : 0); } +bool hubp2_is_flip_pending(struct hubp *hubp) +{ + uint32_t flip_pending = 0; + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dc_plane_address earliest_inuse_address; + + REG_GET(DCSURF_FLIP_CONTROL, + SURFACE_FLIP_PENDING, &flip_pending); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE, + SURFACE_EARLIEST_INUSE_ADDRESS, &earliest_inuse_address.grph.addr.low_part); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &earliest_inuse_address.grph.addr.high_part); + + if (flip_pending) + return true; + + if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) + return true; + + return false; +} + +void hubp2_set_blank(struct hubp *hubp, bool blank) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t blank_en = blank ? 1 : 0; + + REG_UPDATE_2(DCHUBP_CNTL, + HUBP_BLANK_EN, blank_en, + HUBP_TTU_DISABLE, blank_en); + + if (blank) { + uint32_t reg_val = REG_READ(DCHUBP_CNTL); + + if (reg_val) { + /* init sequence workaround: in case HUBP is + * power gated, this wait would timeout. + * + * we just wrote reg_val to non-0, if it stay 0 + * it means HUBP is gated + */ + REG_WAIT(DCHUBP_CNTL, + HUBP_NO_OUTSTANDING_REQ, 1, + 1, 200); + } + + hubp->mpcc_id = 0xf; + hubp->opp_id = OPP_ID_INVALID; + } +} + +void hubp2_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + int src_x_offset = pos->x - pos->x_hotspot - param->viewport.x; + int src_y_offset = pos->y - pos->y_hotspot - param->viewport.y; + int x_hotspot = pos->x_hotspot; + int y_hotspot = pos->y_hotspot; + int cursor_height = (int)hubp->curs_attr.height; + int cursor_width = (int)hubp->curs_attr.width; + uint32_t dst_x_offset; + uint32_t cur_en = pos->enable ? 1 : 0; + + /* + * Guard aganst cursor_set_position() from being called with invalid + * attributes + * + * TODO: Look at combining cursor_set_position() and + * cursor_set_attributes() into cursor_update() + */ + if (hubp->curs_attr.address.quad_part == 0) + return; + + // Rotated cursor width/height and hotspots tweaks for offset calculation + if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) { + swap(cursor_height, cursor_width); + if (param->rotation == ROTATION_ANGLE_90) { + src_x_offset = pos->x - pos->y_hotspot - param->viewport.x; + src_y_offset = pos->y - pos->x_hotspot - param->viewport.y; + } + } else if (param->rotation == ROTATION_ANGLE_180) { + src_x_offset = pos->x - param->viewport.x; + src_y_offset = pos->y - param->viewport.y; + } + + if (param->mirror) { + x_hotspot = param->viewport.width - x_hotspot; + src_x_offset = param->viewport.x + param->viewport.width - src_x_offset; + } + + dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; + dst_x_offset *= param->ref_clk_khz; + dst_x_offset /= param->pixel_clk_khz; + + ASSERT(param->h_scale_ratio.value); + + if (param->h_scale_ratio.value) + dst_x_offset = dc_fixpt_floor(dc_fixpt_div( + dc_fixpt_from_int(dst_x_offset), + param->h_scale_ratio)); + + if (src_x_offset >= (int)param->viewport.width) + cur_en = 0; /* not visible beyond right edge*/ + + if (src_x_offset + cursor_width <= 0) + cur_en = 0; /* not visible beyond left edge*/ + + if (src_y_offset >= (int)param->viewport.height) + cur_en = 0; /* not visible beyond bottom edge*/ + + if (src_y_offset + cursor_height <= 0) + cur_en = 0; /* not visible beyond top edge*/ + + if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) + hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr); + + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, cur_en); + + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, pos->y); + + REG_SET_2(CURSOR_HOT_SPOT, 0, + CURSOR_HOT_SPOT_X, x_hotspot, + CURSOR_HOT_SPOT_Y, y_hotspot); + + REG_SET(CURSOR_DST_OFFSET, 0, + CURSOR_DST_X_OFFSET, dst_x_offset); + /* TODO Handle surface pixel formats other than 4:4:4 */ +} + +void hubp2_clk_cntl(struct hubp *hubp, bool enable) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + uint32_t clk_enable = enable ? 1 : 0; + + REG_UPDATE(HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, clk_enable); +} + +void hubp2_vtg_sel(struct hubp *hubp, uint32_t otg_inst) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_VTG_SEL, otg_inst); +} + +void hubp2_clear_underflow(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, 1); +} + +void hubp2_read_state_common(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dcn_hubp_state *s = &hubp2->state; + struct _vcs_dpi_display_dlg_regs_st *dlg_attr = &s->dlg_attr; + struct _vcs_dpi_display_ttu_regs_st *ttu_attr = &s->ttu_attr; + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + /* Requester */ + REG_GET(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, &rq_regs->plane1_base_address); + REG_GET_4(DCN_EXPANSION_MODE, + DRQ_EXPANSION_MODE, &rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, &rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, &rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, &rq_regs->crq_expansion_mode); + + /* DLG - Per hubp */ + REG_GET_2(BLANK_OFFSET_0, + REFCYC_H_BLANK_END, &dlg_attr->refcyc_h_blank_end, + DLG_V_BLANK_END, &dlg_attr->dlg_vblank_end); + + REG_GET(BLANK_OFFSET_1, + MIN_DST_Y_NEXT_START, &dlg_attr->min_dst_y_next_start); + + REG_GET(DST_DIMENSIONS, + REFCYC_PER_HTOTAL, &dlg_attr->refcyc_per_htotal); + + REG_GET_2(DST_AFTER_SCALER, + REFCYC_X_AFTER_SCALER, &dlg_attr->refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, &dlg_attr->dst_y_after_scaler); + + if (REG(PREFETCH_SETTINS)) + REG_GET_2(PREFETCH_SETTINS, + DST_Y_PREFETCH, &dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, &dlg_attr->vratio_prefetch); + else + REG_GET_2(PREFETCH_SETTINGS, + DST_Y_PREFETCH, &dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, &dlg_attr->vratio_prefetch); + + REG_GET_2(VBLANK_PARAMETERS_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_GET(REF_FREQ_TO_PIX_FREQ, + REF_FREQ_TO_PIX_FREQ, &dlg_attr->ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_GET(VBLANK_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_VBLANK_L, &dlg_attr->refcyc_per_pte_group_vblank_l); + + REG_GET(VBLANK_PARAMETERS_3, + REFCYC_PER_META_CHUNK_VBLANK_L, &dlg_attr->refcyc_per_meta_chunk_vblank_l); + + if (REG(NOM_PARAMETERS_0)) + REG_GET(NOM_PARAMETERS_0, + DST_Y_PER_PTE_ROW_NOM_L, &dlg_attr->dst_y_per_pte_row_nom_l); + + if (REG(NOM_PARAMETERS_1)) + REG_GET(NOM_PARAMETERS_1, + REFCYC_PER_PTE_GROUP_NOM_L, &dlg_attr->refcyc_per_pte_group_nom_l); + + REG_GET(NOM_PARAMETERS_4, + DST_Y_PER_META_ROW_NOM_L, &dlg_attr->dst_y_per_meta_row_nom_l); + + REG_GET(NOM_PARAMETERS_5, + REFCYC_PER_META_CHUNK_NOM_L, &dlg_attr->refcyc_per_meta_chunk_nom_l); + + REG_GET_2(PER_LINE_DELIVERY_PRE, + 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_GET_2(PER_LINE_DELIVERY, + REFCYC_PER_LINE_DELIVERY_L, &dlg_attr->refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, &dlg_attr->refcyc_per_line_delivery_c); + + if (REG(PREFETCH_SETTINS_C)) + REG_GET(PREFETCH_SETTINS_C, + VRATIO_PREFETCH_C, &dlg_attr->vratio_prefetch_c); + else + REG_GET(PREFETCH_SETTINGS_C, + VRATIO_PREFETCH_C, &dlg_attr->vratio_prefetch_c); + + REG_GET(VBLANK_PARAMETERS_2, + REFCYC_PER_PTE_GROUP_VBLANK_C, &dlg_attr->refcyc_per_pte_group_vblank_c); + + REG_GET(VBLANK_PARAMETERS_4, + REFCYC_PER_META_CHUNK_VBLANK_C, &dlg_attr->refcyc_per_meta_chunk_vblank_c); + + if (REG(NOM_PARAMETERS_2)) + REG_GET(NOM_PARAMETERS_2, + DST_Y_PER_PTE_ROW_NOM_C, &dlg_attr->dst_y_per_pte_row_nom_c); + + if (REG(NOM_PARAMETERS_3)) + REG_GET(NOM_PARAMETERS_3, + REFCYC_PER_PTE_GROUP_NOM_C, &dlg_attr->refcyc_per_pte_group_nom_c); + + REG_GET(NOM_PARAMETERS_6, + DST_Y_PER_META_ROW_NOM_C, &dlg_attr->dst_y_per_meta_row_nom_c); + + REG_GET(NOM_PARAMETERS_7, + REFCYC_PER_META_CHUNK_NOM_C, &dlg_attr->refcyc_per_meta_chunk_nom_c); + + /* TTU - per hubp */ + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &ttu_attr->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &ttu_attr->qos_level_high_wm); + + REG_GET_2(DCN_GLOBAL_TTU_CNTL, + MIN_TTU_VBLANK, &ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, &ttu_attr->qos_level_flip); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + + REG_GET_3(DCN_SURF0_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, &ttu_attr->qos_level_fixed_l, + QoS_RAMP_DISABLE, &ttu_attr->qos_ramp_disable_l); + + REG_GET(DCN_SURF0_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, + &ttu_attr->refcyc_per_req_delivery_pre_l); + + REG_GET_3(DCN_SURF1_TTU_CNTL0, + REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, &ttu_attr->qos_level_fixed_c, + QoS_RAMP_DISABLE, &ttu_attr->qos_ramp_disable_c); + + REG_GET(DCN_SURF1_TTU_CNTL1, + REFCYC_PER_REQ_DELIVERY_PRE, + &ttu_attr->refcyc_per_req_delivery_pre_c); + + /* Rest of hubp */ + REG_GET(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, &s->pixel_format); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &s->inuse_addr_hi); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE, + SURFACE_EARLIEST_INUSE_ADDRESS, &s->inuse_addr_lo); + + REG_GET_2(DCSURF_PRI_VIEWPORT_DIMENSION, + PRI_VIEWPORT_WIDTH, &s->viewport_width, + PRI_VIEWPORT_HEIGHT, &s->viewport_height); + + REG_GET_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, &s->rotation_angle, + H_MIRROR_EN, &s->h_mirror_en); + + REG_GET(DCSURF_TILING_CONFIG, + SW_MODE, &s->sw_mode); + + REG_GET(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, &s->dcc_en); + + REG_GET_3(DCHUBP_CNTL, + HUBP_BLANK_EN, &s->blank_en, + HUBP_TTU_DISABLE, &s->ttu_disable, + HUBP_UNDERFLOW_STATUS, &s->underflow_status); + + REG_GET(DCN_GLOBAL_TTU_CNTL, + MIN_TTU_VBLANK, &s->min_ttu_vblank); + + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &s->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &s->qos_level_high_wm); + +} + +void hubp2_read_state(struct hubp *hubp) +{ + struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + struct dcn_hubp_state *s = &hubp2->state; + struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs; + + hubp2_read_state_common(hubp); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG, + CHUNK_SIZE, &rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, &rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, &rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, &rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, &rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, &rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, &rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, &rq_regs->rq_regs_l.pte_row_height_linear); + + REG_GET_8(DCHUBP_REQ_SIZE_CONFIG_C, + CHUNK_SIZE_C, &rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, &rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, &rq_regs->rq_regs_c.pte_row_height_linear); + +} + 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_is_flip_pending = hubp2_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, + .set_blank = hubp2_set_blank, + .dcc_control = hubp2_dcc_control, .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, + .set_cursor_position = hubp2_cursor_set_position, + .hubp_clk_cntl = hubp2_clk_cntl, + .hubp_vtg_sel = hubp2_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_read_state = hubp2_read_state, + .hubp_clear_underflow = hubp2_clear_underflow, .hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl, .hubp_init = hubp1_init, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h index d5acc348be22..d5c8615af45e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.h @@ -38,12 +38,6 @@ 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), \ @@ -72,8 +66,8 @@ 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),\ +#define HUBP_MASK_SH_LIST_DCN2_SHARE_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN_SHARE_COMMON(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),\ @@ -82,12 +76,6 @@ 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), \ @@ -127,13 +115,21 @@ HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, mask_sh),\ HUBP_SF(HUBPREQ0_VMID_SETTINGS_0, VMID, mask_sh) +/*DCN2.x and DCN1.x*/ +#define HUBP_MASK_SH_LIST_DCN2_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN2_SHARE_COMMON(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MPTE_GROUP_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MPTE_GROUP_SIZE_C, mask_sh) + +/*DCN2.0 specific*/ #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) - +/*DCN2.x */ #define DCN2_HUBP_REG_COMMON_VARIABLE_LIST \ HUBP_COMMON_REG_VARIABLE_LIST; \ uint32_t DMDATA_ADDRESS_HIGH; \ @@ -149,14 +145,22 @@ uint32_t FLIP_PARAMETERS_2;\ uint32_t DCN_CUR1_TTU_CNTL0;\ uint32_t DCN_CUR1_TTU_CNTL1;\ - uint32_t VMID_SETTINGS_0;\ + uint32_t VMID_SETTINGS_0 + + +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define DCN21_HUBP_REG_COMMON_VARIABLE_LIST \ + DCN2_HUBP_REG_COMMON_VARIABLE_LIST; \ uint32_t FLIP_PARAMETERS_3;\ uint32_t FLIP_PARAMETERS_4;\ + uint32_t FLIP_PARAMETERS_5;\ + uint32_t FLIP_PARAMETERS_6;\ uint32_t VBLANK_PARAMETERS_5;\ uint32_t VBLANK_PARAMETERS_6 +#endif #define DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type) \ - DCN_HUBP_REG_FIELD_LIST(type); \ + DCN_HUBP_REG_FIELD_BASE_LIST(type); \ type DMDATA_ADDRESS_HIGH;\ type DMDATA_MODE;\ type DMDATA_UPDATED;\ @@ -180,17 +184,41 @@ type SURFACE_TRIPLE_BUFFER_ENABLE;\ type VMID +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +#define DCN21_HUBP_REG_FIELD_VARIABLE_LIST(type) \ + DCN2_HUBP_REG_FIELD_VARIABLE_LIST(type);\ + type REFCYC_PER_VM_GROUP_FLIP;\ + type REFCYC_PER_VM_REQ_FLIP;\ + type REFCYC_PER_VM_GROUP_VBLANK;\ + type REFCYC_PER_VM_REQ_VBLANK;\ + type REFCYC_PER_PTE_GROUP_FLIP_C; \ + type REFCYC_PER_META_CHUNK_FLIP_C; \ + type VM_GROUP_SIZE +#endif + struct dcn_hubp2_registers { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_COMMON_VARIABLE_LIST; +#else DCN2_HUBP_REG_COMMON_VARIABLE_LIST; +#endif }; struct dcn_hubp2_shift { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); +#else DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint8_t); +#endif }; struct dcn_hubp2_mask { +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN21_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); +#else DCN2_HUBP_REG_FIELD_VARIABLE_LIST(uint32_t); +#endif }; struct dcn20_hubp { @@ -217,10 +245,6 @@ void hubp2_setup_interdependent( 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); @@ -262,16 +286,53 @@ bool hubp2_program_surface_flip_and_addr( const struct dc_plane_address *address, bool flip_immediate); +void hubp2_dcc_control(struct hubp *hubp, bool enable, + enum hubp_ind_block_size independent_64b_blks); + +void hubp2_program_size( + struct hubp *hubp, + enum surface_pixel_format format, + const struct plane_size *plane_size, + struct dc_plane_dcc_param *dcc); + +void hubp2_program_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + bool horizontal_mirror); + +void hubp2_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format); + void hubp2_program_surface_config( struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, unsigned int compat_level); +bool hubp2_is_flip_pending(struct hubp *hubp); + +void hubp2_set_blank(struct hubp *hubp, bool blank); + +void hubp2_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); + +void hubp2_clk_cntl(struct hubp *hubp, bool enable); + +void hubp2_vtg_sel(struct hubp *hubp, uint32_t otg_inst); + +void hubp2_clear_underflow(struct hubp *hubp); + +void hubp2_read_state_common(struct hubp *hubp); + +void hubp2_read_state(struct hubp *hubp); + #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 index d810c8940129..1212da12c414 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -64,23 +64,7 @@ #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( +static void dcn20_enable_power_gating_plane( struct dce_hwseq *hws, bool enable) { @@ -94,28 +78,34 @@ static void enable_power_gating_plane( 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);*/ + if (REG(DOMAIN8_PG_CONFIG)) + REG_UPDATE(DOMAIN8_PG_CONFIG, DOMAIN8_POWER_FORCEON, force_on); + if (REG(DOMAIN10_PG_CONFIG)) + REG_UPDATE(DOMAIN10_PG_CONFIG, DOMAIN8_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);*/ + if (REG(DOMAIN9_PG_CONFIG)) + REG_UPDATE(DOMAIN9_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + if (REG(DOMAIN11_PG_CONFIG)) + REG_UPDATE(DOMAIN11_PG_CONFIG, DOMAIN9_POWER_FORCEON, force_on); + /* DCS0/1/2/3/4/5 */ 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); + if (REG(DOMAIN19_PG_CONFIG)) + REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN19_POWER_FORCEON, force_on); + if (REG(DOMAIN20_PG_CONFIG)) + REG_UPDATE(DOMAIN20_PG_CONFIG, DOMAIN20_POWER_FORCEON, force_on); + if (REG(DOMAIN21_PG_CONFIG)) + REG_UPDATE(DOMAIN21_PG_CONFIG, DOMAIN21_POWER_FORCEON, force_on); } -static void dcn20_dccg_init(struct dce_hwseq *hws) +void dcn20_dccg_init(struct dce_hwseq *hws) { /* * set MICROSECOND_TIME_BASE_DIV @@ -138,8 +128,46 @@ static void dcn20_dccg_init(struct dce_hwseq *hws) /* This value is dependent on the hardware pipeline delay so set once per SOC */ REG_WRITE(DISPCLK_FREQ_CHANGE_CNTL, 0x801003c); } +void dcn20_display_init(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + + /* RBBMIF + * disable RBBMIF timeout detection for all clients + * Ensure RBBMIF does not drop register accesses due to the per-client timeout + */ + REG_WRITE(RBBMIF_TIMEOUT_DIS, 0xFFFFFFFF); + REG_WRITE(RBBMIF_TIMEOUT_DIS_2, 0xFFFFFFFF); -static void disable_vga( + /* DCCG */ + dcn20_dccg_init(hws); + + REG_UPDATE(DC_MEM_GLOBAL_PWR_REQ_CNTL, DC_MEM_GLOBAL_PWR_REQ_DIS, 0); + + /* DCHUB/MMHUBBUB + * set global timer refclk divider + * 100Mhz refclk -> 2 + * 27Mhz refclk -> 1 + * 48Mhz refclk -> 1 + */ + 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); + + /* OPTC + * OTG_CONTROL.OTG_DISABLE_POINT_CNTL = 0x3; will be set during optc2_enable_crtc + */ + + /* AZ + * default value is 0x64 for 100Mhz ref clock, if the ref clock is 100Mhz, no need to program this regiser, + * if not, it should be programmed according to the ref clock + */ + REG_UPDATE(AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, 0x64); + /* Enable controller clock gating */ + REG_WRITE(AZALIA_CONTROLLER_CLOCK_GATING, 0x1); +} + +void dcn20_disable_vga( struct dce_hwseq *hws) { REG_WRITE(D1VGA_CONTROL, 0); @@ -163,7 +191,7 @@ void dcn20_program_tripleBuffer( } /* Blank pixel data during initialization */ -static void dcn20_init_blank( +void dcn20_init_blank( struct dc *dc, struct timing_generator *tg) { @@ -442,29 +470,6 @@ static void dcn20_hubp_pg_control( } - -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 */ @@ -490,7 +495,9 @@ static void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) hubp->power_gated = true; dc->optimized_required = false; /* We're powering off, no need to optimize */ - dcn20_plane_atomic_power_down(dc, pipe_ctx); + dc->hwss.plane_atomic_power_down(dc, + pipe_ctx->plane_res.dpp, + pipe_ctx->plane_res.hubp); pipe_ctx->stream = NULL; memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); @@ -514,199 +521,6 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) 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, @@ -715,11 +529,9 @@ enum dc_status dcn20_enable_stream_timing( 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 + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; /* 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 @@ -730,12 +542,17 @@ enum dc_status dcn20_enable_stream_timing( /* TODO check if timing_changed, disable stream if timing changed */ - if (odm_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) 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); + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); + /* HW program guide assume display already disable * by unplug sequence. OTG assume stop. */ @@ -759,11 +576,7 @@ enum dc_status dcn20_enable_stream_timing( 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) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( odm_pipe->stream_res.opp, true); @@ -784,6 +597,8 @@ enum dc_status dcn20_enable_stream_timing( params.vertical_total_min = stream->adjust.v_total_min; params.vertical_total_max = stream->adjust.v_total_max; + params.vertical_total_mid = stream->adjust.v_total_mid; + params.vertical_total_mid_frame_num = stream->adjust.v_total_mid_frame_num; if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, ¶ms); @@ -814,6 +629,10 @@ void dcn20_program_output_csc(struct dc *dc, { struct mpc *mpc = dc->res_pool->mpc; enum mpc_output_csc_mode ocsc_mode = MPC_OUTPUT_CSC_COEF_A; + int mpcc_id = pipe_ctx->plane_res.hubp->inst; + + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { if (mpc->funcs->set_output_csc != NULL) @@ -843,7 +662,9 @@ bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, * 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)) + if (mpc->funcs->power_on_mpc_mem_pwr) + mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); + if (pipe_ctx->top_pipe == NULL && mpc->funcs->set_output_gamma && stream->out_transfer_func) { if (stream->out_transfer_func->type == TF_TYPE_HWPWL) params = &stream->out_transfer_func->pwl; @@ -909,14 +730,14 @@ static bool dcn20_set_shaper_3dlut( result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); if (plane_state->lut3d_func && - plane_state->lut3d_func->initialized == true) + plane_state->lut3d_func->state.bits.initialized == 1) 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->state.bits.initialized == 1 && plane_state->lut3d_func->hdr_multiplier != 0) dpp_base->funcs->dpp_set_hdr_multiplier(dpp_base, plane_state->lut3d_func->hdr_multiplier); @@ -1005,14 +826,20 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, 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); + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; - if (combine_pipe) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; + opp_cnt++; + } + + if (opp_cnt > 1) 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); + opp_inst, opp_cnt, + &pipe_ctx->stream->timing); else pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); @@ -1028,7 +855,8 @@ void dcn20_blank_pixel_data( 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); + struct pipe_ctx *odm_pipe; + int odm_cnt = 1; 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; @@ -1036,8 +864,10 @@ void dcn20_blank_pixel_data( /* get opp dpg blank color */ color_space_to_black_color(dc, color_space, &black_color); - if (bot_odm_pipe) - width = width / 2; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + odm_cnt++; + + width = width / odm_cnt; if (blank) { if (stream_res->abm) @@ -1057,10 +887,10 @@ void dcn20_blank_pixel_data( 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 ? + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( + odm_pipe->stream_res.opp, + dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE && blank ? CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, stream->timing.display_color_depth, &black_color, @@ -1106,6 +936,9 @@ void dcn20_enable_plane( /* enable DCFCLK current DCHUB */ pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true); + /* initialize HUBP on power up */ + pipe_ctx->plane_res.hubp->funcs->hubp_init(pipe_ctx->plane_res.hubp); + /* make sure OPP_PIPE_CLOCK_EN = 1 */ pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( pipe_ctx->stream_res.opp, @@ -1201,7 +1034,7 @@ static void dcn20_program_all_pipe_in_tree( struct pipe_ctx *pipe_ctx, struct dc_state *context) { - if (pipe_ctx->top_pipe == NULL) { + if (pipe_ctx->top_pipe == NULL && !pipe_ctx->prev_odm_pipe) { bool blank = !is_pipe_tree_visible(pipe_ctx); pipe_ctx->stream_res.tg->funcs->program_global_sync( @@ -1223,8 +1056,13 @@ static void dcn20_program_all_pipe_in_tree( 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) + if (pipe_ctx->bottom_pipe != NULL) { + ASSERT(pipe_ctx->bottom_pipe != pipe_ctx); dcn20_program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); + } else if (pipe_ctx->next_odm_pipe != NULL) { + ASSERT(pipe_ctx->next_odm_pipe != pipe_ctx); + dcn20_program_all_pipe_in_tree(dc, pipe_ctx->next_odm_pipe, context); + } } void dcn20_pipe_control_lock_global( @@ -1265,17 +1103,6 @@ void dcn20_pipe_control_lock( if (pipe->plane_state != NULL) flip_immediate = pipe->plane_state->flip_immediate; - if (flip_immediate && lock) { - while (pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->plane_res.hubp)) { - udelay(1); - } - - if (pipe->bottom_pipe != NULL) - while (pipe->bottom_pipe->plane_res.hubp->funcs->hubp_is_flip_pending(pipe->bottom_pipe->plane_res.hubp)) { - udelay(1); - } - } - /* In flip immediate and pipe splitting case, we need to use GSL * for synchronization. Only do setup on locking and on flip type change. */ @@ -1303,18 +1130,32 @@ static void dcn20_apply_ctx_for_surface( int num_planes, struct dc_state *context) { - + const unsigned int TIMEOUT_FOR_PIPE_ENABLE_MS = 100; 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); + struct pipe_ctx *prev_top_pipe_to_program = + find_top_pipe_for_stream(dc, dc->current_state, stream); DC_LOGGER_INIT(dc->ctx->logger); if (!top_pipe_to_program) return; + /* Carry over GSL groups in case the context is changing. */ + 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]; + + if (pipe_ctx->stream == stream && + pipe_ctx->stream == old_pipe_ctx->stream) + pipe_ctx->stream_res.gsl_group = + old_pipe_ctx->stream_res.gsl_group; + } + tg = top_pipe_to_program->stream_res.tg; interdependent_update = top_pipe_to_program->plane_state && @@ -1345,7 +1186,7 @@ static void dcn20_apply_ctx_for_surface( 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); + dc->hwss.disable_plane(dc, old_pipe_ctx); } if ((!pipe_ctx->plane_state || @@ -1391,6 +1232,22 @@ static void dcn20_apply_ctx_for_surface( 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]); + + /* + * If we are enabling a pipe, we need to wait for pending clear as this is a critical + * part of the enable operation otherwise, DM may request an immediate flip which + * will cause HW to perform an "immediate enable" (as opposed to "vsync enable") which + * is unsupported on DCN. + */ + i = 0; + if (num_planes > 0 && top_pipe_to_program && + (prev_top_pipe_to_program == NULL || prev_top_pipe_to_program->plane_state == NULL)) { + while (i < TIMEOUT_FOR_PIPE_ENABLE_MS && + top_pipe_to_program->plane_res.hubp->funcs->hubp_is_flip_pending(top_pipe_to_program->plane_res.hubp)) { + i += 1; + msleep(1); + } + } } @@ -1400,16 +1257,16 @@ void dcn20_prepare_bandwidth( { struct hubbub *hubbub = dc->res_pool->hubbub; + dc->clk_mgr->funcs->update_clocks( + dc->clk_mgr, + context, + false); + /* 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( @@ -1462,8 +1319,8 @@ bool dcn20_update_bandwidth( 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 (pipe_ctx->prev_odm_pipe == NULL) + dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); } pipe_ctx->plane_res.hubp->funcs->hubp_setup( @@ -1553,12 +1410,15 @@ 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) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + 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); + while (odm_pipe) { + dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true); + odm_pipe = odm_pipe->next_odm_pipe; + } } #endif } @@ -1567,12 +1427,15 @@ 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) { + struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe; + 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); + while (odm_pipe) { + dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false); + odm_pipe = odm_pipe->next_odm_pipe; + } } #endif } @@ -1597,9 +1460,9 @@ void dcn20_set_dmdata_attributes(struct pipe_ctx *pipe_ctx) hubp->funcs->dmdata_set_attributes(hubp, &attr); } -void dcn20_disable_stream(struct pipe_ctx *pipe_ctx, int option) +void dcn20_disable_stream(struct pipe_ctx *pipe_ctx) { - dce110_disable_stream(pipe_ctx, option); + dce110_disable_stream(pipe_ctx); } static void dcn20_init_vm_ctx( @@ -1637,6 +1500,7 @@ static int dcn20_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_ph 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; + config.page_table_default_page_addr = pa_config->page_table_default_page_addr; return dc->res_pool->hubbub->funcs->init_dchub_sys_ctx(dc->res_pool->hubbub, &config); } @@ -1702,18 +1566,22 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, struct encoder_unblank_param params = { { 0 } }; struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; - params.odm = dc_res_get_odm_bottom_pipe(pipe_ctx); + struct pipe_ctx *odm_pipe; + params.opp_cnt = 1; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + params.opp_cnt++; + } /* 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) + if (optc1_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt > 1) 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, params.opp_cnt > 1); pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms); } @@ -1749,14 +1617,29 @@ static void dcn20_reset_back_end_for_pipe( 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); + core_link_disable_stream(pipe_ctx); + else if (pipe_ctx->stream_res.audio) + dc->hwss.disable_audio_stream(pipe_ctx); + + /* free acquired resources */ + if (pipe_ctx->stream_res.audio) { + /*disable az_endpoint*/ + pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio); + + /*free audio*/ + if (dc->caps.dynamic_audio == true) { + /*we have to dynamic arbitrate the audio endpoints*/ + /*we free the resource, need reset is_audio_acquired*/ + update_audio_usage(&dc->current_state->res_ctx, dc->res_pool, + pipe_ctx->stream_res.audio, false); + pipe_ctx->stream_res.audio = NULL; + } } } #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - else if (pipe_ctx->stream_res.dsc) + else if (pipe_ctx->stream_res.dsc) { dp_set_dsc_enable(pipe_ctx, false); + } #endif /* by upper caller loop, parent pipe: pipe0, will be reset last. @@ -1770,6 +1653,10 @@ static void dcn20_reset_back_end_for_pipe( 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); + + if (pipe_ctx->stream_res.tg->funcs->set_drr) + pipe_ctx->stream_res.tg->funcs->set_drr( + pipe_ctx->stream_res.tg, NULL); } for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -1799,7 +1686,7 @@ static void dcn20_reset_hw_ctx_wrap( if (!pipe_ctx_old->stream) continue; - if (pipe_ctx_old->top_pipe) + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) continue; if (!pipe_ctx->stream || @@ -1819,7 +1706,7 @@ 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; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha; int mpcc_id; struct mpcc *new_mpcc; struct mpc *mpc = dc->res_pool->mpc; @@ -2012,14 +1899,198 @@ static void dcn20_set_flip_control_gsl( } +static void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) +{ + enum dc_lane_count lane_count = + pipe_ctx->stream->link->cur_link_settings.lane_count; + + struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; + struct dc_link *link = pipe_ctx->stream->link; + + uint32_t active_total_with_borders; + uint32_t early_control = 0; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + /* For MST, there are multiply stream go to only one link. + * connect DIG back_end to front_end while enable_stream and + * disconnect them during disable_stream + * BY this, it is logic clean to separate stream and link + */ + link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc, + pipe_ctx->stream_res.stream_enc->id, true); + + if (link->dc->hwss.program_dmdata_engine) + link->dc->hwss.program_dmdata_engine(pipe_ctx); + + link->dc->hwss.update_info_frame(pipe_ctx); + + /* enable early control to avoid corruption on DP monitor*/ + active_total_with_borders = + timing->h_addressable + + timing->h_border_left + + timing->h_border_right; + + if (lane_count != 0) + early_control = active_total_with_borders % lane_count; + + if (early_control == 0) + early_control = lane_count; + + tg->funcs->set_early_control(tg, early_control); + + /* enable audio only within mode set */ + if (pipe_ctx->stream_res.audio != NULL) { + if (dc_is_dp_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc); + } +} + +static void dcn20_program_dmdata_engine(struct pipe_ctx *pipe_ctx) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + bool enable = false; + struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; + enum dynamic_metadata_mode mode = dc_is_dp_signal(stream->signal) + ? dmdata_dp + : dmdata_hdmi; + + /* if using dynamic meta, don't set up generic infopackets */ + if (pipe_ctx->stream->dmdata_address.quad_part != 0) { + pipe_ctx->stream_res.encoder_info_frame.hdrsmd.valid = false; + enable = true; + } + + if (!hubp) + return; + + if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata) + return; + + stream_enc->funcs->set_dynamic_metadata(stream_enc, enable, + hubp->inst, mode); +} + +static void dcn20_fpga_init_hw(struct dc *dc) +{ + int i, j; + struct dce_hwseq *hws = dc->hwseq; + struct resource_pool *res_pool = dc->res_pool; + struct dc_state *context = dc->current_state; + + 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 + dc->hwss.enable_power_gating_plane(hws, true); + + // Specific to FPGA dccg and registers + 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); + // + + + /* 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); + } +} + 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; @@ -2036,6 +2107,8 @@ void dcn20_hw_sequencer_construct(struct dc *dc) 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.program_dmdata_engine = dcn20_program_dmdata_engine; + dc->hwss.enable_stream = dcn20_enable_stream; 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; @@ -2045,5 +2118,23 @@ void dcn20_hw_sequencer_construct(struct dc *dc) 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; + dc->hwss.init_blank = dcn20_init_blank; + dc->hwss.disable_plane = dcn20_disable_plane; + dc->hwss.plane_atomic_disable = dcn20_plane_atomic_disable; + dc->hwss.enable_power_gating_plane = dcn20_enable_power_gating_plane; + dc->hwss.dpp_pg_control = dcn20_dpp_pg_control; + dc->hwss.hubp_pg_control = dcn20_hubp_pg_control; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + dc->hwss.dsc_pg_control = dcn20_dsc_pg_control; +#else + dc->hwss.dsc_pg_control = NULL; +#endif + dc->hwss.disable_vga = dcn20_disable_vga; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + dc->hwss.init_hw = dcn20_fpga_init_hw; + dc->hwss.init_pipes = NULL; + } + + } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h index 2b0409454073..92ab3dd91814 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.h @@ -75,7 +75,7 @@ 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_disable_stream(struct pipe_ctx *pipe_ctx); void dcn20_program_tripleBuffer( const struct dc *dc, @@ -91,13 +91,9 @@ void dcn20_pipe_control_lock_global( 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); +void dcn20_dccg_init(struct dce_hwseq *hws); +void dcn20_init_blank( + struct dc *dc, + struct timing_generator *tg); +void dcn20_display_init(struct dc *dc); #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 index f495582e9e87..e476f27aa3a9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_link_encoder.c @@ -341,6 +341,7 @@ static const struct link_encoder_funcs dcn20_link_enc_funcs = { .fec_set_enable = enc2_fec_set_enable, .fec_set_ready = enc2_fec_set_ready, .fec_is_active = enc2_fec_is_active, + .get_dig_mode = dcn10_get_dig_mode, .get_dig_frontend = dcn10_get_dig_frontend, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c index 240749e4cf83..5a188b2bc033 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.c @@ -233,14 +233,14 @@ static void mpc2_ogam_get_reg_field( reg->masks.exp_resion_start_segment = mpc20->mpc_mask->MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B; } -static void mpc20_power_on_ogam_lut( +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); + MPCC_OGAM_MEM_PWR_DIS, power_on == true ? 1:0); } @@ -368,6 +368,11 @@ void apply_DEDCN20_305_wa( { struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + if (mpc->ctx->dc->debug.cm_in_bypass) { + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); + return; + } + if (mpc->ctx->dc->work_arounds.dedcn20_305_wa == false) { /*hw fixed in new review*/ return; @@ -390,10 +395,16 @@ void mpc2_set_output_gamma( enum dc_lut_mode next_mode; struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); + if (mpc->ctx->dc->debug.cm_in_bypass) { + REG_SET(MPCC_OGAM_MODE[mpcc_id], 0, MPCC_OGAM_MODE, 0); + return; + } + 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; @@ -435,23 +446,22 @@ 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); + REG_GET_3(MPCC_STATUS[mpcc_id], + MPCC_BUSY, &mpc_busy, + MPCC_IDLE, &mpc_idle, + MPCC_DISABLED, &mpc_disabled); - ASSERT(mpc_busy == 0); - ASSERT(mpc_idle == 1); + if (top_sel == 0xf) { + ASSERT(!mpc_busy); + ASSERT(mpc_idle); + ASSERT(mpc_disabled); + } else { + ASSERT(!mpc_disabled); + ASSERT(!mpc_idle); } } @@ -488,6 +498,7 @@ const struct mpc_funcs dcn20_mpc_funcs = { .insert_plane = mpc1_insert_plane, .remove_mpcc = mpc1_remove_mpcc, .mpc_init = mpc1_mpc_init, + .mpc_init_single_inst = mpc1_mpc_init_single_inst, .update_blending = mpc2_update_blending, .get_mpcc_for_dpp = mpc2_get_mpcc_for_dpp, .wait_for_idle = mpc2_assert_idle_mpcc, @@ -498,6 +509,7 @@ const struct mpc_funcs dcn20_mpc_funcs = { .set_output_csc = mpc2_set_output_csc, .set_ocsc_default = mpc2_set_ocsc_default, .set_output_gamma = mpc2_set_output_gamma, + .power_on_mpc_mem_pwr = mpc20_power_on_ogam_lut, }; void dcn20_mpc_construct(struct dcn20_mpc *mpc20, diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h index 9750095d2d73..9f53192da2dc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_mpc.h @@ -159,6 +159,7 @@ 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(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_DIS, 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),\ @@ -173,6 +174,7 @@ 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;\ @@ -217,7 +219,8 @@ 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; + type MPCC_DISABLED;\ + type MPCC_OGAM_MEM_PWR_DIS; struct dcn20_mpc_registers { MPC_REG_VARIABLE_LIST_DCN2_0 @@ -282,4 +285,5 @@ void mpc2_set_output_gamma( void mpc2_assert_idle_mpcc(struct mpc *mpc, int id); void mpc2_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id); +void mpc20_power_on_ogam_lut(struct mpc *mpc, int mpcc_id, bool power_on); #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 index d9e7c711a71c..40164ed015ea 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c @@ -332,7 +332,6 @@ static struct opp_funcs dcn20_opp_funcs = { .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, }; diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c index 1ae973962d53..2137e2be2140 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c @@ -191,15 +191,6 @@ void optc2_set_dsc_config(struct timing_generator *optc, 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); @@ -224,7 +215,6 @@ void optc2_set_odm_bypass(struct timing_generator *optc, 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, @@ -236,13 +226,16 @@ void optc2_set_odm_bypass(struct timing_generator *optc, OTG_H_TIMING_DIV_BY2, h_div_2); REG_SET(OPTC_MEMORY_CONFIG, 0, OPTC_MEM_SEL, 0); + optc1->opp_count = 1; } -void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, - int mpcc_hactive, enum dc_pixel_encoding pixel_encoding) +void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) { struct optc *optc1 = DCN10TG_FROM_TG(optc); /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192 */ + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; int memory_mask = mpcc_hactive <= 2560 ? 0x3 : 0xf; uint32_t data_fmt = 0; @@ -257,23 +250,24 @@ void optc2_set_odm_combine(struct timing_generator *optc, int combine_opp_id, REG_SET(OPTC_MEMORY_CONFIG, 0, OPTC_MEM_SEL, memory_mask << (optc->inst * 4)); - if (pixel_encoding == PIXEL_ENCODING_YCBCR422) + if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) data_fmt = 1; - else if (pixel_encoding == PIXEL_ENCODING_YCBCR420) + else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) data_fmt = 2; REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); + ASSERT(opp_cnt == 2); 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); + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); 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; + optc1->opp_count = opp_cnt; } void optc2_get_optc_source(struct timing_generator *optc, @@ -339,65 +333,6 @@ void optc2_triplebuffer_unlock(struct timing_generator *optc) } - -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); @@ -492,10 +427,8 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .triplebuffer_lock = optc2_triplebuffer_lock, .triplebuffer_unlock = optc2_triplebuffer_unlock, .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc2_lock, + .lock = optc1_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, @@ -522,7 +455,8 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .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 + .setup_manual_trigger = optc2_setup_manual_trigger, + .is_matching_timing = optc1_is_matching_timing }; void dcn20_timing_generator_init(struct optc *optc1) @@ -537,6 +471,5 @@ void dcn20_timing_generator_init(struct optc *optc1) optc1->min_v_blank_interlace = 5; optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. 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 index ebf07c582da2..32a58431fd09 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h @@ -96,8 +96,8 @@ void optc2_set_dsc_config(struct timing_generator *optc, 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_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing); void optc2_get_optc_source(struct timing_generator *optc, uint32_t *num_of_src_opp, @@ -106,9 +106,6 @@ void optc2_get_optc_source(struct timing_generator *optc, 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); diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index b949e202d6cb..b4e3ce22ed52 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -82,6 +82,7 @@ #include "amdgpu_socbb.h" +/* NV12 SOC BB is currently in FW, mark SW bounding box invalid. */ #define SOC_BOUNDING_BOX_VALID false #define DC_LOGGER_INIT(logger) @@ -156,8 +157,119 @@ struct _vcs_dpi_ip_params_st dcn2_0_ip = { .xfc_fill_constant_bytes = 0, }; -struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { 0 }; - +struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = { + /* Defaults that get patched on driver load from firmware. */ + .clock_limits = { + { + .state = 0, + .dcfclk_mhz = 560.0, + .fabricclk_mhz = 560.0, + .dispclk_mhz = 513.0, + .dppclk_mhz = 513.0, + .phyclk_mhz = 540.0, + .socclk_mhz = 560.0, + .dscclk_mhz = 171.0, + .dram_speed_mts = 8960.0, + }, + { + .state = 1, + .dcfclk_mhz = 694.0, + .fabricclk_mhz = 694.0, + .dispclk_mhz = 642.0, + .dppclk_mhz = 642.0, + .phyclk_mhz = 600.0, + .socclk_mhz = 694.0, + .dscclk_mhz = 214.0, + .dram_speed_mts = 11104.0, + }, + { + .state = 2, + .dcfclk_mhz = 875.0, + .fabricclk_mhz = 875.0, + .dispclk_mhz = 734.0, + .dppclk_mhz = 734.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 875.0, + .dscclk_mhz = 245.0, + .dram_speed_mts = 14000.0, + }, + { + .state = 3, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 1000.0, + .dispclk_mhz = 1100.0, + .dppclk_mhz = 1100.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1000.0, + .dscclk_mhz = 367.0, + .dram_speed_mts = 16000.0, + }, + { + .state = 4, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + /*Extra state, no dispclk ramping*/ + { + .state = 5, + .dcfclk_mhz = 1200.0, + .fabricclk_mhz = 1200.0, + .dispclk_mhz = 1284.0, + .dppclk_mhz = 1284.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1200.0, + .dscclk_mhz = 428.0, + .dram_speed_mts = 16000.0, + }, + }, + .num_states = 5, + .sr_exit_time_us = 8.6, + .sr_enter_plus_exit_time_us = 10.9, + .urgent_latency_us = 4.0, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, + .max_avg_sdp_bw_use_normal_percent = 40.0, + .max_avg_dram_bw_use_normal_percent = 40.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 40.0, + .max_request_size_bytes = 256, + .dram_channel_width_bytes = 2, + .fabric_datapath_to_dcn_data_return_bytes = 64, + .dcn_downspread_percent = 0.5, + .downspread_percent = 0.38, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 131, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 16, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 404.0, + .dummy_pstate_latency_us = 5.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, + .dispclk_dppclk_vco_speed_mhz = 3850, + .xfc_bus_transport_time_us = 20, + .xfc_xbuf_latency_tolerance_us = 4, + .use_urgent_burst_bw = 0 +}; + +struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 }; #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f @@ -314,7 +426,7 @@ static const struct dce_audio_shift audio_shift = { DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) }; -static const struct dce_aduio_mask audio_mask = { +static const struct dce_audio_mask audio_mask = { DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) }; @@ -695,6 +807,16 @@ static const struct dc_plane_cap plane_cap = { .fp16 = 1 } }; +static const struct resource_caps res_cap_nv14 = { + .num_timing_generator = 5, + .num_opp = 5, + .num_video_plane = 5, + .num_audio = 6, + .num_stream_encoder = 5, + .num_pll = 5, + .num_dwb = 0, + .num_ddc = 5, +}; static const struct dc_debug_options debug_defaults_drv = { .disable_dmcu = true, @@ -1197,7 +1319,11 @@ static void get_pixel_clock_parameters( 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; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; pixel_clk_params->encoder_object_id = stream->link->link_enc->id; @@ -1215,7 +1341,9 @@ static void get_pixel_clock_parameters( 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) + if (opp_cnt == 4) + pixel_clk_params->requested_pix_clk_100hz /= 4; + else if (optc1_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) pixel_clk_params->requested_pix_clk_100hz /= 2; if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) @@ -1359,22 +1487,16 @@ static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, 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->stream_res.dsc) + release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); } } 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; + else + return DC_OK; } #endif @@ -1473,17 +1595,92 @@ static void swizzle_to_dml_params( } } -static bool dcn20_split_stream_for_combine( +static bool dcn20_split_stream_for_odm( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *prev_odm_pipe, + struct pipe_ctx *next_odm_pipe) +{ + int pipe_idx = next_odm_pipe->pipe_idx; + + *next_odm_pipe = *prev_odm_pipe; + + next_odm_pipe->pipe_idx = pipe_idx; + next_odm_pipe->plane_res.mi = pool->mis[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.hubp = pool->hubps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.ipp = pool->ipps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + next_odm_pipe->stream_res.dsc = NULL; +#endif + if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) { + ASSERT(!next_odm_pipe->next_odm_pipe); + next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe; + next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe; + } + prev_odm_pipe->next_odm_pipe = next_odm_pipe; + next_odm_pipe->prev_odm_pipe = prev_odm_pipe; + ASSERT(next_odm_pipe->top_pipe == NULL); + + if (prev_odm_pipe->plane_state) { + struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; + int new_width; + + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* 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 = &next_odm_pipe->plane_res.scl_data; + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Need at least 16 pixels width per side */ + if (new_width <= 16) + return false; + new_width = sd->recout.width + sd->recout.x - sd->h_active; + 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; + } + next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (next_odm_pipe->stream->timing.flags.DSC == 1) { + acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc); + ASSERT(next_odm_pipe->stream_res.dsc); + if (next_odm_pipe->stream_res.dsc == NULL) + return false; + } +#endif + + return true; +} + +static void dcn20_split_stream_for_mpc( struct resource_context *res_ctx, const struct resource_pool *pool, struct pipe_ctx *primary_pipe, - struct pipe_ctx *secondary_pipe, - bool is_odm_combine) + struct pipe_ctx *secondary_pipe) { 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; @@ -1506,57 +1703,9 @@ static bool dcn20_split_stream_for_combine( 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; + ASSERT(primary_pipe->plane_state); + resource_build_scaling_params(primary_pipe); + resource_build_scaling_params(secondary_pipe); } void dcn20_populate_dml_writeback_from_context( @@ -1669,6 +1818,19 @@ int dcn20_populate_dml_pipes_from_context( 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; + pipes[pipe_cnt].pipe.dest.odm_combine = res_ctx->pipe_ctx[i].prev_odm_pipe + || res_ctx->pipe_ctx[i].next_odm_pipe; + 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; + else if (res_ctx->pipe_ctx[i].prev_odm_pipe) { + struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].prev_odm_pipe; + + while (first_pipe->prev_odm_pipe) + first_pipe = first_pipe->prev_odm_pipe; + pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx; + } switch (res_ctx->pipe_ctx[i].stream->signal) { case SIGNAL_TYPE_DISPLAY_PORT_MST: @@ -1721,7 +1883,6 @@ int dcn20_populate_dml_pipes_from_context( break; } - switch (res_ctx->pipe_ctx[i].stream->timing.pixel_encoding) { case PIXEL_ENCODING_RGB: case PIXEL_ENCODING_YCBCR444: @@ -1743,10 +1904,6 @@ int dcn20_populate_dml_pipes_from_context( 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; @@ -1795,14 +1952,6 @@ int dcn20_populate_dml_pipes_from_context( && 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; @@ -1812,13 +1961,13 @@ int dcn20_populate_dml_pipes_from_context( 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; + pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch; + pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.chroma_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.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.data_pitch = pln->plane_size.surface_pitch; + pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch; } pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable; pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width; @@ -1986,20 +2135,24 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) 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; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; /* Only need to validate top pipe */ - if (pipe_ctx->top_pipe || !stream || !stream->timing.flags.DSC) + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_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_width = (stream->timing.h_addressable + stream->timing.h_border_left + + stream->timing.h_border_right) / opp_cnt; 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; + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg)) return false; @@ -2008,15 +2161,93 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) } #endif -bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, - bool fast_validate) +static struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *primary_pipe) { - bool out = false; + struct pipe_ctx *secondary_pipe = NULL; + + if (dc && primary_pipe) { + int j; + int preferred_pipe_idx = 0; + + /* first check the prev dc state: + * if this primary pipe has a bottom pipe in prev. state + * and if the bottom pipe is still available (which it should be), + * pick that pipe as secondary + * Same logic applies for ODM pipes. Since mpo is not allowed with odm + * check in else case. + */ + if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } else if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } - BW_VAL_TRACE_SETUP(); + /* + * if this primary pipe does not have a bottom pipe in prev. state + * start backward and find a pipe that did not used to be a bottom pipe in + * prev. dc state. This way we make sure we keep the same assignment as + * last state and will not have to reprogram every pipe + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + if (dc->current_state->res_ctx.pipe_ctx[j].top_pipe == NULL) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + /* + * We should never hit this assert unless assignments are shuffled around + * if this happens we will prob. hit a vsync tdr + */ + ASSERT(secondary_pipe); + /* + * search backwards for the second pipe to keep pipe + * assignment more consistent + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + + return secondary_pipe; +} + +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out) +{ + bool out = false; 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 @@ -2024,15 +2255,44 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, #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; + /* merge previously split odm pipes since mode support needs to make the decision */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *odm_pipe = pipe->next_odm_pipe; + + if (pipe->prev_odm_pipe) + continue; + + pipe->next_odm_pipe = NULL; + while (odm_pipe) { + struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; + + odm_pipe->plane_state = NULL; + odm_pipe->stream = NULL; + odm_pipe->top_pipe = NULL; + odm_pipe->bottom_pipe = NULL; + odm_pipe->prev_odm_pipe = NULL; + odm_pipe->next_odm_pipe = NULL; +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + if (odm_pipe->stream_res.dsc) + release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); +#endif + /* Clear plane_res and stream_res */ + memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res)); + memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res)); + odm_pipe = next_odm_pipe; + } + if (pipe->plane_state) + resource_build_scaling_params(pipe); + } + + /* merge previously mpc split pipes since mode support needs to make the decision */ 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; @@ -2040,7 +2300,6 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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; @@ -2048,10 +2307,7 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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)); @@ -2066,8 +2322,9 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, &context->res_ctx, pipes); + *pipe_cnt_out = pipe_cnt; + if (!pipe_cnt) { - BW_VAL_TRACE_SKIP(pass); out = true; goto validate_out; } @@ -2160,17 +2417,12 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, } 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); + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); ASSERT(hsplit_pipe); - if (!dcn20_split_stream_for_combine( + if (!dcn20_split_stream_for_odm( &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe, - true)) + pipe, hsplit_pipe)) goto validate_fail; pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; dcn20_build_mapped_resource(dc, context, pipe->stream); @@ -2206,16 +2458,20 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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); + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); ASSERT(hsplit_pipe || force_split); if (!hsplit_pipe) continue; - if (!dcn20_split_stream_for_combine( + if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + if (!dcn20_split_stream_for_odm( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe)) + goto validate_fail; + } else + dcn20_split_stream_for_mpc( &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe, - context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx])) - goto validate_fail; + pipe, hsplit_pipe); pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; } } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { @@ -2232,13 +2488,26 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, } #endif - BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + *vlevel_out = vlevel; - if (fast_validate) { - BW_VAL_TRACE_SKIP(fast); - out = true; - goto validate_out; - } + out = true; + goto validate_out; + +validate_fail: + out = false; + +validate_out: + return out; +} + +void dcn20_calculate_wm( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *out_pipe_cnt, + int *pipe_split_from, + int vlevel) +{ + int pipe_cnt, i, pipe_idx; for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { if (!context->res_ctx.pipe_ctx[i].stream) @@ -2265,10 +2534,16 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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; } + if (dc->debug.min_disp_clk_khz > pipes[pipe_cnt].clks_cfg.dispclk_mhz * 1000) + pipes[pipe_cnt].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; + if (dc->debug.min_dpp_clk_khz > pipes[pipe_cnt].clks_cfg.dppclk_mhz * 1000) + pipes[pipe_cnt].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; + pipe_cnt++; } @@ -2281,6 +2556,8 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, &context->res_ctx, pipes); } + *out_pipe_cnt = pipe_cnt; + 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; @@ -2327,6 +2604,17 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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; +} + +void dcn20_calculate_dlg_params( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + int i, j, pipe_idx, pipe_idx_unsplit; + bool visited[MAX_PIPES] = { 0 }; + /* Writeback MCIF_WB arbitration parameters */ dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt); @@ -2335,32 +2623,69 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, 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.fclk_khz = 0; 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(); + /* + * An artifact of dml pipe split/odm is that pipes get merged back together for + * calculation. Therefore we need to only extract for first pipe in ascending index order + * and copy into the other split half. + */ + for (i = 0, pipe_idx = 0, pipe_idx_unsplit = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + if (!visited[pipe_idx]) { + display_pipe_source_params_st *src = &pipes[pipe_idx_unsplit].pipe.src; + display_pipe_dest_params_st *dst = &pipes[pipe_idx_unsplit].pipe.dest; + + dst->vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx_unsplit]; + dst->vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx_unsplit]; + dst->vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx_unsplit]; + dst->vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx_unsplit]; + /* + * j iterates inside pipes array, unlike i which iterates inside + * pipe_ctx array + */ + if (src->is_hsplit) + for (j = pipe_idx + 1; j < pipe_cnt; j++) { + display_pipe_source_params_st *src_j = &pipes[j].pipe.src; + display_pipe_dest_params_st *dst_j = &pipes[j].pipe.dest; + + if (src_j->is_hsplit && !visited[j] + && src->hsplit_grp == src_j->hsplit_grp) { + dst_j->vstartup_start = context->bw_ctx.dml.vba.VStartup[pipe_idx_unsplit]; + dst_j->vupdate_offset = context->bw_ctx.dml.vba.VUpdateOffsetPix[pipe_idx_unsplit]; + dst_j->vupdate_width = context->bw_ctx.dml.vba.VUpdateWidthPix[pipe_idx_unsplit]; + dst_j->vready_offset = context->bw_ctx.dml.vba.VReadyOffsetPix[pipe_idx_unsplit]; + visited[j] = true; + } + } + visited[pipe_idx] = true; + pipe_idx_unsplit++; + } + pipe_idx++; + } 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 + ASSERT(visited[pipe_idx]); context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest; pipe_idx++; } + /*save a original dppclock copy*/ + context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz; + context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; + context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz * 1000; + context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000; 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; @@ -2383,8 +2708,43 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, pipes[pipe_idx].pipe); pipe_idx++; } +} + +static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + BW_VAL_TRACE_SETUP(); + + int vlevel = 0; + int pipe_split_from[MAX_PIPES]; + int pipe_cnt = 0; + 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(); + + out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel); + + if (pipe_cnt == 0) + goto validate_out; + + if (!out) + goto validate_fail; + + BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + + if (fast_validate) { + BW_VAL_TRACE_SKIP(fast); + goto validate_out; + } + + dcn20_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel); + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); + + BW_VAL_TRACE_END_WATERMARKS(); - out = true; goto validate_out; validate_fail: @@ -2402,6 +2762,50 @@ validate_out: return out; } + +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool voltage_supported = false; + bool full_pstate_supported = false; + bool dummy_pstate_supported = false; + double p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us; + + if (fast_validate) + return dcn20_validate_bandwidth_internal(dc, context, true); + + + // Best case, we support full UCLK switch latency + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 || + (voltage_supported && full_pstate_supported)) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = true; + goto restore_dml_state; + } + + // Fallback: Try to only support G6 temperature read latency + context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us; + + voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false); + dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support; + + if (voltage_supported && dummy_pstate_supported) { + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + goto restore_dml_state; + } + + // ERROR: fallback is supposed to always work. + ASSERT(false); + +restore_dml_state: + memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); + context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us; + + return voltage_supported; +} + struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer( struct dc_state *state, const struct resource_pool *pool, @@ -2576,9 +2980,6 @@ static void cap_soc_clocks( && 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); @@ -2674,6 +3075,10 @@ static void update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_ num_calculated_states++; } + calculated_states[num_calculated_states - 1].socclk_mhz = max_clocks->socClockInKhz / 1000; + calculated_states[num_calculated_states - 1].fabricclk_mhz = max_clocks->socClockInKhz / 1000; + calculated_states[num_calculated_states - 1].dcfclk_mhz = max_clocks->dcfClockInKhz / 1000; + memcpy(bb->clock_limits, calculated_states, sizeof(bb->clock_limits)); bb->num_states = num_calculated_states; @@ -2711,6 +3116,27 @@ static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_s kernel_fpu_end(); } +static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb( + uint32_t hw_internal_rev) +{ + if (ASICREV_IS_NAVI12_P(hw_internal_rev)) + return &dcn2_0_nv12_soc; + + return &dcn2_0_soc; +} + +static struct _vcs_dpi_ip_params_st *get_asic_rev_ip_params( + uint32_t hw_internal_rev) +{ + /* NV12 and NV10 */ + return &dcn2_0_ip; +} + +static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) +{ + return DML_PROJECT_NAVI10v2; +} + #define fixed16_to_double(x) (((double) x) / ((double) (1 << 16))) #define fixed16_to_double_to_cpu(x) fixed16_to_double(le32_to_cpu(x)) @@ -2718,6 +3144,11 @@ 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; + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(dc->ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(dc->ctx->asic_id.hw_internal_rev); + DC_LOGGER_INIT(dc->ctx->logger); if (!bb && !SOC_BOUNDING_BOX_VALID) { @@ -2728,103 +3159,103 @@ static bool init_soc_bounding_box(struct dc *dc, if (bb && !SOC_BOUNDING_BOX_VALID) { int i; - dcn2_0_soc.sr_exit_time_us = + dcn2_0_nv12_soc.sr_exit_time_us = fixed16_to_double_to_cpu(bb->sr_exit_time_us); - dcn2_0_soc.sr_enter_plus_exit_time_us = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.urgent_latency_us = fixed16_to_double_to_cpu(bb->urgent_latency_us); - dcn2_0_soc.urgent_latency_pixel_data_only_us = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.writeback_latency_us = fixed16_to_double_to_cpu(bb->writeback_latency_us); - dcn2_0_soc.ideal_dram_bw_after_urgent_percent = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.max_request_size_bytes = le32_to_cpu(bb->max_request_size_bytes); - dcn2_0_soc.dram_channel_width_bytes = + dcn2_0_nv12_soc.dram_channel_width_bytes = le32_to_cpu(bb->dram_channel_width_bytes); - dcn2_0_soc.fabric_datapath_to_dcn_data_return_bytes = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.dcn_downspread_percent = fixed16_to_double_to_cpu(bb->dcn_downspread_percent); - dcn2_0_soc.downspread_percent = + dcn2_0_nv12_soc.downspread_percent = fixed16_to_double_to_cpu(bb->downspread_percent); - dcn2_0_soc.dram_page_open_time_ns = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.channel_interleave_bytes = le32_to_cpu(bb->channel_interleave_bytes); - dcn2_0_soc.num_banks = + dcn2_0_nv12_soc.num_banks = le32_to_cpu(bb->num_banks); - dcn2_0_soc.num_chans = + dcn2_0_nv12_soc.num_chans = le32_to_cpu(bb->num_chans); - dcn2_0_soc.vmm_page_size_bytes = + dcn2_0_nv12_soc.vmm_page_size_bytes = le32_to_cpu(bb->vmm_page_size_bytes); - dcn2_0_soc.dram_clock_change_latency_us = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.dram_clock_change_latency_us = 10; + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.return_bus_width_bytes = le32_to_cpu(bb->return_bus_width_bytes); - dcn2_0_soc.dispclk_dppclk_vco_speed_mhz = + dcn2_0_nv12_soc.dispclk_dppclk_vco_speed_mhz = le32_to_cpu(bb->dispclk_dppclk_vco_speed_mhz); - dcn2_0_soc.xfc_bus_transport_time_us = + dcn2_0_nv12_soc.xfc_bus_transport_time_us = le32_to_cpu(bb->xfc_bus_transport_time_us); - dcn2_0_soc.xfc_xbuf_latency_tolerance_us = + dcn2_0_nv12_soc.xfc_xbuf_latency_tolerance_us = le32_to_cpu(bb->xfc_xbuf_latency_tolerance_us); - dcn2_0_soc.use_urgent_burst_bw = + dcn2_0_nv12_soc.use_urgent_burst_bw = le32_to_cpu(bb->use_urgent_burst_bw); - dcn2_0_soc.num_states = + dcn2_0_nv12_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 = + for (i = 0; i < dcn2_0_nv12_soc.num_states; i++) { + dcn2_0_nv12_soc.clock_limits[i].state = le32_to_cpu(bb->clock_limits[i].state); - dcn2_0_soc.clock_limits[i].dcfclk_mhz = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_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 = + dcn2_0_nv12_soc.clock_limits[i].dram_speed_mts = fixed16_to_double_to_cpu(bb->clock_limits[i].dram_speed_mts); } } @@ -2833,7 +3264,6 @@ static bool init_soc_bounding_box(struct dc *dc, 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; @@ -2855,19 +3285,15 @@ static bool init_soc_bounding_box(struct dc *dc, 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); + update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states); else if (clock_limits_available) - cap_soc_clocks(&dcn2_0_soc, max_clocks); + cap_soc_clocks(loaded_bb, 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); + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; + patch_bounding_box(dc, loaded_bb); return true; } @@ -2880,19 +3306,30 @@ static bool construct( int i; struct dc_context *ctx = dc->ctx; struct irq_service_init_data init_data; + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(ctx->asic_id.hw_internal_rev); + enum dml_project dml_project_version = + get_dml_project_version(ctx->asic_id.hw_internal_rev); ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_nv10; pool->base.funcs = &dcn20_res_pool_funcs; + if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { + pool->base.res_cap = &res_cap_nv14; + pool->base.pipe_count = 5; + pool->base.mpcc_count = 5; + } else { + pool->base.res_cap = &res_cap_nv10; + pool->base.pipe_count = 6; + pool->base.mpcc_count = 6; + } /************************************************* * 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; @@ -2998,7 +3435,7 @@ static bool construct( goto create_fail; } - dml_init_instance(&dc->dml, &dcn2_0_soc, &dcn2_0_ip, DML_PROJECT_NAVI10); + dml_init_instance(&dc->dml, loaded_bb, loaded_ip, dml_project_version); if (!dc->debug.disable_pplib_wm_range) { struct pp_smu_wm_range_sets ranges = {0}; @@ -3006,7 +3443,7 @@ static bool construct( ranges.num_reader_wm_sets = 0; - if (dcn2_0_soc.num_states == 1) { + if (loaded_bb->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; @@ -3014,13 +3451,13 @@ static bool construct( 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++) { + } else if (loaded_bb->num_states > 1) { + for (i = 0; i < 4 && i < loaded_bb->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.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0; + ranges.reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16; ranges.num_reader_wm_sets = i + 1; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h index b5a75289f444..44f95aa0d61e 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h @@ -116,6 +116,18 @@ void dcn20_set_mcif_arb_params( display_e2e_pipe_params_st *pipes, int pipe_cnt); bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out); +void dcn20_calculate_dlg_params( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); 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); 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 index f5bcffc426b8..5ab9d6240498 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.c @@ -207,9 +207,8 @@ static void enc2_stream_encoder_stop_hdmi_info_packets( #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT - /* Update GSP7 SDP 128 byte long */ -static void enc2_send_gsp7_128_info_packet( +static void enc2_update_gsp7_128_info_packet( struct dcn10_stream_encoder *enc1, const struct dc_info_packet_128 *info_packet) { @@ -277,18 +276,9 @@ static void enc2_send_gsp7_128_info_packet( 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) + uint32_t dsc_slice_width) { 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, @@ -296,8 +286,16 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, REG_SET(DP_DSC_BYTES_PER_PIXEL, 0, DP_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); +} + + +static void enc2_dp_set_dsc_pps_info_packet(struct stream_encoder *enc, + bool enable, + uint8_t *dsc_packed_pps) +{ + struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc); - if (dsc_mode != OPTC_DSC_DISABLED) { + if (enable) { struct dc_info_packet_128 pps_sdp; ASSERT(dsc_packed_pps); @@ -309,7 +307,7 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, 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); + enc2_update_gsp7_128_info_packet(enc1, &pps_sdp); /* Enable Generic Stream Packet 7 (GSP) transmission */ //REG_UPDATE(DP_SEC_CNTL, @@ -340,9 +338,8 @@ static void enc2_dp_set_dsc_config(struct stream_encoder *enc, 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. */ @@ -373,7 +370,7 @@ static void enc2_read_state(struct stream_encoder *enc, struct enc_state *s) * * Ensure the OTG master update lock is set when changing DME configuration. */ -static void enc2_set_dynamic_metadata(struct stream_encoder *enc, +void enc2_set_dynamic_metadata(struct stream_encoder *enc, bool enable_dme, uint32_t hubp_requestor_id, enum dynamic_metadata_mode dmdata_mode) @@ -463,7 +460,7 @@ void enc2_stream_encoder_dp_unblank( 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) { + if (is_two_pixels_per_containter(¶m->timing) || param->opp_cnt > 1) { /*this logic should be the same in get_pixel_clock_parameters() */ n_multiply = 1; } @@ -580,14 +577,14 @@ static const struct stream_encoder_funcs dcn20_str_enc_funcs = { .setup_stereo_sync = enc1_setup_stereo_sync, .set_avmute = enc1_stream_encoder_set_avmute, .dig_connect_to_otg = enc1_dig_connect_to_otg, + .dig_source_otg = enc1_dig_source_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, + .dp_set_dsc_pps_info_packet = enc2_dp_set_dsc_pps_info_packet, #endif .set_dynamic_metadata = enc2_set_dynamic_metadata, + .hdmi_reset_stream_attribute = enc1_reset_hdmi_stream_attribute, }; void dcn20_stream_encoder_construct( 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 index 6d40e8c9b78f..3f94a9f13c4a 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_stream_encoder.h @@ -104,4 +104,9 @@ void enc2_stream_encoder_dp_unblank( struct stream_encoder *enc, const struct encoder_unblank_param *param); +void enc2_set_dynamic_metadata(struct stream_encoder *enc, + bool enable_dme, + uint32_t hubp_requestor_id, + enum dynamic_metadata_mode dmdata_mode); + #endif /* __DC_STREAM_ENCODER_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile new file mode 100644 index 000000000000..b2b39090fb57 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for DCN21. + +DCN21 = dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o + +CFLAGS_dcn21_resource.o := -mhard-float -msse -mpreferred-stack-boundary=4 + +AMD_DAL_DCN21 = $(addprefix $(AMDDALPATH)/dc/dcn21/,$(DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCN21) diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c new file mode 100644 index 000000000000..d1266741763b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.c @@ -0,0 +1,595 @@ +/* +* 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 "dm_services.h" +#include "dcn20/dcn20_hubbub.h" +#include "dcn21_hubbub.h" +#include "reg_helper.h" + +#define REG(reg)\ + hubbub1->regs->reg +#define DC_LOGGER \ + hubbub1->base.ctx->logger +#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 1 + +static uint32_t convert_and_clamp( + uint32_t wm_ns, + uint32_t refclk_mhz, + uint32_t clamp_value) +{ + uint32_t ret_val = 0; + ret_val = wm_ns * refclk_mhz; + ret_val /= 1000; + + if (ret_val > clamp_value) + ret_val = clamp_value; + + return ret_val; +} + +void dcn21_dchvm_init(struct hubbub *hubbub) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + + //Init DCHVM block + REG_UPDATE(DCHVM_CTRL0, HOSTVM_INIT_REQ, 1); + + //Poll until RIOMMU_ACTIVE = 1 + //TODO: Figure out interval us and retry count + REG_WAIT(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, 1, 5, 100); + + //Reflect the power status of DCHUBBUB + REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1); + + //Start rIOMMU prefetching + REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1); + + // Enable dynamic clock gating + REG_UPDATE_4(DCHVM_CLK_CTRL, + HVM_DISPCLK_R_GATE_DIS, 0, + HVM_DISPCLK_G_GATE_DIS, 0, + HVM_DCFCLK_R_GATE_DIS, 0, + HVM_DCFCLK_G_GATE_DIS, 0); + + //Poll until HOSTVM_PREFETCH_DONE = 1 + //TODO: Figure out interval us and retry count + REG_WAIT(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, 1, 5, 100); +} + +static int hubbub21_init_dchub(struct hubbub *hubbub, + struct dcn_hubbub_phys_addr_config *pa_config) +{ + struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub); + + 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); + + dcn21_dchvm_init(hubbub); + + return NUM_VMID; +} + +static void hubbub21_program_urgent_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); + uint32_t prog_wm_value; + + /* Repeat for water mark set A, B, C and D. */ + /* clock state A */ + if (safe_to_lower || watermarks->a.urgent_ns > hubbub1->watermarks.a.urgent_ns) { + hubbub1->watermarks.a.urgent_ns = watermarks->a.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + } + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->a.frac_urg_bw_flip + > hubbub1->watermarks.a.frac_urg_bw_flip) { + hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, watermarks->a.frac_urg_bw_flip); + } + + if (safe_to_lower || watermarks->a.frac_urg_bw_nom + > hubbub1->watermarks.a.frac_urg_bw_nom) { + hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, watermarks->a.frac_urg_bw_nom); + } + + /* clock state B */ + if (safe_to_lower || watermarks->b.urgent_ns > hubbub1->watermarks.b.urgent_ns) { + hubbub1->watermarks.b.urgent_ns = watermarks->b.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->b.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + } + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->a.frac_urg_bw_flip + > hubbub1->watermarks.a.frac_urg_bw_flip) { + hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, watermarks->a.frac_urg_bw_flip); + } + + if (safe_to_lower || watermarks->a.frac_urg_bw_nom + > hubbub1->watermarks.a.frac_urg_bw_nom) { + hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, watermarks->a.frac_urg_bw_nom); + } + + /* clock state C */ + if (safe_to_lower || watermarks->c.urgent_ns > hubbub1->watermarks.c.urgent_ns) { + hubbub1->watermarks.c.urgent_ns = watermarks->c.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->c.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + } + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->a.frac_urg_bw_flip + > hubbub1->watermarks.a.frac_urg_bw_flip) { + hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, watermarks->a.frac_urg_bw_flip); + } + + if (safe_to_lower || watermarks->a.frac_urg_bw_nom + > hubbub1->watermarks.a.frac_urg_bw_nom) { + hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, watermarks->a.frac_urg_bw_nom); + } + + /* clock state D */ + if (safe_to_lower || watermarks->d.urgent_ns > hubbub1->watermarks.d.urgent_ns) { + hubbub1->watermarks.d.urgent_ns = watermarks->d.urgent_ns; + prog_wm_value = convert_and_clamp(watermarks->d.urgent_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, 0, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, prog_wm_value); + + DC_LOG_BANDWIDTH_CALCS("URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + } + + /* determine the transfer time for a quantity of data for a particular requestor.*/ + if (safe_to_lower || watermarks->a.frac_urg_bw_flip + > hubbub1->watermarks.a.frac_urg_bw_flip) { + hubbub1->watermarks.a.frac_urg_bw_flip = watermarks->a.frac_urg_bw_flip; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, 0, + DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, watermarks->a.frac_urg_bw_flip); + } + + if (safe_to_lower || watermarks->a.frac_urg_bw_nom + > hubbub1->watermarks.a.frac_urg_bw_nom) { + hubbub1->watermarks.a.frac_urg_bw_nom = watermarks->a.frac_urg_bw_nom; + + REG_SET(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, 0, + DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, watermarks->a.frac_urg_bw_nom); + } +} + +static void hubbub21_program_stutter_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); + uint32_t prog_wm_value; + + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->a.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.a.cstate_pstate.cstate_exit_ns = + watermarks->a.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->b.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.b.cstate_pstate.cstate_exit_ns = + watermarks->b.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->c.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.c.cstate_pstate.cstate_exit_ns = + watermarks->c.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + /* clock state D */ + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns + > hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_ENTER_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + } + + if (safe_to_lower || watermarks->d.cstate_pstate.cstate_exit_ns + > hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns) { + hubbub1->watermarks.d.cstate_pstate.cstate_exit_ns = + watermarks->d.cstate_pstate.cstate_exit_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } +} + +static void hubbub21_program_pstate_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); + uint32_t prog_wm_value; + + /* clock state A */ + if (safe_to_lower || watermarks->a.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.a.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.a.cstate_pstate.pstate_change_ns = + watermarks->a.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); + } + + /* clock state B */ + if (safe_to_lower || watermarks->b.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.b.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.b.cstate_pstate.pstate_change_ns = + watermarks->b.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); + } + + /* clock state C */ + if (safe_to_lower || watermarks->c.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.c.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.c.cstate_pstate.pstate_change_ns = + watermarks->c.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); + } + + /* clock state D */ + if (safe_to_lower || watermarks->d.cstate_pstate.pstate_change_ns + > hubbub1->watermarks.d.cstate_pstate.pstate_change_ns) { + hubbub1->watermarks.d.cstate_pstate.pstate_change_ns = + watermarks->d.cstate_pstate.pstate_change_ns; + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_SET_2(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, 0, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value, + DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + DC_LOG_BANDWIDTH_CALCS("DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + } +} + +void hubbub21_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); + + hubbub21_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub21_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + hubbub21_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + + /* + * The DCHub arbiter has a mechanism to dynamically rate limit the DCHub request stream to the fabric. + * If the memory controller is fully utilized and the DCHub requestors are + * well ahead of their amortized schedule, then it is safe to prevent the next winner + * from being committed and sent to the fabric. + * The utilization of the memory controller is approximated by ensuring that + * the number of outstanding requests is greater than a threshold specified + * by the ARB_MIN_REQ_OUTSTANDING. To determine that the DCHub requestors are well ahead of the amortized schedule, + * the slack of the next winner is compared with the ARB_SAT_LEVEL in DLG RefClk cycles. + * + * TODO: Revisit request limit after figure out right number. request limit for Renoir isn't decided yet, set maximum value (0x1FF) + * to turn off it for now. + */ + REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0, + DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); + REG_UPDATE_2(DCHUBBUB_ARB_DF_REQ_OUTSTAND, + DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 0x1FF, + DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, 0xA); + REG_UPDATE(DCHUBBUB_ARB_HOSTVM_CNTL, + DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, 0xF); + + hubbub1_allow_self_refresh_control(hubbub, !hubbub->ctx->dc->debug.disable_stutter); +} + +void hubbub21_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; + REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, &s->data_urgent); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, &s->sr_enter); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, &s->sr_exit); + + REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, &s->dram_clk_chanage); + + s = &wm->sets[1]; + s->wm_set = 1; + REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, &s->data_urgent); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, &s->sr_enter); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, &s->sr_exit); + + REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, &s->dram_clk_chanage); + + s = &wm->sets[2]; + s->wm_set = 2; + REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, &s->data_urgent); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, &s->sr_enter); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, &s->sr_exit); + + REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, &s->dram_clk_chanage); + + s = &wm->sets[3]; + s->wm_set = 3; + REG_GET(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, + DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, &s->data_urgent); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, + DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, &s->sr_enter); + + REG_GET(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, + DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, &s->sr_exit); + + REG_GET(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, + DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, &s->dram_clk_chanage); +} + + +static const struct hubbub_funcs hubbub21_funcs = { + .update_dchub = hubbub2_update_dchub, + .init_dchub_sys_ctx = hubbub21_init_dchub, + .init_vm_ctx = NULL, + .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 = hubbub21_wm_read_state, + .get_dchub_ref_freq = hubbub2_get_dchub_ref_freq, + .program_watermarks = hubbub21_program_watermarks, +}; + +void hubbub21_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 = &hubbub21_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/dcn21/dcn21_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.h new file mode 100644 index 000000000000..6ff3cdb89178 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubbub.h @@ -0,0 +1,132 @@ +/* +* 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_DCN21_DCN21_HUBBUB_H_ +#define DAL_DC_DCN21_DCN21_HUBBUB_H_ + +#include "dcn20/dcn20_hubbub.h" + +#define HUBBUB_HVM_REG_LIST() \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C),\ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D),\ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DCHVM_CTRL0), \ + SR(DCHVM_MEM_CTRL), \ + SR(DCHVM_CLK_CTRL), \ + SR(DCHVM_RIOMMU_CTRL0), \ + SR(DCHVM_RIOMMU_STAT0) + +#define HUBBUB_REG_LIST_DCN21()\ + HUBBUB_REG_LIST_DCN_COMMON(), \ + HUBBUB_SR_WATERMARK_REG_LIST(), \ + HUBBUB_HVM_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_HVM(mask_sh) \ + HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND_COMMIT_THRESHOLD, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, DCHUBBUB_ARB_FRAC_URG_BW_NOM_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, DCHUBBUB_ARB_FRAC_URG_BW_NOM_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, DCHUBBUB_ARB_VM_ROW_URGENCY_WATERMARK_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_ENTER_WATERMARK_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, DCHUBBUB_ARB_VM_ROW_ALLOW_SR_EXIT_WATERMARK_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, DCHUBBUB_ARB_VM_ROW_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_HOSTVM_CNTL, DCHUBBUB_ARB_MAX_QOS_COMMIT_THRESHOLD, mask_sh), \ + HUBBUB_SF(DCHVM_CTRL0, HOSTVM_INIT_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_FORCE_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_MEM_CTRL, HVM_GPUVMRET_POWER_STATUS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_R_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DISPCLK_G_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_R_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, HVM_DCFCLK_G_GATE_DIS, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, TR_REQ_REQCLKREQ_MODE, mask_sh), \ + HUBBUB_SF(DCHVM_CLK_CTRL, TW_RSP_COMPCLKREQ_MODE, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, RIOMMU_ACTIVE, mask_sh), \ + HUBBUB_SF(DCHVM_RIOMMU_STAT0, HOSTVM_PREFETCH_DONE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D, mask_sh) + +#define HUBBUB_MASK_SH_LIST_DCN21(mask_sh)\ + HUBBUB_MASK_SH_LIST_HVM(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) + +void dcn21_dchvm_init(struct hubbub *hubbub); +void hubbub21_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +void hubbub21_wm_read_state(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm); + +void hubbub21_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); + +#endif /* DAL_DC_DCN21_DCN21_HUBBUB_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c new file mode 100644 index 000000000000..a00af513aa2b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c @@ -0,0 +1,244 @@ +/* +* 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 "dcn21_hubp.h" + +#include "dm_services.h" +#include "reg_helper.h" + +#define REG(reg)\ + hubp21->hubp_regs->reg + +#define CTX \ + hubp21->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubp21->hubp_shift->field_name, hubp21->hubp_mask->field_name + +/* + * In DCN2.1, the non-double buffered version of the following 4 DLG registers are used in RTL. + * As a result, if S/W updates any of these registers during a mode change, + * the current frame before the mode change will use the new value right away + * and can lead to generating incorrect request deadlines and incorrect TTU/QoS behavior. + * + * REFCYC_PER_VM_GROUP_FLIP[22:0] + * REFCYC_PER_VM_GROUP_VBLANK[22:0] + * REFCYC_PER_VM_REQ_FLIP[22:0] + * REFCYC_PER_VM_REQ_VBLANK[22:0] + * + * REFCYC_PER_VM_*_FLIP affects the deadline of the VM requests generated + * when flipping to a new surface + * + * REFCYC_PER_VM_*_VBLANK affects the deadline of the VM requests generated + * during prefetch period of a frame. The prefetch starts at a pre-determined + * number of lines before the display active per frame + * + * DCN may underflow due to incorrectly programming these registers + * during VM stage of prefetch/iflip. First lines of display active + * or a sub-region of active using a new surface will be corrupted + * until the VM data returns at flip/mode change transitions + * + * Work around: + * workaround is always opt to use the more aggressive settings. + * On any mode switch, if the new reg values are smaller than the current values, + * then update the regs with the new values. + * + * Link to the ticket: http://ontrack-internal.amd.com/browse/DEDCN21-142 + * + */ +void apply_DEDCN21_142_wa_for_hostvm_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr) +{ + struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp); + uint32_t cur_value; + + REG_GET(VBLANK_PARAMETERS_5, REFCYC_PER_VM_GROUP_VBLANK, &cur_value); + if (cur_value > dlg_attr->refcyc_per_vm_group_vblank) + REG_SET(VBLANK_PARAMETERS_5, 0, + REFCYC_PER_VM_GROUP_VBLANK, dlg_attr->refcyc_per_vm_group_vblank); + + REG_GET(VBLANK_PARAMETERS_6, + REFCYC_PER_VM_REQ_VBLANK, + &cur_value); + if (cur_value > dlg_attr->refcyc_per_vm_req_vblank) + REG_SET(VBLANK_PARAMETERS_6, 0, + REFCYC_PER_VM_REQ_VBLANK, dlg_attr->refcyc_per_vm_req_vblank); + + REG_GET(FLIP_PARAMETERS_3, REFCYC_PER_VM_GROUP_FLIP, &cur_value); + if (cur_value > dlg_attr->refcyc_per_vm_group_flip) + REG_SET(FLIP_PARAMETERS_3, 0, + REFCYC_PER_VM_GROUP_FLIP, dlg_attr->refcyc_per_vm_group_flip); + + REG_GET(FLIP_PARAMETERS_4, REFCYC_PER_VM_REQ_FLIP, &cur_value); + if (cur_value > dlg_attr->refcyc_per_vm_req_flip) + REG_SET(FLIP_PARAMETERS_4, 0, + REFCYC_PER_VM_REQ_FLIP, dlg_attr->refcyc_per_vm_req_flip); + + REG_SET(FLIP_PARAMETERS_5, 0, + REFCYC_PER_PTE_GROUP_FLIP_C, dlg_attr->refcyc_per_pte_group_flip_c); + REG_SET(FLIP_PARAMETERS_6, 0, + REFCYC_PER_META_CHUNK_FLIP_C, dlg_attr->refcyc_per_meta_chunk_flip_c); +} + +void hubp21_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + hubp2_program_deadline(hubp, dlg_attr, ttu_attr); + + apply_DEDCN21_142_wa_for_hostvm_deadline(hubp, dlg_attr); +} + +void hubp21_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs) +{ + struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp); + + REG_UPDATE(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, rq_regs->plane1_base_address); + REG_SET_4(DCN_EXPANSION_MODE, 0, + DRQ_EXPANSION_MODE, rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, rq_regs->crq_expansion_mode); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG, 0, + CHUNK_SIZE, rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, rq_regs->rq_regs_l.dpte_group_size, + VM_GROUP_SIZE, rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, rq_regs->rq_regs_l.pte_row_height_linear); + REG_SET_7(DCHUBP_REQ_SIZE_CONFIG_C, 0, + CHUNK_SIZE_C, rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.dpte_group_size, + SWATH_HEIGHT_C, rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, rq_regs->rq_regs_c.pte_row_height_linear); +} + +static void hubp21_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); + hubp21_program_requestor(hubp, rq_regs); + hubp21_program_deadline(hubp, dlg_attr, ttu_attr); + +} + +void hubp21_set_vm_system_aperture_settings(struct hubp *hubp, + struct vm_system_aperture_param *apt) +{ + struct dcn21_hubp *hubp21 = TO_DCN21_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_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 hubp21_init(struct hubp *hubp) +{ + // DEDCN21-133: Inconsistent row starting line for flip between DPTE and Meta + // This is a chicken bit to enable the ECO fix. + + struct dcn21_hubp *hubp21 = TO_DCN21_HUBP(hubp); + //hubp[i].HUBPREQ_DEBUG.HUBPREQ_DEBUG[26] = 1; + REG_WRITE(HUBPREQ_DEBUG, 1 << 26); +} +static struct hubp_funcs dcn21_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 = hubp21_setup, + .hubp_setup_interdependent = hubp2_setup_interdependent, + .hubp_set_vm_system_aperture_settings = hubp21_set_vm_system_aperture_settings, + .set_blank = hubp1_set_blank, + .dcc_control = hubp1_dcc_control, + .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 = hubp21_init, +}; + +bool hubp21_construct( + struct dcn21_hubp *hubp21, + 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) +{ + hubp21->base.funcs = &dcn21_hubp_funcs; + hubp21->base.ctx = ctx; + hubp21->hubp_regs = hubp_regs; + hubp21->hubp_shift = hubp_shift; + hubp21->hubp_mask = hubp_mask; + hubp21->base.inst = inst; + hubp21->base.opp_id = OPP_ID_INVALID; + hubp21->base.mpcc_id = 0xf; + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.h new file mode 100644 index 000000000000..aeda719a2a13 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.h @@ -0,0 +1,133 @@ +/* +* 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_DCN21_DCN21_HUBP_H_ +#define DAL_DC_DCN21_DCN21_HUBP_H_ + +#include "../dcn20/dcn20_hubp.h" +#include "../dcn10/dcn10_hubp.h" + +#define TO_DCN21_HUBP(hubp)\ + container_of(hubp, struct dcn21_hubp, base) + +#define HUBP_REG_LIST_DCN21(id)\ + HUBP_REG_LIST_DCN2_COMMON(id),\ + SRI(FLIP_PARAMETERS_3, HUBPREQ, id),\ + SRI(FLIP_PARAMETERS_4, HUBPREQ, id),\ + SRI(FLIP_PARAMETERS_5, HUBPREQ, id),\ + SRI(FLIP_PARAMETERS_6, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_5, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_6, HUBPREQ, id) + +#define HUBP_MASK_SH_LIST_DCN21_COMMON(mask_sh)\ + HUBP_MASK_SH_LIST_DCN_SHARE_COMMON(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(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),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_3, REFCYC_PER_VM_GROUP_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_4, REFCYC_PER_VM_REQ_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_5, REFCYC_PER_PTE_GROUP_FLIP_C, mask_sh),\ + HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_6, REFCYC_PER_META_CHUNK_FLIP_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_5, REFCYC_PER_VM_GROUP_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_6, REFCYC_PER_VM_REQ_VBLANK, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, VM_GROUP_SIZE, mask_sh) + +#define HUBP_MASK_SH_LIST_DCN21(mask_sh)\ + HUBP_MASK_SH_LIST_DCN21_COMMON(mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh) + + +struct dcn21_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 hubp21_construct( + struct dcn21_hubp *hubp21, + 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 apply_DEDCN21_142_wa_for_hostvm_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr); + +void hubp21_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr); + +void hubp21_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs); +#endif /* DAL_DC_DCN21_DCN21_HUBP_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c new file mode 100644 index 000000000000..3ca5139f1273 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c @@ -0,0 +1,1680 @@ +/* +* 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 "dm_services.h" +#include "dc.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn20/dcn20_resource.h" + +#include "clk_mgr.h" +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn20/dcn20_hubbub.h" +#include "dcn20/dcn20_mpc.h" +#include "dcn20/dcn20_hubp.h" +#include "dcn21_hubp.h" +#include "irq/dcn21/irq_service_dcn21.h" +#include "dcn20/dcn20_dpp.h" +#include "dcn20/dcn20_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn20/dcn20_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn20/dcn20_link_encoder.h" +#include "dcn20/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/dcn20_dccg.h" +#include "dcn21_hubbub.h" +#include "dcn10/dcn10_resource.h" + +#include "dcn20/dcn20_dwb.h" +#include "dcn20/dcn20_mmhubbub.h" + +#include "renoir_ip_offset.h" +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" + +#include "nbio/nbio_7_0_offset.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 "dcn21_resource.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#define SOC_BOUNDING_BOX_VALID false +#define DC_LOGGER_INIT(logger) + + +struct _vcs_dpi_ip_params_st dcn2_1_ip = { + .gpuvm_enable = 0, + .hostvm_enable = 0, + .gpuvm_max_page_table_levels = 1, + .hostvm_max_page_table_levels = 4, + .hostvm_cached_page_table_levels = 2, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .num_dsc = 3, +#else + .num_dsc = 0, +#endif + .rob_buffer_size_kbytes = 168, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs_luma = 44, + .dpte_buffer_size_in_pte_reqs_chroma = 42,//todo + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_enable = 1, + .max_page_table_levels = 4, + .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 = 4, + .max_num_dpp = 4, + .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 = 4, + .max_vscl_ratio = 4, + .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 = false, + .xfc_fill_bw_overhead_percent = 10.0, + .xfc_fill_constant_bytes = 0, + .ptoi_supported = 0 +}; + +struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = { + .clock_limits = { + { + .state = 0, + .dcfclk_mhz = 304.0, + .fabricclk_mhz = 600.0, + .dispclk_mhz = 618.0, + .dppclk_mhz = 440.0, + .phyclk_mhz = 600.0, + .socclk_mhz = 278.0, + .dscclk_mhz = 205.67, + .dram_speed_mts = 1600.0, + }, + { + .state = 1, + .dcfclk_mhz = 304.0, + .fabricclk_mhz = 600.0, + .dispclk_mhz = 618.0, + .dppclk_mhz = 618.0, + .phyclk_mhz = 600.0, + .socclk_mhz = 278.0, + .dscclk_mhz = 205.67, + .dram_speed_mts = 1600.0, + }, + { + .state = 2, + .dcfclk_mhz = 608.0, + .fabricclk_mhz = 1066.0, + .dispclk_mhz = 888.0, + .dppclk_mhz = 888.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 278.0, + .dscclk_mhz = 287.67, + .dram_speed_mts = 2133.0, + }, + { + .state = 3, + .dcfclk_mhz = 676.0, + .fabricclk_mhz = 1600.0, + .dispclk_mhz = 1015.0, + .dppclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 715.0, + .dscclk_mhz = 318.334, + .dram_speed_mts = 4266.0, + }, + { + .state = 4, + .dcfclk_mhz = 810.0, + .fabricclk_mhz = 1600.0, + .dispclk_mhz = 1015.0, + .dppclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 953.0, + .dscclk_mhz = 318.334, + .dram_speed_mts = 4266.0, + }, + /*Extra state, no dispclk ramping*/ + { + .state = 5, + .dcfclk_mhz = 810.0, + .fabricclk_mhz = 1600.0, + .dispclk_mhz = 1015.0, + .dppclk_mhz = 1015.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 953.0, + .dscclk_mhz = 318.334, + .dram_speed_mts = 4266.0, + }, + + }, + + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0, + .max_avg_sdp_bw_use_normal_percent = 60.0, + .max_avg_dram_bw_use_normal_percent = 100.0, + .writeback_latency_us = 12.0, + .max_request_size_bytes = 256, + .dram_channel_width_bytes = 4, + .fabric_datapath_to_dcn_data_return_bytes = 32, + .dcn_downspread_percent = 0.5, + .downspread_percent = 0.5, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 128, + .urgent_out_of_order_return_per_channel_bytes = 4096, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 4, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 23.84, + .return_bus_width_bytes = 64, + .dispclk_dppclk_vco_speed_mhz = 3550, + .xfc_bus_transport_time_us = 4, + .xfc_xbuf_latency_tolerance_us = 4, + .use_urgent_burst_bw = 1, + .num_states = 5 +}; + +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + +/* 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) DMU_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) \ + NBIF0_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 + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN2_1(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), +}; + +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 bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#ifdef CONFIG_DRM_AMD_DC_DMUB +static const struct dcn21_dmcub_registers dmcub_regs = { + DMCUB_REG_LIST_DCN() +}; + +static const struct dcn21_dmcub_shift dmcub_shift = { + DMCUB_COMMON_MASK_SH_LIST_BASE(__SHIFT) +}; + +static const struct dcn21_dmcub_mask dmcub_mask = { + DMCUB_COMMON_MASK_SH_LIST_BASE(_MASK) +}; +#endif + +#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), +}; + +#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_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_COMMON_REG_LIST_DCN_BASE() +}; + +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) +}; + +#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 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) +}; + +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) +}; + +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) +}; + +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 hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN21(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN21(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN21(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN21() +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN21(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN21(_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 + +#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), +}; + +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),\ +} + + +#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), +}; + +#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), +}; + +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 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), +}; + +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) +}; + +static struct input_pixel_processor *dcn21_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; +} + +static struct dpp *dcn21_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; +} + +static struct dce_aux *dcn21_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), +}; + +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 *dcn21_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; +} + +static const struct resource_caps res_cap_rn = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 6, // 6 audio endpoints. 4 audio streams + .num_stream_encoder = 5, + .num_pll = 5, // maybe 3 because the last two used for USB-c + .num_dwb = 1, + .num_ddc = 5, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .num_dsc = 3, +#endif +}; + +#ifdef DIAGS_BUILD +static const struct resource_caps res_cap_rn_FPGA_4pipe = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 7, + .num_stream_encoder = 4, + .num_pll = 4, + .num_dwb = 1, + .num_ddc = 4, + .num_dsc = 0, +}; + +static const struct resource_caps res_cap_rn_FPGA_2pipe_dsc = { + .num_timing_generator = 2, + .num_opp = 2, + .num_video_plane = 2, + .num_audio = 7, + .num_stream_encoder = 2, + .num_pll = 4, + .num_dwb = 1, + .num_ddc = 4, +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + .num_dsc = 2, +#endif +}; +#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 = 16000 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 250 + } +}; + +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_AVOID_MULT_DISP, + .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 = true, + .disable_48mhz_pwrdwn = true, +}; + +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, + .disable_48mhz_pwrdwn = true, +}; + +enum dcn20_clk_src_array_id { + DCN20_CLK_SRC_PLL0, + DCN20_CLK_SRC_PLL1, + DCN20_CLK_SRC_TOTAL_DCN21 +}; + +static void destruct(struct dcn21_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); + +#ifdef CONFIG_DRM_AMD_DC_DMUB + if (pool->base.dmcub != NULL) + dcn21_dmcub_destroy(&pool->base.dmcub); +#endif + + 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); +} + + +static void calculate_wm_set_for_vlevel( + int vlevel, + struct wm_range_table_entry *table_entry, + struct dcn_watermarks *wm_set, + struct display_mode_lib *dml, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; + + ASSERT(vlevel < dml->soc.num_states); + /* only pipe 0 is read for voltage and dcf/soc clocks */ + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; + pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; + + dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; + + wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; + wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; + wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; + wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; +#endif + dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; + +} + +void dcn21_calculate_wm( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *out_pipe_cnt, + int *pipe_split_from, + int vlevel_req) +{ + int pipe_cnt, i, pipe_idx; + int vlevel, vlevel_max; + struct wm_range_table_entry *table_entry; + struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; + + ASSERT(bw_params); + + 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_req][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_req][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_req][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_req][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_req][pipe_split_from[i]]; + else + pipes[pipe_cnt].pipe.dest.odm_combine = 0; + } + 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); + } + + *out_pipe_cnt = pipe_cnt; + + vlevel_max = bw_params->clk_table.num_entries - 1; + + + /* WM Set D */ + table_entry = &bw_params->wm_table.entries[WM_D]; + if (table_entry->wm_type == WM_TYPE_RETRAINING) + vlevel = 0; + else + vlevel = vlevel_max; + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, + &context->bw_ctx.dml, pipes, pipe_cnt); + /* WM Set C */ + table_entry = &bw_params->wm_table.entries[WM_C]; + vlevel = MIN(MAX(vlevel_req, 2), vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, + &context->bw_ctx.dml, pipes, pipe_cnt); + /* WM Set B */ + table_entry = &bw_params->wm_table.entries[WM_B]; + vlevel = MIN(MAX(vlevel_req, 1), vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, + &context->bw_ctx.dml, pipes, pipe_cnt); + + /* WM Set A */ + table_entry = &bw_params->wm_table.entries[WM_A]; + vlevel = MIN(vlevel_req, vlevel_max); + calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, + &context->bw_ctx.dml, pipes, pipe_cnt); +} + + +bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + BW_VAL_TRACE_SETUP(); + + int vlevel = 0; + int pipe_split_from[MAX_PIPES]; + int pipe_cnt = 0; + 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(); + + out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel); + + if (pipe_cnt == 0) + goto validate_out; + + if (!out) + goto validate_fail; + + BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + + if (fast_validate) { + BW_VAL_TRACE_SKIP(fast); + goto validate_out; + } + + dcn21_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel); + dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); + + BW_VAL_TRACE_END_WATERMARKS(); + + 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; +} +static void dcn21_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn21_resource_pool *dcn21_pool = TO_DCN21_RES_POOL(*pool); + + destruct(dcn21_pool); + kfree(dcn21_pool); + *pool = NULL; +} + +static struct clock_source *dcn21_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 struct hubp *dcn21_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn21_hubp *hubp21 = + kzalloc(sizeof(struct dcn21_hubp), GFP_KERNEL); + + if (!hubp21) + return NULL; + + if (hubp21_construct(hubp21, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp21->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp21); + return NULL; +} + +static struct hubbub *dcn21_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub) + return NULL; + + hubbub21_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + for (i = 0; i < res_cap_rn.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 output_pixel_processor *dcn21_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 timing_generator *dcn21_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; +} + +struct mpc *dcn21_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; +} + +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); + +} + +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + +struct display_stream_compressor *dcn21_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; +} +#endif + +static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool); + struct clk_limit_table *clk_table = &bw_params->clk_table; + int i; + + dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator; + dcn2_1_ip.max_num_dpp = pool->base.pipe_count; + dcn2_1_soc.num_chans = bw_params->num_channels; + dcn2_1_soc.num_states = 0; + + for (i = 0; i < clk_table->num_entries; i++) { + + dcn2_1_soc.clock_limits[i].state = i; + dcn2_1_soc.clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz; + dcn2_1_soc.clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz; + dcn2_1_soc.clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz; + /* This is probably wrong, TODO: find correct calculation */ + dcn2_1_soc.clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 16 / 1000; + dcn2_1_soc.num_states++; + } +} + +/* Temporary Place holder until we can get them from fuse */ +static struct dpm_clocks dummy_clocks = { + .DcfClocks = { + {.Freq = 400, .Vol = 1}, + {.Freq = 483, .Vol = 1}, + {.Freq = 602, .Vol = 1}, + {.Freq = 738, .Vol = 1} }, + .SocClocks = { + {.Freq = 300, .Vol = 1}, + {.Freq = 400, .Vol = 1}, + {.Freq = 400, .Vol = 1}, + {.Freq = 400, .Vol = 1} }, + .FClocks = { + {.Freq = 400, .Vol = 1}, + {.Freq = 800, .Vol = 1}, + {.Freq = 1067, .Vol = 1}, + {.Freq = 1600, .Vol = 1} }, + .MemClocks = { + {.Freq = 800, .Vol = 1}, + {.Freq = 1600, .Vol = 1}, + {.Freq = 1067, .Vol = 1}, + {.Freq = 1600, .Vol = 1} }, + +}; + +enum pp_smu_status dummy_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + return PP_SMU_RESULT_OK; +} + +enum pp_smu_status dummy_get_dpm_clock_table(struct pp_smu *pp, + struct dpm_clocks *clock_table) +{ + *clock_table = dummy_clocks; + return PP_SMU_RESULT_OK; +} + +struct pp_smu_funcs *dcn21_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); + + pp_smu->ctx.ver = PP_SMU_VER_RN; + + pp_smu->rn_funcs.get_dpm_clock_table = dummy_get_dpm_clock_table; + pp_smu->rn_funcs.set_wm_ranges = dummy_set_wm_ranges; + + return pp_smu; +} + +void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu) +{ + if (pp_smu && *pp_smu) { + kfree(*pp_smu); + *pp_smu = NULL; + } +} + +static struct audio *dcn21_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +struct stream_encoder *dcn21_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_DCN21_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN21_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN21_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn21_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 = dcn21_create_audio, + .create_stream_encoder = dcn21_stream_encoder_create, + .create_hwseq = dcn21_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 = dcn21_hwseq_create, +}; + +static struct resource_funcs dcn21_res_pool_funcs = { + .destroy = dcn21_destroy_resource_pool, + .link_enc_create = dcn20_link_encoder_create, + .validate_bandwidth = dcn21_validate_bandwidth, + .add_stream_to_ctx = dcn20_add_stream_to_ctx, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, + .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, + .update_bw_bounding_box = update_bw_bounding_box +}; + +static bool construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn21_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_rn; +#ifdef DIAGS_BUILD + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + //pool->base.res_cap = &res_cap_nv10_FPGA_2pipe_dsc; + pool->base.res_cap = &res_cap_rn_FPGA_4pipe; +#endif + + pool->base.funcs = &dcn21_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + pool->base.pipe_count = 4; + 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.hw_3d_lut = true; + + dc->caps.max_slave_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = 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; + dc->debug = debug_defaults_diags; + } else + dc->debug = debug_defaults_diags; + + // 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] = + dcn21_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] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + + pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN21; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn21_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; + } + +#ifdef CONFIG_DRM_AMD_DC_DMUB + pool->base.dmcub = dcn21_dmcub_create(ctx, + &dmcub_regs, + &dmcub_shift, + &dmcub_mask); + if (pool->base.dmcub == NULL) { + dm_error("DC: failed to create dmcub!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } +#endif + + pool->base.pp_smu = dcn21_pp_smu_create(ctx); + + dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21); + + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn21_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] = dcn21_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] = dcn21_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] = dcn21_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] = dcn21_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] = dcn21_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] = dcn21_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] = dcn21_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 = dcn21_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 = dcn21_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] = dcn21_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 *dcn21_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn21_resource_pool *pool = + kzalloc(sizeof(struct dcn21_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/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h new file mode 100644 index 000000000000..a27355171bca --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h @@ -0,0 +1,45 @@ +/* + * 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 _DCN21_RESOURCE_H_ +#define _DCN21_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN21_RES_POOL(pool)\ + container_of(pool, struct dcn21_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +struct dcn21_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn21_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN21_RESOURCE_H_ */ 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 680689cab5dd..c03a441ee638 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -44,6 +44,9 @@ enum pp_smu_ver { #ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 PP_SMU_VER_NV, #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + PP_SMU_VER_RN, +#endif PP_SMU_VER_MAX }; @@ -246,6 +249,47 @@ struct pp_smu_funcs_nv { }; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + +#define PP_SMU_NUM_SOCCLK_DPM_LEVELS 8 +#define PP_SMU_NUM_DCFCLK_DPM_LEVELS 4 +#define PP_SMU_NUM_FCLK_DPM_LEVELS 4 +#define PP_SMU_NUM_MEMCLK_DPM_LEVELS 4 + +struct dpm_clock { + uint32_t Freq; // In MHz + uint32_t Vol; // Millivolts with 2 fractional bits +}; + + +/* this is a copy of the structure defined in smuxx_driver_if.h*/ +struct dpm_clocks { + struct dpm_clock DcfClocks[PP_SMU_NUM_DCFCLK_DPM_LEVELS]; + struct dpm_clock SocClocks[PP_SMU_NUM_SOCCLK_DPM_LEVELS]; + struct dpm_clock FClocks[PP_SMU_NUM_FCLK_DPM_LEVELS]; + struct dpm_clock MemClocks[PP_SMU_NUM_MEMCLK_DPM_LEVELS]; +}; + + +struct pp_smu_funcs_rn { + struct pp_smu pp_smu; + + /* + * reader and writer WM's are sent together as part of one table + * + * PPSMC_MSG_SetDriverDramAddrHigh + * PPSMC_MSG_SetDriverDramAddrLow + * PPSMC_MSG_TransferTableDram2Smu + * + */ + enum pp_smu_status (*set_wm_ranges)(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges); + + enum pp_smu_status (*get_dpm_clock_table) (struct pp_smu *pp, + struct dpm_clocks *clock_table); +}; +#endif + struct pp_smu_funcs { struct pp_smu ctx; union { @@ -253,6 +297,9 @@ struct pp_smu_funcs { #ifndef CONFIG_TRIM_DRM_AMD_DC_DCN2_0 struct pp_smu_funcs_nv nv_funcs; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + struct pp_smu_funcs_rn rn_funcs; +#endif }; }; diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index b426ba02b793..1a0429744630 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -151,6 +151,7 @@ void generic_reg_wait(const struct dc_context *ctx, unsigned int delay_between_poll_us, unsigned int time_out_num_tries, const char *func_name, int line); +unsigned int snprintf_count(char *pBuf, unsigned int bufSize, char *fmt, ...); /* These macros need to be used with soc15 registers in order to retrieve * the actual offset. diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile index 0bb7a20675c4..af2a864a6da0 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile @@ -32,12 +32,22 @@ endif dml_ccflags := -mhard-float -msse $(cc_stack_align) +ifdef CONFIG_CC_IS_CLANG +dml_ccflags += -msse2 +endif + CFLAGS_display_mode_lib.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) +CFLAGS_display_mode_vba_20v2.o := $(dml_ccflags) +CFLAGS_display_rq_dlg_calc_20v2.o := $(dml_ccflags) +endif +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +CFLAGS_display_mode_vba_21.o := $(dml_ccflags) +CFLAGS_display_rq_dlg_calc_21.o := $(dml_ccflags) endif ifdef CONFIG_DRM_AMD_DCN3AG CFLAGS_display_mode_vba_3ag.o := $(dml_ccflags) @@ -51,7 +61,12 @@ DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.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 +DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o endif +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o +endif + AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML)) diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c new file mode 100644 index 000000000000..0fafd693ffb4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.c @@ -0,0 +1,5136 @@ +/* + * 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_20v2.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); +static bool CalculateDelayAfterScaler( + struct display_mode_lib *mode_lib, + double ReturnBW, + double ReadBandwidthPlaneLuma, + double ReadBandwidthPlaneChroma, + double TotalDataReadBandwidth, + double DisplayPipeLineDeliveryTimeLuma, + double DisplayPipeLineDeliveryTimeChroma, + double DPPCLK, + double DISPCLK, + double PixelClock, + 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 HTotal, + unsigned int SwathWidthSingleDPPY, + double BytePerPixelDETY, + double BytePerPixelDETC, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler + ); +// 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 DPPPerPlane, + unsigned int NumberOfCursors, + 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, + 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 dml20v2_DisplayPipeConfiguration(struct display_mode_lib *mode_lib); +static void dml20v2_DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( + struct display_mode_lib *mode_lib); + +void dml20v2_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); + dml20v2_DisplayPipeConfiguration(mode_lib); + dml20v2_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 CalculateDelayAfterScaler( + struct display_mode_lib *mode_lib, + double ReturnBW, + double ReadBandwidthPlaneLuma, + double ReadBandwidthPlaneChroma, + double TotalDataReadBandwidth, + double DisplayPipeLineDeliveryTimeLuma, + double DisplayPipeLineDeliveryTimeChroma, + double DPPCLK, + double DISPCLK, + double PixelClock, + 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 HTotal, + unsigned int SwathWidthSingleDPPY, + double BytePerPixelDETY, + double BytePerPixelDETC, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + bool Interlace, + bool ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler + ) +{ + unsigned int DPPCycles, DISPCLKCycles; + double DataFabricLineDeliveryTimeLuma; + double DataFabricLineDeliveryTimeChroma; + double DSTTotalPixelsAfterScaler; + + DataFabricLineDeliveryTimeLuma = SwathWidthSingleDPPY * SwathHeightY * dml_ceil(BytePerPixelDETY, 1) / (mode_lib->vba.ReturnBW * ReadBandwidthPlaneLuma / TotalDataReadBandwidth); + mode_lib->vba.LastPixelOfLineExtraWatermark = dml_max(mode_lib->vba.LastPixelOfLineExtraWatermark, DataFabricLineDeliveryTimeLuma - DisplayPipeLineDeliveryTimeLuma); + + if (BytePerPixelDETC != 0) { + DataFabricLineDeliveryTimeChroma = SwathWidthSingleDPPY / 2 * SwathHeightC * dml_ceil(BytePerPixelDETC, 2) / (mode_lib->vba.ReturnBW * ReadBandwidthPlaneChroma / TotalDataReadBandwidth); + mode_lib->vba.LastPixelOfLineExtraWatermark = dml_max(mode_lib->vba.LastPixelOfLineExtraWatermark, DataFabricLineDeliveryTimeChroma - DisplayPipeLineDeliveryTimeChroma); + } + + 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 || (Interlace && ProgressiveToInterlaceUnitInOPP)) + *DSTYAfterScaler = 1; + else + *DSTYAfterScaler = 0; + + DSTTotalPixelsAfterScaler = ((double) (*DSTYAfterScaler * HTotal)) + *DSTXAfterScaler; + *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / HTotal, 1); + *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * HTotal)); + + return true; +} + +static bool CalculatePrefetchSchedule( + struct display_mode_lib *mode_lib, + double DPPCLK, + double DISPCLK, + double PixelClock, + double DCFCLKDeepSleep, + unsigned int DPPPerPlane, + unsigned int NumberOfCursors, + 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, + double *Tno_bw, + unsigned int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix) +{ + bool MyError = false; + double 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; + + *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; + } + } 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 dml20v2_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) { + 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]; + + 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]; + } + + 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; + } + + CalculateDelayAfterScaler(mode_lib, mode_lib->vba.ReturnBW, mode_lib->vba.ReadBandwidthPlaneLuma[k], mode_lib->vba.ReadBandwidthPlaneChroma[k], mode_lib->vba.TotalDataReadBandwidth, + mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k], mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k], + mode_lib->vba.DPPCLK[k], mode_lib->vba.DISPCLK, mode_lib->vba.PixelClock[k], 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, + mode_lib->vba.SwathWidthY[k] / mode_lib->vba.HRatio[k], mode_lib->vba.OutputFormat[k], mode_lib->vba.HTotal[k], + mode_lib->vba.SwathWidthSingleDPPY[k], mode_lib->vba.BytePerPixelDETY[k], mode_lib->vba.BytePerPixelDETC[k], mode_lib->vba.SwathHeightY[k], mode_lib->vba.SwathHeightC[k], mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, &mode_lib->vba.DSTXAfterScaler[k], &mode_lib->vba.DSTYAfterScaler[k]); + + 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.DPPPerPlane[k], + mode_lib->vba.NumberOfCursors[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.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 dml20v2_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 dml20v2_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); + + locals->MaxTotalVActiveRDBandwidth = 0; + for (k = 0; k < locals->NumberOfActivePlanes; k++) { + locals->MaxTotalVActiveRDBandwidth = locals->MaxTotalVActiveRDBandwidth + locals->ReadBandwidth[k]; + } + + 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; + } + + CalculateDelayAfterScaler(mode_lib, mode_lib->vba.ReturnBWPerState[i], mode_lib->vba.ReadBandwidthLuma[k], mode_lib->vba.ReadBandwidthChroma[k], mode_lib->vba.MaxTotalVActiveRDBandwidth, + mode_lib->vba.DisplayPipeLineDeliveryTimeLuma[k], mode_lib->vba.DisplayPipeLineDeliveryTimeChroma[k], + mode_lib->vba.RequiredDPPCLK[i][j][k], mode_lib->vba.RequiredDISPCLK[i][j], mode_lib->vba.PixelClock[k], 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.HTotal[k], + mode_lib->vba.SwathWidthYSingleDPP[k], mode_lib->vba.BytePerPixelInDETY[k], mode_lib->vba.BytePerPixelInDETC[k], mode_lib->vba.SwathHeightYThisState[k], mode_lib->vba.SwathHeightCThisState[k], mode_lib->vba.Interlace[k], mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + &mode_lib->vba.DSTXAfterScaler[k], &mode_lib->vba.DSTYAfterScaler[k]); + + 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.NoOfDPP[i][j][k], + mode_lib->vba.NumberOfCursors[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[k], + mode_lib->vba.DSTYAfterScaler[k], + &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.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*/ + 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_20v2.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.h new file mode 100644 index 000000000000..a989d3ca1e99 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_mode_vba_20v2.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 _DCN20V2_DISPLAY_MODE_VBA_H_ +#define _DCN20V2_DISPLAY_MODE_VBA_H_ + +void dml20v2_recalculate(struct display_mode_lib *mode_lib); +void dml20v2_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.c new file mode 100644 index 000000000000..ed8bf5f723c9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.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_20v2.h" + +// Function: dml20v2_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 dml20v2_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: dml20v2_rq_dlg_get_dlg_params +// Calculate deadline related parameters +// +static void dml20v2_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 dml20v2_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 dml20v2_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)); + dml20v2_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 dml20v2_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 dml20v2_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); + dml20v2_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe.src); + dml20v2_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_20v2.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.h new file mode 100644 index 000000000000..0378406bf7e7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/display_rq_dlg_calc_20v2.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 __DML20V2_DISPLAY_RQ_DLG_CALC_H__ +#define __DML20V2_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 dml20v2_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 dml20v2_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/dcn21/display_mode_vba_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c new file mode 100644 index 000000000000..456cd0e3289c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.c @@ -0,0 +1,6123 @@ +/* + * 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 "../dml_inline_defs.h" +#include "../display_mode_vba.h" +#include "display_mode_vba_21.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. + */ + +typedef unsigned int uint; + +typedef struct { + double DPPCLK; + double DISPCLK; + double PixelClock; + double DCFCLKDeepSleep; + unsigned int DPPPerPlane; + bool ScalerEnabled; + enum scan_direction_class SourceScan; + unsigned int BlockWidth256BytesY; + unsigned int BlockHeight256BytesY; + unsigned int BlockWidth256BytesC; + unsigned int BlockHeight256BytesC; + unsigned int InterlaceEnable; + unsigned int NumberOfCursors; + unsigned int VBlank; + unsigned int HTotal; +} Pipe; + +typedef struct { + bool Enable; + unsigned int MaxPageTableLevels; + unsigned int CachedPageTableLevels; +} HostVM; + +#define BPP_INVALID 0 +#define BPP_BLENDED_PIPE 0xffffffff + +static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib); +static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( + struct display_mode_lib *mode_lib); +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 PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + Pipe *myPipe, + unsigned int DSCDelay, + double DPPCLKDelaySubtotal, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCFormater, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int ScalerRecoutWidth, + enum output_format_class OutputFormat, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int MaxVStartup, + unsigned int GPUVMPageTableLevels, + bool GPUVMEnable, + HostVM *myHostVM, + bool DynamicMetadataEnable, + int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + bool DCCEnable, + double UrgentLatency, + 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 ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBWLuma, + double *RequiredPrefetchPixDataBWChroma, + unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + double *Tno_bw, + double *prefetch_vmrow_bw, + unsigned int *swath_width_luma_ub, + unsigned int *swath_width_chroma_ub, + unsigned int *VUpdateOffsetPix, + double *VUpdateWidthPix, + double *VReadyOffsetPix); +static double RoundToDFSGranularityUp(double Clock, double VCOSpeed); +static double RoundToDFSGranularityDown(double Clock, double VCOSpeed); +static double CalculateDCCConfiguration( + bool DCCEnabled, + bool DCCProgrammingAssumesScanDirectionUnknown, + unsigned int ViewportWidth, + unsigned int ViewportHeight, + double DETBufferSize, + unsigned int RequestHeight256Byte, + unsigned int SwathHeight, + enum dm_swizzle_mode TilingFormat, + unsigned int BytePerPixel, + enum scan_direction_class ScanOrientation, + unsigned int *MaxUncompressedBlock, + unsigned int *MaxCompressedBlock, + unsigned int *Independent64ByteBlock); +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, + bool HostVMEnable, + unsigned int HostVMMaxPageTableLevels, + unsigned int HostVMCachedPageTableLevels, + unsigned int VMMPageSize, + unsigned int PTEBufferSizeInRequests, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + unsigned int *dpte_row_width_ub, + unsigned int *dpte_row_height, + unsigned int *MetaRequestWidth, + unsigned int *MetaRequestHeight, + unsigned int *meta_row_width, + unsigned int *meta_row_height, + unsigned int *vm_group_bytes, + long *dpte_group_bytes, + unsigned int *PixelPTEReqWidth, + unsigned int *PixelPTEReqHeight, + unsigned int *PTERequestSize, + unsigned int *DPDE0BytesFrame, + unsigned int *MetaPTEBytesFrame); + +static double CalculateTWait( + unsigned int PrefetchMode, + double DRAMClockChangeLatency, + double UrgentLatency, + 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); +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + double UrgentExtraLatency, + double UrgentLatency, + unsigned int GPUVMMaxPageTableLevels, + bool HostVMEnable, + unsigned int HostVMMaxPageTableLevels, + unsigned int HostVMCachedPageTableLevels, + bool GPUVMEnable, + double PDEAndMetaPTEBytesPerFrame, + double MetaRowBytes, + double DPTEBytesPerRow, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + double LineTime, + double VRatio, + double Tno_bw, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + unsigned int dpte_row_height_chroma, + unsigned int meta_row_height_chroma, + 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 CalculateWatermarksAndDRAMSpeedChangeSupport( + struct display_mode_lib *mode_lib, + unsigned int PrefetchMode, + unsigned int NumberOfActivePlanes, + unsigned int MaxLineBufferLines, + unsigned int LineBufferSize, + unsigned int DPPOutputBufferPixels, + double DETBufferSizeInKByte, + unsigned int WritebackInterfaceLumaBufferSize, + unsigned int WritebackInterfaceChromaBufferSize, + double DCFCLK, + double UrgentOutOfOrderReturn, + double ReturnBW, + bool GPUVMEnable, + long dpte_group_bytes[], + unsigned int MetaChunkSize, + double UrgentLatency, + double ExtraLatency, + double WritebackLatency, + double WritebackChunkSize, + double SOCCLK, + double DRAMClockChangeLatency, + double SRExitTime, + double SREnterPlusExitTime, + double DCFCLKDeepSleep, + int DPPPerPlane[], + bool DCCEnable[], + double DPPCLK[], + unsigned int SwathWidthSingleDPPY[], + unsigned int SwathHeightY[], + double ReadBandwidthPlaneLuma[], + unsigned int SwathHeightC[], + double ReadBandwidthPlaneChroma[], + unsigned int LBBitPerPixel[], + unsigned int SwathWidthY[], + double HRatio[], + unsigned int vtaps[], + unsigned int VTAPsChroma[], + double VRatio[], + unsigned int HTotal[], + double PixelClock[], + unsigned int BlendingAndTiming[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + bool WritebackEnable[], + enum source_format_class WritebackPixelFormat[], + double WritebackDestinationWidth[], + double WritebackDestinationHeight[], + double WritebackSourceHeight[], + enum clock_change_support *DRAMClockChangeSupport, + double *UrgentWatermark, + double *WritebackUrgentWatermark, + double *DRAMClockChangeWatermark, + double *WritebackDRAMClockChangeWatermark, + double *StutterExitWatermark, + double *StutterEnterPlusExitWatermark, + double *MinActiveDRAMClockChangeLatencySupported); +static void CalculateDCFCLKDeepSleep( + struct display_mode_lib *mode_lib, + unsigned int NumberOfActivePlanes, + double BytePerPixelDETY[], + double BytePerPixelDETC[], + double VRatio[], + unsigned int SwathWidthY[], + int DPPPerPlane[], + double HRatio[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double *DCFCLKDeepSleep); +static void CalculateDETBufferSize( + double DETBufferSizeInKByte, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double *DETBufferSizeY, + double *DETBufferSizeC); +static void CalculateUrgentBurstFactor( + unsigned int DETBufferSizeInKByte, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + unsigned int SwathWidthY, + double LineTime, + double UrgentLatency, + double CursorBufferSize, + unsigned int CursorWidth, + unsigned int CursorBPP, + double VRatio, + double VRatioPreY, + double VRatioPreC, + double BytePerPixelInDETY, + double BytePerPixelInDETC, + double *UrgentBurstFactorCursor, + double *UrgentBurstFactorCursorPre, + double *UrgentBurstFactorLuma, + double *UrgentBurstFactorLumaPre, + double *UrgentBurstFactorChroma, + double *UrgentBurstFactorChromaPre, + unsigned int *NotEnoughUrgentLatencyHiding, + unsigned int *NotEnoughUrgentLatencyHidingPre); + +static void CalculatePixelDeliveryTimes( + unsigned int NumberOfActivePlanes, + double VRatio[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + unsigned int swath_width_luma_ub[], + unsigned int swath_width_chroma_ub[], + int DPPPerPlane[], + double HRatio[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double BytePerPixelDETC[], + enum scan_direction_class SourceScan[], + unsigned int BlockWidth256BytesY[], + unsigned int BlockHeight256BytesY[], + unsigned int BlockWidth256BytesC[], + unsigned int BlockHeight256BytesC[], + double DisplayPipeLineDeliveryTimeLuma[], + double DisplayPipeLineDeliveryTimeChroma[], + double DisplayPipeLineDeliveryTimeLumaPrefetch[], + double DisplayPipeLineDeliveryTimeChromaPrefetch[], + double DisplayPipeRequestDeliveryTimeLuma[], + double DisplayPipeRequestDeliveryTimeChroma[], + double DisplayPipeRequestDeliveryTimeLumaPrefetch[], + double DisplayPipeRequestDeliveryTimeChromaPrefetch[]); + +static void CalculateMetaAndPTETimes( + unsigned int NumberOfActivePlanes, + bool GPUVMEnable, + unsigned int MetaChunkSize, + unsigned int MinMetaChunkSizeBytes, + unsigned int GPUVMMaxPageTableLevels, + unsigned int HTotal[], + double VRatio[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + double DestinationLinesToRequestRowInVBlank[], + double DestinationLinesToRequestRowInImmediateFlip[], + double DestinationLinesToRequestVMInVBlank[], + double DestinationLinesToRequestVMInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + enum scan_direction_class SourceScan[], + unsigned int dpte_row_height[], + unsigned int dpte_row_height_chroma[], + unsigned int meta_row_width[], + unsigned int meta_row_height[], + unsigned int meta_req_width[], + unsigned int meta_req_height[], + long dpte_group_bytes[], + unsigned int PTERequestSizeY[], + unsigned int PTERequestSizeC[], + unsigned int PixelPTEReqWidthY[], + unsigned int PixelPTEReqHeightY[], + unsigned int PixelPTEReqWidthC[], + unsigned int PixelPTEReqHeightC[], + unsigned int dpte_row_width_luma_ub[], + unsigned int dpte_row_width_chroma_ub[], + unsigned int vm_group_bytes[], + unsigned int dpde0_bytes_per_frame_ub_l[], + unsigned int dpde0_bytes_per_frame_ub_c[], + unsigned int meta_pte_bytes_per_frame_ub_l[], + unsigned int meta_pte_bytes_per_frame_ub_c[], + double DST_Y_PER_PTE_ROW_NOM_L[], + double DST_Y_PER_PTE_ROW_NOM_C[], + double DST_Y_PER_META_ROW_NOM_L[], + double TimePerMetaChunkNominal[], + double TimePerMetaChunkVBlank[], + double TimePerMetaChunkFlip[], + double time_per_pte_group_nom_luma[], + double time_per_pte_group_vblank_luma[], + double time_per_pte_group_flip_luma[], + double time_per_pte_group_nom_chroma[], + double time_per_pte_group_vblank_chroma[], + double time_per_pte_group_flip_chroma[], + double TimePerVMGroupVBlank[], + double TimePerVMGroupFlip[], + double TimePerVMRequestVBlank[], + double TimePerVMRequestFlip[]); + +static double CalculateExtraLatency( + double UrgentRoundTripAndOutOfOrderLatency, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + double ReturnBW, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + long dpte_group_bytes[], + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + int HostVMMaxPageTableLevels, + int HostVMCachedPageTableLevels); + +void dml21_recalculate(struct display_mode_lib *mode_lib) +{ + ModeSupportAndSystemConfiguration(mode_lib); + PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib); + DisplayPipeConfiguration(mode_lib); + DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation(mode_lib); +} + +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 PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + Pipe *myPipe, + unsigned int DSCDelay, + double DPPCLKDelaySubtotal, + double DPPCLKDelaySCL, + double DPPCLKDelaySCLLBOnly, + double DPPCLKDelayCNVCFormater, + double DPPCLKDelayCNVCCursor, + double DISPCLKDelaySubtotal, + unsigned int ScalerRecoutWidth, + enum output_format_class OutputFormat, + unsigned int MaxInterDCNTileRepeaters, + unsigned int VStartup, + unsigned int MaxVStartup, + unsigned int GPUVMPageTableLevels, + bool GPUVMEnable, + HostVM *myHostVM, + bool DynamicMetadataEnable, + int DynamicMetadataLinesBeforeActiveRequired, + unsigned int DynamicMetadataTransmittedBytes, + bool DCCEnable, + double UrgentLatency, + 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 ProgressiveToInterlaceUnitInOPP, + double *DSTXAfterScaler, + double *DSTYAfterScaler, + double *DestinationLinesForPrefetch, + double *PrefetchBandwidth, + double *DestinationLinesToRequestVMInVBlank, + double *DestinationLinesToRequestRowInVBlank, + double *VRatioPrefetchY, + double *VRatioPrefetchC, + double *RequiredPrefetchPixDataBWLuma, + double *RequiredPrefetchPixDataBWChroma, + unsigned int *VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + double *Tno_bw, + double *prefetch_vmrow_bw, + unsigned int *swath_width_luma_ub, + unsigned int *swath_width_chroma_ub, + 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 Tvm_oto_lines; + double Tr0_oto_lines; + double Tsw_oto_lines; + double dst_y_prefetch_oto; + double TimeForFetchingMetaPTE = 0; + double TimeForFetchingRowInVBlank = 0; + double LinesToRequestPrefetchPixelData = 0; + double HostVMInefficiencyFactor; + unsigned int HostVMDynamicLevels; + + if (GPUVMEnable == true && myHostVM->Enable == true) { + HostVMInefficiencyFactor = + PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData + / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; + HostVMDynamicLevels = myHostVM->MaxPageTableLevels + - myHostVM->CachedPageTableLevels; + } else { + HostVMInefficiencyFactor = 1; + HostVMDynamicLevels = 0; + } + + if (myPipe->ScalerEnabled) + DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCL; + else + DPPCycles = DPPCLKDelaySubtotal + DPPCLKDelaySCLLBOnly; + + DPPCycles = DPPCycles + DPPCLKDelayCNVCFormater + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor; + + DISPCLKCycles = DISPCLKDelaySubtotal; + + if (myPipe->DPPCLK == 0.0 || myPipe->DISPCLK == 0.0) + return true; + + *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK + DSCDelay; + + if (myPipe->DPPPerPlane > 1) + *DSTXAfterScaler = *DSTXAfterScaler + ScalerRecoutWidth; + + if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && ProgressiveToInterlaceUnitInOPP)) + *DSTYAfterScaler = 1; + else + *DSTYAfterScaler = 0; + + DSTTotalPixelsAfterScaler = ((double) (*DSTYAfterScaler * myPipe->HTotal)) + *DSTXAfterScaler; + *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1); + *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal)); + + *VUpdateOffsetPix = dml_ceil(myPipe->HTotal / 4.0, 1); + TotalRepeaterDelayTime = MaxInterDCNTileRepeaters * (2.0 / myPipe->DPPCLK + 3.0 / myPipe->DISPCLK); + *VUpdateWidthPix = (14.0 / myPipe->DCFCLKDeepSleep + 12.0 / myPipe->DPPCLK + TotalRepeaterDelayTime) + * myPipe->PixelClock; + + *VReadyOffsetPix = dml_max( + 150.0 / myPipe->DPPCLK, + TotalRepeaterDelayTime + 20.0 / myPipe->DCFCLKDeepSleep + 10.0 / myPipe->DPPCLK) + * myPipe->PixelClock; + + Tsetup = (double) (*VUpdateOffsetPix + *VUpdateWidthPix + *VReadyOffsetPix) / myPipe->PixelClock; + + LineTime = (double) myPipe->HTotal / myPipe->PixelClock; + + if (DynamicMetadataEnable) { + double Tdmbf, Tdmec, Tdmsks; + + Tdm = dml_max(0.0, UrgentExtraLatency - TCalc); + Tdmbf = DynamicMetadataTransmittedBytes / 4.0 / myPipe->DISPCLK; + Tdmec = LineTime; + if (DynamicMetadataLinesBeforeActiveRequired == -1) + Tdmsks = myPipe->VBlank * LineTime / 2.0; + else + Tdmsks = DynamicMetadataLinesBeforeActiveRequired * LineTime; + if (myPipe->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 (GPUVMPageTableLevels >= 3) + *Tno_bw = UrgentExtraLatency + UrgentLatency * ((GPUVMPageTableLevels - 2) * (myHostVM->MaxPageTableLevels + 1) - 1); + 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 / myPipe->HTotal); + + Tsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime; + + if (myPipe->SourceScan == dm_horz) { + *swath_width_luma_ub = dml_ceil(SwathWidthY - 1, myPipe->BlockWidth256BytesY) + myPipe->BlockWidth256BytesY; + *swath_width_chroma_ub = dml_ceil(SwathWidthY / 2 - 1, myPipe->BlockWidth256BytesC) + myPipe->BlockWidth256BytesC; + } else { + *swath_width_luma_ub = dml_ceil(SwathWidthY - 1, myPipe->BlockHeight256BytesY) + myPipe->BlockHeight256BytesY; + *swath_width_chroma_ub = dml_ceil(SwathWidthY / 2 - 1, myPipe->BlockHeight256BytesC) + myPipe->BlockHeight256BytesC; + } + + prefetch_bw_oto = (PrefetchSourceLinesY * *swath_width_luma_ub * dml_ceil(BytePerPixelDETY, 1) + PrefetchSourceLinesC * *swath_width_chroma_ub * dml_ceil(BytePerPixelDETC, 2)) / Tsw_oto; + + + if (GPUVMEnable == true) { + Tvm_oto = dml_max(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto, + dml_max(UrgentExtraLatency + UrgentLatency * (GPUVMPageTableLevels * (HostVMDynamicLevels + 1) - 1), + LineTime / 4.0)); + } else + Tvm_oto = LineTime / 4.0; + + if ((GPUVMEnable == true || DCCEnable == true)) { + Tr0_oto = dml_max( + (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto, + dml_max(UrgentLatency * (HostVMDynamicLevels + 1), dml_max(LineTime - Tvm_oto, LineTime / 4))); + } else + Tr0_oto = (LineTime - Tvm_oto) / 2.0; + + Tvm_oto_lines = dml_ceil(4 * Tvm_oto / LineTime, 1) / 4.0; + Tr0_oto_lines = dml_ceil(4 * Tr0_oto / LineTime, 1) / 4.0; + Tsw_oto_lines = dml_ceil(4 * Tsw_oto / LineTime, 1) / 4.0; + dst_y_prefetch_oto = Tvm_oto_lines + 2 * Tr0_oto_lines + Tsw_oto_lines + 0.75; + + dst_y_prefetch_equ = dml_floor(4.0 * (dst_y_prefetch_equ + 0.125), 1) / 4.0; + + if (dst_y_prefetch_oto < dst_y_prefetch_equ) + *DestinationLinesForPrefetch = dst_y_prefetch_oto; + else + *DestinationLinesForPrefetch = dst_y_prefetch_equ; + + 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", myPipe->HTotal); + + *PrefetchBandwidth = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + if (*DestinationLinesForPrefetch > 1) { + double PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor + + PrefetchSourceLinesY * *swath_width_luma_ub * dml_ceil(BytePerPixelDETY, 1) + + PrefetchSourceLinesC * *swath_width_chroma_ub * dml_ceil(BytePerPixelDETC, 2)) + / (*DestinationLinesForPrefetch * LineTime - *Tno_bw); + + double PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame * + HostVMInefficiencyFactor + PrefetchSourceLinesY * + *swath_width_luma_ub * dml_ceil(BytePerPixelDETY, 1) + + PrefetchSourceLinesC * *swath_width_chroma_ub * + dml_ceil(BytePerPixelDETC, 2)) / + (*DestinationLinesForPrefetch * LineTime - *Tno_bw - 2 * + UrgentLatency * (1 + HostVMDynamicLevels)); + + double PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow + * HostVMInefficiencyFactor + PrefetchSourceLinesY * + *swath_width_luma_ub * dml_ceil(BytePerPixelDETY, 1) + + PrefetchSourceLinesC * *swath_width_chroma_ub * + dml_ceil(BytePerPixelDETC, 2)) / + (*DestinationLinesForPrefetch * LineTime - + UrgentExtraLatency - UrgentLatency * (GPUVMPageTableLevels + * (HostVMDynamicLevels + 1) - 1)); + + double PrefetchBandwidth4 = (PrefetchSourceLinesY * *swath_width_luma_ub * + dml_ceil(BytePerPixelDETY, 1) + PrefetchSourceLinesC * + *swath_width_chroma_ub * dml_ceil(BytePerPixelDETC, 2)) / + (*DestinationLinesForPrefetch * LineTime - + UrgentExtraLatency - UrgentLatency * (GPUVMPageTableLevels + * (HostVMDynamicLevels + 1) - 1) - 2 * UrgentLatency * + (1 + HostVMDynamicLevels)); + + if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (*DestinationLinesForPrefetch - dml_ceil(Tsw_oto_lines, 1) / 4.0 - 0.75) * LineTime - *Tno_bw > 0) { + PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / ((*DestinationLinesForPrefetch - dml_ceil(Tsw_oto_lines, 1) / 4.0 - 0.75) * LineTime - *Tno_bw); + } + if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1 >= UrgentExtraLatency + UrgentLatency * (GPUVMPageTableLevels * (HostVMDynamicLevels + 1) - 1) && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth1 >= UrgentLatency * (1 + HostVMDynamicLevels)) { + *PrefetchBandwidth = PrefetchBandwidth1; + } else if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2 >= UrgentExtraLatency + UrgentLatency * (GPUVMPageTableLevels * (HostVMDynamicLevels + 1) - 1) && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth2 < UrgentLatency * (1 + HostVMDynamicLevels)) { + *PrefetchBandwidth = PrefetchBandwidth2; + } else if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3 < UrgentExtraLatency + UrgentLatency * (GPUVMPageTableLevels * (HostVMDynamicLevels + 1) - 1) && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth3 >= UrgentLatency * (1 + HostVMDynamicLevels)) { + *PrefetchBandwidth = PrefetchBandwidth3; + } else { + *PrefetchBandwidth = PrefetchBandwidth4; + } + + if (GPUVMEnable) { + TimeForFetchingMetaPTE = dml_max(*Tno_bw + (double) PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / *PrefetchBandwidth, + dml_max(UrgentExtraLatency + UrgentLatency * (GPUVMPageTableLevels * (HostVMDynamicLevels + 1) - 1), LineTime / 4)); + } else { +// 5/30/2018 - This was an optimization requested from Sy but now NumberOfCursors is no longer a factor +// so if this needs to be reinstated, then it should be officially done in the VBA code as well. +// if (mode_lib->NumberOfCursors > 0 || XFCEnabled) + TimeForFetchingMetaPTE = LineTime / 4; +// else +// TimeForFetchingMetaPTE = 0.0; + } + + if ((GPUVMEnable == true || DCCEnable == true)) { + TimeForFetchingRowInVBlank = + dml_max( + (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) + / *PrefetchBandwidth, + dml_max( + UrgentLatency * (1 + HostVMDynamicLevels), + dml_max( + (LineTime + - TimeForFetchingMetaPTE) / 2.0, + LineTime + / 4.0))); + } else { +// See note above dated 5/30/2018 +// if (NumberOfCursors > 0 || XFCEnabled) + TimeForFetchingRowInVBlank = (LineTime - TimeForFetchingMetaPTE) / 2.0; +// else // TODO: Did someone else add this?? +// TimeForFetchingRowInVBlank = 0.0; + } + + *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * TimeForFetchingMetaPTE / LineTime, 1.0) / 4.0; + + *DestinationLinesToRequestRowInVBlank = dml_ceil(4.0 * TimeForFetchingRowInVBlank / LineTime, 1.0) / 4.0; + + LinesToRequestPrefetchPixelData = *DestinationLinesForPrefetch +// See note above dated 5/30/2018 +// - ((NumberOfCursors > 0 || GPUVMEnable || DCCEnable) ? + - ((GPUVMEnable || DCCEnable) ? + (*DestinationLinesToRequestVMInVBlank + 2 * *DestinationLinesToRequestRowInVBlank) : + 0.0); // TODO: Did someone else add this?? + + 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; + } + } + + *RequiredPrefetchPixDataBWLuma = myPipe->DPPPerPlane + * (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData + * dml_ceil(BytePerPixelDETY, 1) + * *swath_width_luma_ub / LineTime; + *RequiredPrefetchPixDataBWChroma = myPipe->DPPPerPlane + * (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData + * dml_ceil(BytePerPixelDETC, 2) + * *swath_width_chroma_ub / LineTime; + } else { + MyError = true; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + *RequiredPrefetchPixDataBWChroma = 0; + } + + dml_print("DML: Tvm: %fus\n", TimeForFetchingMetaPTE); + dml_print("DML: Tr0: %fus\n", TimeForFetchingRowInVBlank); + dml_print("DML: Tsw: %fus\n", (double)(*DestinationLinesForPrefetch) * LineTime - TimeForFetchingMetaPTE - TimeForFetchingRowInVBlank); + dml_print("DML: Tpre: %fus\n", (double)(*DestinationLinesForPrefetch) * LineTime); + dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n", PixelPTEBytesPerRow); + + } else { + MyError = true; + } + + { + double prefetch_vm_bw; + double prefetch_row_bw; + + if (PDEAndMetaPTEBytesFrame == 0) { + prefetch_vm_bw = 0; + } else if (*DestinationLinesToRequestVMInVBlank > 0) { + prefetch_vm_bw = PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInVBlank * LineTime); + } else { + prefetch_vm_bw = 0; + MyError = true; + } + if (MetaRowByte + PixelPTEBytesPerRow == 0) { + prefetch_row_bw = 0; + } else if (*DestinationLinesToRequestRowInVBlank > 0) { + prefetch_row_bw = (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (*DestinationLinesToRequestRowInVBlank * LineTime); + } else { + prefetch_row_bw = 0; + MyError = true; + } + + *prefetch_vmrow_bw = dml_max(prefetch_vm_bw, prefetch_row_bw); + } + + if (MyError) { + *PrefetchBandwidth = 0; + TimeForFetchingMetaPTE = 0; + TimeForFetchingRowInVBlank = 0; + *DestinationLinesToRequestVMInVBlank = 0; + *DestinationLinesToRequestRowInVBlank = 0; + *DestinationLinesForPrefetch = 0; + LinesToRequestPrefetchPixelData = 0; + *VRatioPrefetchY = 0; + *VRatioPrefetchC = 0; + *RequiredPrefetchPixDataBWLuma = 0; + *RequiredPrefetchPixDataBWChroma = 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 CalculateDCCConfiguration( + bool DCCEnabled, + bool DCCProgrammingAssumesScanDirectionUnknown, + unsigned int ViewportWidth, + unsigned int ViewportHeight, + double DETBufferSize, + unsigned int RequestHeight256Byte, + unsigned int SwathHeight, + enum dm_swizzle_mode TilingFormat, + unsigned int BytePerPixel, + enum scan_direction_class ScanOrientation, + unsigned int *MaxUncompressedBlock, + unsigned int *MaxCompressedBlock, + unsigned int *Independent64ByteBlock) +{ + double MaximumDCCCompressionSurface = 0.0; + enum { + REQ_256Bytes, + REQ_128BytesNonContiguous, + REQ_128BytesContiguous, + REQ_NA + } Request = REQ_NA; + + if (DCCEnabled == true) { + if (DCCProgrammingAssumesScanDirectionUnknown == true) { + if (DETBufferSize >= RequestHeight256Byte * ViewportWidth * BytePerPixel + && DETBufferSize + >= 256 / RequestHeight256Byte + * ViewportHeight) { + Request = REQ_256Bytes; + } else if ((DETBufferSize + < RequestHeight256Byte * ViewportWidth * BytePerPixel + && (BytePerPixel == 2 || BytePerPixel == 4)) + || (DETBufferSize + < 256 / RequestHeight256Byte + * ViewportHeight + && BytePerPixel == 8 + && (TilingFormat == dm_sw_4kb_d + || TilingFormat + == dm_sw_4kb_d_x + || TilingFormat + == dm_sw_var_d + || TilingFormat + == dm_sw_var_d_x + || TilingFormat + == dm_sw_64kb_d + || TilingFormat + == dm_sw_64kb_d_x + || TilingFormat + == dm_sw_64kb_d_t + || TilingFormat + == dm_sw_64kb_r_x))) { + Request = REQ_128BytesNonContiguous; + } else { + Request = REQ_128BytesContiguous; + } + } else { + if (BytePerPixel == 1) { + if (ScanOrientation == dm_vert || SwathHeight == 16) { + Request = REQ_256Bytes; + } else { + Request = REQ_128BytesContiguous; + } + } else if (BytePerPixel == 2) { + if ((ScanOrientation == dm_vert && SwathHeight == 16) || (ScanOrientation != dm_vert && SwathHeight == 8)) { + Request = REQ_256Bytes; + } else if (ScanOrientation == dm_vert) { + Request = REQ_128BytesContiguous; + } else { + Request = REQ_128BytesNonContiguous; + } + } else if (BytePerPixel == 4) { + if (SwathHeight == 8) { + Request = REQ_256Bytes; + } else if (ScanOrientation == dm_vert) { + Request = REQ_128BytesContiguous; + } else { + Request = REQ_128BytesNonContiguous; + } + } else if (BytePerPixel == 8) { + if (TilingFormat == dm_sw_4kb_d || TilingFormat == dm_sw_4kb_d_x + || TilingFormat == dm_sw_var_d + || TilingFormat == dm_sw_var_d_x + || TilingFormat == dm_sw_64kb_d + || TilingFormat == dm_sw_64kb_d_x + || TilingFormat == dm_sw_64kb_d_t + || TilingFormat == dm_sw_64kb_r_x) { + if ((ScanOrientation == dm_vert && SwathHeight == 8) + || (ScanOrientation != dm_vert + && SwathHeight == 4)) { + Request = REQ_256Bytes; + } else if (ScanOrientation != dm_vert) { + Request = REQ_128BytesContiguous; + } else { + Request = REQ_128BytesNonContiguous; + } + } else { + if (ScanOrientation != dm_vert || SwathHeight == 8) { + Request = REQ_256Bytes; + } else { + Request = REQ_128BytesContiguous; + } + } + } + } + } else { + Request = REQ_NA; + } + + if (Request == REQ_256Bytes) { + *MaxUncompressedBlock = 256; + *MaxCompressedBlock = 256; + *Independent64ByteBlock = false; + MaximumDCCCompressionSurface = 4.0; + } else if (Request == REQ_128BytesContiguous) { + *MaxUncompressedBlock = 128; + *MaxCompressedBlock = 128; + *Independent64ByteBlock = false; + MaximumDCCCompressionSurface = 2.0; + } else if (Request == REQ_128BytesNonContiguous) { + *MaxUncompressedBlock = 256; + *MaxCompressedBlock = 64; + *Independent64ByteBlock = true; + MaximumDCCCompressionSurface = 4.0; + } else { + *MaxUncompressedBlock = 0; + *MaxCompressedBlock = 0; + *Independent64ByteBlock = 0; + MaximumDCCCompressionSurface = 0.0; + } + + return MaximumDCCCompressionSurface; +} + +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, + bool HostVMEnable, + unsigned int HostVMMaxPageTableLevels, + unsigned int HostVMCachedPageTableLevels, + unsigned int VMMPageSize, + unsigned int PTEBufferSizeInRequests, + unsigned int Pitch, + unsigned int DCCMetaPitch, + unsigned int *MacroTileWidth, + unsigned int *MetaRowByte, + unsigned int *PixelPTEBytesPerRow, + bool *PTEBufferSizeNotExceeded, + unsigned int *dpte_row_width_ub, + unsigned int *dpte_row_height, + unsigned int *MetaRequestWidth, + unsigned int *MetaRequestHeight, + unsigned int *meta_row_width, + unsigned int *meta_row_height, + unsigned int *vm_group_bytes, + long *dpte_group_bytes, + unsigned int *PixelPTEReqWidth, + unsigned int *PixelPTEReqHeight, + unsigned int *PTERequestSize, + unsigned int *DPDE0BytesFrame, + unsigned int *MetaPTEBytesFrame) +{ + unsigned int MPDEBytesFrame; + unsigned int DCCMetaSurfaceBytes; + unsigned int MacroTileSizeBytes; + unsigned int MacroTileHeight; + unsigned int ExtraDPDEBytesFrame; + unsigned int PDEAndMetaPTEBytesFrame; + unsigned int PixelPTEReqHeightPTEs; + + if (DCCEnable == true) { + *MetaRequestHeight = 8 * BlockHeight256Bytes; + *MetaRequestWidth = 8 * BlockWidth256Bytes; + if (ScanDirection == dm_horz) { + *meta_row_height = *MetaRequestHeight; + *meta_row_width = dml_ceil((double) SwathWidth - 1, *MetaRequestWidth) + + *MetaRequestWidth; + *MetaRowByte = *meta_row_width * *MetaRequestHeight * BytePerPixel / 256.0; + } else { + *meta_row_height = *MetaRequestWidth; + *meta_row_width = dml_ceil((double) SwathWidth - 1, *MetaRequestHeight) + + *MetaRequestHeight; + *MetaRowByte = *meta_row_width * *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) * (mode_lib->vba.HostVMMaxPageTableLevels + 1) - 2); + } 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) * (mode_lib->vba.HostVMMaxPageTableLevels + 1) > 2) { + 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 + 1) * (mode_lib->vba.HostVMMaxPageTableLevels + 1) - 3); + } else { + *DPDE0BytesFrame = 0; + ExtraDPDEBytesFrame = 0; + } + + PDEAndMetaPTEBytesFrame = *MetaPTEBytesFrame + MPDEBytesFrame + *DPDE0BytesFrame + + ExtraDPDEBytesFrame; + + if (HostVMEnable == true) { + PDEAndMetaPTEBytesFrame = PDEAndMetaPTEBytesFrame * (1 + 8 * (HostVMMaxPageTableLevels - HostVMCachedPageTableLevels)); + } + + if (GPUVMEnable == true) { + double FractionOfPTEReturnDrop; + + if (SurfaceTiling == dm_sw_linear) { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = 1; + *PixelPTEReqWidth = 8.0 * VMMPageSize / BytePerPixel; + *PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } else if (MacroTileSizeBytes == 4096) { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = MacroTileHeight; + *PixelPTEReqWidth = 8 * *MacroTileWidth; + *PTERequestSize = 64; + if (ScanDirection == dm_horz) + FractionOfPTEReturnDrop = 0; + else + FractionOfPTEReturnDrop = 7 / 8; + } else if (VMMPageSize == 4096 && MacroTileSizeBytes > 4096) { + PixelPTEReqHeightPTEs = 16; + *PixelPTEReqHeight = 16 * BlockHeight256Bytes; + *PixelPTEReqWidth = 16 * BlockWidth256Bytes; + *PTERequestSize = 128; + FractionOfPTEReturnDrop = 0; + } else { + PixelPTEReqHeightPTEs = 1; + *PixelPTEReqHeight = MacroTileHeight; + *PixelPTEReqWidth = 8 * *MacroTileWidth; + *PTERequestSize = 64; + FractionOfPTEReturnDrop = 0; + } + + if (SurfaceTiling == dm_sw_linear) { + *dpte_row_height = dml_min(128, + 1 << (unsigned int) dml_floor( + dml_log2( + (double) PTEBufferSizeInRequests * *PixelPTEReqWidth / Pitch), + 1)); + *dpte_row_width_ub = (dml_ceil((double) (Pitch * *dpte_row_height - 1) / *PixelPTEReqWidth, 1) + 1) * *PixelPTEReqWidth; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqWidth * *PTERequestSize; + } else if (ScanDirection == dm_horz) { + *dpte_row_height = *PixelPTEReqHeight; + *dpte_row_width_ub = (dml_ceil((double) (SwathWidth - 1) / *PixelPTEReqWidth, 1) + 1) * *PixelPTEReqWidth; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqWidth * *PTERequestSize; + } else { + *dpte_row_height = dml_min(*PixelPTEReqWidth, *MacroTileWidth); + *dpte_row_width_ub = (dml_ceil((double) (SwathWidth - 1) / *PixelPTEReqHeight, 1) + 1) * *PixelPTEReqHeight; + *PixelPTEBytesPerRow = *dpte_row_width_ub / *PixelPTEReqHeight * *PTERequestSize; + } + if (*PixelPTEBytesPerRow * (1 - FractionOfPTEReturnDrop) + <= 64 * PTEBufferSizeInRequests) { + *PTEBufferSizeNotExceeded = true; + } else { + *PTEBufferSizeNotExceeded = false; + } + } else { + *PixelPTEBytesPerRow = 0; + *PTEBufferSizeNotExceeded = true; + } + dml_print("DML: vm_bytes = meta_pte_bytes_per_frame (per_pipe) = MetaPTEBytesFrame = : %d\n", *MetaPTEBytesFrame); + + if (HostVMEnable == true) { + *PixelPTEBytesPerRow = *PixelPTEBytesPerRow * (1 + 8 * (HostVMMaxPageTableLevels - HostVMCachedPageTableLevels)); + } + + if (HostVMEnable == true) { + *vm_group_bytes = 512; + *dpte_group_bytes = 512; + } else if (GPUVMEnable == true) { + *vm_group_bytes = 2048; + if (SurfaceTiling != dm_sw_linear && PixelPTEReqHeightPTEs == 1 && ScanDirection != dm_horz) { + *dpte_group_bytes = 512; + } else { + *dpte_group_bytes = 2048; + } + } else { + *vm_group_bytes = 0; + *dpte_group_bytes = 0; + } + + return PDEAndMetaPTEBytesFrame; +} + +static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerformanceCalculation( + struct display_mode_lib *mode_lib) +{ + struct vba_vars_st *locals = &mode_lib->vba; + 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; + + // DISPCLK and 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) { + locals->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 { + locals->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] + / locals->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)) { + locals->PSCL_THROUGHPUT_CHROMA[k] = 0.0; + locals->DPPCLKUsingSingleDPP[k] = + mode_lib->vba.DPPCLKUsingSingleDPPLuma; + } else { + if (mode_lib->vba.HRatio[k] > 1) { + locals->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 { + locals->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 + / locals->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]; + } + + locals->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 - 1].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) { + mode_lib->vba.DPPCLK_calculated[k] = locals->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 and B P-State/DRAM Clock Change Watermark + 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) + locals->SwathWidthSingleDPPY[k] = mode_lib->vba.ViewportWidth[k]; + else + locals->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) + locals->SwathWidthY[k] = dml_min( + (double) locals->SwathWidthSingleDPPY[k], + dml_round( + mode_lib->vba.HActive[k] / 2.0 + * mode_lib->vba.HRatio[k])); + else + locals->SwathWidthY[k] = locals->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) { + locals->BytePerPixelDETY[k] = 8; + locals->BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_32) { + locals->BytePerPixelDETY[k] = 4; + locals->BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_16 || mode_lib->vba.SourcePixelFormat[k] == dm_mono_16) { + locals->BytePerPixelDETY[k] = 2; + locals->BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_444_8 || mode_lib->vba.SourcePixelFormat[k] == dm_mono_8) { + locals->BytePerPixelDETY[k] = 1; + locals->BytePerPixelDETC[k] = 0; + } else if (mode_lib->vba.SourcePixelFormat[k] == dm_420_8) { + locals->BytePerPixelDETY[k] = 1; + locals->BytePerPixelDETC[k] = 2; + } else { // dm_420_10 + locals->BytePerPixelDETY[k] = 4.0 / 3.0; + locals->BytePerPixelDETC[k] = 8.0 / 3.0; + } + } + + mode_lib->vba.TotalDataReadBandwidth = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + locals->ReadBandwidthPlaneLuma[k] = locals->SwathWidthSingleDPPY[k] + * dml_ceil(locals->BytePerPixelDETY[k], 1) + / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) + * mode_lib->vba.VRatio[k]; + locals->ReadBandwidthPlaneChroma[k] = locals->SwathWidthSingleDPPY[k] + / 2 * dml_ceil(locals->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, + locals->ReadBandwidthPlaneLuma[k] + + locals->ReadBandwidthPlaneChroma[k]); + mode_lib->vba.TotalDataReadBandwidth += locals->ReadBandwidthPlaneLuma[k] + + locals->ReadBandwidthPlaneChroma[k]; + } + + // DCFCLK Deep Sleep + CalculateDCFCLKDeepSleep( + mode_lib, + mode_lib->vba.NumberOfActivePlanes, + locals->BytePerPixelDETY, + locals->BytePerPixelDETC, + mode_lib->vba.VRatio, + locals->SwathWidthY, + mode_lib->vba.DPPPerPlane, + mode_lib->vba.HRatio, + mode_lib->vba.PixelClock, + locals->PSCL_THROUGHPUT_LUMA, + locals->PSCL_THROUGHPUT_CHROMA, + locals->DPPCLK, + &mode_lib->vba.DCFCLKDeepSleep); + + // DSCCLK + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if ((mode_lib->vba.BlendingAndTiming[k] != k) || !mode_lib->vba.DSCEnabled[k]) { + locals->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]) + locals->DSCCLK_calculated[k] = + mode_lib->vba.PixelClockBackEnd[k] / 6 + / mode_lib->vba.DSCFormatFactor + / (1 + - mode_lib->vba.DISPCLKDPPCLKDSCCLKDownSpreading + / 100); + else + locals->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]) { + locals->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 { + locals->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])); + } + locals->DSCDelay[k] = locals->DSCDelay[k] + * mode_lib->vba.PixelClock[k] + / mode_lib->vba.PixelClockBackEnd[k]; + } else { + locals->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]) + locals->DSCDelay[k] = locals->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; + bool PTEBufferSizeNotExceededY; + bool PTEBufferSizeNotExceededC; + + Calculate256BBlockSizes( + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(locals->BytePerPixelDETY[k], 1), + dml_ceil(locals->BytePerPixelDETC[k], 2), + &locals->BlockHeight256BytesY[k], + &locals->BlockHeight256BytesC[k], + &locals->BlockWidth256BytesY[k], + &locals->BlockWidth256BytesC[k]); + + locals->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], + &locals->VInitPreFillY[k], + &locals->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], + locals->BlockHeight256BytesC[k], + locals->BlockWidth256BytesC[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil( + locals->BytePerPixelDETC[k], + 2), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k] / 2, + mode_lib->vba.ViewportHeight[k] / 2, + locals->SwathWidthY[k] / 2, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsChroma, + mode_lib->vba.PitchC[k], + mode_lib->vba.DCCMetaPitchC[k], + &locals->MacroTileWidthC[k], + &MetaRowByteC, + &PixelPTEBytesPerRowC, + &PTEBufferSizeNotExceededC, + &locals->dpte_row_width_chroma_ub[k], + &locals->dpte_row_height_chroma[k], + &locals->meta_req_width_chroma[k], + &locals->meta_req_height_chroma[k], + &locals->meta_row_width_chroma[k], + &locals->meta_row_height_chroma[k], + &locals->vm_group_bytes_chroma, + &locals->dpte_group_bytes_chroma, + &locals->PixelPTEReqWidthC[k], + &locals->PixelPTEReqHeightC[k], + &locals->PTERequestSizeC[k], + &locals->dpde0_bytes_per_frame_ub_c[k], + &locals->meta_pte_bytes_per_frame_ub_c[k]); + + locals->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], + &locals->VInitPreFillC[k], + &locals->MaxNumSwathC[k]); + } else { + PixelPTEBytesPerRowC = 0; + PDEAndMetaPTEBytesFrameC = 0; + MetaRowByteC = 0; + locals->MaxNumSwathC[k] = 0; + locals->PrefetchSourceLinesC[k] = 0; + locals->PTEBufferSizeInRequestsForLuma = mode_lib->vba.PTEBufferSizeInRequestsLuma + mode_lib->vba.PTEBufferSizeInRequestsChroma; + } + + PDEAndMetaPTEBytesFrameY = CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + locals->BlockHeight256BytesY[k], + locals->BlockWidth256BytesY[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(locals->BytePerPixelDETY[k], 1), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k], + mode_lib->vba.ViewportHeight[k], + locals->SwathWidthY[k], + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.VMMPageSize, + locals->PTEBufferSizeInRequestsForLuma, + mode_lib->vba.PitchY[k], + mode_lib->vba.DCCMetaPitchY[k], + &locals->MacroTileWidthY[k], + &MetaRowByteY, + &PixelPTEBytesPerRowY, + &PTEBufferSizeNotExceededY, + &locals->dpte_row_width_luma_ub[k], + &locals->dpte_row_height[k], + &locals->meta_req_width[k], + &locals->meta_req_height[k], + &locals->meta_row_width[k], + &locals->meta_row_height[k], + &locals->vm_group_bytes[k], + &locals->dpte_group_bytes[k], + &locals->PixelPTEReqWidthY[k], + &locals->PixelPTEReqHeightY[k], + &locals->PTERequestSizeY[k], + &locals->dpde0_bytes_per_frame_ub_l[k], + &locals->meta_pte_bytes_per_frame_ub_l[k]); + + locals->PixelPTEBytesPerRow[k] = PixelPTEBytesPerRowY + PixelPTEBytesPerRowC; + locals->PDEAndMetaPTEBytesFrame[k] = PDEAndMetaPTEBytesFrameY + + PDEAndMetaPTEBytesFrameC; + locals->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, + locals->meta_row_height[k], + locals->meta_row_height_chroma[k], + PixelPTEBytesPerRowY, + PixelPTEBytesPerRowC, + locals->dpte_row_height[k], + locals->dpte_row_height_chroma[k], + &locals->meta_row_bw[k], + &locals->dpte_row_bw[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.UrgentOutOfOrderReturnPerChannel = dml_max3( + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelDataOnly, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelVMDataOnly); + + mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency = + (mode_lib->vba.RoundTripPingLatencyCycles + 32) / mode_lib->vba.DCFCLK + + mode_lib->vba.UrgentOutOfOrderReturnPerChannel + * mode_lib->vba.NumberOfChannels + / mode_lib->vba.ReturnBW; + + mode_lib->vba.UrgentExtraLatency = CalculateExtraLatency( + mode_lib->vba.UrgentRoundTripAndOutOfOrderLatency, + mode_lib->vba.TotalActiveDPP, + mode_lib->vba.PixelChunkSizeInKByte, + mode_lib->vba.TotalDCCActiveDPP, + mode_lib->vba.MetaChunkSize, + mode_lib->vba.ReturnBW, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.NumberOfActivePlanes, + mode_lib->vba.DPPPerPlane, + locals->dpte_group_bytes, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels); + + + 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) { + locals->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 + locals->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) { + locals->WritebackDelay[mode_lib->vba.VoltageLevel][k] = + dml_max( + locals->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) + locals->WritebackDelay[mode_lib->vba.VoltageLevel][k] = + locals->WritebackDelay[mode_lib->vba.VoltageLevel][j]; + + mode_lib->vba.VStartupLines = 13; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + locals->MaxVStartupLines[k] = mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k] - dml_max(1.0, dml_ceil(locals->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) + locals->MaximumMaxVStartupLines = dml_max(locals->MaximumMaxVStartupLines, locals->MaxVStartupLines[k]); + + // We don't really care to iterate between the various prefetch modes + //mode_lib->vba.PrefetchERROR = CalculateMinAndMaxPrefetchMode(mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, &mode_lib->vba.MinPrefetchMode, &mode_lib->vba.MaxPrefetchMode); + mode_lib->vba.UrgentLatency = dml_max3(mode_lib->vba.UrgentLatencyPixelDataOnly, mode_lib->vba.UrgentLatencyPixelMixedWithVMData, mode_lib->vba.UrgentLatencyVMDataOnly); + + do { + double MaxTotalRDBandwidth = 0; + double MaxTotalRDBandwidthNoUrgentBurst = 0; + bool DestinationLineTimesForPrefetchLessThan2 = false; + bool VRatioPrefetchMoreThan4 = false; + double TWait = CalculateTWait( + mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb], + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.UrgentLatency, + mode_lib->vba.SREnterPlusExitTime); + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + Pipe myPipe; + HostVM myHostVM; + + if (mode_lib->vba.XFCEnabled[k] == true) { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = + CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + locals->SwathWidthY[k], + dml_ceil( + locals->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; + } + + myPipe.DPPCLK = locals->DPPCLK[k]; + myPipe.DISPCLK = mode_lib->vba.DISPCLK; + myPipe.PixelClock = mode_lib->vba.PixelClock[k]; + myPipe.DCFCLKDeepSleep = mode_lib->vba.DCFCLKDeepSleep; + myPipe.DPPPerPlane = mode_lib->vba.DPPPerPlane[k]; + myPipe.ScalerEnabled = mode_lib->vba.ScalerEnabled[k]; + myPipe.SourceScan = mode_lib->vba.SourceScan[k]; + myPipe.BlockWidth256BytesY = locals->BlockWidth256BytesY[k]; + myPipe.BlockHeight256BytesY = locals->BlockHeight256BytesY[k]; + myPipe.BlockWidth256BytesC = locals->BlockWidth256BytesC[k]; + myPipe.BlockHeight256BytesC = locals->BlockHeight256BytesC[k]; + myPipe.InterlaceEnable = mode_lib->vba.Interlace[k]; + myPipe.NumberOfCursors = mode_lib->vba.NumberOfCursors[k]; + myPipe.VBlank = mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k]; + myPipe.HTotal = mode_lib->vba.HTotal[k]; + + + myHostVM.Enable = mode_lib->vba.HostVMEnable; + myHostVM.MaxPageTableLevels = mode_lib->vba.HostVMMaxPageTableLevels; + myHostVM.CachedPageTableLevels = mode_lib->vba.HostVMCachedPageTableLevels; + + mode_lib->vba.ErrorResult[k] = + CalculatePrefetchSchedule( + mode_lib, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + &myPipe, + locals->DSCDelay[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) (locals->SwathWidthY[k] + / mode_lib->vba.HRatio[k]), + mode_lib->vba.OutputFormat[k], + mode_lib->vba.MaxInterDCNTileRepeaters, + dml_min(mode_lib->vba.VStartupLines, locals->MaxVStartupLines[k]), + locals->MaxVStartupLines[k], + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + &myHostVM, + mode_lib->vba.DynamicMetadataEnable[k], + mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], + mode_lib->vba.DynamicMetadataTransmittedBytes[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.UrgentLatency, + mode_lib->vba.UrgentExtraLatency, + mode_lib->vba.TCalc, + locals->PDEAndMetaPTEBytesFrame[k], + locals->MetaRowByte[k], + locals->PixelPTEBytesPerRow[k], + locals->PrefetchSourceLinesY[k], + locals->SwathWidthY[k], + locals->BytePerPixelDETY[k], + locals->VInitPreFillY[k], + locals->MaxNumSwathY[k], + locals->PrefetchSourceLinesC[k], + locals->BytePerPixelDETC[k], + locals->VInitPreFillC[k], + locals->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.ProgressiveToInterlaceUnitInOPP, + &locals->DSTXAfterScaler[k], + &locals->DSTYAfterScaler[k], + &locals->DestinationLinesForPrefetch[k], + &locals->PrefetchBandwidth[k], + &locals->DestinationLinesToRequestVMInVBlank[k], + &locals->DestinationLinesToRequestRowInVBlank[k], + &locals->VRatioPrefetchY[k], + &locals->VRatioPrefetchC[k], + &locals->RequiredPrefetchPixDataBWLuma[k], + &locals->RequiredPrefetchPixDataBWChroma[k], + &locals->VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + &locals->Tno_bw[k], + &locals->prefetch_vmrow_bw[k], + &locals->swath_width_luma_ub[k], + &locals->swath_width_chroma_ub[k], + &mode_lib->vba.VUpdateOffsetPix[k], + &mode_lib->vba.VUpdateWidthPix[k], + &mode_lib->vba.VReadyOffsetPix[k]); + if (mode_lib->vba.BlendingAndTiming[k] == k) { + locals->VStartup[k] = dml_min( + mode_lib->vba.VStartupLines, + locals->MaxVStartupLines[k]); + if (locals->VStartupRequiredWhenNotEnoughTimeForDynamicMetadata + != 0) { + locals->VStartup[k] = + locals->VStartupRequiredWhenNotEnoughTimeForDynamicMetadata; + } + } else { + locals->VStartup[k] = + dml_min( + mode_lib->vba.VStartupLines, + locals->MaxVStartupLines[mode_lib->vba.BlendingAndTiming[k]]); + } + } + + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + unsigned int m; + + locals->cursor_bw[k] = 0; + locals->cursor_bw_pre[k] = 0; + for (m = 0; m < mode_lib->vba.NumberOfCursors[k]; m++) { + locals->cursor_bw[k] += mode_lib->vba.CursorWidth[k][m] * mode_lib->vba.CursorBPP[k][m] / 8.0 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * mode_lib->vba.VRatio[k]; + locals->cursor_bw_pre[k] += mode_lib->vba.CursorWidth[k][m] * mode_lib->vba.CursorBPP[k][m] / 8.0 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * locals->VRatioPrefetchY[k]; + } + + CalculateUrgentBurstFactor( + mode_lib->vba.DETBufferSizeInKByte, + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.SwathHeightC[k], + locals->SwathWidthY[k], + mode_lib->vba.HTotal[k] / + mode_lib->vba.PixelClock[k], + mode_lib->vba.UrgentLatency, + mode_lib->vba.CursorBufferSize, + mode_lib->vba.CursorWidth[k][0] + mode_lib->vba.CursorWidth[k][1], + dml_max(mode_lib->vba.CursorBPP[k][0], mode_lib->vba.CursorBPP[k][1]), + mode_lib->vba.VRatio[k], + locals->VRatioPrefetchY[k], + locals->VRatioPrefetchC[k], + locals->BytePerPixelDETY[k], + locals->BytePerPixelDETC[k], + &locals->UrgentBurstFactorCursor[k], + &locals->UrgentBurstFactorCursorPre[k], + &locals->UrgentBurstFactorLuma[k], + &locals->UrgentBurstFactorLumaPre[k], + &locals->UrgentBurstFactorChroma[k], + &locals->UrgentBurstFactorChromaPre[k], + &locals->NotEnoughUrgentLatencyHiding, + &locals->NotEnoughUrgentLatencyHidingPre); + + if (mode_lib->vba.UseUrgentBurstBandwidth == false) { + locals->UrgentBurstFactorLuma[k] = 1; + locals->UrgentBurstFactorChroma[k] = 1; + locals->UrgentBurstFactorCursor[k] = 1; + locals->UrgentBurstFactorLumaPre[k] = 1; + locals->UrgentBurstFactorChromaPre[k] = 1; + locals->UrgentBurstFactorCursorPre[k] = 1; + } + + MaxTotalRDBandwidth = MaxTotalRDBandwidth + + dml_max3(locals->prefetch_vmrow_bw[k], + locals->ReadBandwidthPlaneLuma[k] * locals->UrgentBurstFactorLuma[k] + + locals->ReadBandwidthPlaneChroma[k] * locals->UrgentBurstFactorChroma[k] + locals->cursor_bw[k] + * locals->UrgentBurstFactorCursor[k] + locals->meta_row_bw[k] + locals->dpte_row_bw[k], + locals->RequiredPrefetchPixDataBWLuma[k] * locals->UrgentBurstFactorLumaPre[k] + locals->RequiredPrefetchPixDataBWChroma[k] + * locals->UrgentBurstFactorChromaPre[k] + locals->cursor_bw_pre[k] * locals->UrgentBurstFactorCursorPre[k]); + + MaxTotalRDBandwidthNoUrgentBurst = MaxTotalRDBandwidthNoUrgentBurst + + dml_max3(locals->prefetch_vmrow_bw[k], + locals->ReadBandwidthPlaneLuma[k] + locals->ReadBandwidthPlaneChroma[k] + locals->cursor_bw[k] + + locals->meta_row_bw[k] + locals->dpte_row_bw[k], + locals->RequiredPrefetchPixDataBWLuma[k] + locals->RequiredPrefetchPixDataBWChroma[k] + locals->cursor_bw_pre[k]); + + if (locals->DestinationLinesForPrefetch[k] < 2) + DestinationLineTimesForPrefetchLessThan2 = true; + if (locals->VRatioPrefetchY[k] > 4 || locals->VRatioPrefetchC[k] > 4) + VRatioPrefetchMoreThan4 = true; + } + mode_lib->vba.FractionOfUrgentBandwidth = MaxTotalRDBandwidthNoUrgentBurst / mode_lib->vba.ReturnBW; + + if (MaxTotalRDBandwidth <= mode_lib->vba.ReturnBW && locals->NotEnoughUrgentLatencyHiding == 0 && locals->NotEnoughUrgentLatencyHidingPre == 0 && !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) { + 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 + - dml_max( + locals->ReadBandwidthPlaneLuma[k] * locals->UrgentBurstFactorLuma[k] + + locals->ReadBandwidthPlaneChroma[k] * locals->UrgentBurstFactorChroma[k] + + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k], + locals->RequiredPrefetchPixDataBWLuma[k] * locals->UrgentBurstFactorLumaPre[k] + + locals->RequiredPrefetchPixDataBWChroma[k] * locals->UrgentBurstFactorChromaPre[k] + + locals->cursor_bw_pre[k] * locals->UrgentBurstFactorCursorPre[k]); + } + + mode_lib->vba.TotImmediateFlipBytes = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.TotImmediateFlipBytes = mode_lib->vba.TotImmediateFlipBytes + locals->PDEAndMetaPTEBytesFrame[k] + locals->MetaRowByte[k] + locals->PixelPTEBytesPerRow[k]; + } + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + CalculateFlipSchedule( + mode_lib, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + mode_lib->vba.UrgentExtraLatency, + mode_lib->vba.UrgentLatency, + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.GPUVMEnable, + locals->PDEAndMetaPTEBytesFrame[k], + locals->MetaRowByte[k], + locals->PixelPTEBytesPerRow[k], + mode_lib->vba.BandwidthAvailableForImmediateFlip, + mode_lib->vba.TotImmediateFlipBytes, + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.VRatio[k], + locals->Tno_bw[k], + mode_lib->vba.DCCEnable[k], + locals->dpte_row_height[k], + locals->meta_row_height[k], + locals->dpte_row_height_chroma[k], + locals->meta_row_height_chroma[k], + &locals->DestinationLinesToRequestVMInImmediateFlip[k], + &locals->DestinationLinesToRequestRowInImmediateFlip[k], + &locals->final_flip_bw[k], + &locals->ImmediateFlipSupportedForPipe[k]); + } + mode_lib->vba.total_dcn_read_bw_with_flip = 0.0; + mode_lib->vba.total_dcn_read_bw_with_flip_no_urgent_burst = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + mode_lib->vba.total_dcn_read_bw_with_flip = + mode_lib->vba.total_dcn_read_bw_with_flip + dml_max3( + locals->prefetch_vmrow_bw[k], + locals->final_flip_bw[k] + locals->ReadBandwidthLuma[k] * locals->UrgentBurstFactorLuma[k] + + locals->ReadBandwidthChroma[k] * locals->UrgentBurstFactorChroma[k] + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k], + locals->final_flip_bw[k] + locals->RequiredPrefetchPixDataBWLuma[k] * locals->UrgentBurstFactorLumaPre[k] + + locals->RequiredPrefetchPixDataBWChroma[k] * locals->UrgentBurstFactorChromaPre[k] + + locals->cursor_bw_pre[k] * locals->UrgentBurstFactorCursorPre[k]); + mode_lib->vba.total_dcn_read_bw_with_flip_no_urgent_burst = + mode_lib->vba.total_dcn_read_bw_with_flip_no_urgent_burst + + dml_max3(locals->prefetch_vmrow_bw[k], + locals->final_flip_bw[k] + locals->ReadBandwidthPlaneLuma[k] + locals->ReadBandwidthPlaneChroma[k] + locals->cursor_bw[k], + locals->final_flip_bw[k] + locals->RequiredPrefetchPixDataBWLuma[k] + locals->RequiredPrefetchPixDataBWChroma[k] + locals->cursor_bw_pre[k]); + + } + mode_lib->vba.FractionOfUrgentBandwidthImmediateFlip = mode_lib->vba.total_dcn_read_bw_with_flip_no_urgent_burst / mode_lib->vba.ReturnBW; + + mode_lib->vba.ImmediateFlipSupported = true; + if (mode_lib->vba.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 (locals->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.HostVMEnable) + || mode_lib->vba.ImmediateFlipSupported)) + || locals->MaximumMaxVStartupLines < mode_lib->vba.VStartupLines)); + + //Watermarks and NB P-State/DRAM Clock Change Support + { + enum clock_change_support DRAMClockChangeSupport; // dummy + CalculateWatermarksAndDRAMSpeedChangeSupport( + mode_lib, + mode_lib->vba.PrefetchMode[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb], + mode_lib->vba.NumberOfActivePlanes, + mode_lib->vba.MaxLineBufferLines, + mode_lib->vba.LineBufferSize, + mode_lib->vba.DPPOutputBufferPixels, + mode_lib->vba.DETBufferSizeInKByte, + mode_lib->vba.WritebackInterfaceLumaBufferSize, + mode_lib->vba.WritebackInterfaceChromaBufferSize, + mode_lib->vba.DCFCLK, + mode_lib->vba.UrgentOutOfOrderReturnPerChannel * mode_lib->vba.NumberOfChannels, + mode_lib->vba.ReturnBW, + mode_lib->vba.GPUVMEnable, + locals->dpte_group_bytes, + mode_lib->vba.MetaChunkSize, + mode_lib->vba.UrgentLatency, + mode_lib->vba.UrgentExtraLatency, + mode_lib->vba.WritebackLatency, + mode_lib->vba.WritebackChunkSize, + mode_lib->vba.SOCCLK, + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.SRExitTime, + mode_lib->vba.SREnterPlusExitTime, + mode_lib->vba.DCFCLKDeepSleep, + mode_lib->vba.DPPPerPlane, + mode_lib->vba.DCCEnable, + locals->DPPCLK, + locals->SwathWidthSingleDPPY, + mode_lib->vba.SwathHeightY, + locals->ReadBandwidthPlaneLuma, + mode_lib->vba.SwathHeightC, + locals->ReadBandwidthPlaneChroma, + mode_lib->vba.LBBitPerPixel, + locals->SwathWidthY, + mode_lib->vba.HRatio, + mode_lib->vba.vtaps, + mode_lib->vba.VTAPsChroma, + mode_lib->vba.VRatio, + mode_lib->vba.HTotal, + mode_lib->vba.PixelClock, + mode_lib->vba.BlendingAndTiming, + locals->BytePerPixelDETY, + locals->BytePerPixelDETC, + mode_lib->vba.WritebackEnable, + mode_lib->vba.WritebackPixelFormat, + mode_lib->vba.WritebackDestinationWidth, + mode_lib->vba.WritebackDestinationHeight, + mode_lib->vba.WritebackSourceHeight, + &DRAMClockChangeSupport, + &mode_lib->vba.UrgentWatermark, + &mode_lib->vba.WritebackUrgentWatermark, + &mode_lib->vba.DRAMClockChangeWatermark, + &mode_lib->vba.WritebackDRAMClockChangeWatermark, + &mode_lib->vba.StutterExitWatermark, + &mode_lib->vba.StutterEnterPlusExitWatermark, + &mode_lib->vba.MinActiveDRAMClockChangeLatencySupported); + } + + + //Display Pipeline Delivery Time in Prefetch, Groups + CalculatePixelDeliveryTimes( + mode_lib->vba.NumberOfActivePlanes, + mode_lib->vba.VRatio, + locals->VRatioPrefetchY, + locals->VRatioPrefetchC, + locals->swath_width_luma_ub, + locals->swath_width_chroma_ub, + mode_lib->vba.DPPPerPlane, + mode_lib->vba.HRatio, + mode_lib->vba.PixelClock, + locals->PSCL_THROUGHPUT_LUMA, + locals->PSCL_THROUGHPUT_CHROMA, + locals->DPPCLK, + locals->BytePerPixelDETC, + mode_lib->vba.SourceScan, + locals->BlockWidth256BytesY, + locals->BlockHeight256BytesY, + locals->BlockWidth256BytesC, + locals->BlockHeight256BytesC, + locals->DisplayPipeLineDeliveryTimeLuma, + locals->DisplayPipeLineDeliveryTimeChroma, + locals->DisplayPipeLineDeliveryTimeLumaPrefetch, + locals->DisplayPipeLineDeliveryTimeChromaPrefetch, + locals->DisplayPipeRequestDeliveryTimeLuma, + locals->DisplayPipeRequestDeliveryTimeChroma, + locals->DisplayPipeRequestDeliveryTimeLumaPrefetch, + locals->DisplayPipeRequestDeliveryTimeChromaPrefetch); + + CalculateMetaAndPTETimes( + mode_lib->vba.NumberOfActivePlanes, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.MetaChunkSize, + mode_lib->vba.MinMetaChunkSizeBytes, + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.HTotal, + mode_lib->vba.VRatio, + locals->VRatioPrefetchY, + locals->VRatioPrefetchC, + locals->DestinationLinesToRequestRowInVBlank, + locals->DestinationLinesToRequestRowInImmediateFlip, + locals->DestinationLinesToRequestVMInVBlank, + locals->DestinationLinesToRequestVMInImmediateFlip, + mode_lib->vba.DCCEnable, + mode_lib->vba.PixelClock, + locals->BytePerPixelDETY, + locals->BytePerPixelDETC, + mode_lib->vba.SourceScan, + locals->dpte_row_height, + locals->dpte_row_height_chroma, + locals->meta_row_width, + locals->meta_row_height, + locals->meta_req_width, + locals->meta_req_height, + locals->dpte_group_bytes, + locals->PTERequestSizeY, + locals->PTERequestSizeC, + locals->PixelPTEReqWidthY, + locals->PixelPTEReqHeightY, + locals->PixelPTEReqWidthC, + locals->PixelPTEReqHeightC, + locals->dpte_row_width_luma_ub, + locals->dpte_row_width_chroma_ub, + locals->vm_group_bytes, + locals->dpde0_bytes_per_frame_ub_l, + locals->dpde0_bytes_per_frame_ub_c, + locals->meta_pte_bytes_per_frame_ub_l, + locals->meta_pte_bytes_per_frame_ub_c, + locals->DST_Y_PER_PTE_ROW_NOM_L, + locals->DST_Y_PER_PTE_ROW_NOM_C, + locals->DST_Y_PER_META_ROW_NOM_L, + locals->TimePerMetaChunkNominal, + locals->TimePerMetaChunkVBlank, + locals->TimePerMetaChunkFlip, + locals->time_per_pte_group_nom_luma, + locals->time_per_pte_group_vblank_luma, + locals->time_per_pte_group_flip_luma, + locals->time_per_pte_group_nom_chroma, + locals->time_per_pte_group_vblank_chroma, + locals->time_per_pte_group_flip_chroma, + locals->TimePerVMGroupVBlank, + locals->TimePerVMGroupFlip, + locals->TimePerVMRequestVBlank, + locals->TimePerVMRequestFlip); + + + // 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) { + locals->AllowDRAMClockChangeDuringVBlank[k] = true; + locals->AllowDRAMSelfRefreshDuringVBlank[k] = true; + locals->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) { + locals->AllowDRAMClockChangeDuringVBlank[k] = false; + locals->AllowDRAMSelfRefreshDuringVBlank[k] = true; + locals->MinTTUVBlank[k] = dml_max( + mode_lib->vba.StutterEnterPlusExitWatermark, + mode_lib->vba.UrgentWatermark); + } else { + locals->AllowDRAMClockChangeDuringVBlank[k] = false; + locals->AllowDRAMSelfRefreshDuringVBlank[k] = false; + locals->MinTTUVBlank[k] = mode_lib->vba.UrgentWatermark; + } + if (!mode_lib->vba.DynamicMetadataEnable[k]) + locals->MinTTUVBlank[k] = mode_lib->vba.TCalc + + locals->MinTTUVBlank[k]; + } + + // DCC Configuration + mode_lib->vba.ActiveDPPs = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + locals->MaximumDCCCompressionYSurface[k] = CalculateDCCConfiguration( + mode_lib->vba.DCCEnable[k], + false, // We should always know the direction DCCProgrammingAssumesScanDirectionUnknown, + mode_lib->vba.ViewportWidth[k], + mode_lib->vba.ViewportHeight[k], + mode_lib->vba.DETBufferSizeInKByte * 1024, + locals->BlockHeight256BytesY[k], + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.SurfaceTiling[k], + locals->BytePerPixelDETY[k], + mode_lib->vba.SourceScan[k], + &locals->DCCYMaxUncompressedBlock[k], + &locals->DCCYMaxCompressedBlock[k], + &locals->DCCYIndependent64ByteBlock[k]); + } + + //XFC Parameters: + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.XFCEnabled[k] == true) { + double TWait; + + locals->XFCSlaveVUpdateOffset[k] = mode_lib->vba.XFCTSlvVupdateOffset; + locals->XFCSlaveVupdateWidth[k] = mode_lib->vba.XFCTSlvVupdateWidth; + locals->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.UrgentLatency, + mode_lib->vba.SREnterPlusExitTime); + mode_lib->vba.XFCRemoteSurfaceFlipDelay = CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + locals->SwathWidthY[k], + dml_ceil(locals->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); + locals->XFCRemoteSurfaceFlipLatency[k] = + dml_floor( + mode_lib->vba.XFCRemoteSurfaceFlipDelay + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1); + locals->XFCTransferDelay[k] = + dml_ceil( + mode_lib->vba.XFCBusTransportTime + / (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]), + 1); + locals->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 = + (locals->DestinationLinesToRequestVMInVBlank[k] + + locals->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); + locals->XFCPrefetchMargin[k] = + mode_lib->vba.XFCRemoteSurfaceFlipDelay + + mode_lib->vba.TFinalxFill + + (locals->DestinationLinesToRequestVMInVBlank[k] + + locals->DestinationLinesToRequestRowInVBlank[k]) + * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + } else { + locals->XFCSlaveVUpdateOffset[k] = 0; + locals->XFCSlaveVupdateWidth[k] = 0; + locals->XFCSlaveVReadyOffset[k] = 0; + locals->XFCRemoteSurfaceFlipLatency[k] = 0; + locals->XFCPrechargeDelay[k] = 0; + locals->XFCTransferDelay[k] = 0; + locals->XFCPrefetchMargin[k] = 0; + } + } + + // Stutter Efficiency + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + CalculateDETBufferSize( + mode_lib->vba.DETBufferSizeInKByte, + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.SwathHeightC[k], + &locals->DETBufferSizeY[k], + &locals->DETBufferSizeC[k]); + + locals->LinesInDETY[k] = locals->DETBufferSizeY[k] + / locals->BytePerPixelDETY[k] / locals->SwathWidthY[k]; + locals->LinesInDETYRoundedDownToSwath[k] = dml_floor( + locals->LinesInDETY[k], + mode_lib->vba.SwathHeightY[k]); + locals->FullDETBufferingTimeY[k] = + locals->LinesInDETYRoundedDownToSwath[k] + * (mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]) + / mode_lib->vba.VRatio[k]; + } + + mode_lib->vba.StutterPeriod = 999999.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (locals->FullDETBufferingTimeY[k] < mode_lib->vba.StutterPeriod) { + mode_lib->vba.StutterPeriod = locals->FullDETBufferingTimeY[k]; + mode_lib->vba.FrameTimeForMinFullDETBufferingTime = + (double) mode_lib->vba.VTotal[k] * mode_lib->vba.HTotal[k] + / mode_lib->vba.PixelClock[k]; + locals->BytePerPixelYCriticalPlane = dml_ceil(locals->BytePerPixelDETY[k], 1); + locals->SwathWidthYCriticalPlane = locals->SwathWidthY[k]; + locals->LinesToFinishSwathTransferStutterCriticalPlane = + mode_lib->vba.SwathHeightY[k] - (locals->LinesInDETY[k] - locals->LinesInDETYRoundedDownToSwath[k]); + } + } + + mode_lib->vba.AverageReadBandwidth = 0.0; + mode_lib->vba.TotalRowReadBandwidth = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + unsigned int DCCRateLimit; + + if (mode_lib->vba.DCCEnable[k]) { + if (locals->DCCYMaxCompressedBlock[k] == 256) + DCCRateLimit = 4; + else + DCCRateLimit = 2; + + mode_lib->vba.AverageReadBandwidth = + mode_lib->vba.AverageReadBandwidth + + (locals->ReadBandwidthPlaneLuma[k] + locals->ReadBandwidthPlaneChroma[k]) / + dml_min(mode_lib->vba.DCCRate[k], DCCRateLimit); + } else { + mode_lib->vba.AverageReadBandwidth = + mode_lib->vba.AverageReadBandwidth + + locals->ReadBandwidthPlaneLuma[k] + + locals->ReadBandwidthPlaneChroma[k]; + } + mode_lib->vba.TotalRowReadBandwidth = mode_lib->vba.TotalRowReadBandwidth + + locals->meta_row_bw[k] + locals->dpte_row_bw[k]; + } + + mode_lib->vba.AverageDCCCompressionRate = mode_lib->vba.TotalDataReadBandwidth / mode_lib->vba.AverageReadBandwidth; + + mode_lib->vba.PartOfBurstThatFitsInROB = + dml_min( + mode_lib->vba.StutterPeriod + * mode_lib->vba.TotalDataReadBandwidth, + mode_lib->vba.ROBBufferSizeInKByte * 1024 + * mode_lib->vba.AverageDCCCompressionRate); + mode_lib->vba.StutterBurstTime = mode_lib->vba.PartOfBurstThatFitsInROB + / mode_lib->vba.AverageDCCCompressionRate / mode_lib->vba.ReturnBW + + (mode_lib->vba.StutterPeriod * mode_lib->vba.TotalDataReadBandwidth + - mode_lib->vba.PartOfBurstThatFitsInROB) + / (mode_lib->vba.DCFCLK * 64) + + mode_lib->vba.StutterPeriod * mode_lib->vba.TotalRowReadBandwidth / mode_lib->vba.ReturnBW; + mode_lib->vba.StutterBurstTime = dml_max( + mode_lib->vba.StutterBurstTime, + (locals->LinesToFinishSwathTransferStutterCriticalPlane * locals->BytePerPixelYCriticalPlane * + locals->SwathWidthYCriticalPlane / mode_lib->vba.ReturnBW) + ); + + mode_lib->vba.TotalActiveWriteback = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.WritebackEnable[k] == true) { + mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1; + } + } + + if (mode_lib->vba.TotalActiveWriteback == 0) { + mode_lib->vba.StutterEfficiencyNotIncludingVBlank = (1 + - (mode_lib->vba.SRExitTime + mode_lib->vba.StutterBurstTime) + / mode_lib->vba.StutterPeriod) * 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; +} + +static void DisplayPipeConfiguration(struct display_mode_lib *mode_lib) +{ + // Display Pipe Configuration + 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 { + 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; + } + + CalculateDETBufferSize( + mode_lib->vba.DETBufferSizeInKByte, + mode_lib->vba.SwathHeightY[k], + mode_lib->vba.SwathHeightC[k], + &mode_lib->vba.DETBufferSizeY[k], + &mode_lib->vba.DETBufferSizeC[k]); + } +} + +static double CalculateTWait( + unsigned int PrefetchMode, + double DRAMClockChangeLatency, + double UrgentLatency, + double SREnterPlusExitTime) +{ + if (PrefetchMode == 0) { + return dml_max( + DRAMClockChangeLatency + UrgentLatency, + dml_max(SREnterPlusExitTime, UrgentLatency)); + } else if (PrefetchMode == 1) { + return dml_max(SREnterPlusExitTime, UrgentLatency); + } else { + return UrgentLatency; + } +} + +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) +{ + 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); + } +} + +static void CalculateFlipSchedule( + struct display_mode_lib *mode_lib, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + double UrgentExtraLatency, + double UrgentLatency, + unsigned int GPUVMMaxPageTableLevels, + bool HostVMEnable, + unsigned int HostVMMaxPageTableLevels, + unsigned int HostVMCachedPageTableLevels, + bool GPUVMEnable, + double PDEAndMetaPTEBytesPerFrame, + double MetaRowBytes, + double DPTEBytesPerRow, + double BandwidthAvailableForImmediateFlip, + unsigned int TotImmediateFlipBytes, + enum source_format_class SourcePixelFormat, + double LineTime, + double VRatio, + double Tno_bw, + bool DCCEnable, + unsigned int dpte_row_height, + unsigned int meta_row_height, + unsigned int dpte_row_height_chroma, + unsigned int meta_row_height_chroma, + double *DestinationLinesToRequestVMInImmediateFlip, + double *DestinationLinesToRequestRowInImmediateFlip, + double *final_flip_bw, + bool *ImmediateFlipSupportedForPipe) +{ + double min_row_time = 0.0; + unsigned int HostVMDynamicLevels; + double TimeForFetchingMetaPTEImmediateFlip; + double TimeForFetchingRowInVBlankImmediateFlip; + double ImmediateFlipBW; + double HostVMInefficiencyFactor; + + if (GPUVMEnable == true && HostVMEnable == true) { + HostVMInefficiencyFactor = + PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData + / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; + HostVMDynamicLevels = HostVMMaxPageTableLevels - HostVMCachedPageTableLevels; + } else { + HostVMInefficiencyFactor = 1; + HostVMDynamicLevels = 0; + } + + ImmediateFlipBW = (PDEAndMetaPTEBytesPerFrame + MetaRowBytes + DPTEBytesPerRow) + * BandwidthAvailableForImmediateFlip / TotImmediateFlipBytes; + + if (GPUVMEnable == true) { + TimeForFetchingMetaPTEImmediateFlip = dml_max3( + Tno_bw + PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / ImmediateFlipBW, + UrgentExtraLatency + UrgentLatency * (GPUVMMaxPageTableLevels * (HostVMDynamicLevels + 1) - 1), + LineTime / 4.0); + } else { + TimeForFetchingMetaPTEImmediateFlip = 0; + } + + *DestinationLinesToRequestVMInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingMetaPTEImmediateFlip / LineTime), 1) / 4.0; + if ((GPUVMEnable == true || DCCEnable == true)) { + TimeForFetchingRowInVBlankImmediateFlip = dml_max3((MetaRowBytes + DPTEBytesPerRow) * HostVMInefficiencyFactor / ImmediateFlipBW, UrgentLatency * (HostVMDynamicLevels + 1), LineTime / 4); + } else { + TimeForFetchingRowInVBlankImmediateFlip = 0; + } + + *DestinationLinesToRequestRowInImmediateFlip = dml_ceil(4.0 * (TimeForFetchingRowInVBlankImmediateFlip / LineTime), 1) / 4.0; + *final_flip_bw = dml_max(PDEAndMetaPTEBytesPerFrame * HostVMInefficiencyFactor / (*DestinationLinesToRequestVMInImmediateFlip * LineTime), (MetaRowBytes + DPTEBytesPerRow) * HostVMInefficiencyFactor / (*DestinationLinesToRequestRowInImmediateFlip * LineTime)); + if (SourcePixelFormat == dm_420_8 || SourcePixelFormat == dm_420_10) { + if (GPUVMEnable == true && DCCEnable != true) { + min_row_time = dml_min( + dpte_row_height * LineTime / VRatio, + dpte_row_height_chroma * LineTime / (VRatio / 2)); + } else if (GPUVMEnable != true && DCCEnable == true) { + min_row_time = dml_min( + meta_row_height * LineTime / VRatio, + meta_row_height_chroma * LineTime / (VRatio / 2)); + } else { + min_row_time = dml_min4( + dpte_row_height * LineTime / VRatio, + meta_row_height * LineTime / VRatio, + dpte_row_height_chroma * LineTime / (VRatio / 2), + meta_row_height_chroma * LineTime / (VRatio / 2)); + } + } else { + if (GPUVMEnable == true && DCCEnable != true) { + min_row_time = dpte_row_height * LineTime / VRatio; + } else if (GPUVMEnable != true && DCCEnable == true) { + min_row_time = meta_row_height * LineTime / VRatio; + } else { + min_row_time = dml_min( + dpte_row_height * LineTime / VRatio, + meta_row_height * LineTime / VRatio); + } + } + + if (*DestinationLinesToRequestVMInImmediateFlip >= 32 + || *DestinationLinesToRequestRowInImmediateFlip >= 16 + || TimeForFetchingMetaPTEImmediateFlip + 2 * TimeForFetchingRowInVBlankImmediateFlip > min_row_time) { + *ImmediateFlipSupportedForPipe = false; + } else { + *ImmediateFlipSupportedForPipe = true; + } +} + +static unsigned int TruncToValidBPP( + double DecimalBPP, + double DesiredBPP, + 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 && (DesiredBPP == 0 || DesiredBPP == 18)) + return 18; + else if (DecimalBPP >= 15 && (DesiredBPP == 0 || DesiredBPP == 15)) + return 15; + else if (DecimalBPP >= 12 && (DesiredBPP == 0 || DesiredBPP == 12)) + return 12; + else + return BPP_INVALID; + } else if (Format == dm_444) { + if (DecimalBPP >= 36 && (DesiredBPP == 0 || DesiredBPP == 36)) + return 36; + else if (DecimalBPP >= 30 && (DesiredBPP == 0 || DesiredBPP == 30)) + return 30; + else if (DecimalBPP >= 24 && (DesiredBPP == 0 || DesiredBPP == 24)) + return 24; + else if (DecimalBPP >= 18 && (DesiredBPP == 0 || DesiredBPP == 18)) + return 18; + else + return BPP_INVALID; + } else { + if (DecimalBPP / 1.5 >= 24 && (DesiredBPP == 0 || DesiredBPP == 24)) + return 24; + else if (DecimalBPP / 1.5 >= 20 && (DesiredBPP == 0 || DesiredBPP == 20)) + return 20; + else if (DecimalBPP / 1.5 >= 16 && (DesiredBPP == 0 || DesiredBPP == 16)) + return 16; + else + return BPP_INVALID; + } + } else { + if (DSCEnabled) { + if (Format == dm_420) { + if (DesiredBPP == 0) { + if (DecimalBPP < 6) + return BPP_INVALID; + else if (DecimalBPP >= 1.5 * DSCInputBitPerComponent - 1.0 / 16.0) + return 1.5 * DSCInputBitPerComponent - 1.0 / 16.0; + else + return dml_floor(16 * DecimalBPP, 1) / 16.0; + } else { + if (DecimalBPP < 6 + || DesiredBPP < 6 + || DesiredBPP > 1.5 * DSCInputBitPerComponent - 1.0 / 16.0 + || DecimalBPP < DesiredBPP) { + return BPP_INVALID; + } else { + return DesiredBPP; + } + } + } else if (Format == dm_n422) { + if (DesiredBPP == 0) { + if (DecimalBPP < 7) + return BPP_INVALID; + else if (DecimalBPP >= 2 * DSCInputBitPerComponent - 1.0 / 16.0) + return 2 * DSCInputBitPerComponent - 1.0 / 16.0; + else + return dml_floor(16 * DecimalBPP, 1) / 16.0; + } else { + if (DecimalBPP < 7 + || DesiredBPP < 7 + || DesiredBPP > 2 * DSCInputBitPerComponent - 1.0 / 16.0 + || DecimalBPP < DesiredBPP) { + return BPP_INVALID; + } else { + return DesiredBPP; + } + } + } else { + if (DesiredBPP == 0) { + if (DecimalBPP < 8) + return BPP_INVALID; + else if (DecimalBPP >= 3 * DSCInputBitPerComponent - 1.0 / 16.0) + return 3 * DSCInputBitPerComponent - 1.0 / 16.0; + else + return dml_floor(16 * DecimalBPP, 1) / 16.0; + } else { + if (DecimalBPP < 8 + || DesiredBPP < 8 + || DesiredBPP > 3 * DSCInputBitPerComponent - 1.0 / 16.0 + || DecimalBPP < DesiredBPP) { + return BPP_INVALID; + } else { + return DesiredBPP; + } + } + } + } else if (Format == dm_420) { + if (DecimalBPP >= 18 && (DesiredBPP == 0 || DesiredBPP == 18)) + return 18; + else if (DecimalBPP >= 15 && (DesiredBPP == 0 || DesiredBPP == 15)) + return 15; + else if (DecimalBPP >= 12 && (DesiredBPP == 0 || DesiredBPP == 12)) + return 12; + else + return BPP_INVALID; + } else if (Format == dm_s422 || Format == dm_n422) { + if (DecimalBPP >= 24 && (DesiredBPP == 0 || DesiredBPP == 24)) + return 24; + else if (DecimalBPP >= 20 && (DesiredBPP == 0 || DesiredBPP == 20)) + return 20; + else if (DecimalBPP >= 16 && (DesiredBPP == 0 || DesiredBPP == 16)) + return 16; + else + return BPP_INVALID; + } else { + if (DecimalBPP >= 36 && (DesiredBPP == 0 || DesiredBPP == 36)) + return 36; + else if (DecimalBPP >= 30 && (DesiredBPP == 0 || DesiredBPP == 30)) + return 30; + else if (DecimalBPP >= 24 && (DesiredBPP == 0 || DesiredBPP == 24)) + return 24; + else + return BPP_INVALID; + } + } +} + +void dml21_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->IdealSDPPortBandwidthPerState[i] = dml_min3( + mode_lib->vba.ReturnBusWidth * mode_lib->vba.DCFCLKPerState[i], + mode_lib->vba.DRAMSpeedPerState[i] * mode_lib->vba.NumberOfChannels + * mode_lib->vba.DRAMChannelWidth, + mode_lib->vba.FabricClockPerState[i] + * mode_lib->vba.FabricDatapathToDCNDataReturn); + if (mode_lib->vba.HostVMEnable == false) { + locals->ReturnBWPerState[i] = locals->IdealSDPPortBandwidthPerState[i] + * mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelDataOnly / 100.0; + } else { + locals->ReturnBWPerState[i] = locals->IdealSDPPortBandwidthPerState[i] + * mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / 100.0; + } + } + /*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] + + dml_max3(mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelDataOnly, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelVMDataOnly) + * 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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, + mode_lib->vba.ForcedOutputLinkBPP[k], + 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 <= 1; ++j) { + locals->TotalNumberOfDCCActiveDPP[i][j] = 0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (mode_lib->vba.DCCEnable[k] == true) + locals->TotalNumberOfDCCActiveDPP[i][j] = locals->TotalNumberOfDCCActiveDPP[i][j] + locals->NoOfDPP[i][j][k]; + } + } + } + + mode_lib->vba.UrgentLatency = dml_max3( + mode_lib->vba.UrgentLatencyPixelDataOnly, + mode_lib->vba.UrgentLatencyPixelMixedWithVMData, + mode_lib->vba.UrgentLatencyVMDataOnly); + mode_lib->vba.PrefetchERROR = CalculateMinAndMaxPrefetchMode( + mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, + &mode_lib->vba.MinPrefetchMode, + &mode_lib->vba.MaxPrefetchMode); + + 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++) { + locals->RequiredDPPCLKThisState[k] = locals->RequiredDPPCLK[i][j][k]; + locals->NoOfDPPThisState[k] = locals->NoOfDPP[i][j][k]; + if (locals->ODMCombineEnablePerState[i][k] == true) { + locals->SwathWidthYThisState[k] = + dml_min(locals->SwathWidthYSingleDPP[k], dml_round(mode_lib->vba.HActive[k] / 2.0 * mode_lib->vba.HRatio[k])); + } else { + locals->SwathWidthYThisState[k] = locals->SwathWidthYSingleDPP[k] / locals->NoOfDPP[i][j][k]; + } + mode_lib->vba.SwathWidthGranularityY = 256.0 + / dml_ceil(locals->BytePerPixelInDETY[k], 1.0) + / locals->MaxSwathHeightY[k]; + mode_lib->vba.RoundedUpMaxSwathSizeBytesY = + (dml_ceil(locals->SwathWidthYThisState[k] - 1.0, mode_lib->vba.SwathWidthGranularityY) + + mode_lib->vba.SwathWidthGranularityY) * locals->BytePerPixelInDETY[k] * locals->MaxSwathHeightY[k]; + if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { + mode_lib->vba.RoundedUpMaxSwathSizeBytesY = dml_ceil( + mode_lib->vba.RoundedUpMaxSwathSizeBytesY, + 256.0) + 256; + } + if (locals->MaxSwathHeightC[k] > 0.0) { + mode_lib->vba.SwathWidthGranularityC = 256.0 / dml_ceil(locals->BytePerPixelInDETC[k], 2.0) / locals->MaxSwathHeightC[k]; + mode_lib->vba.RoundedUpMaxSwathSizeBytesC = (dml_ceil(locals->SwathWidthYThisState[k] / 2.0 - 1.0, mode_lib->vba.SwathWidthGranularityC) + + mode_lib->vba.SwathWidthGranularityC) * locals->BytePerPixelInDETC[k] * locals->MaxSwathHeightC[k]; + if (mode_lib->vba.SourcePixelFormat[k] == dm_420_10) { + mode_lib->vba.RoundedUpMaxSwathSizeBytesC = dml_ceil(mode_lib->vba.RoundedUpMaxSwathSizeBytesC, 256.0) + 256; + } + } else { + mode_lib->vba.RoundedUpMaxSwathSizeBytesC = 0.0; + } + if (mode_lib->vba.RoundedUpMaxSwathSizeBytesY + mode_lib->vba.RoundedUpMaxSwathSizeBytesC + <= mode_lib->vba.DETBufferSizeInKByte * 1024.0 / 2.0) { + locals->SwathHeightYThisState[k] = locals->MaxSwathHeightY[k]; + locals->SwathHeightCThisState[k] = locals->MaxSwathHeightC[k]; + } else { + locals->SwathHeightYThisState[k] = + locals->MinSwathHeightY[k]; + locals->SwathHeightCThisState[k] = + locals->MinSwathHeightC[k]; + } + } + + CalculateDCFCLKDeepSleep( + mode_lib, + mode_lib->vba.NumberOfActivePlanes, + locals->BytePerPixelInDETY, + locals->BytePerPixelInDETC, + mode_lib->vba.VRatio, + locals->SwathWidthYThisState, + locals->NoOfDPPThisState, + mode_lib->vba.HRatio, + mode_lib->vba.PixelClock, + locals->PSCL_FACTOR, + locals->PSCL_FACTOR_CHROMA, + locals->RequiredDPPCLKThisState, + &mode_lib->vba.ProjectedDCFCLKDeepSleep); + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; 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], + locals->Read256BlockHeightC[k], + locals->Read256BlockWidthC[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(locals->BytePerPixelInDETC[k], 2.0), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k] / 2.0, + mode_lib->vba.ViewportHeight[k] / 2.0, + locals->SwathWidthYThisState[k] / 2.0, + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.VMMPageSize, + mode_lib->vba.PTEBufferSizeInRequestsChroma, + mode_lib->vba.PitchC[k], + 0.0, + &locals->MacroTileWidthC[k], + &mode_lib->vba.MetaRowBytesC, + &mode_lib->vba.DPTEBytesPerRowC, + &locals->PTEBufferSizeNotExceededC[i][j][k], + locals->dpte_row_width_chroma_ub, + &locals->dpte_row_height_chroma[k], + &locals->meta_req_width_chroma[k], + &locals->meta_req_height_chroma[k], + &locals->meta_row_width_chroma[k], + &locals->meta_row_height_chroma[k], + &locals->vm_group_bytes_chroma, + &locals->dpte_group_bytes_chroma, + locals->PixelPTEReqWidthC, + locals->PixelPTEReqHeightC, + locals->PTERequestSizeC, + locals->dpde0_bytes_per_frame_ub_c, + locals->meta_pte_bytes_per_frame_ub_c); + locals->PrefetchLinesC[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k]/2, + mode_lib->vba.VTAPsChroma[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + locals->SwathHeightCThisState[k], + mode_lib->vba.ViewportYStartC[k], + &locals->PrefillC[k], + &locals->MaxNumSwC[k]); + locals->PTEBufferSizeInRequestsForLuma = mode_lib->vba.PTEBufferSizeInRequestsLuma; + } 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; + } + mode_lib->vba.PDEAndMetaPTEBytesPerFrameY = CalculateVMAndRowBytes( + mode_lib, + mode_lib->vba.DCCEnable[k], + locals->Read256BlockHeightY[k], + locals->Read256BlockWidthY[k], + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.SurfaceTiling[k], + dml_ceil(locals->BytePerPixelInDETY[k], 1.0), + mode_lib->vba.SourceScan[k], + mode_lib->vba.ViewportWidth[k], + mode_lib->vba.ViewportHeight[k], + locals->SwathWidthYThisState[k], + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.VMMPageSize, + locals->PTEBufferSizeInRequestsForLuma, + mode_lib->vba.PitchY[k], + mode_lib->vba.DCCMetaPitchY[k], + &locals->MacroTileWidthY[k], + &mode_lib->vba.MetaRowBytesY, + &mode_lib->vba.DPTEBytesPerRowY, + &locals->PTEBufferSizeNotExceededY[i][j][k], + locals->dpte_row_width_luma_ub, + &locals->dpte_row_height[k], + &locals->meta_req_width[k], + &locals->meta_req_height[k], + &locals->meta_row_width[k], + &locals->meta_row_height[k], + &locals->vm_group_bytes[k], + &locals->dpte_group_bytes[k], + locals->PixelPTEReqWidthY, + locals->PixelPTEReqHeightY, + locals->PTERequestSizeY, + locals->dpde0_bytes_per_frame_ub_l, + locals->meta_pte_bytes_per_frame_ub_l); + locals->PrefetchLinesY[k] = CalculatePrefetchSourceLines( + mode_lib, + mode_lib->vba.VRatio[k], + mode_lib->vba.vtaps[k], + mode_lib->vba.Interlace[k], + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + locals->SwathHeightYThisState[k], + mode_lib->vba.ViewportYStartY[k], + &locals->PrefillY[k], + &locals->MaxNumSwY[k]); + 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, + locals->meta_row_height[k], + locals->meta_row_height_chroma[k], + mode_lib->vba.DPTEBytesPerRowY, + mode_lib->vba.DPTEBytesPerRowC, + locals->dpte_row_height[k], + locals->dpte_row_height_chroma[k], + &locals->meta_row_bw[k], + &locals->dpte_row_bw[k]); + } + mode_lib->vba.ExtraLatency = CalculateExtraLatency( + locals->UrgentRoundTripAndOutOfOrderLatencyPerState[i], + locals->TotalNumberOfActiveDPP[i][j], + mode_lib->vba.PixelChunkSizeInKByte, + locals->TotalNumberOfDCCActiveDPP[i][j], + mode_lib->vba.MetaChunkSize, + locals->ReturnBWPerState[i], + mode_lib->vba.GPUVMEnable, + mode_lib->vba.HostVMEnable, + mode_lib->vba.NumberOfActivePlanes, + locals->NoOfDPPThisState, + locals->dpte_group_bytes, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels); + + 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]; + } + } + } + mode_lib->vba.MaxMaxVStartup = 0; + 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.MaxMaxVStartup = dml_max(mode_lib->vba.MaxMaxVStartup, locals->MaximumVStartup[k]); + } + + mode_lib->vba.NextPrefetchMode = mode_lib->vba.MinPrefetchMode; + mode_lib->vba.NextMaxVStartup = mode_lib->vba.MaxMaxVStartup; + do { + mode_lib->vba.PrefetchMode[i][j] = mode_lib->vba.NextPrefetchMode; + mode_lib->vba.MaxVStartup = mode_lib->vba.NextMaxVStartup; + + 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++) { + Pipe myPipe; + HostVM myHostVM; + + if (mode_lib->vba.XFCEnabled[k] == true) { + mode_lib->vba.XFCRemoteSurfaceFlipDelay = + CalculateRemoteSurfaceFlipDelay( + mode_lib, + mode_lib->vba.VRatio[k], + locals->SwathWidthYThisState[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; + } + + myPipe.DPPCLK = locals->RequiredDPPCLK[i][j][k]; + myPipe.DISPCLK = locals->RequiredDISPCLK[i][j]; + myPipe.PixelClock = mode_lib->vba.PixelClock[k]; + myPipe.DCFCLKDeepSleep = mode_lib->vba.ProjectedDCFCLKDeepSleep; + myPipe.DPPPerPlane = locals->NoOfDPP[i][j][k]; + myPipe.ScalerEnabled = mode_lib->vba.ScalerEnabled[k]; + myPipe.SourceScan = mode_lib->vba.SourceScan[k]; + myPipe.BlockWidth256BytesY = locals->Read256BlockWidthY[k]; + myPipe.BlockHeight256BytesY = locals->Read256BlockHeightY[k]; + myPipe.BlockWidth256BytesC = locals->Read256BlockWidthC[k]; + myPipe.BlockHeight256BytesC = locals->Read256BlockHeightC[k]; + myPipe.InterlaceEnable = mode_lib->vba.Interlace[k]; + myPipe.NumberOfCursors = mode_lib->vba.NumberOfCursors[k]; + myPipe.VBlank = mode_lib->vba.VTotal[k] - mode_lib->vba.VActive[k]; + myPipe.HTotal = mode_lib->vba.HTotal[k]; + + + myHostVM.Enable = mode_lib->vba.HostVMEnable; + myHostVM.MaxPageTableLevels = mode_lib->vba.HostVMMaxPageTableLevels; + myHostVM.CachedPageTableLevels = mode_lib->vba.HostVMCachedPageTableLevels; + + + mode_lib->vba.IsErrorResult[i][j][k] = CalculatePrefetchSchedule( + mode_lib, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + &myPipe, + locals->DSCDelayPerState[i][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, + locals->SwathWidthYThisState[k] / mode_lib->vba.HRatio[k], + mode_lib->vba.OutputFormat[k], + mode_lib->vba.MaxInterDCNTileRepeaters, + dml_min(mode_lib->vba.MaxVStartup, locals->MaximumVStartup[k]), + locals->MaximumVStartup[k], + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.GPUVMEnable, + &myHostVM, + mode_lib->vba.DynamicMetadataEnable[k], + mode_lib->vba.DynamicMetadataLinesBeforeActiveRequired[k], + mode_lib->vba.DynamicMetadataTransmittedBytes[k], + mode_lib->vba.DCCEnable[k], + mode_lib->vba.UrgentLatency, + mode_lib->vba.ExtraLatency, + mode_lib->vba.TimeCalc, + locals->PDEAndMetaPTEBytesPerFrame[k], + locals->MetaRowBytes[k], + locals->DPTEBytesPerRow[k], + locals->PrefetchLinesY[k], + locals->SwathWidthYThisState[k], + locals->BytePerPixelInDETY[k], + locals->PrefillY[k], + locals->MaxNumSwY[k], + locals->PrefetchLinesC[k], + locals->BytePerPixelInDETC[k], + locals->PrefillC[k], + locals->MaxNumSwC[k], + locals->SwathHeightYThisState[k], + locals->SwathHeightCThisState[k], + mode_lib->vba.TWait, + mode_lib->vba.XFCEnabled[k], + mode_lib->vba.XFCRemoteSurfaceFlipDelay, + mode_lib->vba.ProgressiveToInterlaceUnitInOPP, + &locals->dst_x_after_scaler, + &locals->dst_y_after_scaler, + &locals->LineTimesForPrefetch[k], + &locals->PrefetchBW[k], + &locals->LinesForMetaPTE[k], + &locals->LinesForMetaAndDPTERow[k], + &locals->VRatioPreY[i][j][k], + &locals->VRatioPreC[i][j][k], + &locals->RequiredPrefetchPixelDataBWLuma[i][j][k], + &locals->RequiredPrefetchPixelDataBWChroma[i][j][k], + &locals->VStartupRequiredWhenNotEnoughTimeForDynamicMetadata, + &locals->Tno_bw[k], + &locals->prefetch_vmrow_bw[k], + locals->swath_width_luma_ub, + locals->swath_width_chroma_ub, + &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; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + uint m; + + locals->cursor_bw[k] = 0; + locals->cursor_bw_pre[k] = 0; + for (m = 0; m < mode_lib->vba.NumberOfCursors[k]; m++) { + locals->cursor_bw[k] = mode_lib->vba.CursorWidth[k][m] * mode_lib->vba.CursorBPP[k][m] + / 8.0 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * mode_lib->vba.VRatio[k]; + locals->cursor_bw_pre[k] = mode_lib->vba.CursorWidth[k][m] * mode_lib->vba.CursorBPP[k][m] + / 8.0 / (mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k]) * locals->VRatioPreY[i][j][k]; + } + + CalculateUrgentBurstFactor( + mode_lib->vba.DETBufferSizeInKByte, + locals->SwathHeightYThisState[k], + locals->SwathHeightCThisState[k], + locals->SwathWidthYThisState[k], + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.UrgentLatency, + mode_lib->vba.CursorBufferSize, + mode_lib->vba.CursorWidth[k][0] + mode_lib->vba.CursorWidth[k][1], + dml_max(mode_lib->vba.CursorBPP[k][0], mode_lib->vba.CursorBPP[k][1]), + mode_lib->vba.VRatio[k], + locals->VRatioPreY[i][j][k], + locals->VRatioPreC[i][j][k], + locals->BytePerPixelInDETY[k], + locals->BytePerPixelInDETC[k], + &locals->UrgentBurstFactorCursor[k], + &locals->UrgentBurstFactorCursorPre[k], + &locals->UrgentBurstFactorLuma[k], + &locals->UrgentBurstFactorLumaPre[k], + &locals->UrgentBurstFactorChroma[k], + &locals->UrgentBurstFactorChromaPre[k], + &locals->NotEnoughUrgentLatencyHiding, + &locals->NotEnoughUrgentLatencyHidingPre); + + if (mode_lib->vba.UseUrgentBurstBandwidth == false) { + locals->UrgentBurstFactorCursor[k] = 1; + locals->UrgentBurstFactorCursorPre[k] = 1; + locals->UrgentBurstFactorLuma[k] = 1; + locals->UrgentBurstFactorLumaPre[k] = 1; + locals->UrgentBurstFactorChroma[k] = 1; + locals->UrgentBurstFactorChromaPre[k] = 1; + } + + mode_lib->vba.MaximumReadBandwidthWithoutPrefetch = mode_lib->vba.MaximumReadBandwidthWithoutPrefetch + + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k] + locals->ReadBandwidthLuma[k] + * locals->UrgentBurstFactorLuma[k] + locals->ReadBandwidthChroma[k] + * locals->UrgentBurstFactorChroma[k] + locals->meta_row_bw[k] + locals->dpte_row_bw[k]; + mode_lib->vba.MaximumReadBandwidthWithPrefetch = mode_lib->vba.MaximumReadBandwidthWithPrefetch + + dml_max3(locals->prefetch_vmrow_bw[k], + locals->ReadBandwidthLuma[k] * locals->UrgentBurstFactorLuma[k] + locals->ReadBandwidthChroma[k] + * locals->UrgentBurstFactorChroma[k] + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k] + + locals->meta_row_bw[k] + locals->dpte_row_bw[k], + locals->RequiredPrefetchPixelDataBWLuma[i][j][k] * locals->UrgentBurstFactorLumaPre[k] + + locals->RequiredPrefetchPixelDataBWChroma[i][j][k] * locals->UrgentBurstFactorChromaPre[k] + + locals->cursor_bw_pre[k] * locals->UrgentBurstFactorCursorPre[k]); + } + locals->BandwidthWithoutPrefetchSupported[i] = true; + if (mode_lib->vba.MaximumReadBandwidthWithoutPrefetch > locals->ReturnBWPerState[i] + || locals->NotEnoughUrgentLatencyHiding == 1) { + locals->BandwidthWithoutPrefetchSupported[i] = false; + } + + locals->PrefetchSupported[i][j] = true; + if (mode_lib->vba.MaximumReadBandwidthWithPrefetch > locals->ReturnBWPerState[i] + || locals->NotEnoughUrgentLatencyHiding == 1 + || locals->NotEnoughUrgentLatencyHidingPre == 1) { + locals->PrefetchSupported[i][j] = false; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->LineTimesForPrefetch[k] < 2.0 + || locals->LinesForMetaPTE[k] >= 32.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; + } + } + mode_lib->vba.AnyLinesForVMOrRowTooLarge = false; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + if (locals->LinesForMetaAndDPTERow[k] >= 16 || locals->LinesForMetaPTE[k] >= 32) { + mode_lib->vba.AnyLinesForVMOrRowTooLarge = true; + } + } + + if (mode_lib->vba.MaxVStartup <= 13 || mode_lib->vba.AnyLinesForVMOrRowTooLarge == false) { + mode_lib->vba.NextMaxVStartup = mode_lib->vba.MaxMaxVStartup; + mode_lib->vba.NextPrefetchMode = mode_lib->vba.NextPrefetchMode + 1; + } else { + mode_lib->vba.NextMaxVStartup = mode_lib->vba.NextMaxVStartup - 1; + } + } while ((locals->PrefetchSupported[i][j] != true || locals->VRatioInPrefetchSupported[i][j] != true) + && (mode_lib->vba.NextMaxVStartup != mode_lib->vba.MaxMaxVStartup + || mode_lib->vba.NextPrefetchMode < mode_lib->vba.MaxPrefetchMode)); + + if (locals->PrefetchSupported[i][j] == true && locals->VRatioInPrefetchSupported[i][j] == true) { + mode_lib->vba.BandwidthAvailableForImmediateFlip = locals->ReturnBWPerState[i]; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.BandwidthAvailableForImmediateFlip = mode_lib->vba.BandwidthAvailableForImmediateFlip + - dml_max(locals->ReadBandwidthLuma[k] * locals->UrgentBurstFactorLuma[k] + + locals->ReadBandwidthChroma[k] * locals->UrgentBurstFactorChroma[k] + + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k], + locals->RequiredPrefetchPixelDataBWLuma[i][j][k] * locals->UrgentBurstFactorLumaPre[k] + + locals->RequiredPrefetchPixelDataBWChroma[i][j][k] * locals->UrgentBurstFactorChromaPre[k] + + locals->cursor_bw_pre[k] * locals->UrgentBurstFactorCursorPre[k]); + } + mode_lib->vba.TotImmediateFlipBytes = 0.0; + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + mode_lib->vba.TotImmediateFlipBytes = mode_lib->vba.TotImmediateFlipBytes + + locals->PDEAndMetaPTEBytesPerFrame[k] + locals->MetaRowBytes[k] + locals->DPTEBytesPerRow[k]; + } + + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + CalculateFlipSchedule( + mode_lib, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + mode_lib->vba.PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + mode_lib->vba.ExtraLatency, + mode_lib->vba.UrgentLatency, + mode_lib->vba.GPUVMMaxPageTableLevels, + mode_lib->vba.HostVMEnable, + mode_lib->vba.HostVMMaxPageTableLevels, + mode_lib->vba.HostVMCachedPageTableLevels, + mode_lib->vba.GPUVMEnable, + locals->PDEAndMetaPTEBytesPerFrame[k], + locals->MetaRowBytes[k], + locals->DPTEBytesPerRow[k], + mode_lib->vba.BandwidthAvailableForImmediateFlip, + mode_lib->vba.TotImmediateFlipBytes, + mode_lib->vba.SourcePixelFormat[k], + mode_lib->vba.HTotal[k] / mode_lib->vba.PixelClock[k], + mode_lib->vba.VRatio[k], + locals->Tno_bw[k], + mode_lib->vba.DCCEnable[k], + locals->dpte_row_height[k], + locals->meta_row_height[k], + locals->dpte_row_height_chroma[k], + locals->meta_row_height_chroma[k], + &locals->DestinationLinesToRequestVMInImmediateFlip[k], + &locals->DestinationLinesToRequestRowInImmediateFlip[k], + &locals->final_flip_bw[k], + &locals->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 + dml_max3( + locals->prefetch_vmrow_bw[k], + locals->final_flip_bw[k] + locals->ReadBandwidthLuma[k] * locals->UrgentBurstFactorLuma[k] + + locals->ReadBandwidthChroma[k] * locals->UrgentBurstFactorChroma[k] + + locals->cursor_bw[k] * locals->UrgentBurstFactorCursor[k], + locals->final_flip_bw[k] + locals->RequiredPrefetchPixelDataBWLuma[i][j][k] + * locals->UrgentBurstFactorLumaPre[k] + locals->RequiredPrefetchPixelDataBWChroma[i][j][k] + * locals->UrgentBurstFactorChromaPre[k] + locals->cursor_bw_pre[k] + * locals->UrgentBurstFactorCursorPre[k]); + } + locals->ImmediateFlipSupportedForState[i][j] = true; + if (mode_lib->vba.total_dcn_read_bw_with_flip + > locals->ReturnBWPerState[i]) { + locals->ImmediateFlipSupportedForState[i][j] = false; + } + for (k = 0; k <= mode_lib->vba.NumberOfActivePlanes - 1; k++) { + if (locals->ImmediateFlipSupportedForPipe[k] == false) { + locals->ImmediateFlipSupportedForState[i][j] = false; + } + } + } else { + locals->ImmediateFlipSupportedForState[i][j] = false; + } + mode_lib->vba.UrgentOutOfOrderReturnPerChannel = dml_max3( + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelDataOnly, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelPixelMixedWithVMData, + mode_lib->vba.UrgentOutOfOrderReturnPerChannelVMDataOnly); + CalculateWatermarksAndDRAMSpeedChangeSupport( + mode_lib, + mode_lib->vba.PrefetchMode[i][j], + mode_lib->vba.NumberOfActivePlanes, + mode_lib->vba.MaxLineBufferLines, + mode_lib->vba.LineBufferSize, + mode_lib->vba.DPPOutputBufferPixels, + mode_lib->vba.DETBufferSizeInKByte, + mode_lib->vba.WritebackInterfaceLumaBufferSize, + mode_lib->vba.WritebackInterfaceChromaBufferSize, + mode_lib->vba.DCFCLKPerState[i], + mode_lib->vba.UrgentOutOfOrderReturnPerChannel * mode_lib->vba.NumberOfChannels, + locals->ReturnBWPerState[i], + mode_lib->vba.GPUVMEnable, + locals->dpte_group_bytes, + mode_lib->vba.MetaChunkSize, + mode_lib->vba.UrgentLatency, + mode_lib->vba.ExtraLatency, + mode_lib->vba.WritebackLatency, + mode_lib->vba.WritebackChunkSize, + mode_lib->vba.SOCCLKPerState[i], + mode_lib->vba.DRAMClockChangeLatency, + mode_lib->vba.SRExitTime, + mode_lib->vba.SREnterPlusExitTime, + mode_lib->vba.ProjectedDCFCLKDeepSleep, + locals->NoOfDPPThisState, + mode_lib->vba.DCCEnable, + locals->RequiredDPPCLKThisState, + locals->SwathWidthYSingleDPP, + locals->SwathHeightYThisState, + locals->ReadBandwidthLuma, + locals->SwathHeightCThisState, + locals->ReadBandwidthChroma, + mode_lib->vba.LBBitPerPixel, + locals->SwathWidthYThisState, + mode_lib->vba.HRatio, + mode_lib->vba.vtaps, + mode_lib->vba.VTAPsChroma, + mode_lib->vba.VRatio, + mode_lib->vba.HTotal, + mode_lib->vba.PixelClock, + mode_lib->vba.BlendingAndTiming, + locals->BytePerPixelInDETY, + locals->BytePerPixelInDETC, + mode_lib->vba.WritebackEnable, + mode_lib->vba.WritebackPixelFormat, + mode_lib->vba.WritebackDestinationWidth, + mode_lib->vba.WritebackDestinationHeight, + mode_lib->vba.WritebackSourceHeight, + &locals->DRAMClockChangeSupport[i][j], + &mode_lib->vba.UrgentWatermark, + &mode_lib->vba.WritebackUrgentWatermark, + &mode_lib->vba.DRAMClockChangeWatermark, + &mode_lib->vba.WritebackDRAMClockChangeWatermark, + &mode_lib->vba.StutterExitWatermark, + &mode_lib->vba.StutterEnterPlusExitWatermark, + &mode_lib->vba.MinActiveDRAMClockChangeLatencySupported); + } + } + + /*Vertical Active BW support*/ + { + double MaxTotalVActiveRDBandwidth = 0.0; + for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; ++k) { + MaxTotalVActiveRDBandwidth = MaxTotalVActiveRDBandwidth + locals->ReadBandwidth[k]; + } + for (i = 0; i <= mode_lib->vba.soc.num_states; ++i) { + locals->MaxTotalVerticalActiveAvailableBandwidth[i] = dml_min( + locals->IdealSDPPortBandwidthPerState[i] * + mode_lib->vba.MaxAveragePercentOfIdealSDPPortBWDisplayCanUseInNormalSystemOperation + / 100.0, mode_lib->vba.DRAMSpeedPerState[i] * + mode_lib->vba.NumberOfChannels * + mode_lib->vba.DRAMChannelWidth * + mode_lib->vba.MaxAveragePercentOfIdealDRAMBWDisplayCanUseInNormalSystemOperation + / 100.0); + + if (MaxTotalVActiveRDBandwidth <= locals->MaxTotalVerticalActiveAvailableBandwidth[i]) { + locals->TotalVerticalActiveBandwidthSupport[i] = true; + } else { + locals->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++) { + if (mode_lib->vba.CursorWidth[k][0] > 0.0) { + for (m = 0; m < mode_lib->vba.NumberOfCursors[k]; m++) { + if (mode_lib->vba.CursorBPP[k][m] == 64 && 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->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->TotalVerticalActiveBandwidthSupport[i] != true) { + status = DML_FAIL_TOTAL_V_ACTIVE_BW; + } 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; + } else if ((mode_lib->vba.HostVMEnable != false + && locals->ImmediateFlipSupportedForState[i][j] != true)) { + status = DML_FAIL_HOST_VM_IMMEDIATE_FLIP; + } else if (locals->PrefetchSupported[i][j] != true) { + status = DML_FAIL_PREFETCH_SUPPORT; + } else if (locals->VRatioInPrefetchSupported[i][j] != true) { + status = DML_FAIL_V_RATIO_PREFETCH; + } + + 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 + || (mode_lib->vba.WhenToDoMPCCombine == dm_mpc_reduce_voltage_and_clocks + && ((locals->DRAMClockChangeSupport[i][1] == dm_dram_clock_change_vactive + && locals->DRAMClockChangeSupport[i][0] != dm_dram_clock_change_vactive) + || (locals->DRAMClockChangeSupport[i][1] == dm_dram_clock_change_vblank + && locals->DRAMClockChangeSupport[i][0] == dm_dram_clock_change_unsupported))))) { + 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]; + 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]; + } +} + +static void CalculateWatermarksAndDRAMSpeedChangeSupport( + struct display_mode_lib *mode_lib, + unsigned int PrefetchMode, + unsigned int NumberOfActivePlanes, + unsigned int MaxLineBufferLines, + unsigned int LineBufferSize, + unsigned int DPPOutputBufferPixels, + double DETBufferSizeInKByte, + unsigned int WritebackInterfaceLumaBufferSize, + unsigned int WritebackInterfaceChromaBufferSize, + double DCFCLK, + double UrgentOutOfOrderReturn, + double ReturnBW, + bool GPUVMEnable, + long dpte_group_bytes[], + unsigned int MetaChunkSize, + double UrgentLatency, + double ExtraLatency, + double WritebackLatency, + double WritebackChunkSize, + double SOCCLK, + double DRAMClockChangeLatency, + double SRExitTime, + double SREnterPlusExitTime, + double DCFCLKDeepSleep, + int DPPPerPlane[], + bool DCCEnable[], + double DPPCLK[], + unsigned int SwathWidthSingleDPPY[], + unsigned int SwathHeightY[], + double ReadBandwidthPlaneLuma[], + unsigned int SwathHeightC[], + double ReadBandwidthPlaneChroma[], + unsigned int LBBitPerPixel[], + unsigned int SwathWidthY[], + double HRatio[], + unsigned int vtaps[], + unsigned int VTAPsChroma[], + double VRatio[], + unsigned int HTotal[], + double PixelClock[], + unsigned int BlendingAndTiming[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + bool WritebackEnable[], + enum source_format_class WritebackPixelFormat[], + double WritebackDestinationWidth[], + double WritebackDestinationHeight[], + double WritebackSourceHeight[], + enum clock_change_support *DRAMClockChangeSupport, + double *UrgentWatermark, + double *WritebackUrgentWatermark, + double *DRAMClockChangeWatermark, + double *WritebackDRAMClockChangeWatermark, + double *StutterExitWatermark, + double *StutterEnterPlusExitWatermark, + double *MinActiveDRAMClockChangeLatencySupported) +{ + double EffectiveLBLatencyHidingY; + double EffectiveLBLatencyHidingC; + double DPPOutputBufferLinesY; + double DPPOutputBufferLinesC; + double DETBufferSizeY; + double DETBufferSizeC; + double LinesInDETY[DC__NUM_DPP__MAX]; + double LinesInDETC; + unsigned int LinesInDETYRoundedDownToSwath[DC__NUM_DPP__MAX]; + unsigned int LinesInDETCRoundedDownToSwath; + double FullDETBufferingTimeY[DC__NUM_DPP__MAX]; + double FullDETBufferingTimeC; + double ActiveDRAMClockChangeLatencyMarginY; + double ActiveDRAMClockChangeLatencyMarginC; + double WritebackDRAMClockChangeLatencyMargin; + double PlaneWithMinActiveDRAMClockChangeMargin; + double SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank; + double FullDETBufferingTimeYStutterCriticalPlane = 0; + double TimeToFinishSwathTransferStutterCriticalPlane = 0; + uint k, j; + + mode_lib->vba.TotalActiveDPP = 0; + mode_lib->vba.TotalDCCActiveDPP = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP + DPPPerPlane[k]; + if (DCCEnable[k] == true) { + mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP + DPPPerPlane[k]; + } + } + + mode_lib->vba.TotalDataReadBandwidth = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + mode_lib->vba.TotalDataReadBandwidth = mode_lib->vba.TotalDataReadBandwidth + + ReadBandwidthPlaneLuma[k] + ReadBandwidthPlaneChroma[k]; + } + + *UrgentWatermark = UrgentLatency + ExtraLatency; + + *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark; + + mode_lib->vba.TotalActiveWriteback = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (WritebackEnable[k] == true) { + mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1; + } + } + + if (mode_lib->vba.TotalActiveWriteback <= 1) { + *WritebackUrgentWatermark = WritebackLatency; + } else { + *WritebackUrgentWatermark = WritebackLatency + + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + } + + if (mode_lib->vba.TotalActiveWriteback <= 1) { + *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency; + } else { + *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK; + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + + mode_lib->vba.LBLatencyHidingSourceLinesY = dml_min((double) MaxLineBufferLines, + dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) + - (vtaps[k] - 1); + + mode_lib->vba.LBLatencyHidingSourceLinesC = dml_min((double) MaxLineBufferLines, + dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / 2 / dml_max(HRatio[k] / 2, 1.0)), 1)) + - (VTAPsChroma[k] - 1); + + EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY / VRatio[k] + * (HTotal[k] / PixelClock[k]); + + EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC + / (VRatio[k] / 2) * (HTotal[k] / PixelClock[k]); + + if (SwathWidthY[k] > 2 * DPPOutputBufferPixels) { + DPPOutputBufferLinesY = (double) DPPOutputBufferPixels / SwathWidthY[k]; + } else if (SwathWidthY[k] > DPPOutputBufferPixels) { + DPPOutputBufferLinesY = 0.5; + } else { + DPPOutputBufferLinesY = 1; + } + + if (SwathWidthY[k] / 2.0 > 2 * DPPOutputBufferPixels) { + DPPOutputBufferLinesC = (double) DPPOutputBufferPixels + / (SwathWidthY[k] / 2.0); + } else if (SwathWidthY[k] / 2.0 > DPPOutputBufferPixels) { + DPPOutputBufferLinesC = 0.5; + } else { + DPPOutputBufferLinesC = 1; + } + + CalculateDETBufferSize( + DETBufferSizeInKByte, + SwathHeightY[k], + SwathHeightC[k], + &DETBufferSizeY, + &DETBufferSizeC); + + LinesInDETY[k] = DETBufferSizeY / BytePerPixelDETY[k] / SwathWidthY[k]; + LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]); + FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] + * (HTotal[k] / PixelClock[k]) / VRatio[k]; + if (BytePerPixelDETC[k] > 0) { + LinesInDETC = DETBufferSizeC / BytePerPixelDETC[k] / (SwathWidthY[k] / 2.0); + LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]); + FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath + * (HTotal[k] / PixelClock[k]) / (VRatio[k] / 2); + } else { + LinesInDETC = 0; + FullDETBufferingTimeC = 999999; + } + + ActiveDRAMClockChangeLatencyMarginY = HTotal[k] / PixelClock[k] + * DPPOutputBufferLinesY + EffectiveLBLatencyHidingY + + FullDETBufferingTimeY[k] - *DRAMClockChangeWatermark; + + if (NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY + - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k]; + } + + if (BytePerPixelDETC[k] > 0) { + ActiveDRAMClockChangeLatencyMarginC = HTotal[k] / PixelClock[k] + * DPPOutputBufferLinesC + EffectiveLBLatencyHidingC + + FullDETBufferingTimeC - *DRAMClockChangeWatermark; + if (NumberOfActivePlanes > 1) { + ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC + - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / (VRatio[k] / 2); + } + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( + ActiveDRAMClockChangeLatencyMarginY, + ActiveDRAMClockChangeLatencyMarginC); + } else { + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY; + } + + if (WritebackEnable[k] == true) { + if (WritebackPixelFormat[k] == dm_444_32) { + WritebackDRAMClockChangeLatencyMargin = (WritebackInterfaceLumaBufferSize + + WritebackInterfaceChromaBufferSize) / (WritebackDestinationWidth[k] + * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] + / PixelClock[k]) * 4) - *WritebackDRAMClockChangeWatermark; + } else { + WritebackDRAMClockChangeLatencyMargin = dml_min( + WritebackInterfaceLumaBufferSize * 8.0 / 10, + 2 * WritebackInterfaceChromaBufferSize * 8.0 / 10) / (WritebackDestinationWidth[k] + * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k])) + - *WritebackDRAMClockChangeWatermark; + } + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min( + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], + WritebackDRAMClockChangeLatencyMargin); + } + } + + mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999; + PlaneWithMinActiveDRAMClockChangeMargin = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] + < mode_lib->vba.MinActiveDRAMClockChangeMargin) { + mode_lib->vba.MinActiveDRAMClockChangeMargin = + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; + if (BlendingAndTiming[k] == k) { + PlaneWithMinActiveDRAMClockChangeMargin = k; + } else { + for (j = 0; j < NumberOfActivePlanes; ++j) { + if (BlendingAndTiming[k] == j) { + PlaneWithMinActiveDRAMClockChangeMargin = j; + } + } + } + } + } + + *MinActiveDRAMClockChangeLatencySupported = mode_lib->vba.MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency; + + SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) + && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) + && mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] + < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) { + SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = + mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k]; + } + } + + mode_lib->vba.TotalNumberOfActiveOTG = 0; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (BlendingAndTiming[k] == k) { + mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG + 1; + } + } + + if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) { + *DRAMClockChangeSupport = dm_dram_clock_change_vactive; + } else if (((mode_lib->vba.SynchronizedVBlank == true + || mode_lib->vba.TotalNumberOfActiveOTG == 1 + || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) + && PrefetchMode == 0)) { + *DRAMClockChangeSupport = dm_dram_clock_change_vblank; + } else { + *DRAMClockChangeSupport = dm_dram_clock_change_unsupported; + } + + FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[0]; + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (FullDETBufferingTimeY[k] <= FullDETBufferingTimeYStutterCriticalPlane) { + TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] + - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) + * (HTotal[k] / PixelClock[k]) / VRatio[k]; + } + } + + *StutterExitWatermark = SRExitTime + mode_lib->vba.LastPixelOfLineExtraWatermark + + ExtraLatency + 10 / DCFCLKDeepSleep; + *StutterEnterPlusExitWatermark = dml_max( + SREnterPlusExitTime + mode_lib->vba.LastPixelOfLineExtraWatermark + + ExtraLatency + 10 / DCFCLKDeepSleep, + TimeToFinishSwathTransferStutterCriticalPlane); + +} + +static void CalculateDCFCLKDeepSleep( + struct display_mode_lib *mode_lib, + unsigned int NumberOfActivePlanes, + double BytePerPixelDETY[], + double BytePerPixelDETC[], + double VRatio[], + unsigned int SwathWidthY[], + int DPPPerPlane[], + double HRatio[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double *DCFCLKDeepSleep) +{ + uint k; + double DisplayPipeLineDeliveryTimeLuma; + double DisplayPipeLineDeliveryTimeChroma; + //double DCFCLKDeepSleepPerPlane[DC__NUM_DPP__MAX]; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (VRatio[k] <= 1) { + DisplayPipeLineDeliveryTimeLuma = SwathWidthY[k] * DPPPerPlane[k] + / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLuma = SwathWidthY[k] / PSCL_THROUGHPUT[k] + / DPPCLK[k]; + } + if (BytePerPixelDETC[k] == 0) { + DisplayPipeLineDeliveryTimeChroma = 0; + } else { + if (VRatio[k] / 2 <= 1) { + DisplayPipeLineDeliveryTimeChroma = SwathWidthY[k] / 2.0 + * DPPPerPlane[k] / (HRatio[k] / 2) / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChroma = SwathWidthY[k] / 2.0 + / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + + if (BytePerPixelDETC[k] > 0) { + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = dml_max( + 1.1 * SwathWidthY[k] * dml_ceil(BytePerPixelDETY[k], 1) + / 32.0 / DisplayPipeLineDeliveryTimeLuma, + 1.1 * SwathWidthY[k] / 2.0 + * dml_ceil(BytePerPixelDETC[k], 2) / 32.0 + / DisplayPipeLineDeliveryTimeChroma); + } else { + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = 1.1 * SwathWidthY[k] + * dml_ceil(BytePerPixelDETY[k], 1) / 64.0 + / DisplayPipeLineDeliveryTimeLuma; + } + mode_lib->vba.DCFCLKDeepSleepPerPlane[k] = dml_max( + mode_lib->vba.DCFCLKDeepSleepPerPlane[k], + PixelClock[k] / 16); + + } + + *DCFCLKDeepSleep = 8; + for (k = 0; k < NumberOfActivePlanes; ++k) { + *DCFCLKDeepSleep = dml_max( + *DCFCLKDeepSleep, + mode_lib->vba.DCFCLKDeepSleepPerPlane[k]); + } +} + +static void CalculateDETBufferSize( + double DETBufferSizeInKByte, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + double *DETBufferSizeY, + double *DETBufferSizeC) +{ + if (SwathHeightC == 0) { + *DETBufferSizeY = DETBufferSizeInKByte * 1024; + *DETBufferSizeC = 0; + } else if (SwathHeightY <= SwathHeightC) { + *DETBufferSizeY = DETBufferSizeInKByte * 1024 / 2; + *DETBufferSizeC = DETBufferSizeInKByte * 1024 / 2; + } else { + *DETBufferSizeY = DETBufferSizeInKByte * 1024 * 2 / 3; + *DETBufferSizeC = DETBufferSizeInKByte * 1024 / 3; + } +} + +static void CalculateUrgentBurstFactor( + unsigned int DETBufferSizeInKByte, + unsigned int SwathHeightY, + unsigned int SwathHeightC, + unsigned int SwathWidthY, + double LineTime, + double UrgentLatency, + double CursorBufferSize, + unsigned int CursorWidth, + unsigned int CursorBPP, + double VRatio, + double VRatioPreY, + double VRatioPreC, + double BytePerPixelInDETY, + double BytePerPixelInDETC, + double *UrgentBurstFactorCursor, + double *UrgentBurstFactorCursorPre, + double *UrgentBurstFactorLuma, + double *UrgentBurstFactorLumaPre, + double *UrgentBurstFactorChroma, + double *UrgentBurstFactorChromaPre, + unsigned int *NotEnoughUrgentLatencyHiding, + unsigned int *NotEnoughUrgentLatencyHidingPre) +{ + double LinesInDETLuma; + double LinesInDETChroma; + unsigned int LinesInCursorBuffer; + double CursorBufferSizeInTime; + double CursorBufferSizeInTimePre; + double DETBufferSizeInTimeLuma; + double DETBufferSizeInTimeLumaPre; + double DETBufferSizeInTimeChroma; + double DETBufferSizeInTimeChromaPre; + double DETBufferSizeY; + double DETBufferSizeC; + + *NotEnoughUrgentLatencyHiding = 0; + *NotEnoughUrgentLatencyHidingPre = 0; + + if (CursorWidth > 0) { + LinesInCursorBuffer = 1 << (unsigned int) dml_floor( + dml_log2(CursorBufferSize * 1024.0 / (CursorWidth * CursorBPP / 8.0)), 1.0); + CursorBufferSizeInTime = LinesInCursorBuffer * LineTime / VRatio; + if (CursorBufferSizeInTime - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorCursor = 0; + } else { + *UrgentBurstFactorCursor = CursorBufferSizeInTime + / (CursorBufferSizeInTime - UrgentLatency); + } + if (VRatioPreY > 0) { + CursorBufferSizeInTimePre = LinesInCursorBuffer * LineTime / VRatioPreY; + if (CursorBufferSizeInTimePre - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHidingPre = 1; + *UrgentBurstFactorCursorPre = 0; + } else { + *UrgentBurstFactorCursorPre = CursorBufferSizeInTimePre + / (CursorBufferSizeInTimePre - UrgentLatency); + } + } else { + *UrgentBurstFactorCursorPre = 1; + } + } + + CalculateDETBufferSize( + DETBufferSizeInKByte, + SwathHeightY, + SwathHeightC, + &DETBufferSizeY, + &DETBufferSizeC); + + LinesInDETLuma = DETBufferSizeY / BytePerPixelInDETY / SwathWidthY; + DETBufferSizeInTimeLuma = dml_floor(LinesInDETLuma, SwathHeightY) * LineTime / VRatio; + if (DETBufferSizeInTimeLuma - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorLuma = 0; + } else { + *UrgentBurstFactorLuma = DETBufferSizeInTimeLuma + / (DETBufferSizeInTimeLuma - UrgentLatency); + } + if (VRatioPreY > 0) { + DETBufferSizeInTimeLumaPre = dml_floor(LinesInDETLuma, SwathHeightY) * LineTime + / VRatioPreY; + if (DETBufferSizeInTimeLumaPre - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHidingPre = 1; + *UrgentBurstFactorLumaPre = 0; + } else { + *UrgentBurstFactorLumaPre = DETBufferSizeInTimeLumaPre + / (DETBufferSizeInTimeLumaPre - UrgentLatency); + } + } else { + *UrgentBurstFactorLumaPre = 1; + } + + if (BytePerPixelInDETC > 0) { + LinesInDETChroma = DETBufferSizeC / BytePerPixelInDETC / (SwathWidthY / 2); + DETBufferSizeInTimeChroma = dml_floor(LinesInDETChroma, SwathHeightC) * LineTime + / (VRatio / 2); + if (DETBufferSizeInTimeChroma - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHiding = 1; + *UrgentBurstFactorChroma = 0; + } else { + *UrgentBurstFactorChroma = DETBufferSizeInTimeChroma + / (DETBufferSizeInTimeChroma - UrgentLatency); + } + if (VRatioPreC > 0) { + DETBufferSizeInTimeChromaPre = dml_floor(LinesInDETChroma, SwathHeightC) + * LineTime / VRatioPreC; + if (DETBufferSizeInTimeChromaPre - UrgentLatency <= 0) { + *NotEnoughUrgentLatencyHidingPre = 1; + *UrgentBurstFactorChromaPre = 0; + } else { + *UrgentBurstFactorChromaPre = DETBufferSizeInTimeChromaPre + / (DETBufferSizeInTimeChromaPre - UrgentLatency); + } + } else { + *UrgentBurstFactorChromaPre = 1; + } + } +} + +static void CalculatePixelDeliveryTimes( + unsigned int NumberOfActivePlanes, + double VRatio[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + unsigned int swath_width_luma_ub[], + unsigned int swath_width_chroma_ub[], + int DPPPerPlane[], + double HRatio[], + double PixelClock[], + double PSCL_THROUGHPUT[], + double PSCL_THROUGHPUT_CHROMA[], + double DPPCLK[], + double BytePerPixelDETC[], + enum scan_direction_class SourceScan[], + unsigned int BlockWidth256BytesY[], + unsigned int BlockHeight256BytesY[], + unsigned int BlockWidth256BytesC[], + unsigned int BlockHeight256BytesC[], + double DisplayPipeLineDeliveryTimeLuma[], + double DisplayPipeLineDeliveryTimeChroma[], + double DisplayPipeLineDeliveryTimeLumaPrefetch[], + double DisplayPipeLineDeliveryTimeChromaPrefetch[], + double DisplayPipeRequestDeliveryTimeLuma[], + double DisplayPipeRequestDeliveryTimeChroma[], + double DisplayPipeRequestDeliveryTimeLumaPrefetch[], + double DisplayPipeRequestDeliveryTimeChromaPrefetch[]) +{ + double req_per_swath_ub; + uint k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (VRatio[k] <= 1) { + DisplayPipeLineDeliveryTimeLuma[k] = swath_width_luma_ub[k] * DPPPerPlane[k] + / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLuma[k] = swath_width_luma_ub[k] + / PSCL_THROUGHPUT[k] / DPPCLK[k]; + } + + if (BytePerPixelDETC[k] == 0) { + DisplayPipeLineDeliveryTimeChroma[k] = 0; + } else { + if (VRatio[k] / 2 <= 1) { + DisplayPipeLineDeliveryTimeChroma[k] = swath_width_chroma_ub[k] + * DPPPerPlane[k] / (HRatio[k] / 2) / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChroma[k] = swath_width_chroma_ub[k] + / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + + if (VRatioPrefetchY[k] <= 1) { + DisplayPipeLineDeliveryTimeLumaPrefetch[k] = swath_width_luma_ub[k] + * DPPPerPlane[k] / HRatio[k] / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeLumaPrefetch[k] = swath_width_luma_ub[k] + / PSCL_THROUGHPUT[k] / DPPCLK[k]; + } + + if (BytePerPixelDETC[k] == 0) { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = 0; + } else { + if (VRatioPrefetchC[k] <= 1) { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = + swath_width_chroma_ub[k] * DPPPerPlane[k] + / (HRatio[k] / 2) / PixelClock[k]; + } else { + DisplayPipeLineDeliveryTimeChromaPrefetch[k] = + swath_width_chroma_ub[k] / PSCL_THROUGHPUT_CHROMA[k] / DPPCLK[k]; + } + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (SourceScan[k] == dm_horz) { + req_per_swath_ub = swath_width_luma_ub[k] / BlockWidth256BytesY[k]; + } else { + req_per_swath_ub = swath_width_luma_ub[k] / BlockHeight256BytesY[k]; + } + DisplayPipeRequestDeliveryTimeLuma[k] = DisplayPipeLineDeliveryTimeLuma[k] + / req_per_swath_ub; + DisplayPipeRequestDeliveryTimeLumaPrefetch[k] = + DisplayPipeLineDeliveryTimeLumaPrefetch[k] / req_per_swath_ub; + if (BytePerPixelDETC[k] == 0) { + DisplayPipeRequestDeliveryTimeChroma[k] = 0; + DisplayPipeRequestDeliveryTimeChromaPrefetch[k] = 0; + } else { + if (SourceScan[k] == dm_horz) { + req_per_swath_ub = swath_width_chroma_ub[k] + / BlockWidth256BytesC[k]; + } else { + req_per_swath_ub = swath_width_chroma_ub[k] + / BlockHeight256BytesC[k]; + } + DisplayPipeRequestDeliveryTimeChroma[k] = + DisplayPipeLineDeliveryTimeChroma[k] / req_per_swath_ub; + DisplayPipeRequestDeliveryTimeChromaPrefetch[k] = + DisplayPipeLineDeliveryTimeChromaPrefetch[k] / req_per_swath_ub; + } + } +} + +static void CalculateMetaAndPTETimes( + unsigned int NumberOfActivePlanes, + bool GPUVMEnable, + unsigned int MetaChunkSize, + unsigned int MinMetaChunkSizeBytes, + unsigned int GPUVMMaxPageTableLevels, + unsigned int HTotal[], + double VRatio[], + double VRatioPrefetchY[], + double VRatioPrefetchC[], + double DestinationLinesToRequestRowInVBlank[], + double DestinationLinesToRequestRowInImmediateFlip[], + double DestinationLinesToRequestVMInVBlank[], + double DestinationLinesToRequestVMInImmediateFlip[], + bool DCCEnable[], + double PixelClock[], + double BytePerPixelDETY[], + double BytePerPixelDETC[], + enum scan_direction_class SourceScan[], + unsigned int dpte_row_height[], + unsigned int dpte_row_height_chroma[], + unsigned int meta_row_width[], + unsigned int meta_row_height[], + unsigned int meta_req_width[], + unsigned int meta_req_height[], + long dpte_group_bytes[], + unsigned int PTERequestSizeY[], + unsigned int PTERequestSizeC[], + unsigned int PixelPTEReqWidthY[], + unsigned int PixelPTEReqHeightY[], + unsigned int PixelPTEReqWidthC[], + unsigned int PixelPTEReqHeightC[], + unsigned int dpte_row_width_luma_ub[], + unsigned int dpte_row_width_chroma_ub[], + unsigned int vm_group_bytes[], + unsigned int dpde0_bytes_per_frame_ub_l[], + unsigned int dpde0_bytes_per_frame_ub_c[], + unsigned int meta_pte_bytes_per_frame_ub_l[], + unsigned int meta_pte_bytes_per_frame_ub_c[], + double DST_Y_PER_PTE_ROW_NOM_L[], + double DST_Y_PER_PTE_ROW_NOM_C[], + double DST_Y_PER_META_ROW_NOM_L[], + double TimePerMetaChunkNominal[], + double TimePerMetaChunkVBlank[], + double TimePerMetaChunkFlip[], + double time_per_pte_group_nom_luma[], + double time_per_pte_group_vblank_luma[], + double time_per_pte_group_flip_luma[], + double time_per_pte_group_nom_chroma[], + double time_per_pte_group_vblank_chroma[], + double time_per_pte_group_flip_chroma[], + double TimePerVMGroupVBlank[], + double TimePerVMGroupFlip[], + double TimePerVMRequestVBlank[], + double TimePerVMRequestFlip[]) +{ + unsigned int meta_chunk_width; + unsigned int min_meta_chunk_width; + unsigned int meta_chunk_per_row_int; + unsigned int meta_row_remainder; + unsigned int meta_chunk_threshold; + unsigned int meta_chunks_per_row_ub; + unsigned int dpte_group_width_luma; + unsigned int dpte_group_width_chroma; + unsigned int dpte_groups_per_row_luma_ub; + unsigned int dpte_groups_per_row_chroma_ub; + unsigned int num_group_per_lower_vm_stage; + unsigned int num_req_per_lower_vm_stage; + uint k; + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (GPUVMEnable == true) { + DST_Y_PER_PTE_ROW_NOM_L[k] = dpte_row_height[k] / VRatio[k]; + if (BytePerPixelDETC[k] == 0) { + DST_Y_PER_PTE_ROW_NOM_C[k] = 0; + } else { + DST_Y_PER_PTE_ROW_NOM_C[k] = dpte_row_height_chroma[k] / (VRatio[k] / 2); + } + } else { + DST_Y_PER_PTE_ROW_NOM_L[k] = 0; + DST_Y_PER_PTE_ROW_NOM_C[k] = 0; + } + if (DCCEnable[k] == true) { + DST_Y_PER_META_ROW_NOM_L[k] = meta_row_height[k] / VRatio[k]; + } else { + DST_Y_PER_META_ROW_NOM_L[k] = 0; + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (DCCEnable[k] == true) { + meta_chunk_width = MetaChunkSize * 1024 * 256 + / dml_ceil(BytePerPixelDETY[k], 1) / meta_row_height[k]; + min_meta_chunk_width = MinMetaChunkSizeBytes * 256 + / dml_ceil(BytePerPixelDETY[k], 1) / meta_row_height[k]; + meta_chunk_per_row_int = meta_row_width[k] / meta_chunk_width; + meta_row_remainder = meta_row_width[k] % meta_chunk_width; + if (SourceScan[k] == dm_horz) { + meta_chunk_threshold = 2 * min_meta_chunk_width - meta_req_width[k]; + } else { + meta_chunk_threshold = 2 * min_meta_chunk_width + - meta_req_height[k]; + } + if (meta_row_remainder <= meta_chunk_threshold) { + meta_chunks_per_row_ub = meta_chunk_per_row_int + 1; + } else { + meta_chunks_per_row_ub = meta_chunk_per_row_int + 2; + } + TimePerMetaChunkNominal[k] = meta_row_height[k] / VRatio[k] * HTotal[k] + / PixelClock[k] / meta_chunks_per_row_ub; + TimePerMetaChunkVBlank[k] = DestinationLinesToRequestRowInVBlank[k] + * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub; + TimePerMetaChunkFlip[k] = DestinationLinesToRequestRowInImmediateFlip[k] + * HTotal[k] / PixelClock[k] / meta_chunks_per_row_ub; + } else { + TimePerMetaChunkNominal[k] = 0; + TimePerMetaChunkVBlank[k] = 0; + TimePerMetaChunkFlip[k] = 0; + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (GPUVMEnable == true) { + if (SourceScan[k] == dm_horz) { + dpte_group_width_luma = dpte_group_bytes[k] / PTERequestSizeY[k] + * PixelPTEReqWidthY[k]; + } else { + dpte_group_width_luma = dpte_group_bytes[k] / PTERequestSizeY[k] + * PixelPTEReqHeightY[k]; + } + dpte_groups_per_row_luma_ub = dml_ceil( + dpte_row_width_luma_ub[k] / dpte_group_width_luma, + 1); + time_per_pte_group_nom_luma[k] = DST_Y_PER_PTE_ROW_NOM_L[k] * HTotal[k] + / PixelClock[k] / dpte_groups_per_row_luma_ub; + time_per_pte_group_vblank_luma[k] = DestinationLinesToRequestRowInVBlank[k] + * HTotal[k] / PixelClock[k] / dpte_groups_per_row_luma_ub; + time_per_pte_group_flip_luma[k] = + DestinationLinesToRequestRowInImmediateFlip[k] * HTotal[k] + / PixelClock[k] + / dpte_groups_per_row_luma_ub; + if (BytePerPixelDETC[k] == 0) { + time_per_pte_group_nom_chroma[k] = 0; + time_per_pte_group_vblank_chroma[k] = 0; + time_per_pte_group_flip_chroma[k] = 0; + } else { + if (SourceScan[k] == dm_horz) { + dpte_group_width_chroma = dpte_group_bytes[k] + / PTERequestSizeC[k] * PixelPTEReqWidthC[k]; + } else { + dpte_group_width_chroma = dpte_group_bytes[k] + / PTERequestSizeC[k] + * PixelPTEReqHeightC[k]; + } + dpte_groups_per_row_chroma_ub = dml_ceil( + dpte_row_width_chroma_ub[k] + / dpte_group_width_chroma, + 1); + time_per_pte_group_nom_chroma[k] = DST_Y_PER_PTE_ROW_NOM_C[k] + * HTotal[k] / PixelClock[k] + / dpte_groups_per_row_chroma_ub; + time_per_pte_group_vblank_chroma[k] = + DestinationLinesToRequestRowInVBlank[k] * HTotal[k] + / PixelClock[k] + / dpte_groups_per_row_chroma_ub; + time_per_pte_group_flip_chroma[k] = + DestinationLinesToRequestRowInImmediateFlip[k] + * HTotal[k] / PixelClock[k] + / dpte_groups_per_row_chroma_ub; + } + } else { + time_per_pte_group_nom_luma[k] = 0; + time_per_pte_group_vblank_luma[k] = 0; + time_per_pte_group_flip_luma[k] = 0; + time_per_pte_group_nom_chroma[k] = 0; + time_per_pte_group_vblank_chroma[k] = 0; + time_per_pte_group_flip_chroma[k] = 0; + } + } + + for (k = 0; k < NumberOfActivePlanes; ++k) { + if (GPUVMEnable == true && (DCCEnable[k] == true || GPUVMMaxPageTableLevels > 1)) { + if (DCCEnable[k] == false) { + if (BytePerPixelDETC[k] > 0) { + num_group_per_lower_vm_stage = + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (dpde0_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } else { + if (GPUVMMaxPageTableLevels == 1) { + if (BytePerPixelDETC[k] > 0) { + num_group_per_lower_vm_stage = + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } else { + if (BytePerPixelDETC[k] > 0) { + num_group_per_lower_vm_stage = + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (dpde0_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_c[k]) / (double) (vm_group_bytes[k]), 1); + } else { + num_group_per_lower_vm_stage = + dml_ceil((double) (dpde0_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1) + + dml_ceil((double) (meta_pte_bytes_per_frame_ub_l[k]) / (double) (vm_group_bytes[k]), 1); + } + } + } + + if (DCCEnable[k] == false) { + if (BytePerPixelDETC[k] > 0) { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] + / 64 + dpde0_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] + / 64; + } + } else { + if (GPUVMMaxPageTableLevels == 1) { + if (BytePerPixelDETC[k] > 0) { + num_req_per_lower_vm_stage = meta_pte_bytes_per_frame_ub_l[k] / 64 + + meta_pte_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = meta_pte_bytes_per_frame_ub_l[k] / 64; + } + } else { + if (BytePerPixelDETC[k] > 0) { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64 + + dpde0_bytes_per_frame_ub_c[k] / 64 + + meta_pte_bytes_per_frame_ub_l[k] / 64 + + meta_pte_bytes_per_frame_ub_c[k] / 64; + } else { + num_req_per_lower_vm_stage = dpde0_bytes_per_frame_ub_l[k] / 64 + + meta_pte_bytes_per_frame_ub_l[k] / 64; + } + } + } + + TimePerVMGroupVBlank[k] = DestinationLinesToRequestVMInVBlank[k] * HTotal[k] + / PixelClock[k] / num_group_per_lower_vm_stage; + TimePerVMGroupFlip[k] = DestinationLinesToRequestVMInImmediateFlip[k] + * HTotal[k] / PixelClock[k] / num_group_per_lower_vm_stage; + TimePerVMRequestVBlank[k] = DestinationLinesToRequestVMInVBlank[k] + * HTotal[k] / PixelClock[k] / num_req_per_lower_vm_stage; + TimePerVMRequestFlip[k] = DestinationLinesToRequestVMInImmediateFlip[k] + * HTotal[k] / PixelClock[k] / num_req_per_lower_vm_stage; + + if (GPUVMMaxPageTableLevels > 2) { + TimePerVMGroupVBlank[k] = TimePerVMGroupVBlank[k] / 2; + TimePerVMGroupFlip[k] = TimePerVMGroupFlip[k] / 2; + TimePerVMRequestVBlank[k] = TimePerVMRequestVBlank[k] / 2; + TimePerVMRequestFlip[k] = TimePerVMRequestFlip[k] / 2; + } + + } else { + TimePerVMGroupVBlank[k] = 0; + TimePerVMGroupFlip[k] = 0; + TimePerVMRequestVBlank[k] = 0; + TimePerVMRequestFlip[k] = 0; + } + } +} + +static double CalculateExtraLatency( + double UrgentRoundTripAndOutOfOrderLatency, + int TotalNumberOfActiveDPP, + int PixelChunkSizeInKByte, + int TotalNumberOfDCCActiveDPP, + int MetaChunkSize, + double ReturnBW, + bool GPUVMEnable, + bool HostVMEnable, + int NumberOfActivePlanes, + int NumberOfDPP[], + long dpte_group_bytes[], + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData, + double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly, + int HostVMMaxPageTableLevels, + int HostVMCachedPageTableLevels) +{ + double CalculateExtraLatency; + double HostVMInefficiencyFactor; + int HostVMDynamicLevels; + + if (GPUVMEnable && HostVMEnable) { + HostVMInefficiencyFactor = + PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData + / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly; + HostVMDynamicLevels = HostVMMaxPageTableLevels - HostVMCachedPageTableLevels; + } else { + HostVMInefficiencyFactor = 1; + HostVMDynamicLevels = 0; + } + + CalculateExtraLatency = UrgentRoundTripAndOutOfOrderLatency + + (TotalNumberOfActiveDPP * PixelChunkSizeInKByte + + TotalNumberOfDCCActiveDPP * MetaChunkSize) * 1024.0 + / ReturnBW; + + if (GPUVMEnable) { + int k; + + for (k = 0; k < NumberOfActivePlanes; k++) { + CalculateExtraLatency = CalculateExtraLatency + + NumberOfDPP[k] * dpte_group_bytes[k] + * (1 + 8 * HostVMDynamicLevels) + * HostVMInefficiencyFactor / ReturnBW; + } + } + return CalculateExtraLatency; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.h b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.h new file mode 100644 index 000000000000..fb9548a2f894 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_mode_vba_21.h @@ -0,0 +1,32 @@ +/* + * 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 __DML21_DISPLAY_MODE_VBA_H__ +#define __DML21_DISPLAY_MODE_VBA_H__ + +void dml21_recalculate(struct display_mode_lib *mode_lib); +void dml21_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib); + +#endif /* _DML21_DISPLAY_MODE_VBA_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c new file mode 100644 index 000000000000..a1f207cbb966 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.c @@ -0,0 +1,1823 @@ +/* + * 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" +#include "display_rq_dlg_calc_21.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. + */ + +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); + +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 hostvm_enable, + 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 + mode_lib->ip.dpte_buffer_size_in_pte_reqs_chroma; + 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 (hostvm_enable) + rq_sizing_param->dpte_group_bytes = 512; + else { + 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_params_st pipe_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_param.src.viewport_width_c / ppe; + vp_height = pipe_param.src.viewport_height_c; + data_pitch = pipe_param.src.data_pitch_c; + meta_pitch = pipe_param.src.meta_pitch_c; + } else { + vp_width = pipe_param.src.viewport_width / ppe; + vp_height = pipe_param.src.viewport_height; + data_pitch = pipe_param.src.data_pitch; + meta_pitch = pipe_param.src.meta_pitch; + } + + if (pipe_param.dest.odm_combine) { + unsigned int access_dir; + unsigned int full_src_vp_width; + unsigned int hactive_half; + unsigned int src_hactive_half; + access_dir = (pipe_param.src.source_scan == dm_vert); // vp access direction: horizontal or vertical accessed + hactive_half = pipe_param.dest.hactive / 2; + if (is_chroma) { + full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio_c * pipe_param.dest.full_recout_width; + src_hactive_half = pipe_param.scale_ratio_depth.hscl_ratio_c * hactive_half; + } else { + full_src_vp_width = pipe_param.scale_ratio_depth.hscl_ratio * pipe_param.dest.full_recout_width; + src_hactive_half = pipe_param.scale_ratio_depth.hscl_ratio * hactive_half; + } + + if (access_dir == 0) { + vp_width = dml_min(full_src_vp_width, src_hactive_half); + dml_print("DML_DLG: %s: vp_width = %d\n", __func__, vp_width); + } else { + vp_height = dml_min(full_src_vp_width, src_hactive_half); + dml_print("DML_DLG: %s: vp_height = %d\n", __func__, vp_height); + + } + dml_print("DML_DLG: %s: full_src_vp_width = %d\n", __func__, full_src_vp_width); + dml_print("DML_DLG: %s: hactive_half = %d\n", __func__, hactive_half); + dml_print("DML_DLG: %s: src_hactive_half = %d\n", __func__, src_hactive_half); + } + 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; + + if (pipe_param.src.hostvm) + rq_sizing_param->mpte_group_bytes = 512; + else + 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_param.src.source_format, + pipe_param.src.sw_mode, + pipe_param.src.macro_tile_size, + pipe_param.src.source_scan, + pipe_param.src.hostvm, + is_chroma); +} + +static void dml_rq_dlg_get_rq_params( + struct display_mode_lib *mode_lib, + display_rq_params_st *rq_param, + const display_pipe_params_st pipe_param) +{ + // get param for luma surface + rq_param->yuv420 = pipe_param.src.source_format == dm_420_8 + || pipe_param.src.source_format == dm_420_10; + rq_param->yuv420_10bpc = pipe_param.src.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_param, + 0); + + if (is_dual_plane((enum source_format_class) (pipe_param.src.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_param, + 1); + } + + // calculate how to split the det buffer space between luma and chroma + handle_det_buf_split(mode_lib, rq_param, pipe_param.src); + print__rq_params_st(mode_lib, *rq_param); +} + +void dml21_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)); + dml_rq_dlg_get_rq_params(mode_lib, &rq_param, pipe_param); + 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 dml_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 max_dst_y_per_vm_vblank; + double max_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) * 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); + swath_width_ub_l = rq_dlg_param.rq_l.swath_width_ub; + dpte_groups_per_row_ub_l = rq_dlg_param.rq_l.dpte_groups_per_row_ub; + swath_width_ub_c = rq_dlg_param.rq_c.swath_width_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 + // TODO: Should this be urgent_latency_pixel_mixed_with_vm_data_us? + line_wait = mode_lib->soc.urgent_latency_pixel_data_only_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_pixel_data_only_us, // TODO: Should this be urgent_latency_pixel_mixed_with_vm_data_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); + + max_dst_y_per_vm_vblank = 32.0; + max_dst_y_per_row_vblank = 16.0; + + // magic! + if (htotal <= 75) { + min_vblank = 300; + max_dst_y_per_vm_vblank = 100.0; + max_dst_y_per_row_vblank = 100.0; + } + + dml_print("DML_DLG: %s: dst_y_per_vm_flip = %3.2f\n", __func__, dst_y_per_vm_flip); + dml_print("DML_DLG: %s: dst_y_per_row_flip = %3.2f\n", __func__, dst_y_per_row_flip); + 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 < max_dst_y_per_vm_vblank); + ASSERT(dst_y_per_row_vblank < max_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)); + + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_vblank); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_vblank); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_flip); + dml_print("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_flip); + + 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->refcyc_per_vm_group_vblank = get_refcyc_per_vm_group_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; + disp_dlg_regs->refcyc_per_vm_group_flip = get_refcyc_per_vm_group_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; + disp_dlg_regs->refcyc_per_vm_req_vblank = get_refcyc_per_vm_req_vblank(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;; + disp_dlg_regs->refcyc_per_vm_req_flip = get_refcyc_per_vm_req_flip(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz;; + + // Clamp to max for now + if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int)dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_group_vblank = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_group_flip >= (unsigned int)dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_group_flip = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_req_vblank >= (unsigned int)dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_req_vblank = dml_pow(2, 23) - 1; + + if (disp_dlg_regs->refcyc_per_vm_req_flip >= (unsigned int)dml_pow(2, 23)) + disp_dlg_regs->refcyc_per_vm_req_flip = dml_pow(2, 23) - 1; + 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 + + dml_print( + "DML: Trow: %fus\n", + line_time_in_us * (double)dpte_row_height_l / (double)vratio_l); + + 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 dml21_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); + dml_rq_dlg_get_rq_params(mode_lib, &rq_param, e2e_pipe_param[pipe_idx].pipe); + dml_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); +} + +void dml_rq_dlg_get_arb_params(struct display_mode_lib *mode_lib, display_arb_params_st *arb_param) +{ + memset(arb_param, 0, sizeof(*arb_param)); + arb_param->max_req_outstanding = 256; + arb_param->min_req_outstanding = 68; + arb_param->sat_level_us = 60; +} + +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)); + } +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h new file mode 100644 index 000000000000..83e95f8cbff2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn21/display_rq_dlg_calc_21.h @@ -0,0 +1,73 @@ +/* + * 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 __DML21_DISPLAY_RQ_DLG_CALC_H__ +#define __DML21_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> functions 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 dml21_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 dml21_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 0c2fab1e93b6..1c97083b8d0b 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 @@ -37,11 +37,14 @@ enum source_format_class { dm_444_64 = 2, dm_420_8 = 3, dm_420_10 = 4, - dm_422_8 = 5, - dm_422_10 = 6, - dm_444_8 = 7, + dm_420_12 = 5, + dm_422_8 = 6, + dm_422_10 = 7, + dm_444_8 = 8, dm_mono_8 = dm_444_8, - dm_mono_16 = dm_444_16 + dm_mono_16 = dm_444_16, + dm_rgbe = 9, + dm_rgbe_alpha = 10, }; enum output_bpc_class { dm_out_6 = 0, dm_out_8 = 1, dm_out_10 = 2, dm_out_12 = 3, dm_out_16 = 4 @@ -83,7 +86,7 @@ enum dm_swizzle_mode { dm_sw_var_d_x = 30, dm_sw_64kb_r_x, dm_sw_gfx7_2d_thin_lvp, - dm_sw_gfx7_2d_thin_gl + 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 = 4, @@ -112,7 +115,8 @@ enum output_standard { enum mpc_combine_affinity { dm_mpc_always_when_possible, dm_mpc_reduce_voltage, - dm_mpc_reduce_voltage_and_clocks + dm_mpc_reduce_voltage_and_clocks, + dm_mpc_never }; enum self_refresh_affinity { @@ -157,4 +161,10 @@ enum writeback_config { dm_whole_buffer_for_single_stream_interleave, }; +enum odm_combine_mode { + dm_odm_combine_mode_disabled, + dm_odm_combine_mode_2to1, + dm_odm_combine_mode_4to1, +}; + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c index 91810c7d5cf5..704efefdcba8 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 @@ -28,6 +28,12 @@ #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/display_mode_vba_20.h" #include "dcn20/display_rq_dlg_calc_20.h" +#include "dcn20/display_mode_vba_20v2.h" +#include "dcn20/display_rq_dlg_calc_20v2.h" +#endif +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +#include "dcn21/display_mode_vba_21.h" +#include "dcn21/display_rq_dlg_calc_21.h" #endif #if defined(CONFIG_DRM_AMD_DC_DCN2_0) @@ -37,6 +43,22 @@ const struct dml_funcs dml20_funcs = { .rq_dlg_get_dlg_reg = dml20_rq_dlg_get_dlg_reg, .rq_dlg_get_rq_reg = dml20_rq_dlg_get_rq_reg }; + +const struct dml_funcs dml20v2_funcs = { + .validate = dml20v2_ModeSupportAndSystemConfigurationFull, + .recalculate = dml20v2_recalculate, + .rq_dlg_get_dlg_reg = dml20v2_rq_dlg_get_dlg_reg, + .rq_dlg_get_rq_reg = dml20v2_rq_dlg_get_rq_reg +}; +#endif + +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +const struct dml_funcs dml21_funcs = { + .validate = dml21_ModeSupportAndSystemConfigurationFull, + .recalculate = dml21_recalculate, + .rq_dlg_get_dlg_reg = dml21_rq_dlg_get_dlg_reg, + .rq_dlg_get_rq_reg = dml21_rq_dlg_get_rq_reg +}; #endif void dml_init_instance(struct display_mode_lib *lib, @@ -52,7 +74,16 @@ void dml_init_instance(struct display_mode_lib *lib, case DML_PROJECT_NAVI10: lib->funcs = dml20_funcs; break; + case DML_PROJECT_NAVI10v2: + lib->funcs = dml20v2_funcs; + break; #endif +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + case DML_PROJECT_DCN21: + lib->funcs = dml21_funcs; + break; +#endif + default: break; } 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 5bf13d67f289..d8c59aa356b6 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 @@ -36,6 +36,10 @@ enum dml_project { DML_PROJECT_RAVEN1, #ifdef CONFIG_DRM_AMD_DC_DCN2_0 DML_PROJECT_NAVI10, + DML_PROJECT_NAVI10v2, +#endif +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + DML_PROJECT_DCN21, #endif }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h index 5678472546ab..f4c1ef9046bf 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 @@ -100,6 +100,7 @@ struct _vcs_dpi_soc_bounding_box_st { unsigned int vmm_page_size_bytes; unsigned int hostvm_min_page_size_bytes; double dram_clock_change_latency_us; + double dummy_pstate_latency_us; double writeback_dram_clock_change_latency_us; unsigned int return_bus_width_bytes; unsigned int voltage_override; @@ -108,6 +109,9 @@ struct _vcs_dpi_soc_bounding_box_st { int use_urgent_burst_bw; unsigned int num_states; struct _vcs_dpi_voltage_scaling_st clock_limits[MAX_CLOCK_LIMIT_STATES]; + bool do_urgent_latency_adjustment; + double urgent_latency_adjustment_fabric_clock_component_us; + double urgent_latency_adjustment_fabric_clock_reference_mhz; }; struct _vcs_dpi_ip_params_st { 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 index 4d2a1262d9db..65cf4edddaff 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c @@ -262,6 +262,13 @@ static void fetch_socbb_params(struct display_mode_lib *mode_lib) //mode_lib->vba.DRAMSpeedPerState[i] = soc->clock_limits[i].dram_speed_mhz; mode_lib->vba.MaxDispclk[i] = soc->clock_limits[i].dispclk_mhz; } + + mode_lib->vba.DoUrgentLatencyAdjustment = + soc->do_urgent_latency_adjustment; + mode_lib->vba.UrgentLatencyAdjustmentFabricClockComponent = + soc->urgent_latency_adjustment_fabric_clock_component_us; + mode_lib->vba.UrgentLatencyAdjustmentFabricClockReference = + soc->urgent_latency_adjustment_fabric_clock_reference_mhz; } static void fetch_ip_params(struct display_mode_lib *mode_lib) @@ -385,8 +392,10 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) 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.SurfaceWidthY[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width; 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.SurfaceWidthC[mode_lib->vba.NumberOfActivePlanes] = src->viewport_width_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; @@ -457,6 +466,10 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) dout->wb.wb_dst_width; mode_lib->vba.WritebackDestinationHeight[mode_lib->vba.NumberOfActivePlanes] = dout->wb.wb_dst_height; + 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.WritebackPixelFormat[mode_lib->vba.NumberOfActivePlanes] = (enum source_format_class) (dout->wb.wb_pixel_format); mode_lib->vba.WritebackHTaps[mode_lib->vba.NumberOfActivePlanes] = @@ -568,6 +581,7 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) 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; + display_pipe_dest_params_st *dst_k = &pipes[k].pipe.dest; if (src_k->is_hsplit && !visited[k] && src->hsplit_grp == src_k->hsplit_grp) { @@ -575,12 +589,15 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib) mode_lib->vba.NumberOfActivePlanes; mode_lib->vba.DPPPerPlane[mode_lib->vba.NumberOfActivePlanes]++; if (mode_lib->vba.SourceScan[mode_lib->vba.NumberOfActivePlanes] - == dm_horz) + == dm_horz) { mode_lib->vba.ViewportWidth[mode_lib->vba.NumberOfActivePlanes] += src_k->viewport_width; - else + mode_lib->vba.ScalerRecoutWidth[mode_lib->vba.NumberOfActivePlanes] += + dst_k->recout_width; + } else { mode_lib->vba.ViewportHeight[mode_lib->vba.NumberOfActivePlanes] += src_k->viewport_height; + } visited[k] = true; } 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 index 0347f74cda3a..91decac50557 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h +++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h @@ -290,6 +290,7 @@ struct vba_vars_st { double PixelClock[DC__NUM_DPP__MAX]; double PixelClockBackEnd[DC__NUM_DPP__MAX]; bool DCCEnable[DC__NUM_DPP__MAX]; + bool FECEnable[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]; @@ -317,6 +318,7 @@ struct vba_vars_st { double DCCRate[DC__NUM_DPP__MAX]; double AverageDCCCompressionRate; bool ODMCombineEnabled[DC__NUM_DPP__MAX]; + enum odm_combine_mode ODMCombineTypeEnabled[DC__NUM_DPP__MAX]; double OutputBpp[DC__NUM_DPP__MAX]; bool DSCEnabled[DC__NUM_DPP__MAX]; unsigned int DSCInputBitPerComponent[DC__NUM_DPP__MAX]; @@ -395,6 +397,7 @@ struct vba_vars_st { double FabricClockPerState[DC__VOLTAGE_STATES + 1]; double SOCCLKPerState[DC__VOLTAGE_STATES + 1]; double PHYCLKPerState[DC__VOLTAGE_STATES + 1]; + double DTBCLKPerState[DC__VOLTAGE_STATES + 1]; double MaxDppclk[DC__VOLTAGE_STATES + 1]; double MaxDSCCLK[DC__VOLTAGE_STATES + 1]; double DRAMSpeedPerState[DC__VOLTAGE_STATES + 1]; @@ -488,6 +491,7 @@ struct vba_vars_st { 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]; + enum odm_combine_mode ODMCombineTypeEnablePerState[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]; @@ -513,6 +517,7 @@ struct vba_vars_st { bool DIOSupport[DC__VOLTAGE_STATES + 1]; bool NotEnoughDSCUnits[DC__VOLTAGE_STATES + 1]; bool DSCCLKRequiredMoreThanSupported[DC__VOLTAGE_STATES + 1]; + bool DTBCLKRequiredMoreThanSupported[DC__VOLTAGE_STATES + 1]; double UrgentRoundTripAndOutOfOrderLatencyPerState[DC__VOLTAGE_STATES + 1]; bool ROBSupport[DC__VOLTAGE_STATES + 1]; bool PTEBufferSizeNotExceeded[DC__VOLTAGE_STATES + 1][2]; @@ -605,6 +610,7 @@ struct vba_vars_st { double MaximumSwathWidthLuma[DC__NUM_DPP__MAX]; double MaximumSwathWidthChroma[DC__NUM_DPP__MAX]; bool odm_combine_dummy[DC__NUM_DPP__MAX]; + enum odm_combine_mode odm_combine_mode_dummy[DC__NUM_DPP__MAX]; double dummy1[DC__NUM_DPP__MAX]; double dummy2[DC__NUM_DPP__MAX]; double dummy3[DC__NUM_DPP__MAX]; @@ -625,6 +631,11 @@ struct vba_vars_st { unsigned int dummyinteger10; unsigned int dummyinteger11; unsigned int dummyinteger12; + unsigned int dummyintegerarr1[DC__NUM_DPP__MAX]; + unsigned int dummyintegerarr2[DC__NUM_DPP__MAX]; + unsigned int dummyintegerarr3[DC__NUM_DPP__MAX]; + unsigned int dummyintegerarr4[DC__NUM_DPP__MAX]; + long dummylongarr1[DC__NUM_DPP__MAX]; bool dummysinglestring; bool SingleDPPViewportSizeSupportPerPlane[DC__NUM_DPP__MAX]; double PlaneRequiredDISPCLKWithODMCombine2To1; @@ -633,6 +644,7 @@ struct vba_vars_st { bool LinkDSCEnable; bool ODMCombine4To1SupportCheckOK[DC__VOLTAGE_STATES + 1]; bool ODMCombineEnableThisState[DC__NUM_DPP__MAX]; + enum odm_combine_mode ODMCombineEnableTypeThisState[DC__NUM_DPP__MAX]; unsigned int SwathWidthCThisState[DC__NUM_DPP__MAX]; bool ViewportSizeSupportPerPlane[DC__NUM_DPP__MAX]; double AlignedDCCMetaPitchY[DC__NUM_DPP__MAX]; @@ -641,6 +653,7 @@ struct vba_vars_st { unsigned int NotEnoughUrgentLatencyHiding; unsigned int NotEnoughUrgentLatencyHidingPre; long PTEBufferSizeInRequestsForLuma; + long PTEBufferSizeInRequestsForChroma; // Missing from VBA long dpte_group_bytes_chroma; @@ -787,6 +800,9 @@ struct vba_vars_st { unsigned int PDEProcessingBufIn64KBReqs; double MaxTotalVActiveRDBandwidth; + bool DoUrgentLatencyAdjustment; + double UrgentLatencyAdjustmentFabricClockComponent; + double UrgentLatencyAdjustmentFabricClockReference; double MinUrgentLatencySupportUs; double MinFullDETBufferingTime; double AverageReadBandwidthGBytePerSecond; @@ -801,6 +817,8 @@ struct vba_vars_st { bool ModeIsSupported; bool ODMCombine4To1Supported; + unsigned int SurfaceWidthY[DC__NUM_DPP__MAX]; + unsigned int SurfaceWidthC[DC__NUM_DPP__MAX]; unsigned int SurfaceHeightY[DC__NUM_DPP__MAX]; unsigned int SurfaceHeightC[DC__NUM_DPP__MAX]; unsigned int WritebackHTaps[DC__NUM_DPP__MAX]; diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index e019cd9447e8..17db603f2d1f 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -9,6 +9,10 @@ endif dsc_ccflags := -mhard-float -msse $(cc_stack_align) +ifdef CONFIG_CC_IS_CLANG +dsc_ccflags += -msse2 +endif + CFLAGS_rc_calc.o := $(dsc_ccflags) CFLAGS_rc_calc_dpi.o := $(dsc_ccflags) CFLAGS_codec_main_amd.o := $(dsc_ccflags) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index ef5f84a144c3..5995bcdfed54 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -28,6 +28,23 @@ #include "dsc.h" #include <drm/drm_dp_helper.h> +struct dc_dsc_policy { + bool use_min_slices_h; + int max_slices_h; // Maximum available if 0 + int min_sice_height; // Must not be less than 8 + int max_target_bpp; + int min_target_bpp; // Minimum target bits per pixel +}; + +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) + .min_sice_height = 108, // DSC Policy: Use slice height recommended by VESA DSC Spreadsheet user guide + .max_target_bpp = 16, + .min_target_bpp = 8, +}; + + /* This module's internal functions */ static bool dsc_buff_block_size_from_dpcd(int dpcd_buff_block_size, int *buff_block_size) @@ -241,14 +258,6 @@ static bool intersect_dsc_caps( 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; @@ -270,19 +279,6 @@ static inline uint32_t calc_dsc_bpp_x16(uint32_t stream_bandwidth_kbps, uint32_t 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. */ @@ -528,8 +524,8 @@ static bool setup_dsc_config( int sink_per_slice_throughput_mps; int branch_max_throughput_mps = 0; bool is_dsc_possible = false; - int num_slices_v; int pic_height; + int slice_height; memset(dsc_cfg, 0, sizeof(struct dc_dsc_config)); @@ -615,7 +611,7 @@ static bool setup_dsc_config( if (!is_dsc_possible) goto done; - // DSC slicing + // Slice width (i.e. number of slices per line) max_slices_h = get_max_dsc_slices(dsc_common_caps.slice_caps); while (max_slices_h > 0) { @@ -678,29 +674,26 @@ static bool setup_dsc_config( 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. + is_dsc_possible = slice_width <= dsc_common_caps.max_slice_width; + if (!is_dsc_possible) + goto done; + + // Slice height (i.e. number of slices per column): start with 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; + slice_height = min(dsc_policy.min_sice_height, pic_height); - num_slices_v--; - } + while (slice_height < pic_height && (pic_height % slice_height != 0 || + (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 && slice_height % 2 != 0))) + slice_height++; - dsc_cfg->num_slices_v = num_slices_v; + if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) // For the case when pic_height < dsc_policy.min_sice_height + is_dsc_possible = (slice_height % 2 == 0); - is_dsc_possible = slice_width <= dsc_common_caps.max_slice_width; if (!is_dsc_possible) goto done; + dsc_cfg->num_slices_v = pic_height/slice_height; + // Final decission: can we do DSC or not? if (is_dsc_possible) { // Fill out the rest of DSC settings 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 deleted file mode 100644 index 340ef4d41ebd..000000000000 --- a/drivers/gpu/drm/amd/display/dc/dsc/drm_dsc_dc.c +++ /dev/null @@ -1,388 +0,0 @@ -// 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; - - /* As per DSC spec v1.2a recommendation: */ - if (vdsc_cfg->native_420) - vdsc_cfg->second_line_offset_adj = 512; - else - vdsc_cfg->second_line_offset_adj = 0; - - return 0; -} -EXPORT_SYMBOL(drm_dsc_compute_rc_parameters); diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index c3d92878875d..b3062275711e 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -24,7 +24,7 @@ # It provides the control and status of HW GPIO pins. GPIO = gpio_base.o gpio_service.o hw_factory.o \ - hw_gpio.o hw_hpd.o hw_ddc.o hw_translate.o + hw_gpio.o hw_hpd.o hw_ddc.o hw_generic.o hw_translate.o AMD_DAL_GPIO = $(addprefix $(AMDDALPATH)/dc/gpio/,$(GPIO)) @@ -80,6 +80,13 @@ AMD_DAL_GPIO_DCN20 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn20/,$(GPIO_DCN20)) AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN20) endif +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +GPIO_DCN21 = hw_translate_dcn21.o hw_factory_dcn21.o + +AMD_DAL_GPIO_DCN21 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn21/,$(GPIO_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN21) +endif ############################################################################### # Diagnostics on FPGA ############################################################################### diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c b/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c index 20d81bca119c..66e4841f41e4 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c @@ -24,9 +24,15 @@ */ #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_generic.h" + #include "hw_factory_dce110.h" #include "dce/dce_11_0_d.h" @@ -143,12 +149,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) } 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, + .init_ddc_data = dal_hw_ddc_init, + .init_generic = NULL, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = NULL, .define_hpd_registers = define_hpd_registers, .define_ddc_registers = define_ddc_registers }; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c index ea3f888e5c65..cf98aa827a9a 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c @@ -27,10 +27,10 @@ #include "include/gpio_types.h" #include "../hw_factory.h" - #include "../hw_gpio.h" #include "../hw_ddc.h" #include "../hw_hpd.h" +#include "../hw_generic.h" #include "hw_factory_dce120.h" @@ -164,12 +164,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) /* 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, + .init_ddc_data = dal_hw_ddc_init, + .init_generic = NULL, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = NULL, .define_hpd_registers = define_hpd_registers, .define_ddc_registers = define_ddc_registers }; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c index 48b67866377e..496d3ffb74bb 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c @@ -32,10 +32,12 @@ #include "../hw_gpio.h" #include "../hw_ddc.h" #include "../hw_hpd.h" +#include "../hw_generic.h" #include "dce/dce_8_0_d.h" #include "dce/dce_8_0_sh_mask.h" + #define REG(reg_name)\ mm ## reg_name @@ -147,12 +149,12 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) } 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, + .init_ddc_data = dal_hw_ddc_init, + .init_generic = NULL, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = NULL, .define_hpd_registers = define_hpd_registers, .define_ddc_registers = define_ddc_registers }; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c index 32aa47a04a0d..b38c96c9fed3 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c @@ -31,6 +31,7 @@ #include "../hw_gpio.h" #include "../hw_ddc.h" #include "../hw_hpd.h" +#include "../hw_generic.h" #include "hw_factory_dcn10.h" @@ -121,6 +122,42 @@ static const struct ddc_sh_mask ddc_mask = { DDC_MASK_SH_LIST(_MASK) }; +#include "../generic_regs.h" + +/* set field name */ +#define SF_GENERIC(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define generic_regs(id) \ +{\ + GENERIC_REG_LIST(id)\ +} + +static const struct generic_registers generic_regs[] = { + generic_regs(A), + generic_regs(B), +}; + +static const struct generic_sh_mask generic_shift[] = { + GENERIC_MASK_SH_LIST(__SHIFT, A), + GENERIC_MASK_SH_LIST(__SHIFT, B), +}; + +static const struct generic_sh_mask generic_mask[] = { + GENERIC_MASK_SH_LIST(_MASK, A), + GENERIC_MASK_SH_LIST(_MASK, B), +}; + +static void define_generic_registers(struct hw_gpio_pin *pin, uint32_t en) +{ + struct hw_generic *generic = HW_GENERIC_FROM_BASE(pin); + + generic->regs = &generic_regs[en]; + generic->shifts = &generic_shift[en]; + generic->masks = &generic_mask[en]; + generic->base.regs = &generic_regs[en].gpio; +} + static void define_ddc_registers( struct hw_gpio_pin *pin, uint32_t en) @@ -159,14 +196,15 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) /* 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, + .init_ddc_data = dal_hw_ddc_init, + .init_generic = dal_hw_generic_init, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = dal_hw_generic_get_pin, .define_hpd_registers = define_hpd_registers, - .define_ddc_registers = define_ddc_registers + .define_ddc_registers = define_ddc_registers, + .define_generic_registers = define_generic_registers }; /* * dal_hw_factory_dcn10_init 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 index abd76d855375..43a440385b43 100644 --- 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 @@ -31,6 +31,7 @@ #include "../hw_gpio.h" #include "../hw_ddc.h" #include "../hw_hpd.h" +#include "../hw_generic.h" #include "hw_factory_dcn20.h" @@ -138,6 +139,32 @@ static const struct ddc_sh_mask ddc_mask[] = { DDC_MASK_SH_LIST_DCN2(_MASK, 6) }; +#include "../generic_regs.h" + +/* set field name */ +#define SF_GENERIC(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define generic_regs(id) \ +{\ + GENERIC_REG_LIST(id)\ +} + +static const struct generic_registers generic_regs[] = { + generic_regs(A), + generic_regs(B), +}; + +static const struct generic_sh_mask generic_shift[] = { + GENERIC_MASK_SH_LIST(__SHIFT, A), + GENERIC_MASK_SH_LIST(__SHIFT, B), +}; + +static const struct generic_sh_mask generic_mask[] = { + GENERIC_MASK_SH_LIST(_MASK, A), + GENERIC_MASK_SH_LIST(_MASK, B), +}; + static void define_ddc_registers( struct hw_gpio_pin *pin, uint32_t en) @@ -173,17 +200,27 @@ static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en) hpd->base.regs = &hpd_regs[en].gpio; } +static void define_generic_registers(struct hw_gpio_pin *pin, uint32_t en) +{ + struct hw_generic *generic = HW_GENERIC_FROM_BASE(pin); + + generic->regs = &generic_regs[en]; + generic->shifts = &generic_shift[en]; + generic->masks = &generic_mask[en]; + generic->base.regs = &generic_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, + .init_ddc_data = dal_hw_ddc_init, + .init_generic = dal_hw_generic_init, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = dal_hw_generic_get_pin, .define_hpd_registers = define_hpd_registers, - .define_ddc_registers = define_ddc_registers + .define_ddc_registers = define_ddc_registers, + .define_generic_registers = define_generic_registers, }; /* * dal_hw_factory_dcn10_init 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 index b393cc13298a..915e896e0e91 100644 --- 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 @@ -71,7 +71,7 @@ static bool offset_to_id( { switch (offset) { /* GENERIC */ - case REG(DC_GENERICA): + case REG(DC_GPIO_GENERIC_A): *id = GPIO_ID_GENERIC; switch (mask) { case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c new file mode 100644 index 000000000000..34485d9de78a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.c @@ -0,0 +1,210 @@ +/* + * 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_generic.h" + +#include "hw_factory_dcn21.h" + + +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" +#include "renoir_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) DMU_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), +}; + +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), +}; + +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), +}; + +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 = { + .init_ddc_data = dal_hw_ddc_init, + .init_generic = dal_hw_generic_init, + .init_hpd = dal_hw_hpd_init, + .get_ddc_pin = dal_hw_ddc_get_pin, + .get_hpd_pin = dal_hw_hpd_get_pin, + .get_generic_pin = dal_hw_generic_get_pin, + .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_dcn21_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/dcn21/hw_factory_dcn21.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.h new file mode 100644 index 000000000000..2443f9e7afbf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_factory_dcn21.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_1) +#ifndef __DAL_HW_FACTORY_DCN21_H__ +#define __DAL_HW_FACTORY_DCN21_H__ + +/* Initialize HW factory function pointers and pin info */ +void dal_hw_factory_dcn21_init(struct hw_factory *factory); + +#endif /* __DAL_HW_FACTORY_DCN20_H__ */ +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c new file mode 100644 index 000000000000..ad7c43746291 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c @@ -0,0 +1,386 @@ +/* + * 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_dcn21.h" + +#include "dm_services.h" +#include "include/gpio_types.h" +#include "../hw_translate.h" + +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" +#include "renoir_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) DMU_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); +#ifdef PALLADIUM_SUPPORTED + *en = GPIO_DDC_LINE_DDC1; + return true; +#endif + 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_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 +#ifdef PALLADIUM_SUPPORTED + *id = GPIO_ID_HPD; + *en = GPIO_DDC_LINE_DDC1; + return true; +#endif + 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_DDC5_A__DC_GPIO_DDC5DATA_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_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_DDC5_A__DC_GPIO_DDC5CLK_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_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); +#ifdef PALLADIUM_SUPPORTED + info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; + result = true; +#endif + 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_dcn21_init(struct hw_translate *tr) +{ + tr->funcs = &funcs; +} + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.h new file mode 100644 index 000000000000..2bfaac24c574 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.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_1) +#ifndef __DAL_HW_TRANSLATE_DCN21_H__ +#define __DAL_HW_TRANSLATE_DCN21_H__ + +struct hw_translate; + +/* Initialize Hw translate function pointers */ +void dal_hw_translate_dcn21_init(struct hw_translate *tr); + +#endif /* __DAL_HW_TRANSLATE_DCN21_H__ */ +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c b/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c index 26695b963c58..df68430aeb0c 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c @@ -38,15 +38,13 @@ #include "../hw_gpio.h" #include "../hw_ddc.h" #include "../hw_hpd.h" +#include "../hw_generic.h" /* function table */ static const struct hw_factory_funcs funcs = { - .create_ddc_data = NULL, - .create_ddc_clock = NULL, - .create_generic = NULL, - .create_hpd = NULL, - .create_sync = NULL, - .create_gsl = NULL, + .init_ddc_data = NULL, + .init_generic = NULL, + .init_hpd = NULL, }; void dal_hw_factory_diag_fpga_init(struct hw_factory *factory) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/generic_regs.h b/drivers/gpu/drm/amd/display/dc/gpio/generic_regs.h new file mode 100644 index 000000000000..8c05295c05c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/generic_regs.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012-16 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef DRIVERS_GPU_DRM_AMD_DC_DEV_DC_GPIO_GENERIC_REGS_H_ +#define DRIVERS_GPU_DRM_AMD_DC_DEV_DC_GPIO_GENERIC_REGS_H_ + +#include "gpio_regs.h" + +#define GENERIC_GPIO_REG_LIST_ENTRY(type, cd, id) \ + .type ## _reg = REG(DC_GPIO_GENERIC_## type),\ + .type ## _mask = DC_GPIO_GENERIC_ ## type ## __DC_GPIO_GENERIC ## id ## _ ## type ## _MASK,\ + .type ## _shift = DC_GPIO_GENERIC_ ## type ## __DC_GPIO_GENERIC ## id ## _ ## type ## __SHIFT + +#define GENERIC_GPIO_REG_LIST(id) \ + {\ + GENERIC_GPIO_REG_LIST_ENTRY(MASK, cd, id),\ + GENERIC_GPIO_REG_LIST_ENTRY(A, cd, id),\ + GENERIC_GPIO_REG_LIST_ENTRY(EN, cd, id),\ + GENERIC_GPIO_REG_LIST_ENTRY(Y, cd, id)\ + } + +#define GENERIC_REG_LIST(id) \ + GENERIC_GPIO_REG_LIST(id), \ + .mux = REG(DC_GENERIC ## id),\ + +#define GENERIC_MASK_SH_LIST(mask_sh, cd) \ + {(DC_GENERIC ## cd ##__GENERIC ## cd ##_EN## mask_sh),\ + (DC_GENERIC ## cd ##__GENERIC ## cd ##_SEL## mask_sh)} + +struct generic_registers { + struct gpio_registers gpio; + uint32_t mux; +}; + +struct generic_sh_mask { + /* enable */ + uint32_t GENERIC_EN; + /* select */ + uint32_t GENERIC_SEL; + +}; + + +#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_GPIO_GENERIC_REGS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c index d03b38e80d9b..f8f85490e77e 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c @@ -67,10 +67,14 @@ enum gpio_result dal_gpio_open_ex( return GPIO_RESULT_ALREADY_OPENED; } + // No action if allocation failed during gpio construct + if (!gpio->hw_container.ddc) { + ASSERT_CRITICAL(false); + return GPIO_RESULT_NON_SPECIFIC_ERROR; + } gpio->mode = mode; - return dal_gpio_service_open( - gpio->service, gpio->id, gpio->en, mode, &gpio->pin); + return dal_gpio_service_open(gpio); } enum gpio_result dal_gpio_get_value( @@ -231,6 +235,21 @@ enum gpio_pin_output_state dal_gpio_get_output_state( return gpio->output_state; } +struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio) +{ + return gpio->hw_container.ddc; +} + +struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio) +{ + return gpio->hw_container.hpd; +} + +struct hw_generic *dal_gpio_get_generic(struct gpio *gpio) +{ + return gpio->hw_container.generic; +} + void dal_gpio_close( struct gpio *gpio) { @@ -267,6 +286,30 @@ struct gpio *dal_gpio_create( gpio->mode = GPIO_MODE_UNKNOWN; gpio->output_state = output_state; + //initialize hw_container union based on id + switch (gpio->id) { + case GPIO_ID_DDC_DATA: + gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en); + break; + case GPIO_ID_DDC_CLOCK: + gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en); + break; + case GPIO_ID_GENERIC: + gpio->service->factory.funcs->init_generic(&gpio->hw_container.generic, service->ctx, id, en); + break; + case GPIO_ID_HPD: + gpio->service->factory.funcs->init_hpd(&gpio->hw_container.hpd, service->ctx, id, en); + break; + // TODO: currently gpio for sync and gsl does not get created, might need it later + case GPIO_ID_SYNC: + break; + case GPIO_ID_GSL: + break; + default: + ASSERT_CRITICAL(false); + gpio->pin = NULL; + } + return gpio; } @@ -280,6 +323,33 @@ void dal_gpio_destroy( dal_gpio_close(*gpio); + switch ((*gpio)->id) { + case GPIO_ID_DDC_DATA: + kfree((*gpio)->hw_container.ddc); + (*gpio)->hw_container.ddc = NULL; + break; + case GPIO_ID_DDC_CLOCK: + //TODO: might want to change it to init_ddc_clock + kfree((*gpio)->hw_container.ddc); + (*gpio)->hw_container.ddc = NULL; + break; + case GPIO_ID_GENERIC: + kfree((*gpio)->hw_container.generic); + (*gpio)->hw_container.generic = NULL; + break; + case GPIO_ID_HPD: + kfree((*gpio)->hw_container.hpd); + (*gpio)->hw_container.hpd = NULL; + break; + // TODO: currently gpio for sync and gsl does not get created, might need it later + case GPIO_ID_SYNC: + break; + case GPIO_ID_GSL: + break; + default: + break; + } + kfree(*gpio); *gpio = NULL; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c index a7fab44f66b6..d03165e71dc6 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c @@ -141,6 +141,58 @@ struct gpio *dal_gpio_service_create_irq( return dal_gpio_create_irq(service, id, en); } +struct gpio *dal_gpio_service_create_generic_mux( + struct gpio_service *service, + uint32_t offset, + uint32_t mask) +{ + enum gpio_id id; + uint32_t en; + struct gpio *generic; + + if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) { + ASSERT_CRITICAL(false); + return NULL; + } + + generic = dal_gpio_create( + service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT); + + return generic; +} + +void dal_gpio_destroy_generic_mux( + struct gpio **mux) +{ + if (!mux || !*mux) { + ASSERT_CRITICAL(false); + return; + } + + dal_gpio_close(*mux); + dal_gpio_destroy(mux); + kfree(*mux); + + *mux = NULL; +} + +struct gpio_pin_info dal_gpio_get_generic_pin_info( + struct gpio_service *service, + enum gpio_id id, + uint32_t en) +{ + struct gpio_pin_info pin; + + if (service->translate.funcs->id_to_offset) { + service->translate.funcs->id_to_offset(id, en, &pin); + } else { + pin.mask = 0xFFFFFFFF; + pin.offset = 0xFFFFFFFF; + } + + return pin; +} + void dal_gpio_service_destroy( struct gpio_service **ptr) { @@ -165,6 +217,21 @@ void dal_gpio_service_destroy( *ptr = NULL; } +enum gpio_result dal_mux_setup_config( + struct gpio *mux, + struct gpio_generic_mux_config *config) +{ + struct gpio_config_data config_data; + + if (!config) + return GPIO_RESULT_INVALID_DATA; + + config_data.config.generic_mux = *config; + config_data.type = GPIO_CONFIG_TYPE_GENERIC_MUX; + + return dal_gpio_set_config(mux, &config_data); +} + /* * @brief * Private API. @@ -223,13 +290,15 @@ enum gpio_result dal_gpio_service_unlock( } enum gpio_result dal_gpio_service_open( - struct gpio_service *service, - enum gpio_id id, - uint32_t en, - enum gpio_mode mode, - struct hw_gpio_pin **ptr) + struct gpio *gpio) { - struct hw_gpio_pin *pin; + struct gpio_service *service = gpio->service; + enum gpio_id id = gpio->id; + uint32_t en = gpio->en; + enum gpio_mode mode = gpio->mode; + + struct hw_gpio_pin **pin = &gpio->pin; + if (!service->busyness[id]) { ASSERT_CRITICAL(false); @@ -243,50 +312,43 @@ enum gpio_result dal_gpio_service_open( switch (id) { case GPIO_ID_DDC_DATA: - pin = service->factory.funcs->create_ddc_data( - service->ctx, id, en); - service->factory.funcs->define_ddc_registers(pin, en); + *pin = service->factory.funcs->get_ddc_pin(gpio); + service->factory.funcs->define_ddc_registers(*pin, en); break; case GPIO_ID_DDC_CLOCK: - pin = service->factory.funcs->create_ddc_clock( - service->ctx, id, en); - service->factory.funcs->define_ddc_registers(pin, en); + *pin = service->factory.funcs->get_ddc_pin(gpio); + service->factory.funcs->define_ddc_registers(*pin, en); break; case GPIO_ID_GENERIC: - pin = service->factory.funcs->create_generic( - service->ctx, id, en); + *pin = service->factory.funcs->get_generic_pin(gpio); + service->factory.funcs->define_generic_registers(*pin, en); break; case GPIO_ID_HPD: - pin = service->factory.funcs->create_hpd( - service->ctx, id, en); - service->factory.funcs->define_hpd_registers(pin, en); + *pin = service->factory.funcs->get_hpd_pin(gpio); + service->factory.funcs->define_hpd_registers(*pin, en); break; + + //TODO: gsl and sync support? create_sync and create_gsl are NULL case GPIO_ID_SYNC: - pin = service->factory.funcs->create_sync( - service->ctx, id, en); - break; case GPIO_ID_GSL: - pin = service->factory.funcs->create_gsl( - service->ctx, id, en); break; default: ASSERT_CRITICAL(false); return GPIO_RESULT_NON_SPECIFIC_ERROR; } - if (!pin) { + if (!*pin) { ASSERT_CRITICAL(false); return GPIO_RESULT_NON_SPECIFIC_ERROR; } - if (!pin->funcs->open(pin, mode)) { + if (!(*pin)->funcs->open(*pin, mode)) { ASSERT_CRITICAL(false); - dal_gpio_service_close(service, &pin); + dal_gpio_service_close(service, pin); return GPIO_RESULT_OPEN_FAILED; } set_pin_busy(service, id, en); - *ptr = pin; return GPIO_RESULT_OK; } @@ -308,11 +370,10 @@ void dal_gpio_service_close( pin->funcs->close(pin); - pin->funcs->destroy(ptr); + *ptr = NULL; } } - enum dc_irq_source dal_irq_get_source( const struct gpio *irq) { diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h index 0c678af75331..b9775a131ecd 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h @@ -42,11 +42,7 @@ struct gpio_service { }; enum gpio_result dal_gpio_service_open( - struct gpio_service *service, - enum gpio_id id, - uint32_t en, - enum gpio_mode mode, - struct hw_gpio_pin **ptr); + struct gpio *gpio); void dal_gpio_service_close( struct gpio_service *service, 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 408857d19c84..1c12961f6472 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c @@ -28,6 +28,7 @@ #include "dm_services.h" +#include "include/gpio_interface.h" #include "include/gpio_types.h" #include "hw_gpio.h" #include "hw_ddc.h" @@ -45,6 +46,8 @@ #define REG(reg)\ (ddc->regs->reg) +struct gpio; + static void destruct( struct hw_ddc *pin) { @@ -227,24 +230,29 @@ static void construct( ddc->base.base.funcs = &funcs; } -struct hw_gpio_pin *dal_hw_ddc_create( +void dal_hw_ddc_init( + struct hw_ddc **hw_ddc, struct dc_context *ctx, enum gpio_id id, uint32_t en) { - struct hw_ddc *pin; - if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) { ASSERT_CRITICAL(false); - return NULL; + *hw_ddc = NULL; } - pin = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL); - if (!pin) { + *hw_ddc = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL); + if (!*hw_ddc) { ASSERT_CRITICAL(false); - return NULL; + return; } - construct(pin, id, en, ctx); - return &pin->base.base; + construct(*hw_ddc, id, en, ctx); +} + +struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio) +{ + struct hw_ddc *hw_ddc = dal_gpio_get_ddc(gpio); + + return &hw_ddc->base.base; } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h index 9690e2a885d7..cc30e65df431 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h @@ -38,9 +38,12 @@ struct hw_ddc { #define HW_DDC_FROM_BASE(hw_gpio) \ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_ddc, base) -struct hw_gpio_pin *dal_hw_ddc_create( +void dal_hw_ddc_init( + struct hw_ddc **hw_ddc, struct dc_context *ctx, enum gpio_id id, uint32_t en); +struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio); + #endif 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 78f528f92907..fa9f1d055ec8 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -51,6 +51,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/hw_factory_dcn20.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#include "dcn21/hw_factory_dcn21.h" +#endif #include "diagnostics/hw_factory_diag.h" @@ -99,6 +102,11 @@ bool dal_hw_factory_init( dal_hw_factory_dcn20_init(factory); return true; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case DCN_VERSION_2_1: + dal_hw_factory_dcn21_init(factory); + return true; +#endif default: ASSERT_CRITICAL(false); diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h index 6e4dd3521935..e15b037f3bcd 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h @@ -28,41 +28,44 @@ struct hw_gpio_pin; struct hw_hpd; +struct hw_ddc; +struct hw_generic; +struct gpio; struct hw_factory { uint32_t number_of_pins[GPIO_ID_COUNT]; const struct hw_factory_funcs { - struct hw_gpio_pin *(*create_ddc_data)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); - struct hw_gpio_pin *(*create_ddc_clock)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); - struct hw_gpio_pin *(*create_generic)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); - struct hw_gpio_pin *(*create_hpd)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); - struct hw_gpio_pin *(*create_sync)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); - struct hw_gpio_pin *(*create_gsl)( - struct dc_context *ctx, - enum gpio_id id, - uint32_t en); + void (*init_ddc_data)( + struct hw_ddc **hw_ddc, + struct dc_context *ctx, + enum gpio_id id, + uint32_t en); + void (*init_generic)( + struct hw_generic **hw_generic, + struct dc_context *ctx, + enum gpio_id id, + uint32_t en); + void (*init_hpd)( + struct hw_hpd **hw_hpd, + struct dc_context *ctx, + enum gpio_id id, + uint32_t en); + struct hw_gpio_pin *(*get_hpd_pin)( + struct gpio *gpio); + struct hw_gpio_pin *(*get_ddc_pin)( + struct gpio *gpio); + struct hw_gpio_pin *(*get_generic_pin)( + struct gpio *gpio); void (*define_hpd_registers)( struct hw_gpio_pin *pin, uint32_t en); void (*define_ddc_registers)( struct hw_gpio_pin *pin, uint32_t en); + void (*define_generic_registers)( + struct hw_gpio_pin *pin, + uint32_t en); } *funcs; }; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c new file mode 100644 index 000000000000..69b899741f6d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.c @@ -0,0 +1,138 @@ +/* + * 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/slab.h> + +#include "dm_services.h" + +#include "include/gpio_interface.h" +#include "include/gpio_types.h" +#include "hw_gpio.h" +#include "hw_generic.h" + +#include "reg_helper.h" +#include "generic_regs.h" + +#undef FN +#define FN(reg_name, field_name) \ + generic->shifts->field_name, generic->masks->field_name + +#define CTX \ + generic->base.base.ctx +#define REG(reg)\ + (generic->regs->reg) + +struct gpio; + +static void dal_hw_generic_construct( + struct hw_generic *pin, + enum gpio_id id, + uint32_t en, + struct dc_context *ctx) +{ + dal_hw_gpio_construct(&pin->base, id, en, ctx); +} + +static void dal_hw_generic_destruct( + struct hw_generic *pin) +{ + dal_hw_gpio_destruct(&pin->base); +} + +static void destroy( + struct hw_gpio_pin **ptr) +{ + struct hw_generic *generic = HW_GENERIC_FROM_BASE(*ptr); + + dal_hw_generic_destruct(generic); + + kfree(generic); + + *ptr = NULL; +} + +static enum gpio_result set_config( + struct hw_gpio_pin *ptr, + const struct gpio_config_data *config_data) +{ + struct hw_generic *generic = HW_GENERIC_FROM_BASE(ptr); + + if (!config_data) + return GPIO_RESULT_INVALID_DATA; + + REG_UPDATE_2(mux, + GENERIC_EN, config_data->config.generic_mux.enable_output_from_mux, + GENERIC_SEL, config_data->config.generic_mux.mux_select); + + return GPIO_RESULT_OK; +} + +static const struct hw_gpio_pin_funcs funcs = { + .destroy = destroy, + .open = dal_hw_gpio_open, + .get_value = dal_hw_gpio_get_value, + .set_value = dal_hw_gpio_set_value, + .set_config = set_config, + .change_mode = dal_hw_gpio_change_mode, + .close = dal_hw_gpio_close, +}; + +static void construct( + struct hw_generic *generic, + enum gpio_id id, + uint32_t en, + struct dc_context *ctx) +{ + dal_hw_generic_construct(generic, id, en, ctx); + generic->base.base.funcs = &funcs; +} + +void dal_hw_generic_init( + struct hw_generic **hw_generic, + struct dc_context *ctx, + enum gpio_id id, + uint32_t en) +{ + if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) { + ASSERT_CRITICAL(false); + *hw_generic = NULL; + } + + *hw_generic = kzalloc(sizeof(struct hw_generic), GFP_KERNEL); + if (!*hw_generic) { + ASSERT_CRITICAL(false); + return; + } + + construct(*hw_generic, id, en, ctx); +} + + +struct hw_gpio_pin *dal_hw_generic_get_pin(struct gpio *gpio) +{ + struct hw_generic *hw_generic = dal_gpio_get_generic(gpio); + + return &hw_generic->base.base; +} diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h new file mode 100644 index 000000000000..bd6ffeb5e9df --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_generic.h @@ -0,0 +1,50 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_HW_generic_H__ +#define __DAL_HW_generic_H__ + +#include "generic_regs.h" +#include "hw_gpio.h" + +struct hw_generic { + struct hw_gpio base; + const struct generic_registers *regs; + const struct generic_sh_mask *shifts; + const struct generic_sh_mask *masks; +}; + +#define HW_GENERIC_FROM_BASE(hw_gpio) \ + container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_generic, base) + +void dal_hw_generic_init( + struct hw_generic **hw_generic, + struct dc_context *ctx, + enum gpio_id id, + uint32_t en); + +struct hw_gpio_pin *dal_hw_generic_get_pin(struct gpio *gpio); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c index 5e11d748e6f3..00c9bcf660a3 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c @@ -27,6 +27,7 @@ #include "dm_services.h" +#include "include/gpio_interface.h" #include "include/gpio_types.h" #include "hw_gpio.h" #include "hw_hpd.h" @@ -43,6 +44,8 @@ #define REG(reg)\ (hpd->regs->reg) +struct gpio; + static void dal_hw_hpd_construct( struct hw_hpd *pin, enum gpio_id id, @@ -136,29 +139,29 @@ static void construct( hpd->base.base.funcs = &funcs; } -struct hw_gpio_pin *dal_hw_hpd_create( +void dal_hw_hpd_init( + struct hw_hpd **hw_hpd, struct dc_context *ctx, enum gpio_id id, uint32_t en) { - struct hw_hpd *hpd; - - if (id != GPIO_ID_HPD) { + if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) { ASSERT_CRITICAL(false); - return NULL; + *hw_hpd = NULL; } - if ((en < GPIO_HPD_MIN) || (en > GPIO_HPD_MAX)) { + *hw_hpd = kzalloc(sizeof(struct hw_hpd), GFP_KERNEL); + if (!*hw_hpd) { ASSERT_CRITICAL(false); - return NULL; + return; } - hpd = kzalloc(sizeof(struct hw_hpd), GFP_KERNEL); - if (!hpd) { - ASSERT_CRITICAL(false); - return NULL; - } + construct(*hw_hpd, id, en, ctx); +} + +struct hw_gpio_pin *dal_hw_hpd_get_pin(struct gpio *gpio) +{ + struct hw_hpd *hw_hpd = dal_gpio_get_hpd(gpio); - construct(hpd, id, en, ctx); - return &hpd->base.base; + return &hw_hpd->base.base; } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h index 4ab7a208f781..e7d8b3bb016c 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h @@ -38,9 +38,12 @@ struct hw_hpd { #define HW_HPD_FROM_BASE(hw_gpio) \ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_hpd, base) -struct hw_gpio_pin *dal_hw_hpd_create( +void dal_hw_hpd_init( + struct hw_hpd **hw_hpd, struct dc_context *ctx, enum gpio_id id, uint32_t en); +struct hw_gpio_pin *dal_hw_hpd_get_pin(struct gpio *gpio); + #endif 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 c35fe201d335..f2046f55d6a8 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -49,6 +49,9 @@ #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #include "dcn20/hw_translate_dcn20.h" #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#include "dcn21/hw_translate_dcn21.h" +#endif #include "diagnostics/hw_translate_diag.h" @@ -94,6 +97,11 @@ bool dal_hw_translate_init( dal_hw_translate_dcn20_init(translate); return true; #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + case DCN_VERSION_2_1: + dal_hw_translate_dcn21_init(translate); + return true; +#endif default: BREAK_TO_DEBUGGER(); 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 0a094d7c9380..fd39e2abe2ed 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_status.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_status.h @@ -48,6 +48,9 @@ enum dc_status { DC_NO_DSC_RESOURCE = 17, #endif DC_FAIL_UNSUPPORTED_1 = 18, + DC_FAIL_CLK_EXCEED_MAX = 21, + DC_FAIL_CLK_BELOW_MIN = 22, /*THIS IS MIN PER IP*/ + DC_FAIL_CLK_BELOW_CFG_REQUIRED = 23, /*THIS IS hard_min in PPLIB*/ 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 a148ffde8b12..f189307750ab 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -63,11 +63,6 @@ struct link_init_data { TODO: remove it when DC is complete. */ }; -enum { - FREE_ACQUIRED_RESOURCE = 0, - KEEP_ACQUIRED_RESOURCE = 1, -}; - struct dc_link *link_create(const struct link_init_data *init_params); void link_destroy(struct dc_link **link); @@ -82,7 +77,7 @@ void core_link_enable_stream( struct dc_state *state, struct pipe_ctx *pipe_ctx); -void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option); +void core_link_disable_stream(struct pipe_ctx *pipe_ctx); void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); /********** DAL Core*********************/ @@ -92,6 +87,9 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); struct resource_pool; struct dc_state; struct resource_context; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +struct clk_bw_params; +#endif struct resource_funcs { void (*destroy)(struct resource_pool **pool); @@ -147,6 +145,11 @@ struct resource_funcs { display_e2e_pipe_params_st *pipes, int pipe_cnt); #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + void (*update_bw_bounding_box)( + struct dc *dc, + struct clk_bw_params *bw_params); +#endif }; @@ -228,14 +231,12 @@ 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; @@ -299,6 +300,8 @@ struct pipe_ctx { struct pipe_ctx *top_pipe; struct pipe_ctx *bottom_pipe; + struct pipe_ctx *next_odm_pipe; + struct pipe_ctx *prev_odm_pipe; #ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct _vcs_dpi_display_dlg_regs_st dlg_regs; 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 2d95eff94239..08a4df2c61a8 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 @@ -38,6 +38,11 @@ bool dp_verify_link_cap( struct dc_link_settings *known_limit_link_setting, int *fail_count); +bool dp_verify_link_cap_with_retries( + struct dc_link *link, + struct dc_link_settings *known_limit_link_setting, + int attempts); + bool dp_validate_mode_timing( struct dc_link *link, const struct dc_crtc_timing *timing); @@ -62,10 +67,15 @@ bool is_dp_active_dongle(const struct dc_link *link); void dp_enable_mst_on_sink(struct dc_link *link, bool enable); +enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); +void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); + #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_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable); +void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable); bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx); #endif 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 36ebd5bc7863..76f9ad1b23df 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 @@ -28,6 +28,131 @@ #include "dc.h" +#define DCN_MINIMUM_DISPCLK_Khz 100000 +#define DCN_MINIMUM_DPPCLK_Khz 100000 + +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +/* Constants */ +#define DDR4_DRAM_WIDTH 64 +#define WM_A 0 +#define WM_B 1 +#define WM_C 2 +#define WM_D 3 +#define WM_SET_COUNT 4 +#endif + +#define DCN_MINIMUM_DISPCLK_Khz 100000 +#define DCN_MINIMUM_DPPCLK_Khz 100000 + +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 +/* Will these bw structures be ASIC specific? */ + +#define MAX_NUM_DPM_LVL 4 +#define WM_SET_COUNT 4 + + +struct clk_limit_table_entry { + unsigned int voltage; /* milivolts withh 2 fractional bits */ + unsigned int dcfclk_mhz; + unsigned int fclk_mhz; + unsigned int memclk_mhz; + unsigned int socclk_mhz; +}; + +/* This table is contiguous */ +struct clk_limit_table { + struct clk_limit_table_entry entries[MAX_NUM_DPM_LVL]; + unsigned int num_entries; +}; + +struct wm_range_table_entry { + unsigned int wm_inst; + unsigned int wm_type; + double pstate_latency_us; + bool valid; +}; + + +struct clk_log_info { + bool enabled; + char *pBuf; + unsigned int bufSize; + unsigned int *sum_chars_printed; +}; + +struct clk_state_registers_and_bypass { + uint32_t dcfclk; + uint32_t dcf_deep_sleep_divider; + uint32_t dcf_deep_sleep_allow; + uint32_t dprefclk; + uint32_t dispclk; + uint32_t dppclk; + + uint32_t dppclk_bypass; + uint32_t dcfclk_bypass; + uint32_t dprefclk_bypass; + uint32_t dispclk_bypass; +}; + +struct rv1_clk_internal { + uint32_t CLK0_CLK8_CURRENT_CNT; //dcfclk + uint32_t CLK0_CLK8_DS_CNTL; //dcf_deep_sleep_divider + uint32_t CLK0_CLK8_ALLOW_DS; //dcf_deep_sleep_allow + uint32_t CLK0_CLK10_CURRENT_CNT; //dprefclk + uint32_t CLK0_CLK11_CURRENT_CNT; //dispclk + + uint32_t CLK0_CLK8_BYPASS_CNTL; //dcfclk bypass + uint32_t CLK0_CLK10_BYPASS_CNTL; //dprefclk bypass + uint32_t CLK0_CLK11_BYPASS_CNTL; //dispclk bypass +}; + +struct rn_clk_internal { + uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk + uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk + uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk + uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk + uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider + uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow + + uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass + uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass + uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass + uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass + +}; + +/* For dtn logging and debugging */ +struct clk_state_registers { + uint32_t CLK0_CLK8_CURRENT_CNT; //dcfclk + uint32_t CLK0_CLK8_DS_CNTL; //dcf_deep_sleep_divider + uint32_t CLK0_CLK8_ALLOW_DS; //dcf_deep_sleep_allow + uint32_t CLK0_CLK10_CURRENT_CNT; //dprefclk + uint32_t CLK0_CLK11_CURRENT_CNT; //dispclk +}; + +/* TODO: combine this with the above */ +struct clk_bypass { + uint32_t dcfclk_bypass; + uint32_t dispclk_pypass; + uint32_t dprefclk_bypass; +}; +/* + * This table is not contiguous, can have holes, each + * entry correspond to one set of WM. For example if + * we have 2 DPM and LPDDR, we will WM set A, B and + * D occupied, C will be emptry. + */ +struct wm_table { + struct wm_range_table_entry entries[WM_SET_COUNT]; +}; + +struct clk_bw_params { + unsigned int vram_type; + unsigned int num_channels; + struct clk_limit_table clk_table; + struct wm_table wm_table; +}; +#endif /* Public interfaces */ struct clk_states { @@ -51,6 +176,10 @@ struct clk_mgr_funcs { void (*init_clocks)(struct clk_mgr *clk_mgr); void (*enable_pme_wa) (struct clk_mgr *clk_mgr); + void (*get_clock)(struct clk_mgr *clk_mgr, + struct dc_state *context, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); }; struct clk_mgr { @@ -58,6 +187,9 @@ struct clk_mgr { struct clk_mgr_funcs *funcs; struct dc_clocks clks; int dprefclk_khz; // Used by program pixel clock in clock source funcs, need to figureout where this goes +#ifdef CONFIG_DRM_AMD_DC_DCN2_1 + struct clk_bw_params *bw_params; +#endif }; /* forward declarations */ 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 0835ac041acf..7dd46eb96d67 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 @@ -64,6 +64,8 @@ enum dentist_divider_range { *************************************************************************************** */ +/* Macros */ + #define TO_CLK_MGR_INTERNAL(clk_mgr)\ container_of(clk_mgr, struct clk_mgr_internal, base) @@ -189,6 +191,7 @@ struct state_dependent_clocks { struct clk_mgr_internal { struct clk_mgr base; + int smu_ver; struct pp_smu_funcs *pp_smu; struct clk_mgr_internal_funcs *funcs; @@ -213,6 +216,8 @@ struct clk_mgr_internal { bool dfs_bypass_enabled; /* True if the DFS-bypass feature is enabled and active. */ bool dfs_bypass_active; + + uint32_t dfs_ref_freq_khz; /* * Cache the display clock returned by VBIOS if DFS-bypass is enabled. * This is basically "Crystal Frequency In KHz" (XTALIN) frequency @@ -276,8 +281,14 @@ static inline bool should_set_clock(bool safe_to_lower, int calc_clk, int cur_cl 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; + if (cur_support != calc_support) { + if (calc_support == true && safe_to_lower) + return true; + else if (calc_support == false && !safe_to_lower) + return true; + } + + return false; } int clk_mgr_helper_get_active_display_cnt( diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 05ee5295d2c1..d8e744f366e5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -38,7 +38,8 @@ struct dccg { struct dccg_funcs { void (*update_dpp_dto)(struct dccg *dccg, int dpp_inst, - int req_dppclk); + int req_dppclk, + bool reduce_divider_only); void (*get_dccg_ref_freq)(struct dccg *dccg, unsigned int xtalin_freq_inKhz, unsigned int *dccg_ref_freq_inKhz); 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 9502478c4a1b..a6297219d7fc 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h @@ -80,6 +80,8 @@ struct dcn_hubbub_phys_addr_config { uint64_t page_table_end_addr; uint64_t page_table_base_addr; } gart_config; + + uint64_t page_table_default_page_addr; }; struct dcn_hubbub_virt_addr_config { @@ -141,6 +143,10 @@ struct hubbub_funcs { struct dcn_watermark_set *watermarks, unsigned int refclk_mhz, bool safe_to_lower); + + bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub); + void (*allow_self_refresh_control)(struct hubbub *hubbub, bool allow); + }; struct hubbub { 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 60c671fcf186..474c7194a9f8 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h @@ -42,6 +42,7 @@ struct dpp { #if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pwl_params shaper_params; + bool cm_bypass_mode; #endif }; @@ -200,7 +201,7 @@ struct dpp_funcs { void (*set_cursor_attributes)( struct dpp *dpp_base, - enum dc_cursor_color_format color_format); + struct dc_cursor_attributes *cursor_attributes); void (*set_cursor_position)( struct dpp *dpp_base, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h index c905d020b59e..1ddb1c6fa149 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h @@ -92,7 +92,9 @@ struct dsc_funcs { 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); + struct dsc_optc_config *dsc_optc_cfg); + bool (*dsc_get_packed_pps)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_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); }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h index a3409294ae0c..ff1a07b35c85 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h @@ -45,22 +45,10 @@ 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) diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h b/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h index 90d0148430fb..5253dc8b15f8 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h @@ -28,12 +28,22 @@ #include "gpio_types.h" + +union gpio_hw_container { + struct hw_ddc *ddc; + struct hw_generic *generic; + struct hw_hpd *hpd; +}; + struct gpio { struct gpio_service *service; struct hw_gpio_pin *pin; enum gpio_id id; uint32_t en; + + union gpio_hw_container hw_container; enum gpio_mode mode; + /* when GPIO comes from VBIOS, it has defined output state */ enum gpio_pin_output_state output_state; }; 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 51bff8717cc9..809b62b51a43 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -47,6 +47,11 @@ enum cursor_lines_per_chunk { CURSOR_LINE_PER_CHUNK_16 }; +enum hubp_ind_block_size { + hubp_ind_block_unconstrained = 0, + hubp_ind_block_64b, +}; + struct hubp { const struct hubp_funcs *funcs; struct dc_context *ctx; @@ -74,7 +79,8 @@ struct hubp_funcs { struct _vcs_dpi_display_ttu_regs_st *ttu_regs); void (*dcc_control)(struct hubp *hubp, bool enable, - bool independent_64b_blks); + enum hubp_ind_block_size blk_size); + void (*mem_program_viewport)( struct hubp *hubp, const struct rect *viewport, @@ -103,7 +109,7 @@ struct hubp_funcs { struct hubp *hubp, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror, @@ -111,9 +117,6 @@ struct hubp_funcs { bool (*hubp_is_flip_pending)(struct hubp *hubp); - void (*hubp_update_dchub)(struct hubp *hubp, - struct dchub_init_data *dh_data); - void (*set_blank)(struct hubp *hubp, bool blank); void (*set_hubp_blank_en)(struct hubp *hubp, bool blank); 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 e5e8640a9ef3..abb4e4237fb6 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 @@ -183,6 +183,9 @@ struct link_encoder_funcs { bool (*fec_is_active)(struct link_encoder *enc); #endif + bool (*is_in_alt_mode) (struct link_encoder *enc); + enum signal_type (*get_dig_mode)( + struct link_encoder *enc); }; #endif /* LINK_ENCODER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h index da89c2edb07c..e8668388581b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h @@ -40,6 +40,10 @@ struct cstate_pstate_watermarks_st { struct dcn_watermarks { uint32_t pte_meta_urgent_ns; uint32_t urgent_ns; +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + uint32_t frac_urg_bw_nom; + uint32_t frac_urg_bw_flip; +#endif struct cstate_pstate_watermarks_st cstate_pstate; }; @@ -149,7 +153,7 @@ struct mem_input_funcs { struct mem_input *mem_input, enum surface_pixel_format format, union dc_tiling_info *tiling_info, - union plane_size *plane_size, + struct plane_size *plane_size, enum dc_rotation_angle rotation, struct dc_plane_dcc_param *dcc, bool horizontal_mirror); 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 45b94e319cd4..58826be81395 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h @@ -128,6 +128,7 @@ struct mpc { struct mpcc mpcc_array[MAX_MPCC]; #if defined(CONFIG_DRM_AMD_DC_DCN2_0) struct pwl_params blender_params; + bool cm_bypass_mode; #endif }; @@ -198,6 +199,9 @@ struct mpc_funcs { * Return: void */ void (*mpc_init)(struct mpc *mpc); + void (*mpc_init_single_inst)( + struct mpc *mpc, + unsigned int mpcc_id); /* * Update the blending configuration for a specified MPCC. @@ -250,6 +254,10 @@ struct mpc_funcs { struct mpc *mpc, int mpcc_id, const struct pwl_params *params); + void (*power_on_mpc_mem_pwr)( + struct mpc *mpc, + int mpcc_id, + bool power_on); #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 5d8a7bcccc6f..957e9047381a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/opp.h @@ -316,11 +316,6 @@ struct opp_funcs { 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); 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 ed7d9588b309..fe9b7a10a1c3 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 @@ -91,7 +91,7 @@ struct encoder_unblank_param { struct dc_link_settings link_settings; struct dc_crtc_timing timing; #ifdef CONFIG_DRM_AMD_DC_DCN2_0 - bool odm; + int opp_cnt; #endif }; @@ -122,9 +122,6 @@ struct enc_state { #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, @@ -211,14 +208,25 @@ struct stream_encoder_funcs { struct stream_encoder *enc, int tg_inst); + void (*hdmi_reset_stream_attribute)( + struct stream_encoder *enc); + + unsigned int (*dig_source_otg)( + struct stream_encoder *enc); + #if defined(CONFIG_DRM_AMD_DC_DCN2_0) #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT + void (*enc_read_state)(struct stream_encoder *enc, struct enc_state *s); + 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); + uint32_t dsc_slice_width); + + void (*dp_set_dsc_pps_info_packet)(struct stream_encoder *enc, + bool enable, + uint8_t *dsc_packed_pps); #endif void (*set_dynamic_metadata)(struct stream_encoder *enc, 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 5e93bc0e8ff9..6196cc32356e 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 @@ -59,6 +59,8 @@ struct gsl_params { struct drr_params { uint32_t vertical_total_min; uint32_t vertical_total_max; + uint32_t vertical_total_mid; + uint32_t vertical_total_mid_frame_num; bool immediate_flip; }; @@ -96,6 +98,11 @@ enum crc_selection { INTERSECT_WINDOW_NOT_A_NOT_B, }; +enum h_timing_div_mode { + H_TIMING_NO_DIV, + H_TIMING_DIV_BY2, +}; + struct crc_params { /* Regions used to calculate CRC*/ uint16_t windowa_x_start; @@ -184,10 +191,8 @@ struct timing_generator_funcs { bool (*did_triggered_reset_occur)(struct timing_generator *tg); void (*setup_global_swap_lock)(struct timing_generator *tg, const struct dcp_gsl_params *gsl_params); - void (*setup_global_lock)(struct timing_generator *tg); 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) @@ -267,9 +272,9 @@ struct timing_generator_funcs { 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_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); + void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing); void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params); void (*set_gsl_source_select)(struct timing_generator *optc, int group_idx, 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 4d56d48a3179..3a938cd414ea 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -48,6 +48,7 @@ struct dce_hwseq_wa { bool DEGVIDCN10_253; bool false_optc_underflow; bool DEGVIDCN10_254; + bool DEGVIDCN21; }; struct hwseq_wa_state { @@ -78,6 +79,8 @@ struct stream_resource; struct dc_phy_addr_space_config; struct dc_virtual_addr_space_config; #endif +struct hubp; +struct dpp; struct hw_sequencer_funcs { @@ -194,8 +197,7 @@ struct hw_sequencer_funcs { void (*enable_stream)(struct pipe_ctx *pipe_ctx); - void (*disable_stream)(struct pipe_ctx *pipe_ctx, - int option); + void (*disable_stream)(struct pipe_ctx *pipe_ctx); void (*unblank_stream)(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); @@ -204,7 +206,7 @@ struct hw_sequencer_funcs { void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx); - void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx, int option); + void (*disable_audio_stream)(struct pipe_ctx *pipe_ctx); void (*pipe_control_lock)( struct dc *dc, @@ -231,11 +233,13 @@ struct hw_sequencer_funcs { bool (*update_bandwidth)( struct dc *dc, struct dc_state *context); + void (*program_dmdata_engine)(struct pipe_ctx *pipe_ctx); 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); + unsigned int vmin, unsigned int vmax, + unsigned int vmid, unsigned int vmid_frame_number); void (*get_position)(struct pipe_ctx **pipe_ctx, int num_pipes, struct crtc_position *position); @@ -279,6 +283,36 @@ struct hw_sequencer_funcs { void (*setup_vupdate_interrupt)(struct pipe_ctx *pipe_ctx); bool (*did_underflow_occur)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*init_blank)(struct dc *dc, struct timing_generator *tg); + void (*disable_vga)(struct dce_hwseq *hws); + void (*bios_golden_init)(struct dc *dc); + void (*plane_atomic_power_down)(struct dc *dc, + struct dpp *dpp, + struct hubp *hubp); + + void (*plane_atomic_disable)( + struct dc *dc, struct pipe_ctx *pipe_ctx); + + void (*enable_power_gating_plane)( + struct dce_hwseq *hws, + bool enable); + + void (*dpp_pg_control)( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on); + + void (*hubp_pg_control)( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on); + + void (*dsc_pg_control)( + struct dce_hwseq *hws, + unsigned int dsc_inst, + bool power_on); + + #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)( @@ -294,6 +328,15 @@ struct hw_sequencer_funcs { void (*disable_writeback)(struct dc *dc, unsigned int dwb_pipe_inst); #endif + enum dc_status (*set_clock)(struct dc *dc, + enum dc_clock_type clock_type, + uint32_t clk_khz, + uint32_t stepping); + + void (*get_clock)(struct dc *dc, + enum dc_clock_type clock_type, + struct dc_clock_config *clock_cfg); + }; void color_space_to_black_color( diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h index 30be7bb4a01a..4eff5d38a2f9 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h @@ -60,7 +60,7 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal); bool dp_set_hw_training_pattern( struct dc_link *link, - enum hw_dp_training_pattern pattern); + enum dc_dp_training_pattern pattern); void dp_set_hw_lane_settings( struct dc_link *link, @@ -72,8 +72,6 @@ void dp_set_hw_test_pattern( uint8_t *custom_pattern, uint32_t custom_pattern_size); -enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); - void dp_retrain_link_dp_test(struct dc_link *link, struct dc_link_settings *link_setting, bool skip_video_pattern); diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 47f81072d7e9..1cc1c8ce633b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -179,7 +179,4 @@ void update_audio_usage( unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format); -struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx); -bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx); - #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index ad87c2f093e2..ea75420fc876 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -77,3 +77,13 @@ AMD_DAL_IRQ_DCN2 = $(addprefix $(AMDDALPATH)/dc/irq/dcn20/,$(IRQ_DCN2)) AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN2) endif +############################################################################### +# DCN 21 +############################################################################### +ifdef CONFIG_DRM_AMD_DC_DCN2_1 +IRQ_DCN21 = irq_service_dcn21.o + +AMD_DAL_IRQ_DCN21= $(addprefix $(AMDDALPATH)/dc/irq/dcn21/,$(IRQ_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN21) +endif 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 index 3cc0f2a1f77c..5db29bf582d3 100644 --- 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 @@ -167,6 +167,11 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { .ack = NULL }; +static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = { + .set = NULL, + .ack = NULL +}; + #undef BASE_INNER #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg @@ -221,12 +226,15 @@ static const struct irq_source_info_funcs vblank_irq_info_funcs = { .funcs = &pflip_irq_info_funcs\ } -#define vupdate_int_entry(reg_num)\ +/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic + * of DCE's DC_IRQ_SOURCE_VUPDATEx. + */ +#define vupdate_no_lock_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\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\ + OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\ + .funcs = &vupdate_no_lock_irq_info_funcs\ } #define vblank_int_entry(reg_num)\ @@ -333,12 +341,12 @@ irq_source_info_dcn20[DAL_IRQ_SOURCES_NUMBER] = { 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), + vupdate_no_lock_int_entry(0), + vupdate_no_lock_int_entry(1), + vupdate_no_lock_int_entry(2), + vupdate_no_lock_int_entry(3), + vupdate_no_lock_int_entry(4), + vupdate_no_lock_int_entry(5), vblank_int_entry(0), vblank_int_entry(1), vblank_int_entry(2), diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c new file mode 100644 index 000000000000..cbe7818529bb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c @@ -0,0 +1,374 @@ +/* + * 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_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" +#include "renoir_ip_offset.h" + + +#include "irq_service_dcn21.h" + +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" + +enum dc_irq_source to_dal_irq_source_dcn21( + 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: + break; + } + 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) DMU_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_dcn21[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_rx_int_entry(0), + hpd_rx_int_entry(1), + hpd_rx_int_entry(2), + hpd_rx_int_entry(3), + hpd_rx_int_entry(4), + 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_dcn21 = { + .to_dal_irq_source = to_dal_irq_source_dcn21 +}; + +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_dcn21; + irq_service->funcs = &irq_service_funcs_dcn21; +} + +struct irq_service *dal_irq_service_dcn21_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/dcn21/irq_service_dcn21.h b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.h new file mode 100644 index 000000000000..da2bd0e93d7a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.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_DCN21_H__ +#define __DAL_IRQ_SERVICE_DCN21_H__ + +#include "../irq_service.h" + +struct irq_service *dal_irq_service_dcn21_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 c9a6dd878d9b..ff664bdb1482 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,6 +77,10 @@ static void virtual_audio_mute_control( struct stream_encoder *enc, bool mute) {} +static void virtual_stream_encoder_reset_hdmi_stream_attribute( + struct stream_encoder *enc) +{} + #ifdef CONFIG_DRM_AMD_DC_DCN2_0 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT static void virtual_enc_dp_set_odm_combine( @@ -116,6 +120,7 @@ static const struct stream_encoder_funcs virtual_str_enc_funcs = { .audio_mute_control = virtual_audio_mute_control, .set_avmute = virtual_stream_encoder_set_avmute, + .hdmi_reset_stream_attribute = virtual_stream_encoder_reset_hdmi_stream_attribute, }; bool virtual_stream_encoder_construct( diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index 6364fbc24cfe..66a54da0641c 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -38,8 +38,8 @@ struct audio_crtc_info { uint32_t h_active; uint32_t v_active; uint32_t pixel_repetition; - uint32_t requested_pixel_clock; /* in KHz */ - uint32_t calculated_pixel_clock; /* in KHz */ + uint32_t requested_pixel_clock_100Hz; /* in 100Hz */ + uint32_t calculated_pixel_clock_100Hz; /* in 100Hz */ uint32_t refresh_rate; enum dc_color_depth color_depth; bool interlaced; 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 887e6a8597c4..1f16892f0add 100644 --- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h +++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h @@ -151,6 +151,21 @@ #define FAMILY_NV 143 /* DCN 2*/ +enum { + NV_NAVI10_P_A0 = 1, + NV_NAVI12_P_A0 = 10, + NV_NAVI14_M_A0 = 20, + NV_UNKNOWN = 0xFF +}; + +#define ASICREV_IS_NAVI10_P(eChipRev) (eChipRev < NV_NAVI12_P_A0) +#define ASICREV_IS_NAVI12_P(eChipRev) ((eChipRev >= NV_NAVI12_P_A0) && (eChipRev < NV_NAVI14_M_A0)) +#define ASICREV_IS_NAVI14_M(eChipRev) ((eChipRev >= NV_NAVI14_M_A0) && (eChipRev < NV_UNKNOWN)) +#endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) +#define RENOIR_A0 0x91 +#define DEVICE_ID_RENOIR_1636 0x1636 // Renoir +#define ASICREV_IS_RENOIR(eChipRev) ((eChipRev >= RENOIR_A0) && (eChipRev < 0xFF)) #endif /* diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h index 1e3ce4d847ae..fcc42372b6cf 100644 --- a/drivers/gpu/drm/amd/display/include/dal_types.h +++ b/drivers/gpu/drm/amd/display/include/dal_types.h @@ -49,6 +49,9 @@ enum dce_version { #if defined(CONFIG_DRM_AMD_DC_DCN2_0) DCN_VERSION_2_0, #endif +#if defined(CONFIG_DRM_AMD_DC_DCN2_1) + DCN_VERSION_2_1, +#endif DCN_VERSION_MAX }; diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index d968956a10cd..18961707db23 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -25,10 +25,12 @@ #ifndef __DAL_DDC_SERVICE_TYPES_H__ #define __DAL_DDC_SERVICE_TYPES_H__ -#define DP_BRANCH_DEVICE_ID_1 0x0010FA -#define DP_BRANCH_DEVICE_ID_2 0x0022B9 -#define DP_BRANCH_DEVICE_ID_3 0x00001A -#define DP_BRANCH_DEVICE_ID_4 0x0080e1 +/* 0010FA dongles (ST Micro) external converter chip id */ +#define DP_BRANCH_DEVICE_ID_0010FA 0x0010FA +/* 0022B9 external converter chip id */ +#define DP_BRANCH_DEVICE_ID_0022B9 0x0022B9 +#define DP_BRANCH_DEVICE_ID_00001A 0x00001A +#define DP_BRANCH_DEVICE_ID_0080E1 0x0080e1 enum ddc_result { DDC_RESULT_UNKNOWN = 0, diff --git a/drivers/gpu/drm/amd/display/include/gpio_interface.h b/drivers/gpu/drm/amd/display/include/gpio_interface.h index 7de64195dc33..5e888a093c16 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_interface.h @@ -93,8 +93,17 @@ enum sync_source dal_gpio_get_sync_source( enum gpio_pin_output_state dal_gpio_get_output_state( const struct gpio *gpio); +struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio); + +struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio); + +struct hw_generic *dal_gpio_get_generic(struct gpio *gpio); + /* Close the handle */ void dal_gpio_close( struct gpio *gpio); + + + #endif diff --git a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h index f40259bade40..9c55d247227e 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_service_interface.h +++ b/drivers/gpu/drm/amd/display/include/gpio_service_interface.h @@ -51,13 +51,29 @@ struct gpio *dal_gpio_service_create_irq( uint32_t offset, uint32_t mask); +struct gpio *dal_gpio_service_create_generic_mux( + struct gpio_service *service, + uint32_t offset, + uint32_t mask); + +void dal_gpio_destroy_generic_mux( + struct gpio **mux); + +enum gpio_result dal_mux_setup_config( + struct gpio *mux, + struct gpio_generic_mux_config *config); + +struct gpio_pin_info dal_gpio_get_generic_pin_info( + struct gpio_service *service, + enum gpio_id id, + uint32_t en); + struct ddc *dal_gpio_create_ddc( struct gpio_service *service, uint32_t offset, uint32_t mask, struct gpio_ddc_hw_info *info); - void dal_gpio_destroy_ddc( struct ddc **ddc); diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h index 80f0d93cfd94..876b0b3e1a9c 100644 --- a/drivers/gpu/drm/amd/display/include/link_service_types.h +++ b/drivers/gpu/drm/amd/display/include/link_service_types.h @@ -71,14 +71,17 @@ enum link_training_result { struct link_training_settings { struct dc_link_settings link_settings; struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]; - bool allow_invalid_msa_timing_param; -}; -enum hw_dp_training_pattern { - HW_DP_TRAINING_PATTERN_1 = 0, - HW_DP_TRAINING_PATTERN_2, - HW_DP_TRAINING_PATTERN_3, - HW_DP_TRAINING_PATTERN_4 + enum dc_voltage_swing *voltage_swing; + enum dc_pre_emphasis *pre_emphasis; + enum dc_post_cursor2 *post_cursor2; + + uint16_t cr_pattern_time; + uint16_t eq_pattern_time; + enum dc_dp_training_pattern pattern_for_eq; + + bool enhanced_framing; + bool allow_invalid_msa_timing_param; }; /*TODO: Move this enum test harness*/ diff --git a/drivers/gpu/drm/amd/display/include/logger_interface.h b/drivers/gpu/drm/amd/display/include/logger_interface.h index a0b68c266dab..6e008de25629 100644 --- a/drivers/gpu/drm/amd/display/include/logger_interface.h +++ b/drivers/gpu/drm/amd/display/include/logger_interface.h @@ -155,4 +155,6 @@ void context_clock_trace( #define DISPLAY_STATS_END(entry) (void)(entry) +#define LOG_GAMMA_WRITE(msg, ...) + #endif /* __DAL_LOGGER_INTERFACE_H__ */ diff --git a/drivers/gpu/drm/amd/display/include/logger_types.h b/drivers/gpu/drm/amd/display/include/logger_types.h index ea8d445816b8..2b219cdb13ad 100644 --- a/drivers/gpu/drm/amd/display/include/logger_types.h +++ b/drivers/gpu/drm/amd/display/include/logger_types.h @@ -63,6 +63,9 @@ #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__) +#define DC_LOG_GAMMA(...) pr_debug("[GAMMA]:"__VA_ARGS__) +#define DC_LOG_ALL_GAMMA(...) pr_debug("[GAMMA]:"__VA_ARGS__) +#define DC_LOG_ALL_TF_CHANNELS(...) pr_debug("[GAMMA]:"__VA_ARGS__) #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT #define DC_LOG_DSC(...) DRM_DEBUG_KMS(__VA_ARGS__) #endif @@ -117,6 +120,10 @@ enum dc_log_type { LOG_DSC, #endif LOG_DWB, + LOG_GAMMA_DEBUG, + LOG_MAX_HW_POINTS, + LOG_ALL_TF_CHANNELS, + LOG_SAMPLE_1DLUT, 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 88898935a5e6..2d8f14b69117 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.c +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.c @@ -30,7 +30,6 @@ #include "opp.h" #include "color_gamma.h" - #define NUM_PTS_IN_REGION 16 #define NUM_REGIONS 32 #define MAX_HW_POINTS (NUM_PTS_IN_REGION*NUM_REGIONS) @@ -40,6 +39,33 @@ static struct hw_x_point coordinates_x[MAX_HW_POINTS + 2]; static struct fixed31_32 pq_table[MAX_HW_POINTS + 2]; static struct fixed31_32 de_pq_table[MAX_HW_POINTS + 2]; +// these are helpers for calculations to reduce stack usage +// do not depend on these being preserved across calls +static struct fixed31_32 scratch_1; +static struct fixed31_32 scratch_2; +static struct translate_from_linear_space_args scratch_gamma_args; + +/* Helper to optimize gamma calculation, only use in translate_from_linear, in + * particular the dc_fixpt_pow function which is very expensive + * The idea is that our regions for X points are exponential and currently they all use + * the same number of points (NUM_PTS_IN_REGION) and in each region every point + * is exactly 2x the one at the same index in the previous region. In other words + * X[i] = 2 * X[i-NUM_PTS_IN_REGION] for i>=16 + * The other fact is that (2x)^gamma = 2^gamma * x^gamma + * So we compute and save x^gamma for the first 16 regions, and for every next region + * just multiply with 2^gamma which can be computed once, and save the result so we + * recursively compute all the values. + */ +static struct fixed31_32 pow_buffer[NUM_PTS_IN_REGION]; +static struct fixed31_32 gamma_of_2; // 2^gamma +int pow_buffer_ptr = -1; + /*sRGB 709 2.2 2.4 P3*/ +static const int32_t gamma_numerator01[] = { 31308, 180000, 0, 0, 0}; +static const int32_t gamma_numerator02[] = { 12920, 4500, 0, 0, 0}; +static const int32_t gamma_numerator03[] = { 55, 99, 0, 0, 0}; +static const int32_t gamma_numerator04[] = { 55, 99, 0, 0, 0}; +static const int32_t gamma_numerator05[] = { 2400, 2200, 2200, 2400, 2600}; + static bool pq_initialized; /* = false; */ static bool de_pq_initialized; /* = false; */ @@ -71,6 +97,18 @@ void setup_x_points_distribution(void) } } +void log_x_points_distribution(struct dal_logger *logger) +{ + int i = 0; + + if (logger != NULL) { + LOG_GAMMA_WRITE("Log X Distribution\n"); + + for (i = 0; i < MAX_HW_POINTS; i++) + LOG_GAMMA_WRITE("%llu\n", coordinates_x[i].x.value); + } +} + static void compute_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) { /* consts for PQ gamma formula. */ @@ -135,59 +173,68 @@ static void compute_de_pq(struct fixed31_32 in_x, struct fixed31_32 *out_y) } + /*de gamma, none linear to linear*/ -static void compute_hlg_oetf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +static void compute_hlg_eotf(struct fixed31_32 in_x, + struct fixed31_32 *out_y, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { struct fixed31_32 a; struct fixed31_32 b; struct fixed31_32 c; struct fixed31_32 threshold; - struct fixed31_32 reference_white_level; + struct fixed31_32 x; + struct fixed31_32 scaling_factor = + dc_fixpt_from_fraction(max_luminance_nits, sdr_white_level); a = dc_fixpt_from_fraction(17883277, 100000000); - if (is_light0_12) { - /*light 0-12*/ - b = dc_fixpt_from_fraction(28466892, 100000000); - c = dc_fixpt_from_fraction(55991073, 100000000); - threshold = dc_fixpt_one; - reference_white_level = dc_fixpt_half; + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + threshold = dc_fixpt_from_fraction(1, 2); + + if (dc_fixpt_lt(in_x, threshold)) { + x = dc_fixpt_mul(in_x, in_x); + x = dc_fixpt_div_int(x, 3); } else { - /*light 0-1*/ - b = dc_fixpt_from_fraction(2372241, 100000000); - c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); - threshold = dc_fixpt_from_fraction(1, 12); - reference_white_level = dc_fixpt_pow(dc_fixpt_from_fraction(3, 1), dc_fixpt_half); + x = dc_fixpt_sub(in_x, c); + x = dc_fixpt_div(x, a); + x = dc_fixpt_exp(x); + x = dc_fixpt_add(x, b); + x = dc_fixpt_div_int(x, 12); } - if (dc_fixpt_lt(threshold, in_x)) - *out_y = dc_fixpt_add(c, dc_fixpt_mul(a, dc_fixpt_log(dc_fixpt_sub(in_x, b)))); - else - *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_half), reference_white_level); + *out_y = dc_fixpt_mul(x, scaling_factor); + } /*re gamma, linear to none linear*/ -static void compute_hlg_eotf(struct fixed31_32 in_x, bool is_light0_12, struct fixed31_32 *out_y) +static void compute_hlg_oetf(struct fixed31_32 in_x, struct fixed31_32 *out_y, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { struct fixed31_32 a; struct fixed31_32 b; struct fixed31_32 c; - struct fixed31_32 reference_white_level; + struct fixed31_32 threshold; + struct fixed31_32 x; + struct fixed31_32 scaling_factor = + dc_fixpt_from_fraction(sdr_white_level, max_luminance_nits); a = dc_fixpt_from_fraction(17883277, 100000000); - if (is_light0_12) { - /*light 0-12*/ - b = dc_fixpt_from_fraction(28466892, 100000000); - c = dc_fixpt_from_fraction(55991073, 100000000); - reference_white_level = dc_fixpt_from_fraction(4, 1); + b = dc_fixpt_from_fraction(28466892, 100000000); + c = dc_fixpt_from_fraction(55991073, 100000000); + threshold = dc_fixpt_from_fraction(1, 12); + x = dc_fixpt_mul(in_x, scaling_factor); + + + if (dc_fixpt_lt(x, threshold)) { + x = dc_fixpt_mul(x, dc_fixpt_from_fraction(3, 1)); + *out_y = dc_fixpt_pow(x, dc_fixpt_half); } else { - /*light 0-1*/ - b = dc_fixpt_from_fraction(2372241, 100000000); - c = dc_fixpt_add(dc_fixpt_one, dc_fixpt_from_fraction(429347, 100000000)); - reference_white_level = dc_fixpt_from_fraction(1, 3); + x = dc_fixpt_mul(x, dc_fixpt_from_fraction(12, 1)); + x = dc_fixpt_sub(x, b); + x = dc_fixpt_log(x); + x = dc_fixpt_mul(a, x); + *out_y = dc_fixpt_add(x, c); } - if (dc_fixpt_lt(dc_fixpt_half, in_x)) - *out_y = dc_fixpt_add(dc_fixpt_exp(dc_fixpt_div(dc_fixpt_sub(in_x, c), a)), b); - else - *out_y = dc_fixpt_mul(dc_fixpt_pow(in_x, dc_fixpt_from_fraction(2, 1)), reference_white_level); } @@ -243,93 +290,101 @@ struct dividers { struct fixed31_32 divider3; }; -enum gamma_type_index { - gamma_type_index_2_4, - gamma_type_index_2_2, - gamma_type_index_2_2_flat -}; -static void build_coefficients(struct gamma_coefficients *coefficients, enum gamma_type_index type) +static bool build_coefficients(struct gamma_coefficients *coefficients, enum dc_transfer_func_predefined type) { - static const int32_t numerator01[] = { 31308, 180000, 0}; - static const int32_t numerator02[] = { 12920, 4500, 0}; - static const int32_t numerator03[] = { 55, 99, 0}; - static const int32_t numerator04[] = { 55, 99, 0}; - static const int32_t numerator05[] = { 2400, 2200, 2200}; uint32_t i = 0; uint32_t index = 0; + bool ret = true; - if (type == gamma_type_index_2_2) + if (type == TRANSFER_FUNCTION_SRGB) + index = 0; + else if (type == TRANSFER_FUNCTION_BT709) index = 1; - else if (type == gamma_type_index_2_2_flat) + else if (type == TRANSFER_FUNCTION_GAMMA22) index = 2; + else if (type == TRANSFER_FUNCTION_GAMMA24) + index = 3; + else if (type == TRANSFER_FUNCTION_GAMMA26) + index = 4; + else { + ret = false; + goto release; + } do { coefficients->a0[i] = dc_fixpt_from_fraction( - numerator01[index], 10000000); + gamma_numerator01[index], 10000000); coefficients->a1[i] = dc_fixpt_from_fraction( - numerator02[index], 1000); + gamma_numerator02[index], 1000); coefficients->a2[i] = dc_fixpt_from_fraction( - numerator03[index], 1000); + gamma_numerator03[index], 1000); coefficients->a3[i] = dc_fixpt_from_fraction( - numerator04[index], 1000); + gamma_numerator04[index], 1000); coefficients->user_gamma[i] = dc_fixpt_from_fraction( - numerator05[index], 1000); + gamma_numerator05[index], 1000); ++i; } while (i != ARRAY_SIZE(coefficients->a0)); +release: + return ret; } static struct fixed31_32 translate_from_linear_space( - struct fixed31_32 arg, - struct fixed31_32 a0, - struct fixed31_32 a1, - struct fixed31_32 a2, - struct fixed31_32 a3, - struct fixed31_32 gamma) + struct translate_from_linear_space_args *args) { const struct fixed31_32 one = dc_fixpt_from_int(1); - if (dc_fixpt_lt(one, arg)) + if (dc_fixpt_le(one, args->arg)) return one; - if (dc_fixpt_le(arg, dc_fixpt_neg(a0))) - return dc_fixpt_sub( - a2, - dc_fixpt_mul( - dc_fixpt_add( - one, - a3), - dc_fixpt_pow( - dc_fixpt_neg(arg), - dc_fixpt_recip(gamma)))); - else if (dc_fixpt_le(a0, arg)) - return dc_fixpt_sub( - dc_fixpt_mul( - dc_fixpt_add( - one, - a3), - dc_fixpt_pow( - arg, - dc_fixpt_recip(gamma))), - a2); + if (dc_fixpt_le(args->arg, dc_fixpt_neg(args->a0))) { + scratch_1 = dc_fixpt_add(one, args->a3); + scratch_2 = dc_fixpt_pow( + dc_fixpt_neg(args->arg), + dc_fixpt_recip(args->gamma)); + scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); + scratch_1 = dc_fixpt_sub(args->a2, scratch_1); + + return scratch_1; + } else if (dc_fixpt_le(args->a0, args->arg)) { + if (pow_buffer_ptr == 0) { + gamma_of_2 = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_recip(args->gamma)); + } + scratch_1 = dc_fixpt_add(one, args->a3); + if (pow_buffer_ptr < 16) + scratch_2 = dc_fixpt_pow(args->arg, + dc_fixpt_recip(args->gamma)); + else + scratch_2 = dc_fixpt_mul(gamma_of_2, + pow_buffer[pow_buffer_ptr%16]); + + pow_buffer[pow_buffer_ptr%16] = scratch_2; + pow_buffer_ptr++; + + scratch_1 = dc_fixpt_mul(scratch_1, scratch_2); + scratch_1 = dc_fixpt_sub(scratch_1, args->a2); + + return scratch_1; + } else - return dc_fixpt_mul( - arg, - a1); + return dc_fixpt_mul(args->arg, args->a1); } static struct fixed31_32 calculate_gamma22(struct fixed31_32 arg) { struct fixed31_32 gamma = dc_fixpt_from_fraction(22, 10); - return translate_from_linear_space(arg, - dc_fixpt_zero, - dc_fixpt_zero, - dc_fixpt_zero, - dc_fixpt_zero, - gamma); + scratch_gamma_args.arg = arg; + scratch_gamma_args.a0 = dc_fixpt_zero; + scratch_gamma_args.a1 = dc_fixpt_zero; + scratch_gamma_args.a2 = dc_fixpt_zero; + scratch_gamma_args.a3 = dc_fixpt_zero; + scratch_gamma_args.gamma = gamma; + + return translate_from_linear_space(&scratch_gamma_args); } static struct fixed31_32 translate_to_linear_space( @@ -365,18 +420,19 @@ static struct fixed31_32 translate_to_linear_space( return linear; } -static inline struct fixed31_32 translate_from_linear_space_ex( +static struct fixed31_32 translate_from_linear_space_ex( struct fixed31_32 arg, struct gamma_coefficients *coeff, uint32_t color_index) { - return translate_from_linear_space( - arg, - coeff->a0[color_index], - coeff->a1[color_index], - coeff->a2[color_index], - coeff->a3[color_index], - coeff->user_gamma[color_index]); + scratch_gamma_args.arg = arg; + scratch_gamma_args.a0 = coeff->a0[color_index]; + scratch_gamma_args.a1 = coeff->a1[color_index]; + scratch_gamma_args.a2 = coeff->a2[color_index]; + scratch_gamma_args.a3 = coeff->a3[color_index]; + scratch_gamma_args.gamma = coeff->user_gamma[color_index]; + + return translate_from_linear_space(&scratch_gamma_args); } @@ -709,30 +765,42 @@ static void build_de_pq(struct pwl_float_data_ex *de_pq, } } -static void build_regamma(struct pwl_float_data_ex *rgb_regamma, +static bool build_regamma(struct pwl_float_data_ex *rgb_regamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, enum gamma_type_index type) + const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) { uint32_t i; + bool ret = false; - struct gamma_coefficients coeff; + struct gamma_coefficients *coeff; struct pwl_float_data_ex *rgb = rgb_regamma; const struct hw_x_point *coord_x = coordinate_x; - build_coefficients(&coeff, type); + coeff = kvzalloc(sizeof(*coeff), GFP_KERNEL); + if (!coeff) + goto release; - i = 0; + if (!build_coefficients(coeff, type)) + goto release; - while (i != hw_points_num + 1) { + memset(pow_buffer, 0, NUM_PTS_IN_REGION * sizeof(struct fixed31_32)); + pow_buffer_ptr = 0; // see variable definition for more info + i = 0; + while (i <= hw_points_num) { /*TODO use y vs r,g,b*/ rgb->r = translate_from_linear_space_ex( - coord_x->x, &coeff, 0); + coord_x->x, coeff, 0); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; ++rgb; ++i; } + pow_buffer_ptr = -1; // reset back to no optimize + ret = true; +release: + kfree(coeff); + return ret; } static void hermite_spline_eetf(struct fixed31_32 input_x, @@ -862,6 +930,8 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, else max_content = max_display; + if (!use_eetf) + pow_buffer_ptr = 0; // see var definition for more info rgb += 32; // first 32 points have problems with fixed point, too small coord_x += 32; for (i = 32; i <= hw_points_num; i++) { @@ -900,19 +970,23 @@ static bool build_freesync_hdr(struct pwl_float_data_ex *rgb_regamma, ++coord_x; ++rgb; } + pow_buffer_ptr = -1; return true; } -static void build_degamma(struct pwl_float_data_ex *curve, +static bool build_degamma(struct pwl_float_data_ex *curve, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, enum gamma_type_index type) + const struct hw_x_point *coordinate_x, enum dc_transfer_func_predefined type) { uint32_t i; struct gamma_coefficients coeff; uint32_t begin_index, end_index; + bool ret = false; + + if (!build_coefficients(&coeff, type)) + goto release; - build_coefficients(&coeff, type); i = 0; /* X points is 2^-25 to 2^7 @@ -941,11 +1015,19 @@ static void build_degamma(struct pwl_float_data_ex *curve, curve[i].b = dc_fixpt_one; i++; } + ret = true; +release: + return ret; } + + + + static void build_hlg_degamma(struct pwl_float_data_ex *degamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, bool is_light0_12) + const struct hw_x_point *coordinate_x, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { uint32_t i; @@ -953,9 +1035,9 @@ static void build_hlg_degamma(struct pwl_float_data_ex *degamma, const struct hw_x_point *coord_x = coordinate_x; i = 0; - + //check when i == 434 while (i != hw_points_num + 1) { - compute_hlg_oetf(coord_x->x, is_light0_12, &rgb->r); + compute_hlg_eotf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; @@ -964,9 +1046,11 @@ static void build_hlg_degamma(struct pwl_float_data_ex *degamma, } } + static void build_hlg_regamma(struct pwl_float_data_ex *regamma, uint32_t hw_points_num, - const struct hw_x_point *coordinate_x, bool is_light0_12) + const struct hw_x_point *coordinate_x, + uint32_t sdr_white_level, uint32_t max_luminance_nits) { uint32_t i; @@ -975,8 +1059,9 @@ static void build_hlg_regamma(struct pwl_float_data_ex *regamma, i = 0; + //when i == 471 while (i != hw_points_num + 1) { - compute_hlg_eotf(coord_x->x, is_light0_12, &rgb->r); + compute_hlg_oetf(coord_x->x, &rgb->r, sdr_white_level, max_luminance_nits); rgb->g = rgb->r; rgb->b = rgb->r; ++coord_x; @@ -1572,14 +1657,15 @@ 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_logical_identity) || + if ((ramp->is_identity && ramp->type != GAMMA_CS_TFM_1D) || (!mapUserRamp && ramp->type == GAMMA_RGB_256)) return true; } output_tf->type = TF_TYPE_DISTRIBUTED_POINTS; - if (ramp && (mapUserRamp || ramp->type != GAMMA_RGB_256)) { + if (ramp && ramp->type != GAMMA_CS_TFM_1D && + (mapUserRamp || ramp->type != GAMMA_RGB_256)) { rgb_user = kvcalloc(ramp->num_entries + _EXTRA_POINTS, sizeof(*rgb_user), GFP_KERNEL); @@ -1634,6 +1720,12 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, MAX_HW_POINTS, coordinates_x, fs_params); + } else if (tf == TRANSFER_FUNCTION_HLG) { + build_freesync_hdr(rgb_regamma, + MAX_HW_POINTS, + coordinates_x, + fs_params); + } else { tf_pts->end_exponent = 0; tf_pts->x_point_at_y1_red = 1; @@ -1642,9 +1734,7 @@ bool mod_color_calculate_regamma_params(struct dc_transfer_func *output_tf, build_regamma(rgb_regamma, MAX_HW_POINTS, - coordinates_x, tf == TRANSFER_FUNCTION_SRGB ? gamma_type_index_2_4 : - tf == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + coordinates_x, tf); } map_regamma_hw_to_x_user(ramp, coeff, rgb_user, coordinates_x, axis_x, rgb_regamma, @@ -1845,13 +1935,19 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf, MAX_HW_POINTS, coordinates_x); else if (tf == TRANSFER_FUNCTION_SRGB || - tf == TRANSFER_FUNCTION_BT709) + tf == TRANSFER_FUNCTION_BT709 || + tf == TRANSFER_FUNCTION_GAMMA22 || + tf == TRANSFER_FUNCTION_GAMMA24 || + tf == TRANSFER_FUNCTION_GAMMA26) build_degamma(curve, MAX_HW_POINTS, coordinates_x, - tf == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : tf == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + tf); + else if (tf == TRANSFER_FUNCTION_HLG) + build_hlg_degamma(curve, + MAX_HW_POINTS, + coordinates_x, + 80, 1000); else if (tf == TRANSFER_FUNCTION_LINEAR) { // just copy coordinates_x into curve i = 0; @@ -1938,7 +2034,10 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_regamma); } else if (trans == TRANSFER_FUNCTION_SRGB || - trans == TRANSFER_FUNCTION_BT709) { + trans == TRANSFER_FUNCTION_BT709 || + trans == TRANSFER_FUNCTION_GAMMA22 || + trans == TRANSFER_FUNCTION_GAMMA24 || + trans == TRANSFER_FUNCTION_GAMMA26) { rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_regamma), GFP_KERNEL); @@ -1952,9 +2051,7 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, build_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : trans == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + trans); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; @@ -1963,18 +2060,21 @@ bool mod_color_calculate_curve(enum dc_transfer_func_predefined trans, ret = true; kvfree(rgb_regamma); - } else if (trans == TRANSFER_FUNCTION_HLG || - trans == TRANSFER_FUNCTION_HLG12) { + } else if (trans == TRANSFER_FUNCTION_HLG) { rgb_regamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_regamma), GFP_KERNEL); if (!rgb_regamma) goto rgb_regamma_alloc_fail; + points->end_exponent = 4; + points->x_point_at_y1_red = 12; + points->x_point_at_y1_green = 12; + points->x_point_at_y1_blue = 12; build_hlg_regamma(rgb_regamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_HLG12 ? true:false); + 80, 1000); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_regamma[i].r; points->green[i] = rgb_regamma[i].g; @@ -2024,8 +2124,10 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, kvfree(rgb_degamma); } else if (trans == TRANSFER_FUNCTION_SRGB || - trans == TRANSFER_FUNCTION_BT709 || - trans == TRANSFER_FUNCTION_GAMMA22) { + trans == TRANSFER_FUNCTION_BT709 || + trans == TRANSFER_FUNCTION_GAMMA22 || + trans == TRANSFER_FUNCTION_GAMMA24 || + trans == TRANSFER_FUNCTION_GAMMA26) { rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_degamma), GFP_KERNEL); @@ -2035,9 +2137,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, build_degamma(rgb_degamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_SRGB ? - gamma_type_index_2_4 : trans == TRANSFER_FUNCTION_GAMMA22 ? - gamma_type_index_2_2_flat : gamma_type_index_2_2); + trans); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; @@ -2046,8 +2146,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, ret = true; kvfree(rgb_degamma); - } else if (trans == TRANSFER_FUNCTION_HLG || - trans == TRANSFER_FUNCTION_HLG12) { + } else if (trans == TRANSFER_FUNCTION_HLG) { rgb_degamma = kvcalloc(MAX_HW_POINTS + _EXTRA_POINTS, sizeof(*rgb_degamma), GFP_KERNEL); @@ -2057,7 +2156,7 @@ bool mod_color_calculate_degamma_curve(enum dc_transfer_func_predefined trans, build_hlg_degamma(rgb_degamma, MAX_HW_POINTS, coordinates_x, - trans == TRANSFER_FUNCTION_HLG12 ? true:false); + 80, 1000); for (i = 0; i <= MAX_HW_POINTS ; i++) { points->red[i] = rgb_degamma[i].r; points->green[i] = rgb_degamma[i].g; diff --git a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h index 369953fafadf..44ddea58523a 100644 --- a/drivers/gpu/drm/amd/display/modules/color/color_gamma.h +++ b/drivers/gpu/drm/amd/display/modules/color/color_gamma.h @@ -82,7 +82,17 @@ struct freesync_hdr_tf_params { unsigned int skip_tm; // skip tm }; +struct translate_from_linear_space_args { + struct fixed31_32 arg; + struct fixed31_32 a0; + struct fixed31_32 a1; + struct fixed31_32 a2; + struct fixed31_32 a3; + struct fixed31_32 gamma; +}; + void setup_x_points_distribution(void); +void log_x_points_distribution(struct dal_logger *logger); void precompute_pq(void); void precompute_de_pq(void); diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index 7c20171a3b6d..ec70c9b12e1a 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -52,93 +52,6 @@ struct core_freesync { struct dc *dc; }; -void setFieldWithMask(unsigned char *dest, unsigned int mask, unsigned int value) -{ - unsigned int shift = 0; - - if (!mask || !dest) - return; - - while (!((mask >> shift) & 1)) - shift++; - - //reset - *dest = *dest & ~mask; - //set - //dont let value span past mask - value = value & (mask >> shift); - //insert value - *dest = *dest | (value << shift); -} - -// VTEM Byte Offset -#define VRR_VTEM_PB0 0 -#define VRR_VTEM_PB1 1 -#define VRR_VTEM_PB2 2 -#define VRR_VTEM_PB3 3 -#define VRR_VTEM_PB4 4 -#define VRR_VTEM_PB5 5 -#define VRR_VTEM_PB6 6 - -#define VRR_VTEM_MD0 7 -#define VRR_VTEM_MD1 8 -#define VRR_VTEM_MD2 9 -#define VRR_VTEM_MD3 10 - - -// VTEM Byte Masks -//PB0 -#define MASK__VRR_VTEM_PB0__RESERVED0 0x01 -#define MASK__VRR_VTEM_PB0__SYNC 0x02 -#define MASK__VRR_VTEM_PB0__VFR 0x04 -#define MASK__VRR_VTEM_PB0__AFR 0x08 -#define MASK__VRR_VTEM_PB0__DS_TYPE 0x30 - //0: Periodic pseudo-static EM Data Set - //1: Periodic dynamic EM Data Set - //2: Unique EM Data Set - //3: Reserved -#define MASK__VRR_VTEM_PB0__END 0x40 -#define MASK__VRR_VTEM_PB0__NEW 0x80 - -//PB1 -#define MASK__VRR_VTEM_PB1__RESERVED1 0xFF - -//PB2 -#define MASK__VRR_VTEM_PB2__ORGANIZATION_ID 0xFF - //0: This is a Vendor Specific EM Data Set - //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean) - //2: This EM Data Set is defined by CTA-861-G - //3: This EM Data Set is defined by VESA -//PB3 -#define MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB 0xFF -//PB4 -#define MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB 0xFF -//PB5 -#define MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF -//PB6 -#define MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF - - - -//PB7-27 (20 bytes): -//PB7 = MD0 -#define MASK__VRR_VTEM_MD0__VRR_EN 0x01 -#define MASK__VRR_VTEM_MD0__M_CONST 0x02 -#define MASK__VRR_VTEM_MD0__RESERVED2 0x0C -#define MASK__VRR_VTEM_MD0__FVA_FACTOR_M1 0xF0 - -//MD1 -#define MASK__VRR_VTEM_MD1__BASE_VFRONT 0xFF - -//MD2 -#define MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 -#define MASK__VRR_VTEM_MD2__RB 0x04 -#define MASK__VRR_VTEM_MD2__RESERVED3 0xF8 - -//MD3 -#define MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF - - #define MOD_FREESYNC_TO_CORE(mod_freesync)\ container_of(mod_freesync, struct core_freesync, public) @@ -435,6 +348,12 @@ static void apply_below_the_range(struct core_freesync *core_freesync, /* Either we've calculated the number of frames to insert, * or we need to insert min duration frames */ + if (last_render_time_in_us / frames_to_insert < + in_out_vrr->min_duration_in_us){ + frames_to_insert -= (frames_to_insert > 1) ? + 1 : 0; + } + if (frames_to_insert > 0) inserted_frame_duration_in_us = last_render_time_in_us / frames_to_insert; @@ -568,22 +487,64 @@ bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, return false; } -static void build_vrr_infopacket_header_vtem(enum signal_type signal, +static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, struct dc_info_packet *infopacket) { - // HEADER - - // HB0, HB1, HB2 indicates PacketType VTEMPacket - infopacket->hb0 = 0x7F; - infopacket->hb1 = 0xC0; - infopacket->hb2 = 0x00; //sequence_index - - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB0], MASK__VRR_VTEM_PB0__VFR, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB2], MASK__VRR_VTEM_PB2__ORGANIZATION_ID, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB3], MASK__VRR_VTEM_PB3__DATA_SET_TAG_MSB, 0); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB4], MASK__VRR_VTEM_PB4__DATA_SET_TAG_LSB, 1); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB5], MASK__VRR_VTEM_PB5__DATA_SET_LENGTH_MSB, 0); - setFieldWithMask(&infopacket->sb[VRR_VTEM_PB6], MASK__VRR_VTEM_PB6__DATA_SET_LENGTH_LSB, 4); + /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ + infopacket->sb[1] = 0x1A; + + /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ + infopacket->sb[2] = 0x00; + + /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ + infopacket->sb[3] = 0x00; + + /* PB4 = Reserved */ + + /* PB5 = Reserved */ + + /* PB6 = [Bits 7:3 = Reserved] */ + + /* PB6 = [Bit 0 = FreeSync Supported] */ + if (vrr->state != VRR_STATE_UNSUPPORTED) + infopacket->sb[6] |= 0x01; + + /* PB6 = [Bit 1 = FreeSync Enabled] */ + if (vrr->state != VRR_STATE_DISABLED && + vrr->state != VRR_STATE_UNSUPPORTED) + infopacket->sb[6] |= 0x02; + + /* PB6 = [Bit 2 = FreeSync Active] */ + if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || + vrr->state == VRR_STATE_ACTIVE_FIXED) + infopacket->sb[6] |= 0x04; + + /* PB7 = FreeSync Minimum refresh rate (Hz) */ + infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); + + /* PB8 = FreeSync Maximum refresh rate (Hz) + * Note: We should never go above the field rate of the mode timing set. + */ + infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); + + + //FreeSync HDR + infopacket->sb[9] = 0; + infopacket->sb[10] = 0; +} + +static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, + struct dc_info_packet *infopacket) +{ + if (app_tf != TRANSFER_FUNC_UNKNOWN) { + infopacket->valid = true; + + infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] + + if (app_tf == TRANSFER_FUNC_GAMMA_22) { + infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] + } + } } static void build_vrr_infopacket_header_v1(enum signal_type signal, @@ -684,105 +645,6 @@ static void build_vrr_infopacket_header_v2(enum signal_type signal, } } -static void build_vrr_vtem_infopacket_data(const struct dc_stream_state *stream, - const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - unsigned int fieldRateInHz; - - if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || - vrr->state == VRR_STATE_ACTIVE_FIXED) { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 1); - } else { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD0], MASK__VRR_VTEM_MD0__VRR_EN, 0); - } - - if (!stream->timing.vic) { - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD1], MASK__VRR_VTEM_MD1__BASE_VFRONT, - stream->timing.v_front_porch); - - - /* TODO: In dal2, we check mode flags for a reduced blanking timing. - * Need a way to relay that information to this function. - * if("ReducedBlanking") - * { - * setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__RB, 1; - * } - */ - - //TODO: DAL2 does FixPoint and rounding. Here we might need to account for that - fieldRateInHz = (stream->timing.pix_clk_100hz * 100)/ - (stream->timing.h_total * stream->timing.v_total); - - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD2], MASK__VRR_VTEM_MD2__BASE_REFRESH_RATE_98, - fieldRateInHz >> 8); - setFieldWithMask(&infopacket->sb[VRR_VTEM_MD3], MASK__VRR_VTEM_MD3__BASE_REFRESH_RATE_07, - fieldRateInHz); - - } - infopacket->valid = true; -} - -static void build_vrr_infopacket_data(const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - /* PB1 = 0x1A (24bit AMD IEEE OUI (0x00001A) - Byte 0) */ - infopacket->sb[1] = 0x1A; - - /* PB2 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 1) */ - infopacket->sb[2] = 0x00; - - /* PB3 = 0x00 (24bit AMD IEEE OUI (0x00001A) - Byte 2) */ - infopacket->sb[3] = 0x00; - - /* PB4 = Reserved */ - - /* PB5 = Reserved */ - - /* PB6 = [Bits 7:3 = Reserved] */ - - /* PB6 = [Bit 0 = FreeSync Supported] */ - if (vrr->state != VRR_STATE_UNSUPPORTED) - infopacket->sb[6] |= 0x01; - - /* PB6 = [Bit 1 = FreeSync Enabled] */ - if (vrr->state != VRR_STATE_DISABLED && - vrr->state != VRR_STATE_UNSUPPORTED) - infopacket->sb[6] |= 0x02; - - /* PB6 = [Bit 2 = FreeSync Active] */ - if (vrr->state == VRR_STATE_ACTIVE_VARIABLE || - vrr->state == VRR_STATE_ACTIVE_FIXED) - infopacket->sb[6] |= 0x04; - - /* PB7 = FreeSync Minimum refresh rate (Hz) */ - infopacket->sb[7] = (unsigned char)(vrr->min_refresh_in_uhz / 1000000); - - /* PB8 = FreeSync Maximum refresh rate (Hz) - * Note: We should never go above the field rate of the mode timing set. - */ - infopacket->sb[8] = (unsigned char)(vrr->max_refresh_in_uhz / 1000000); - - - //FreeSync HDR - infopacket->sb[9] = 0; - infopacket->sb[10] = 0; -} - -static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, - struct dc_info_packet *infopacket) -{ - if (app_tf != TRANSFER_FUNC_UNKNOWN) { - infopacket->valid = true; - - infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] - - if (app_tf == TRANSFER_FUNC_GAMMA_22) { - infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] - } - } -} - static void build_vrr_infopacket_checksum(unsigned int *payload_size, struct dc_info_packet *infopacket) { @@ -835,21 +697,6 @@ static void build_vrr_infopacket_v2(enum signal_type signal, infopacket->valid = true; } -static void build_vrr_infopacket_vtem(const struct dc_stream_state *stream, - const struct mod_vrr_params *vrr, - struct dc_info_packet *infopacket) -{ - //VTEM info packet for HdmiVrr - - memset(infopacket, 0, sizeof(struct dc_info_packet)); - - //VTEM Packet is structured differently - build_vrr_infopacket_header_vtem(stream->signal, infopacket); - build_vrr_vtem_infopacket_data(stream, vrr, infopacket); - - infopacket->valid = true; -} - void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, const struct dc_stream_state *stream, const struct mod_vrr_params *vrr, @@ -862,16 +709,13 @@ void mod_freesync_build_vrr_infopacket(struct mod_freesync *mod_freesync, * Check if Freesync is supported. Return if false. If true, * set the corresponding bit in the info packet */ - if (!vrr->supported || (!vrr->send_info_frame && packet_type != PACKET_TYPE_VTEM)) + if (!vrr->supported || (!vrr->send_info_frame)) return; switch (packet_type) { case PACKET_TYPE_FS2: build_vrr_infopacket_v2(stream->signal, vrr, app_tf, infopacket); break; - case PACKET_TYPE_VTEM: - build_vrr_infopacket_vtem(stream, vrr, infopacket); - break; case PACKET_TYPE_VRR: case PACKET_TYPE_FS1: default: @@ -887,8 +731,8 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, struct core_freesync *core_freesync = NULL; unsigned long long nominal_field_rate_in_uhz = 0; unsigned int refresh_range = 0; - unsigned int min_refresh_in_uhz = 0; - unsigned int max_refresh_in_uhz = 0; + unsigned long long min_refresh_in_uhz = 0; + unsigned long long max_refresh_in_uhz = 0; if (mod_freesync == NULL) return; @@ -915,7 +759,7 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, min_refresh_in_uhz = nominal_field_rate_in_uhz; if (!vrr_settings_require_update(core_freesync, - in_config, min_refresh_in_uhz, max_refresh_in_uhz, + in_config, (unsigned int)min_refresh_in_uhz, (unsigned int)max_refresh_in_uhz, in_out_vrr)) return; @@ -931,15 +775,15 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, return; } else { - in_out_vrr->min_refresh_in_uhz = min_refresh_in_uhz; + in_out_vrr->min_refresh_in_uhz = (unsigned int)min_refresh_in_uhz; in_out_vrr->max_duration_in_us = calc_duration_in_us_from_refresh_in_uhz( - min_refresh_in_uhz); + (unsigned int)min_refresh_in_uhz); - in_out_vrr->max_refresh_in_uhz = max_refresh_in_uhz; + in_out_vrr->max_refresh_in_uhz = (unsigned int)max_refresh_in_uhz; in_out_vrr->min_duration_in_us = calc_duration_in_us_from_refresh_in_uhz( - max_refresh_in_uhz); + (unsigned int)max_refresh_in_uhz); refresh_range = in_out_vrr->max_refresh_in_uhz - in_out_vrr->min_refresh_in_uhz; @@ -950,17 +794,18 @@ void mod_freesync_build_vrr_params(struct mod_freesync *mod_freesync, in_out_vrr->fixed.ramping_active = in_config->ramping; in_out_vrr->btr.btr_enabled = in_config->btr; + if (in_out_vrr->max_refresh_in_uhz < 2 * in_out_vrr->min_refresh_in_uhz) in_out_vrr->btr.btr_enabled = false; + in_out_vrr->btr.btr_active = false; in_out_vrr->btr.inserted_duration_in_us = 0; in_out_vrr->btr.frames_to_insert = 0; in_out_vrr->btr.frame_counter = 0; in_out_vrr->btr.mid_point_in_us = - in_out_vrr->min_duration_in_us + - (in_out_vrr->max_duration_in_us - - in_out_vrr->min_duration_in_us) / 2; + (in_out_vrr->min_duration_in_us + + in_out_vrr->max_duration_in_us) / 2; if (in_out_vrr->state == VRR_STATE_UNSUPPORTED) { in_out_vrr->adjust.v_total_min = stream->timing.v_total; diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index dcef85994c45..dc187844d10b 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -173,4 +173,6 @@ bool mod_freesync_is_valid_range(struct mod_freesync *mod_freesync, uint32_t min_refresh_request_in_uhz, uint32_t max_refresh_request_in_uhz); + + #endif diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h index 5b1c9a4c7643..d930bdecb117 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h @@ -27,10 +27,10 @@ #define MOD_INFO_PACKET_H_ #include "mod_shared.h" - //Forward Declarations struct dc_stream_state; struct dc_info_packet; +struct mod_vrr_params; void mod_build_vsc_infopacket(const struct dc_stream_state *stream, struct dc_info_packet *info_packet); diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c index bc13c552797f..d885d642ed7f 100644 --- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c @@ -27,9 +27,78 @@ #include "core_types.h" #include "dc_types.h" #include "mod_shared.h" +#include "mod_freesync.h" +#include "dc.h" #define HDMI_INFOFRAME_TYPE_VENDOR 0x81 +// VTEM Byte Offset +#define VTEM_PB0 0 +#define VTEM_PB1 1 +#define VTEM_PB2 2 +#define VTEM_PB3 3 +#define VTEM_PB4 4 +#define VTEM_PB5 5 +#define VTEM_PB6 6 + +#define VTEM_MD0 7 +#define VTEM_MD1 8 +#define VTEM_MD2 9 +#define VTEM_MD3 10 + + +// VTEM Byte Masks +//PB0 +#define MASK_VTEM_PB0__RESERVED0 0x01 +#define MASK_VTEM_PB0__SYNC 0x02 +#define MASK_VTEM_PB0__VFR 0x04 +#define MASK_VTEM_PB0__AFR 0x08 +#define MASK_VTEM_PB0__DS_TYPE 0x30 + //0: Periodic pseudo-static EM Data Set + //1: Periodic dynamic EM Data Set + //2: Unique EM Data Set + //3: Reserved +#define MASK_VTEM_PB0__END 0x40 +#define MASK_VTEM_PB0__NEW 0x80 + +//PB1 +#define MASK_VTEM_PB1__RESERVED1 0xFF + +//PB2 +#define MASK_VTEM_PB2__ORGANIZATION_ID 0xFF + //0: This is a Vendor Specific EM Data Set + //1: This EM Data Set is defined by This Specification (HDMI 2.1 r102.clean) + //2: This EM Data Set is defined by CTA-861-G + //3: This EM Data Set is defined by VESA +//PB3 +#define MASK_VTEM_PB3__DATA_SET_TAG_MSB 0xFF +//PB4 +#define MASK_VTEM_PB4__DATA_SET_TAG_LSB 0xFF +//PB5 +#define MASK_VTEM_PB5__DATA_SET_LENGTH_MSB 0xFF +//PB6 +#define MASK_VTEM_PB6__DATA_SET_LENGTH_LSB 0xFF + + + +//PB7-27 (20 bytes): +//PB7 = MD0 +#define MASK_VTEM_MD0__VRR_EN 0x01 +#define MASK_VTEM_MD0__M_CONST 0x02 +#define MASK_VTEM_MD0__RESERVED2 0x0C +#define MASK_VTEM_MD0__FVA_FACTOR_M1 0xF0 + +//MD1 +#define MASK_VTEM_MD1__BASE_VFRONT 0xFF + +//MD2 +#define MASK_VTEM_MD2__BASE_REFRESH_RATE_98 0x03 +#define MASK_VTEM_MD2__RB 0x04 +#define MASK_VTEM_MD2__RESERVED3 0xF8 + +//MD3 +#define MASK_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF + enum ColorimetryRGBDP { ColorimetryRGB_DP_sRGB = 0, ColorimetryRGB_DP_AdobeRGB = 3, diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c index b3810b864676..05e2be856037 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -66,6 +66,39 @@ static const unsigned char abm_config[abm_defines_max_config][abm_defines_max_le { 3, 6, 10, 12 }, /* Alt #3 - Super aggressiveness */ }; +struct abm_parameters { + unsigned char min_reduction; + unsigned char max_reduction; + unsigned char bright_pos_gain; + unsigned char dark_pos_gain; + unsigned char brightness_gain; + unsigned char contrast_factor; + unsigned char deviation_gain; + unsigned char min_knee; + unsigned char max_knee; +}; + +static const struct abm_parameters abm_settings_config0[abm_defines_max_level] = { +// min_red max_red bright_pos dark_pos brightness_gain contrast deviation min_knee max_knee + {0xff, 0xbf, 0x20, 0x00, 0xff, 0x99, 0xb3, 0x40, 0xE0}, + {0xff, 0x85, 0x20, 0x00, 0xff, 0x90, 0xa8, 0x40, 0xE0}, + {0xff, 0x40, 0x20, 0x00, 0xff, 0x90, 0x68, 0x40, 0xE0}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0x90, 0xb3, 0x70, 0x70}, +}; + +static const struct abm_parameters abm_settings_config1[abm_defines_max_level] = { +// min_red max_red bright_pos dark_pos brightness_gain contrast deviation min_knee max_knee + {0xf0, 0xd9, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, + {0xcd, 0xa5, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, + {0x99, 0x65, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, + {0x82, 0x4d, 0x20, 0x00, 0x00, 0xa8, 0xb3, 0x70, 0x70}, +}; + +static const struct abm_parameters * const abm_settings[] = { + abm_settings_config0, + abm_settings_config1, +}; + #define NUM_AMBI_LEVEL 5 #define NUM_AGGR_LEVEL 4 #define NUM_POWER_FN_SEGS 8 @@ -131,11 +164,13 @@ struct iram_table_v_2_2 { uint8_t max_reduction[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x16 U0.8 */ uint8_t bright_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x2a U2.6 */ uint8_t dark_pos_gain[NUM_AMBI_LEVEL][NUM_AGGR_LEVEL]; /* 0x3e U2.6 */ - uint8_t hybridFactor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */ - uint8_t contrastFactor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */ + uint8_t hybrid_factor[NUM_AGGR_LEVEL]; /* 0x52 U0.8 */ + uint8_t contrast_factor[NUM_AGGR_LEVEL]; /* 0x56 U0.8 */ uint8_t deviation_gain[NUM_AGGR_LEVEL]; /* 0x5a U0.8 */ uint8_t iir_curve[NUM_AMBI_LEVEL]; /* 0x5e U0.8 */ - uint8_t pad[29]; /* 0x63 U0.8 */ + uint8_t min_knee[NUM_AGGR_LEVEL]; /* 0x63 U0.8 */ + uint8_t max_knee[NUM_AGGR_LEVEL]; /* 0x67 U0.8 */ + uint8_t pad[21]; /* 0x6b U0.8 */ /* parameters for crgb conversion */ uint16_t crgb_thresh[NUM_POWER_FN_SEGS]; /* 0x80 U3.13 */ @@ -501,15 +536,72 @@ void fill_iram_v_2_2(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parame ram_table->dark_pos_gain[4][2] = 0x00; ram_table->dark_pos_gain[4][3] = 0x00; - ram_table->hybridFactor[0] = 0xff; - ram_table->hybridFactor[1] = 0xff; - ram_table->hybridFactor[2] = 0xff; - ram_table->hybridFactor[3] = 0xc0; + ram_table->hybrid_factor[0] = 0xff; + ram_table->hybrid_factor[1] = 0xff; + ram_table->hybrid_factor[2] = 0xff; + ram_table->hybrid_factor[3] = 0xc0; - ram_table->contrastFactor[0] = 0x99; - ram_table->contrastFactor[1] = 0x99; - ram_table->contrastFactor[2] = 0x90; - ram_table->contrastFactor[3] = 0x80; + ram_table->contrast_factor[0] = 0x99; + ram_table->contrast_factor[1] = 0x99; + ram_table->contrast_factor[2] = 0x90; + ram_table->contrast_factor[3] = 0x80; + + ram_table->iir_curve[0] = 0x65; + ram_table->iir_curve[1] = 0x65; + ram_table->iir_curve[2] = 0x65; + ram_table->iir_curve[3] = 0x65; + ram_table->iir_curve[4] = 0x65; + + //Gamma 2.2 + ram_table->crgb_thresh[0] = cpu_to_be16(0x127c); + ram_table->crgb_thresh[1] = cpu_to_be16(0x151b); + ram_table->crgb_thresh[2] = cpu_to_be16(0x17d5); + ram_table->crgb_thresh[3] = cpu_to_be16(0x1a56); + ram_table->crgb_thresh[4] = cpu_to_be16(0x1c83); + ram_table->crgb_thresh[5] = cpu_to_be16(0x1e72); + ram_table->crgb_thresh[6] = cpu_to_be16(0x20f0); + ram_table->crgb_thresh[7] = cpu_to_be16(0x232b); + ram_table->crgb_offset[0] = cpu_to_be16(0x2999); + ram_table->crgb_offset[1] = cpu_to_be16(0x3999); + ram_table->crgb_offset[2] = cpu_to_be16(0x4666); + ram_table->crgb_offset[3] = cpu_to_be16(0x5999); + ram_table->crgb_offset[4] = cpu_to_be16(0x6333); + ram_table->crgb_offset[5] = cpu_to_be16(0x7800); + ram_table->crgb_offset[6] = cpu_to_be16(0x8c00); + ram_table->crgb_offset[7] = cpu_to_be16(0xa000); + ram_table->crgb_slope[0] = cpu_to_be16(0x3609); + ram_table->crgb_slope[1] = cpu_to_be16(0x2dfa); + ram_table->crgb_slope[2] = cpu_to_be16(0x27ea); + ram_table->crgb_slope[3] = cpu_to_be16(0x235d); + ram_table->crgb_slope[4] = cpu_to_be16(0x2042); + ram_table->crgb_slope[5] = cpu_to_be16(0x1dc3); + ram_table->crgb_slope[6] = cpu_to_be16(0x1b1a); + ram_table->crgb_slope[7] = cpu_to_be16(0x1910); + + fill_backlight_transform_table_v_2_2( + params, ram_table); +} + +void fill_iram_v_2_3(struct iram_table_v_2_2 *ram_table, struct dmcu_iram_parameters params) +{ + unsigned int i, j; + unsigned int set = params.set; + + ram_table->flags = 0x0; + for (i = 0; i < NUM_AGGR_LEVEL; i++) { + ram_table->hybrid_factor[i] = abm_settings[set][i].brightness_gain; + ram_table->contrast_factor[i] = abm_settings[set][i].contrast_factor; + ram_table->deviation_gain[i] = abm_settings[set][i].deviation_gain; + ram_table->min_knee[i] = abm_settings[set][i].min_knee; + ram_table->max_knee[i] = abm_settings[set][i].max_knee; + + for (j = 0; j < NUM_AMBI_LEVEL; j++) { + ram_table->min_reduction[j][i] = abm_settings[set][i].min_reduction; + ram_table->max_reduction[j][i] = abm_settings[set][i].max_reduction; + ram_table->bright_pos_gain[j][i] = abm_settings[set][i].bright_pos_gain; + ram_table->dark_pos_gain[j][i] = abm_settings[set][i].dark_pos_gain; + } + } ram_table->iir_curve[0] = 0x65; ram_table->iir_curve[1] = 0x65; @@ -561,7 +653,12 @@ bool dmcu_load_iram(struct dmcu *dmcu, memset(&ram_table, 0, sizeof(ram_table)); - if (dmcu->dmcu_version.abm_version == 0x22) { + if (dmcu->dmcu_version.abm_version == 0x23) { + fill_iram_v_2_3((struct iram_table_v_2_2 *)ram_table, params); + + result = dmcu->funcs->load_iram( + dmcu, 0, (char *)(&ram_table), IRAM_RESERVE_AREA_START_V2_2); + } else if (dmcu->dmcu_version.abm_version == 0x22) { fill_iram_v_2_2((struct iram_table_v_2_2 *)ram_table, params); result = dmcu->funcs->load_iram( |