diff options
Diffstat (limited to 'drivers/gpu')
45 files changed, 2982 insertions, 767 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index b9e0ca85226a..9cefbd15177a 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -316,6 +316,19 @@ config DRM_SIMPLE_BRIDGE Support for non-programmable DRM bridges, such as ADI ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs. +config DRM_SOLOMON_SSD2825 + tristate "SSD2825 RGB/DSI bridge" + depends on SPI_MASTER && OF + select DRM_MIPI_DSI + select DRM_KMS_HELPER + select DRM_PANEL + help + Say Y here if you want support for the Solomon SSD2825 RGB/DSI + SPI bridge driver. + + Say M here if you want to support this hardware as a module. + The module will be named "ssd2825". + config DRM_THINE_THC63LVD1024 tristate "Thine THC63LVD1024 LVDS decoder bridge" depends on OF @@ -438,6 +451,18 @@ config DRM_TI_TPD12S015 Texas Instruments TPD12S015 HDMI level shifter and ESD protection driver. +config DRM_WAVESHARE_BRIDGE + tristate "Waveshare DSI bridge" + depends on OF + depends on BACKLIGHT_CLASS_DEVICE + select DRM_PANEL_BRIDGE + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select REGMAP_I2C + help + Driver for waveshare DSI to DPI bridge board. + Please say Y if you have such hardware + source "drivers/gpu/drm/bridge/analogix/Kconfig" source "drivers/gpu/drm/bridge/adv7511/Kconfig" diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 245e8a27e3fc..c7dc03182e59 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_DRM_SIL_SII8620) += sil-sii8620.o obj-$(CONFIG_DRM_SII902X) += sii902x.o obj-$(CONFIG_DRM_SII9234) += sii9234.o obj-$(CONFIG_DRM_SIMPLE_BRIDGE) += simple-bridge.o +obj-$(CONFIG_DRM_SOLOMON_SSD2825) += ssd2825.o obj-$(CONFIG_DRM_THINE_THC63LVD1024) += thc63lvd1024.o obj-$(CONFIG_DRM_TOSHIBA_TC358762) += tc358762.o obj-$(CONFIG_DRM_TOSHIBA_TC358764) += tc358764.o @@ -40,6 +41,7 @@ obj-$(CONFIG_DRM_TI_SN65DSI86) += ti-sn65dsi86.o obj-$(CONFIG_DRM_TI_TDP158) += ti-tdp158.o obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o +obj-$(CONFIG_DRM_WAVESHARE_BRIDGE) += waveshare-dsi.o obj-$(CONFIG_DRM_NWL_MIPI_DSI) += nwl-dsi.o obj-$(CONFIG_DRM_ITE_IT66121) += ite-it66121.o diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c index 52b7b5889e6f..d7e1c2f8f53c 100644 --- a/drivers/gpu/drm/bridge/display-connector.c +++ b/drivers/gpu/drm/bridge/display-connector.c @@ -108,7 +108,7 @@ static u32 *display_connector_get_output_bus_fmts(struct drm_bridge *bridge, struct drm_connector_state *conn_state, unsigned int *num_output_fmts) { - struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge *prev_bridge __free(drm_bridge_put) = drm_bridge_get_prev_bridge(bridge); struct drm_bridge_state *prev_bridge_state; if (!prev_bridge || !prev_bridge->funcs->atomic_get_output_bus_fmts) { @@ -151,7 +151,7 @@ static u32 *display_connector_get_input_bus_fmts(struct drm_bridge *bridge, u32 output_fmt, unsigned int *num_input_fmts) { - struct drm_bridge *prev_bridge = drm_bridge_get_prev_bridge(bridge); + struct drm_bridge *prev_bridge __free(drm_bridge_put) = drm_bridge_get_prev_bridge(bridge); struct drm_bridge_state *prev_bridge_state; if (!prev_bridge || !prev_bridge->funcs->atomic_get_input_bus_fmts) { diff --git a/drivers/gpu/drm/bridge/ssd2825.c b/drivers/gpu/drm/bridge/ssd2825.c new file mode 100644 index 000000000000..f2fdbf7c117d --- /dev/null +++ b/drivers/gpu/drm/bridge/ssd2825.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> +#include <linux/units.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> +#include <drm/drm_drv.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> +#include <drm/drm_panel.h> +#include <video/mipi_display.h> + +#define SSD2825_DEVICE_ID_REG 0xb0 +#define SSD2825_RGB_INTERFACE_CTRL_REG_1 0xb1 +#define SSD2825_RGB_INTERFACE_CTRL_REG_2 0xb2 +#define SSD2825_RGB_INTERFACE_CTRL_REG_3 0xb3 +#define SSD2825_RGB_INTERFACE_CTRL_REG_4 0xb4 +#define SSD2825_RGB_INTERFACE_CTRL_REG_5 0xb5 +#define SSD2825_RGB_INTERFACE_CTRL_REG_6 0xb6 +#define SSD2825_NON_BURST_EV BIT(2) +#define SSD2825_BURST BIT(3) +#define SSD2825_PCKL_HIGH BIT(13) +#define SSD2825_HSYNC_HIGH BIT(14) +#define SSD2825_VSYNC_HIGH BIT(15) +#define SSD2825_CONFIGURATION_REG 0xb7 +#define SSD2825_CONF_REG_HS BIT(0) +#define SSD2825_CONF_REG_CKE BIT(1) +#define SSD2825_CONF_REG_SLP BIT(2) +#define SSD2825_CONF_REG_VEN BIT(3) +#define SSD2825_CONF_REG_HCLK BIT(4) +#define SSD2825_CONF_REG_CSS BIT(5) +#define SSD2825_CONF_REG_DCS BIT(6) +#define SSD2825_CONF_REG_REN BIT(7) +#define SSD2825_CONF_REG_ECD BIT(8) +#define SSD2825_CONF_REG_EOT BIT(9) +#define SSD2825_CONF_REG_LPE BIT(10) +#define SSD2825_VC_CTRL_REG 0xb8 +#define SSD2825_PLL_CTRL_REG 0xb9 +#define SSD2825_PLL_CONFIGURATION_REG 0xba +#define SSD2825_CLOCK_CTRL_REG 0xbb +#define SSD2825_PACKET_SIZE_CTRL_REG_1 0xbc +#define SSD2825_PACKET_SIZE_CTRL_REG_2 0xbd +#define SSD2825_PACKET_SIZE_CTRL_REG_3 0xbe +#define SSD2825_PACKET_DROP_REG 0xbf +#define SSD2825_OPERATION_CTRL_REG 0xc0 +#define SSD2825_MAX_RETURN_SIZE_REG 0xc1 +#define SSD2825_RETURN_DATA_COUNT_REG 0xc2 +#define SSD2825_ACK_RESPONSE_REG 0xc3 +#define SSD2825_LINE_CTRL_REG 0xc4 +#define SSD2825_INTERRUPT_CTRL_REG 0xc5 +#define SSD2825_INTERRUPT_STATUS_REG 0xc6 +#define SSD2825_ERROR_STATUS_REG 0xc7 +#define SSD2825_DATA_FORMAT_REG 0xc8 +#define SSD2825_DELAY_ADJ_REG_1 0xc9 +#define SSD2825_DELAY_ADJ_REG_2 0xca +#define SSD2825_DELAY_ADJ_REG_3 0xcb +#define SSD2825_DELAY_ADJ_REG_4 0xcc +#define SSD2825_DELAY_ADJ_REG_5 0xcd +#define SSD2825_DELAY_ADJ_REG_6 0xce +#define SSD2825_HS_TX_TIMER_REG_1 0xcf +#define SSD2825_HS_TX_TIMER_REG_2 0xd0 +#define SSD2825_LP_RX_TIMER_REG_1 0xd1 +#define SSD2825_LP_RX_TIMER_REG_2 0xd2 +#define SSD2825_TE_STATUS_REG 0xd3 +#define SSD2825_SPI_READ_REG 0xd4 +#define SSD2825_SPI_READ_REG_RESET 0xfa +#define SSD2825_PLL_LOCK_REG 0xd5 +#define SSD2825_TEST_REG 0xd6 +#define SSD2825_TE_COUNT_REG 0xd7 +#define SSD2825_ANALOG_CTRL_REG_1 0xd8 +#define SSD2825_ANALOG_CTRL_REG_2 0xd9 +#define SSD2825_ANALOG_CTRL_REG_3 0xda +#define SSD2825_ANALOG_CTRL_REG_4 0xdb +#define SSD2825_INTERRUPT_OUT_CTRL_REG 0xdc +#define SSD2825_RGB_INTERFACE_CTRL_REG_7 0xdd +#define SSD2825_LANE_CONFIGURATION_REG 0xde +#define SSD2825_DELAY_ADJ_REG_7 0xdf +#define SSD2825_INPUT_PIN_CTRL_REG_1 0xe0 +#define SSD2825_INPUT_PIN_CTRL_REG_2 0xe1 +#define SSD2825_BIDIR_PIN_CTRL_REG_1 0xe2 +#define SSD2825_BIDIR_PIN_CTRL_REG_2 0xe3 +#define SSD2825_BIDIR_PIN_CTRL_REG_3 0xe4 +#define SSD2825_BIDIR_PIN_CTRL_REG_4 0xe5 +#define SSD2825_BIDIR_PIN_CTRL_REG_5 0xe6 +#define SSD2825_BIDIR_PIN_CTRL_REG_6 0xe7 +#define SSD2825_BIDIR_PIN_CTRL_REG_7 0xe8 +#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_1 0xe9 +#define SSD2825_CABC_BRIGHTNESS_CTRL_REG_2 0xea +#define SSD2825_CABC_BRIGHTNESS_STATUS_REG 0xeb +#define SSD2825_READ_REG 0xff + +#define SSD2825_COM_BYTE 0x00 +#define SSD2825_DAT_BYTE 0x01 + +#define SSD2828_LP_CLOCK_DIVIDER(n) (((n) - 1) & 0x3f) +#define SSD2825_LP_MIN_CLK 5000 /* KHz */ +#define SSD2825_REF_MIN_CLK 2000 /* KHz */ + +static const struct regulator_bulk_data ssd2825_supplies[] = { + { .supply = "dvdd" }, + { .supply = "avdd" }, + { .supply = "vddio" }, +}; + +struct ssd2825_dsi_output { + struct mipi_dsi_device *dev; + struct drm_panel *panel; + struct drm_bridge *bridge; +}; + +struct ssd2825_priv { + struct spi_device *spi; + struct device *dev; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; + + struct clk *tx_clk; + + struct mipi_dsi_host dsi_host; + struct drm_bridge bridge; + struct ssd2825_dsi_output output; + + struct mutex mlock; /* for host transfer operations */ + + u32 pd_lines; /* number of Parallel Port Input Data Lines */ + u32 dsi_lanes; /* number of DSI Lanes */ + + /* Parameters for PLL programming */ + u32 pll_freq_kbps; /* PLL in kbps */ + u32 nibble_freq_khz; /* PLL div by 4 */ + + u32 hzd; /* HS Zero Delay in ns*/ + u32 hpd; /* HS Prepare Delay is ns */ +}; + +static inline struct ssd2825_priv *dsi_host_to_ssd2825(struct mipi_dsi_host *host) +{ + return container_of(host, struct ssd2825_priv, dsi_host); +} + +static inline struct ssd2825_priv *bridge_to_ssd2825(struct drm_bridge *bridge) +{ + return container_of(bridge, struct ssd2825_priv, bridge); +} + +static int ssd2825_write_raw(struct ssd2825_priv *priv, u8 high_byte, u8 low_byte) +{ + struct spi_device *spi = priv->spi; + u8 tx_buf[2]; + + /* + * Low byte is the value, high byte defines type of + * write cycle, 0 for command and 1 for data. + */ + tx_buf[0] = low_byte; + tx_buf[1] = high_byte; + + return spi_write(spi, tx_buf, 2); +} + +static int ssd2825_write_reg(struct ssd2825_priv *priv, u8 reg, u16 command) +{ + u8 datal = (command & 0x00FF); + u8 datah = (command & 0xFF00) >> 8; + int ret; + + /* Command write cycle */ + ret = ssd2825_write_raw(priv, SSD2825_COM_BYTE, reg); + if (ret) + return ret; + + /* Data write cycle bits 7-0 */ + ret = ssd2825_write_raw(priv, SSD2825_DAT_BYTE, datal); + if (ret) + return ret; + + /* Data write cycle bits 15-8 */ + ret = ssd2825_write_raw(priv, SSD2825_DAT_BYTE, datah); + if (ret) + return ret; + + return 0; +} + +static int ssd2825_write_dsi(struct ssd2825_priv *priv, const u8 *command, int len) +{ + int ret, i; + + ret = ssd2825_write_reg(priv, SSD2825_PACKET_SIZE_CTRL_REG_1, len); + if (ret) + return ret; + + ret = ssd2825_write_raw(priv, SSD2825_COM_BYTE, SSD2825_PACKET_DROP_REG); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + ret = ssd2825_write_raw(priv, SSD2825_DAT_BYTE, command[i]); + if (ret) + return ret; + } + + return 0; +} + +static int ssd2825_read_raw(struct ssd2825_priv *priv, u8 cmd, u16 *data) +{ + struct spi_device *spi = priv->spi; + struct spi_message msg; + struct spi_transfer xfer[2]; + u8 tx_buf[2]; + u8 rx_buf[2]; + int ret; + + memset(&xfer, 0, sizeof(xfer)); + + tx_buf[1] = (cmd & 0xFF00) >> 8; + tx_buf[0] = (cmd & 0x00FF); + + xfer[0].tx_buf = tx_buf; + xfer[0].bits_per_word = 9; + xfer[0].len = 2; + + xfer[1].rx_buf = rx_buf; + xfer[1].bits_per_word = 16; + xfer[1].len = 2; + + spi_message_init(&msg); + spi_message_add_tail(&xfer[0], &msg); + spi_message_add_tail(&xfer[1], &msg); + + ret = spi_sync(spi, &msg); + if (ret) { + dev_err(&spi->dev, "ssd2825 read raw failed %d\n", ret); + return ret; + } + + *data = rx_buf[1] | (rx_buf[0] << 8); + + return 0; +} + +static int ssd2825_read_reg(struct ssd2825_priv *priv, u8 reg, u16 *data) +{ + int ret; + + /* Reset the read register */ + ret = ssd2825_write_reg(priv, SSD2825_SPI_READ_REG, SSD2825_SPI_READ_REG_RESET); + if (ret) + return ret; + + /* Push the address to read */ + ret = ssd2825_write_raw(priv, SSD2825_COM_BYTE, reg); + if (ret) + return ret; + + /* Perform a reading cycle */ + ret = ssd2825_read_raw(priv, SSD2825_SPI_READ_REG_RESET, data); + if (ret) + return ret; + + return 0; +} + +static int ssd2825_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dev) +{ + struct ssd2825_priv *priv = dsi_host_to_ssd2825(host); + struct drm_bridge *bridge; + struct drm_panel *panel; + struct device_node *ep; + int ret; + + if (dev->lanes > 4) { + dev_err(priv->dev, "unsupported number of data lanes(%u)\n", dev->lanes); + return -EINVAL; + } + + /* + * ssd2825 supports both Video and Pulse mode, but the driver only + * implements Video (event) mode currently + */ + if (!(dev->mode_flags & MIPI_DSI_MODE_VIDEO)) { + dev_err(priv->dev, "Only MIPI_DSI_MODE_VIDEO is supported\n"); + return -EOPNOTSUPP; + } + + ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, &bridge); + if (ret) + return ret; + + if (panel) { + bridge = drm_panel_bridge_add_typed(panel, DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + } + + priv->output.dev = dev; + priv->output.bridge = bridge; + priv->output.panel = panel; + + priv->dsi_lanes = dev->lanes; + + /* get input ep (port0/endpoint0) */ + ret = -EINVAL; + ep = of_graph_get_endpoint_by_regs(host->dev->of_node, 0, 0); + if (ep) { + ret = of_property_read_u32(ep, "bus-width", &priv->pd_lines); + of_node_put(ep); + } + + if (ret) + priv->pd_lines = mipi_dsi_pixel_format_to_bpp(dev->format); + + drm_bridge_add(&priv->bridge); + + return 0; +} + +static int ssd2825_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *dev) +{ + struct ssd2825_priv *priv = dsi_host_to_ssd2825(host); + + drm_bridge_remove(&priv->bridge); + if (priv->output.panel) + drm_panel_bridge_remove(priv->output.bridge); + + return 0; +} + +static ssize_t ssd2825_dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct ssd2825_priv *priv = dsi_host_to_ssd2825(host); + u16 config; + int ret; + + if (msg->rx_len) { + dev_warn(priv->dev, "MIPI rx is not supported\n"); + return -EOPNOTSUPP; + } + + guard(mutex)(&priv->mlock); + + ret = ssd2825_read_reg(priv, SSD2825_CONFIGURATION_REG, &config); + if (ret) + return ret; + + switch (msg->type) { + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_LONG_WRITE: + config |= SSD2825_CONF_REG_DCS; + break; + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_LONG_WRITE: + config &= ~SSD2825_CONF_REG_DCS; + break; + case MIPI_DSI_DCS_READ: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + default: + return 0; + } + + ret = ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config); + if (ret) + return ret; + + ret = ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0x0000); + if (ret) + return ret; + + ret = ssd2825_write_dsi(priv, msg->tx_buf, msg->tx_len); + if (ret) + return ret; + + return 0; +} + +static const struct mipi_dsi_host_ops ssd2825_dsi_host_ops = { + .attach = ssd2825_dsi_host_attach, + .detach = ssd2825_dsi_host_detach, + .transfer = ssd2825_dsi_host_transfer, +}; + +static void ssd2825_hw_reset(struct ssd2825_priv *priv) +{ + gpiod_set_value_cansleep(priv->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(priv->reset_gpio, 0); + usleep_range(5000, 6000); +} + +/* + * PLL configuration register settings. + * + * See the "PLL Configuration Register Description" in the SSD2825 datasheet. + */ +static u16 construct_pll_config(struct ssd2825_priv *priv, + u32 desired_pll_freq_kbps, u32 reference_freq_khz) +{ + u32 div_factor = 1, mul_factor, fr = 0; + + while (reference_freq_khz / (div_factor + 1) >= SSD2825_REF_MIN_CLK) + div_factor++; + if (div_factor > 31) + div_factor = 31; + + mul_factor = DIV_ROUND_UP(desired_pll_freq_kbps * div_factor, + reference_freq_khz); + + priv->pll_freq_kbps = reference_freq_khz * mul_factor / div_factor; + priv->nibble_freq_khz = priv->pll_freq_kbps / 4; + + if (priv->pll_freq_kbps >= 501000) + fr = 3; + else if (priv->pll_freq_kbps >= 251000) + fr = 2; + else if (priv->pll_freq_kbps >= 126000) + fr = 1; + + return (fr << 14) | (div_factor << 8) | mul_factor; +} + +static int ssd2825_setup_pll(struct ssd2825_priv *priv, + const struct drm_display_mode *mode) +{ + u16 pll_config, lp_div; + u32 nibble_delay, pclk_mult, tx_freq_khz; + u8 hzd, hpd; + + tx_freq_khz = clk_get_rate(priv->tx_clk) / KILO; + if (!tx_freq_khz) + tx_freq_khz = SSD2825_REF_MIN_CLK; + + pclk_mult = priv->pd_lines / priv->dsi_lanes + 1; + pll_config = construct_pll_config(priv, pclk_mult * mode->clock, + tx_freq_khz); + + lp_div = priv->pll_freq_kbps / (SSD2825_LP_MIN_CLK * 8); + + /* nibble_delay in nanoseconds */ + nibble_delay = MICRO / priv->nibble_freq_khz; + + hzd = priv->hzd / nibble_delay; + hpd = (priv->hpd - 4 * nibble_delay) / nibble_delay; + + /* Disable PLL */ + ssd2825_write_reg(priv, SSD2825_PLL_CTRL_REG, 0x0000); + ssd2825_write_reg(priv, SSD2825_LINE_CTRL_REG, 0x0001); + + /* Set delays */ + ssd2825_write_reg(priv, SSD2825_DELAY_ADJ_REG_1, (hzd << 8) | hpd); + + /* Set PLL coefficients */ + ssd2825_write_reg(priv, SSD2825_PLL_CONFIGURATION_REG, pll_config); + + /* Clock Control Register */ + ssd2825_write_reg(priv, SSD2825_CLOCK_CTRL_REG, + SSD2828_LP_CLOCK_DIVIDER(lp_div)); + + /* Enable PLL */ + ssd2825_write_reg(priv, SSD2825_PLL_CTRL_REG, 0x0001); + ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0); + + return 0; +} + +static void ssd2825_bridge_atomic_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) +{ + struct ssd2825_priv *priv = bridge_to_ssd2825(bridge); + struct mipi_dsi_device *dsi_dev = priv->output.dev; + const struct drm_crtc_state *crtc_state; + const struct drm_display_mode *mode; + struct drm_connector *connector; + struct drm_crtc *crtc; + u32 input_bus_flags = bridge->timings->input_bus_flags; + u16 flags = 0, config; + u8 pixel_format; + int ret; + + /* Power Sequence */ + ret = clk_prepare_enable(priv->tx_clk); + if (ret) + dev_err(priv->dev, "error enabling tx_clk (%d)\n", ret); + + ret = regulator_bulk_enable(ARRAY_SIZE(ssd2825_supplies), priv->supplies); + if (ret) + dev_err(priv->dev, "error enabling regulators (%d)\n", ret); + + usleep_range(1000, 2000); + + ssd2825_hw_reset(priv); + + /* Perform SW reset */ + ssd2825_write_reg(priv, SSD2825_OPERATION_CTRL_REG, 0x0100); + + /* Set pixel format */ + switch (dsi_dev->format) { + case MIPI_DSI_FMT_RGB565: + pixel_format = 0x00; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + pixel_format = 0x01; + break; + case MIPI_DSI_FMT_RGB666: + pixel_format = 0x02; + break; + case MIPI_DSI_FMT_RGB888: + default: + pixel_format = 0x03; + break; + } + + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); + crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + mode = &crtc_state->adjusted_mode; + + /* Set panel timings */ + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_1, + ((mode->vtotal - mode->vsync_end) << 8) | + (mode->htotal - mode->hsync_end)); + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_2, + ((mode->vtotal - mode->vsync_start) << 8) | + (mode->htotal - mode->hsync_start)); + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_3, + ((mode->vsync_start - mode->vdisplay) << 8) | + (mode->hsync_start - mode->hdisplay)); + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_4, mode->hdisplay); + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_5, mode->vdisplay); + + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + flags |= SSD2825_HSYNC_HIGH; + + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + flags |= SSD2825_VSYNC_HIGH; + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_VIDEO) + flags |= SSD2825_NON_BURST_EV; + + if (input_bus_flags & DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE) + flags |= SSD2825_PCKL_HIGH; + + ssd2825_write_reg(priv, SSD2825_RGB_INTERFACE_CTRL_REG_6, flags | pixel_format); + ssd2825_write_reg(priv, SSD2825_LANE_CONFIGURATION_REG, dsi_dev->lanes - 1); + ssd2825_write_reg(priv, SSD2825_TEST_REG, 0x0004); + + /* Call PLL configuration */ + ssd2825_setup_pll(priv, mode); + + usleep_range(10000, 11000); + + config = SSD2825_CONF_REG_HS | SSD2825_CONF_REG_CKE | SSD2825_CONF_REG_DCS | + SSD2825_CONF_REG_ECD | SSD2825_CONF_REG_EOT; + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_LPM) + config &= ~SSD2825_CONF_REG_HS; + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) + config &= ~SSD2825_CONF_REG_EOT; + + /* Initial DSI configuration register set */ + ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config); + ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0); + + if (priv->output.panel) + drm_panel_enable(priv->output.panel); +} + +static void ssd2825_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) +{ + struct ssd2825_priv *priv = bridge_to_ssd2825(bridge); + struct mipi_dsi_device *dsi_dev = priv->output.dev; + u16 config; + + config = SSD2825_CONF_REG_HS | SSD2825_CONF_REG_DCS | + SSD2825_CONF_REG_ECD | SSD2825_CONF_REG_EOT; + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_VIDEO) + config |= SSD2825_CONF_REG_VEN; + + if (dsi_dev->mode_flags & MIPI_DSI_MODE_NO_EOT_PACKET) + config &= ~SSD2825_CONF_REG_EOT; + + /* Complete configuration after DSI commands were sent */ + ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, config); + ssd2825_write_reg(priv, SSD2825_PLL_CTRL_REG, 0x0001); + ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0x0000); +} + +static void ssd2825_bridge_atomic_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) +{ + struct ssd2825_priv *priv = bridge_to_ssd2825(bridge); + int ret; + + msleep(100); + + /* Exit DSI configuration register set */ + ssd2825_write_reg(priv, SSD2825_CONFIGURATION_REG, + SSD2825_CONF_REG_ECD | SSD2825_CONF_REG_EOT); + ssd2825_write_reg(priv, SSD2825_VC_CTRL_REG, 0); + + /* HW disable */ + gpiod_set_value_cansleep(priv->reset_gpio, 1); + usleep_range(5000, 6000); + + ret = regulator_bulk_disable(ARRAY_SIZE(ssd2825_supplies), + priv->supplies); + if (ret < 0) + dev_err(priv->dev, "error disabling regulators (%d)\n", ret); + + clk_disable_unprepare(priv->tx_clk); +} + +static int ssd2825_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct ssd2825_priv *priv = bridge_to_ssd2825(bridge); + + return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, + flags); +} + +static enum drm_mode_status +ssd2825_bridge_mode_valid(struct drm_bridge *bridge, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + if (mode->hdisplay > 1366) + return MODE_H_ILLEGAL; + + if (mode->vdisplay > 1366) + return MODE_V_ILLEGAL; + + return MODE_OK; +} + +static bool ssd2825_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* Default to positive sync */ + + if (!(adjusted_mode->flags & + (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC))) + adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC; + + if (!(adjusted_mode->flags & + (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))) + adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC; + + return true; +} + +static const struct drm_bridge_funcs ssd2825_bridge_funcs = { + .attach = ssd2825_bridge_attach, + .mode_valid = ssd2825_bridge_mode_valid, + .mode_fixup = ssd2825_mode_fixup, + + .atomic_pre_enable = ssd2825_bridge_atomic_pre_enable, + .atomic_enable = ssd2825_bridge_atomic_enable, + .atomic_disable = ssd2825_bridge_atomic_disable, + + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, +}; + +static const struct drm_bridge_timings default_ssd2825_timings = { + .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_DE_HIGH, +}; + +static int ssd2825_probe(struct spi_device *spi) +{ + struct ssd2825_priv *priv; + struct device *dev = &spi->dev; + struct device_node *np = dev->of_node; + int ret; + + /* Driver supports only 8 bit 3 Wire mode */ + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret) + return ret; + + priv = devm_drm_bridge_alloc(dev, struct ssd2825_priv, bridge, &ssd2825_bridge_funcs); + if (IS_ERR(priv)) + return PTR_ERR(priv); + + spi_set_drvdata(spi, priv); + + priv->spi = spi; + priv->dev = dev; + + mutex_init(&priv->mlock); + + priv->tx_clk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(priv->tx_clk)) + return dev_err_probe(dev, PTR_ERR(priv->tx_clk), + "can't retrieve bridge tx_clk\n"); + + priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(priv->reset_gpio), + "failed to get reset GPIO\n"); + + ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(ssd2825_supplies), + ssd2825_supplies, &priv->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + priv->hzd = 133; /* ns */ + device_property_read_u32(dev, "solomon,hs-zero-delay-ns", &priv->hzd); + + priv->hpd = 40; /* ns */ + device_property_read_u32(dev, "solomon,hs-prep-delay-ns", &priv->hpd); + + priv->dsi_host.dev = dev; + priv->dsi_host.ops = &ssd2825_dsi_host_ops; + + priv->bridge.timings = &default_ssd2825_timings; + priv->bridge.of_node = np; + + return mipi_dsi_host_register(&priv->dsi_host); +} + +static void ssd2825_remove(struct spi_device *spi) +{ + struct ssd2825_priv *priv = spi_get_drvdata(spi); + + mipi_dsi_host_unregister(&priv->dsi_host); +} + +static const struct of_device_id ssd2825_of_match[] = { + { .compatible = "solomon,ssd2825" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ssd2825_of_match); + +static struct spi_driver ssd2825_driver = { + .driver = { + .name = "ssd2825", + .of_match_table = ssd2825_of_match, + }, + .probe = ssd2825_probe, + .remove = ssd2825_remove, +}; +module_spi_driver(ssd2825_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("Solomon SSD2825 RGB to MIPI-DSI bridge driver SPI"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/waveshare-dsi.c b/drivers/gpu/drm/bridge/waveshare-dsi.c new file mode 100644 index 000000000000..01c70e7d3d3b --- /dev/null +++ b/drivers/gpu/drm/bridge/waveshare-dsi.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 NXP + * Based on panel-raspberrypi-touchscreen by Broadcom + */ + +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/regmap.h> + +#include <drm/drm_bridge.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_of.h> +#include <drm/drm_panel.h> + +struct ws_bridge { + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct backlight_device *backlight; + struct device *dev; + struct regmap *reg_map; +}; + +static const struct regmap_config ws_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0xff, +}; + +static struct ws_bridge *bridge_to_ws_bridge(struct drm_bridge *bridge) +{ + return container_of(bridge, struct ws_bridge, bridge); +} + +static int ws_bridge_attach_dsi(struct ws_bridge *ws) +{ + const struct mipi_dsi_device_info info = { + .type = "ws-bridge", + .channel = 0, + .node = NULL, + }; + struct device_node *dsi_host_node; + struct device *dev = ws->dev; + struct mipi_dsi_device *dsi; + struct mipi_dsi_host *host; + int ret; + + dsi_host_node = of_graph_get_remote_node(dev->of_node, 0, 0); + if (!dsi_host_node) { + dev_err(dev, "Failed to get remote port\n"); + return -ENODEV; + } + host = of_find_mipi_dsi_host_by_node(dsi_host_node); + of_node_put(dsi_host_node); + if (!host) + return dev_err_probe(dev, -EPROBE_DEFER, "Failed to find dsi_host\n"); + + dsi = devm_mipi_dsi_device_register_full(dev, host, &info); + if (IS_ERR(dsi)) + return dev_err_probe(dev, PTR_ERR(dsi), "Failed to create dsi device\n"); + + dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->lanes = 2; + + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to attach dsi to host\n"); + + return 0; +} + +static int ws_bridge_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct ws_bridge *ws = bridge_to_ws_bridge(bridge); + int ret; + + ret = ws_bridge_attach_dsi(ws); + if (ret) + return ret; + + return drm_bridge_attach(encoder, ws->next_bridge, + &ws->bridge, flags); +} + +static void ws_bridge_bridge_enable(struct drm_bridge *bridge) +{ + struct ws_bridge *ws = bridge_to_ws_bridge(bridge); + + regmap_write(ws->reg_map, 0xad, 0x01); + backlight_enable(ws->backlight); +} + +static void ws_bridge_bridge_disable(struct drm_bridge *bridge) +{ + struct ws_bridge *ws = bridge_to_ws_bridge(bridge); + + backlight_disable(ws->backlight); + regmap_write(ws->reg_map, 0xad, 0x00); +} + +static const struct drm_bridge_funcs ws_bridge_bridge_funcs = { + .enable = ws_bridge_bridge_enable, + .disable = ws_bridge_bridge_disable, + .attach = ws_bridge_bridge_attach, +}; + +static int ws_bridge_bl_update_status(struct backlight_device *bl) +{ + struct ws_bridge *ws = bl_get_data(bl); + + regmap_write(ws->reg_map, 0xab, 0xff - backlight_get_brightness(bl)); + regmap_write(ws->reg_map, 0xaa, 0x01); + + return 0; +} + +static const struct backlight_ops ws_bridge_bl_ops = { + .update_status = ws_bridge_bl_update_status, +}; + +static struct backlight_device *ws_bridge_create_backlight(struct ws_bridge *ws) +{ + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 255, + .max_brightness = 255, + }; + struct device *dev = ws->dev; + + return devm_backlight_device_register(dev, dev_name(dev), dev, ws, + &ws_bridge_bl_ops, &props); +} + +static int ws_bridge_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct drm_panel *panel; + struct ws_bridge *ws; + int ret; + + ws = devm_drm_bridge_alloc(dev, struct ws_bridge, bridge, &ws_bridge_bridge_funcs); + if (!ws) + return -ENOMEM; + + ws->dev = dev; + + ws->reg_map = devm_regmap_init_i2c(i2c, &ws_regmap_config); + if (IS_ERR(ws->reg_map)) + return dev_err_probe(dev, PTR_ERR(ws->reg_map), "Failed to allocate regmap\n"); + + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, &panel, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to find remote panel\n"); + + ws->next_bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(ws->next_bridge)) + return PTR_ERR(ws->next_bridge); + + ws->backlight = ws_bridge_create_backlight(ws); + if (IS_ERR(ws->backlight)) { + ret = PTR_ERR(ws->backlight); + dev_err(dev, "Failed to create backlight: %d\n", ret); + return ret; + } + + regmap_write(ws->reg_map, 0xc0, 0x01); + regmap_write(ws->reg_map, 0xc2, 0x01); + regmap_write(ws->reg_map, 0xac, 0x01); + + ws->bridge.type = DRM_MODE_CONNECTOR_DPI; + ws->bridge.of_node = dev->of_node; + devm_drm_bridge_add(dev, &ws->bridge); + + return 0; +} + +static const struct of_device_id ws_bridge_of_ids[] = { + {.compatible = "waveshare,dsi2dpi",}, + { } +}; + +MODULE_DEVICE_TABLE(of, ws_bridge_of_ids); + +static struct i2c_driver ws_bridge_driver = { + .driver = { + .name = "ws_dsi2dpi", + .of_match_table = ws_bridge_of_ids, + }, + .probe = ws_bridge_probe, +}; +module_i2c_driver(ws_bridge_driver); + +MODULE_AUTHOR("Joseph Guo <qijian.guo@nxp.com>"); +MODULE_DESCRIPTION("Waveshare DSI2DPI bridge driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c index 5eb7e9bfe361..8c915427d053 100644 --- a/drivers/gpu/drm/display/drm_bridge_connector.c +++ b/drivers/gpu/drm/display/drm_bridge_connector.c @@ -816,6 +816,8 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (bridge_connector->bridge_hdmi_cec && bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER) { + bridge = bridge_connector->bridge_hdmi_cec; + ret = drmm_connector_hdmi_cec_notifier_register(connector, NULL, bridge->hdmi_cec_dev); @@ -825,6 +827,8 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (bridge_connector->bridge_hdmi_cec && bridge_connector->bridge_hdmi_cec->ops & DRM_BRIDGE_OP_HDMI_CEC_ADAPTER) { + bridge = bridge_connector->bridge_hdmi_cec; + ret = drmm_connector_hdmi_cec_register(connector, &drm_bridge_connector_hdmi_cec_funcs, bridge->hdmi_cec_adapter_name, diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index ef56b474acf5..d5ebe6ea0acb 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -456,6 +456,7 @@ mode_fixup(struct drm_atomic_state *state) ret = drm_atomic_bridge_chain_check(bridge, new_crtc_state, new_conn_state); + drm_bridge_put(bridge); if (ret) { drm_dbg_atomic(encoder->dev, "Bridge atomic check failed\n"); return ret; @@ -527,6 +528,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, bridge = drm_bridge_chain_get_first_bridge(encoder); ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info, mode); + drm_bridge_put(bridge); if (ret != MODE_OK) { drm_dbg_atomic(encoder->dev, "[BRIDGE] mode_valid() failed\n"); return ret; @@ -1212,6 +1214,7 @@ encoder_bridge_disable(struct drm_device *dev, struct drm_atomic_state *state) */ bridge = drm_bridge_chain_get_first_bridge(encoder); drm_atomic_bridge_chain_disable(bridge, state); + drm_bridge_put(bridge); /* Right function depends upon target state. */ if (funcs) { @@ -1329,6 +1332,7 @@ encoder_bridge_post_disable(struct drm_device *dev, struct drm_atomic_state *sta */ bridge = drm_bridge_chain_get_first_bridge(encoder); drm_atomic_bridge_chain_post_disable(bridge, state); + drm_bridge_put(bridge); } } @@ -1501,6 +1505,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *state) bridge = drm_bridge_chain_get_first_bridge(encoder); drm_bridge_chain_mode_set(bridge, mode, adjusted_mode); + drm_bridge_put(bridge); } } @@ -1580,6 +1585,7 @@ encoder_bridge_pre_enable(struct drm_device *dev, struct drm_atomic_state *state */ bridge = drm_bridge_chain_get_first_bridge(encoder); drm_atomic_bridge_chain_pre_enable(bridge, state); + drm_bridge_put(bridge); } } @@ -1655,6 +1661,7 @@ encoder_bridge_enable(struct drm_device *dev, struct drm_atomic_state *state) } drm_atomic_bridge_chain_enable(bridge, state); + drm_bridge_put(bridge); } } diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index dd45d9b504d8..c3bfcd735a3c 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -941,11 +941,11 @@ static int select_bus_fmt_recursive(struct drm_bridge *first_bridge, { unsigned int i, num_in_bus_fmts = 0; struct drm_bridge_state *cur_state; - struct drm_bridge *prev_bridge; + struct drm_bridge *prev_bridge __free(drm_bridge_put) = + drm_bridge_get_prev_bridge(cur_bridge); u32 *in_bus_fmts; int ret; - prev_bridge = drm_bridge_get_prev_bridge(cur_bridge); cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, cur_bridge); diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 6a44351e58b7..4a89b6acb6af 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -332,7 +332,12 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) if (obj->funcs->close) obj->funcs->close(obj, file_priv); + mutex_lock(&file_priv->prime.lock); + drm_prime_remove_buf_handle(&file_priv->prime, id); + + mutex_unlock(&file_priv->prime.lock); + drm_vma_node_revoke(&obj->vma_node, file_priv); drm_gem_object_handle_put_unlocked(obj); @@ -870,14 +875,6 @@ long drm_gem_dma_resv_wait(struct drm_file *filep, u32 handle, } EXPORT_SYMBOL(drm_gem_dma_resv_wait); -/** - * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl - * @dev: drm_device - * @data: ioctl data - * @file_priv: drm file-private structure - * - * Releases the handle to an mm object. - */ int drm_gem_close_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -893,17 +890,6 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data, return ret; } -/** - * drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl - * @dev: drm_device - * @data: ioctl data - * @file_priv: drm file-private structure - * - * Create a global name for an object, returning the name. - * - * Note that the name does not hold a reference; when the object - * is freed, the name goes away. - */ int drm_gem_flink_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -943,17 +929,6 @@ err: return ret; } -/** - * drm_gem_open_ioctl - implementation of the GEM_OPEN ioctl - * @dev: drm_device - * @data: ioctl data - * @file_priv: drm file-private structure - * - * Open an object using the global name, returning a handle and the size. - * - * This handle (of course) holds a reference to the object, so the object - * will not go away until the handle is deleted. - */ int drm_gem_open_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -988,6 +963,57 @@ err: return ret; } +int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_change_handle *args = data; + struct drm_gem_object *obj; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_GEM)) + return -EOPNOTSUPP; + + obj = drm_gem_object_lookup(file_priv, args->handle); + if (!obj) + return -ENOENT; + + if (args->handle == args->new_handle) + return 0; + + mutex_lock(&file_priv->prime.lock); + + spin_lock(&file_priv->table_lock); + ret = idr_alloc(&file_priv->object_idr, obj, + args->new_handle, args->new_handle + 1, GFP_NOWAIT); + spin_unlock(&file_priv->table_lock); + + if (ret < 0) + goto out_unlock; + + if (obj->dma_buf) { + ret = drm_prime_add_buf_handle(&file_priv->prime, obj->dma_buf, args->new_handle); + if (ret < 0) { + spin_lock(&file_priv->table_lock); + idr_remove(&file_priv->object_idr, args->new_handle); + spin_unlock(&file_priv->table_lock); + goto out_unlock; + } + + drm_prime_remove_buf_handle(&file_priv->prime, args->handle); + } + + ret = 0; + + spin_lock(&file_priv->table_lock); + idr_remove(&file_priv->object_idr, args->handle); + spin_unlock(&file_priv->table_lock); + +out_unlock: + mutex_unlock(&file_priv->prime.lock); + + return ret; +} + /** * drm_gem_open - initializes GEM file-private structures at devnode open time * @dev: drm_device which is being opened by userspace diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index e79c3c623c9a..5a3bed48ab1f 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -85,6 +85,8 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); +int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, + struct dma_buf *dma_buf, uint32_t handle); void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, uint32_t handle); @@ -170,6 +172,8 @@ int drm_gem_close_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_gem_flink_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_gem_change_handle_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); int drm_gem_open_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f593dc569d31..d8a24875a7ba 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -653,6 +653,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_IOCTL_GEM_CHANGE_HANDLE, drm_gem_change_handle_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0), diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 3a9b3278a6e3..fe03915d0095 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -773,41 +773,13 @@ ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload, EXPORT_SYMBOL(mipi_dsi_generic_write); /** - * mipi_dsi_generic_write_chatty() - mipi_dsi_generic_write() w/ an error log - * @dsi: DSI peripheral device - * @payload: buffer containing the payload - * @size: size of payload buffer - * - * Like mipi_dsi_generic_write() but includes a dev_err() - * call for you and returns 0 upon success, not the number of bytes sent. - * - * Return: 0 on success or a negative error code on failure. - */ -int mipi_dsi_generic_write_chatty(struct mipi_dsi_device *dsi, - const void *payload, size_t size) -{ - struct device *dev = &dsi->dev; - ssize_t ret; - - ret = mipi_dsi_generic_write(dsi, payload, size); - if (ret < 0) { - dev_err(dev, "sending generic data %*ph failed: %zd\n", - (int)size, payload, ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL(mipi_dsi_generic_write_chatty); - -/** - * mipi_dsi_generic_write_multi() - mipi_dsi_generic_write_chatty() w/ accum_err + * mipi_dsi_generic_write_multi() - mipi_dsi_generic_write() w/ accum_err * @ctx: Context for multiple DSI transactions * @payload: buffer containing the payload * @size: size of payload buffer * - * Like mipi_dsi_generic_write_chatty() but deals with errors in a way that - * makes it convenient to make several calls in a row. + * A wrapper around mipi_dsi_generic_write() that deals with errors in a way + * that makes it convenient to make several calls in a row. */ void mipi_dsi_generic_write_multi(struct mipi_dsi_multi_context *ctx, const void *payload, size_t size) @@ -829,6 +801,30 @@ void mipi_dsi_generic_write_multi(struct mipi_dsi_multi_context *ctx, EXPORT_SYMBOL(mipi_dsi_generic_write_multi); /** + * mipi_dsi_dual_generic_write_multi() - mipi_dsi_generic_write_multi() for + * two dsi channels, one after the other + * @ctx: Context for multiple DSI transactions + * @dsi1: First dsi channel to write buffer to + * @dsi2: Second dsi channel to write buffer to + * @payload: Buffer containing the payload + * @size: Size of payload buffer + * + * A wrapper around mipi_dsi_generic_write_multi() that allows the user to + * conveniently write to two dsi channels, one after the other. + */ +void mipi_dsi_dual_generic_write_multi(struct mipi_dsi_multi_context *ctx, + struct mipi_dsi_device *dsi1, + struct mipi_dsi_device *dsi2, + const void *payload, size_t size) +{ + ctx->dsi = dsi1; + mipi_dsi_generic_write_multi(ctx, payload, size); + ctx->dsi = dsi2; + mipi_dsi_generic_write_multi(ctx, payload, size); +} +EXPORT_SYMBOL(mipi_dsi_dual_generic_write_multi); + +/** * mipi_dsi_generic_read() - receive data using a generic read packet * @dsi: DSI peripheral device * @params: buffer containing the request parameters @@ -1008,6 +1004,30 @@ void mipi_dsi_dcs_write_buffer_multi(struct mipi_dsi_multi_context *ctx, EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer_multi); /** + * mipi_dsi_dual_dcs_write_buffer_multi - mipi_dsi_dcs_write_buffer_multi() for + * two dsi channels, one after the other + * @ctx: Context for multiple DSI transactions + * @dsi1: First dsi channel to write buffer to + * @dsi2: Second dsi channel to write buffer to + * @data: Buffer containing data to be transmitted + * @len: Size of transmission buffer + * + * A wrapper around mipi_dsi_dcs_write_buffer_multi() that allows the user to + * conveniently write to two dsi channels, one after the other. + */ +void mipi_dsi_dual_dcs_write_buffer_multi(struct mipi_dsi_multi_context *ctx, + struct mipi_dsi_device *dsi1, + struct mipi_dsi_device *dsi2, + const void *data, size_t len) +{ + ctx->dsi = dsi1; + mipi_dsi_dcs_write_buffer_multi(ctx, data, len); + ctx->dsi = dsi2; + mipi_dsi_dcs_write_buffer_multi(ctx, data, len); +} +EXPORT_SYMBOL(mipi_dsi_dual_dcs_write_buffer_multi); + +/** * mipi_dsi_dcs_write() - send DCS write command * @dsi: DSI peripheral device * @cmd: DCS command diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c index a23fc712a8b7..43a10b4af43a 100644 --- a/drivers/gpu/drm/drm_prime.c +++ b/drivers/gpu/drm/drm_prime.c @@ -93,7 +93,7 @@ struct drm_prime_member { struct rb_node handle_rb; }; -static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, +int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle) { struct drm_prime_member *member; @@ -190,8 +190,6 @@ void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, { struct rb_node *rb; - mutex_lock(&prime_fpriv->lock); - rb = prime_fpriv->handles.rb_node; while (rb) { struct drm_prime_member *member; @@ -210,8 +208,6 @@ void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, rb = rb->rb_left; } } - - mutex_unlock(&prime_fpriv->lock); } void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 6b3541159c0f..09b12c30df69 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -119,6 +119,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, *status = drm_bridge_chain_mode_valid(bridge, &connector->display_info, mode); + drm_bridge_put(bridge); if (*status != MODE_OK) { /* There is also no point in continuing for crtc check * here. */ diff --git a/drivers/gpu/drm/mxsfb/lcdif_kms.c b/drivers/gpu/drm/mxsfb/lcdif_kms.c index dbd42cc1da87..1c3b33be6c40 100644 --- a/drivers/gpu/drm/mxsfb/lcdif_kms.c +++ b/drivers/gpu/drm/mxsfb/lcdif_kms.c @@ -433,7 +433,6 @@ static int lcdif_crtc_atomic_check(struct drm_crtc *crtc, struct drm_connector *connector; struct drm_encoder *encoder; struct drm_bridge_state *bridge_state; - struct drm_bridge *bridge; u32 bus_format, bus_flags; bool format_set = false, flags_set = false; int ret, i; @@ -453,7 +452,8 @@ static int lcdif_crtc_atomic_check(struct drm_crtc *crtc, encoder = connector_state->best_encoder; - bridge = drm_bridge_chain_get_first_bridge(encoder); + struct drm_bridge *bridge __free(drm_bridge_put) = + drm_bridge_chain_get_first_bridge(encoder); if (!bridge) continue; diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h index 561877725aac..bb34b0a6082d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.h +++ b/drivers/gpu/drm/nouveau/nouveau_chan.h @@ -31,8 +31,6 @@ struct nouveau_channel { u64 addr; } push; - /* TODO: this will be reworked in the near future */ - bool accel_done; void *fence; struct { int max; diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 0e27b76d1e1c..c25ef9a54b9f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -90,7 +90,6 @@ FIRE_RING(struct nouveau_channel *chan) { if (chan->dma.cur == chan->dma.put) return; - chan->accel_done = true; WRITE_PUT(chan->dma.cur); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c index b9581feb24cc..a23b40b27b81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/enum.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c @@ -44,7 +44,7 @@ nvkm_snprintbf(char *data, int size, const struct nvkm_bitfield *bf, u32 value) bool space = false; while (size >= 1 && bf->name) { if (value & bf->mask) { - int this = snprintf(data, size, "%s%s", + int this = scnprintf(data, size, "%s%s", space ? " " : "", bf->name); size -= this; data += this; diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs index 7e59a34b830d..7e7d4e2de2fb 100644 --- a/drivers/gpu/drm/nova/file.rs +++ b/drivers/gpu/drm/nova/file.rs @@ -2,13 +2,11 @@ use crate::driver::{NovaDevice, NovaDriver}; use crate::gem::NovaObject; -use crate::uapi::{GemCreate, GemInfo, Getparam}; use kernel::{ alloc::flags::*, drm::{self, gem::BaseObject}, pci, prelude::*, - types::Opaque, uapi, }; @@ -26,20 +24,19 @@ impl File { /// IOCTL: get_param: Query GPU / driver metadata. pub(crate) fn get_param( dev: &NovaDevice, - getparam: &Opaque<uapi::drm_nova_getparam>, + getparam: &mut uapi::drm_nova_getparam, _file: &drm::File<File>, ) -> Result<u32> { let adev = &dev.adev; let parent = adev.parent().ok_or(ENOENT)?; let pdev: &pci::Device = parent.try_into()?; - let getparam: &Getparam = getparam.into(); - let value = match getparam.param() as u32 { + let value = match getparam.param as u32 { uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?, _ => return Err(EINVAL), }; - getparam.set_value(value); + getparam.value = value; Ok(0) } @@ -47,13 +44,12 @@ impl File { /// IOCTL: gem_create: Create a new DRM GEM object. pub(crate) fn gem_create( dev: &NovaDevice, - req: &Opaque<uapi::drm_nova_gem_create>, + req: &mut uapi::drm_nova_gem_create, file: &drm::File<File>, ) -> Result<u32> { - let req: &GemCreate = req.into(); - let obj = NovaObject::new(dev, req.size().try_into()?)?; + let obj = NovaObject::new(dev, req.size.try_into()?)?; - req.set_handle(obj.create_handle(file)?); + req.handle = obj.create_handle(file)?; Ok(0) } @@ -61,13 +57,12 @@ impl File { /// IOCTL: gem_info: Query GEM metadata. pub(crate) fn gem_info( _dev: &NovaDevice, - req: &Opaque<uapi::drm_nova_gem_info>, + req: &mut uapi::drm_nova_gem_info, file: &drm::File<File>, ) -> Result<u32> { - let req: &GemInfo = req.into(); - let bo = NovaObject::lookup_handle(file, req.handle())?; + let bo = NovaObject::lookup_handle(file, req.handle)?; - req.set_size(bo.size().try_into()?); + req.size = bo.size().try_into()?; Ok(0) } diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs index 64fd670e99e1..8893e58ee0db 100644 --- a/drivers/gpu/drm/nova/nova.rs +++ b/drivers/gpu/drm/nova/nova.rs @@ -5,7 +5,6 @@ mod driver; mod file; mod gem; -mod uapi; use crate::driver::NovaDriver; diff --git a/drivers/gpu/drm/nova/uapi.rs b/drivers/gpu/drm/nova/uapi.rs deleted file mode 100644 index eb228a58d423..000000000000 --- a/drivers/gpu/drm/nova/uapi.rs +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -use kernel::uapi; - -// TODO Work out some common infrastructure to avoid boilerplate code for uAPI abstractions. - -macro_rules! define_uapi_abstraction { - ($name:ident <= $inner:ty) => { - #[repr(transparent)] - pub struct $name(::kernel::types::Opaque<$inner>); - - impl ::core::convert::From<&::kernel::types::Opaque<$inner>> for &$name { - fn from(value: &::kernel::types::Opaque<$inner>) -> Self { - // SAFETY: `Self` is a transparent wrapper of `$inner`. - unsafe { ::core::mem::transmute(value) } - } - } - }; -} - -define_uapi_abstraction!(Getparam <= uapi::drm_nova_getparam); - -impl Getparam { - pub fn param(&self) -> u64 { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`. - unsafe { (*self.0.get()).param } - } - - pub fn set_value(&self, v: u64) { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`. - unsafe { (*self.0.get()).value = v }; - } -} - -define_uapi_abstraction!(GemCreate <= uapi::drm_nova_gem_create); - -impl GemCreate { - pub fn size(&self) -> u64 { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`. - unsafe { (*self.0.get()).size } - } - - pub fn set_handle(&self, handle: u32) { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`. - unsafe { (*self.0.get()).handle = handle }; - } -} - -define_uapi_abstraction!(GemInfo <= uapi::drm_nova_gem_info); - -impl GemInfo { - pub fn handle(&self) -> u32 { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`. - unsafe { (*self.0.get()).handle } - } - - pub fn set_size(&self, size: u64) { - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`. - unsafe { (*self.0.get()).size = size }; - } -} diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 09b9f7ff9340..407c5f6a268b 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -215,6 +215,19 @@ config DRM_PANEL_HIMAX_HX8394 If M is selected the module will be called panel-himax-hx8394. +config DRM_PANEL_HYDIS_HV101HD1 + tristate "Hydis HV101HD1 panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the Hydis HV101HD1 + 2-lane 1366x768 MIPI DSI panel found in ASUS VivoTab RT TF600T. + HV101HD1 is a color active matrix TFT LCD module using amorphous + silicon TFT's (Thin Film Transistors) as an active switching devices. + + If M is selected the module will be called panel-hydis-hv101hd1 + config DRM_PANEL_ILITEK_IL9322 tristate "Ilitek ILI9322 320x240 QVGA panels" depends on OF && SPI @@ -843,6 +856,17 @@ config DRM_PANEL_SAMSUNG_S6E8AA0 select DRM_MIPI_DSI select VIDEOMODE_HELPERS +config DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01 + tristate "Samsung AMS561RA01 panel with S6E8AA5X01 controller" + depends on GPIOLIB && OF && REGULATOR + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Samsung AMS561RA01 + panel, which uses Samsung's S6E8AA5X01 controller. The panel has a + ~5.6 inch AMOLED display, and the controller is driven by the MIPI + DSI protocol with 4 lanes. + config DRM_PANEL_SAMSUNG_SOFEF00 tristate "Samsung sofef00/s6e3fc2x01 OnePlus 6/6T DSI cmd mode panels" depends on OF @@ -971,7 +995,7 @@ config DRM_PANEL_STARTEK_KD070FHFID015 depends on BACKLIGHT_CLASS_DEVICE help Say Y here if you want to enable support for STARTEK KD070FHFID015 DSI panel - based on RENESAS-R69429 controller. The pannel is a 7-inch TFT LCD display + based on RENESAS-R69429 controller. The panel is a 7-inch TFT LCD display with a resolution of 1024 x 600 pixels. It provides a MIPI DSI interface to the host, a built-in LED backlight and touch controller. diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 957555b49996..3615a761b44f 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83102) += panel-himax-hx83102.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o +obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o @@ -87,6 +88,7 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0_DSI) += panel-samsung-s6e63m0-dsi.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS427AP24) += panel-samsung-s6e88a0-ams427ap24.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01) += panel-samsung-s6e88a0-ams452ef01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o +obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01) += panel-samsung-s6e8aa5x01-ams561ra01.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_SOFEF00) += panel-samsung-sofef00.o obj-$(CONFIG_DRM_PANEL_SEIKO_43WVF1G) += panel-seiko-43wvf1g.o obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 9a56e208cbdd..3e4c3a439988 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -1736,10 +1736,11 @@ static const struct panel_delay delay_200_500_e50 = { .enable = 50, }; -static const struct panel_delay delay_200_500_e50_p2e200 = { +static const struct panel_delay delay_200_500_e50_d50_p2e200 = { .hpd_absent = 200, .unprepare = 500, .enable = 50, + .disable = 50, .prepare_to_enable = 200, }; @@ -1795,6 +1796,13 @@ static const struct panel_delay delay_200_500_e200_d10 = { .disable = 10, }; +static const struct panel_delay delay_200_500_e200_d50 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 50, +}; + static const struct panel_delay delay_200_150_e200 = { .hpd_absent = 200, .unprepare = 150, @@ -1828,6 +1836,13 @@ static const struct panel_delay delay_50_500_e200_d200_po2e335 = { .powered_on_to_enable = 335, }; +static const struct panel_delay delay_200_500_e50_d100 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 50, + .disable = 100, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .ident = { \ @@ -1857,6 +1872,7 @@ static const struct panel_delay delay_50_500_e200_d200_po2e335 = { * Sort first by vendor, then by product ID. */ static const struct edp_panel_entry edp_panels[] = { + EDP_PANEL_ENTRY('A', 'U', 'O', 0x04a4, &delay_200_500_e50, "B122UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x105c, &delay_200_500_e50, "B116XTN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x125c, &delay_200_500_e50, "Unknown"), @@ -1875,6 +1891,7 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x435c, &delay_200_500_e50, "Unknown"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x52b0, &delay_200_500_e50, "B116XAK02.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), @@ -1882,10 +1899,12 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x723c, &delay_200_500_e50, "B140XTN07.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x73aa, &delay_200_500_e50, "B116XTN02.3"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x8bba, &delay_200_500_e50, "B140UAN08.5"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xa199, &delay_200_500_e50, "B116XAN06.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xa7b3, &delay_200_500_e50, "B140UAN04.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xc4b4, &delay_200_500_e50, "B116XAT04.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xc9a8, &delay_200_500_e50, "B140QAN08.H"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xcdba, &delay_200_500_e50, "B140UAX01.2"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xd497, &delay_200_500_e50, "B120XAN01.0"), EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), @@ -1934,21 +1953,24 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a1b, &delay_200_500_e50, "NV133WUM-N63"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a36, &delay_200_500_e200, "Unknown"), - EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80, "NV116WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a3e, &delay_200_500_e80_d50, "NV116WHM-N49"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ae8, &delay_200_500_e50_p2e80, "NV140WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b09, &delay_200_500_e50_po2e200, "NV140FHM-NZ"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b1e, &delay_200_500_e80, "NE140QDM-N6A"), - EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80_d50, "NV122WUM-N41"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf6, &delay_200_500_e200, "NV140WUM-N64"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d45, &delay_200_500_e80, "NV116WHM-N4B"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0d73, &delay_200_500_e80, "NE140WUM-N6S"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ddf, &delay_200_500_e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1130, &delay_200_500_e50, "N116BGE-EB2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), @@ -1966,27 +1988,33 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115d, &delay_200_500_e80_d50, "N116BCA-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x115e, &delay_200_500_e80_d50, "N116BCA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x115f, &delay_200_500_e80_d50, "N116BCL-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1160, &delay_200_500_e80_d50, "N116BCJ-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1161, &delay_200_500_e80, "N116BCP-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1163, &delay_200_500_e80_d50, "N116BCJ-EAK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x124c, &delay_200_500_e80_d50, "N122JCA-ENK"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x142e, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14a8, &delay_200_500_e80, "N140JCA-ELP"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x162b, &delay_200_500_e80_d50, "N160JCE-ELL"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x7402, &delay_200_500_e200_d50, "N116BCA-EAK"), - EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_p2e200, "MNC207QS1-1"), - EDP_PANEL_ENTRY('C', 'S', 'O', 0x1413, &delay_200_500_e50_p2e200, "MNE007JA1-2"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_d50_p2e200, "MNC207QS1-1"), + EDP_PANEL_ENTRY('C', 'S', 'O', 0x1413, &delay_200_500_e50_d50_p2e200, "MNE007JA1-2"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1100, &delay_200_500_e80_d50, "MNB601LS1-1"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1103, &delay_200_500_e80_d50, "MNB601LS1-3"), - EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50, "MNB601LS1-4"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1104, &delay_200_500_e50_d100, "MNB601LS1-4"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1448, &delay_200_500_e50, "MNE007QS3-7"), EDP_PANEL_ENTRY('C', 'S', 'W', 0x1457, &delay_80_500_e80_p2e200, "MNE007QS3-8"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1462, &delay_200_500_e50, "MNE007QS5-2"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1468, &delay_200_500_e50, "MNE007QB2-2"), EDP_PANEL_ENTRY('E', 'T', 'C', 0x0000, &delay_50_500_e200_d200_po2e335, "LP079QX1-SP0V"), @@ -2033,6 +2061,9 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('S', 'T', 'A', 0x0009, &delay_200_500_e250, "116QHD024002"), EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"), + EDP_PANEL_ENTRY('T', 'M', 'A', 0x0811, &delay_200_500_e80_d50, "TM140VDXP01-04"), + EDP_PANEL_ENTRY('T', 'M', 'A', 0x2094, &delay_200_500_e50_d100, "TL140VDMS03-01"), + { /* sentinal */ } }; diff --git a/drivers/gpu/drm/panel/panel-himax-hx8279.c b/drivers/gpu/drm/panel/panel-himax-hx8279.c index fb302d1f91b9..9e443c719843 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8279.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8279.c @@ -935,7 +935,7 @@ static int hx8279_check_dig_gamma(struct hx8279 *hx, struct device *dev, const u j++; x++; } while (x < 4); - }; + } return 0; } diff --git a/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c b/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c new file mode 100644 index 000000000000..46426c388932 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/array_size.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> + +struct hv101hd1 { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct regulator_bulk_data *supplies; +}; + +static const struct regulator_bulk_data hv101hd1_supplies[] = { + { .supply = "vdd" }, + { .supply = "vio" }, +}; + +static inline struct hv101hd1 *to_hv101hd1(struct drm_panel *panel) +{ + return container_of(panel, struct hv101hd1, panel); +} + +static int hv101hd1_prepare(struct drm_panel *panel) +{ + struct hv101hd1 *hv = to_hv101hd1(panel); + struct mipi_dsi_multi_context ctx = { .dsi = hv->dsi }; + struct device *dev = &hv->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(hv101hd1_supplies), hv->supplies); + if (ret) { + dev_err(dev, "error enabling regulators (%d)\n", ret); + return ret; + } + + mipi_dsi_dcs_exit_sleep_mode_multi(&ctx); + mipi_dsi_msleep(&ctx, 20); + + mipi_dsi_dcs_set_display_on_multi(&ctx); + mipi_dsi_msleep(&ctx, 20); + + return 0; +} + +static int hv101hd1_disable(struct drm_panel *panel) +{ + struct hv101hd1 *hv = to_hv101hd1(panel); + struct mipi_dsi_multi_context ctx = { .dsi = hv->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&ctx); + mipi_dsi_msleep(&ctx, 120); + mipi_dsi_dcs_enter_sleep_mode_multi(&ctx); + mipi_dsi_msleep(&ctx, 20); + + return 0; +} + +static int hv101hd1_unprepare(struct drm_panel *panel) +{ + struct hv101hd1 *hv = to_hv101hd1(panel); + + return regulator_bulk_disable(ARRAY_SIZE(hv101hd1_supplies), + hv->supplies); +} + +static const struct drm_display_mode hv101hd1_mode = { + .clock = (1366 + 74 + 36 + 24) * (768 + 21 + 7 + 4) * 60 / 1000, + .hdisplay = 1366, + .hsync_start = 1366 + 74, + .hsync_end = 1366 + 74 + 36, + .htotal = 1366 + 74 + 36 + 24, + .vdisplay = 768, + .vsync_start = 768 + 21, + .vsync_end = 768 + 21 + 7, + .vtotal = 768 + 21 + 7 + 4, + .width_mm = 140, + .height_mm = 220, +}; + +static int hv101hd1_get_modes(struct drm_panel *panel, struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &hv101hd1_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs hv101hd1_panel_funcs = { + .prepare = hv101hd1_prepare, + .disable = hv101hd1_disable, + .unprepare = hv101hd1_unprepare, + .get_modes = hv101hd1_get_modes, +}; + +static int hv101hd1_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct hv101hd1 *hv; + int ret; + + hv = devm_drm_panel_alloc(dev, struct hv101hd1, panel, + &hv101hd1_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(hv)) + return PTR_ERR(hv); + + ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(hv101hd1_supplies), + hv101hd1_supplies, &hv->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + hv->dsi = dsi; + mipi_dsi_set_drvdata(dsi, hv); + + dsi->lanes = 2; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; + + ret = drm_panel_of_backlight(&hv->panel); + if (ret) + return dev_err_probe(dev, ret, "Failed to get backlight\n"); + + drm_panel_add(&hv->panel); + + ret = mipi_dsi_attach(dsi); + if (ret) { + drm_panel_remove(&hv->panel); + return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); + } + + return 0; +} + +static void hv101hd1_remove(struct mipi_dsi_device *dsi) +{ + struct hv101hd1 *hv = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, + "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&hv->panel); +} + +static const struct of_device_id hv101hd1_of_match[] = { + { .compatible = "hydis,hv101hd1" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hv101hd1_of_match); + +static struct mipi_dsi_driver hv101hd1_driver = { + .driver = { + .name = "panel-hv101hd1", + .of_match_table = hv101hd1_of_match, + }, + .probe = hv101hd1_probe, + .remove = hv101hd1_remove, +}; +module_mipi_dsi_driver(hv101hd1_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("DRM driver for Hydis HV101HD1 panel"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c index 5f897e143758..83656bb4b0b2 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -81,25 +81,25 @@ static int jdi_panel_disable(struct drm_panel *panel) static int jdi_panel_unprepare(struct drm_panel *panel) { struct jdi_panel *jdi = to_panel_jdi(panel); - int ret; - ret = mipi_dsi_dcs_set_display_off(jdi->link1); - if (ret < 0) - dev_err(panel->dev, "failed to set display off: %d\n", ret); + /* + * One context per panel since we'll continue trying to shut down the + * other panel even if one isn't responding. + */ + struct mipi_dsi_multi_context dsi_ctx1 = { .dsi = jdi->link1 }; + struct mipi_dsi_multi_context dsi_ctx2 = { .dsi = jdi->link2 }; - ret = mipi_dsi_dcs_set_display_off(jdi->link2); - if (ret < 0) - dev_err(panel->dev, "failed to set display off: %d\n", ret); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx1); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx2); /* Specified by JDI @ 50ms, subject to change */ msleep(50); - ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link1); - if (ret < 0) - dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); - ret = mipi_dsi_dcs_enter_sleep_mode(jdi->link2); - if (ret < 0) - dev_err(panel->dev, "failed to enter sleep mode: %d\n", ret); + /* Doesn't hurt to try sleep mode even if display off fails */ + dsi_ctx1.accum_err = 0; + dsi_ctx2.accum_err = 0; + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx1); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx2); /* Specified by JDI @ 150ms, subject to change */ msleep(150); @@ -123,72 +123,46 @@ static int jdi_panel_unprepare(struct drm_panel *panel) /* Specified by JDI @ 20ms, subject to change */ msleep(20); - return ret; + return 0; } -static int jdi_setup_symmetrical_split(struct mipi_dsi_device *left, - struct mipi_dsi_device *right, - const struct drm_display_mode *mode) +static void jdi_setup_symmetrical_split(struct mipi_dsi_multi_context *dsi_ctx, + struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + const struct drm_display_mode *mode) { - int err; - - err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1); - if (err < 0) { - dev_err(&left->dev, "failed to set column address: %d\n", err); - return err; - } - - err = mipi_dsi_dcs_set_column_address(right, 0, mode->hdisplay / 2 - 1); - if (err < 0) { - dev_err(&right->dev, "failed to set column address: %d\n", err); - return err; - } - - err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1); - if (err < 0) { - dev_err(&left->dev, "failed to set page address: %d\n", err); - return err; - } - - err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1); - if (err < 0) { - dev_err(&right->dev, "failed to set page address: %d\n", err); - return err; - } - - return 0; + mipi_dsi_dual(mipi_dsi_dcs_set_column_address_multi, + dsi_ctx, left, right, + 0, mode->hdisplay / 2 - 1); + mipi_dsi_dual(mipi_dsi_dcs_set_page_address_multi, + dsi_ctx, left, right, + 0, mode->vdisplay - 1); } -static int jdi_write_dcdc_registers(struct jdi_panel *jdi) +static void jdi_write_dcdc_registers(struct mipi_dsi_multi_context *dsi_ctx, + struct jdi_panel *jdi) { /* Clear the manufacturer command access protection */ - mipi_dsi_generic_write_seq(jdi->link1, MCS_CMD_ACS_PROT, - MCS_CMD_ACS_PROT_OFF); - mipi_dsi_generic_write_seq(jdi->link2, MCS_CMD_ACS_PROT, - MCS_CMD_ACS_PROT_OFF); + mipi_dsi_dual_generic_write_seq_multi(dsi_ctx, jdi->link1, jdi->link2, + MCS_CMD_ACS_PROT, + MCS_CMD_ACS_PROT_OFF); /* - * Change the VGH/VGL divide rations to move the noise generated by the + * Change the VGH/VGL divide ratios to move the noise generated by the * TCONN. This should hopefully avoid interaction with the backlight * controller. */ - mipi_dsi_generic_write_seq(jdi->link1, MCS_PWR_CTRL_FUNC, - MCS_PWR_CTRL_PARAM1_VGH_330_DIV | - MCS_PWR_CTRL_PARAM1_DEFAULT, - MCS_PWR_CTRL_PARAM2_VGL_410_DIV | - MCS_PWR_CTRL_PARAM2_DEFAULT); - - mipi_dsi_generic_write_seq(jdi->link2, MCS_PWR_CTRL_FUNC, - MCS_PWR_CTRL_PARAM1_VGH_330_DIV | - MCS_PWR_CTRL_PARAM1_DEFAULT, - MCS_PWR_CTRL_PARAM2_VGL_410_DIV | - MCS_PWR_CTRL_PARAM2_DEFAULT); - - return 0; + mipi_dsi_dual_generic_write_seq_multi(dsi_ctx, jdi->link1, jdi->link2, + MCS_PWR_CTRL_FUNC, + MCS_PWR_CTRL_PARAM1_VGH_330_DIV | + MCS_PWR_CTRL_PARAM1_DEFAULT, + MCS_PWR_CTRL_PARAM2_VGL_410_DIV | + MCS_PWR_CTRL_PARAM2_DEFAULT); } static int jdi_panel_prepare(struct drm_panel *panel) { struct jdi_panel *jdi = to_panel_jdi(panel); + struct mipi_dsi_multi_context dsi_ctx = {}; int err; /* Disable backlight to avoid showing random pixels @@ -231,88 +205,36 @@ static int jdi_panel_prepare(struct drm_panel *panel) * put in place to communicate the configuration back to the DSI host * controller. */ - err = jdi_setup_symmetrical_split(jdi->link1, jdi->link2, - jdi->mode); - if (err < 0) { - dev_err(panel->dev, "failed to set up symmetrical split: %d\n", - err); - goto poweroff; - } - - err = mipi_dsi_dcs_set_tear_scanline(jdi->link1, - jdi->mode->vdisplay - 16); - if (err < 0) { - dev_err(panel->dev, "failed to set tear scanline: %d\n", err); - goto poweroff; - } - - err = mipi_dsi_dcs_set_tear_scanline(jdi->link2, - jdi->mode->vdisplay - 16); - if (err < 0) { - dev_err(panel->dev, "failed to set tear scanline: %d\n", err); - goto poweroff; - } - - err = mipi_dsi_dcs_set_tear_on(jdi->link1, - MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (err < 0) { - dev_err(panel->dev, "failed to set tear on: %d\n", err); - goto poweroff; - } - - err = mipi_dsi_dcs_set_tear_on(jdi->link2, - MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (err < 0) { - dev_err(panel->dev, "failed to set tear on: %d\n", err); - goto poweroff; - } + jdi_setup_symmetrical_split(&dsi_ctx, jdi->link1, jdi->link2, + jdi->mode); - err = mipi_dsi_dcs_set_pixel_format(jdi->link1, MIPI_DCS_PIXEL_FMT_24BIT); - if (err < 0) { - dev_err(panel->dev, "failed to set pixel format: %d\n", err); - goto poweroff; - } + mipi_dsi_dual(mipi_dsi_dcs_set_tear_scanline_multi, + &dsi_ctx, jdi->link1, jdi->link2, + jdi->mode->vdisplay - 16); - err = mipi_dsi_dcs_set_pixel_format(jdi->link2, MIPI_DCS_PIXEL_FMT_24BIT); - if (err < 0) { - dev_err(panel->dev, "failed to set pixel format: %d\n", err); - goto poweroff; - } + mipi_dsi_dual(mipi_dsi_dcs_set_tear_on_multi, + &dsi_ctx, jdi->link1, jdi->link2, + MIPI_DSI_DCS_TEAR_MODE_VBLANK); - err = mipi_dsi_dcs_exit_sleep_mode(jdi->link1); - if (err < 0) { - dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); - goto poweroff; - } + mipi_dsi_dual(mipi_dsi_dcs_set_pixel_format_multi, + &dsi_ctx, jdi->link1, jdi->link2, + MIPI_DCS_PIXEL_FMT_24BIT); - err = mipi_dsi_dcs_exit_sleep_mode(jdi->link2); - if (err < 0) { - dev_err(panel->dev, "failed to exit sleep mode: %d\n", err); - goto poweroff; - } + mipi_dsi_dual(mipi_dsi_dcs_exit_sleep_mode_multi, + &dsi_ctx, jdi->link1, jdi->link2); - err = jdi_write_dcdc_registers(jdi); - if (err < 0) { - dev_err(panel->dev, "failed to write dcdc registers: %d\n", err); - goto poweroff; - } + jdi_write_dcdc_registers(&dsi_ctx, jdi); /* - * We need to wait 150ms between mipi_dsi_dcs_exit_sleep_mode() and - * mipi_dsi_dcs_set_display_on(). + * We need to wait 150ms between mipi_dsi_dcs_exit_sleep_mode_multi() + * and mipi_dsi_dcs_set_display_on_multi(). */ - msleep(150); + mipi_dsi_msleep(&dsi_ctx, 150); - err = mipi_dsi_dcs_set_display_on(jdi->link1); - if (err < 0) { - dev_err(panel->dev, "failed to set display on: %d\n", err); - goto poweroff; - } + mipi_dsi_dual(mipi_dsi_dcs_set_display_on_multi, + &dsi_ctx, jdi->link1, jdi->link2); - err = mipi_dsi_dcs_set_display_on(jdi->link2); - if (err < 0) { - dev_err(panel->dev, "failed to set display on: %d\n", err); + if (dsi_ctx.accum_err < 0) goto poweroff; - } jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM; jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35560.c b/drivers/gpu/drm/panel/panel-novatek-nt35560.c index 98f0782c8411..17898a29efe8 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35560.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35560.c @@ -161,7 +161,7 @@ static int nt35560_set_brightness(struct backlight_device *bl) par = 0x00; ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, &par, 1); - if (ret) { + if (ret < 0) { dev_err(nt->dev, "failed to disable display backlight (%d)\n", ret); return ret; } diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index 32cf64c7c18b..226d91daf8c7 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -23,14 +23,6 @@ #define DSI_NUM_MIN 1 -#define mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, cmd, seq...) \ - do { \ - dsi_ctx.dsi = dsi0; \ - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, cmd, seq); \ - dsi_ctx.dsi = dsi1; \ - mipi_dsi_dcs_write_seq_multi(&dsi_ctx, cmd, seq); \ - } while (0) - struct panel_info { struct drm_panel panel; struct mipi_dsi_device *dsi[2]; @@ -71,217 +63,217 @@ static int elish_boe_init_sequence(struct panel_info *pinfo) struct mipi_dsi_device *dsi1 = pinfo->dsi[1]; struct mipi_dsi_multi_context dsi_ctx = { .dsi = NULL }; /* No datasheet, so write magic init sequence directly */ - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x05); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x18, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0x84); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x05, 0x2d); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x06, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x07, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x08, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0x45); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x12, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x15, 0x83); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0x0c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29, 0x0a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x31, 0xfe); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x32, 0xfd); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x33, 0xfb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x34, 0xf8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0xf5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x36, 0xf3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x37, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x38, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0xef); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0xec); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x40, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x41, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x13); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x45, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x46, 0xf4); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x47, 0xe7); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x48, 0xda); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x49, 0xcd); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x99); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x50, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x68); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x52, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x54, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x59, 0xfb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5c, 0xef); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5e, 0xda); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x60, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x61, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x62, 0xcb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x63, 0xbf); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x64, 0xb3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x65, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x66, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x67, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x25, 0x47); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0x47); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0x47); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x84, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x85, 0x0c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x91, 0x1f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x92, 0x0f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x93, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x94, 0x18); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x95, 0x03); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x96, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb0, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x1f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x24); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x27); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x31); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd1, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd2, 0x30); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xde, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdf, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x81); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9f, 0x50); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x6f, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x70, 0x11); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x73, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x74, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x76, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x77, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa9, 0x50); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xaa, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xab, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xad, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xba, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbe, 0x04); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbf, 0x49); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc0, 0x04); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc1, 0x59); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc2, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc5, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc6, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc7, 0x48); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xca, 0x43); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcb, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xce, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcf, 0x43); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd3, 0x43); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd7, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdc, 0x43); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdd, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xe1, 0x43); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xe2, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf2, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf3, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xf4, 0x48); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x13, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x14, 0x23); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbc, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbd, 0x23); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x97, 0x3c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x98, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x99, 0x95); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9a, 0x03); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9b, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9c, 0x0b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9d, 0x0a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9e, 0x90); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9f, 0x50); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa3, 0x50); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x14, 0x60); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0xc0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xd0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x02, 0xaf); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0xee); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x99); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1d, 0x09); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x2c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x13); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x05); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x18, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x00, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x01, 0x84); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x05, 0x2d); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x06, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x07, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x08, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x09, 0x45); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x11, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x12, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x15, 0x83); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x16, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x29, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x30, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x31, 0xfe); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x32, 0xfd); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x33, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x34, 0xf8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x35, 0xf5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x36, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x37, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x38, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x39, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3a, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3b, 0xec); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x40, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x41, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2a, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x45, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x46, 0xf4); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x47, 0xe7); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x48, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x49, 0xcd); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4f, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x50, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x68); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x52, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x53, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x54, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x58, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x59, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5c, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5e, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x60, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x61, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x62, 0xcb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x63, 0xbf); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x64, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x65, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x66, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x67, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x25, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x30, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x39, 0x47); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x19, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1b, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1c, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2a, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x84, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x85, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x91, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x92, 0x0f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x93, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x94, 0x18); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x95, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x96, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb0, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x19, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x24); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb8, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x27); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd0, 0x31); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd1, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd2, 0x30); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd4, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xde, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xdf, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x00, 0x81); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9f, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x6f, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x70, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x73, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x74, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x76, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x77, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xa9, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xaa, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xab, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xad, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb8, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xba, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbb, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbe, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbf, 0x49); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc0, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc1, 0x59); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc5, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc6, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc7, 0x48); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xca, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xcb, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xce, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xcf, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd0, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd3, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd4, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd7, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xdc, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xdd, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xe1, 0x43); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xe2, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xf2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xf3, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xf4, 0x48); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x13, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x14, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbc, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbd, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x97, 0x3c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x98, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x99, 0x95); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9a, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9b, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9c, 0x0b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9d, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9e, 0x90); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9f, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xa3, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x14, 0x60); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x16, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4f, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3a, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xd0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x02, 0xaf); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x09, 0xee); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1c, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1d, 0x09); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x53, 0x2c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x35, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbb, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x11); mipi_dsi_msleep(&dsi_ctx, 70); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x29); return dsi_ctx.accum_err; } @@ -292,195 +284,195 @@ static int elish_csot_init_sequence(struct panel_info *pinfo) struct mipi_dsi_device *dsi1 = pinfo->dsi[1]; struct mipi_dsi_multi_context dsi_ctx = { .dsi = NULL }; /* No datasheet, so write magic init sequence directly */ - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x05); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x18, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xd0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x02, 0xaf); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x30); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0xee); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x99); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1d, 0x09); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x23); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0x84); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x05, 0x2d); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x06, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x07, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x08, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x09, 0x45); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x12, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x15, 0x83); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x16, 0x0c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29, 0x0a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x31, 0xfe); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x32, 0xfd); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x33, 0xfb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x34, 0xf8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x35, 0xf5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x36, 0xf3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x37, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x38, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0xf2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3a, 0xef); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0xec); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x40, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x41, 0xe5); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x13); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x45, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x46, 0xf4); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x47, 0xe7); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x48, 0xda); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x49, 0xcd); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x4f, 0x99); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x50, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x68); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x52, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x54, 0x66); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x58, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x59, 0xfb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5c, 0xef); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5e, 0xda); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x60, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x61, 0xd8); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x62, 0xcb); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x63, 0xbf); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x64, 0xb3); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x65, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x66, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x67, 0xb2); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x53, 0x2c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x55, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x13); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x25, 0x46); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x30, 0x46); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x39, 0x46); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1c, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2a, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0xf0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x84, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x85, 0x0c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x51, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x91, 0x1f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x92, 0x0f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x93, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x94, 0x18); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x95, 0x03); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x96, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb0, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x19, 0x1f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x24); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x27); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x31); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd1, 0x20); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xde, 0x80); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xdf, 0x02); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x26); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x00, 0x81); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x01, 0xb0); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x22); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x6f, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x70, 0x11); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x73, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x74, 0x4d); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xa9, 0x50); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xaa, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xab, 0x28); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xad, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb8, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xb9, 0x4b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xba, 0x96); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbb, 0x4b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbe, 0x07); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbf, 0x4b); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc0, 0x07); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc1, 0x5c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc2, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc5, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc6, 0x3f); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xc7, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xca, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcb, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xce, 0x00); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xcf, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd0, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd3, 0x08); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xd4, 0x40); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x25); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbc, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xbd, 0x1c); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x9a, 0x03); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x10); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x05); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x18, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xd0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x02, 0xaf); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x00, 0x30); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x09, 0xee); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1c, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1d, 0x09); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3a, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4f, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x58, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x35, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x23); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x00, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x01, 0x84); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x05, 0x2d); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x06, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x07, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x08, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x09, 0x45); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x11, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x12, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x15, 0x83); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x16, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x29, 0x0a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x30, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x31, 0xfe); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x32, 0xfd); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x33, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x34, 0xf8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x35, 0xf5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x36, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x37, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x38, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x39, 0xf2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3a, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3b, 0xec); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3d, 0xe9); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3f, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x40, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x41, 0xe5); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2a, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x45, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x46, 0xf4); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x47, 0xe7); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x48, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x49, 0xcd); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4a, 0xc0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4b, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4c, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4d, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4e, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x4f, 0x99); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x50, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x68); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x52, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x53, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x54, 0x66); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2b, 0x0e); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x58, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x59, 0xfb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5a, 0xf7); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5b, 0xf3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5c, 0xef); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5d, 0xe3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5e, 0xda); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x5f, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x60, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x61, 0xd8); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x62, 0xcb); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x63, 0xbf); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x64, 0xb3); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x65, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x66, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x67, 0xb2); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x0f, 0xff); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x53, 0x2c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x55, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbb, 0x13); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x3b, 0x03, 0xac, 0x1a, 0x04, 0x04); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x25, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x30, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x39, 0x46); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x19, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1a, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1b, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1c, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2a, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x2b, 0xe0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0xf0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x84, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x85, 0x0c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x51, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x91, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x92, 0x0f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x93, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x94, 0x18); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x95, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x96, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb0, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x19, 0x1f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x1b, 0x1b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x24); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb8, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x27); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd0, 0x31); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd1, 0x20); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd4, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xde, 0x80); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xdf, 0x02); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x26); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x00, 0x81); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x01, 0xb0); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x22); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x6f, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x70, 0x11); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x73, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x74, 0x4d); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xa0, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xa9, 0x50); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xaa, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xab, 0x28); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xad, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb8, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xb9, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xba, 0x96); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbb, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbe, 0x07); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbf, 0x4b); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc0, 0x07); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc1, 0x5c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc2, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc5, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc6, 0x3f); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xc7, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xca, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xcb, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xce, 0x00); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xcf, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd0, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd3, 0x08); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xd4, 0x40); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x25); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbc, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xbd, 0x1c); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x2a); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xfb, 0x01); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x9a, 0x03); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0xff, 0x10); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x11); mipi_dsi_msleep(&dsi_ctx, 70); - mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x29); + mipi_dsi_dual_dcs_write_seq_multi(&dsi_ctx, dsi0, dsi1, 0x29); return dsi_ctx.accum_err; } diff --git a/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c index 3231e84dc66c..8a608972fc41 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-ota5601a.c @@ -276,11 +276,8 @@ static int ota5601a_probe(struct spi_device *spi) } err = drm_panel_of_backlight(&panel->drm_panel); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(dev, "Failed to get backlight handle\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, "Failed to get backlight handle\n"); drm_panel_add(&panel->drm_panel); diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01-ams561ra01.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01-ams561ra01.c new file mode 100644 index 000000000000..56e10c7c3a76 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa5x01-ams561ra01.c @@ -0,0 +1,981 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Samsung AMS561RA01 panel with S6E8AA5X01 controller. + * + * Copyright (C) 2025 Kaustabh Chakraborty <kauschluss@disroot.org> + */ + +#include <linux/backlight.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_modes.h> +#include <drm/drm_panel.h> +#include <drm/drm_probe_helper.h> + +/* Manufacturer Command Set */ +#define MCS_AIDCTL 0xb2 +#define MCS_ADAPTIVECTL 0xb5 +#define MCS_ELVSS 0xb6 +#define MCS_TEMPERCTL 0xb8 +#define MCS_PENTILE 0xc0 +#define MCS_GAMMACTL 0xca +#define MCS_LTPSCTL 0xcb +#define MCS_PCD 0xcc +#define MCS_ERRFLAG 0xe7 +#define MCS_ACCESSPROT 0xf0 +#define MCS_DISPCTL 0xf2 +#define MCS_GAMMAUPD 0xf7 + +#define GAMMA_CMD_LEN 34 +#define AID_CMD_LEN 3 + +static const struct { + u8 gamma[GAMMA_CMD_LEN]; + u8 aid[AID_CMD_LEN]; +} s6e8aa5x01_ams561ra01_cmds[] = { + { + /* 5 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x94, + 0x88, 0x89, 0x8a, 0x87, 0x87, 0x89, + 0x8d, 0x8c, 0x8d, 0x89, 0x8c, 0x8e, + 0x8e, 0x8f, 0x90, 0xa3, 0xa2, 0x9a, + 0xcf, 0xca, 0x9f, 0xe6, 0xff, 0xb4, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0xa5 }, + }, { + /* 6 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x95, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c, + 0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x9a, + 0xd0, 0xcc, 0xa2, 0xed, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x95 }, + }, { + /* 7 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x95, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x8c, 0x8a, 0x8c, 0x85, 0x88, 0x8c, + 0x8b, 0x8c, 0x8e, 0xa2, 0xa2, 0x99, + 0xc8, 0xc4, 0x9d, 0xed, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x89 }, + }, { + /* 8 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8a, 0x87, 0x87, 0x89, + 0x8a, 0x88, 0x8b, 0x83, 0x86, 0x8b, + 0x8c, 0x8b, 0x8d, 0x9d, 0x9f, 0x97, + 0xc7, 0xc3, 0x9c, 0xf5, 0xff, 0xbb, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x7e }, + }, { + /* 9 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8a, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x8a, 0x82, 0x84, 0x88, + 0x90, 0x8f, 0x91, 0x95, 0x97, 0x94, + 0xc6, 0xc2, 0x9d, 0xf5, 0xff, 0xbb, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x73 }, + }, { + /* 10 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8a, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x8a, 0x82, 0x84, 0x88, + 0x90, 0x8f, 0x91, 0x94, 0x97, 0x93, + 0xc6, 0xc2, 0x9e, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x67 }, + }, { + /* 11 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8a, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x8a, 0x82, 0x84, 0x88, + 0x8b, 0x8b, 0x8d, 0x90, 0x93, 0x92, + 0xc5, 0xc1, 0x9c, 0xf5, 0xff, 0xbb, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x56 }, + }, { + /* 12 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x82, 0x84, 0x88, + 0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8f, + 0xcd, 0xc9, 0xa1, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x4a }, + }, { + /* 13 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x82, 0x84, 0x88, + 0x87, 0x86, 0x8a, 0x8c, 0x90, 0x8e, + 0xc4, 0xbf, 0x9c, 0xf5, 0xff, 0xbb, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x3b }, + }, { + /* 14 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x82, 0x84, 0x88, + 0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f, + 0xc2, 0xbf, 0x9c, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x35 }, + }, { + /* 15 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x82, 0x84, 0x88, + 0x87, 0x86, 0x89, 0x8c, 0x90, 0x8f, + 0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x25 }, + }, { + /* 16 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x82, 0x84, 0x88, + 0x88, 0x86, 0x89, 0x8c, 0x90, 0x8f, + 0xb7, 0xb6, 0x96, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x20 }, + }, { + /* 17 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x7f, 0x80, 0x86, + 0x86, 0x85, 0x89, 0x88, 0x8c, 0x8e, + 0xbf, 0xbe, 0x9c, 0xec, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x05, 0x11 }, + }, { + /* 19 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x7f, 0x80, 0x86, + 0x87, 0x85, 0x89, 0x88, 0x8c, 0x8e, + 0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0xf2 }, + }, { + /* 20 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x95, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x89, 0x86, 0x89, 0x7f, 0x80, 0x86, + 0x87, 0x85, 0x89, 0x89, 0x8c, 0x8e, + 0xb3, 0xb4, 0x97, 0xeb, 0xff, 0xb7, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0xe4 }, + }, { + /* 21 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x96, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x8a, 0x88, 0x8b, 0x7d, 0x7e, 0x84, + 0x8c, 0x8a, 0x8c, 0x8e, 0x90, 0x8f, + 0xb6, 0xb6, 0x97, 0xe3, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0xd5 }, + }, { + /* 22 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x97, + 0x88, 0x89, 0x8b, 0x87, 0x87, 0x89, + 0x8a, 0x88, 0x8b, 0x81, 0x82, 0x86, + 0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f, + 0xb6, 0xb6, 0x95, 0xe3, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0xc5 }, + }, { + /* 24 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x97, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86, + 0x87, 0x86, 0x88, 0x8e, 0x90, 0x8f, + 0xb6, 0xb6, 0x94, 0xe3, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0xa7 }, + }, { + /* 25 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x98, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86, + 0x87, 0x86, 0x87, 0x8e, 0x90, 0x8f, + 0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0x95 }, + }, { + /* 27 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x99, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x83, 0x86, 0x8a, + 0x88, 0x87, 0x87, 0x88, 0x8b, 0x8c, + 0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0x76 }, + }, { + /* 29 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x99, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x83, 0x86, 0x89, + 0x88, 0x87, 0x88, 0x88, 0x8b, 0x8b, + 0xbf, 0xbf, 0x9a, 0xda, 0xfa, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0x54 }, + }, { + /* 30 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x84, 0x86, 0x8a, + 0x87, 0x87, 0x87, 0x88, 0x8b, 0x8b, + 0xbf, 0xbf, 0x99, 0xda, 0xfa, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0x44 }, + }, { + /* 32 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9a, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x89, 0x87, 0x8a, 0x84, 0x86, 0x8a, + 0x87, 0x87, 0x87, 0x89, 0x8b, 0x8b, + 0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x04, 0x1f }, + }, { + /* 34 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x88, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8b, 0x87, 0x8b, 0x83, 0x86, 0x89, + 0x87, 0x87, 0x88, 0x88, 0x8b, 0x8a, + 0xbf, 0xbf, 0x98, 0xd2, 0xf2, 0xac, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0xff }, + }, { + /* 37 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86, + 0x86, 0x86, 0x86, 0x8d, 0x90, 0x8d, + 0xc0, 0xbf, 0x9a, 0xd2, 0xf2, 0xac, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0xd3 }, + }, { + /* 39 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8a, 0x81, 0x82, 0x86, + 0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d, + 0xb6, 0xb6, 0x93, 0xda, 0xf9, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0xb3 }, + }, { + /* 41 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x85, + 0x87, 0x86, 0x87, 0x8d, 0x90, 0x8d, + 0xb6, 0xb6, 0x94, 0xda, 0xf9, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0x93 }, + }, { + /* 44 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86, + 0x87, 0x86, 0x86, 0x85, 0x87, 0x8a, + 0xbe, 0xbe, 0x99, 0xda, 0xf9, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0x66 }, + }, { + /* 47 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9b, + 0x89, 0x89, 0x8c, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86, + 0x88, 0x86, 0x87, 0x84, 0x87, 0x89, + 0xb4, 0xb4, 0x94, 0xe2, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0x40 }, + }, { + /* 50 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c, + 0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86, + 0x88, 0x86, 0x87, 0x84, 0x87, 0x89, + 0xb4, 0xb4, 0x95, 0xe2, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x03, 0x0e }, + }, { + /* 53 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c, + 0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86, + 0x88, 0x86, 0x87, 0x85, 0x87, 0x8a, + 0xb4, 0xb4, 0x96, 0xe2, 0xff, 0xb3, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0xe2 }, + }, { + /* 56 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c, + 0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x81, 0x82, 0x86, + 0x88, 0x86, 0x87, 0x85, 0x87, 0x8a, + 0xab, 0xab, 0x90, 0xdd, 0xf7, 0xaf, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0xb5 }, + }, { + /* 60 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c, + 0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87, + 0x83, 0x81, 0x84, 0x81, 0x84, 0x88, + 0xb3, 0xb3, 0x96, 0xcf, 0xe5, 0xa8, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x77 }, + }, { + /* 64 nits */ + { MCS_GAMMACTL, + 0x00, 0x98, 0x00, 0xa4, 0x00, 0x9c, + 0x89, 0x89, 0x8b, 0x88, 0x88, 0x8a, + 0x8a, 0x87, 0x8b, 0x82, 0x82, 0x87, + 0x83, 0x81, 0x84, 0x82, 0x84, 0x88, + 0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x36 }, + }, { + /* 68 nits */ + { MCS_GAMMACTL, + 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x9d, + 0x88, 0x88, 0x89, 0x89, 0x89, 0x8b, + 0x8a, 0x88, 0x8b, 0x7f, 0x80, 0x86, + 0x88, 0x86, 0x87, 0x7d, 0x7f, 0x85, + 0xb2, 0xb3, 0x97, 0xcf, 0xe5, 0xa8, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 72 nits */ + { MCS_GAMMACTL, + 0x00, 0x9c, 0x00, 0xa9, 0x00, 0xa0, + 0x88, 0x88, 0x89, 0x88, 0x88, 0x8a, + 0x8c, 0x8a, 0x8d, 0x7f, 0x81, 0x85, + 0x84, 0x82, 0x84, 0x85, 0x87, 0x8a, + 0xaa, 0xab, 0x93, 0xcf, 0xe5, 0xa8, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 77 nits */ + { MCS_GAMMACTL, + 0x00, 0xa1, 0x00, 0xad, 0x00, 0xa5, + 0x89, 0x89, 0x8a, 0x88, 0x87, 0x89, + 0x8c, 0x89, 0x8d, 0x7f, 0x81, 0x85, + 0x84, 0x83, 0x84, 0x81, 0x83, 0x86, + 0xaa, 0xab, 0x93, 0xc0, 0xd3, 0xa1, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 82 nits */ + { MCS_GAMMACTL, + 0x00, 0xa5, 0x00, 0xb0, 0x00, 0xa9, + 0x88, 0x89, 0x89, 0x85, 0x86, 0x89, + 0x8a, 0x88, 0x8b, 0x82, 0x82, 0x87, + 0x81, 0x80, 0x82, 0x89, 0x8b, 0x8b, + 0xa2, 0xa3, 0x8e, 0xc0, 0xd3, 0xa1, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 87 nits */ + { MCS_GAMMACTL, + 0x00, 0xab, 0x00, 0xb4, 0x00, 0xad, + 0x88, 0x89, 0x8a, 0x84, 0x86, 0x88, + 0x8a, 0x88, 0x8b, 0x7f, 0x7f, 0x84, + 0x86, 0x84, 0x85, 0x85, 0x86, 0x88, + 0xa2, 0xa3, 0x8f, 0xc0, 0xd3, 0xa1, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 93 nits */ + { MCS_GAMMACTL, + 0x00, 0xaf, 0x00, 0xb9, 0x00, 0xb1, + 0x88, 0x89, 0x8a, 0x84, 0x85, 0x87, + 0x8a, 0x89, 0x8b, 0x7e, 0x7e, 0x83, + 0x87, 0x86, 0x86, 0x88, 0x8a, 0x89, + 0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 98 nits */ + { MCS_GAMMACTL, + 0x00, 0xb3, 0x00, 0xbc, 0x00, 0xb5, + 0x88, 0x88, 0x88, 0x84, 0x84, 0x86, + 0x8a, 0x88, 0x8a, 0x7f, 0x7f, 0x84, + 0x84, 0x83, 0x84, 0x88, 0x8a, 0x89, + 0x9c, 0x9c, 0x8b, 0xc0, 0xd3, 0xa1, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 105 nits */ + { MCS_GAMMACTL, + 0x00, 0xb7, 0x00, 0xc0, 0x00, 0xba, + 0x87, 0x87, 0x88, 0x85, 0x85, 0x87, + 0x89, 0x88, 0x89, 0x7f, 0x7f, 0x83, + 0x81, 0x80, 0x82, 0x88, 0x8a, 0x89, + 0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 111 nits */ + { MCS_GAMMACTL, + 0x00, 0xbb, 0x00, 0xc3, 0x00, 0xbe, + 0x87, 0x87, 0x88, 0x85, 0x85, 0x88, + 0x88, 0x87, 0x89, 0x80, 0x80, 0x84, + 0x81, 0x81, 0x82, 0x85, 0x86, 0x87, + 0x9c, 0x9c, 0x8b, 0xb2, 0xc2, 0x9a, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x15 }, + }, { + /* 119 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4, + 0x87, 0x87, 0x88, 0x82, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x82, 0x81, 0x84, + 0x83, 0x82, 0x83, 0x80, 0x81, 0x84, + 0x9c, 0x9c, 0x8c, 0xb2, 0xc2, 0x9a, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x02, 0x14 }, + }, { + /* 126 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4, + 0x87, 0x87, 0x88, 0x82, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x82, 0x81, 0x84, + 0x83, 0x82, 0x83, 0x80, 0x81, 0x84, + 0x9c, 0x9c, 0x8d, 0xb2, 0xc2, 0x9a, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x01, 0xde }, + }, { + /* 134 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc4, + 0x87, 0x87, 0x88, 0x82, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x82, 0x81, 0x84, + 0x83, 0x82, 0x83, 0x80, 0x81, 0x84, + 0x9c, 0x9c, 0x8d, 0xa4, 0xb0, 0x92, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x01, 0x94 }, + }, { + /* 143 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3, + 0x87, 0x87, 0x88, 0x82, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x82, 0x81, 0x85, + 0x83, 0x82, 0x83, 0x80, 0x81, 0x84, + 0x92, 0x92, 0x89, 0xab, 0xb6, 0x96, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x01, 0x46 }, + }, { + /* 152 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3, + 0x87, 0x87, 0x88, 0x83, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x81, 0x81, 0x85, + 0x84, 0x82, 0x83, 0x80, 0x81, 0x83, + 0x92, 0x92, 0x8b, 0xab, 0xb6, 0x96, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0xfa }, + }, { + /* 162 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3, + 0x87, 0x87, 0x88, 0x83, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x81, 0x81, 0x84, + 0x84, 0x82, 0x84, 0x80, 0x81, 0x83, + 0x92, 0x92, 0x8b, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0xac }, + }, { + /* 172 nits */ + { MCS_GAMMACTL, + 0x00, 0xc0, 0x00, 0xc8, 0x00, 0xc3, + 0x87, 0x87, 0x88, 0x83, 0x84, 0x86, + 0x87, 0x85, 0x87, 0x81, 0x81, 0x84, + 0x84, 0x82, 0x83, 0x80, 0x81, 0x84, + 0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x57 }, + }, { + /* 183 nits */ + { MCS_GAMMACTL, + 0x00, 0xc2, 0x00, 0xca, 0x00, 0xc5, + 0x86, 0x86, 0x87, 0x85, 0x84, 0x87, + 0x87, 0x86, 0x88, 0x7e, 0x80, 0x83, + 0x84, 0x82, 0x83, 0x80, 0x81, 0x83, + 0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 195 nits */ + { MCS_GAMMACTL, + 0x00, 0xc7, 0x00, 0xce, 0x00, 0xc9, + 0x86, 0x87, 0x86, 0x83, 0x83, 0x85, + 0x85, 0x84, 0x86, 0x82, 0x82, 0x85, + 0x80, 0x80, 0x81, 0x81, 0x81, 0x84, + 0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 207 nits */ + { MCS_GAMMACTL, + 0x00, 0xcc, 0x00, 0xd2, 0x00, 0xce, + 0x86, 0x86, 0x87, 0x81, 0x83, 0x84, + 0x84, 0x82, 0x84, 0x83, 0x83, 0x85, + 0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81, + 0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 220 nits */ + { MCS_GAMMACTL, + 0x00, 0xd1, 0x00, 0xd6, 0x00, 0xd3, + 0x86, 0x86, 0x86, 0x81, 0x83, 0x84, + 0x84, 0x82, 0x84, 0x80, 0x80, 0x83, + 0x81, 0x81, 0x82, 0x7c, 0x7d, 0x81, + 0x93, 0x92, 0x8c, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 234 nits */ + { MCS_GAMMACTL, + 0x00, 0xd6, 0x00, 0xdb, 0x00, 0xd8, + 0x85, 0x85, 0x85, 0x81, 0x83, 0x84, + 0x83, 0x82, 0x83, 0x80, 0x80, 0x82, + 0x84, 0x82, 0x83, 0x79, 0x79, 0x7e, + 0x93, 0x92, 0x8d, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 249 nits */ + { MCS_GAMMACTL, + 0x00, 0xdc, 0x00, 0xe0, 0x00, 0xdd, + 0x84, 0x84, 0x84, 0x81, 0x82, 0x83, + 0x84, 0x82, 0x84, 0x7f, 0x7f, 0x82, + 0x81, 0x80, 0x81, 0x80, 0x81, 0x82, + 0x8c, 0x8c, 0x86, 0x9d, 0xa4, 0x8e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 265 nits */ + { MCS_GAMMACTL, + 0x00, 0xe2, 0x00, 0xe5, 0x00, 0xe3, + 0x83, 0x83, 0x83, 0x81, 0x82, 0x83, + 0x82, 0x82, 0x83, 0x82, 0x81, 0x83, + 0x7f, 0x7e, 0x80, 0x7c, 0x7d, 0x80, + 0x8c, 0x8c, 0x86, 0x8e, 0x92, 0x87, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 282 nits */ + { MCS_GAMMACTL, + 0x00, 0xe8, 0x00, 0xea, 0x00, 0xe9, + 0x83, 0x83, 0x83, 0x80, 0x82, 0x82, + 0x81, 0x82, 0x82, 0x82, 0x81, 0x82, + 0x81, 0x80, 0x81, 0x80, 0x80, 0x81, + 0x85, 0x85, 0x83, 0x8e, 0x92, 0x87, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 300 nits */ + { MCS_GAMMACTL, + 0x00, 0xed, 0x00, 0xef, 0x00, 0xed, + 0x81, 0x82, 0x81, 0x81, 0x81, 0x82, + 0x82, 0x82, 0x83, 0x80, 0x80, 0x81, + 0x81, 0x81, 0x82, 0x83, 0x83, 0x83, + 0x80, 0x80, 0x7f, 0x8e, 0x92, 0x87, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 316 nits */ + { MCS_GAMMACTL, + 0x00, 0xf3, 0x00, 0xf4, 0x00, 0xf3, + 0x80, 0x81, 0x80, 0x81, 0x81, 0x81, + 0x82, 0x82, 0x82, 0x81, 0x80, 0x81, + 0x82, 0x82, 0x83, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 333 nits */ + { MCS_GAMMACTL, + 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf8, + 0x80, 0x81, 0x80, 0x81, 0x80, 0x81, + 0x81, 0x82, 0x82, 0x81, 0x80, 0x81, + 0x83, 0x83, 0x83, 0x7e, 0x7d, 0x7e, + 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 360 nits */ + { MCS_GAMMACTL, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 378 nits */ + { MCS_GAMMACTL, + 0x01, 0x04, 0x01, 0x03, 0x01, 0x04, + 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 395 nits */ + { MCS_GAMMACTL, + 0x01, 0x09, 0x01, 0x07, 0x01, 0x08, + 0x7e, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, + 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, + 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 413 nits */ + { MCS_GAMMACTL, + 0x01, 0x0e, 0x01, 0x0b, 0x01, 0x0c, + 0x7e, 0x7f, 0x80, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7d, 0x7d, 0x7d, + 0x80, 0x80, 0x7f, 0x7d, 0x7e, 0x7e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 430 nits */ + { MCS_GAMMACTL, + 0x01, 0x13, 0x01, 0x0f, 0x01, 0x10, + 0x7d, 0x7f, 0x80, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7d, 0x7d, 0x7d, + 0x80, 0x80, 0x7f, 0x7c, 0x7d, 0x7e, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 448 nits */ + { MCS_GAMMACTL, + 0x01, 0x18, 0x01, 0x13, 0x01, 0x14, + 0x7c, 0x7e, 0x80, 0x7e, 0x7e, 0x7e, + 0x7e, 0x7e, 0x7d, 0x7e, 0x7f, 0x7e, + 0x80, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, + 0x80, 0x80, 0x7e, 0x7b, 0x7c, 0x7d, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 465 nits */ + { MCS_GAMMACTL, + 0x01, 0x1d, 0x01, 0x17, 0x01, 0x18, + 0x7c, 0x7e, 0x80, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7d, 0x7e, 0x7f, 0x7e, + 0x80, 0x7f, 0x7f, 0x7b, 0x7b, 0x7b, + 0x80, 0x80, 0x7e, 0x7a, 0x7c, 0x7d, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 483 nits */ + { MCS_GAMMACTL, + 0x01, 0x22, 0x01, 0x1b, 0x01, 0x1c, + 0x7b, 0x7e, 0x80, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7c, 0x7e, 0x7f, 0x7e, + 0x80, 0x7f, 0x7f, 0x7a, 0x7a, 0x7a, + 0x80, 0x80, 0x7e, 0x79, 0x7b, 0x7c, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, { + /* 500 nits */ + { MCS_GAMMACTL, + 0x01, 0x27, 0x01, 0x1f, 0x01, 0x20, + 0x7b, 0x7e, 0x80, 0x7d, 0x7d, 0x7d, + 0x7d, 0x7d, 0x7c, 0x7e, 0x7f, 0x7e, + 0x80, 0x7f, 0x7f, 0x7a, 0x7a, 0x7a, + 0x81, 0x80, 0x7e, 0x79, 0x7b, 0x7c, + 0x00, 0x00, 0x00, }, + { MCS_AIDCTL, 0x00, 0x10 }, + }, +}; + +struct s6e8aa5x01_ams561ra01_ctx { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct backlight_device *bl; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; + u32 nr_supplies; +}; + +static const struct regulator_bulk_data s6e8aa5x01_ams561ra01_supplies[] = { + { .supply = "vdd" }, + { .supply = "vci" }, +}; + +static inline struct s6e8aa5x01_ams561ra01_ctx *to_ctx(struct drm_panel *panel) +{ + return container_of(panel, struct s6e8aa5x01_ams561ra01_ctx, panel); +} + +static int s6e8aa5x01_ams561ra01_update_status(struct backlight_device *bl) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = bl_get_data(bl); + struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi }; + u16 lvl = backlight_get_brightness(bl); + + if (!ctx->panel.enabled) + return 0; + + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ACCESSPROT, 0x5a, 0x5a); + + mipi_dsi_dcs_write_buffer_multi(&dsi, + s6e8aa5x01_ams561ra01_cmds[lvl].gamma, + GAMMA_CMD_LEN); + mipi_dsi_dcs_write_buffer_multi(&dsi, + s6e8aa5x01_ams561ra01_cmds[lvl].aid, + AID_CMD_LEN); + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_GAMMAUPD, 0x03); + + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ACCESSPROT, 0xa5, 0xa5); + + return dsi.accum_err; +} + +static int s6e8aa5x01_ams561ra01_prepare(struct drm_panel *panel) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = to_ctx(panel); + struct device *dev = &ctx->dsi->dev; + int ret; + + ret = regulator_bulk_enable(ctx->nr_supplies, ctx->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + + return 0; +} + +static int s6e8aa5x01_ams561ra01_unprepare(struct drm_panel *panel) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = to_ctx(panel); + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + + regulator_bulk_disable(ctx->nr_supplies, ctx->supplies); + + return 0; +} + +static int s6e8aa5x01_ams561ra01_enable(struct drm_panel *panel) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = to_ctx(panel); + struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi); + mipi_dsi_msleep(&dsi, 100); + + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ACCESSPROT, 0x5a, 0x5a); + + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PENTILE, 0xd8, 0xd8, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_PCD, 0x5c); + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ERRFLAG, 0xed, 0xc7, 0x23, 0x67); + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_DISPCTL, 0x0c, 0x0c, 0xb9, 0x01); + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_LTPSCTL, + 0x00, 0x45, 0x10, 0x10, 0x08, 0x32, 0x54, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x48, 0x5e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, + 0x08, 0x05, 0x2a, 0x54, 0x03, 0xcc, 0x00, 0xff, + 0xfb, 0x03, 0x0d, 0x00, 0x11, 0x0f, 0x02, 0x03, + 0x0b, 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x00, 0x02, 0x03, 0x0b, + 0x0c, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13); + + mipi_dsi_dcs_write_seq_multi(&dsi, MCS_ACCESSPROT, 0xa5, 0xa5); + + mipi_dsi_dcs_set_display_on_multi(&dsi); + + return dsi.accum_err; +} + +static int s6e8aa5x01_ams561ra01_disable(struct drm_panel *panel) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = to_ctx(panel); + struct mipi_dsi_multi_context dsi = { .dsi = ctx->dsi }; + + mipi_dsi_dcs_set_display_off_multi(&dsi); + mipi_dsi_msleep(&dsi, 100); + + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi); + mipi_dsi_msleep(&dsi, 150); + + return dsi.accum_err; +} + +static const struct drm_display_mode s6e8aa5x01_ams561ra01_mode = { + .clock = (720 + 62 + 2 + 26) * (1480 + 12 + 2 + 10) * 60 / 1000, + .hdisplay = 720, + .hsync_start = 720 + 62, + .hsync_end = 720 + 62 + 2, + .htotal = 720 + 62 + 2 + 26, + .vdisplay = 1480, + .vsync_start = 1480 + 12, + .vsync_end = 1480 + 12 + 2, + .vtotal = 1480 + 12 + 2 + 10, + .width_mm = 62, + .height_mm = 128, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static int s6e8aa5x01_ams561ra01_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + return drm_connector_helper_get_modes_fixed(connector, + &s6e8aa5x01_ams561ra01_mode); +} + +static const struct backlight_ops s6e8aa5x01_ams561ra01_bl_ops = { + .update_status = s6e8aa5x01_ams561ra01_update_status, +}; + +static const struct drm_panel_funcs s6e8aa5x01_ams561ra01_panel_funcs = { + .prepare = s6e8aa5x01_ams561ra01_prepare, + .unprepare = s6e8aa5x01_ams561ra01_unprepare, + .enable = s6e8aa5x01_ams561ra01_enable, + .disable = s6e8aa5x01_ams561ra01_disable, + .get_modes = s6e8aa5x01_ams561ra01_get_modes, +}; + +static int s6e8aa5x01_ams561ra01_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct s6e8aa5x01_ams561ra01_ctx *ctx; + int ret; + + ctx = devm_drm_panel_alloc(dev, struct s6e8aa5x01_ams561ra01_ctx, panel, + &s6e8aa5x01_ams561ra01_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->nr_supplies = ARRAY_SIZE(s6e8aa5x01_ams561ra01_supplies); + ret = devm_regulator_bulk_get_const(dev, ctx->nr_supplies, + s6e8aa5x01_ams561ra01_supplies, + &ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "failed to get reset-gpios\n"); + + ctx->bl = devm_backlight_device_register(dev, dev_name(dev), dev, ctx, + &s6e8aa5x01_ams561ra01_bl_ops, + NULL); + if (IS_ERR(ctx->bl)) + return dev_err_probe(dev, PTR_ERR(ctx->bl), + "failed to register backlight device\n"); + + ctx->bl->props.type = BACKLIGHT_PLATFORM; + ctx->bl->props.brightness = ARRAY_SIZE(s6e8aa5x01_ams561ra01_cmds) - 1; + ctx->bl->props.max_brightness = ctx->bl->props.brightness; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_VIDEO_NO_HFP; + + ctx->panel.prepare_prev_first = true; + drm_panel_add(&ctx->panel); + + ret = devm_mipi_dsi_attach(dev, dsi); + if (ret < 0) { + drm_panel_remove(&ctx->panel); + return dev_err_probe(dev, ret, "failed to attach to DSI host\n"); + } + + return 0; +} + +static void s6e8aa5x01_ams561ra01_remove(struct mipi_dsi_device *dsi) +{ + struct s6e8aa5x01_ams561ra01_ctx *ctx = mipi_dsi_get_drvdata(dsi); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id s6e8aa5x01_ams561ra01_of_device_id[] = { + { .compatible = "samsung,s6e8aa5x01-ams561ra01" }, + { } +}; +MODULE_DEVICE_TABLE(of, s6e8aa5x01_ams561ra01_of_device_id); + +static struct mipi_dsi_driver s6e8aa5x01_ams561ra01_dsi_driver = { + .probe = s6e8aa5x01_ams561ra01_probe, + .remove = s6e8aa5x01_ams561ra01_remove, + .driver = { + .name = "panel-samsung-s6e8aa5x01-ams561ra01", + .of_match_table = s6e8aa5x01_ams561ra01_of_device_id, + }, +}; +module_mipi_dsi_driver(s6e8aa5x01_ams561ra01_dsi_driver); + +MODULE_AUTHOR("Kaustabh Chakraborty <kauschluss@disroot.org>"); +MODULE_DESCRIPTION("Samsung AMS561RA01 Panel with S6E8AA5X01 Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 3333d4a07504..0019de93be1b 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -3716,6 +3716,29 @@ static const struct panel_desc olimex_lcd_olinuxino_43ts = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct drm_display_mode olimex_lcd_olinuxino_5cts_mode = { + .clock = 33300, + .hdisplay = 800, + .hsync_start = 800 + 210, + .hsync_end = 800 + 210 + 20, + .htotal = 800 + 210 + 20 + 26, + .vdisplay = 480, + .vsync_start = 480 + 22, + .vsync_end = 480 + 22 + 10, + .vtotal = 480 + 22 + 10 + 13, +}; + +static const struct panel_desc olimex_lcd_olinuxino_5cts = { + .modes = &olimex_lcd_olinuxino_5cts_mode, + .num_modes = 1, + .size = { + .width = 154, + .height = 86, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X24, +}; + + static const struct display_timing ontat_kd50g21_40nt_a1_timing = { .pixelclock = { 30000000, 30000000, 50000000 }, .hactive = { 800, 800, 800 }, @@ -5279,6 +5302,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "olimex,lcd-olinuxino-43-ts", .data = &olimex_lcd_olinuxino_43ts, }, { + .compatible = "olimex,lcd-olinuxino-5-cts", + .data = &olimex_lcd_olinuxino_5cts, + }, { .compatible = "ontat,kd50g21-40nt-a1", .data = &ontat_kd50g21_40nt_a1, }, { diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 1a007a244d84..6c348fe28955 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Driver for panels based on Sitronix ST7703 controller, souch as: + * Driver for panels based on Sitronix ST7703 controller, such as: * * - Rocktech jh057n00900 5.5" MIPI-DSI panel * diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 1116f2d2826e..9256806eb662 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1103,14 +1103,15 @@ static int panthor_ioctl_group_create(struct drm_device *ddev, void *data, ret = group_priority_permit(file, args->priority); if (ret) - return ret; + goto out; ret = panthor_group_create(pfile, args, queue_args); - if (ret >= 0) { - args->group_handle = ret; - ret = 0; - } + if (ret < 0) + goto out; + args->group_handle = ret; + ret = 0; +out: kvfree(queue_args); return ret; } @@ -1400,14 +1401,9 @@ panthor_open(struct drm_device *ddev, struct drm_file *file) struct panthor_file *pfile; int ret; - if (!try_module_get(THIS_MODULE)) - return -EINVAL; - pfile = kzalloc(sizeof(*pfile), GFP_KERNEL); - if (!pfile) { - ret = -ENOMEM; - goto err_put_mod; - } + if (!pfile) + return -ENOMEM; pfile->ptdev = ptdev; pfile->user_mmio.offset = DRM_PANTHOR_USER_MMIO_OFFSET; @@ -1439,9 +1435,6 @@ err_destroy_vm_pool: err_free_file: kfree(pfile); - -err_put_mod: - module_put(THIS_MODULE); return ret; } @@ -1454,7 +1447,6 @@ panthor_postclose(struct drm_device *ddev, struct drm_file *file) panthor_vm_pool_destroy(pfile); kfree(pfile); - module_put(THIS_MODULE); } static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = { @@ -1555,6 +1547,7 @@ static void panthor_show_fdinfo(struct drm_printer *p, struct drm_file *file) } static const struct file_operations panthor_drm_driver_fops = { + .owner = THIS_MODULE, .open = drm_open, .release = drm_release, .unlocked_ioctl = drm_ioctl, diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 8f17394cc82a..ba5dc3e443d9 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -641,6 +641,15 @@ struct panthor_group { size_t kbo_sizes; } fdinfo; + /** @task_info: Info of current->group_leader that created the group. */ + struct { + /** @task_info.pid: pid of current->group_leader */ + pid_t pid; + + /** @task_info.comm: comm of current->group_leader */ + char comm[TASK_COMM_LEN]; + } task_info; + /** @state: Group state. */ enum panthor_group_state state; @@ -1355,8 +1364,12 @@ cs_slot_process_fatal_event_locked(struct panthor_device *ptdev, fatal = cs_iface->output->fatal; info = cs_iface->output->fatal_info; - if (group) + if (group) { + drm_warn(&ptdev->base, "CS_FATAL: pid=%d, comm=%s\n", + group->task_info.pid, group->task_info.comm); + group->fatal_queues |= BIT(cs_id); + } if (CS_EXCEPTION_TYPE(fatal) == DRM_PANTHOR_EXCEPTION_CS_UNRECOVERABLE) { /* If this exception is unrecoverable, queue a reset, and make @@ -1416,6 +1429,11 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev, spin_unlock(&queue->fence_ctx.lock); } + if (group) { + drm_warn(&ptdev->base, "CS_FAULT: pid=%d, comm=%s\n", + group->task_info.pid, group->task_info.comm); + } + drm_warn(&ptdev->base, "CSG slot %d CS slot: %d\n" "CS_FAULT.EXCEPTION_TYPE: 0x%x (%s)\n" @@ -1632,11 +1650,15 @@ csg_slot_process_progress_timer_event_locked(struct panthor_device *ptdev, u32 c lockdep_assert_held(&sched->lock); - drm_warn(&ptdev->base, "CSG slot %d progress timeout\n", csg_id); - group = csg_slot->group; - if (!drm_WARN_ON(&ptdev->base, !group)) + if (!drm_WARN_ON(&ptdev->base, !group)) { + drm_warn(&ptdev->base, "CSG_PROGRESS_TIMER_EVENT: pid=%d, comm=%s\n", + group->task_info.pid, group->task_info.comm); + group->timedout = true; + } + + drm_warn(&ptdev->base, "CSG slot %d progress timeout\n", csg_id); sched_queue_delayed_work(sched, tick, 0); } @@ -3218,7 +3240,8 @@ queue_timedout_job(struct drm_sched_job *sched_job) struct panthor_scheduler *sched = ptdev->scheduler; struct panthor_queue *queue = group->queues[job->queue_idx]; - drm_warn(&ptdev->base, "job timeout\n"); + drm_warn(&ptdev->base, "job timeout: pid=%d, comm=%s, seqno=%llu\n", + group->task_info.pid, group->task_info.comm, job->done_fence->seqno); drm_WARN_ON(&ptdev->base, atomic_read(&sched->reset.in_progress)); @@ -3389,6 +3412,14 @@ err_free_queue: return ERR_PTR(ret); } +static void group_init_task_info(struct panthor_group *group) +{ + struct task_struct *task = current->group_leader; + + group->task_info.pid = task->pid; + get_task_comm(group->task_info.comm, task); +} + static void add_group_kbo_sizes(struct panthor_device *ptdev, struct panthor_group *group) { @@ -3540,6 +3571,8 @@ int panthor_group_create(struct panthor_file *pfile, add_group_kbo_sizes(group->ptdev, group); spin_lock_init(&group->fdinfo.lock); + group_init_task_info(group); + return gid; err_put_group: diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c index e2cda28a1af4..5a550fd76bf0 100644 --- a/drivers/gpu/drm/scheduler/sched_main.c +++ b/drivers/gpu/drm/scheduler/sched_main.c @@ -349,37 +349,16 @@ static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched) } /** - * __drm_sched_run_free_queue - enqueue free-job work + * drm_sched_run_free_queue - enqueue free-job work * @sched: scheduler instance */ -static void __drm_sched_run_free_queue(struct drm_gpu_scheduler *sched) +static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched) { if (!READ_ONCE(sched->pause_submit)) queue_work(sched->submit_wq, &sched->work_free_job); } /** - * drm_sched_run_free_queue - enqueue free-job work if ready - * @sched: scheduler instance - */ -static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched) -{ - struct drm_sched_job *job; - - job = list_first_entry_or_null(&sched->pending_list, - struct drm_sched_job, list); - if (job && dma_fence_is_signaled(&job->s_fence->finished)) - __drm_sched_run_free_queue(sched); -} - -static void drm_sched_run_free_queue_unlocked(struct drm_gpu_scheduler *sched) -{ - spin_lock(&sched->job_list_lock); - drm_sched_run_free_queue(sched); - spin_unlock(&sched->job_list_lock); -} - -/** * drm_sched_job_done - complete a job * @s_job: pointer to the job which is done * @@ -398,7 +377,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result) dma_fence_get(&s_fence->finished); drm_sched_fence_finished(s_fence, result); dma_fence_put(&s_fence->finished); - __drm_sched_run_free_queue(sched); + drm_sched_run_free_queue(sched); } /** @@ -1134,12 +1113,16 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched) * drm_sched_get_finished_job - fetch the next finished job to be destroyed * * @sched: scheduler instance + * @have_more: are there more finished jobs on the list + * + * Informs the caller through @have_more whether there are more finished jobs + * besides the returned one. * * Returns the next finished job from the pending list (if there is one) * ready for it to be destroyed. */ static struct drm_sched_job * -drm_sched_get_finished_job(struct drm_gpu_scheduler *sched) +drm_sched_get_finished_job(struct drm_gpu_scheduler *sched, bool *have_more) { struct drm_sched_job *job, *next; @@ -1147,22 +1130,25 @@ drm_sched_get_finished_job(struct drm_gpu_scheduler *sched) job = list_first_entry_or_null(&sched->pending_list, struct drm_sched_job, list); - if (job && dma_fence_is_signaled(&job->s_fence->finished)) { /* remove job from pending_list */ list_del_init(&job->list); /* cancel this job's TO timer */ cancel_delayed_work(&sched->work_tdr); - /* make the scheduled timestamp more accurate */ + + *have_more = false; next = list_first_entry_or_null(&sched->pending_list, typeof(*next), list); - if (next) { + /* make the scheduled timestamp more accurate */ if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &next->s_fence->scheduled.flags)) next->s_fence->scheduled.timestamp = dma_fence_timestamp(&job->s_fence->finished); + + *have_more = dma_fence_is_signaled(&next->s_fence->finished); + /* start TO timer for next job */ drm_sched_start_timeout(sched); } @@ -1221,12 +1207,15 @@ static void drm_sched_free_job_work(struct work_struct *w) struct drm_gpu_scheduler *sched = container_of(w, struct drm_gpu_scheduler, work_free_job); struct drm_sched_job *job; + bool have_more; - job = drm_sched_get_finished_job(sched); - if (job) + job = drm_sched_get_finished_job(sched, &have_more); + if (job) { sched->ops->free_job(job); + if (have_more) + drm_sched_run_free_queue(sched); + } - drm_sched_run_free_queue_unlocked(sched); drm_sched_run_job_queue(sched); } diff --git a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c index 65acffc3fea8..8e9ae7d980eb 100644 --- a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c +++ b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c @@ -219,7 +219,7 @@ mock_sched_timedout_job(struct drm_sched_job *sched_job) unsigned long flags; if (job->flags & DRM_MOCK_SCHED_JOB_DONT_RESET) { - job->flags &= ~DRM_MOCK_SCHED_JOB_DONT_RESET; + job->flags |= DRM_MOCK_SCHED_JOB_RESET_SKIPPED; return DRM_GPU_SCHED_STAT_NO_HANG; } diff --git a/drivers/gpu/drm/scheduler/tests/sched_tests.h b/drivers/gpu/drm/scheduler/tests/sched_tests.h index 63d4f2ac7074..5b262126b776 100644 --- a/drivers/gpu/drm/scheduler/tests/sched_tests.h +++ b/drivers/gpu/drm/scheduler/tests/sched_tests.h @@ -95,9 +95,10 @@ struct drm_mock_sched_job { struct completion done; -#define DRM_MOCK_SCHED_JOB_DONE 0x1 -#define DRM_MOCK_SCHED_JOB_TIMEDOUT 0x2 -#define DRM_MOCK_SCHED_JOB_DONT_RESET 0x4 +#define DRM_MOCK_SCHED_JOB_DONE 0x1 +#define DRM_MOCK_SCHED_JOB_TIMEDOUT 0x2 +#define DRM_MOCK_SCHED_JOB_DONT_RESET 0x4 +#define DRM_MOCK_SCHED_JOB_RESET_SKIPPED 0x8 unsigned long flags; struct list_head link; diff --git a/drivers/gpu/drm/scheduler/tests/tests_basic.c b/drivers/gpu/drm/scheduler/tests/tests_basic.c index 55eb142bd7c5..82a41a456b0a 100644 --- a/drivers/gpu/drm/scheduler/tests/tests_basic.c +++ b/drivers/gpu/drm/scheduler/tests/tests_basic.c @@ -317,8 +317,8 @@ static void drm_sched_skip_reset(struct kunit *test) KUNIT_ASSERT_FALSE(test, done); KUNIT_ASSERT_EQ(test, - job->flags & DRM_MOCK_SCHED_JOB_DONT_RESET, - 0); + job->flags & DRM_MOCK_SCHED_JOB_RESET_SKIPPED, + DRM_MOCK_SCHED_JOB_RESET_SKIPPED); i = drm_mock_sched_advance(sched, 1); KUNIT_ASSERT_EQ(test, i, 1); diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 5e997ae8bc9c..2def155ce496 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -46,6 +46,7 @@ MODULE_PARM_DESC(super_pages, "Enable/Disable Super Pages support."); static int v3d_get_param_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct v3d_file_priv *v3d_priv = file_priv->driver_priv; struct v3d_dev *v3d = to_v3d_dev(dev); struct drm_v3d_get_param *args = data; static const u32 reg_map[] = { @@ -107,6 +108,16 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES: args->value = !!v3d->gemfs; return 0; + case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER: + mutex_lock(&v3d->reset_lock); + args->value = v3d->reset_counter; + mutex_unlock(&v3d->reset_lock); + return 0; + case DRM_V3D_PARAM_CONTEXT_RESET_COUNTER: + mutex_lock(&v3d->reset_lock); + args->value = v3d_priv->reset_counter; + mutex_unlock(&v3d->reset_lock); + return 0; default: DRM_DEBUG("Unknown parameter %d\n", args->param); return -EINVAL; diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 411e47702f8a..82d84a96235f 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -204,6 +204,11 @@ struct v3d_dev { * all jobs. */ struct v3d_perfmon *global_perfmon; + + /* Global reset counter. The counter must be incremented when + * a GPU reset happens. It must be protected by @reset_lock. + */ + unsigned int reset_counter; }; static inline struct v3d_dev * @@ -233,6 +238,12 @@ struct v3d_file_priv { /* Stores the GPU stats for a specific queue for this fd. */ struct v3d_stats stats[V3D_MAX_QUEUES]; + + /* Per-fd reset counter, must be incremented when a job submitted + * by this fd causes a GPU reset. It must be protected by + * &struct v3d_dev->reset_lock. + */ + unsigned int reset_counter; }; struct v3d_bo { diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index cb9df8822472..f9d9a198d718 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -721,6 +721,8 @@ v3d_cache_clean_job_run(struct drm_sched_job *sched_job) static enum drm_gpu_sched_stat v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) { + struct v3d_job *job = to_v3d_job(sched_job); + struct v3d_file_priv *v3d_priv = job->file->driver_priv; enum v3d_queue q; mutex_lock(&v3d->reset_lock); @@ -735,6 +737,9 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) /* get the GPU back into the init state */ v3d_reset(v3d); + v3d->reset_counter++; + v3d_priv->reset_counter++; + for (q = 0; q < V3D_MAX_QUEUES; q++) drm_sched_resubmit_jobs(&v3d->queue[q].sched); diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 8d7ca0cdd79f..2ee3749e2b28 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -77,9 +77,22 @@ int vkms_output_init(struct vkms_device *vkmsdev) return ret; } + encoder_cfg->encoder->possible_clones |= + drm_encoder_mask(encoder_cfg->encoder); + vkms_config_encoder_for_each_possible_crtc(encoder_cfg, idx, possible_crtc) { encoder_cfg->encoder->possible_crtcs |= drm_crtc_mask(&possible_crtc->crtc->crtc); + + if (vkms_config_crtc_get_writeback(possible_crtc)) { + struct drm_encoder *wb_encoder = + &possible_crtc->crtc->wb_encoder; + + encoder_cfg->encoder->possible_clones |= + drm_encoder_mask(wb_encoder); + wb_encoder->possible_clones |= + drm_encoder_mask(encoder_cfg->encoder); + } } } diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index fe163271d5b5..45d69a3b85f6 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -174,6 +174,8 @@ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, if (ret) return ret; vkms_output->wb_encoder.possible_crtcs |= drm_crtc_mask(&vkms_output->crtc); + vkms_output->wb_encoder.possible_clones |= + drm_encoder_mask(&vkms_output->wb_encoder); drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index c2294abbe753..00be92da5509 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -538,7 +538,7 @@ static void vmw_event_fence_action_seq_passed(struct dma_fence *f, if (likely(eaction->tv_sec != NULL)) { struct timespec64 ts; - ktime_to_timespec64(f->timestamp); + ts = ktime_to_timespec64(f->timestamp); /* monotonic time, so no y2038 overflow */ *eaction->tv_sec = ts.tv_sec; *eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC; |