Home | History | Annotate | Line # | Download | only in display
      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 
     51 static 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 
     70 static 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 
     85 static 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 
    118 static 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 
    153 static 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 
    164 int 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