brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 0494432 Raw
206 lines · c
1/*2 * Copyright © 2016 Intel Corporation3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice (including the next12 * paragraph) shall be included in all copies or substantial portions of the13 * Software.14 *15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21 * 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		0xFF45 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 intel_panel *panel = &connector->panel;51	struct mipi_dsi_device *dsi_device;52	u8 data[2] = {};53	enum port port;54	size_t len = panel->backlight.max > U8_MAX ? 2 : 1;55 56	for_each_dsi_port(port, panel->vbt.dsi.bl_ports) {57		dsi_device = intel_dsi->dsi_hosts[port]->device;58		mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,59				  &data, len);60		break;61	}62 63	return (data[1] << 8) | data[0];64}65 66static void dcs_set_backlight(const struct drm_connector_state *conn_state, u32 level)67{68	struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));69	struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;70	struct mipi_dsi_device *dsi_device;71	u8 data[2] = {};72	enum port port;73	size_t len = panel->backlight.max > U8_MAX ? 2 : 1;74	unsigned long mode_flags;75 76	if (len == 1) {77		data[0] = level;78	} else {79		data[0] = level >> 8;80		data[1] = level;81	}82 83	for_each_dsi_port(port, panel->vbt.dsi.bl_ports) {84		dsi_device = intel_dsi->dsi_hosts[port]->device;85		mode_flags = dsi_device->mode_flags;86		dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;87		mipi_dsi_dcs_write(dsi_device, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,88				   &data, len);89		dsi_device->mode_flags = mode_flags;90	}91}92 93static void dcs_disable_backlight(const struct drm_connector_state *conn_state, u32 level)94{95	struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));96	struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;97	struct mipi_dsi_device *dsi_device;98	enum port port;99 100	dcs_set_backlight(conn_state, 0);101 102	for_each_dsi_port(port, panel->vbt.dsi.cabc_ports) {103		u8 cabc = POWER_SAVE_OFF;104 105		dsi_device = intel_dsi->dsi_hosts[port]->device;106		mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,107				   &cabc, sizeof(cabc));108	}109 110	for_each_dsi_port(port, panel->vbt.dsi.bl_ports) {111		u8 ctrl = 0;112 113		dsi_device = intel_dsi->dsi_hosts[port]->device;114 115		mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,116				  &ctrl, sizeof(ctrl));117 118		ctrl &= ~CONTROL_DISPLAY_BL;119		ctrl &= ~CONTROL_DISPLAY_DD;120		ctrl &= ~CONTROL_DISPLAY_BCTRL;121 122		mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,123				   &ctrl, sizeof(ctrl));124	}125}126 127static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state,128				 const struct drm_connector_state *conn_state, u32 level)129{130	struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(conn_state->best_encoder));131	struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;132	struct mipi_dsi_device *dsi_device;133	enum port port;134 135	for_each_dsi_port(port, panel->vbt.dsi.bl_ports) {136		u8 ctrl = 0;137 138		dsi_device = intel_dsi->dsi_hosts[port]->device;139 140		mipi_dsi_dcs_read(dsi_device, MIPI_DCS_GET_CONTROL_DISPLAY,141				  &ctrl, sizeof(ctrl));142 143		ctrl |= CONTROL_DISPLAY_BL;144		ctrl |= CONTROL_DISPLAY_DD;145		ctrl |= CONTROL_DISPLAY_BCTRL;146 147		mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_CONTROL_DISPLAY,148				   &ctrl, sizeof(ctrl));149	}150 151	for_each_dsi_port(port, panel->vbt.dsi.cabc_ports) {152		u8 cabc = POWER_SAVE_MEDIUM;153 154		dsi_device = intel_dsi->dsi_hosts[port]->device;155		mipi_dsi_dcs_write(dsi_device, MIPI_DCS_WRITE_POWER_SAVE,156				   &cabc, sizeof(cabc));157	}158 159	dcs_set_backlight(conn_state, level);160}161 162static int dcs_setup_backlight(struct intel_connector *connector,163			       enum pipe unused)164{165	struct drm_i915_private *i915 = to_i915(connector->base.dev);166	struct intel_panel *panel = &connector->panel;167 168	if (panel->vbt.backlight.brightness_precision_bits > 8)169		panel->backlight.max = (1 << panel->vbt.backlight.brightness_precision_bits) - 1;170	else171		panel->backlight.max = PANEL_PWM_MAX_VALUE;172 173	panel->backlight.level = panel->backlight.max;174 175	drm_dbg_kms(&i915->drm,176		    "[CONNECTOR:%d:%s] Using DCS for backlight control\n",177		    connector->base.base.id, connector->base.name);178 179	return 0;180}181 182static const struct intel_panel_bl_funcs dcs_bl_funcs = {183	.setup = dcs_setup_backlight,184	.enable = dcs_enable_backlight,185	.disable = dcs_disable_backlight,186	.set = dcs_set_backlight,187	.get = dcs_get_backlight,188};189 190int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector)191{192	struct drm_device *dev = intel_connector->base.dev;193	struct intel_encoder *encoder = intel_attached_encoder(intel_connector);194	struct intel_panel *panel = &intel_connector->panel;195 196	if (panel->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS)197		return -ENODEV;198 199	if (drm_WARN_ON(dev, encoder->type != INTEL_OUTPUT_DSI))200		return -EINVAL;201 202	panel->backlight.funcs = &dcs_bl_funcs;203 204	return 0;205}206