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 "intel_drv.h" 27 #include "intel_dsi.h" 28 #include "i915_drv.h" 29 #include <video/mipi_display.h> 30 #include <drm/drm_mipi_dsi.h> 31 32 #define CONTROL_DISPLAY_BCTRL (1 << 5) 33 #define CONTROL_DISPLAY_DD (1 << 3) 34 #define CONTROL_DISPLAY_BL (1 << 2) 35 36 #define POWER_SAVE_OFF (0 << 0) 37 #define POWER_SAVE_LOW (1 << 0) 38 #define POWER_SAVE_MEDIUM (2 << 0) 39 #define POWER_SAVE_HIGH (3 << 0) 40 #define POWER_SAVE_OUTDOOR_MODE (4 << 0) 41 42 #define PANEL_PWM_MAX_VALUE 0xFF 43 44 static u32 dcs_get_backlight(struct intel_connector *connector) 45 { 46 struct intel_encoder *encoder = connector->encoder; 47 struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); 48 struct mipi_dsi_device *dsi_device; 49 u8 data = 0; 50 enum port port; 51 52 /* FIXME: Need to take care of 16 bit brightness level */ 53 for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) { 54 dsi_device = intel_dsi->dsi_hosts[port]->device; 55 mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, 56 &data, sizeof(data)); 57 break; 58 } 59 60 return data; 61 } 62 63 static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level) 64 { 65 struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder); 66 struct mipi_dsi_device *dsi_device; 67 u8 data = level; 68 enum port port; 69 70 /* FIXME: Need to take care of 16 bit brightness level */ 71 for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) { 72 dsi_device = intel_dsi->dsi_hosts[port]->device; 73 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 74 &data, sizeof(data)); 75 } 76 } 77 78 static void dcs_disable_backlight(const struct drm_connector_state *conn_state) 79 { 80 struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder); 81 struct mipi_dsi_device *dsi_device; 82 enum port port; 83 84 dcs_set_backlight(conn_state, 0); 85 86 for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) { 87 u8 cabc = POWER_SAVE_OFF; 88 89 dsi_device = intel_dsi->dsi_hosts[port]->device; 90 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE, 91 &cabc, sizeof(cabc)); 92 } 93 94 for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) { 95 u8 ctrl = 0; 96 97 dsi_device = intel_dsi->dsi_hosts[port]->device; 98 99 mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY, 100 &ctrl, sizeof(ctrl)); 101 102 ctrl &= ~CONTROL_DISPLAY_BL; 103 ctrl &= ~CONTROL_DISPLAY_DD; 104 ctrl &= ~CONTROL_DISPLAY_BCTRL; 105 106 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY, 107 &ctrl, sizeof(ctrl)); 108 } 109 } 110 111 static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state, 112 const struct drm_connector_state *conn_state) 113 { 114 struct intel_dsi *intel_dsi = enc_to_intel_dsi(conn_state->best_encoder); 115 struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; 116 struct mipi_dsi_device *dsi_device; 117 enum port port; 118 119 for_each_dsi_port(port, intel_dsi->dcs_backlight_ports) { 120 u8 ctrl = 0; 121 122 dsi_device = intel_dsi->dsi_hosts[port]->device; 123 124 mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY, 125 &ctrl, sizeof(ctrl)); 126 127 ctrl |= CONTROL_DISPLAY_BL; 128 ctrl |= CONTROL_DISPLAY_DD; 129 ctrl |= CONTROL_DISPLAY_BCTRL; 130 131 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY, 132 &ctrl, sizeof(ctrl)); 133 } 134 135 for_each_dsi_port(port, intel_dsi->dcs_cabc_ports) { 136 u8 cabc = POWER_SAVE_MEDIUM; 137 138 dsi_device = intel_dsi->dsi_hosts[port]->device; 139 mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE, 140 &cabc, sizeof(cabc)); 141 } 142 143 dcs_set_backlight(conn_state, panel->backlight.level); 144 } 145 146 static int dcs_setup_backlight(struct intel_connector *connector, 147 enum i915_pipe unused) 148 { 149 struct intel_panel *panel = &connector->panel; 150 151 panel->backlight.max = PANEL_PWM_MAX_VALUE; 152 panel->backlight.level = PANEL_PWM_MAX_VALUE; 153 154 return 0; 155 } 156 157 int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector) 158 { 159 struct drm_device *dev = intel_connector->base.dev; 160 struct drm_i915_private *dev_priv = to_i915(dev); 161 struct intel_encoder *encoder = intel_connector->encoder; 162 struct intel_panel *panel = &intel_connector->panel; 163 164 if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS) 165 return -ENODEV; 166 167 if (WARN_ON(encoder->type != INTEL_OUTPUT_DSI)) 168 return -EINVAL; 169 170 panel->backlight.setup = dcs_setup_backlight; 171 panel->backlight.enable = dcs_enable_backlight; 172 panel->backlight.disable = dcs_disable_backlight; 173 panel->backlight.set = dcs_set_backlight; 174 panel->backlight.get = dcs_get_backlight; 175 176 return 0; 177 } 178