提交 af911133 编写于 作者: D Dave Airlie

Merge branch 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux into drm-next

Last batch of new stuff for DC. Highlights:
- Fix some memory leaks
- S3 fixes
- Hotplug fixes
- Fix some CX multi-display issues
- MST fixes
- DML updates from the hw team
- Various code cleanups
- Misc bug fixes

* 'drm-next-4.15-dc' of git://people.freedesktop.org/~agd5f/linux: (155 commits)
  drm/amd/display:: Fix NULL pointer in Raven hotplug
  drm/amd/display: Fix memoryleak during S3 resume.
  drm/amd/display: add hardware_planes_only to list of affected planes
  drm/amd/display: Fix brace style
  drm/amd/display: Remove needless cast in amdgpu_dm_connector_init()
  drm/amd/display: Fix brace style in amdgpu_dm_connector_ddc_get_modes()
  drm/amd/display: Tidy up dm_drm_plane_reset()
  drm/amd/display: Fix indentation in create_eml_sink()
  drm/amd/display: Replace block with strncpy() in fill_audio_info()
  drm/amd/display: Fix brace style in amdgpu_dm_initialize_drm_device()
  drm/amd/display: Simplify handle_hpd_rx_irq()
  drm/amd/display: Fix brace style in dm_handle_hpd_rx_irq()
  drm/amd/display: Fix brace style in amdgpu_dm_update_connector_after_detect()
  drm/amd/display: Fix indentation in dm_resume()
  drm/amd/display: Fix indentation in dm_suspend()
  drm/amd/display: Simplify dm_late_init()
  amdgpu/dc: inline dml_round_to_multiple
  amdgpu/dc: drop dml_util_is_420
  drm/amd/display: Add bunch of missing license headers in DML
  amdgpu/dc: inline a bunch of the dml wrappers.
  ...
......@@ -17,6 +17,16 @@ config DRM_AMD_DC_PRE_VEGA
by default. This includes Polaris, Carrizo, Tonga, Bonaire,
and Hawaii.
config DRM_AMD_DC_FBC
bool "AMD FBC - Enable Frame Buffer Compression"
depends on DRM_AMD_DC
help
Choose this option if you want to use frame buffer compression
support.
This is a power optimisation feature, check its availability
on your hardware before enabling this option.
config DRM_AMD_DC_DCN1_0
bool "DCN 1.0 Raven family"
depends on DRM_AMD_DC && X86
......
......@@ -538,9 +538,8 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev)
static int dm_late_init(void *handle)
{
struct drm_device *dev = ((struct amdgpu_device *)handle)->ddev;
int r = detect_mst_link_for_all_connectors(dev);
return r;
return detect_mst_link_for_all_connectors(dev);
}
static void s3_handle_mst(struct drm_device *dev, bool suspend)
......@@ -599,10 +598,7 @@ static int dm_suspend(void *handle)
WARN_ON(adev->dm.cached_state);
adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
dc_set_power_state(
dm->dc,
DC_ACPI_CM_POWER_STATE_D3
);
dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
return ret;
}
......@@ -632,10 +628,7 @@ static int dm_resume(void *handle)
struct amdgpu_display_manager *dm = &adev->dm;
/* power on hardware */
dc_set_power_state(
dm->dc,
DC_ACPI_CM_POWER_STATE_D0
);
dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
return 0;
}
......@@ -648,6 +641,11 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
struct drm_connector *connector;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
struct dm_crtc_state *dm_crtc_state;
struct drm_plane *plane;
struct drm_plane_state *plane_state;
struct dm_plane_state *dm_plane_state;
struct dm_atomic_state *cached_state;
int ret = 0;
int i;
......@@ -686,6 +684,34 @@ int amdgpu_dm_display_resume(struct amdgpu_device *adev)
for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i)
new_crtc_state->active_changed = true;
cached_state = to_dm_atomic_state(adev->dm.cached_state);
/*
* During suspend, the cached state is saved before all streams are
* disabled. Refresh cached state to match actual current state before
* restoring it.
*/
WARN_ON(kref_read(&cached_state->context->refcount) > 1);
dc_release_state(cached_state->context);
for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i) {
dm_crtc_state = to_dm_crtc_state(new_crtc_state);
if (dm_crtc_state->stream) {
WARN_ON(kref_read(&dm_crtc_state->stream->refcount) > 1);
dc_stream_release(dm_crtc_state->stream);
dm_crtc_state->stream = NULL;
}
}
for_each_new_plane_in_state(adev->dm.cached_state, plane, plane_state, i) {
dm_plane_state = to_dm_plane_state(plane_state);
if (dm_plane_state->dc_state) {
WARN_ON(kref_read(&dm_plane_state->dc_state->refcount) > 1);
dc_plane_state_release(dm_plane_state->dc_state);
dm_plane_state->dc_state = NULL;
}
}
ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state);
drm_atomic_state_put(adev->dm.cached_state);
......@@ -860,9 +886,9 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
connector);
aconnector->dc_sink = sink;
if (sink->dc_edid.length == 0)
if (sink->dc_edid.length == 0) {
aconnector->edid = NULL;
else {
} else {
aconnector->edid =
(struct edid *) sink->dc_edid.raw_edid;
......@@ -980,8 +1006,9 @@ static void dm_handle_hpd_rx_irq(struct amdgpu_dm_connector *aconnector)
dpcd_bytes_to_read);
new_irq_handled = false;
} else
} else {
break;
}
}
if (process_count == max_process_count)
......@@ -993,20 +1020,20 @@ static void handle_hpd_rx_irq(void *param)
struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
struct drm_connector *connector = &aconnector->base;
struct drm_device *dev = connector->dev;
const struct dc_link *dc_link = aconnector->dc_link;
struct dc_link *dc_link = aconnector->dc_link;
bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
/* TODO:Temporary add mutex to protect hpd interrupt not have a gpio
* conflict, after implement i2c helper, this mutex should be
* retired.
*/
if (aconnector->dc_link->type != dc_connection_mst_branch)
if (dc_link->type != dc_connection_mst_branch)
mutex_lock(&aconnector->hpd_lock);
if (dc_link_handle_hpd_rx_irq(aconnector->dc_link, NULL) &&
if (dc_link_handle_hpd_rx_irq(dc_link, NULL) &&
!is_mst_root_connector) {
/* Downstream Port status changed. */
if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPDRX)) {
if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
amdgpu_dm_update_connector_after_detect(aconnector);
......@@ -1018,10 +1045,10 @@ static void handle_hpd_rx_irq(void *param)
}
}
if ((dc_link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
(dc_link->type == dc_connection_mst_branch))
(dc_link->type == dc_connection_mst_branch))
dm_handle_hpd_rx_irq(aconnector);
if (aconnector->dc_link->type != dc_connection_mst_branch)
if (dc_link->type != dc_connection_mst_branch)
mutex_unlock(&aconnector->hpd_lock);
}
......@@ -1381,9 +1408,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
goto fail_free_planes;
aencoder = kzalloc(sizeof(*aencoder), GFP_KERNEL);
if (!aencoder) {
if (!aencoder)
goto fail_free_connector;
}
if (amdgpu_dm_encoder_init(dm->ddev, aencoder, i)) {
DRM_ERROR("KMS: Failed to initialize encoder\n");
......@@ -1754,7 +1780,9 @@ static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
int r = amdgpu_bo_reserve(rbo, false);
if (unlikely(r)) {
DRM_ERROR("Unable to reserve buffer\n");
// Don't show error msg. when return -ERESTARTSYS
if (r != -ERESTARTSYS)
DRM_ERROR("Unable to reserve buffer: %d\n", r);
return r;
}
......@@ -2206,11 +2234,9 @@ static void fill_audio_info(struct audio_info *audio_info,
cea_revision = drm_connector->display_info.cea_rev;
while (i < AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS &&
edid_caps->display_name[i]) {
audio_info->display_name[i] = edid_caps->display_name[i];
i++;
}
strncpy(audio_info->display_name,
edid_caps->display_name,
AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS - 1);
if (cea_revision >= 3) {
audio_info->mode_count = edid_caps->audio_mode_count;
......@@ -2318,8 +2344,16 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
drm_connector = &aconnector->base;
if (!aconnector->dc_sink)
if (!aconnector->dc_sink) {
/*
* Exclude MST from creating fake_sink
* TODO: need to enable MST into fake_sink feature
*/
if (aconnector->mst_port)
goto stream_create_fail;
create_fake_sink(aconnector);
}
stream = dc_create_stream_for_sink(aconnector->dc_sink);
......@@ -2453,7 +2487,8 @@ amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
* 2. This interface *is called* in context of user-mode ioctl. Which
* makes it a bad place for *any* MST-related activit. */
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
if (aconnector->base.force == DRM_FORCE_UNSPECIFIED &&
!aconnector->fake_enable)
connected = (aconnector->dc_sink != NULL);
else
connected = (aconnector->base.force == DRM_FORCE_ON);
......@@ -2681,8 +2716,7 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
(edid->extensions + 1) * EDID_LENGTH,
&init_params);
if (aconnector->base.force
== DRM_FORCE_ON)
if (aconnector->base.force == DRM_FORCE_ON)
aconnector->dc_sink = aconnector->dc_link->local_sink ?
aconnector->dc_link->local_sink :
aconnector->dc_em_sink;
......@@ -2746,7 +2780,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
stream->src.height = mode->vdisplay;
stream->dst = stream->src;
if (dc_validate_stream(adev->dm.dc, stream))
if (dc_validate_stream(adev->dm.dc, stream) == DC_OK)
result = MODE_OK;
dc_stream_release(stream);
......@@ -2791,7 +2825,7 @@ static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
if (!dm_crtc_state->stream)
return 0;
if (dc_validate_stream(dc, dm_crtc_state->stream))
if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
return 0;
return ret;
......@@ -2835,13 +2869,13 @@ static void dm_drm_plane_reset(struct drm_plane *plane)
plane->funcs->atomic_destroy_state(plane, plane->state);
amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
WARN_ON(amdgpu_state == NULL);
if (amdgpu_state) {
plane->state = &amdgpu_state->base;
plane->state->plane = plane;
plane->state->rotation = DRM_MODE_ROTATE_0;
} else
WARN_ON(1);
}
}
static struct drm_plane_state *
......@@ -2986,7 +3020,7 @@ static int dm_plane_atomic_check(struct drm_plane *plane,
if (!dm_plane_state->dc_state)
return 0;
if (dc_validate_plane(dc, dm_plane_state->dc_state))
if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
return 0;
return -EINVAL;
......@@ -3272,8 +3306,9 @@ static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
drm_edid_to_eld(connector, edid);
amdgpu_dm_get_native_mode(connector);
} else
} else {
amdgpu_dm_connector->num_modes = 0;
}
}
static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
......@@ -3421,7 +3456,8 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
struct dc *dc = dm->dc;
struct dc_link *link = dc_get_link_at_index(dc, link_index);
struct amdgpu_i2c_adapter *i2c;
((struct dc_link *)link)->priv = aconnector;
link->priv = aconnector;
DRM_DEBUG_DRIVER("%s()\n", __func__);
......@@ -3661,10 +3697,10 @@ static void handle_cursor_update(struct drm_plane *plane,
return;
DRM_DEBUG_DRIVER("%s: crtc_id=%d with size %d to %d\n",
__func__,
amdgpu_crtc->crtc_id,
plane->state->crtc_w,
plane->state->crtc_h);
__func__,
amdgpu_crtc->crtc_id,
plane->state->crtc_w,
plane->state->crtc_h);
ret = get_cursor_position(plane, crtc, &position);
if (ret)
......@@ -3691,14 +3727,15 @@ static void handle_cursor_update(struct drm_plane *plane,
attributes.pitch = attributes.width;
if (!dc_stream_set_cursor_attributes(crtc_state->stream,
&attributes))
DRM_ERROR("DC failed to set cursor attributes\n");
if (crtc_state->stream) {
if (!dc_stream_set_cursor_attributes(crtc_state->stream,
&attributes))
DRM_ERROR("DC failed to set cursor attributes\n");
if (crtc_state->stream)
if (!dc_stream_set_cursor_position(crtc_state->stream,
&position))
DRM_ERROR("DC failed to set cursor position\n");
}
}
static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
......@@ -3726,7 +3763,8 @@ static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
*/
static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
uint32_t target)
uint32_t target,
struct dc_state *state)
{
unsigned long flags;
uint32_t target_vblank;
......@@ -3797,7 +3835,13 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
surface_updates->flip_addr = &addr;
dc_update_planes_and_stream(adev->dm.dc, surface_updates, 1, acrtc_state->stream, NULL);
dc_commit_updates_for_stream(adev->dm.dc,
surface_updates,
1,
acrtc_state->stream,
NULL,
&surface_updates->surface,
state);
DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
__func__,
......@@ -3823,6 +3867,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
struct drm_crtc_state *new_pcrtc_state =
drm_atomic_get_new_crtc_state(state, pcrtc);
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
int planes_count = 0;
unsigned long flags;
......@@ -3880,7 +3925,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
amdgpu_dm_do_flip(
crtc,
fb,
drm_crtc_vblank_count(crtc) + *wait_for_vblank);
drm_crtc_vblank_count(crtc) + *wait_for_vblank,
dm_state->context);
}
}
......@@ -3900,7 +3946,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (false == dc_commit_planes_to_stream(dm->dc,
plane_states_constructed,
planes_count,
dc_stream_attach))
dc_stream_attach,
dm_state->context))
dm_error("%s: Failed to attach plane!\n", __func__);
} else {
/*TODO BUG Here should go disable planes on CRTC. */
......@@ -3931,6 +3978,8 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
if (drm_atomic_crtc_needs_modeset(new_crtc_state) && dm_old_crtc_state->stream)
manage_dm_interrupts(adev, acrtc, false);
}
/* Add check here for SoC's that support hardware cursor plane, to
* unset legacy_cursor_update */
return drm_atomic_helper_commit(dev, state, nonblock);
......@@ -4120,7 +4169,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dm->dc,
status->plane_states,
status->plane_count,
dm_new_crtc_state->stream))
dm_new_crtc_state->stream,
dm_state->context))
dm_error("%s: Failed to update stream scaling!\n", __func__);
}
......@@ -4339,7 +4389,8 @@ static int dm_update_crtcs_state(struct dc *dc,
aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
/* TODO This hack should go away */
if (aconnector) {
if (aconnector && enable) {
// Make sure fake sink is created in plug-in scenario
new_con_state = drm_atomic_get_connector_state(state,
&aconnector->base);
......@@ -4368,12 +4419,13 @@ static int dm_update_crtcs_state(struct dc *dc,
}
}
if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream)) {
if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
new_crtc_state->mode_changed = false;
DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d",
new_crtc_state->mode_changed);
new_crtc_state->mode_changed);
}
......@@ -4402,10 +4454,10 @@ static int dm_update_crtcs_state(struct dc *dc,
crtc->base.id);
/* i.e. reset mode */
if (!dc_remove_stream_from_ctx(
if (dc_remove_stream_from_ctx(
dc,
dm_state->context,
dm_old_crtc_state->stream)) {
dm_old_crtc_state->stream) != DC_OK) {
ret = -EINVAL;
goto fail;
}
......@@ -4416,6 +4468,13 @@ static int dm_update_crtcs_state(struct dc *dc,
*lock_and_validation_needed = true;
} else {/* Add stream for any updated/enabled CRTC */
/*
* Quick fix to prevent NULL pointer on new_stream when
* added MST connectors not found in existing crtc_state in the chained mode
* TODO: need to dig out the root cause of that
*/
if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
goto next_crtc;
if (modereset_required(new_crtc_state))
goto next_crtc;
......@@ -4431,10 +4490,10 @@ static int dm_update_crtcs_state(struct dc *dc,
DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
crtc->base.id);
if (!dc_add_stream_to_ctx(
if (dc_add_stream_to_ctx(
dc,
dm_state->context,
dm_new_crtc_state->stream)) {
dm_new_crtc_state->stream) != DC_OK) {
ret = -EINVAL;
goto fail;
}
......@@ -4586,7 +4645,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
struct drm_connector *connector;
struct drm_connector_state *old_con_state, *new_con_state;
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
/*
* This bool will be set for true for any modeset/reset
......@@ -4595,18 +4654,34 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
bool lock_and_validation_needed = false;
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret) {
DRM_ERROR("Atomic state validation failed with error :%d !\n", ret);
return ret;
}
/*
* Hack: Commit needs planes right now, specifically for gamma
* TODO rework commit to check CRTC for gamma change
* legacy_cursor_update should be made false for SoC's having
* a dedicated hardware plane for cursor in amdgpu_dm_atomic_commit(),
* otherwise for software cursor plane,
* we should not add it to list of affected planes.
*/
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->color_mgmt_changed) {
if (state->legacy_cursor_update) {
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->color_mgmt_changed) {
ret = drm_atomic_add_affected_planes(state, crtc);
if (ret)
goto fail;
}
}
} else {
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (!new_crtc_state->enable)
continue;
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret)
return ret;
ret = drm_atomic_add_affected_planes(state, crtc);
if (ret)
goto fail;
......@@ -4684,7 +4759,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
if (ret)
goto fail;
if (!dc_validate_global_state(dc, dm_state->context)) {
if (dc_validate_global_state(dc, dm_state->context) != DC_OK) {
ret = -EINVAL;
goto fail;
}
......
......@@ -208,24 +208,21 @@ static void remove_timer_handler(struct amdgpu_device *adev,
DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
}
if (handler_in == NULL) {
/* Remove ALL handlers. */
/* Remove ALL handlers. */
if (handler_in == NULL)
continue;
}
if (handler_in == handler_temp) {
/* Remove a SPECIFIC handler.
* Found our handler - we can stop here. */
/* Remove a SPECIFIC handler.
* Found our handler - we can stop here. */
if (handler_in == handler_temp)
break;
}
}
DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
if (handler_in != NULL && handler_removed == false) {
if (handler_in != NULL && handler_removed == false)
DRM_ERROR("DM_IRQ: handler: %p is not in the list!\n",
handler_in);
}
}
static bool
......@@ -435,7 +432,7 @@ int amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
* Disable HW interrupt for HPD and HPDRX only since FLIP and VBLANK
* will be disabled from manage_dm_interrupts on disable CRTC.
*/
for (src = DC_IRQ_SOURCE_HPD1; src < DC_IRQ_SOURCE_HPD6RX; src++) {
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
......@@ -462,7 +459,7 @@ int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
DRM_DEBUG_KMS("DM_IRQ: early resume\n");
/* re-enable short pulse interrupts HW interrupt */
for (src = DC_IRQ_SOURCE_HPD1RX; src < DC_IRQ_SOURCE_HPD6RX + 1; src++) {
for (src = DC_IRQ_SOURCE_HPD1RX; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
......@@ -488,7 +485,7 @@ int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
* Renable HW interrupt for HPD and only since FLIP and VBLANK
* will be enabled from manage_dm_interrupts on enable CRTC.
*/
for (src = DC_IRQ_SOURCE_HPD1; src < DC_IRQ_SOURCE_HPD6; src++) {
for (src = DC_IRQ_SOURCE_HPD1; src <= DC_IRQ_SOURCE_HPD6; src++) {
hnd_list_l = &adev->dm.irq_handler_list_low_tab[src].head;
hnd_list_h = &adev->dm.irq_handler_list_high_tab[src];
if (!list_empty(hnd_list_l) || !list_empty(hnd_list_h))
......
......@@ -174,14 +174,60 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
.atomic_get_property = amdgpu_dm_connector_atomic_get_property
};
static int dm_connector_update_modes(struct drm_connector *connector,
struct edid *edid)
{
int ret;
ret = drm_add_edid_modes(connector, edid);
drm_edid_to_eld(connector, edid);
return ret;
}
static int dm_dp_mst_get_modes(struct drm_connector *connector)
{
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
int ret = 0;
ret = drm_add_edid_modes(&aconnector->base, aconnector->edid);
if (!aconnector)
return dm_connector_update_modes(connector, NULL);
if (!aconnector->edid) {
struct edid *edid;
struct dc_sink *dc_sink;
struct dc_sink_init_data init_params = {
.link = aconnector->dc_link,
.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
drm_edid_to_eld(&aconnector->base, aconnector->edid);
if (!edid) {
drm_mode_connector_update_edid_property(
&aconnector->base,
NULL);
return ret;
}
aconnector->edid = edid;
dc_sink = dc_link_add_remote_sink(
aconnector->dc_link,
(uint8_t *)edid,
(edid->extensions + 1) * EDID_LENGTH,
&init_params);
dc_sink->priv = aconnector;
aconnector->dc_sink = dc_sink;
if (aconnector->dc_sink)
amdgpu_dm_add_sink_to_freesync_module(
connector, edid);
drm_mode_connector_update_edid_property(
&aconnector->base, edid);
}
ret = dm_connector_update_modes(connector, aconnector->edid);
return ret;
}
......@@ -241,9 +287,10 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
struct amdgpu_device *adev = dev->dev_private;
struct amdgpu_dm_connector *aconnector;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
aconnector = to_amdgpu_dm_connector(connector);
if (aconnector->mst_port == master
&& !aconnector->port) {
......@@ -253,11 +300,11 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
aconnector->port = port;
drm_mode_connector_set_path_property(connector, pathprop);
drm_modeset_unlock(&dev->mode_config.connection_mutex);
drm_connector_list_iter_end(&conn_iter);
return &aconnector->base;
}
}
drm_modeset_unlock(&dev->mode_config.connection_mutex);
drm_connector_list_iter_end(&conn_iter);
aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
if (!aconnector)
......@@ -343,92 +390,20 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
{
struct amdgpu_dm_connector *master = container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
struct drm_device *dev = master->base.dev;
struct amdgpu_device *adev = dev->dev_private;
struct drm_connector *connector;
struct amdgpu_dm_connector *aconnector;
struct edid *edid;
struct dc_sink *dc_sink;
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
aconnector = to_amdgpu_dm_connector(connector);
if (aconnector->port &&
aconnector->port->pdt != DP_PEER_DEVICE_NONE &&
aconnector->port->pdt != DP_PEER_DEVICE_MST_BRANCHING &&
!aconnector->dc_sink) {
/*
* This is plug in case, where port has been created but
* sink hasn't been created yet
*/
if (!aconnector->edid) {
struct dc_sink_init_data init_params = {
.link = aconnector->dc_link,
.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST};
edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
if (!edid) {
drm_mode_connector_update_edid_property(
&aconnector->base,
NULL);
continue;
}
aconnector->edid = edid;
dc_sink = dc_link_add_remote_sink(
aconnector->dc_link,
(uint8_t *)edid,
(edid->extensions + 1) * EDID_LENGTH,
&init_params);
dc_sink->priv = aconnector;
aconnector->dc_sink = dc_sink;
if (aconnector->dc_sink)
amdgpu_dm_add_sink_to_freesync_module(
connector,
edid);
dm_restore_drm_connector_state(connector->dev, connector);
} else
edid = aconnector->edid;
DRM_DEBUG_KMS("edid retrieved %p\n", edid);
drm_mode_connector_update_edid_property(
&aconnector->base,
aconnector->edid);
}
}
drm_modeset_unlock_all(dev);
schedule_work(&adev->dm.mst_hotplug_work);
drm_kms_helper_hotplug_event(dev);
}
static void dm_dp_mst_register_connector(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct amdgpu_device *adev = dev->dev_private;
int i;
drm_modeset_lock_all(dev);
if (adev->mode_info.rfbdev) {
/*Do not add if already registered in past*/
for (i = 0; i < adev->mode_info.rfbdev->helper.connector_count; i++) {
if (adev->mode_info.rfbdev->helper.connector_info[i]->connector
== connector) {
drm_modeset_unlock_all(dev);
return;
}
}
if (adev->mode_info.rfbdev)
drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector);
}
else
DRM_ERROR("adev->mode_info.rfbdev is NULL\n");
drm_modeset_unlock_all(dev);
drm_connector_register(connector);
}
......
......@@ -35,6 +35,12 @@
#include "amdgpu_dm_irq.h"
#include "amdgpu_pm.h"
unsigned long long dm_get_timestamp(struct dc_context *ctx)
{
/* TODO: return actual timestamp */
return 0;
}
bool dm_write_persistent_data(struct dc_context *ctx,
const struct dc_sink *sink,
const char *module_name,
......
......@@ -80,8 +80,6 @@ static bool construct(struct dc_context *ctx, struct dal_logger *logger,
logger->buffer_read_offset = 0;
logger->buffer_write_offset = 0;
logger->write_wrap_count = 0;
logger->read_wrap_count = 0;
logger->open_count = 0;
logger->flags.bits.ENABLE_CONSOLE = 1;
......@@ -162,23 +160,24 @@ static void log_to_debug_console(struct log_entry *entry)
}
/* Print everything unread existing in log_buffer to debug console*/
static void flush_to_debug_console(struct dal_logger *logger)
void dm_logger_flush_buffer(struct dal_logger *logger, bool should_warn)
{
int i = logger->buffer_read_offset;
char *string_start = &logger->log_buffer[i];
char *string_start = &logger->log_buffer[logger->buffer_read_offset];
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (i < logger->buffer_write_offset) {
if (should_warn)
dm_output_to_console(
"---------------- FLUSHING LOG BUFFER ----------------\n");
while (logger->buffer_read_offset < logger->buffer_write_offset) {
if (logger->log_buffer[i] == '\0') {
if (logger->log_buffer[logger->buffer_read_offset] == '\0') {
dm_output_to_console("%s", string_start);
string_start = (char *)logger->log_buffer + i + 1;
string_start = logger->log_buffer + logger->buffer_read_offset + 1;
}
i++;
logger->buffer_read_offset++;
}
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
if (should_warn)
dm_output_to_console(
"-------------- END FLUSHING LOG BUFFER --------------\n\n");
}
static void log_to_internal_buffer(struct log_entry *entry)
......@@ -195,35 +194,17 @@ static void log_to_internal_buffer(struct log_entry *entry)
if (size > 0 && size < logger->log_buffer_size) {
int total_free_space = 0;
int space_before_wrap = 0;
if (logger->buffer_write_offset > logger->buffer_read_offset) {
total_free_space = logger->log_buffer_size -
logger->buffer_write_offset +
logger->buffer_read_offset;
space_before_wrap = logger->log_buffer_size -
logger->buffer_write_offset;
} else if (logger->buffer_write_offset <
logger->buffer_read_offset) {
total_free_space = logger->log_buffer_size -
logger->buffer_read_offset +
logger->buffer_write_offset;
space_before_wrap = total_free_space;
} else if (logger->write_wrap_count !=
logger->read_wrap_count) {
/* Buffer is completely full already */
total_free_space = 0;
space_before_wrap = 0;
} else {
int buffer_space = logger->log_buffer_size -
logger->buffer_write_offset;
if (logger->buffer_write_offset == logger->buffer_read_offset) {
/* Buffer is empty, start writing at beginning */
total_free_space = logger->log_buffer_size;
space_before_wrap = logger->log_buffer_size;
buffer_space = logger->log_buffer_size;
logger->buffer_write_offset = 0;
logger->buffer_read_offset = 0;
}
if (space_before_wrap > size) {
if (buffer_space > size) {
/* No wrap around, copy 'size' bytes
* from 'entry->buf' to 'log_buffer'
*/
......@@ -232,28 +213,12 @@ static void log_to_internal_buffer(struct log_entry *entry)
entry->buf, size);
logger->buffer_write_offset += size;
} else if (total_free_space > size) {
/* We have enough room without flushing,
* but need to wrap around */
int space_after_wrap = total_free_space -
space_before_wrap;
memmove(logger->log_buffer +
logger->buffer_write_offset,
entry->buf, space_before_wrap);
memmove(logger->log_buffer, entry->buf +
space_before_wrap, space_after_wrap);
logger->buffer_write_offset = space_after_wrap;
logger->write_wrap_count++;
} else {
/* Not enough room remaining, we should flush
* existing logs */
/* Flush existing unread logs to console */
flush_to_debug_console(logger);
dm_logger_flush_buffer(logger, true);
/* Start writing to beginning of buffer */
memmove(logger->log_buffer, entry->buf, size);
......@@ -325,9 +290,10 @@ void dm_logger_write(
log_heading(&entry);
size = dm_log_to_buffer(
buffer, LOG_MAX_LINE_SIZE, msg, args);
buffer, LOG_MAX_LINE_SIZE - 1, msg, args);
entry.buf_offset += size;
buffer[entry.buf_offset + size] = '\0';
entry.buf_offset += size + 1;
/* --Flush log_entry buffer-- */
/* print to kernel console */
......
......@@ -26,42 +26,5 @@
#ifndef __DAL_LOGGER_H__
#define __DAL_LOGGER_H__
/* Structure for keeping track of offsets, buffer, etc */
#define DAL_LOGGER_BUFFER_MAX_SIZE 2048
/*Connectivity log needs to output EDID, which needs at lease 256x3 bytes,
* change log line size to 896 to meet the request.
*/
#define LOG_MAX_LINE_SIZE 896
#include "include/logger_types.h"
struct dal_logger {
/* How far into the circular buffer has been read by dsat
* Read offset should never cross write offset. Write \0's to
* read data just to be sure?
*/
uint32_t buffer_read_offset;
/* How far into the circular buffer we have written
* Write offset should never cross read offset
*/
uint32_t buffer_write_offset;
uint32_t write_wrap_count;
uint32_t read_wrap_count;
uint32_t open_count;
char *log_buffer; /* Pointer to malloc'ed buffer */
uint32_t log_buffer_size; /* Size of circular buffer */
uint32_t mask; /*array of masks for major elements*/
union logger_flags flags;
struct dc_context *ctx;
};
#endif /* __DAL_LOGGER_H__ */
......@@ -1042,13 +1042,13 @@ static enum bp_result get_embedded_panel_info_v2_1(
info->lcd_timing.misc_info.VERTICAL_CUT_OFF = 0;
info->lcd_timing.misc_info.H_REPLICATION_BY2 =
lvds->lcd_timing.miscinfo & ATOM_H_REPLICATIONBY2;
!!(lvds->lcd_timing.miscinfo & ATOM_H_REPLICATIONBY2);
info->lcd_timing.misc_info.V_REPLICATION_BY2 =
lvds->lcd_timing.miscinfo & ATOM_V_REPLICATIONBY2;
!!(lvds->lcd_timing.miscinfo & ATOM_V_REPLICATIONBY2);
info->lcd_timing.misc_info.COMPOSITE_SYNC =
lvds->lcd_timing.miscinfo & ATOM_COMPOSITESYNC;
!!(lvds->lcd_timing.miscinfo & ATOM_COMPOSITESYNC);
info->lcd_timing.misc_info.INTERLACE =
lvds->lcd_timing.miscinfo & ATOM_INTERLACE;
!!(lvds->lcd_timing.miscinfo & ATOM_INTERLACE);
/* not provided by VBIOS*/
info->lcd_timing.misc_info.DOUBLE_CLOCK = 0;
......@@ -1056,7 +1056,7 @@ static enum bp_result get_embedded_panel_info_v2_1(
info->ss_id = 0;
info->realtek_eDPToLVDS =
(lvds->dplvdsrxid == eDP_TO_LVDS_REALTEK_ID ? 1:0);
!!(lvds->dplvdsrxid == eDP_TO_LVDS_REALTEK_ID);
return BP_RESULT_OK;
}
......
......@@ -5,7 +5,7 @@
CFLAGS_dcn_calcs.o := -mhard-float -msse -mpreferred-stack-boundary=4
CFLAGS_dcn_calc_auto.o := -mhard-float -msse -mpreferred-stack-boundary=4
CFLAGS_dcn_calc_math.o := -mhard-float -msse -mpreferred-stack-boundary=4
CFLAGS_dcn_calc_math.o := -mhard-float -msse -mpreferred-stack-boundary=4 -Wno-tautological-compare
BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o
......
......@@ -25,6 +25,41 @@
#include "dcn_calc_math.h"
float dcn_bw_mod(const float arg1, const float arg2)
{
if (arg1 != arg1)
return arg2;
if (arg2 != arg2)
return arg1;
return arg1 - arg1 * ((int) (arg1 / arg2));
}
float dcn_bw_min2(const float arg1, const float arg2)
{
if (arg1 != arg1)
return arg2;
if (arg2 != arg2)
return arg1;
return arg1 < arg2 ? arg1 : arg2;
}
unsigned int dcn_bw_max(const unsigned int arg1, const unsigned int arg2)
{
if (arg1 != arg1)
return arg2;
if (arg2 != arg2)
return arg1;
return arg1 > arg2 ? arg1 : arg2;
}
float dcn_bw_max2(const float arg1, const float arg2)
{
if (arg1 != arg1)
return arg2;
if (arg2 != arg2)
return arg1;
return arg1 > arg2 ? arg1 : arg2;
}
float dcn_bw_floor2(const float arg, const float significance)
{
if (significance == 0)
......@@ -40,6 +75,16 @@ float dcn_bw_ceil2(const float arg, const float significance)
return flr + 0.00001 >= arg ? arg : flr + significance;
}
float dcn_bw_max3(float v1, float v2, float v3)
{
return v3 > dcn_bw_max2(v1, v2) ? v3 : dcn_bw_max2(v1, v2);
}
float dcn_bw_max5(float v1, float v2, float v3, float v4, float v5)
{
return dcn_bw_max3(v1, v2, v3) > dcn_bw_max2(v4, v5) ? dcn_bw_max3(v1, v2, v3) : dcn_bw_max2(v4, v5);
}
float dcn_bw_pow(float a, float exp)
{
float temp;
......
......@@ -26,38 +26,14 @@
#ifndef _DCN_CALC_MATH_H_
#define _DCN_CALC_MATH_H_
static inline float dcn_bw_mod(const float arg1, const float arg2)
{
return arg1 - arg1 * ((int) (arg1 / arg2));
}
static inline float dcn_bw_min2(const float arg1, const float arg2)
{
return arg1 < arg2 ? arg1 : arg2;
}
static inline unsigned int dcn_bw_max(const unsigned int arg1, const unsigned int arg2)
{
return arg1 > arg2 ? arg1 : arg2;
}
static inline float dcn_bw_max2(const float arg1, const float arg2)
{
return arg1 > arg2 ? arg1 : arg2;
}
static inline float dcn_bw_max3(float v1, float v2, float v3)
{
return v3 > dcn_bw_max2(v1, v2) ? v3 : dcn_bw_max2(v1, v2);
}
static inline float dcn_bw_max5(float v1, float v2, float v3, float v4, float v5)
{
return dcn_bw_max3(v1, v2, v3) > dcn_bw_max2(v4, v5) ? dcn_bw_max3(v1, v2, v3) : dcn_bw_max2(v4, v5);
}
float dcn_bw_mod(const float arg1, const float arg2);
float dcn_bw_min2(const float arg1, const float arg2);
unsigned int dcn_bw_max(const unsigned int arg1, const unsigned int arg2);
float dcn_bw_max2(const float arg1, const float arg2);
float dcn_bw_floor2(const float arg, const float significance);
float dcn_bw_ceil2(const float arg, const float significance);
float dcn_bw_max3(float v1, float v2, float v3);
float dcn_bw_max5(float v1, float v2, float v3, float v4, float v5);
float dcn_bw_pow(float a, float exp);
float dcn_bw_log(float a, float b);
......
......@@ -364,7 +364,8 @@ static void pipe_ctx_to_e2e_pipe_params (
}
input->dest.vactive = pipe->stream->timing.v_addressable;
input->dest.vactive = pipe->stream->timing.v_addressable + pipe->stream->timing.v_border_top
+ pipe->stream->timing.v_border_bottom;
input->dest.recout_width = pipe->plane_res.scl_data.recout.width;
input->dest.recout_height = pipe->plane_res.scl_data.recout.height;
......@@ -385,10 +386,6 @@ static void pipe_ctx_to_e2e_pipe_params (
- pipe->stream->timing.v_addressable
- pipe->stream->timing.v_border_bottom
- pipe->stream->timing.v_border_top;
input->dest.vsync_plus_back_porch = pipe->stream->timing.v_total
- pipe->stream->timing.v_addressable
- pipe->stream->timing.v_front_porch;
input->dest.pixel_rate_mhz = pipe->stream->timing.pix_clk_khz/1000.0;
input->dest.vstartup_start = pipe->pipe_dlg_param.vstartup_start;
input->dest.vupdate_offset = pipe->pipe_dlg_param.vupdate_offset;
......@@ -458,9 +455,9 @@ static void dcn_bw_calc_rq_dlg_ttu(
/*todo: soc->sr_enter_plus_exit_time??*/
dlg_sys_param.t_srx_delay_us = dc->dcn_ip->dcfclk_cstate_latency / v->dcf_clk_deep_sleep;
dml_rq_dlg_get_rq_params(dml, &rq_param, input.pipe.src);
extract_rq_regs(dml, rq_regs, rq_param);
dml_rq_dlg_get_dlg_params(
dml1_rq_dlg_get_rq_params(dml, &rq_param, input.pipe.src);
dml1_extract_rq_regs(dml, rq_regs, rq_param);
dml1_rq_dlg_get_dlg_params(
dml,
dlg_regs,
ttu_regs,
......@@ -473,96 +470,6 @@ static void dcn_bw_calc_rq_dlg_ttu(
pipe->plane_state->flip_immediate);
}
static void dcn_dml_wm_override(
const struct dcn_bw_internal_vars *v,
struct display_mode_lib *dml,
struct dc_state *context,
const struct resource_pool *pool)
{
int i, in_idx, active_count;
struct _vcs_dpi_display_e2e_pipe_params_st *input = kzalloc(pool->pipe_count * sizeof(struct _vcs_dpi_display_e2e_pipe_params_st),
GFP_KERNEL);
struct wm {
double urgent;
struct _vcs_dpi_cstate_pstate_watermarks_st cpstate;
double pte_meta_urgent;
} a;
for (i = 0, in_idx = 0; i < pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->stream || !pipe->plane_state)
continue;
input[in_idx].clks_cfg.dcfclk_mhz = v->dcfclk;
input[in_idx].clks_cfg.dispclk_mhz = v->dispclk;
input[in_idx].clks_cfg.dppclk_mhz = v->dppclk;
input[in_idx].clks_cfg.refclk_mhz = pool->ref_clock_inKhz / 1000;
input[in_idx].clks_cfg.socclk_mhz = v->socclk;
input[in_idx].clks_cfg.voltage = v->voltage_level;
input[in_idx].dout.output_format = (v->output_format[in_idx] == dcn_bw_420) ? dm_420 : dm_444;
input[in_idx].dout.output_type = (v->output[in_idx] == dcn_bw_hdmi) ? dm_hdmi : dm_dp;
//input[in_idx].dout.output_standard;
switch (v->output_deep_color[in_idx]) {
case dcn_bw_encoder_12bpc:
input[in_idx].dout.output_bpc = dm_out_12;
break;
case dcn_bw_encoder_10bpc:
input[in_idx].dout.output_bpc = dm_out_10;
break;
case dcn_bw_encoder_8bpc:
default:
input[in_idx].dout.output_bpc = dm_out_8;
break;
}
pipe_ctx_to_e2e_pipe_params(pipe, &input[in_idx].pipe);
dml_rq_dlg_get_rq_reg(
dml,
&pipe->rq_regs,
input[in_idx].pipe.src);
in_idx++;
}
active_count = in_idx;
a.urgent = dml_wm_urgent_e2e(dml, input, active_count);
a.cpstate = dml_wm_cstate_pstate_e2e(dml, input, active_count);
a.pte_meta_urgent = dml_wm_pte_meta_urgent(dml, a.urgent);
context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns =
a.cpstate.cstate_exit_us * 1000;
context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns =
a.cpstate.cstate_enter_plus_exit_us * 1000;
context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns =
a.cpstate.pstate_change_us * 1000;
context->bw.dcn.watermarks.a.pte_meta_urgent_ns = a.pte_meta_urgent * 1000;
context->bw.dcn.watermarks.a.urgent_ns = a.urgent * 1000;
context->bw.dcn.watermarks.b = context->bw.dcn.watermarks.a;
context->bw.dcn.watermarks.c = context->bw.dcn.watermarks.a;
context->bw.dcn.watermarks.d = context->bw.dcn.watermarks.a;
for (i = 0, in_idx = 0; i < pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
if (!pipe->stream || !pipe->plane_state)
continue;
dml_rq_dlg_get_dlg_reg(dml,
&pipe->dlg_regs,
&pipe->ttu_regs,
input, active_count,
in_idx,
true,
true,
v->pte_enable == dcn_bw_yes,
pipe->plane_state->flip_immediate);
in_idx++;
}
kfree(input);
}
static void split_stream_across_pipes(
struct resource_context *res_ctx,
const struct resource_pool *pool,
......@@ -578,8 +485,10 @@ static void split_stream_across_pipes(
secondary_pipe->pipe_idx = pipe_idx;
secondary_pipe->plane_res.mi = pool->mis[secondary_pipe->pipe_idx];
secondary_pipe->plane_res.hubp = pool->hubps[secondary_pipe->pipe_idx];
secondary_pipe->plane_res.ipp = pool->ipps[secondary_pipe->pipe_idx];
secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx];
secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx];
if (primary_pipe->bottom_pipe) {
ASSERT(primary_pipe->bottom_pipe != secondary_pipe);
secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe;
......@@ -719,6 +628,49 @@ static bool dcn_bw_apply_registry_override(struct dc *dc)
return updated;
}
void hack_disable_optional_pipe_split(struct dcn_bw_internal_vars *v)
{
/*
* disable optional pipe split by lower dispclk bounding box
* at DPM0
*/
v->max_dispclk[0] = v->max_dppclk_vmin0p65;
}
void hack_force_pipe_split(struct dcn_bw_internal_vars *v,
unsigned int pixel_rate_khz)
{
float pixel_rate_mhz = pixel_rate_khz / 1000;
/*
* force enabling pipe split by lower dpp clock for DPM0 to just
* below the specify pixel_rate, so bw calc would split pipe.
*/
if (pixel_rate_mhz < v->max_dppclk[0])
v->max_dppclk[0] = pixel_rate_mhz;
}
void hack_bounding_box(struct dcn_bw_internal_vars *v,
struct dc_debug *dbg,
struct dc_state *context)
{
if (dbg->pipe_split_policy == MPC_SPLIT_AVOID) {
hack_disable_optional_pipe_split(v);
}
if (dbg->pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP &&
context->stream_count >= 2) {
hack_disable_optional_pipe_split(v);
}
if (context->stream_count == 1 &&
dbg->force_single_disp_pipe_split) {
struct dc_stream_state *stream0 = context->streams[0];
hack_force_pipe_split(v, stream0->timing.pix_clk_khz);
}
}
bool dcn_validate_bandwidth(
struct dc *dc,
struct dc_state *context)
......@@ -730,6 +682,7 @@ bool dcn_validate_bandwidth(
bool bw_limit_pass;
float bw_limit;
PERFORMANCE_TRACE_START();
if (dcn_bw_apply_registry_override(dc))
dcn_bw_sync_calcs_and_dml(dc);
......@@ -850,9 +803,7 @@ bool dcn_validate_bandwidth(
v->phyclk_per_state[1] = v->phyclkv_mid0p72;
v->phyclk_per_state[0] = v->phyclkv_min0p65;
if (dc->debug.disable_pipe_split) {
v->max_dispclk[0] = v->max_dppclk_vmin0p65;
}
hack_bounding_box(v, &dc->debug, context);
if (v->voltage_override == dcn_bw_v_max0p9) {
v->voltage_override_level = number_of_states - 1;
......@@ -882,10 +833,11 @@ bool dcn_validate_bandwidth(
v->htotal[input_idx] = pipe->stream->timing.h_total;
v->vtotal[input_idx] = pipe->stream->timing.v_total;
v->vactive[input_idx] = pipe->stream->timing.v_addressable +
pipe->stream->timing.v_border_top + pipe->stream->timing.v_border_bottom;
v->v_sync_plus_back_porch[input_idx] = pipe->stream->timing.v_total
- pipe->stream->timing.v_addressable
- v->vactive[input_idx]
- pipe->stream->timing.v_front_porch;
v->vactive[input_idx] = pipe->stream->timing.v_addressable;
v->pixel_clock[input_idx] = pipe->stream->timing.pix_clk_khz / 1000.0f;
if (!pipe->plane_state) {
......@@ -1006,6 +958,10 @@ bool dcn_validate_bandwidth(
else
bw_consumed = v->fabric_and_dram_bandwidth_vmax0p9;
if (bw_consumed < v->fabric_and_dram_bandwidth)
if (dc->debug.voltage_align_fclk)
bw_consumed = v->fabric_and_dram_bandwidth;
display_pipe_configuration(v);
calc_wm_sets_and_perf_params(context, v);
context->bw.dcn.calc_clk.fclk_khz = (int)(bw_consumed * 1000000 /
......@@ -1018,9 +974,17 @@ bool dcn_validate_bandwidth(
context->bw.dcn.calc_clk.min_active_dram_ccm_us = (int)(v->min_active_dram_clock_change_margin);
context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = (int)(v->dcf_clk_deep_sleep * 1000);
context->bw.dcn.calc_clk.dcfclk_khz = (int)(v->dcfclk * 1000);
context->bw.dcn.calc_clk.dispclk_khz = (int)(v->dispclk * 1000);
if (dc->debug.max_disp_clk == true)
context->bw.dcn.calc_clk.dispclk_khz = (int)(dc->dcn_soc->max_dispclk_vmax0p9 * 1000);
if (context->bw.dcn.calc_clk.dispclk_khz <
dc->debug.min_disp_clk_khz) {
context->bw.dcn.calc_clk.dispclk_khz =
dc->debug.min_disp_clk_khz;
}
context->bw.dcn.calc_clk.dppclk_div = (int)(v->dispclk_dppclk_ratio) == 2;
for (i = 0, input_idx = 0; i < pool->pipe_count; i++) {
......@@ -1108,9 +1072,6 @@ bool dcn_validate_bandwidth(
input_idx++;
}
if (dc->debug.use_dml_wm)
dcn_dml_wm_override(v, (struct display_mode_lib *)
&dc->dml, context, pool);
}
if (v->voltage_level == 0) {
......@@ -1129,6 +1090,8 @@ bool dcn_validate_bandwidth(
kernel_fpu_end();
PERFORMANCE_TRACE_END();
if (bw_limit_pass && v->voltage_level != 5)
return true;
else
......@@ -1263,7 +1226,7 @@ unsigned int dcn_find_dcfclk_suits_all(
else
dcf_clk = dc->dcn_soc->dcfclkv_min0p65*1000;
dm_logger_write(dc->ctx->logger, LOG_HW_MARKS,
dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS,
"\tdcf_clk for voltage = %d\n", dcf_clk);
return dcf_clk;
}
......@@ -1386,6 +1349,53 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
ranges.writer_wm_sets[3].min_drain_clk_khz = max_fclk_khz;
ranges.writer_wm_sets[3].max_drain_clk_khz = max_fclk_khz;
if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
ranges.reader_wm_sets[0].wm_inst = WM_A;
ranges.reader_wm_sets[0].min_drain_clk_khz = 300000;
ranges.reader_wm_sets[0].max_drain_clk_khz = 654000;
ranges.reader_wm_sets[0].min_fill_clk_khz = 800000;
ranges.reader_wm_sets[0].max_fill_clk_khz = 800000;
ranges.writer_wm_sets[0].wm_inst = WM_A;
ranges.writer_wm_sets[0].min_fill_clk_khz = 200000;
ranges.writer_wm_sets[0].max_fill_clk_khz = 757000;
ranges.writer_wm_sets[0].min_drain_clk_khz = 800000;
ranges.writer_wm_sets[0].max_drain_clk_khz = 800000;
ranges.reader_wm_sets[1].wm_inst = WM_B;
ranges.reader_wm_sets[1].min_drain_clk_khz = 300000;
ranges.reader_wm_sets[1].max_drain_clk_khz = 654000;
ranges.reader_wm_sets[1].min_fill_clk_khz = 933000;
ranges.reader_wm_sets[1].max_fill_clk_khz = 933000;
ranges.writer_wm_sets[1].wm_inst = WM_B;
ranges.writer_wm_sets[1].min_fill_clk_khz = 200000;
ranges.writer_wm_sets[1].max_fill_clk_khz = 757000;
ranges.writer_wm_sets[1].min_drain_clk_khz = 933000;
ranges.writer_wm_sets[1].max_drain_clk_khz = 933000;
ranges.reader_wm_sets[2].wm_inst = WM_C;
ranges.reader_wm_sets[2].min_drain_clk_khz = 300000;
ranges.reader_wm_sets[2].max_drain_clk_khz = 654000;
ranges.reader_wm_sets[2].min_fill_clk_khz = 1067000;
ranges.reader_wm_sets[2].max_fill_clk_khz = 1067000;
ranges.writer_wm_sets[2].wm_inst = WM_C;
ranges.writer_wm_sets[2].min_fill_clk_khz = 200000;
ranges.writer_wm_sets[2].max_fill_clk_khz = 757000;
ranges.writer_wm_sets[2].min_drain_clk_khz = 1067000;
ranges.writer_wm_sets[2].max_drain_clk_khz = 1067000;
ranges.reader_wm_sets[3].wm_inst = WM_D;
ranges.reader_wm_sets[3].min_drain_clk_khz = 300000;
ranges.reader_wm_sets[3].max_drain_clk_khz = 654000;
ranges.reader_wm_sets[3].min_fill_clk_khz = 1200000;
ranges.reader_wm_sets[3].max_fill_clk_khz = 1200000;
ranges.writer_wm_sets[3].wm_inst = WM_D;
ranges.writer_wm_sets[3].min_fill_clk_khz = 200000;
ranges.writer_wm_sets[3].max_fill_clk_khz = 757000;
ranges.writer_wm_sets[3].min_drain_clk_khz = 1200000;
ranges.writer_wm_sets[3].max_drain_clk_khz = 1200000;
}
/* Notify PP Lib/SMU which Watermarks to use for which clock ranges */
pp->set_wm_ranges(&pp->pp_smu, &ranges);
}
......
......@@ -38,6 +38,7 @@
#include "bios_parser_interface.h"
#include "include/irq_service_interface.h"
#include "transform.h"
#include "dpp.h"
#include "timing_generator.h"
#include "virtual/virtual_link_encoder.h"
......@@ -47,6 +48,7 @@
#include "dc_link_ddc.h"
#include "dm_helpers.h"
#include "mem_input.h"
#include "hubp.h"
/*******************************************************************************
......@@ -332,10 +334,19 @@ static void set_dither_option(struct dc_stream_state *stream,
{
struct bit_depth_reduction_params params;
struct dc_link *link = stream->status.link;
struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
struct pipe_ctx *pipes = NULL;
int i;
for (i = 0; i < MAX_PIPES; i++) {
if (link->dc->current_state->res_ctx.pipe_ctx[i].stream ==
stream) {
pipes = &link->dc->current_state->res_ctx.pipe_ctx[i];
break;
}
}
memset(&params, 0, sizeof(params));
if (!stream)
if (!pipes)
return;
if (option > DITHER_OPTION_MAX)
return;
......@@ -349,6 +360,36 @@ static void set_dither_option(struct dc_stream_state *stream,
opp_program_bit_depth_reduction(pipes->stream_res.opp, &params);
}
void set_dpms(
struct dc *dc,
struct dc_stream_state *stream,
bool dpms_off)
{
struct pipe_ctx *pipe_ctx = NULL;
int i;
for (i = 0; i < MAX_PIPES; i++) {
if (dc->current_state->res_ctx.pipe_ctx[i].stream == stream) {
pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
break;
}
}
if (!pipe_ctx) {
ASSERT(0);
return;
}
if (stream->dpms_off != dpms_off) {
stream->dpms_off = dpms_off;
if (dpms_off)
core_link_disable_stream(pipe_ctx,
KEEP_ACQUIRED_RESOURCE);
else
core_link_enable_stream(dc->current_state, pipe_ctx);
}
}
static void allocate_dc_stream_funcs(struct dc *dc)
{
if (dc->hwss.set_drr != NULL) {
......@@ -371,6 +412,9 @@ static void allocate_dc_stream_funcs(struct dc *dc)
dc->stream_funcs.set_dither_option =
set_dither_option;
dc->stream_funcs.set_dpms =
set_dpms;
dc->link_funcs.set_drive_settings =
set_drive_settings;
......@@ -507,7 +551,7 @@ static bool construct(struct dc *dc,
dc_version = resource_parse_asic_id(init_params->asic_id);
dc->ctx->dce_version = dc_version;
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
dc->ctx->fbc_gpu_addr = init_params->fbc_gpu_addr;
#endif
/* Resource should construct all asic specific resources.
......@@ -749,7 +793,7 @@ bool dc_enable_stereo(
* Applies given context to HW and copy it into current context.
* It's up to the user to release the src context afterwards.
*/
static bool dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
{
struct dc_bios *dcb = dc->ctx->dc_bios;
enum dc_status result = DC_ERROR_UNEXPECTED;
......@@ -763,41 +807,31 @@ static bool dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
if (!dcb->funcs->is_accelerated_mode(dcb))
dc->hwss.enable_accelerated_mode(dc);
dc->hwss.ready_shared_resources(dc);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
}
result = dc->hwss.apply_ctx_to_hw(dc, context);
program_timing_sync(dc, context);
for (i = 0; i < context->stream_count; i++) {
const struct dc_sink *sink = context->streams[i]->sink;
for (j = 0; j < context->stream_status[i].plane_count; j++) {
dc->hwss.apply_ctx_for_surface(
dc, context->streams[i],
context->stream_status[i].plane_count,
context);
dc->hwss.apply_ctx_for_surface(
dc, context->streams[i],
context->stream_status[i].plane_count,
context);
/*
* enable stereo
* TODO rework dc_enable_stereo call to work with validation sets?
*/
for (k = 0; k < MAX_PIPES; k++) {
pipe = &context->res_ctx.pipe_ctx[k];
for (l = 0 ; pipe && l < context->stream_count; l++) {
if (context->streams[l] &&
context->streams[l] == pipe->stream &&
dc->hwss.setup_stereo)
dc->hwss.setup_stereo(pipe, dc);
}
/*
* enable stereo
* TODO rework dc_enable_stereo call to work with validation sets?
*/
for (k = 0; k < MAX_PIPES; k++) {
pipe = &context->res_ctx.pipe_ctx[k];
for (l = 0 ; pipe && l < context->stream_count; l++) {
if (context->streams[l] &&
context->streams[l] == pipe->stream &&
dc->hwss.setup_stereo)
dc->hwss.setup_stereo(pipe, dc);
}
}
CONN_MSG_MODE(sink->link, "{%dx%d, %dx%d@%dKhz}",
context->streams[i]->timing.h_addressable,
context->streams[i]->timing.v_addressable,
......@@ -806,8 +840,27 @@ static bool dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
context->streams[i]->timing.pix_clk_khz);
}
dc->hwss.ready_shared_resources(dc, context);
for (i = 0; i < dc->res_pool->pipe_count; i++) {
pipe = &context->res_ctx.pipe_ctx[i];
dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe);
}
result = dc->hwss.apply_ctx_to_hw(dc, context);
program_timing_sync(dc, context);
dc_enable_stereo(dc, context, dc_streams, context->stream_count);
for (i = 0; i < context->stream_count; i++) {
for (j = 0; j < MAX_PIPES; j++) {
pipe = &context->res_ctx.pipe_ctx[j];
if (!pipe->top_pipe && pipe->stream == context->streams[i])
dc->hwss.pipe_control_lock(dc, pipe, false);
}
}
dc_release_state(dc->current_state);
dc->current_state = context;
......@@ -816,7 +869,7 @@ static bool dc_commit_state_no_check(struct dc *dc, struct dc_state *context)
dc->hwss.optimize_shared_resources(dc);
return (result == DC_OK);
return result;
}
bool dc_commit_state(struct dc *dc, struct dc_state *context)
......@@ -865,16 +918,24 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
return true;
}
/*
* TODO this whole function needs to go
*
* dc_surface_update is needlessly complex. See if we can just replace this
* with a dc_plane_state and follow the atomic model a bit more closely here.
*/
bool dc_commit_planes_to_stream(
struct dc *dc,
struct dc_plane_state **plane_states,
uint8_t new_plane_count,
struct dc_stream_state *dc_stream)
struct dc_stream_state *dc_stream,
struct dc_state *state)
{
/* no need to dynamically allocate this. it's pretty small */
struct dc_surface_update updates[MAX_SURFACES];
struct dc_flip_addrs flip_addr[MAX_SURFACES];
struct dc_plane_info plane_info[MAX_SURFACES];
struct dc_scaling_info scaling_info[MAX_SURFACES];
struct dc_flip_addrs *flip_addr;
struct dc_plane_info *plane_info;
struct dc_scaling_info *scaling_info;
int i;
struct dc_stream_update *stream_update =
kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
......@@ -884,10 +945,14 @@ bool dc_commit_planes_to_stream(
return false;
}
flip_addr = kcalloc(MAX_SURFACES, sizeof(struct dc_flip_addrs),
GFP_KERNEL);
plane_info = kcalloc(MAX_SURFACES, sizeof(struct dc_plane_info),
GFP_KERNEL);
scaling_info = kcalloc(MAX_SURFACES, sizeof(struct dc_scaling_info),
GFP_KERNEL);
memset(updates, 0, sizeof(updates));
memset(flip_addr, 0, sizeof(flip_addr));
memset(plane_info, 0, sizeof(plane_info));
memset(scaling_info, 0, sizeof(scaling_info));
stream_update->src = dc_stream->src;
stream_update->dst = dc_stream->dst;
......@@ -920,14 +985,15 @@ bool dc_commit_planes_to_stream(
updates[i].scaling_info = &scaling_info[i];
}
dc_update_planes_and_stream(
dc_commit_updates_for_stream(
dc,
updates,
new_plane_count,
dc_stream, stream_update);
dc_post_update_surfaces_to_stream(dc);
dc_stream, stream_update, plane_states, state);
kfree(flip_addr);
kfree(plane_info);
kfree(scaling_info);
kfree(stream_update);
return true;
}
......@@ -1030,7 +1096,6 @@ static enum surface_update_type get_plane_info_update_type(
temp_plane_info.plane_size = u->surface->plane_size;
temp_plane_info.rotation = u->surface->rotation;
temp_plane_info.stereo_format = u->surface->stereo_format;
temp_plane_info.tiling_info = u->surface->tiling_info;
if (surface_index == 0)
temp_plane_info.visible = u->plane_info->visible;
......@@ -1043,10 +1108,26 @@ static enum surface_update_type get_plane_info_update_type(
if (pixel_format_to_bpp(u->plane_info->format) !=
pixel_format_to_bpp(u->surface->format)) {
/* different bytes per element will require full bandwidth
* and DML calculation
*/
return UPDATE_TYPE_FULL;
} else {
return UPDATE_TYPE_MED;
}
if (memcmp(&u->plane_info->tiling_info, &u->surface->tiling_info,
sizeof(union dc_tiling_info)) != 0) {
/* todo: below are HW dependent, we should add a hook to
* DCE/N resource and validated there.
*/
if (u->plane_info->tiling_info.gfx9.swizzle != DC_SW_LINEAR) {
/* swizzled mode requires RQ to be setup properly,
* thus need to run DML to calculate RQ settings
*/
return UPDATE_TYPE_FULL;
}
}
return UPDATE_TYPE_MED;
}
static enum surface_update_type get_scaling_info_update_type(
......@@ -1150,192 +1231,20 @@ static struct dc_stream_status *stream_get_status(
static const enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
void dc_update_planes_and_stream(struct dc *dc,
struct dc_surface_update *srf_updates, int surface_count,
static void commit_planes_for_stream(struct dc *dc,
struct dc_surface_update *srf_updates,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update)
struct dc_stream_update *stream_update,
enum surface_update_type update_type,
struct dc_state *context)
{
struct dc_state *context;
int i, j;
enum surface_update_type update_type;
const struct dc_stream_status *stream_status;
struct dc_context *dc_ctx = dc->ctx;
stream_status = dc_stream_get_status(stream);
ASSERT(stream_status);
if (!stream_status)
return; /* Cannot commit surface to stream that is not committed */
#ifdef ENABLE_FBC
if (srf_updates->flip_addr) {
if (srf_updates->flip_addr->address.grph.addr.low_part == 0)
ASSERT(0);
}
#endif
context = dc->current_state;
/* update current stream with the new updates */
if (stream_update) {
if ((stream_update->src.height != 0) &&
(stream_update->src.width != 0))
stream->src = stream_update->src;
if ((stream_update->dst.height != 0) &&
(stream_update->dst.width != 0))
stream->dst = stream_update->dst;
if (stream_update->out_transfer_func &&
stream_update->out_transfer_func !=
stream->out_transfer_func) {
if (stream->out_transfer_func != NULL)
dc_transfer_func_release(stream->out_transfer_func);
dc_transfer_func_retain(stream_update->out_transfer_func);
stream->out_transfer_func =
stream_update->out_transfer_func;
}
}
/* do not perform surface update if surface has invalid dimensions
* (all zero) and no scaling_info is provided
*/
if (surface_count > 0 &&
srf_updates->surface->src_rect.width == 0 &&
srf_updates->surface->src_rect.height == 0 &&
srf_updates->surface->dst_rect.width == 0 &&
srf_updates->surface->dst_rect.height == 0 &&
!srf_updates->scaling_info) {
ASSERT(false);
return;
}
update_type = dc_check_update_surfaces_for_stream(
dc, srf_updates, surface_count, stream_update, stream_status);
if (update_type >= update_surface_trace_level)
update_surface_trace(dc, srf_updates, surface_count);
if (update_type >= UPDATE_TYPE_FULL) {
struct dc_plane_state *new_planes[MAX_SURFACES] = {0};
for (i = 0; i < surface_count; i++)
new_planes[i] = srf_updates[i].surface;
/* initialize scratch memory for building context */
context = dc_create_state();
if (context == NULL) {
DC_ERROR("Failed to allocate new validate context!\n");
return;
}
dc_resource_state_copy_construct(
dc->current_state, context);
/*remove old surfaces from context */
if (!dc_rem_all_planes_for_stream(dc, stream, context)) {
BREAK_TO_DEBUGGER();
goto fail;
}
/* add surface to context */
if (!dc_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) {
BREAK_TO_DEBUGGER();
goto fail;
}
}
/* save update parameters into surface */
for (i = 0; i < surface_count; i++) {
struct dc_plane_state *surface = srf_updates[i].surface;
if (srf_updates[i].flip_addr) {
surface->address = srf_updates[i].flip_addr->address;
surface->flip_immediate =
srf_updates[i].flip_addr->flip_immediate;
}
if (srf_updates[i].scaling_info) {
surface->scaling_quality =
srf_updates[i].scaling_info->scaling_quality;
surface->dst_rect =
srf_updates[i].scaling_info->dst_rect;
surface->src_rect =
srf_updates[i].scaling_info->src_rect;
surface->clip_rect =
srf_updates[i].scaling_info->clip_rect;
}
if (srf_updates[i].plane_info) {
surface->color_space =
srf_updates[i].plane_info->color_space;
surface->format =
srf_updates[i].plane_info->format;
surface->plane_size =
srf_updates[i].plane_info->plane_size;
surface->rotation =
srf_updates[i].plane_info->rotation;
surface->horizontal_mirror =
srf_updates[i].plane_info->horizontal_mirror;
surface->stereo_format =
srf_updates[i].plane_info->stereo_format;
surface->tiling_info =
srf_updates[i].plane_info->tiling_info;
surface->visible =
srf_updates[i].plane_info->visible;
surface->per_pixel_alpha =
srf_updates[i].plane_info->per_pixel_alpha;
surface->dcc =
srf_updates[i].plane_info->dcc;
}
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);
}
}
if (srf_updates[i].gamma &&
srf_updates[i].gamma != surface->gamma_correction) {
if (surface->gamma_correction != NULL)
dc_gamma_release(&surface->gamma_correction);
dc_gamma_retain(srf_updates[i].gamma);
surface->gamma_correction = srf_updates[i].gamma;
}
if (srf_updates[i].in_transfer_func &&
srf_updates[i].in_transfer_func != surface->in_transfer_func) {
if (surface->in_transfer_func != NULL)
dc_transfer_func_release(
surface->
in_transfer_func);
dc_transfer_func_retain(
srf_updates[i].in_transfer_func);
surface->in_transfer_func =
srf_updates[i].in_transfer_func;
}
if (srf_updates[i].hdr_static_metadata)
surface->hdr_static_ctx =
*(srf_updates[i].hdr_static_metadata);
}
if (update_type == UPDATE_TYPE_FULL) {
if (!dc->res_pool->funcs->validate_bandwidth(dc, context)) {
BREAK_TO_DEBUGGER();
goto fail;
} else {
dc->hwss.set_bandwidth(dc, context, false);
context_clock_trace(dc, context);
}
dc->hwss.set_bandwidth(dc, context, false);
context_clock_trace(dc, context);
}
if (update_type > UPDATE_TYPE_FAST) {
......@@ -1346,8 +1255,14 @@ void dc_update_planes_and_stream(struct dc *dc,
}
}
if (surface_count == 0)
if (surface_count == 0) {
/*
* In case of turning off screen, no need to program front end a second time.
* just return after program front end.
*/
dc->hwss.apply_ctx_for_surface(dc, stream, surface_count, context);
return;
}
/* Lock pipes for provided surfaces, or all active if full update*/
for (i = 0; i < surface_count; i++) {
......@@ -1373,10 +1288,6 @@ void dc_update_planes_and_stream(struct dc *dc,
/* Full fe update*/
for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
struct pipe_ctx *cur_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[j];
bool is_new_pipe_surface = cur_pipe_ctx->plane_state != pipe_ctx->plane_state;
struct dc_cursor_position position = { 0 };
if (update_type != UPDATE_TYPE_FULL || !pipe_ctx->plane_state)
continue;
......@@ -1387,17 +1298,6 @@ void dc_update_planes_and_stream(struct dc *dc,
dc->hwss.apply_ctx_for_surface(
dc, pipe_ctx->stream, stream_status->plane_count, context);
}
/* TODO: this is a hack w/a for switching from mpo to pipe split */
dc_stream_set_cursor_position(pipe_ctx->stream, &position);
if (is_new_pipe_surface) {
dc->hwss.update_plane_addr(dc, pipe_ctx);
dc->hwss.set_input_transfer_func(
pipe_ctx, pipe_ctx->plane_state);
dc->hwss.set_output_transfer_func(
pipe_ctx, pipe_ctx->stream);
}
}
if (update_type > UPDATE_TYPE_FAST)
......@@ -1423,7 +1323,9 @@ void dc_update_planes_and_stream(struct dc *dc,
if (update_type == UPDATE_TYPE_FAST)
continue;
if (srf_updates[i].in_transfer_func)
/* work around to program degamma regs for split pipe after set mode. */
if (srf_updates[i].in_transfer_func || (pipe_ctx->top_pipe &&
pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state))
dc->hwss.set_input_transfer_func(
pipe_ctx, pipe_ctx->plane_state);
......@@ -1459,16 +1361,79 @@ void dc_update_planes_and_stream(struct dc *dc,
break;
}
}
}
if (dc->current_state != context) {
void dc_commit_updates_for_stream(struct dc *dc,
struct dc_surface_update *srf_updates,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
struct dc_plane_state **plane_states,
struct dc_state *state)
{
const struct dc_stream_status *stream_status;
enum surface_update_type update_type;
struct dc_state *context;
struct dc_context *dc_ctx = dc->ctx;
int i, j;
stream_status = dc_stream_get_status(stream);
context = dc->current_state;
update_type = dc_check_update_surfaces_for_stream(
dc, srf_updates, surface_count, stream_update, stream_status);
if (update_type >= update_surface_trace_level)
update_surface_trace(dc, srf_updates, surface_count);
if (update_type >= UPDATE_TYPE_FULL) {
/* initialize scratch memory for building context */
context = dc_create_state();
if (context == NULL) {
DC_ERROR("Failed to allocate new validate context!\n");
return;
}
dc_resource_state_copy_construct(state, context);
}
for (i = 0; i < surface_count; i++) {
struct dc_plane_state *surface = srf_updates[i].surface;
/* Since memory free requires elevated IRQL, an interrupt
* request is generated by mem free. If this happens
* between freeing and reassigning the context, our vsync
* interrupt will call into dc and cause a memory
* corruption BSOD. Hence, we first reassign the context,
* then free the old context.
/* TODO: On flip we don't build the state, so it still has the
* old address. Which is why we are updating the address here
*/
if (srf_updates[i].flip_addr)
surface->address = srf_updates[i].flip_addr->address;
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);
}
}
}
commit_planes_for_stream(
dc,
srf_updates,
surface_count,
stream,
stream_update,
update_type,
context);
if (update_type >= UPDATE_TYPE_FULL)
dc_post_update_surfaces_to_stream(dc);
if (dc->current_state != context) {
struct dc_state *old = dc->current_state;
......@@ -1476,10 +1441,9 @@ void dc_update_planes_and_stream(struct dc *dc,
dc_release_state(old);
}
return;
fail:
dc_release_state(context);
}
uint8_t dc_get_current_stream_count(struct dc *dc)
......
......@@ -45,6 +45,7 @@
#include "dce/dce_11_0_enum.h"
#include "dce/dce_11_0_sh_mask.h"
#define EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK 0x007C /* Copied from atombios.h */
#define LINK_INFO(...) \
dm_logger_write(dc_ctx->logger, LOG_HW_HOTPLUG, \
__VA_ARGS__)
......@@ -78,14 +79,15 @@ static void destruct(struct dc_link *link)
dc_sink_release(link->remote_sinks[i]);
}
static struct gpio *get_hpd_gpio(const struct dc_link *link)
struct gpio *get_hpd_gpio(struct dc_bios *dcb,
struct graphics_object_id link_id,
struct gpio_service *gpio_service)
{
enum bp_result bp_result;
struct dc_bios *dcb = link->ctx->dc_bios;
struct graphics_object_hpd_info hpd_info;
struct gpio_pin_info pin_info;
if (dcb->funcs->get_hpd_info(dcb, link->link_id, &hpd_info) != BP_RESULT_OK)
if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)
return NULL;
bp_result = dcb->funcs->get_gpio_pin_info(dcb,
......@@ -97,7 +99,7 @@ static struct gpio *get_hpd_gpio(const struct dc_link *link)
}
return dal_gpio_service_create_irq(
link->ctx->gpio_service,
gpio_service,
pin_info.offset,
pin_info.mask);
}
......@@ -153,7 +155,7 @@ static bool program_hpd_filter(
}
/* Obtain HPD handle */
hpd = get_hpd_gpio(link);
hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
if (!hpd)
return result;
......@@ -186,7 +188,7 @@ static bool detect_sink(struct dc_link *link, enum dc_connection_type *type)
struct gpio *hpd_pin;
/* todo: may need to lock gpio access */
hpd_pin = get_hpd_gpio(link);
hpd_pin = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
if (hpd_pin == NULL)
goto hpd_gpio_failure;
......@@ -496,6 +498,7 @@ static void detect_dp(
}
if (is_mst_supported(link)) {
sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
link->type = dc_connection_mst_branch;
/*
* This call will initiate MST topology discovery. Which
......@@ -524,12 +527,11 @@ static void detect_dp(
if (reason == DETECT_REASON_BOOT)
boot = true;
if (dm_helpers_dp_mst_start_top_mgr(
if (!dm_helpers_dp_mst_start_top_mgr(
link->ctx,
link, boot)) {
link->type = dc_connection_mst_branch;
} else {
/* MST not supported */
link->type = dc_connection_single;
sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;
}
}
......@@ -638,8 +640,8 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
if (link->dpcd_caps.sink_count.bits.SINK_COUNT)
link->dpcd_sink_count = link->dpcd_caps.sink_count.
bits.SINK_COUNT;
else
link->dpcd_sink_count = 1;
else
link->dpcd_sink_count = 1;
dal_ddc_service_set_transaction_type(
link->ddc,
......@@ -746,6 +748,7 @@ bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
if (link->type == dc_connection_mst_branch) {
LINK_INFO("link=%d, mst branch is now Disconnected\n",
link->link_index);
dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
link->mst_stream_alloc_table.stream_count = 0;
......@@ -770,7 +773,7 @@ static enum hpd_source_id get_hpd_line(
struct gpio *hpd;
enum hpd_source_id hpd_id = HPD_SOURCEID_UNKNOWN;
hpd = get_hpd_gpio(link);
hpd = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
if (hpd) {
switch (dal_irq_get_source(hpd)) {
......@@ -940,7 +943,7 @@ static bool construct(
goto create_fail;
}
hpd_gpio = get_hpd_gpio(link);
hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);
if (hpd_gpio != NULL)
link->irq_source_hpd = dal_irq_get_source(hpd_gpio);
......@@ -1343,7 +1346,18 @@ static bool get_ext_hdmi_settings(struct pipe_ctx *pipe_ctx,
sizeof(integrated_info->dp2_ext_hdmi_6g_reg_settings));
result = true;
break;
case ENGINE_ID_DIGD:
settings->slv_addr = integrated_info->dp3_ext_hdmi_slv_addr;
settings->reg_num = integrated_info->dp3_ext_hdmi_6g_reg_num;
settings->reg_num_6g = integrated_info->dp3_ext_hdmi_6g_reg_num;
memmove(settings->reg_settings,
integrated_info->dp3_ext_hdmi_reg_settings,
sizeof(integrated_info->dp3_ext_hdmi_reg_settings));
memmove(settings->reg_settings_6g,
integrated_info->dp3_ext_hdmi_6g_reg_settings,
sizeof(integrated_info->dp3_ext_hdmi_6g_reg_settings));
result = true;
break;
default:
break;
}
......@@ -1680,7 +1694,9 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
is_over_340mhz = true;
if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
if ((pipe_ctx->stream->sink->link->chip_caps >> 2) == 0x2) {
unsigned short masked_chip_caps = pipe_ctx->stream->sink->link->chip_caps &
EXT_DISPLAY_PATH_CAPS__EXT_CHIP_MASK;
if (masked_chip_caps == (0x2 << 2)) {
/* DP159, Retimer settings */
eng_id = pipe_ctx->stream_res.stream_enc->id;
......@@ -1691,7 +1707,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
write_i2c_default_retimer_setting(pipe_ctx,
is_vga_mode, is_over_340mhz);
}
} else if ((pipe_ctx->stream->sink->link->chip_caps >> 2) == 0x1) {
} else if (masked_chip_caps == (0x1 << 2)) {
/* PI3EQX1204, Redriver settings */
write_i2c_redriver_setting(pipe_ctx, is_over_340mhz);
}
......@@ -1782,7 +1798,7 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
else
dp_disable_link_phy_mst(link, signal);
} else
link->link_enc->funcs->disable_output(link->link_enc, signal);
link->link_enc->funcs->disable_output(link->link_enc, signal, link);
}
enum dc_status dc_link_validate_mode_timing(
......@@ -2319,16 +2335,20 @@ void core_link_enable_stream(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
allocate_mst_payload(pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
core_dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->sink->link->cur_link_settings);
}
void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
void core_link_disable_stream(struct pipe_ctx *pipe_ctx, int option)
{
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
deallocate_mst_payload(pipe_ctx);
core_dc->hwss.disable_stream(pipe_ctx);
core_dc->hwss.disable_stream(pipe_ctx, option);
disable_link(pipe_ctx->stream->sink->link, pipe_ctx->stream->signal);
}
......
......@@ -1700,6 +1700,12 @@ static void dp_test_send_link_training(struct dc_link *link)
dp_retrain_link_dp_test(link, &link_settings, false);
}
/* TODO hbr2 compliance eye output is unstable
* (toggling on and off) with debugger break
* This caueses intermittent PHY automation failure
* Need to look into the root cause */
static uint8_t force_tps4_for_cp2520 = 1;
static void dp_test_send_phy_test_pattern(struct dc_link *link)
{
union phy_test_pattern dpcd_test_pattern;
......@@ -1758,10 +1764,16 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
break;
case PHY_TEST_PATTERN_CP2520_1:
test_pattern = DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
/* CP2520 pattern is unstable, temporarily use TPS4 instead */
test_pattern = (force_tps4_for_cp2520 == 1) ?
DP_TEST_PATTERN_TRAINING_PATTERN4 :
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
break;
case PHY_TEST_PATTERN_CP2520_2:
test_pattern = DP_TEST_PATTERN_CP2520_2;
/* CP2520 pattern is unstable, temporarily use TPS4 instead */
test_pattern = (force_tps4_for_cp2520 == 1) ?
DP_TEST_PATTERN_TRAINING_PATTERN4 :
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
break;
case PHY_TEST_PATTERN_CP2520_3:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
......
......@@ -89,12 +89,12 @@ void dp_enable_link_phy(
if (dc_is_dp_sst_signal(signal)) {
if (signal == SIGNAL_TYPE_EDP) {
link_enc->funcs->power_control(link_enc, true);
link->dc->hwss.edp_power_control(link->link_enc, true);
link_enc->funcs->enable_dp_output(
link_enc,
link_settings,
clock_source);
link_enc->funcs->backlight_control(link_enc, true);
link->dc->hwss.edp_backlight_control(link, true);
} else
link_enc->funcs->enable_dp_output(
link_enc,
......@@ -138,12 +138,12 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal)
dp_receiver_power_ctrl(link, false);
if (signal == SIGNAL_TYPE_EDP) {
link->link_enc->funcs->backlight_control(link->link_enc, false);
link->dc->hwss.edp_backlight_control(link, false);
edp_receiver_ready_T9(link);
link->link_enc->funcs->disable_output(link->link_enc, signal);
link->link_enc->funcs->power_control(link->link_enc, false);
link->link_enc->funcs->disable_output(link->link_enc, signal, link);
link->dc->hwss.edp_power_control(link->link_enc, false);
} else
link->link_enc->funcs->disable_output(link->link_enc, signal);
link->link_enc->funcs->disable_output(link->link_enc, signal, link);
/* Clear current link setting.*/
memset(&link->cur_link_settings, 0,
......@@ -282,11 +282,12 @@ void dp_retrain_link_dp_test(struct dc_link *link,
dp_receiver_power_ctrl(link, false);
link->dc->hwss.disable_stream(&pipes[i]);
link->dc->hwss.disable_stream(&pipes[i], KEEP_ACQUIRED_RESOURCE);
link->link_enc->funcs->disable_output(
link->link_enc,
SIGNAL_TYPE_DISPLAY_PORT);
SIGNAL_TYPE_DISPLAY_PORT,
link);
/* Clear current link setting. */
memset(&link->cur_link_settings, 0,
......
......@@ -31,6 +31,7 @@
#include "opp.h"
#include "timing_generator.h"
#include "transform.h"
#include "dpp.h"
#include "core_types.h"
#include "set_mode_types.h"
#include "virtual/virtual_stream_encoder.h"
......@@ -242,7 +243,10 @@ bool resource_construct(
pool->stream_enc_count++;
}
}
dc->caps.dynamic_audio = false;
if (pool->audio_count < pool->stream_enc_count) {
dc->caps.dynamic_audio = true;
}
for (i = 0; i < num_virtual_links; i++) {
pool->stream_enc[pool->stream_enc_count] =
virtual_stream_encoder_create(
......@@ -846,12 +850,20 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
*/
pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable;
pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable;
pipe_ctx->plane_res.scl_data.recout.x += timing->h_border_left;
pipe_ctx->plane_res.scl_data.recout.y += timing->v_border_top;
pipe_ctx->plane_res.scl_data.h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
pipe_ctx->plane_res.scl_data.v_active = timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
/* Taps calculations */
res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
if (pipe_ctx->plane_res.xfm != NULL)
res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
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) {
/* Try 24 bpp linebuffer */
......@@ -859,6 +871,9 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
res = pipe_ctx->plane_res.xfm->funcs->transform_get_optimal_number_of_taps(
pipe_ctx->plane_res.xfm, &pipe_ctx->plane_res.scl_data, &plane_state->scaling_quality);
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)
......@@ -1021,9 +1036,9 @@ static int acquire_first_split_pipe(
memset(pipe_ctx, 0, sizeof(*pipe_ctx));
pipe_ctx->stream_res.tg = pool->timing_generators[i];
pipe_ctx->plane_res.mi = pool->mis[i];
pipe_ctx->plane_res.hubp = pool->hubps[i];
pipe_ctx->plane_res.ipp = pool->ipps[i];
pipe_ctx->plane_res.xfm = pool->transforms[i];
pipe_ctx->plane_res.dpp = pool->dpps[i];
pipe_ctx->stream_res.opp = pool->opps[i];
pipe_ctx->pipe_idx = i;
......@@ -1070,9 +1085,6 @@ bool dc_add_plane_to_context(
return false;
}
/* retain new surfaces */
dc_plane_state_retain(plane_state);
free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
......@@ -1082,11 +1094,11 @@ bool dc_add_plane_to_context(
free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
}
#endif
if (!free_pipe) {
stream_status->plane_states[i] = NULL;
if (!free_pipe)
return false;
}
/* retain new surfaces */
dc_plane_state_retain(plane_state);
free_pipe->plane_state = plane_state;
if (head_pipe != free_pipe) {
......@@ -1178,8 +1190,8 @@ bool dc_remove_plane_from_context(
stream_status->plane_count--;
/* Trim back arrays */
for (i = 0; i < stream_status->plane_count; i++)
/* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */
for (; i < stream_status->plane_count; i++)
stream_status->plane_states[i] = stream_status->plane_states[i + 1];
stream_status->plane_states[stream_status->plane_count] = NULL;
......@@ -1312,6 +1324,28 @@ bool dc_is_stream_unchanged(
return true;
}
bool dc_is_stream_scaling_unchanged(
struct dc_stream_state *old_stream, struct dc_stream_state *stream)
{
if (old_stream == stream)
return true;
if (old_stream == NULL || stream == NULL)
return false;
if (memcmp(&old_stream->src,
&stream->src,
sizeof(struct rect)) != 0)
return false;
if (memcmp(&old_stream->dst,
&stream->dst,
sizeof(struct rect)) != 0)
return false;
return true;
}
/* Maximum TMDS single link pixel clock 165MHz */
#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
......@@ -1330,7 +1364,7 @@ static void update_stream_engine_usage(
}
/* TODO: release audio object */
static void update_audio_usage(
void update_audio_usage(
struct resource_context *res_ctx,
const struct resource_pool *pool,
struct audio *audio,
......@@ -1356,8 +1390,10 @@ static int acquire_first_free_pipe(
pipe_ctx->stream_res.tg = pool->timing_generators[i];
pipe_ctx->plane_res.mi = pool->mis[i];
pipe_ctx->plane_res.hubp = pool->hubps[i];
pipe_ctx->plane_res.ipp = pool->ipps[i];
pipe_ctx->plane_res.xfm = pool->transforms[i];
pipe_ctx->plane_res.dpp = pool->dpps[i];
pipe_ctx->stream_res.opp = pool->opps[i];
pipe_ctx->pipe_idx = i;
......@@ -1414,12 +1450,17 @@ static struct audio *find_first_free_audio(
const struct resource_pool *pool)
{
int i;
for (i = 0; i < pool->audio_count; i++) {
if ((res_ctx->is_audio_acquired[i] == false) && (res_ctx->is_stream_enc_acquired[i] == true)) {
return pool->audios[i];
}
}
/*not found the matching one, first come first serve*/
for (i = 0; i < pool->audio_count; i++) {
if (res_ctx->is_audio_acquired[i] == false) {
return pool->audios[i];
}
}
return 0;
}
......@@ -1438,7 +1479,7 @@ bool resource_is_stream_unchanged(
return false;
}
bool dc_add_stream_to_ctx(
enum dc_status dc_add_stream_to_ctx(
struct dc *dc,
struct dc_state *new_ctx,
struct dc_stream_state *stream)
......@@ -1459,10 +1500,10 @@ bool dc_add_stream_to_ctx(
if (res != DC_OK)
DC_ERROR("Adding stream %p to context failed with err %d!\n", stream, res);
return res == DC_OK;
return res;
}
bool dc_remove_stream_from_ctx(
enum dc_status dc_remove_stream_from_ctx(
struct dc *dc,
struct dc_state *new_ctx,
struct dc_stream_state *stream)
......@@ -1632,10 +1673,11 @@ enum dc_status resource_map_pool_resources(
/* acquire new resources */
pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
#ifdef CONFIG_DRM_AMD_DC_DCN1_0
if (pipe_idx < 0)
acquire_first_split_pipe(&context->res_ctx, pool, stream);
pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
#endif
if (pipe_idx < 0)
return DC_NO_CONTROLLER_RESOURCE;
......@@ -1716,17 +1758,18 @@ void dc_resource_state_construct(
dst_ctx->dis_clk = dc->res_pool->display_clock;
}
bool dc_validate_global_state(
enum dc_status dc_validate_global_state(
struct dc *dc,
struct dc_state *new_ctx)
{
enum dc_status result = DC_ERROR_UNEXPECTED;
int i, j;
if (dc->res_pool->funcs->validate_global &&
dc->res_pool->funcs->validate_global(
dc, new_ctx) != DC_OK)
return false;
if (dc->res_pool->funcs->validate_global) {
result = dc->res_pool->funcs->validate_global(dc, new_ctx);
if (result != DC_OK)
return result;
}
for (i = 0; new_ctx && i < new_ctx->stream_count; i++) {
struct dc_stream_state *stream = new_ctx->streams[i];
......@@ -2713,7 +2756,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream,
fmt_bit_depth->pixel_encoding = pixel_encoding;
}
bool dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
{
struct dc *core_dc = dc;
struct dc_link *link = stream->sink->link;
......@@ -2737,16 +2780,16 @@ bool dc_validate_stream(struct dc *dc, struct dc_stream_state *stream)
link,
&stream->timing);
return res == DC_OK;
return res;
}
bool dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state)
{
struct dc *core_dc = dc;
enum dc_status res = DC_OK;
/* TODO For now validates pixel format only */
if (core_dc->res_pool->funcs->validate_plane)
return core_dc->res_pool->funcs->validate_plane(plane_state) == DC_OK;
if (dc->res_pool->funcs->validate_plane)
return dc->res_pool->funcs->validate_plane(plane_state, &dc->caps);
return true;
return res;
}
......@@ -173,7 +173,7 @@ struct dc_stream_status *dc_stream_get_status(
* Update the cursor attributes and set cursor surface address
*/
bool dc_stream_set_cursor_attributes(
const struct dc_stream_state *stream,
struct dc_stream_state *stream,
const struct dc_cursor_attributes *attributes)
{
int i;
......@@ -189,21 +189,51 @@ bool dc_stream_set_cursor_attributes(
return false;
}
if (attributes->address.quad_part == 0) {
dm_output_to_console("DC: Cursor address is 0!\n");
return false;
}
core_dc = stream->ctx->dc;
res_ctx = &core_dc->current_state->res_ctx;
for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
if (pipe_ctx->stream != stream || !pipe_ctx->plane_res.ipp)
if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp))
continue;
if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
continue;
pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes(
pipe_ctx->plane_res.ipp, attributes);
if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL)
pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes(
pipe_ctx->plane_res.ipp, attributes);
if (pipe_ctx->plane_res.hubp != NULL &&
pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL)
pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
pipe_ctx->plane_res.hubp, attributes);
if (pipe_ctx->plane_res.mi != NULL &&
pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL)
pipe_ctx->plane_res.mi->funcs->set_cursor_attributes(
pipe_ctx->plane_res.mi, attributes);
if (pipe_ctx->plane_res.xfm != NULL &&
pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL)
pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes(
pipe_ctx->plane_res.xfm, attributes);
if (pipe_ctx->plane_res.dpp != NULL &&
pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL)
pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
pipe_ctx->plane_res.dpp, attributes);
}
stream->cursor_attributes = *attributes;
return true;
}
......@@ -231,6 +261,10 @@ bool dc_stream_set_cursor_position(
for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
struct mem_input *mi = pipe_ctx->plane_res.mi;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct transform *xfm = pipe_ctx->plane_res.xfm;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
struct dc_cursor_position pos_cpy = *position;
struct dc_cursor_mi_param param = {
.pixel_clk_khz = stream->timing.pix_clk_khz,
......@@ -241,7 +275,9 @@ bool dc_stream_set_cursor_position(
};
if (pipe_ctx->stream != stream ||
!pipe_ctx->plane_res.ipp || !pipe_ctx->plane_state)
(!pipe_ctx->plane_res.mi && !pipe_ctx->plane_res.hubp) ||
!pipe_ctx->plane_state ||
(!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp))
continue;
if (pipe_ctx->plane_state->address.type
......@@ -251,7 +287,22 @@ bool dc_stream_set_cursor_position(
if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
pos_cpy.enable = false;
ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
if (ipp->funcs->ipp_cursor_set_position != NULL)
ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
if (mi != NULL && mi->funcs->set_cursor_position != NULL)
mi->funcs->set_cursor_position(mi, &pos_cpy, &param);
if (hubp != NULL && hubp->funcs->set_cursor_position != NULL)
hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
if (xfm != NULL && xfm->funcs->set_cursor_position != NULL)
xfm->funcs->set_cursor_position(xfm, &pos_cpy, &param, hubp->curs_attr.width);
if (dpp != NULL && dpp->funcs->set_cursor_position != NULL)
dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width);
}
return true;
......
......@@ -30,6 +30,7 @@
/* DC core (private) */
#include "core_types.h"
#include "transform.h"
#include "dpp.h"
/*******************************************************************************
* Private functions
......
......@@ -38,7 +38,7 @@
#include "inc/compressor.h"
#include "dml/display_mode_lib.h"
#define DC_VER "3.1.01"
#define DC_VER "3.1.07"
#define MAX_SURFACES 3
#define MAX_STREAMS 6
......@@ -56,11 +56,12 @@ struct dc_caps {
uint32_t max_planes;
uint32_t max_downscale_ratio;
uint32_t i2c_speed_in_khz;
unsigned int max_cursor_size;
unsigned int max_video_width;
bool dcc_const_color;
bool dynamic_audio;
};
struct dc_dcc_surface_param {
struct dc_size surface_size;
enum surface_pixel_format format;
......@@ -132,6 +133,10 @@ struct dc_stream_state_funcs {
void (*set_dither_option)(struct dc_stream_state *stream,
enum dc_dither_option option);
void (*set_dpms)(struct dc *dc,
struct dc_stream_state *stream,
bool dpms_off);
};
struct link_training_settings;
......@@ -162,6 +167,23 @@ struct dc_config {
bool disable_disp_pll_sharing;
};
enum dcc_option {
DCC_ENABLE = 0,
DCC_DISABLE = 1,
DCC_HALF_REQ_DISALBE = 2,
};
enum pipe_split_policy {
MPC_SPLIT_DYNAMIC = 0,
MPC_SPLIT_AVOID = 1,
MPC_SPLIT_AVOID_MULT_DISP = 2,
};
enum wm_report_mode {
WM_REPORT_DEFAULT = 0,
WM_REPORT_OVERRIDE = 1,
};
struct dc_debug {
bool surface_visual_confirm;
bool sanity_checks;
......@@ -170,14 +192,21 @@ struct dc_debug {
bool timing_trace;
bool clock_trace;
bool validation_trace;
/* stutter efficiency related */
bool disable_stutter;
bool disable_dcc;
bool use_max_lb;
enum dcc_option disable_dcc;
enum pipe_split_policy pipe_split_policy;
bool force_single_disp_pipe_split;
bool voltage_align_fclk;
bool disable_dfs_bypass;
bool disable_dpp_power_gate;
bool disable_hubp_power_gate;
bool disable_pplib_wm_range;
bool use_dml_wm;
bool disable_pipe_split;
enum wm_report_mode pplib_wm_report_mode;
unsigned int min_disp_clk_khz;
int sr_exit_time_dpm0_ns;
int sr_enter_plus_exit_time_dpm0_ns;
int sr_exit_time_ns;
......@@ -191,6 +220,11 @@ struct dc_debug {
bool disable_dmcu;
bool disable_psr;
bool force_abm_enable;
bool disable_hbup_pg;
bool disable_dpp_pg;
bool disable_stereo_support;
bool vsr_support;
bool performance_trace;
};
struct dc_state;
struct resource_pool;
......@@ -233,7 +267,7 @@ struct dc {
struct dm_pp_display_configuration prev_display_config;
/* FBC compressor */
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
struct compressor *fbc_compressor;
#endif
};
......@@ -268,7 +302,7 @@ struct dc_init_data {
struct dc_config flags;
uint32_t log_mask;
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
uint64_t fbc_gpu_addr;
#endif
};
......@@ -285,6 +319,38 @@ enum {
TRANSFER_FUNC_POINTS = 1025
};
// Moved here from color module for linux
enum color_transfer_func {
transfer_func_unknown,
transfer_func_srgb,
transfer_func_bt709,
transfer_func_pq2084,
transfer_func_pq2084_interim,
transfer_func_linear_0_1,
transfer_func_linear_0_125,
transfer_func_dolbyvision,
transfer_func_gamma_22,
transfer_func_gamma_26
};
enum color_color_space {
color_space_unsupported,
color_space_srgb,
color_space_bt601,
color_space_bt709,
color_space_xv_ycc_bt601,
color_space_xv_ycc_bt709,
color_space_xr_rgb,
color_space_bt2020,
color_space_adobe,
color_space_dci_p3,
color_space_sc_rgb_ms_ref,
color_space_display_native,
color_space_app_ctrl,
color_space_dolby_vision,
color_space_custom_coordinates
};
struct dc_hdr_static_metadata {
/* display chromaticities and white point in units of 0.00001 */
unsigned int chromaticity_green_x;
......@@ -365,6 +431,12 @@ struct dc_plane_state {
struct dc_gamma *gamma_correction;
struct dc_transfer_func *in_transfer_func;
// sourceContentAttribute cache
bool is_source_input_valid;
struct dc_hdr_static_metadata source_input_mastering_info;
enum color_color_space source_input_color_space;
enum color_transfer_func source_input_tf;
enum dc_color_space color_space;
enum surface_pixel_format format;
enum dc_rotation_angle rotation;
......@@ -449,23 +521,6 @@ struct dc_flip_addrs {
/* TODO: add flip duration for FreeSync */
};
/*
* Set up surface attributes and associate to a stream
* The surfaces parameter is an absolute set of all surface active for the stream.
* If no surfaces are provided, the stream will be blanked; no memory read.
* Any flip related attribute changes must be done through this interface.
*
* After this call:
* Surfaces attributes are programmed and configured to be composed into stream.
* This does not trigger a flip. No surface address is programmed.
*/
bool dc_commit_planes_to_stream(
struct dc *dc,
struct dc_plane_state **plane_states,
uint8_t new_plane_count,
struct dc_stream_state *stream);
bool dc_post_update_surfaces_to_stream(
struct dc *dc);
......@@ -554,9 +609,12 @@ struct dc_stream_state {
int phy_pix_clk;
enum signal_type signal;
bool dpms_off;
struct dc_stream_status status;
struct dc_cursor_attributes cursor_attributes;
/* from stream struct */
struct kref refcount;
};
......@@ -569,11 +627,10 @@ struct dc_stream_update {
bool dc_is_stream_unchanged(
struct dc_stream_state *old_stream, struct dc_stream_state *stream);
bool dc_is_stream_scaling_unchanged(
struct dc_stream_state *old_stream, struct dc_stream_state *stream);
/*
* Setup stream attributes if no stream updates are provided
* there will be no impact on the stream parameters
*
* Set up surface attributes and associate to a stream
* The surfaces parameter is an absolute set of all surface active for the stream.
* If no surfaces are provided, the stream will be blanked; no memory read.
......@@ -582,14 +639,22 @@ bool dc_is_stream_unchanged(
* After this call:
* Surfaces attributes are programmed and configured to be composed into stream.
* This does not trigger a flip. No surface address is programmed.
*
*/
void dc_update_planes_and_stream(struct dc *dc,
struct dc_surface_update *surface_updates, int surface_count,
bool dc_commit_planes_to_stream(
struct dc *dc,
struct dc_plane_state **plane_states,
uint8_t new_plane_count,
struct dc_stream_state *dc_stream,
struct dc_stream_update *stream_update);
struct dc_state *state);
void dc_commit_updates_for_stream(struct dc *dc,
struct dc_surface_update *srf_updates,
int surface_count,
struct dc_stream_state *stream,
struct dc_stream_update *stream_update,
struct dc_plane_state **plane_states,
struct dc_state *state);
/*
* Log the current stream state.
*/
......@@ -616,12 +681,12 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream,
uint32_t *h_position,
uint32_t *v_position);
bool dc_add_stream_to_ctx(
enum dc_status dc_add_stream_to_ctx(
struct dc *dc,
struct dc_state *new_ctx,
struct dc_stream_state *stream);
bool dc_remove_stream_from_ctx(
enum dc_status dc_remove_stream_from_ctx(
struct dc *dc,
struct dc_state *new_ctx,
struct dc_stream_state *stream);
......@@ -660,11 +725,11 @@ struct dc_validation_set {
uint8_t plane_count;
};
bool dc_validate_stream(struct dc *dc, struct dc_stream_state *stream);
enum dc_status dc_validate_stream(struct dc *dc, struct dc_stream_state *stream);
bool dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state);
enum dc_status dc_validate_plane(struct dc *dc, const struct dc_plane_state *plane_state);
bool dc_validate_global_state(
enum dc_status dc_validate_global_state(
struct dc *dc,
struct dc_state *new_ctx);
......@@ -991,7 +1056,7 @@ struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params);
******************************************************************************/
/* TODO: Deprecated once we switch to dc_set_cursor_position */
bool dc_stream_set_cursor_attributes(
const struct dc_stream_state *stream,
struct dc_stream_state *stream,
const struct dc_cursor_attributes *attributes);
bool dc_stream_set_cursor_position(
......
......@@ -204,6 +204,8 @@ enum surface_pixel_format {
/*grow 444 video here if necessary */
};
/* Pixel format */
enum pixel_format {
/*graph*/
......
......@@ -92,7 +92,7 @@ struct dc_context {
bool created_bios;
struct gpio_service *gpio_service;
struct i2caux *i2caux;
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
uint64_t fbc_gpu_addr;
#endif
};
......@@ -151,6 +151,7 @@ enum dc_edid_status {
EDID_BAD_INPUT,
EDID_NO_RESPONSE,
EDID_BAD_CHECKSUM,
EDID_THE_SAME,
};
/* audio capability from EDID*/
......
......@@ -27,6 +27,10 @@
#include "hw_sequencer.h"
#define BL_REG_LIST()\
SR(LVTMA_PWRSEQ_CNTL), \
SR(LVTMA_PWRSEQ_STATE)
#define HWSEQ_DCEF_REG_LIST_DCE8() \
.DCFE_CLOCK_CONTROL[0] = mmCRTC0_CRTC_DCFE_CLOCK_CONTROL, \
.DCFE_CLOCK_CONTROL[1] = mmCRTC1_CRTC_DCFE_CLOCK_CONTROL, \
......@@ -86,24 +90,27 @@
SRII(BLND_CONTROL, BLND, 0),\
SRII(BLND_CONTROL, BLND, 1),\
SR(BLNDV_CONTROL),\
HWSEQ_PIXEL_RATE_REG_LIST(CRTC)
HWSEQ_PIXEL_RATE_REG_LIST(CRTC),\
BL_REG_LIST()
#define HWSEQ_DCE8_REG_LIST() \
HWSEQ_DCEF_REG_LIST_DCE8(), \
HWSEQ_BLND_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(CRTC)
HWSEQ_PIXEL_RATE_REG_LIST(CRTC),\
BL_REG_LIST()
#define HWSEQ_DCE10_REG_LIST() \
HWSEQ_DCEF_REG_LIST(), \
HWSEQ_BLND_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(CRTC)
HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \
BL_REG_LIST()
#define HWSEQ_ST_REG_LIST() \
HWSEQ_DCE11_REG_LIST_BASE(), \
.DCFE_CLOCK_CONTROL[2] = mmDCFEV_CLOCK_CONTROL, \
.CRTC_H_BLANK_START_END[2] = mmCRTCV_H_BLANK_START_END, \
.BLND_V_UPDATE_LOCK[2] = mmBLNDV_V_UPDATE_LOCK, \
.BLND_CONTROL[2] = mmBLNDV_CONTROL,
.BLND_CONTROL[2] = mmBLNDV_CONTROL
#define HWSEQ_CZ_REG_LIST() \
HWSEQ_DCE11_REG_LIST_BASE(), \
......@@ -123,16 +130,16 @@
SR(DCHUB_FB_LOCATION),\
SR(DCHUB_AGP_BASE),\
SR(DCHUB_AGP_BOT),\
SR(DCHUB_AGP_TOP)
SR(DCHUB_AGP_TOP), \
BL_REG_LIST()
#define HWSEQ_DCE112_REG_LIST() \
HWSEQ_DCE10_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \
HWSEQ_PHYPLL_REG_LIST(CRTC)
HWSEQ_PHYPLL_REG_LIST(CRTC), \
BL_REG_LIST()
#define HWSEQ_DCN_REG_LIST()\
HWSEQ_PIXEL_RATE_REG_LIST(OTG), \
HWSEQ_PHYPLL_REG_LIST(OTG), \
SRII(OTG_GLOBAL_SYNC_STATUS, OTG, 0), \
SRII(OTG_GLOBAL_SYNC_STATUS, OTG, 1), \
SRII(OTG_GLOBAL_SYNC_STATUS, OTG, 2), \
......@@ -156,23 +163,15 @@
SR(REFCLK_CNTL), \
SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A),\
SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A),\
SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A),\
SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B),\
SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B),\
SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B),\
SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C),\
SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C),\
SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C),\
SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D),\
SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D),\
SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D),\
SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL),\
SR(DCHUBBUB_ARB_DRAM_STATE_CNTL),\
......@@ -181,32 +180,11 @@
SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \
SR(DCHUBBUB_TEST_DEBUG_INDEX), \
SR(DCHUBBUB_TEST_DEBUG_DATA), \
SR(DC_IP_REQUEST_CNTL), \
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(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(DIO_MEM_PWR_CTRL), \
SR(DCCG_GATE_DISABLE_CNTL), \
SR(DCCG_GATE_DISABLE_CNTL2), \
SR(DCFCLK_CNTL),\
SR(DCFCLK_CNTL), \
SR(D1VGA_CONTROL), \
SR(D2VGA_CONTROL), \
SR(D3VGA_CONTROL), \
SR(D4VGA_CONTROL), \
/* 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),\
......@@ -221,17 +199,56 @@
MMHUB_SR(MC_VM_SYSTEM_APERTURE_LOW_ADDR),\
MMHUB_SR(MC_VM_SYSTEM_APERTURE_HIGH_ADDR)
#define HWSEQ_SR_WATERMARK_REG_LIST()\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C),\
SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D),\
SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D)
#define HWSEQ_DCN1_REG_LIST()\
HWSEQ_DCN_REG_LIST(), \
HWSEQ_SR_WATERMARK_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(OTG), \
HWSEQ_PHYPLL_REG_LIST(OTG), \
SR(DCHUBBUB_SDPIF_FB_TOP),\
SR(DCHUBBUB_SDPIF_FB_BASE),\
SR(DCHUBBUB_SDPIF_FB_OFFSET),\
SR(DCHUBBUB_SDPIF_AGP_BASE),\
SR(DCHUBBUB_SDPIF_AGP_BOT),\
SR(DCHUBBUB_SDPIF_AGP_TOP)
SR(DCHUBBUB_SDPIF_AGP_TOP),\
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(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(D1VGA_CONTROL), \
SR(D2VGA_CONTROL), \
SR(D3VGA_CONTROL), \
SR(D4VGA_CONTROL), \
SR(DC_IP_REQUEST_CNTL), \
BL_REG_LIST()
struct dce_hwseq_registers {
/* Backlight registers */
uint32_t LVTMA_PWRSEQ_CNTL;
uint32_t LVTMA_PWRSEQ_STATE;
uint32_t DCFE_CLOCK_CONTROL[6];
uint32_t DCFEV_CLOCK_CONTROL;
uint32_t DC_MEM_GLOBAL_PWR_REQ_CNTL;
......@@ -376,20 +393,28 @@ struct dce_hwseq_registers {
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_)
#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_)
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)
#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_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)\
......@@ -397,14 +422,18 @@ 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)
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)
#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)
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)
#define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\
......@@ -416,35 +445,12 @@ struct dce_hwseq_registers {
HWS_SF(DPP_TOP0_, DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \
HWS_SF(OPP_PIPE0_, OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, mask_sh),\
HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \
HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, 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(, 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(, DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \
HWS_SF(, DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh), \
HWS_SF(, DCFCLK_CNTL, DCFCLK_GATE_DIS, mask_sh)
......@@ -468,7 +474,34 @@ struct dce_hwseq_registers {
HWS_SF(, VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, PHYSICAL_PAGE_ADDR_LO32, mask_sh),\
HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, PHYSICAL_PAGE_NUMBER_MSB, mask_sh),\
HWS_SF(, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, PHYSICAL_PAGE_NUMBER_LSB, mask_sh),\
HWS_SF(, MC_VM_SYSTEM_APERTURE_LOW_ADDR, LOGICAL_ADDR, mask_sh)
HWS_SF(, MC_VM_SYSTEM_APERTURE_LOW_ADDR, LOGICAL_ADDR, 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(, 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(, 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)
#define HWSEQ_REG_FIELD_LIST(type) \
type DCFE_CLOCK_ENABLE; \
......@@ -498,7 +531,9 @@ struct dce_hwseq_registers {
type PHYSICAL_PAGE_NUMBER_LSB;\
type LOGICAL_ADDR; \
type ENABLE_L1_TLB;\
type SYSTEM_ACCESS_MODE;
type SYSTEM_ACCESS_MODE;\
type LVTMA_BLON;\
type LVTMA_PWRSEQ_TARGET_STATE_R;
#define HWSEQ_DCN_REG_FIELD_LIST(type) \
type VUPDATE_NO_LOCK_EVENT_CLEAR; \
......@@ -524,6 +559,8 @@ struct dce_hwseq_registers {
type DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE;\
type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE;\
type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE;\
type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE;\
type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE;\
type DCHUBBUB_ARB_SAT_LEVEL;\
type DCHUBBUB_ARB_MIN_REQ_OUTSTAND;\
type OPP_PIPE_CLOCK_EN;\
......
......@@ -37,6 +37,7 @@
#define CTX \
ipp_dce->base.ctx
static void dce_ipp_cursor_set_position(
struct input_pixel_processor *ipp,
const struct dc_cursor_position *position,
......@@ -133,6 +134,7 @@ static void dce_ipp_cursor_set_attributes(
REG_UPDATE(CUR_UPDATE, CURSOR_UPDATE_LOCK, false);
}
static void dce_ipp_program_prescale(
struct input_pixel_processor *ipp,
struct ipp_prescale_params *params)
......
......@@ -82,13 +82,6 @@
#define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20
#define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40
/* all values are in milliseconds */
/* For eDP, after power-up/power/down,
* 300/500 msec max. delay from LCDVCC to black video generation */
#define PANEL_POWER_UP_TIMEOUT 300
#define PANEL_POWER_DOWN_TIMEOUT 500
#define HPD_CHECK_INTERVAL 10
/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
#define TMDS_MIN_PIXEL_CLOCK 25000
/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
......@@ -122,8 +115,6 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
.psr_program_dp_dphy_fast_training =
dce110_psr_program_dp_dphy_fast_training,
.psr_program_secondary_packet = dce110_psr_program_secondary_packet,
.backlight_control = dce110_link_encoder_edp_backlight_control,
.power_control = dce110_link_encoder_edp_power_control,
.connect_dig_be_to_fe = dce110_link_encoder_connect_dig_be_to_fe,
.enable_hpd = dce110_link_encoder_enable_hpd,
.disable_hpd = dce110_link_encoder_disable_hpd,
......@@ -493,165 +484,6 @@ static void configure_encoder(
REG_UPDATE(DP_DPHY_SCRAM_CNTL, DPHY_SCRAMBLER_ADVANCE, 1);
}
static bool is_panel_powered_on(struct dce110_link_encoder *enc110)
{
bool ret;
uint32_t value;
REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value);
ret = value;
return ret == 1;
}
/* TODO duplicate of dc_link.c version */
static struct gpio *get_hpd_gpio(const struct link_encoder *enc)
{
enum bp_result bp_result;
struct dc_bios *dcb = enc->ctx->dc_bios;
struct graphics_object_hpd_info hpd_info;
struct gpio_pin_info pin_info;
if (dcb->funcs->get_hpd_info(dcb, enc->connector, &hpd_info) != BP_RESULT_OK)
return NULL;
bp_result = dcb->funcs->get_gpio_pin_info(dcb,
hpd_info.hpd_int_gpio_uid, &pin_info);
if (bp_result != BP_RESULT_OK) {
ASSERT(bp_result == BP_RESULT_NORECORD);
return NULL;
}
return dal_gpio_service_create_irq(
enc->ctx->gpio_service,
pin_info.offset,
pin_info.mask);
}
/*
* @brief
* eDP only.
*/
static void link_encoder_edp_wait_for_hpd_ready(
struct dce110_link_encoder *enc110,
bool power_up)
{
struct dc_context *ctx = enc110->base.ctx;
struct graphics_object_id connector = enc110->base.connector;
struct gpio *hpd;
bool edp_hpd_high = false;
uint32_t time_elapsed = 0;
uint32_t timeout = power_up ?
PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
if (dal_graphics_object_id_get_connector_id(connector) !=
CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (!power_up)
/* from KV, we will not HPD low after turning off VCC -
* instead, we will check the SW timer in power_up(). */
return;
/* when we power on/off the eDP panel,
* we need to wait until SENSE bit is high/low */
/* obtain HPD */
/* TODO what to do with this? */
hpd = get_hpd_gpio(&enc110->base);
if (!hpd) {
BREAK_TO_DEBUGGER();
return;
}
dal_gpio_open(hpd, GPIO_MODE_INTERRUPT);
/* wait until timeout or panel detected */
do {
uint32_t detected = 0;
dal_gpio_get_value(hpd, &detected);
if (!(detected ^ power_up)) {
edp_hpd_high = true;
break;
}
msleep(HPD_CHECK_INTERVAL);
time_elapsed += HPD_CHECK_INTERVAL;
} while (time_elapsed < timeout);
dal_gpio_close(hpd);
dal_gpio_destroy_irq(&hpd);
if (false == edp_hpd_high) {
dm_logger_write(ctx->logger, LOG_ERROR,
"%s: wait timed out!\n", __func__);
}
}
/*
* @brief
* eDP only. Control the power of the eDP panel.
*/
void dce110_link_encoder_edp_power_control(
struct link_encoder *enc,
bool power_up)
{
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
struct dc_context *ctx = enc110->base.ctx;
struct bp_transmitter_control cntl = { 0 };
enum bp_result bp_result;
if (dal_graphics_object_id_get_connector_id(enc110->base.connector) !=
CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if ((power_up && !is_panel_powered_on(enc110)) ||
(!power_up && is_panel_powered_on(enc110))) {
/* Send VBIOS command to prompt eDP panel power */
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: Panel Power action: %s\n",
__func__, (power_up ? "On":"Off"));
cntl.action = power_up ?
TRANSMITTER_CONTROL_POWER_ON :
TRANSMITTER_CONTROL_POWER_OFF;
cntl.transmitter = enc110->base.transmitter;
cntl.connector_obj_id = enc110->base.connector;
cntl.coherent = false;
cntl.lanes_number = LANE_COUNT_FOUR;
cntl.hpd_sel = enc110->base.hpd_source;
bp_result = link_transmitter_control(enc110, &cntl);
if (BP_RESULT_OK != bp_result) {
dm_logger_write(ctx->logger, LOG_ERROR,
"%s: Panel Power bp_result: %d\n",
__func__, bp_result);
}
} else {
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: Skipping Panel Power action: %s\n",
__func__, (power_up ? "On":"Off"));
}
link_encoder_edp_wait_for_hpd_ready(enc110, true);
}
static void aux_initialize(
struct dce110_link_encoder *enc110)
{
......@@ -674,16 +506,6 @@ static void aux_initialize(
}
/*todo: cloned in stream enc, fix*/
static bool is_panel_backlight_on(struct dce110_link_encoder *enc110)
{
uint32_t value;
REG_GET(LVTMA_PWRSEQ_CNTL, LVTMA_BLON, &value);
return value;
}
void dce110_psr_program_dp_dphy_fast_training(struct link_encoder *enc,
bool exit_link_training_required)
{
......@@ -718,69 +540,6 @@ void dce110_psr_program_secondary_packet(struct link_encoder *enc,
DP_SEC_GSP0_PRIORITY, 1);
}
/*todo: cloned in stream enc, fix*/
/*
* @brief
* eDP only. Control the backlight of the eDP panel
*/
void dce110_link_encoder_edp_backlight_control(
struct link_encoder *enc,
bool enable)
{
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
struct dc_context *ctx = enc110->base.ctx;
struct bp_transmitter_control cntl = { 0 };
if (dal_graphics_object_id_get_connector_id(enc110->base.connector)
!= CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (enable && is_panel_backlight_on(enc110)) {
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: panel already powered up. Do nothing.\n",
__func__);
return;
}
if (!enable && !is_panel_backlight_on(enc110)) {
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: panel already powered down. Do nothing.\n",
__func__);
return;
}
/* Send VBIOS command to control eDP panel backlight */
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: backlight action: %s\n",
__func__, (enable ? "On":"Off"));
cntl.action = enable ?
TRANSMITTER_CONTROL_BACKLIGHT_ON :
TRANSMITTER_CONTROL_BACKLIGHT_OFF;
/*cntl.engine_id = ctx->engine;*/
cntl.transmitter = enc110->base.transmitter;
cntl.connector_obj_id = enc110->base.connector;
/*todo: unhardcode*/
cntl.lanes_number = LANE_COUNT_FOUR;
cntl.hpd_sel = enc110->base.hpd_source;
/* For eDP, the following delays might need to be considered
* after link training completed:
* idle period - min. accounts for required BS-Idle pattern,
* max. allows for source frame synchronization);
* 50 msec max. delay from valid video data from source
* to video on dislpay or backlight enable.
*
* Disable the delay for now.
* Enable it in the future if necessary.
*/
/* dc_service_sleep_in_milliseconds(50); */
link_transmitter_control(enc110, &cntl);
}
static bool is_dig_enabled(const struct dce110_link_encoder *enc110)
{
uint32_t value;
......@@ -998,11 +757,6 @@ void dce110_link_encoder_construct(
enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
}
dm_logger_write(init_data->ctx->logger, LOG_I2C_AUX,
"Using channel: %s [%d]\n",
DECODE_CHANNEL_ID(init_data->channel),
init_data->channel);
/* Override features with DCE-specific values */
if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info(
enc110->base.ctx->dc_bios, enc110->base.id,
......@@ -1092,7 +846,7 @@ void dce110_link_encoder_hw_init(
ASSERT(result == BP_RESULT_OK);
} else if (enc110->base.connector.id == CONNECTOR_ID_EDP) {
enc->funcs->power_control(&enc110->base, true);
ctx->dc->hwss.edp_power_control(enc, true);
}
aux_initialize(enc110);
......@@ -1279,7 +1033,8 @@ void dce110_link_encoder_enable_dp_mst_output(
*/
void dce110_link_encoder_disable_output(
struct link_encoder *enc,
enum signal_type signal)
enum signal_type signal,
struct dc_link *link)
{
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
struct dc_context *ctx = enc110->base.ctx;
......@@ -1291,7 +1046,7 @@ void dce110_link_encoder_disable_output(
return;
}
if (enc110->base.connector.id == CONNECTOR_ID_EDP)
dce110_link_encoder_edp_backlight_control(enc, false);
ctx->dc->hwss.edp_backlight_control(link, false);
/* Power-down RX and disable GPU PHY should be paired.
* Disabling PHY without powering down RX may cause
* symbol lock loss, on which we will get DP Sink interrupt. */
......
......@@ -44,8 +44,6 @@
SRI(DC_HPD_CONTROL, HPD, id)
#define LE_COMMON_REG_LIST_BASE(id) \
SR(LVTMA_PWRSEQ_CNTL), \
SR(LVTMA_PWRSEQ_STATE), \
SR(DMCU_RAM_ACCESS_CTRL), \
SR(DMCU_IRAM_RD_CTRL), \
SR(DMCU_IRAM_RD_DATA), \
......@@ -104,8 +102,7 @@
LE_COMMON_REG_LIST_BASE(id), \
SRI(DP_DPHY_BS_SR_SWAP_CNTL, DP, id), \
SRI(DP_DPHY_INTERNAL_CTRL, DP, id), \
SRI(DP_DPHY_HBR2_PATTERN_CONTROL, DP, id), \
SR(DMU_MEM_PWR_CNTL)
SRI(DP_DPHY_HBR2_PATTERN_CONTROL, DP, id)
struct dce110_link_enc_aux_registers {
uint32_t AUX_CONTROL;
......@@ -117,10 +114,6 @@ struct dce110_link_enc_hpd_registers {
};
struct dce110_link_enc_registers {
/* Backlight registers */
uint32_t LVTMA_PWRSEQ_CNTL;
uint32_t LVTMA_PWRSEQ_STATE;
/* DMCU registers */
uint32_t MASTER_COMM_DATA_REG1;
uint32_t MASTER_COMM_DATA_REG2;
......@@ -236,7 +229,8 @@ void dce110_link_encoder_enable_dp_mst_output(
/* disable PHY output */
void dce110_link_encoder_disable_output(
struct link_encoder *link_enc,
enum signal_type signal);
enum signal_type signal,
struct dc_link *link);
/* set DP lane settings */
void dce110_link_encoder_dp_set_lane_settings(
......@@ -252,14 +246,6 @@ void dce110_link_encoder_update_mst_stream_allocation_table(
struct link_encoder *enc,
const struct link_mst_stream_allocation_table *table);
void dce110_link_encoder_edp_backlight_control(
struct link_encoder *enc,
bool enable);
void dce110_link_encoder_edp_power_control(
struct link_encoder *enc,
bool power_up);
void dce110_link_encoder_connect_dig_be_to_fe(
struct link_encoder *enc,
enum engine_id engine,
......
......@@ -361,7 +361,7 @@ static void program_grph_pixel_format(
enum surface_pixel_format format)
{
uint32_t red_xbar = 0, blue_xbar = 0; /* no swap */
uint32_t grph_depth, grph_format;
uint32_t grph_depth = 0, grph_format = 0;
uint32_t sign = 0, floating = 0;
if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 ||
......@@ -685,9 +685,6 @@ void dce_mem_input_construct(
dce_mi->regs = regs;
dce_mi->shifts = mi_shift;
dce_mi->masks = mi_mask;
dce_mi->base.mpcc_id = 0xf;
dce_mi->base.opp_id = 0xf;
}
void dce112_mem_input_construct(
......
......@@ -743,7 +743,7 @@ static void dce100_destroy_resource_pool(struct resource_pool **pool)
*pool = NULL;
}
enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state)
enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps)
{
if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN)
......
......@@ -16,7 +16,7 @@ struct resource_pool *dce100_create_resource_pool(
uint8_t num_virtual_links,
struct dc *dc);
enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state);
enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps);
enum dc_status dce100_add_stream_to_ctx(
struct dc *dc,
......
......@@ -514,7 +514,7 @@ void dce110_compressor_construct(struct dce110_compressor *compressor,
compressor->base.lpt_channels_num = 0;
compressor->base.attached_inst = 0;
compressor->base.is_enabled = false;
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
compressor->base.funcs = &dce110_compressor_funcs;
#endif
......
......@@ -32,8 +32,9 @@
#include "dce110_hw_sequencer.h"
#include "dce110_timing_generator.h"
#include "dce/dce_hwseq.h"
#include "gpio_service_interface.h"
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
#include "dce110_compressor.h"
#endif
......@@ -45,10 +46,10 @@
#include "transform.h"
#include "stream_encoder.h"
#include "link_encoder.h"
#include "link_hwss.h"
#include "clock_source.h"
#include "abm.h"
#include "audio.h"
#include "dce/dce_hwseq.h"
#include "reg_helper.h"
/* include DCE11 register header files */
......@@ -56,6 +57,24 @@
#include "dce/dce_11_0_sh_mask.h"
#include "custom_float.h"
/*
* All values are in milliseconds;
* For eDP, after power-up/power/down,
* 300/500 msec max. delay from LCDVCC to black video generation
*/
#define PANEL_POWER_UP_TIMEOUT 300
#define PANEL_POWER_DOWN_TIMEOUT 500
#define HPD_CHECK_INTERVAL 10
#define CTX \
hws->ctx
#define REG(reg)\
hws->regs->reg
#undef FN
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
struct dce110_hw_seq_reg_offsets {
uint32_t crtc;
};
......@@ -761,10 +780,216 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
}
void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
/*todo: cloned in stream enc, fix*/
static bool is_panel_backlight_on(struct dce_hwseq *hws)
{
uint32_t value;
REG_GET(LVTMA_PWRSEQ_CNTL, LVTMA_BLON, &value);
return value;
}
static bool is_panel_powered_on(struct dce_hwseq *hws)
{
uint32_t value;
REG_GET(LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, &value);
return value == 1;
}
static enum bp_result link_transmitter_control(
struct dc_bios *bios,
struct bp_transmitter_control *cntl)
{
enum bp_result result;
result = bios->funcs->transmitter_control(bios, cntl);
return result;
}
/*
* @brief
* eDP only.
*/
void hwss_edp_wait_for_hpd_ready(
struct link_encoder *enc,
bool power_up)
{
struct dc_context *ctx = enc->ctx;
struct graphics_object_id connector = enc->connector;
struct gpio *hpd;
bool edp_hpd_high = false;
uint32_t time_elapsed = 0;
uint32_t timeout = power_up ?
PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
if (dal_graphics_object_id_get_connector_id(connector)
!= CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (!power_up)
/*
* From KV, we will not HPD low after turning off VCC -
* instead, we will check the SW timer in power_up().
*/
return;
/*
* When we power on/off the eDP panel,
* we need to wait until SENSE bit is high/low.
*/
/* obtain HPD */
/* TODO what to do with this? */
hpd = get_hpd_gpio(ctx->dc_bios, connector, ctx->gpio_service);
if (!hpd) {
BREAK_TO_DEBUGGER();
return;
}
dal_gpio_open(hpd, GPIO_MODE_INTERRUPT);
/* wait until timeout or panel detected */
do {
uint32_t detected = 0;
dal_gpio_get_value(hpd, &detected);
if (!(detected ^ power_up)) {
edp_hpd_high = true;
break;
}
msleep(HPD_CHECK_INTERVAL);
time_elapsed += HPD_CHECK_INTERVAL;
} while (time_elapsed < timeout);
dal_gpio_close(hpd);
dal_gpio_destroy_irq(&hpd);
if (false == edp_hpd_high) {
dm_logger_write(ctx->logger, LOG_ERROR,
"%s: wait timed out!\n", __func__);
}
}
void hwss_edp_power_control(
struct link_encoder *enc,
bool power_up)
{
struct dc_context *ctx = enc->ctx;
struct dce_hwseq *hwseq = ctx->dc->hwseq;
struct bp_transmitter_control cntl = { 0 };
enum bp_result bp_result;
if (dal_graphics_object_id_get_connector_id(enc->connector)
!= CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (power_up != is_panel_powered_on(hwseq)) {
/* Send VBIOS command to prompt eDP panel power */
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: Panel Power action: %s\n",
__func__, (power_up ? "On":"Off"));
cntl.action = power_up ?
TRANSMITTER_CONTROL_POWER_ON :
TRANSMITTER_CONTROL_POWER_OFF;
cntl.transmitter = enc->transmitter;
cntl.connector_obj_id = enc->connector;
cntl.coherent = false;
cntl.lanes_number = LANE_COUNT_FOUR;
cntl.hpd_sel = enc->hpd_source;
bp_result = link_transmitter_control(ctx->dc_bios, &cntl);
if (bp_result != BP_RESULT_OK)
dm_logger_write(ctx->logger, LOG_ERROR,
"%s: Panel Power bp_result: %d\n",
__func__, bp_result);
} else {
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: Skipping Panel Power action: %s\n",
__func__, (power_up ? "On":"Off"));
}
hwss_edp_wait_for_hpd_ready(enc, true);
}
/*todo: cloned in stream enc, fix*/
/*
* @brief
* eDP only. Control the backlight of the eDP panel
*/
void hwss_edp_backlight_control(
struct dc_link *link,
bool enable)
{
struct dce_hwseq *hws = link->dc->hwseq;
struct dc_context *ctx = link->dc->ctx;
struct bp_transmitter_control cntl = { 0 };
if (dal_graphics_object_id_get_connector_id(link->link_id)
!= CONNECTOR_ID_EDP) {
BREAK_TO_DEBUGGER();
return;
}
if (enable && is_panel_backlight_on(hws)) {
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: panel already powered up. Do nothing.\n",
__func__);
return;
}
/* Send VBIOS command to control eDP panel backlight */
dm_logger_write(ctx->logger, LOG_HW_RESUME_S3,
"%s: backlight action: %s\n",
__func__, (enable ? "On":"Off"));
cntl.action = enable ?
TRANSMITTER_CONTROL_BACKLIGHT_ON :
TRANSMITTER_CONTROL_BACKLIGHT_OFF;
/*cntl.engine_id = ctx->engine;*/
cntl.transmitter = link->link_enc->transmitter;
cntl.connector_obj_id = link->link_enc->connector;
/*todo: unhardcode*/
cntl.lanes_number = LANE_COUNT_FOUR;
cntl.hpd_sel = link->link_enc->hpd_source;
/* For eDP, the following delays might need to be considered
* after link training completed:
* idle period - min. accounts for required BS-Idle pattern,
* max. allows for source frame synchronization);
* 50 msec max. delay from valid video data from source
* to video on dislpay or backlight enable.
*
* Disable the delay for now.
* Enable it in the future if necessary.
*/
/* dc_service_sleep_in_milliseconds(50); */
link_transmitter_control(link->dc->ctx->dc_bios, &cntl);
}
void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option)
{
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->sink->link;
struct dc *dc = pipe_ctx->stream->ctx->dc;
if (pipe_ctx->stream_res.audio) {
pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
......@@ -775,6 +1000,13 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
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*/
pipe_ctx->stream_res.audio = NULL;
/*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);
}
/* TODO: notify audio driver for if audio modes list changed
* add audio mode list change flag */
......@@ -798,7 +1030,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
/* blank at encoder level */
if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (pipe_ctx->stream->sink->link->connector_signal == SIGNAL_TYPE_EDP)
link->link_enc->funcs->backlight_control(link->link_enc, false);
hwss_edp_backlight_control(link, false);
pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
}
link->link_enc->funcs->connect_dig_be_to_fe(
......@@ -820,7 +1052,7 @@ void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
params.link_settings.link_rate = link_settings->link_rate;
pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
if (link->connector_signal == SIGNAL_TYPE_EDP)
link->link_enc->funcs->backlight_control(link->link_enc, true);
hwss_edp_backlight_control(link, true);
}
......@@ -1132,33 +1364,21 @@ static enum dc_status apply_single_controller_ctx_to_hw(
resource_build_info_frame(pipe_ctx);
dce110_update_info_frame(pipe_ctx);
if (!pipe_ctx_old->stream) {
core_link_enable_stream(context, pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dce110_unblank_stream(pipe_ctx,
&stream->sink->link->cur_link_settings);
if (!pipe_ctx->stream->dpms_off)
core_link_enable_stream(context, pipe_ctx);
}
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
/* program_scaler and allocate_mem_input are not new asic */
if ((!pipe_ctx_old ||
memcmp(&pipe_ctx_old->plane_res.scl_data, &pipe_ctx->plane_res.scl_data,
sizeof(struct scaler_data)) != 0) &&
pipe_ctx->plane_state) {
program_scaler(dc, pipe_ctx);
}
/* mst support - use total stream count */
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
if (pipe_ctx->plane_res.mi->funcs->allocate_mem_input != NULL)
#endif
if (pipe_ctx->plane_res.mi != NULL) {
pipe_ctx->plane_res.mi->funcs->allocate_mem_input(
pipe_ctx->plane_res.mi,
stream->timing.h_total,
stream->timing.v_total,
stream->timing.pix_clk_khz,
context->stream_count);
pipe_ctx->plane_res.mi,
stream->timing.h_total,
stream->timing.v_total,
stream->timing.pix_clk_khz,
context->stream_count);
}
pipe_ctx->stream->sink->link->psr_enabled = false;
......@@ -1171,6 +1391,16 @@ static void power_down_encoders(struct dc *dc)
{
int i;
enum connector_id connector_id;
enum signal_type signal = SIGNAL_TYPE_NONE;
/* do not know BIOS back-front mapping, simply blank all. It will not
* hurt for non-DP
*/
for (i = 0; i < dc->res_pool->stream_enc_count; i++) {
dc->res_pool->stream_enc[i]->funcs->dp_blank(
dc->res_pool->stream_enc[i]);
}
for (i = 0; i < dc->link_count; i++) {
connector_id = dal_graphics_object_id_get_connector_id(dc->links[i]->link_id);
if ((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
......@@ -1178,10 +1408,12 @@ static void power_down_encoders(struct dc *dc)
if (!dc->links[i]->wa_flags.dp_keep_receiver_powered)
dp_receiver_power_ctrl(dc->links[i], false);
if (connector_id == CONNECTOR_ID_EDP)
signal = SIGNAL_TYPE_EDP;
}
dc->links[i]->link_enc->funcs->disable_output(
dc->links[i]->link_enc, SIGNAL_TYPE_NONE);
dc->links[i]->link_enc, signal, dc->links[i]);
}
}
......@@ -1218,7 +1450,7 @@ static void power_down_all_hw_blocks(struct dc *dc)
power_down_clock_sources(dc);
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (dc->fbc_compressor)
dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
#endif
......@@ -1325,7 +1557,7 @@ static void set_safe_displaymarks(
SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK, SAFE_NBP_MARK };
for (i = 0; i < MAX_PIPES; i++) {
if (res_ctx->pipe_ctx[i].stream == NULL)
if (res_ctx->pipe_ctx[i].stream == NULL || res_ctx->pipe_ctx[i].plane_res.mi == NULL)
continue;
res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_display_marks(
......@@ -1334,6 +1566,7 @@ static void set_safe_displaymarks(
max_marks,
max_marks,
MAX_WATERMARK);
if (i == underlay_idx)
res_ctx->pipe_ctx[i].plane_res.mi->funcs->mem_input_program_chroma_display_marks(
res_ctx->pipe_ctx[i].plane_res.mi,
......@@ -1341,6 +1574,7 @@ static void set_safe_displaymarks(
max_marks,
max_marks,
MAX_WATERMARK);
}
}
......@@ -1391,7 +1625,7 @@ static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
if (events->cursor_update)
value |= 0x2;
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
value |= 0x84;
#endif
......@@ -1521,7 +1755,7 @@ static void apply_min_clocks(
}
}
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
/*
* Check if FBC can be enabled
......@@ -1644,7 +1878,10 @@ static void dce110_reset_hw_ctx_wrap(
pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
struct clock_source *old_clk = pipe_ctx_old->clock_source;
core_link_disable_stream(pipe_ctx_old);
/* disable 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);
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)) {
dm_error("DC: failed to blank crtc!\n");
......@@ -1713,7 +1950,7 @@ enum dc_status dce110_apply_ctx_to_hw(
set_safe_displaymarks(&context->res_ctx, dc->res_pool);
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (dc->fbc_compressor)
dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
#endif
......@@ -1889,6 +2126,7 @@ enum dc_status dce110_apply_ctx_to_hw(
return status;
}
/* pplib is notified if disp_num changed */
dc->hwss.set_bandwidth(dc, context, true);
/* to save power */
......@@ -1896,7 +2134,7 @@ enum dc_status dce110_apply_ctx_to_hw(
dcb->funcs->set_scratch_critical_state(dcb, false);
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (dc->fbc_compressor)
enable_fbc(dc, context);
......@@ -2305,7 +2543,7 @@ static void init_hw(struct dc *dc)
abm->funcs->init_backlight(abm);
abm->funcs->abm_init(abm);
}
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (dc->fbc_compressor)
dc->fbc_compressor->funcs->power_up_fbc(dc->fbc_compressor);
#endif
......@@ -2490,6 +2728,8 @@ static void dce110_program_front_end_for_pipe(
struct dc_plane_state *plane_state = pipe_ctx->plane_state;
struct xfm_grph_csc_adjustment adjust;
struct out_csc_color_matrix tbl_entry;
struct pipe_ctx *cur_pipe_ctx =
&dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
unsigned int i;
memset(&tbl_entry, 0, sizeof(tbl_entry));
......@@ -2553,6 +2793,15 @@ static void dce110_program_front_end_for_pipe(
program_scaler(dc, pipe_ctx);
#if defined(CONFIG_DRM_AMD_DC_FBC)
if (dc->fbc_compressor && old_pipe->stream) {
if (plane_state->tiling_info.gfx8.array_mode == DC_ARRAY_LINEAR_GENERAL)
dc->fbc_compressor->funcs->disable_fbc(dc->fbc_compressor);
else
enable_fbc(dc, dc->current_state);
}
#endif
mi->funcs->mem_input_program_surface_config(
mi,
plane_state->format,
......@@ -2571,6 +2820,14 @@ static void dce110_program_front_end_for_pipe(
&plane_state->tiling_info,
plane_state->rotation);
/* Moved programming gamma from dc to hwss */
if (cur_pipe_ctx->plane_state != pipe_ctx->plane_state) {
dc->hwss.set_input_transfer_func(
pipe_ctx, pipe_ctx->plane_state);
dc->hwss.set_output_transfer_func(
pipe_ctx, pipe_ctx->stream);
}
dm_logger_write(dc->ctx->logger, LOG_SURFACE,
"Pipe:%d 0x%x: addr hi:0x%x, "
"addr low:0x%x, "
......@@ -2683,7 +2940,7 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
}
}
static void ready_shared_resources(struct dc *dc) {}
static void ready_shared_resources(struct dc *dc, struct dc_state *context) {}
static void optimize_shared_resources(struct dc *dc) {}
......@@ -2720,7 +2977,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
.wait_for_mpcc_disconnect = dce110_wait_for_mpcc_disconnect,
.ready_shared_resources = ready_shared_resources,
.optimize_shared_resources = optimize_shared_resources,
.edp_backlight_control = hwss_edp_backlight_control,
.edp_power_control = hwss_edp_power_control,
};
void dce110_hw_sequencer_construct(struct dc *dc)
......
......@@ -47,7 +47,7 @@ void dce110_set_displaymarks(
void dce110_enable_stream(struct pipe_ctx *pipe_ctx);
void dce110_disable_stream(struct pipe_ctx *pipe_ctx);
void dce110_disable_stream(struct pipe_ctx *pipe_ctx, int option);
void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
struct dc_link_settings *link_settings);
......@@ -68,5 +68,14 @@ void dce110_fill_display_configs(
uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context);
void dp_receiver_power_ctrl(struct dc_link *link, bool on);
void hwss_edp_power_control(
struct link_encoder *enc,
bool power_up);
void hwss_edp_backlight_control(
struct dc_link *link,
bool enable);
#endif /* __DC_HWSS_DCE110_H__ */
......@@ -52,7 +52,7 @@
#include "dce/dce_abm.h"
#include "dce/dce_dmcu.h"
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
#include "dce110/dce110_compressor.h"
#endif
......@@ -849,7 +849,7 @@ static bool dce110_validate_bandwidth(
static bool dce110_validate_surface_sets(
struct dc_state *context)
{
int i;
int i, j;
for (i = 0; i < context->stream_count; i++) {
if (context->stream_status[i].plane_count == 0)
......@@ -858,14 +858,27 @@ static bool dce110_validate_surface_sets(
if (context->stream_status[i].plane_count > 2)
return false;
if ((context->stream_status[i].plane_states[i]->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) &&
(context->stream_status[i].plane_states[i]->src_rect.width > 1920 ||
context->stream_status[i].plane_states[i]->src_rect.height > 1080))
return false;
for (j = 0; j < context->stream_status[i].plane_count; j++) {
struct dc_plane_state *plane =
context->stream_status[i].plane_states[j];
/* irrespective of plane format, stream should be RGB encoded */
if (context->streams[i]->timing.pixel_encoding != PIXEL_ENCODING_RGB)
return false;
/* underlay validation */
if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
if ((plane->src_rect.width > 1920 ||
plane->src_rect.height > 1080))
return false;
/* irrespective of plane format,
* stream should be RGB encoded
*/
if (context->streams[i]->timing.pixel_encoding
!= PIXEL_ENCODING_RGB)
return false;
}
}
}
return true;
......@@ -1266,7 +1279,7 @@ static bool construct(
}
}
#ifdef ENABLE_FBC
#if defined(CONFIG_DRM_AMD_DC_FBC)
dc->fbc_compressor = dce110_compressor_create(ctx);
......
......@@ -3,8 +3,8 @@
DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \
dcn10_dpp.o dcn10_opp.o dcn10_timing_generator.o \
dcn10_mem_input.o dcn10_mpc.o \
dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_dpp_cm_helper.o
dcn10_hubp.o dcn10_mpc.o \
dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o
AMD_DAL_DCN10 = $(addprefix $(AMDDALPATH)/dc/dcn10/,$(DCN10))
......
......@@ -26,7 +26,7 @@
#include "reg_helper.h"
#include "dcn10_dpp.h"
#include "dcn10_dpp_cm_helper.h"
#include "dcn10_cm_common.h"
#define REG(reg) reg
......
......@@ -23,8 +23,8 @@
*
*/
#ifndef __DAL_DPP_DCN10_CM_HELPER_H__
#define __DAL_DPP_DCN10_CM_HELPER_H__
#ifndef __DAL_DCN10_CM_COMMON_H__
#define __DAL_DCN10_CM_COMMON_H__
#define TF_HELPER_REG_FIELD_LIST(type) \
type exp_region0_lut_offset; \
......
......@@ -39,14 +39,14 @@
#define BLACK_OFFSET_CBCR 0x8000
#define REG(reg)\
xfm->tf_regs->reg
dpp->tf_regs->reg
#define CTX \
xfm->base.ctx
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
xfm->tf_shift->field_name, xfm->tf_mask->field_name
dpp->tf_shift->field_name, dpp->tf_mask->field_name
enum pixel_format_description {
PIXEL_FORMAT_FIXED = 0,
......@@ -99,7 +99,7 @@ enum gamut_remap_select {
};
/* Program gamut remap in bypass mode */
void dpp_set_gamut_remap_bypass(struct dcn10_dpp *xfm)
void dpp_set_gamut_remap_bypass(struct dcn10_dpp *dpp)
{
REG_SET(CM_GAMUT_REMAP_CONTROL, 0,
CM_GAMUT_REMAP_MODE, 0);
......@@ -110,7 +110,7 @@ void dpp_set_gamut_remap_bypass(struct dcn10_dpp *xfm)
bool dpp_get_optimal_number_of_taps(
struct transform *xfm,
struct dpp *dpp,
struct scaler_data *scl_data,
const struct scaling_taps *in_taps)
{
......@@ -154,28 +154,29 @@ bool dpp_get_optimal_number_of_taps(
else
scl_data->taps.h_taps_c = in_taps->h_taps_c;
if (!xfm->ctx->dc->debug.always_scale) {
if (!dpp->ctx->dc->debug.always_scale) {
if (IDENTITY_RATIO(scl_data->ratios.horz))
scl_data->taps.h_taps = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert))
scl_data->taps.v_taps = 1;
if (IDENTITY_RATIO(scl_data->ratios.horz_c))
scl_data->taps.h_taps_c = 1;
if (IDENTITY_RATIO(scl_data->ratios.vert_c))
scl_data->taps.v_taps_c = 1;
/*
* Spreadsheet doesn't handle taps_c is one properly,
* need to force Chroma to always be scaled to pass
* bandwidth validation.
*/
}
return true;
}
void dpp_reset(struct transform *xfm_base)
void dpp_reset(struct dpp *dpp_base)
{
struct dcn10_dpp *xfm = TO_DCN10_DPP(xfm_base);
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
xfm->filter_h_c = NULL;
xfm->filter_v_c = NULL;
xfm->filter_h = NULL;
xfm->filter_v = NULL;
dpp->filter_h_c = NULL;
dpp->filter_v_c = NULL;
dpp->filter_h = NULL;
dpp->filter_v = NULL;
/* set boundary mode to 0 */
REG_SET(DSCL_CONTROL, 0, SCL_BOUNDARY_MODE, 0);
......@@ -183,28 +184,28 @@ void dpp_reset(struct transform *xfm_base)
static void dcn10_dpp_cm_set_regamma_pwl(
struct transform *xfm_base, const struct pwl_params *params)
static void dpp1_cm_set_regamma_pwl(
struct dpp *dpp_base, const struct pwl_params *params)
{
struct dcn10_dpp *xfm = TO_DCN10_DPP(xfm_base);
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
dcn10_dpp_cm_power_on_regamma_lut(xfm_base, true);
dcn10_dpp_cm_configure_regamma_lut(xfm_base, xfm->is_write_to_ram_a_safe);
dpp1_cm_power_on_regamma_lut(dpp_base, true);
dpp1_cm_configure_regamma_lut(dpp_base, dpp->is_write_to_ram_a_safe);
if (xfm->is_write_to_ram_a_safe)
dcn10_dpp_cm_program_regamma_luta_settings(xfm_base, params);
if (dpp->is_write_to_ram_a_safe)
dpp1_cm_program_regamma_luta_settings(dpp_base, params);
else
dcn10_dpp_cm_program_regamma_lutb_settings(xfm_base, params);
dpp1_cm_program_regamma_lutb_settings(dpp_base, params);
dcn10_dpp_cm_program_regamma_lut(
xfm_base, params->rgb_resulted, params->hw_points_num);
dpp1_cm_program_regamma_lut(
dpp_base, params->rgb_resulted, params->hw_points_num);
}
static void dcn10_dpp_cm_set_regamma_mode(
struct transform *xfm_base,
static void dpp1_cm_set_regamma_mode(
struct dpp *dpp_base,
enum opp_regamma mode)
{
struct dcn10_dpp *xfm = TO_DCN10_DPP(xfm_base);
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
uint32_t re_mode = 0;
uint32_t obuf_bypass = 0; /* need for pipe split */
uint32_t obuf_hupscale = 0;
......@@ -220,8 +221,8 @@ static void dcn10_dpp_cm_set_regamma_mode(
re_mode = 2;
break;
case OPP_REGAMMA_USER:
re_mode = xfm->is_write_to_ram_a_safe ? 3 : 4;
xfm->is_write_to_ram_a_safe = !xfm->is_write_to_ram_a_safe;
re_mode = dpp->is_write_to_ram_a_safe ? 3 : 4;
dpp->is_write_to_ram_a_safe = !dpp->is_write_to_ram_a_safe;
break;
default:
break;
......@@ -233,7 +234,7 @@ static void dcn10_dpp_cm_set_regamma_mode(
OBUF_H_2X_UPSCALE_EN, obuf_hupscale);
}
static void ippn10_setup_format_flags(enum surface_pixel_format input_format,\
static void dpp1_setup_format_flags(enum surface_pixel_format input_format,\
enum pixel_format_description *fmt)
{
......@@ -246,11 +247,11 @@ static void ippn10_setup_format_flags(enum surface_pixel_format input_format,\
*fmt = PIXEL_FORMAT_FIXED;
}
static void ippn10_set_degamma_format_float(
struct transform *xfm_base,
static void dpp1_set_degamma_format_float(
struct dpp *dpp_base,
bool is_float)
{
struct dcn10_dpp *xfm = TO_DCN10_DPP(xfm_base);
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
if (is_float) {
REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 3);
......@@ -261,8 +262,8 @@ static void ippn10_set_degamma_format_float(
}
}
void ippn10_cnv_setup (
struct transform *xfm_base,
void dpp1_cnv_setup (
struct dpp *dpp_base,
enum surface_pixel_format input_format,
enum expansion_mode mode)
{
......@@ -272,10 +273,10 @@ void ippn10_cnv_setup (
enum dc_color_space color_space;
enum dcn10_input_csc_select select;
bool is_float;
struct dcn10_dpp *xfm = TO_DCN10_DPP(xfm_base);
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
bool force_disable_cursor = false;
ippn10_setup_format_flags(input_format, &fmt);
dpp1_setup_format_flags(input_format, &fmt);
alpha_en = 1;
pixel_format = 0;
color_space = COLOR_SPACE_SRGB;
......@@ -303,7 +304,7 @@ void ippn10_cnv_setup (
break;
}
ippn10_set_degamma_format_float(xfm_base, is_float);
dpp1_set_degamma_format_float(dpp_base, is_float);
switch (input_format) {
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
......@@ -361,7 +362,7 @@ void ippn10_cnv_setup (
CNVC_SURFACE_PIXEL_FORMAT, pixel_format);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en);
ippn10_program_input_csc(xfm_base, color_space, select);
dpp1_program_input_csc(dpp_base, color_space, select);
if (force_disable_cursor) {
REG_UPDATE(CURSOR_CONTROL,
......@@ -371,54 +372,110 @@ void ippn10_cnv_setup (
}
}
static const struct transform_funcs dcn10_dpp_funcs = {
.transform_reset = dpp_reset,
.transform_set_scaler = dcn10_dpp_dscl_set_scaler_manual_scale,
.transform_get_optimal_number_of_taps = dpp_get_optimal_number_of_taps,
.transform_set_gamut_remap = dcn10_dpp_cm_set_gamut_remap,
.opp_set_csc_adjustment = dcn10_dpp_cm_set_output_csc_adjustment,
.opp_set_csc_default = dcn10_dpp_cm_set_output_csc_default,
.opp_power_on_regamma_lut = dcn10_dpp_cm_power_on_regamma_lut,
.opp_program_regamma_lut = dcn10_dpp_cm_program_regamma_lut,
.opp_configure_regamma_lut = dcn10_dpp_cm_configure_regamma_lut,
.opp_program_regamma_lutb_settings = dcn10_dpp_cm_program_regamma_lutb_settings,
.opp_program_regamma_luta_settings = dcn10_dpp_cm_program_regamma_luta_settings,
.opp_program_regamma_pwl = dcn10_dpp_cm_set_regamma_pwl,
.opp_set_regamma_mode = dcn10_dpp_cm_set_regamma_mode,
.ipp_set_degamma = ippn10_set_degamma,
.ipp_program_input_lut = ippn10_program_input_lut,
.ipp_program_degamma_pwl = ippn10_set_degamma_pwl,
.ipp_setup = ippn10_cnv_setup,
.ipp_full_bypass = ippn10_full_bypass,
void dpp1_set_cursor_attributes(
struct dpp *dpp_base,
const struct dc_cursor_attributes *attr)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
enum dc_cursor_color_format color_format = attr->color_format;
REG_UPDATE_2(CURSOR0_CONTROL,
CUR0_MODE, color_format,
CUR0_EXPANSION_MODE, 0);
if (color_format == CURSOR_MODE_MONO) {
/* todo: clarify what to program these to */
REG_UPDATE(CURSOR0_COLOR0,
CUR0_COLOR0, 0x00000000);
REG_UPDATE(CURSOR0_COLOR1,
CUR0_COLOR1, 0xFFFFFFFF);
}
/* TODO: Fixed vs float */
REG_UPDATE_3(FORMAT_CONTROL,
CNVC_BYPASS, 0,
FORMAT_CONTROL__ALPHA_EN, 1,
FORMAT_EXPANSION_MODE, 0);
}
void dpp1_set_cursor_position(
struct dpp *dpp_base,
const struct dc_cursor_position *pos,
const struct dc_cursor_mi_param *param,
uint32_t width)
{
struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base);
int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start;
uint32_t cur_en = pos->enable ? 1 : 0;
if (src_x_offset >= (int)param->viewport_width)
cur_en = 0; /* not visible beyond right edge*/
if (src_x_offset + (int)width < 0)
cur_en = 0; /* not visible beyond left edge*/
REG_UPDATE(CURSOR0_CONTROL,
CUR0_ENABLE, cur_en);
}
static const struct dpp_funcs dcn10_dpp_funcs = {
.dpp_reset = dpp_reset,
.dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale,
.dpp_get_optimal_number_of_taps = dpp_get_optimal_number_of_taps,
.dpp_set_gamut_remap = dpp1_cm_set_gamut_remap,
.opp_set_csc_adjustment = dpp1_cm_set_output_csc_adjustment,
.opp_set_csc_default = dpp1_cm_set_output_csc_default,
.opp_power_on_regamma_lut = dpp1_cm_power_on_regamma_lut,
.opp_program_regamma_lut = dpp1_cm_program_regamma_lut,
.opp_configure_regamma_lut = dpp1_cm_configure_regamma_lut,
.opp_program_regamma_lutb_settings = dpp1_cm_program_regamma_lutb_settings,
.opp_program_regamma_luta_settings = dpp1_cm_program_regamma_luta_settings,
.opp_program_regamma_pwl = dpp1_cm_set_regamma_pwl,
.opp_set_regamma_mode = dpp1_cm_set_regamma_mode,
.ipp_set_degamma = dpp1_set_degamma,
.ipp_program_input_lut = dpp1_program_input_lut,
.ipp_program_degamma_pwl = dpp1_set_degamma_pwl,
.ipp_setup = dpp1_cnv_setup,
.ipp_full_bypass = dpp1_full_bypass,
.set_cursor_attributes = dpp1_set_cursor_attributes,
.set_cursor_position = dpp1_set_cursor_position,
};
static struct dpp_caps dcn10_dpp_cap = {
.dscl_data_proc_format = DSCL_DATA_PRCESSING_FIXED_FORMAT,
.dscl_calc_lb_num_partitions = dpp1_dscl_calc_lb_num_partitions,
};
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
void dcn10_dpp_construct(
struct dcn10_dpp *xfm,
void dpp1_construct(
struct dcn10_dpp *dpp,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_dpp_registers *tf_regs,
const struct dcn_dpp_shift *tf_shift,
const struct dcn_dpp_mask *tf_mask)
{
xfm->base.ctx = ctx;
dpp->base.ctx = ctx;
xfm->base.inst = inst;
xfm->base.funcs = &dcn10_dpp_funcs;
dpp->base.inst = inst;
dpp->base.funcs = &dcn10_dpp_funcs;
dpp->base.caps = &dcn10_dpp_cap;
xfm->tf_regs = tf_regs;
xfm->tf_shift = tf_shift;
xfm->tf_mask = tf_mask;
dpp->tf_regs = tf_regs;
dpp->tf_shift = tf_shift;
dpp->tf_mask = tf_mask;
xfm->lb_pixel_depth_supported =
dpp->lb_pixel_depth_supported =
LB_PIXEL_DEPTH_18BPP |
LB_PIXEL_DEPTH_24BPP |
LB_PIXEL_DEPTH_30BPP;
xfm->lb_bits_per_entry = LB_BITS_PER_ENTRY;
xfm->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/
dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY;
dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/
}
......@@ -25,10 +25,10 @@
#ifndef __DAL_DPP_DCN10_H__
#define __DAL_DPP_DCN10_H__
#include "transform.h"
#include "dpp.h"
#define TO_DCN10_DPP(transform)\
container_of(transform, struct dcn10_dpp, base)
#define TO_DCN10_DPP(dpp)\
container_of(dpp, struct dcn10_dpp, base)
/* TODO: Use correct number of taps. Using polaris values for now */
#define LB_TOTAL_NUMBER_OF_ENTRIES 5124
......@@ -112,7 +112,9 @@
SRI(CM_DGAM_CONTROL, CM, id), \
SRI(FORMAT_CONTROL, CNVC_CFG, id), \
SRI(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \
SRI(CURSOR0_CONTROL, CNVC_CUR, id)
SRI(CURSOR0_CONTROL, CNVC_CUR, id), \
SRI(CURSOR0_COLOR0, CNVC_CUR, id), \
SRI(CURSOR0_COLOR1, CNVC_CUR, id)
......@@ -162,7 +164,8 @@
SRI(CM_IGAM_LUT_RW_CONTROL, CM, id), \
SRI(CM_IGAM_LUT_RW_INDEX, CM, id), \
SRI(CM_IGAM_LUT_SEQ_COLOR, CM, id), \
SRI(CURSOR_CONTROL, CURSOR, id)
SRI(CURSOR_CONTROL, CURSOR, id), \
SRI(CM_CMOUT_CONTROL, CM, id)
#define TF_REG_LIST_SH_MASK_DCN(mask_sh)\
......@@ -302,7 +305,9 @@
TF_SF(CNVC_CFG0_CNVC_SURFACE_PIXEL_FORMAT, CNVC_SURFACE_PIXEL_FORMAT, mask_sh), \
TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_MODE, mask_sh), \
TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_EXPANSION_MODE, mask_sh), \
TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh)
TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \
TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \
TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh)
#define TF_REG_LIST_SH_MASK_DCN10(mask_sh)\
TF_REG_LIST_SH_MASK_DCN(mask_sh),\
......@@ -397,6 +402,7 @@
TF_SF(CM0_CM_CONTROL, CM_BYPASS_EN, mask_sh), \
TF_SF(CM0_CM_IGAM_LUT_SEQ_COLOR, CM_IGAM_LUT_SEQ_COLOR, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, OUTPUT_FP, mask_sh), \
TF_SF(CM0_CM_CMOUT_CONTROL, CM_CMOUT_ROUND_TRUNC_MODE, mask_sh), \
TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \
TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \
TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \
......@@ -545,6 +551,7 @@
type CM_RGAM_RAMA_EXP_REGION33_LUT_OFFSET; \
type CM_RGAM_RAMA_EXP_REGION33_NUM_SEGMENTS; \
type CM_RGAM_LUT_MODE; \
type CM_CMOUT_ROUND_TRUNC_MODE; \
type OBUF_BYPASS; \
type OBUF_H_2X_UPSCALE_EN; \
type CM_BLNDGAM_LUT_MODE; \
......@@ -989,7 +996,9 @@
type CUR0_EXPANSION_MODE; \
type CUR0_ENABLE; \
type CM_BYPASS; \
type FORMAT_CONTROL__ALPHA_EN
type FORMAT_CONTROL__ALPHA_EN; \
type CUR0_COLOR0; \
type CUR0_COLOR1
......@@ -1075,6 +1084,7 @@ struct dcn_dpp_registers {
uint32_t CM_RGAM_RAMA_REGION_0_1;
uint32_t CM_RGAM_RAMA_REGION_32_33;
uint32_t CM_RGAM_CONTROL;
uint32_t CM_CMOUT_CONTROL;
uint32_t OBUF_CONTROL;
uint32_t CM_BLNDGAM_LUT_WRITE_EN_MASK;
uint32_t CM_BLNDGAM_CONTROL;
......@@ -1237,10 +1247,12 @@ struct dcn_dpp_registers {
uint32_t CNVC_SURFACE_PIXEL_FORMAT;
uint32_t CURSOR_CONTROL;
uint32_t CURSOR0_CONTROL;
uint32_t CURSOR0_COLOR0;
uint32_t CURSOR0_COLOR1;
};
struct dcn10_dpp {
struct transform base;
struct dpp base;
const struct dcn_dpp_registers *tf_regs;
const struct dcn_dpp_shift *tf_shift;
......@@ -1256,107 +1268,116 @@ struct dcn10_dpp {
bool is_write_to_ram_a_safe;
};
enum dcn10_input_csc_select {
INPUT_CSC_SELECT_BYPASS = 0,
INPUT_CSC_SELECT_ICSC,
INPUT_CSC_SELECT_COMA
};
void ippn10_degamma_ram_select(
struct transform *xfm_base,
bool dpp1_dscl_is_lb_conf_valid(
int ceil_vratio,
int num_partitions,
int vtaps);
void dpp1_dscl_calc_lb_num_partitions(
const struct scaler_data *scl_data,
enum lb_memory_config lb_config,
int *num_part_y,
int *num_part_c);
void dpp1_degamma_ram_select(
struct dpp *dpp_base,
bool use_ram_a);
void ippn10_program_degamma_luta_settings(
struct transform *xfm_base,
void dpp1_program_degamma_luta_settings(
struct dpp *dpp_base,
const struct pwl_params *params);
void ippn10_program_degamma_lutb_settings(
struct transform *xfm_base,
void dpp1_program_degamma_lutb_settings(
struct dpp *dpp_base,
const struct pwl_params *params);
void ippn10_program_degamma_lut(
struct transform *xfm_base,
void dpp1_program_degamma_lut(
struct dpp *dpp_base,
const struct pwl_result_data *rgb,
uint32_t num,
bool is_ram_a);
void ippn10_power_on_degamma_lut(
struct transform *xfm_base,
void dpp1_power_on_degamma_lut(
struct dpp *dpp_base,
bool power_on);
void ippn10_program_input_csc(
struct transform *xfm_base,
void dpp1_program_input_csc(
struct dpp *dpp_base,
enum dc_color_space color_space,
enum dcn10_input_csc_select select);
void ippn10_program_input_lut(
struct transform *xfm_base,
void dpp1_program_input_lut(
struct dpp *dpp_base,
const struct dc_gamma *gamma);
void ippn10_full_bypass(struct transform *xfm_base);
void dpp1_full_bypass(struct dpp *dpp_base);
void ippn10_set_degamma(
struct transform *xfm_base,
void dpp1_set_degamma(
struct dpp *dpp_base,
enum ipp_degamma_mode mode);
void ippn10_set_degamma_pwl(struct transform *xfm_base,
void dpp1_set_degamma_pwl(struct dpp *dpp_base,
const struct pwl_params *params);
bool dpp_get_optimal_number_of_taps(
struct transform *xfm,
struct dpp *dpp,
struct scaler_data *scl_data,
const struct scaling_taps *in_taps);
void dpp_reset(struct transform *xfm_base);
void dpp_reset(struct dpp *dpp_base);
void dcn10_dpp_cm_program_regamma_lut(
struct transform *xfm_base,
void dpp1_cm_program_regamma_lut(
struct dpp *dpp_base,
const struct pwl_result_data *rgb,
uint32_t num);
void dcn10_dpp_cm_power_on_regamma_lut(
struct transform *xfm_base,
void dpp1_cm_power_on_regamma_lut(
struct dpp *dpp_base,
bool power_on);
void dcn10_dpp_cm_configure_regamma_lut(
struct transform *xfm_base,
void dpp1_cm_configure_regamma_lut(
struct dpp *dpp_base,
bool is_ram_a);
/*program re gamma RAM A*/
void dcn10_dpp_cm_program_regamma_luta_settings(
struct transform *xfm_base,
void dpp1_cm_program_regamma_luta_settings(
struct dpp *dpp_base,
const struct pwl_params *params);
/*program re gamma RAM B*/
void dcn10_dpp_cm_program_regamma_lutb_settings(
struct transform *xfm_base,
void dpp1_cm_program_regamma_lutb_settings(
struct dpp *dpp_base,
const struct pwl_params *params);
void dcn10_dpp_cm_set_output_csc_adjustment(
struct transform *xfm_base,
void dpp1_cm_set_output_csc_adjustment(
struct dpp *dpp_base,
const struct out_csc_color_matrix *tbl_entry);
void dcn10_dpp_cm_set_output_csc_default(
struct transform *xfm_base,
void dpp1_cm_set_output_csc_default(
struct dpp *dpp_base,
const struct default_adjustment *default_adjust);
void dcn10_dpp_cm_set_gamut_remap(
struct transform *xfm,
const struct xfm_grph_csc_adjustment *adjust);
void dpp1_cm_set_gamut_remap(
struct dpp *dpp,
const struct dpp_grph_csc_adjustment *adjust);
void dcn10_dpp_dscl_set_scaler_manual_scale(
struct transform *xfm_base,
void dpp1_dscl_set_scaler_manual_scale(
struct dpp *dpp_base,
const struct scaler_data *scl_data);
void ippn10_cnv_setup (
struct transform *xfm_base,
void dpp1_cnv_setup (
struct dpp *dpp_base,
enum surface_pixel_format input_format,
enum expansion_mode mode);
void ippn10_full_bypass(struct transform *xfm_base);
void dpp1_full_bypass(struct dpp *dpp_base);
void dcn10_dpp_construct(struct dcn10_dpp *xfm110,
void dpp1_construct(struct dcn10_dpp *dpp1,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_dpp_registers *tf_regs,
......
......@@ -37,188 +37,6 @@
#define CTX \
ippn10->base.ctx
static bool ippn10_cursor_program_control(
struct dcn10_ipp *ippn10,
bool pixel_data_invert,
enum dc_cursor_color_format color_format)
{
if (REG(CURSOR_SETTINS))
REG_SET_2(CURSOR_SETTINS, 0,
/* no shift of the cursor HDL schedule */
CURSOR0_DST_Y_OFFSET, 0,
/* used to shift the cursor chunk request deadline */
CURSOR0_CHUNK_HDL_ADJUST, 3);
else
REG_SET_2(CURSOR_SETTINGS, 0,
/* no shift of the cursor HDL schedule */
CURSOR0_DST_Y_OFFSET, 0,
/* used to shift the cursor chunk request deadline */
CURSOR0_CHUNK_HDL_ADJUST, 3);
REG_UPDATE_2(CURSOR0_CONTROL,
CUR0_MODE, color_format,
CUR0_EXPANSION_MODE, 0);
if (color_format == CURSOR_MODE_MONO) {
/* todo: clarify what to program these to */
REG_UPDATE(CURSOR0_COLOR0,
CUR0_COLOR0, 0x00000000);
REG_UPDATE(CURSOR0_COLOR1,
CUR0_COLOR1, 0xFFFFFFFF);
}
/* TODO: Fixed vs float */
REG_UPDATE_3(FORMAT_CONTROL,
CNVC_BYPASS, 0,
ALPHA_EN, 1,
FORMAT_EXPANSION_MODE, 0);
return true;
}
enum cursor_pitch {
CURSOR_PITCH_64_PIXELS = 0,
CURSOR_PITCH_128_PIXELS,
CURSOR_PITCH_256_PIXELS
};
enum cursor_lines_per_chunk {
CURSOR_LINE_PER_CHUNK_2 = 1,
CURSOR_LINE_PER_CHUNK_4,
CURSOR_LINE_PER_CHUNK_8,
CURSOR_LINE_PER_CHUNK_16
};
static enum cursor_pitch ippn10_get_cursor_pitch(
unsigned int pitch)
{
enum cursor_pitch hw_pitch;
switch (pitch) {
case 64:
hw_pitch = CURSOR_PITCH_64_PIXELS;
break;
case 128:
hw_pitch = CURSOR_PITCH_128_PIXELS;
break;
case 256:
hw_pitch = CURSOR_PITCH_256_PIXELS;
break;
default:
DC_ERR("Invalid cursor pitch of %d. "
"Only 64/128/256 is supported on DCN.\n", pitch);
hw_pitch = CURSOR_PITCH_64_PIXELS;
break;
}
return hw_pitch;
}
static enum cursor_lines_per_chunk ippn10_get_lines_per_chunk(
unsigned int cur_width,
enum dc_cursor_color_format format)
{
enum cursor_lines_per_chunk line_per_chunk;
if (format == CURSOR_MODE_MONO)
/* impl B. expansion in CUR Buffer reader */
line_per_chunk = CURSOR_LINE_PER_CHUNK_16;
else if (cur_width <= 32)
line_per_chunk = CURSOR_LINE_PER_CHUNK_16;
else if (cur_width <= 64)
line_per_chunk = CURSOR_LINE_PER_CHUNK_8;
else if (cur_width <= 128)
line_per_chunk = CURSOR_LINE_PER_CHUNK_4;
else
line_per_chunk = CURSOR_LINE_PER_CHUNK_2;
return line_per_chunk;
}
static void ippn10_cursor_set_attributes(
struct input_pixel_processor *ipp,
const struct dc_cursor_attributes *attr)
{
struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
enum cursor_pitch hw_pitch = ippn10_get_cursor_pitch(attr->pitch);
enum cursor_lines_per_chunk lpc = ippn10_get_lines_per_chunk(
attr->width, attr->color_format);
ippn10->curs_attr = *attr;
REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
REG_UPDATE(CURSOR_SURFACE_ADDRESS,
CURSOR_SURFACE_ADDRESS, attr->address.low_part);
REG_UPDATE_2(CURSOR_SIZE,
CURSOR_WIDTH, attr->width,
CURSOR_HEIGHT, attr->height);
REG_UPDATE_3(CURSOR_CONTROL,
CURSOR_MODE, attr->color_format,
CURSOR_PITCH, hw_pitch,
CURSOR_LINES_PER_CHUNK, lpc);
ippn10_cursor_program_control(ippn10,
attr->attribute_flags.bits.INVERT_PIXEL_DATA,
attr->color_format);
}
static void ippn10_cursor_set_position(
struct input_pixel_processor *ipp,
const struct dc_cursor_position *pos,
const struct dc_cursor_mi_param *param)
{
struct dcn10_ipp *ippn10 = TO_DCN10_IPP(ipp);
int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start;
uint32_t cur_en = pos->enable ? 1 : 0;
uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 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 (ippn10->curs_attr.address.quad_part == 0)
return;
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 = dal_fixed31_32_floor(dal_fixed31_32_div(
dal_fixed31_32_from_int(dst_x_offset),
param->h_scale_ratio));
if (src_x_offset >= (int)param->viewport_width)
cur_en = 0; /* not visible beyond right edge*/
if (src_x_offset + (int)ippn10->curs_attr.width < 0)
cur_en = 0; /* not visible beyond left edge*/
if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0)
ippn10_cursor_set_attributes(ipp, &ippn10->curs_attr);
REG_UPDATE(CURSOR_CONTROL,
CURSOR_ENABLE, cur_en);
REG_UPDATE(CURSOR0_CONTROL,
CUR0_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, pos->x_hotspot,
CURSOR_HOT_SPOT_Y, pos->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 */
}
/*****************************************/
/* Constructor, Destructor */
/*****************************************/
......@@ -230,13 +48,6 @@ static void dcn10_ipp_destroy(struct input_pixel_processor **ipp)
}
static const struct ipp_funcs dcn10_ipp_funcs = {
.ipp_cursor_set_attributes = ippn10_cursor_set_attributes,
.ipp_cursor_set_position = ippn10_cursor_set_position,
.ipp_set_degamma = NULL,
.ipp_program_input_lut = NULL,
.ipp_full_bypass = NULL,
.ipp_setup = NULL,
.ipp_program_degamma_pwl = NULL,
.ipp_destroy = dcn10_ipp_destroy
};
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册