linux/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2016 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21 * DEALINGS IN THE SOFTWARE.
  22 *
  23 * Author: Deepak M <m.deepak at intel.com>
  24 */
  25
  26#include <drm/drm_mipi_dsi.h>
  27#include <video/mipi_display.h>
  28
  29#include "i915_drv.h"
  30#include "intel_display_types.h"
  31#include "intel_dsi.h"
  32#include "intel_dsi_dcs_backlight.h"
  33
  34#define CONTROL_DISPLAY_BCTRL           (1 << 5)
  35#define CONTROL_DISPLAY_DD              (1 << 3)
  36#define CONTROL_DISPLAY_BL              (1 << 2)
  37
  38#define POWER_SAVE_OFF                  (0 << 0)
  39#define POWER_SAVE_LOW                  (1 << 0)
  40#define POWER_SAVE_MEDIUM               (2 << 0)
  41#define POWER_SAVE_HIGH                 (3 << 0)
  42#define POWER_SAVE_OUTDOOR_MODE         (4 << 0)
  43
  44#define PANEL_PWM_MAX_VALUE             0xFF
  45
  46static u32 dcs_get_backlight(struct intel_connector *connector, enum pipe unused)
  47{
  48        struct intel_encoder *encoder = intel_attached_encoder(connector);
  49        struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
  50        struct mipi_dsi_device *dsi_device;
  51        u8 data = 0;
  52        enum port port;
  53
  54        /* FIXME: Need to take care of 16 bit brightness level */
  55        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
  56                dsi_device = intel_dsi->dsi_hosts[port]->device;
  57                mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
  58                                  &data, sizeof(data));
  59                break;
  60        }
  61
  62        return data;
  63}
  64
  65static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)
  66{
  67        struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));
  68        struct mipi_dsi_device *dsi_device;
  69        u8 data = level;
  70        enum port port;
  71
  72        /* FIXME: Need to take care of 16 bit brightness level */
  73        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
  74                dsi_device = intel_dsi->dsi_hosts[port]->device;
  75                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
  76                                   &data, sizeof(data));
  77        }
  78}
  79
  80static void dcs_disable_backlight(const struct drm_connector_state *conn_state, u32 level)
  81{
  82        struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));
  83        struct mipi_dsi_device *dsi_device;
  84        enum port port;
  85
  86        dcs_set_backlight(conn_state, 0);
  87
  88        for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
  89                u8 cabc = POWER_SAVE_OFF;
  90
  91                dsi_device = intel_dsi->dsi_hosts[port]->device;
  92                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
  93                                   &cabc, sizeof(cabc));
  94        }
  95
  96        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
  97                u8 ctrl = 0;
  98
  99                dsi_device = intel_dsi->dsi_hosts[port]->device;
 100
 101                mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
 102                                  &ctrl, sizeof(ctrl));
 103
 104                ctrl &= ~CONTROL_DISPLAY_BL;
 105                ctrl &= ~CONTROL_DISPLAY_DD;
 106                ctrl &= ~CONTROL_DISPLAY_BCTRL;
 107
 108                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
 109                                   &ctrl, sizeof(ctrl));
 110        }
 111}
 112
 113static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,
 114                                 const struct drm_connector_state *conn_state, u32 level)
 115{
 116        struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));
 117        struct mipi_dsi_device *dsi_device;
 118        enum port port;
 119
 120        for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) {
 121                u8 ctrl = 0;
 122
 123                dsi_device = intel_dsi->dsi_hosts[port]->device;
 124
 125                mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,
 126                                  &ctrl, sizeof(ctrl));
 127
 128                ctrl |= CONTROL_DISPLAY_BL;
 129                ctrl |= CONTROL_DISPLAY_DD;
 130                ctrl |= CONTROL_DISPLAY_BCTRL;
 131
 132                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,
 133                                   &ctrl, sizeof(ctrl));
 134        }
 135
 136        for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) {
 137                u8 cabc = POWER_SAVE_MEDIUM;
 138
 139                dsi_device = intel_dsi->dsi_hosts[port]->device;
 140                mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,
 141                                   &cabc, sizeof(cabc));
 142        }
 143
 144        dcs_set_backlight(conn_state, level);
 145}
 146
 147static int dcs_setup_backlight(struct intel_connector *connector,
 148                               enum pipe unused)
 149{
 150        struct intel_panel *panel = &connector->panel;
 151
 152        panel->backlight.max = PANEL_PWM_MAX_VALUE;
 153        panel->backlight.level = PANEL_PWM_MAX_VALUE;
 154
 155        return 0;
 156}
 157
 158static const struct intel_panel_bl_funcs dcs_bl_funcs = {
 159        .setup = dcs_setup_backlight,
 160        .enable = dcs_enable_backlight,
 161        .disable = dcs_disable_backlight,
 162        .set = dcs_set_backlight,
 163        .get = dcs_get_backlight,
 164};
 165
 166int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector)
 167{
 168        struct drm_device *dev = intel_connector->base.dev;
 169        struct drm_i915_private *dev_priv = to_i915(dev);
 170        struct intel_encoder *encoder = intel_attached_encoder(intel_connector);
 171        struct intel_panel *panel = &intel_connector->panel;
 172
 173        if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS)
 174                return -ENODEV;
 175
 176        if (drm_WARN_ON(dev, encoder->type != INTEL_OUTPUT_DSI))
 177                return -EINVAL;
 178
 179        panel->backlight.funcs = &dcs_bl_funcs;
 180
 181        return 0;
 182}
 183