]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
drm/amd: Add abm level drm property
authorDavid Francis <David.Francis@amd.com>
Mon, 26 Nov 2018 20:51:09 +0000 (15:51 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 26 Nov 2018 20:54:27 +0000 (15:54 -0500)
Adaptive Backlight Management (ABM) is a feature
that reduces backlight level to save power, while
increasing pixel contrast and pixel luminance
to maintain readability and image quality.

ABM will adjust in response to the
pixel luminance of the displayed content.

ABM is made available as a drm property on eDP
monitors called "abm level", which ranges from 0 to 4.
When this property is set to 0, ABM is off.  Levels 1
to 4 represent different ranges of backlight reduction.
At higher levels both the backlight reduction and pixel
adjustment will be greater.

ABM requires DMCU firmware, which is currently available for
Raven ASICs only.  If the feature does not work, please
ensure your firmware is up to date.

v2:
Fix commit message, only attach property if DMCU loaded
v3:
Store ABM level in crtc state to accommodate dc
v4:
Fix ABM saving on dpms cycle

Signed-off-by: David Francis <David.Francis@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dc.h

index 686a26de50f91e816471548bf3c1a0fc3f86db86..aa121e30d7152a5c3d785c55a4a297dc3c311e95 100644 (file)
@@ -631,6 +631,11 @@ int amdgpu_display_modeset_create_props(struct amdgpu_device *adev)
                        drm_property_create_range(adev->ddev, 0, "max bpc", 8, 16);
                if (!adev->mode_info.max_bpc_property)
                        return -ENOMEM;
+               adev->mode_info.abm_level_property =
+                       drm_property_create_range(adev->ddev, 0,
+                                               "abm level", 0, 4);
+               if (!adev->mode_info.abm_level_property)
+                       return -ENOMEM;
        }
 
        return 0;
index 0dc2c5c57015947bc98204df4639be5be12b1f09..ef5664b403a93dc9aad728ecb1fe4c3e3d2cd6c5 100644 (file)
@@ -340,6 +340,8 @@ struct amdgpu_mode_info {
        struct drm_property *dither_property;
        /* maximum number of bits per channel for monitor color */
        struct drm_property *max_bpc_property;
+       /* Adaptive Backlight Modulation (power feature) */
+       struct drm_property *abm_level_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
index 1701225edc50e36abcb964d93b10216a3b94e85a..1ed079a6ca81fc45287a4f09d4d7ab74cd12cdf0 100644 (file)
@@ -2948,6 +2948,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
        state->adjust = cur->adjust;
        state->vrr_infopacket = cur->vrr_infopacket;
        state->freesync_enabled = cur->freesync_enabled;
+       state->abm_level = cur->abm_level;
 
        /* TODO Duplicate dc_stream after objects are stream object is flattened */
 
@@ -3065,6 +3066,9 @@ int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
        } else if (property == adev->mode_info.max_bpc_property) {
                dm_new_state->max_bpc = val;
                ret = 0;
+       } else if (property == adev->mode_info.abm_level_property) {
+               dm_new_state->abm_level = val;
+               ret = 0;
        }
 
        return ret;
@@ -3110,7 +3114,11 @@ int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
        } else if (property == adev->mode_info.max_bpc_property) {
                *val = dm_state->max_bpc;
                ret = 0;
+       } else if (property == adev->mode_info.abm_level_property) {
+               *val = dm_state->abm_level;
+               ret = 0;
        }
+
        return ret;
 }
 
@@ -3175,6 +3183,7 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
 
        new_state->freesync_capable = state->freesync_capable;
        new_state->freesync_enable = state->freesync_enable;
+       new_state->abm_level = state->abm_level;
 
        return &new_state->base;
 }
@@ -3924,6 +3933,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
                                adev->mode_info.max_bpc_property,
                                0);
 
+       if (connector_type == DRM_MODE_CONNECTOR_eDP &&
+           dc_is_dmcu_initialized(adev->dm.dc)) {
+               drm_object_attach_property(&aconnector->base.base,
+                               adev->mode_info.abm_level_property, 0);
+       }
 }
 
 static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -4430,6 +4444,7 @@ static bool commit_planes_to_stream(
        struct dc_stream_state *dc_stream = dm_new_crtc_state->stream;
        struct dc_stream_update *stream_update =
                        kzalloc(sizeof(struct dc_stream_update), GFP_KERNEL);
+       unsigned int abm_level;
 
        if (!stream_update) {
                BREAK_TO_DEBUGGER();
@@ -4462,6 +4477,11 @@ static bool commit_planes_to_stream(
                stream_update->adjust = &dc_stream->adjust;
        }
 
+       if (dm_new_crtc_state->abm_level != dm_old_crtc_state->abm_level) {
+               abm_level = dm_new_crtc_state->abm_level;
+               stream_update->abm_level = &abm_level;
+       }
+
        for (i = 0; i < new_plane_count; i++) {
                updates[i].surface = plane_states[i];
                updates[i].gamma =
@@ -4599,6 +4619,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
 
                dc_stream_attach->adjust = acrtc_state->adjust;
                dc_stream_attach->vrr_infopacket = acrtc_state->vrr_infopacket;
+               dc_stream_attach->abm_level = acrtc_state->abm_level;
 
                if (false == commit_planes_to_stream(dm->dc,
                                                        plane_states_constructed,
@@ -4779,7 +4800,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                }
        }
 
-       /* Handle scaling and underscan changes*/
+       /* Handle scaling, underscan, and abm changes*/
        for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
                struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
                struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
@@ -4795,11 +4816,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state))
                        continue;
 
-               /* Skip anything that is not scaling or underscan changes */
-               if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
-                       continue;
 
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+               /* Skip anything that is not scaling or underscan changes */
+               if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state) &&
+                               (dm_new_crtc_state->abm_level == dm_old_crtc_state->abm_level))
+                       continue;
 
                update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
                                dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
@@ -4813,6 +4837,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
 
                dm_new_crtc_state->stream->adjust = dm_new_crtc_state->adjust;
                dm_new_crtc_state->stream->vrr_infopacket = dm_new_crtc_state->vrr_infopacket;
+               dm_new_crtc_state->stream->abm_level = dm_new_crtc_state->abm_level;
 
                /*TODO How it works with MPO ?*/
                if (!commit_planes_to_stream(
@@ -5151,6 +5176,8 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm,
                        set_freesync_on_stream(dm, dm_new_crtc_state,
                                               dm_new_conn_state, new_stream);
 
+                       dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level;
+
                        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;
index 607c3cdd7d0c25039232d644cfc97295ed49f56d..0512a98109135833873172cdd9f806bd619b7934 100644 (file)
@@ -234,6 +234,8 @@ struct dm_crtc_state {
        bool freesync_enabled;
        struct dc_crtc_timing_adjust adjust;
        struct dc_info_packet vrr_infopacket;
+
+       int abm_level;
 };
 
 #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base)
@@ -256,6 +258,7 @@ struct dm_connector_state {
        bool underscan_enable;
        bool freesync_enable;
        bool freesync_capable;
+       uint8_t abm_level;
 };
 
 #define to_dm_connector_state(x)\
index 1d8bd554869ba919d054f85d8d3d5ff7d1fd6b7f..dba6b57830c78c832f48905514d859601d46803f 100644 (file)
@@ -1686,6 +1686,15 @@ void dc_resume(struct dc *dc)
                core_link_resume(dc->links[i]);
 }
 
+bool dc_is_dmcu_initialized(struct dc *dc)
+{
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+
+       if (dmcu)
+               return dmcu->funcs->is_dmcu_initialized(dmcu);
+       return false;
+}
+
 bool dc_submit_i2c(
                struct dc *dc,
                uint32_t link_index,
@@ -1810,4 +1819,4 @@ void get_clock_requirements_for_state(struct dc_state *state, struct AsicStateEx
        info->dcfClockDeepSleep                 = (unsigned int)state->bw.dcn.clk.dcfclk_deep_sleep_khz;
        info->fClock                                    = (unsigned int)state->bw.dcn.clk.fclk_khz;
        info->phyClock                                  = (unsigned int)state->bw.dcn.clk.phyclk_khz;
-}
\ No newline at end of file
+}
index 6b0988310138d398001d11e5157509915db4dbf7..dea8bc39c688cdcda34d995d9c14e5f370b88985 100644 (file)
@@ -742,5 +742,6 @@ void dc_set_power_state(
                struct dc *dc,
                enum dc_acpi_cm_power_state power_state);
 void dc_resume(struct dc *dc);
+bool dc_is_dmcu_initialized(struct dc *dc);
 
 #endif /* DC_INTERFACE_H_ */