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 46 static u32 dcs_get_backlight(struct intel_connector *connector) 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 65 static 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 80 static void dcs_disable_backlight(const struct drm_connector_state *conn_state) 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 113 static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state, 114 const struct drm_connector_state *conn_state) 115 { 116 struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder)); 117 struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; 118 struct mipi_dsi_device *dsi_device; 119 enum port port; 120 121 for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) { 122 u8 ctrl = 0; 123 124 dsi_device = intel_dsi->dsi_hosts[port]->device; 125 126 mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY, 127 &ctrl, sizeof(ctrl)); 128 129 ctrl |= CONTROL_DISPLAY_BL; 130 ctrl |= CONTROL_DISPLAY_DD; 131 ctrl |= CONTROL_DISPLAY_BCTRL; 132 133 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY, 134 &ctrl, sizeof(ctrl)); 135 } 136 137 for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) { 138 u8 cabc = POWER_SAVE_MEDIUM; 139 140 dsi_device = intel_dsi->dsi_hosts[port]->device; 141 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE, 142 &cabc, sizeof(cabc)); 143 } 144 145 dcs_set_backlight(conn_state, panel->backlight.level); 146 } 147 148 static int dcs_setup_backlight(struct intel_connector *connector, 149 enum pipe unused) 150 { 151 struct intel_panel *panel = &connector->panel; 152 153 panel->backlight.max = PANEL_PWM_MAX_VALUE; 154 panel->backlight.level = PANEL_PWM_MAX_VALUE; 155 156 return 0; 157 } 158 159 int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector) 160 { 161 struct drm_device *dev = intel_connector->base.dev; 162 struct drm_i915_private *dev_priv = to_i915(dev); 163 struct intel_encoder *encoder = intel_attached_encoder(intel_connector); 164 struct intel_panel *panel = &intel_connector->panel; 165 166 if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS) 167 return -ENODEV; 168 169 if (drm_WARN_ON(dev, encoder->type != INTEL_OUTPUT_DSI)) 170 return -EINVAL; 171 172 panel->backlight.setup = dcs_setup_backlight; 173 panel->backlight.enable = dcs_enable_backlight; 174 panel->backlight.disable = dcs_disable_backlight; 175 panel->backlight.set = dcs_set_backlight; 176 panel->backlight.get = dcs_get_backlight; 177 178 return 0; 179 } 180