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