[Intel-gfx] [RFC CABC PATCH v2 3/3] drm/i915: CABC support for backlight control

Singh, Gaurav K gaurav.k.singh at intel.com
Wed Aug 5 00:50:31 PDT 2015



On 7/30/2015 4:18 PM, Singh, Gaurav K wrote:
>
>
> On 7/24/2015 5:54 PM, Deepak M wrote:
>> In CABC (Content Adaptive Brightness Control) content grey level
>> scale can be increased while simultaneously decreasing
>> brightness of the backlight to achieve same perceived brightness.
>>
>> The CABC is not standardized and panel vendors are free to follow
>> their implementation. The CABC implementaion here assumes that the
>> panels use standard SW register for control.
>>
>> In this design there will be no PWM signal from the SoC and DCS
>> commands are sent to enable and control the backlight brightness.
>>
>> v2:
>> - Created a new backlight driver for cabc, which will be registered
>>    only when it cabc is supported by panel.
>>    (Addressed comment from Daniel Vetter)
>>
>> Signed-off-by: Deepak M <m.deepak at intel.com>
>> ---
>>   drivers/gpu/drm/i915/Makefile         |    1 +
>>   drivers/gpu/drm/i915/intel_drv.h      |    3 +-
>>   drivers/gpu/drm/i915/intel_dsi.c      |   13 ++
>>   drivers/gpu/drm/i915/intel_dsi_cabc.c |  349 
>> +++++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/intel_dsi_cabc.h |   45 +++++
>>   drivers/gpu/drm/i915/intel_panel.c    |   22 ++-
>>   include/video/mipi_display.h          |    8 +
>>   7 files changed, 436 insertions(+), 5 deletions(-)
>>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.c
>>   create mode 100644 drivers/gpu/drm/i915/intel_dsi_cabc.h
>>
>> diff --git a/drivers/gpu/drm/i915/Makefile 
>> b/drivers/gpu/drm/i915/Makefile
>> index de21965..a73953c 100644
>> --- a/drivers/gpu/drm/i915/Makefile
>> +++ b/drivers/gpu/drm/i915/Makefile
>> @@ -75,6 +75,7 @@ i915-y += dvo_ch7017.o \
>>         intel_dp_mst.o \
>>         intel_dsi.o \
>>         intel_dsi_pll.o \
>> +      intel_dsi_cabc.o \
>>         intel_dsi_panel_vbt.o \
>>         intel_dvo.o \
>>         intel_hdmi.o \
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h 
>> b/drivers/gpu/drm/i915/intel_drv.h
>> index 3f0a890..9f806dd5 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1319,7 +1319,8 @@ extern struct drm_display_mode 
>> *intel_find_panel_downclock(
>>                   struct drm_connector *connector);
>>   void intel_backlight_register(struct drm_device *dev);
>>   void intel_backlight_unregister(struct drm_device *dev);
>> -
>> +extern int cabc_backlight_device_register(struct intel_connector 
>> *connector);
>> +extern void cabc_backlight_device_unregister(struct intel_connector 
>> *connector);
>>     /* intel_psr.c */
>>   void intel_psr_enable(struct intel_dp *intel_dp);
>> diff --git a/drivers/gpu/drm/i915/intel_dsi.c 
>> b/drivers/gpu/drm/i915/intel_dsi.c
>> index 98998e9..8f006f2 100644
>> --- a/drivers/gpu/drm/i915/intel_dsi.c
>> +++ b/drivers/gpu/drm/i915/intel_dsi.c
>> @@ -34,6 +34,7 @@
>>   #include "i915_drv.h"
>>   #include "intel_drv.h"
>>   #include "intel_dsi.h"
>> +#include "intel_dsi_cabc.h"
>>     static const struct {
>>       u16 panel_id;
>> @@ -376,6 +377,7 @@ static void intel_dsi_enable(struct intel_encoder 
>> *encoder)
>>       struct drm_device *dev = encoder->base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +    struct intel_connector *connector = intel_dsi->attached_connector;
>>       enum port port;
>>         DRM_DEBUG_KMS("\n");
>> @@ -396,6 +398,9 @@ static void intel_dsi_enable(struct intel_encoder 
>> *encoder)
>>             intel_dsi_port_enable(encoder);
>>       }
>> +
>> +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_enable_backlight(connector);
>>   }
>>     static void intel_dsi_pre_enable(struct intel_encoder *encoder)
>> @@ -469,11 +474,15 @@ static void intel_dsi_disable(struct 
>> intel_encoder *encoder)
>>       struct drm_device *dev = encoder->base.dev;
>>       struct drm_i915_private *dev_priv = dev->dev_private;
>>       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +    struct intel_connector *connector = intel_dsi->attached_connector;
>>       enum port port;
>>       u32 temp;
>>         DRM_DEBUG_KMS("\n");
>>   +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_disable_backlight(connector);
>> +
>>       if (is_vid_mode(intel_dsi)) {
>>           for_each_dsi_port(port, intel_dsi->ports)
>>               wait_for_dsi_fifo_empty(intel_dsi, port);
>> @@ -1099,6 +1108,10 @@ void intel_dsi_init(struct drm_device *dev)
>>         intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
>>   +    if (dev_priv->vbt.dsi.config->cabc_supported)
>> +        cabc_setup_backlight(connector,
>> +            intel_encoder->crtc_mask ==
>> +                (1 << PIPE_A) ? PIPE_A : PIPE_B);
>>       return;
>>     err:
>> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.c 
>> b/drivers/gpu/drm/i915/intel_dsi_cabc.c
>> new file mode 100644
>> index 0000000..2a78326
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.c
>> @@ -0,0 +1,349 @@
>> +/*
>> + * Copyright © 2006-2010 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including 
>> the next
>> + * paragraph) shall be included in all copies or substantial 
>> portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
>> OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/moduleparam.h>
>> +#include "intel_drv.h"
>> +#include "intel_dsi.h"
>> +#include "i915_drv.h"
>> +#include "intel_dsi_cabc.h"
>> +#include <video/mipi_display.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +
>> +int cabc_setup_backlight(struct intel_connector *connector,
>> +        enum pipe unused)
>> +{
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct intel_dsi *intel_dsi = NULL;
>> +    struct drm_crtc *crtc = NULL;
>> +    struct intel_encoder *encoder = NULL;
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct mipi_dsi_device *dsi_device;
>> +    u8 level;
>> +
>> +    list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +        for_each_encoder_on_crtc(dev, crtc, encoder) {
>> +            if (encoder->type == INTEL_OUTPUT_DSI)
>> +                intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +        }
>> +    }
>> +    dsi_device = intel_dsi->dsi_hosts[0]->device;
> This will work only for MIPI Port A not for MIPI Port C. Use 
> for_each_dsi_port macro and intel_dsi->dsi_hosts[port] to correctly 
> reach to mipi_dsi_device for both ports. If it is dual link, break 
> after the completion of the first iteration.
>> +    panel->backlight.max = CABC_MAX_VALUE;
>> +    panel->backlight.level = CABC_MAX_VALUE;
>> +    level = CABC_MAX_VALUE;
>> +    panel->backlight.enabled = true;
>> +    return 0;
>> +}
>> +
>> +u32 cabc_get_backlight(struct intel_connector *connector)
>> +{
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct intel_dsi *intel_dsi = NULL;
>> +    struct drm_crtc *crtc = NULL;
>> +    struct intel_encoder *encoder = NULL;
>> +    struct mipi_dsi_device *dsi_device;
>> +    struct intel_panel *panel = &connector->panel;
>> +    u8 data[2] = {0};
>> +    enum port port = PORT_A;
> will fail for single link MIPI Port C.
>> +    u32 ret;
>> +
>> +    list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +        for_each_encoder_on_crtc(dev, crtc, encoder) {
>> +            if (encoder->type == INTEL_OUTPUT_DSI)
>> +                intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +        }
>> +    }
>> +    if (intel_dsi->dual_link) {
> Put the below or required logic into static inline function returning 
> enum port .
>> +        if (intel_dsi->dl_cabc_port == CABC_PORT_A ||
>> +                intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
>> +            port = PORT_A;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
>> +            port = PORT_C;
>> +    }
> Use for_each_dsi_port macro here . call the  inline function within 
> for_each_dsi_port macro to get the required enum port for dual link.
>> +
>> +    dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +    mipi_dsi_dcs_read(dsi_device, MIPI_DCS_CABC_LEVEL_RD, data, 2);
>> +
>> +    ret = (data[1] * panel->backlight.max) / 255;
>> +    return ret;
>> +}
>> +
>> +void cabc_set_backlight(struct intel_connector *connector, u32 level)
>> +{
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct intel_dsi *intel_dsi = NULL;
>> +    struct drm_crtc *crtc = NULL;
>> +    struct intel_encoder *encoder = NULL;
>> +    struct mipi_dsi_device *dsi_device;
>> +    u8 data[2] = {0};
>> +    enum port port = PORT_A;
>> +    struct intel_panel *panel = &connector->panel;
>> +    u8 count = 1;
>> +    u32 hw_level;
>> +
>> +    list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +        for_each_encoder_on_crtc(dev, crtc, encoder) {
>> +            if (encoder->type == INTEL_OUTPUT_DSI)
>> +                intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +        }
>> +    }
>> +
>> +    if (intel_dsi->dual_link) {
> Put the below logic into static inline function returning enum port .
>> +        if (intel_dsi->dl_cabc_port == CABC_PORT_A)
>> +            port = PORT_A;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
>> +            port = PORT_C;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
>> +            port = PORT_A;
>> +    }
>> +
> Below part not required. use for_each_dsi_port macro.
>> +    if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
>> +            CABC_PORT_A_AND_C)
>> +        count = 2;
>> +
>> +
>> +    hw_level = level % (panel->backlight.max + 1);
>> +    hw_level = (hw_level * 255) / panel->backlight.max;
>> +    panel->backlight.level = hw_level;
>> +
> Use for_each_dsi_port macro as explained above.
>> +    do {
>> +        dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +        data[1] = hw_level;
>> +        data[0] = MIPI_DCS_CABC_LEVEL_WR;
>> +        mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
>> +        if (count == 2)
>> +            port = PORT_C;
>> +    } while (--count > 0);
>> +}
>> +
>> +void cabc_enable_backlight(struct intel_connector *connector)
>> +{
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct intel_dsi *intel_dsi = NULL;
>> +    struct drm_crtc *crtc = NULL;
>> +    struct intel_encoder *encoder = NULL;
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct mipi_dsi_device *dsi_device;
>> +    enum port port = PORT_A;
> Will fail for single link Port C
>> +    u8 data[2] = {0};
>> +    u8 count = 1;
>> +
>> +    list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +        for_each_encoder_on_crtc(dev, crtc, encoder) {
>> +            if (encoder->type == INTEL_OUTPUT_DSI)
>> +                intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +        }
>> +    }
>> +
>> +    if (intel_dsi->dual_link) {
> Same comment .Put the below logic into static inline function 
> returning enum port .
>> +        if (intel_dsi->dl_cabc_port == CABC_PORT_A)
>> +            port = PORT_A;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
>> +            port = PORT_C;
> Also below condition need not be taken into the inline function. Since 
> it is dual link and with other conditions are met, then 
> CABC_PORT_A_AND_C will be automatically taken care for both ports by 
> the for_each_dsi_port macro.
> Within for_each_dsi_port, just check for intel_dsi->dl_cabc_port != 
> CABC_PORT_A_AND_C, if yes call the inline function to get the port no 
> and if no, all other conditions will be taken care for both ports by 
> for_each_dsi_port.
> Before the end of for_each_dsi_port ,you may require to check the 
> intel_dsi->dl_cabc_port != CABC_PORT_A_AND_C , so that you can return 
> from the macro.
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
>> +            port = PORT_A;
>> +    }
>> +
>> +    if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
>> +            CABC_PORT_A_AND_C)
>> +        count = 2;
>> +
>> +    do {
> same comment as above. Use for_each_dsi_port
>> +        dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +
>> +
>> +        data[0] = MIPI_DCS_CABC_CONTROL_BRIGHT_WR;
>> +        data[1] = CABC_BACKLIGHT | CABC_DIMMING_DISPLAY | CABC_BCTRL;
>> +        mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
>> +        data[0] = MIPI_DCS_CABC_CONTROL_WR;
>> +        data[1] = CABC_VIDEO_MODE;
>> +        mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
>> +
>> +        if (count == 2)
>> +            port = PORT_C;
>> +    } while (--count > 0);
>> +
>> +    cabc_set_backlight(connector, panel->backlight.level);
>> +}
>> +
>> +void cabc_disable_backlight(struct intel_connector *connector)
>> +{
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct intel_dsi *intel_dsi = NULL;
>> +    struct drm_crtc *crtc = NULL;
>> +    struct intel_encoder *encoder = NULL;
>> +    struct mipi_dsi_device *dsi_device;
>> +    enum port port = PORT_A;
> Will fail for single link Port C
>> +    u8 data[2] = {0};
>> +    u8 count = 1;
>> +
>> +    list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +        for_each_encoder_on_crtc(dev, crtc, encoder) {
>> +            if (encoder->type == INTEL_OUTPUT_DSI)
>> +                intel_dsi = enc_to_intel_dsi(&encoder->base);
>> +        }
>> +    }
>> +
>> +    if (intel_dsi->dual_link) {
> Same comment as above. Use static inline function for this.
>> +        if (intel_dsi->dl_cabc_port == CABC_PORT_A)
>> +            port = PORT_A;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_C)
>> +            port = PORT_C;
>> +        else if (intel_dsi->dl_cabc_port == CABC_PORT_A_AND_C)
>> +            port = PORT_A;
>> +    }
>> +
>> +    if (intel_dsi->dual_link && intel_dsi->dl_cabc_port ==
>> +            CABC_PORT_A_AND_C)
>> +        count = 2;
>> +
>> +    do {
> Use for_each_dsi_port macro
>> +        dsi_device = intel_dsi->dsi_hosts[port]->device;
>> +
>> +        cabc_set_backlight(connector, 0);
>> +        data[1] = CABC_OFF;
>> +        data[0] = MIPI_DCS_CABC_CONTROL_WR;
>> +        mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
>> +        data[0] = MIPI_DCS_CABC_CONTROL_BRIGHT_WR;
>> +        mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
>> +
>> +        if (count == 2)
>> +            port = PORT_C;
>> +    } while (--count > 0);
>> +}
>> +
>> +static int cabc_backlight_device_update_status(struct 
>> backlight_device *bd)
>> +{
>> +    struct intel_connector *connector = bl_get_data(bd);
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct drm_device *dev = connector->base.dev;
>> +
>> +    drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>> +    DRM_DEBUG_KMS("updating intel_backlight, brightness=%d/%d\n",
>> +            bd->props.brightness, bd->props.max_brightness);
>> +    cabc_set_backlight(connector, bd->props.brightness);
>> +
>> +    /*
>> +     * Allow flipping bl_power as a sub-state of enabled. Sadly the
>> +     * backlight class device does not make it easy to to differentiate
>> +     * between callbacks for brightness and bl_power, so our 
>> backlight_power
>> +     * callback needs to take this into account.
>> +     */
>> +    if (panel->backlight.enabled) {
>> +        if (panel->backlight_power) {
>> +            bool enable = bd->props.power == FB_BLANK_UNBLANK &&
>> +                bd->props.brightness != 0;
>> +            panel->backlight_power(connector, enable);
>> +        }
>> +    } else {
>> +        bd->props.power = FB_BLANK_POWERDOWN;
>> +    }
>> +
>> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
>> +    return 0;
>> +}
>> +
>> +static int cabc_backlight_device_get_brightness(struct 
>> backlight_device *bd)
>> +{
>> +    struct intel_connector *connector = bl_get_data(bd);
>> +    struct drm_device *dev = connector->base.dev;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>> +    int ret;
>> +
>> +    intel_runtime_pm_get(dev_priv);
>> +    drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>> +
>> +    ret = cabc_get_backlight(connector);
>> +
>> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
>> +    intel_runtime_pm_put(dev_priv);
>> +
>> +    return ret;
>> +}
>> +
>> +static const struct backlight_ops cabc_backlight_device_ops = {
>> +    .update_status = cabc_backlight_device_update_status,
>> +    .get_brightness = cabc_backlight_device_get_brightness,
>> +};
>> +
>> +int cabc_backlight_device_register(struct intel_connector *connector)
>> +{
>> +    struct intel_panel *panel = &connector->panel;
>> +    struct backlight_properties props;
>> +
>> +    if (WARN_ON(panel->backlight.device))
>> +        return -ENODEV;
>> +
>> +    if (!panel->backlight.present)
>> +        return 0;
>> +
>> +    WARN_ON(panel->backlight.max == 0);
>> +
>> +    memset(&props, 0, sizeof(props));
>> +    props.type = BACKLIGHT_FIRMWARE;
>> +
>> +    /*
>> +     * Note: Everything should work even if the backlight device max
>> +     * presented to the userspace is arbitrarily chosen.
>> +     */
>> +    props.max_brightness = panel->backlight.max;
>> +    props.brightness = props.max_brightness;
>> +
>> +    if (panel->backlight.enabled)
>> +        props.power = FB_BLANK_UNBLANK;
>> +    else
>> +        props.power = FB_BLANK_POWERDOWN;
>> +
>> +    /*
>> +     * Note: using the same name independent of the connector prevents
>> +     * registration of multiple backlight devices in the driver.
>> +     */
>> +    panel->backlight.device =
>> +        backlight_device_register("intel_backlight",
>> +                connector->base.kdev,
>> +                connector,
>> +                &cabc_backlight_device_ops, &props);
>> +
>> +    if (IS_ERR(panel->backlight.device)) {
>> +        DRM_ERROR("Failed to register backlight: %ld\n",
>> +                PTR_ERR(panel->backlight.device));
>> +        panel->backlight.device = NULL;
>> +        return -ENODEV;
>> +    }
>> +
>> +    DRM_DEBUG_KMS("Connector %s backlight sysfs interface 
>> registered\n",
>> +            connector->base.name);
>> +
>> +    return 0;
>> +}
>> +
>> +void cabc_backlight_device_unregister(struct intel_connector 
>> *connector)
>> +{
>> +    struct intel_panel *panel = &connector->panel;
>> +
>> +    if (panel->backlight.device) {
>> + backlight_device_unregister(panel->backlight.device);
>> +        panel->backlight.device = NULL;
>> +    }
>> +}
>> diff --git a/drivers/gpu/drm/i915/intel_dsi_cabc.h 
>> b/drivers/gpu/drm/i915/intel_dsi_cabc.h
>> new file mode 100644
>> index 0000000..5d134f5
>> --- /dev/null
>> +++ b/drivers/gpu/drm/i915/intel_dsi_cabc.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * Copyright © 2013 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person 
>> obtaining a
>> + * copy of this software and associated documentation files (the 
>> "Software"),
>> + * to deal in the Software without restriction, including without 
>> limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, 
>> sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom 
>> the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including 
>> the next
>> + * paragraph) shall be included in all copies or substantial 
>> portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
>> EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
>> MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO 
>> EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES 
>> OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
>> ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
>> + * DEALINGS IN THE SOFTWARE.
>> + *
>> + */
>> +
>> +extern int cabc_backlight_device_register(struct intel_connector 
>> *connector);
>> +extern void cabc_backlight_device_unregister(struct intel_connector 
>> *connector);
>> +void cabc_set_backlight(struct intel_connector *connector, u32 level);
>> +u32 cabc_get_backlight(struct intel_connector *connector);
>> +void cabc_enable_backlight(struct intel_connector *connector);
>> +void cabc_disable_backlight(struct intel_connector *connector);
>> +int cabc_setup_backlight(struct intel_connector *connector, enum 
>> pipe unused);
>> +
>> +#define CABC_OFF                       (0 << 0)
>> +#define CABC_USER_INTERFACE_IMAGE      (1 << 0)
>> +#define CABC_STILL_PICTURE             (2 << 0)
>> +#define CABC_VIDEO_MODE                        (3 << 0)
>> +
>> +#define CABC_BACKLIGHT                 (1 << 2)
>> +#define CABC_DIMMING_DISPLAY           (1 << 3)
>> +#define CABC_BCTRL                     (1 << 5)
>> +
>> +#define CABC_PORT_A                    0x00
>> +#define CABC_PORT_C                    0x01
>> +#define CABC_PORT_A_AND_C              0x02
>> +#define CABC_MAX_VALUE               0xff
>> diff --git a/drivers/gpu/drm/i915/intel_panel.c 
>> b/drivers/gpu/drm/i915/intel_panel.c
>> index 55aad23..c73449b 100644
>> --- a/drivers/gpu/drm/i915/intel_panel.c
>> +++ b/drivers/gpu/drm/i915/intel_panel.c
>> @@ -1502,15 +1502,29 @@ void intel_panel_fini(struct intel_panel *panel)
>>   void intel_backlight_register(struct drm_device *dev)
>>   {
>>       struct intel_connector *connector;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>   -    list_for_each_entry(connector, 
>> &dev->mode_config.connector_list, base.head)
>> -        intel_backlight_device_register(connector);
>> +    list_for_each_entry(connector, &dev->mode_config.connector_list,
>> +                    base.head) {
>> +        if (connector->encoder->type == INTEL_OUTPUT_DSI &&
>> +            dev_priv->vbt.dsi.config->cabc_supported)
>> +            cabc_backlight_device_register(connector);
>> +        else
>> +            intel_backlight_device_register(connector);
>> +    }
>>   }
>>     void intel_backlight_unregister(struct drm_device *dev)
>>   {
>>       struct intel_connector *connector;
>> +    struct drm_i915_private *dev_priv = dev->dev_private;
>>   -    list_for_each_entry(connector, 
>> &dev->mode_config.connector_list, base.head)
>> -        intel_backlight_device_unregister(connector);
>> +    list_for_each_entry(connector, &dev->mode_config.connector_list,
>> +                    base.head) {
>> +        if (connector->encoder->type == INTEL_OUTPUT_DSI &&
>> +            dev_priv->vbt.dsi.config->cabc_supported)
>> +            cabc_backlight_device_unregister(connector);
>> +        else
>> +            intel_backlight_device_unregister(connector);
>> +    }
>>   }
>> diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
>> index ddcc8ca..5b8eeec 100644
>> --- a/include/video/mipi_display.h
>> +++ b/include/video/mipi_display.h
>> @@ -117,6 +117,14 @@ enum {
>>       MIPI_DCS_GET_SCANLINE        = 0x45,
>>       MIPI_DCS_READ_DDB_START        = 0xA1,
>>       MIPI_DCS_READ_DDB_CONTINUE    = 0xA8,
Please add them in increment order. Also, in HLD it is mentioned that 
offset for MIPI_DCS_CABC_LEVEL_RD is 0x51. Correct either of them 
accordingly.
>> +    MIPI_DCS_CABC_LEVEL_RD          = 0x52,
>> +    MIPI_DCS_CABC_MIN_BRIGHTNESS_RD = 0x5F,
>> +    MIPI_DCS_CABC_CONTROL_RD        = 0x56,
>> +    MIPI_DCS_CABC_CONTROL_BRIGHT_RD = 0x54,
>> +    MIPI_DCS_CABC_LEVEL_WR          = 0x51,
>> +    MIPI_DCS_CABC_MIN_BRIGHTNESS_WR = 0x5E,
>> +    MIPI_DCS_CABC_CONTROL_WR        = 0x55,
>> +    MIPI_DCS_CABC_CONTROL_BRIGHT_WR = 0x53,
>>   };
>>     /* MIPI DCS pixel formats */
>



More information about the Intel-gfx mailing list