blob: 67fac51d4771e0ddc345dcf357e03426b2af54d3 [file]
/* SPDX-License-Identifier: GPL-2.0-only
*
* MIPI-DSI based Samsung common panel driver header
*
* Copyright (c) 2019 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _PANEL_SAMSUNG_DRV_
#define _PANEL_SAMSUNG_DRV_
#include <linux/printk.h>
#include <linux/bits.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/backlight.h>
#include <drm/drm_bridge.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_property.h>
#include <drm/drm_mipi_dsi.h>
#include "../exynos_drm_connector.h"
#define MAX_REGULATORS 3
#define MAX_HDR_FORMATS 4
#define MAX_BL_RANGES 10
#define MAX_TE2_TYPE 10
#define HDR_DOLBY_VISION BIT(1)
#define HDR_HDR10 BIT(2)
#define HDR_HLG BIT(3)
#define BL_STATE_STANDBY BL_CORE_FBBLANK
#define BL_STATE_LP BIT(30) /* backlight is in LP mode */
#define DEFAULT_GAMMA_STR "default"
#define PANEL_REV_PROTO1 BIT(0)
#define PANEL_REV_PROTO1_1 BIT(1)
#define PANEL_REV_PROTO1_2 BIT(2)
#define PANEL_REV_EVT1 BIT(3)
#define PANEL_REV_EVT1_1 BIT(4)
#define PANEL_REV_EVT1_2 BIT(5)
#define PANEL_REV_DVT1 BIT(6)
#define PANEL_REV_DVT1_1 BIT(7)
#define PANEL_REV_PVT BIT(8)
#define PANEL_REV_LATEST BIT(31)
#define PANEL_REV_ALL (~0)
#define PANEL_REV_GE(rev) (~((rev) - 1))
#define PANEL_REV_LT(rev) ((rev) - 1)
#define PANEL_REV_ALL_BUT(rev) (PANEL_REV_ALL & ~(rev))
/* indicates that all commands in this cmd set should be batched together */
#define PANEL_CMD_SET_BATCH BIT(0)
/*
* indicates that all commands in this cmd set should be queued, a follow up
* command should take care of triggering transfer of batch
*/
#define PANEL_CMD_SET_QUEUE BIT(1)
/* packetgo feature to batch msgs can wait for vblank, use this flag to ignore explicitly */
#define PANEL_CMD_SET_IGNORE_VBLANK BIT(2)
#define HBM_FLAG_GHBM_UPDATE BIT(0)
#define HBM_FLAG_BL_UPDATE BIT(1)
#define HBM_FLAG_LHBM_UPDATE BIT(2)
#define HBM_FLAG_DIMMING_UPDATE BIT(3)
#define IS_HBM_ON(mode) ((mode) >= HBM_ON_IRC_ON && (mode) < HBM_STATE_MAX)
#define IS_HBM_ON_IRC_OFF(mode) (((mode) == HBM_ON_IRC_OFF))
/**
* enum exynos_panel_state - panel operating state
* @PANEL_STATE_UNINITIALIZED: Panel has never been initialized, and panel OTP info such as
* panel serial and revision has not been read yet
* @PANEL_STATE_HANDOFF: Panel looked active when driver was loaded. The panel is uninitialized
* in this state and will switch to PANEL_STATE_ON once it gets initialized
* @PANEL_STATE_OFF: Panel is fully disabled and powered off
* @PANEL_STATE_NORMAL: Panel is ON in Normal operating mode
* @PANEL_STATE_LP: Panel is ON in Low Power mode
* @PANEL_STATE_BLANK: Panel is ON but no contents are shown on display
*/
enum exynos_panel_state {
PANEL_STATE_UNINITIALIZED,
PANEL_STATE_HANDOFF,
PANEL_STATE_OFF,
PANEL_STATE_NORMAL,
PANEL_STATE_LP,
PANEL_STATE_BLANK,
};
/**
* enum exynos_panel_idle_mode - type of idle mode supported per mode
* @IDLE_MODE_UNSUPPORTED: No idle mode is supported in this mode
* @IDLE_MODE_ON_INACTIVITY: In this mode the panel can go into idle automatically
* after last frame update
* @IDLE_MODE_ON_SELF_REFRESH: Manually go into lower idle mode when display enters
* self refresh state
*/
enum exynos_panel_idle_mode {
IDLE_MODE_UNSUPPORTED,
IDLE_MODE_ON_INACTIVITY,
IDLE_MODE_ON_SELF_REFRESH,
};
struct exynos_panel;
struct exynos_panel_te2_timing {
/* @rising_edge: vertical start point */
u16 rising_edge;
/* @falling_edge: vertical end point */
u16 falling_edge;
};
/**
* struct exynos_panel_mode - panel mode info
*/
struct exynos_panel_mode {
/* @mode: drm display mode info */
struct drm_display_mode mode;
/* @exynos_mode: exynos driver specific mode info */
struct exynos_display_mode exynos_mode;
/* @priv_data: per mode panel driver private data */
const void *priv_data;
/* @te2_timing: TE2 signal timing */
struct exynos_panel_te2_timing te2_timing;
/*
* @idle_mode:
*
* Indicates whether going into lower refresh rate is allowed while in this mode, and what
* type of idle mode is supported, for more info refer to enum exynos_panel_idle_mode.
*/
enum exynos_panel_idle_mode idle_mode;
};
struct exynos_panel_funcs {
/**
* @set_brightness:
*
* This callback is used to implement driver specific logic for brightness
* configuration. Otherwise defaults to sending brightness commands through
* dcs command update
*/
int (*set_brightness)(struct exynos_panel *exynos_panel, u16 br);
/**
* @set_lp_mode:
*
* This callback is used to handle command sequences to enter low power modes.
*/
void (*set_lp_mode)(struct exynos_panel *exynos_panel,
const struct exynos_panel_mode *mode);
/**
* @set_nolp_mode:
*
* This callback is used to handle command sequences to exit from low power
* modes.
*/
void (*set_nolp_mode)(struct exynos_panel *exynos_panel,
const struct exynos_panel_mode *mode);
/**
* @set_binned_lp:
*
* This callback is used to handle additional command sequences for low power
* modes based on different brightness threshold.
*/
void (*set_binned_lp)(struct exynos_panel *exynos_panel, u16 br);
/**
* @set_hbm_mode:
*
* This callback is used to implement panel specific logic for high brightness
* mode enablement. If this is not defined, it means that panel does not
* support HBM
*/
void (*set_hbm_mode)(struct exynos_panel *exynos_panel, enum exynos_hbm_mode mode);
/**
* @set_dimming_on:
*
* This callback is used to implement panel specific logic for dimming mode
* enablement. If this is not defined, it means that panel does not support
* dimmimg.
*/
void (*set_dimming_on)(struct exynos_panel *exynos_panel,
bool dimming_on);
/**
* @set_local_hbm_mode:
*
* This callback is used to implement panel specific logic for local high
* brightness mode enablement. If this is not defined, it means that panel
* does not support local HBM
*/
void (*set_local_hbm_mode)(struct exynos_panel *exynos_panel,
bool local_hbm_en);
/**
* @set_power:
*
* This callback is used to implement panel specific power on/off sequence.
*/
int (*set_power)(struct exynos_panel *exynos_panel, bool enable);
/**
* @is_mode_seamless:
*
* This callback is used to check if a switch to a particular mode can be done
* seamlessly without full mode set given the current hardware configuration
*/
bool (*is_mode_seamless)(const struct exynos_panel *exynos_panel,
const struct exynos_panel_mode *mode);
/**
* @mode_set:
*
* This callback is used to perform driver specific logic for mode_set.
* This could be called while display is on or off, should check internal
* state to perform appropriate mode set configuration depending on this state.
*/
void (*mode_set)(struct exynos_panel *exynos_panel,
const struct exynos_panel_mode *mode);
/**
* @panel_init:
*
* This callback is used to do one time initialization for any panel
* specific functions.
*/
void (*panel_init)(struct exynos_panel *exynos_panel);
/**
* @panel_reset:
*
* This callback is used to allow panel to toggle only reset pin instead of full
* prepare sequence (including power rails) while the device is in BLANK state.
* This is not called in any other state.
*/
void (*panel_reset)(struct exynos_panel *exynos_panel);
/**
* @print_gamma:
*
* This callback is used to print the hex dump of gamma address/data
* for the provided mode.
*
* The expected format:
* [gamma address]: [gamma data...]
*/
void (*print_gamma)(struct seq_file *seq,
const struct drm_display_mode *mode);
/**
* @gamma_store:
*
* This callback is used to store the user-provided gamma table.
* The user-provided table should include FPS, register, register
* data size and gamma data.
*
* The expected format:
* [FPS1]
* [register1]
* [register1 data size]
* [gamma data]
* [register2]
* [register2 data size]
* [gamma data]
* [FPS2]
* [register1]
* .....
*/
ssize_t (*gamma_store)(struct exynos_panel *exynos_panel,
const char *buf, size_t len);
/**
* @restore_native_gamma
*
* This callback is used to replace current gamma table by the
* original gamma.
*/
ssize_t (*restore_native_gamma)(struct exynos_panel *exynos_panel);
/**
* @get_panel_rev:
*
* This callback is used to get panel HW revision from panel_extinfo.
*/
void (*get_panel_rev)(struct exynos_panel *exynos_panel, u32 id);
/**
* @read_id:
*
* This callback is used to read panel id.
*/
int (*read_id)(struct exynos_panel *exynos_panel);
/**
* @get_te2_edges:
*
* This callback is used to get the rising and falling edges of TE2 signal.
* The input buf is used to store the results in string.
*/
ssize_t (*get_te2_edges)(struct exynos_panel *exynos_panel,
char *buf, bool lp_mode);
/**
* @configure_te2_edges:
*
* This callback is used to configure the rising and falling edges of TE2
* signal. The input timings include the values we need to configure.
*/
int (*configure_te2_edges)(struct exynos_panel *exynos_panel,
u32 *timings, bool lp_mode);
/**
* @update_te2:
*
* This callback is used to update the TE2 signal via DCS commands.
* This should be called when the display state is changed between
* normal and LP modes, or the refresh rate and LP brightness are
* changed.
*/
void (*update_te2)(struct exynos_panel *exynos_panel);
/**
* @atomic_check
*
* This optional callback happens in atomic check phase, it gives a chance to panel driver
* to check and/or adjust atomic state ahead of atomic commit.
*
* Should return 0 on success (no problems with atomic commit) otherwise negative errno
*/
int (*atomic_check)(struct exynos_panel *exynos_panel, struct drm_atomic_state *state);
/**
* @commit_done
*
* Called after atomic commit flush has completed but transfer may not have started yet
*/
void (*commit_done)(struct exynos_panel *exynos_panel);
/**
* @set_self_refresh
*
* Called when display self refresh state has changed. While in self refresh state, the
* panel can optimize for power assuming that there are no pending updates.
*
* Returns true if underlying mode was updated to reflect new self refresh state,
* otherwise returns false if no action was taken.
*/
bool (*set_self_refresh)(struct exynos_panel *exynos_panel, bool enable);
/**
* @set_op_hz
*
* set display panel working on specified operation rate.
*
* Returns 0 if successfully setting operation rate.
*/
int (*set_op_hz)(struct exynos_panel *exynos_panel, unsigned int hz);
};
/**
* struct exynos_dsi_cmd - information for a dsi command.
* @cmd_len: Length of a dsi command.
* @cmd: Pointer to a dsi command.
* @delay_ms: Delay time after executing this dsi command.
* @panel_rev:Send the command only when the panel revision is matched.
*/
struct exynos_dsi_cmd {
u32 cmd_len;
const u8 *cmd;
u32 delay_ms;
u32 panel_rev;
u8 type;
};
/**
* struct exynos_dsi_cmd_set - a dsi command sequence.
* @num_cmd: Number of dsi commands in this sequence.
* @cmds: Pointer to a dsi command sequence.
*/
struct exynos_dsi_cmd_set {
const u32 num_cmd;
const struct exynos_dsi_cmd *cmds;
};
/**
* struct exynos_binned_lp - information for binned lp mode.
* @name: Name of this binned lp mode.
* @bl_threshold: Max brightness supported by this mode
* @cmd_set: A dsi command sequence to enter this mode.
* @te2_timing: TE2 signal timing.
*/
struct exynos_binned_lp {
const char *name;
u32 bl_threshold;
struct exynos_dsi_cmd_set cmd_set;
struct exynos_panel_te2_timing te2_timing;
};
struct exynos_panel_desc {
const u8 *dsc_pps;
u8 panel_id_reg;
u32 dsc_pps_len;
u32 data_lane_cnt;
u32 hdr_formats; /* supported HDR formats bitmask */
u32 max_luminance;
u32 max_avg_luminance;
u32 min_luminance;
u32 max_brightness;
u32 min_brightness;
u32 dft_brightness; /* default brightness */
bool is_partial;
bool is_panel_idle_supported;
const struct brightness_capability *brt_capability;
const u32 *bl_range;
u32 bl_num_ranges;
const struct exynos_panel_mode *modes;
size_t num_modes;
const struct exynos_dsi_cmd_set *off_cmd_set;
/* @lp_mode: provides a low power mode if available, otherwise null */
const struct exynos_panel_mode *lp_mode;
const size_t lp_mode_count;
const struct exynos_dsi_cmd_set *lp_cmd_set;
const struct exynos_binned_lp *binned_lp;
const size_t num_binned_lp;
const struct drm_panel_funcs *panel_func;
const struct exynos_panel_funcs *exynos_panel_func;
};
#define PANEL_ID_MAX 32
#define PANEL_EXTINFO_MAX 16
#define LOCAL_HBM_MAX_TIMEOUT_MS 3000 /* 3000 ms */
#define LOCAL_HBM_GAMMA_CMD_SIZE_MAX 16
struct exynos_bl_notifier {
u32 ranges[MAX_BL_RANGES];
u32 num_ranges;
u32 current_range;
};
struct te2_mode_data {
/* @mode: normal or LP mode data */
const struct drm_display_mode *mode;
/* @binned_lp: LP mode data */
const struct exynos_binned_lp *binned_lp;
/* @timing: normal or LP mode timing */
struct exynos_panel_te2_timing timing;
};
struct te2_data {
struct te2_mode_data mode_data[MAX_TE2_TYPE];
};
struct exynos_panel {
struct device *dev;
struct drm_panel panel;
struct dentry *debugfs_entry;
struct dentry *debugfs_cmdset_entry;
struct gpio_desc *reset_gpio;
struct gpio_desc *enable_gpio;
struct regulator *vci;
struct regulator *vddi;
struct regulator *vddd;
struct regulator *vddr_en;
struct regulator *vddr;
u32 vddd_normal_uV;
u32 vddd_lp_uV;
struct exynos_drm_connector exynos_connector;
struct drm_bridge bridge;
const struct exynos_panel_desc *desc;
const struct exynos_panel_mode *current_mode;
/* Deprected: please refer to panel_state instead */
bool enabled;
bool initialized;
enum exynos_panel_state panel_state;
/* If true, panel won't be powered off */
bool force_power_on;
/* indicates whether panel idle feature is enabled */
bool panel_idle_enabled;
/* indicates self refresh is active */
bool self_refresh_active;
/**
* refresh rate in panel idle mode
* 0 means not in idle mode or not specified
* greater than 0 means panel idle is active
*/
unsigned int panel_idle_vrefresh;
unsigned int op_hz;
/**
* indicates the lower bound of refresh rate
* 0 means there is no lower bound limitation
* -1 means display should not switch to lower
* refresh rate while idle.
*/
int min_vrefresh;
/**
* When the value is set to non-zero value, the panel
* driver kernel idle timer will be disabled internally
* (similar to writing 0 to panel_idle sysfs node) for
* at least the delay time provided after a refresh rate update.
*/
u32 idle_delay_ms;
enum exynos_hbm_mode hbm_mode;
bool dimming_on;
/* request_dimming_on from drm commit */
bool request_dimming_on;
struct backlight_device *bl;
struct mutex mode_lock;
struct mutex bl_state_lock;
struct exynos_bl_notifier bl_notifier;
struct mutex lp_state_lock;
const struct exynos_binned_lp *current_binned_lp;
struct drm_property_blob *lp_mode_blob;
char panel_id[PANEL_ID_MAX];
char panel_extinfo[PANEL_EXTINFO_MAX];
u32 panel_rev;
enum drm_panel_orientation orientation;
struct device_node *touch_dev;
struct te2_data te2;
ktime_t last_commit_ts;
ktime_t last_mode_set_ts;
ktime_t last_self_refresh_active_ts;
struct delayed_work idle_work;
struct {
struct local_hbm {
bool gamma_para_ready;
u8 gamma_cmd[LOCAL_HBM_GAMMA_CMD_SIZE_MAX];
/* request local hbm mode from atomic_commit */
bool request_hbm_mode;
/* indicate if local hbm enabled or not */
bool enabled;
/* max local hbm on period in ms */
u32 max_timeout_ms;
/* work used to turn off local hbm if reach max_timeout */
struct delayed_work timeout_work;
} local_hbm;
/* request global hbm mode from drm commit */
enum exynos_hbm_mode request_global_hbm_mode;
/* send mipi commands asynchronously after frame start */
struct work_struct hbm_work;
/* mipi command update flags in hbm_work */
u8 update_flags;
struct mutex hbm_work_lock;
struct drm_crtc_commit *commit;
struct workqueue_struct *wq;
} hbm;
};
static inline bool is_panel_active(const struct exynos_panel *ctx)
{
switch (ctx->panel_state) {
case PANEL_STATE_LP:
case PANEL_STATE_NORMAL:
return true;
case PANEL_STATE_UNINITIALIZED:
case PANEL_STATE_HANDOFF:
case PANEL_STATE_BLANK:
case PANEL_STATE_OFF:
default:
return false;
}
}
static inline bool is_panel_initialized(const struct exynos_panel *ctx)
{
return ctx->panel_state != PANEL_STATE_UNINITIALIZED &&
ctx->panel_state != PANEL_STATE_HANDOFF;
}
static inline int exynos_dcs_write(struct exynos_panel *ctx, const void *data,
size_t len)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
return mipi_dsi_dcs_write_buffer(dsi, data, len);
}
static inline int exynos_dcs_compression_mode(struct exynos_panel *ctx, bool enable)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
return mipi_dsi_compression_mode(dsi, enable);
}
static inline int exynos_dcs_set_brightness(struct exynos_panel *ctx, u16 br)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
return mipi_dsi_dcs_set_display_brightness(dsi, br);
}
static inline int exynos_get_actual_vrefresh(struct exynos_panel *ctx)
{
if (ctx->panel_idle_vrefresh)
return ctx->panel_idle_vrefresh;
return drm_mode_vrefresh(&ctx->current_mode->mode);
}
static inline void exynos_bin2hex(const void *buf, size_t len,
char *linebuf, size_t linebuflen)
{
const size_t max_size = (linebuflen - 1) / 2;
const size_t count = min(max_size, len);
char *end;
end = bin2hex(linebuf, buf, count);
*end = '\0';
}
static inline void backlight_state_changed(struct backlight_device *bl)
{
sysfs_notify(&bl->dev.kobj, NULL, "state");
}
#define EXYNOS_DSI_CMD_REV(cmd, delay, rev) { sizeof(cmd), cmd, delay, (u32)rev }
#define EXYNOS_DSI_CMD(cmd, delay) EXYNOS_DSI_CMD_REV(cmd, delay, PANEL_REV_ALL)
#define EXYNOS_DSI_CMD0_REV(cmd, rev) EXYNOS_DSI_CMD_REV(cmd, 0, rev)
#define EXYNOS_DSI_CMD0(cmd) EXYNOS_DSI_CMD(cmd, 0)
#define EXYNOS_DSI_CMD_SEQ_DELAY_REV(rev, delay, seq...) \
EXYNOS_DSI_CMD_REV(((const u8 []){seq}), delay, rev)
#define EXYNOS_DSI_CMD_SEQ_DELAY(delay, seq...) \
EXYNOS_DSI_CMD_SEQ_DELAY_REV(PANEL_REV_ALL, delay, seq)
#define EXYNOS_DSI_CMD_SEQ_REV(rev, seq...) \
EXYNOS_DSI_CMD_SEQ_DELAY_REV(rev, 0, seq)
#define EXYNOS_DSI_CMD_SEQ(seq...) EXYNOS_DSI_CMD_SEQ_DELAY(0, seq)
#define DEFINE_EXYNOS_CMD_SET(name) \
const struct exynos_dsi_cmd_set name ## _cmd_set = { \
.num_cmd = ARRAY_SIZE(name ## _cmds), .cmds = name ## _cmds }
#define BINNED_LP_MODE(mode_name, bl_thr, cmdset) \
{ \
.name = mode_name, \
.bl_threshold = bl_thr, \
{ .num_cmd = ARRAY_SIZE(cmdset), \
.cmds = cmdset }, \
{ .rising_edge = 0, \
.falling_edge = 0 } \
}
#define BINNED_LP_MODE_TIMING(mode_name, bl_thr, cmdset, rising, falling) \
{ \
.name = mode_name, \
.bl_threshold = bl_thr, \
{ .num_cmd = ARRAY_SIZE(cmdset), \
.cmds = cmdset }, \
{ .rising_edge = rising, \
.falling_edge = falling } \
}
#define EXYNOS_DCS_WRITE_PRINT_ERR(ctx, cmd, len, ret) do { \
dev_err(ctx->dev, "failed to write cmd (%d)\n", ret); \
print_hex_dump(KERN_ERR, "command: ", \
DUMP_PREFIX_NONE, 16, 1, cmd, len, false); \
} while (0)
#define EXYNOS_DCS_WRITE_SEQ(ctx, seq...) do { \
u8 d[] = { seq }; \
int ret; \
ret = exynos_dcs_write(ctx, d, ARRAY_SIZE(d)); \
if (ret < 0) \
EXYNOS_DCS_WRITE_PRINT_ERR(ctx, d, ARRAY_SIZE(d), ret); \
} while (0)
#define EXYNOS_DCS_WRITE_SEQ_FLAGS(ctx, flags, seq...) do { \
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); \
u8 d[] = { seq }; \
int ret; \
ret = exynos_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d), flags); \
if (ret < 0) \
EXYNOS_DCS_WRITE_PRINT_ERR(ctx, d, ARRAY_SIZE(d), ret); \
} while (0)
#define EXYNOS_DCS_WRITE_SEQ_DELAY(ctx, delay, seq...) do { \
EXYNOS_DCS_WRITE_SEQ(ctx, seq); \
usleep_range(delay * 1000, delay * 1000 + 10); \
} while (0)
#define EXYNOS_DCS_WRITE_TABLE(ctx, table) do { \
int ret; \
ret = exynos_dcs_write(ctx, table, ARRAY_SIZE(table)); \
if (ret < 0) \
EXYNOS_DCS_WRITE_PRINT_ERR(ctx, table, ARRAY_SIZE(table), ret); \
} while (0)
#define EXYNOS_DCS_WRITE_TABLE_FLAGS(ctx, table, flags) do { \
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); \
int ret; \
ret = exynos_dsi_dcs_write_buffer(dsi, table, ARRAY_SIZE(table), flags); \
if (ret < 0) \
EXYNOS_DCS_WRITE_PRINT_ERR(ctx, table, ARRAY_SIZE(table), ret); \
} while (0)
#define EXYNOS_DCS_WRITE_TABLE_DELAY(ctx, delay, table) do { \
EXYNOS_DCS_WRITE_TABLE(ctx, table); \
usleep_range(delay * 1000, delay * 1000 + 10); \
} while (0)
#define EXYNOS_DCS_BUF_ADD(ctx, seq...) \
EXYNOS_DCS_WRITE_SEQ_FLAGS(ctx, 0, seq)
#define EXYNOS_DCS_BUF_ADD_SET(ctx, set) \
EXYNOS_DCS_WRITE_TABLE_FLAGS(ctx, set, 0)
#define EXYNOS_DCS_BUF_ADD_AND_FLUSH(ctx, seq...) \
EXYNOS_DCS_WRITE_SEQ_FLAGS(ctx, MIPI_DSI_MSG_LASTCOMMAND, seq)
#define EXYNOS_DCS_BUF_ADD_SET_AND_FLUSH(ctx, set) \
EXYNOS_DCS_WRITE_TABLE_FLAGS(ctx, set, MIPI_DSI_MSG_LASTCOMMAND)
#define DSC_PPS_SIZE sizeof(struct drm_dsc_picture_parameter_set)
#define EXYNOS_PPS_WRITE_BUF(ctx, payload) do { \
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); \
int ret; \
ret = mipi_dsi_picture_parameter_set(dsi, \
(struct drm_dsc_picture_parameter_set *)(payload)); \
if (ret < 0) \
dev_err(ctx->dev, "failed to write pps(%d)\n", ret); \
} while (0)
#define EXYNOS_PPS_LONG_WRITE(ctx) EXYNOS_PPS_WRITE_BUF(ctx, ctx->desc->dsc_pps)
#define for_each_display_mode(i, mode, ctx) \
for (i = 0, mode = &ctx->desc->modes[i].mode; \
i < ctx->desc->num_modes; i++, \
mode = &ctx->desc->modes[i].mode) \
#define for_each_exynos_binned_lp(i, binned_lp, ctx) \
for (i = 0, binned_lp = &ctx->desc->binned_lp[i]; \
i < ctx->desc->num_binned_lp; i++, \
binned_lp = &ctx->desc->binned_lp[i]) \
#define for_each_te2_timing(ctx, lp_mode, data, i) \
for (data = ctx->te2.mode_data + (!(lp_mode) ? 0 : (ctx)->desc->num_modes), \
i = !(lp_mode) ? (ctx)->desc->num_modes : (ctx)->desc->num_binned_lp - 1; \
i > 0; \
i--, data++) \
unsigned int panel_get_idle_time_delta(struct exynos_panel *ctx);
int exynos_panel_configure_te2_edges(struct exynos_panel *ctx,
u32 *timings, bool lp_mode);
ssize_t exynos_panel_get_te2_edges(struct exynos_panel *ctx,
char *buf, bool lp_mode);
int exynos_panel_get_current_mode_te2(struct exynos_panel *ctx,
struct exynos_panel_te2_timing *timing);
int exynos_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector);
int exynos_panel_disable(struct drm_panel *panel);
int exynos_panel_unprepare(struct drm_panel *panel);
int exynos_panel_prepare(struct drm_panel *panel);
void exynos_panel_get_panel_rev(struct exynos_panel *ctx, u8 rev);
int exynos_panel_init(struct exynos_panel *ctx);
void exynos_panel_reset(struct exynos_panel *ctx);
int exynos_panel_set_power(struct exynos_panel *ctx, bool on);
int exynos_panel_set_brightness(struct exynos_panel *exynos_panel, u16 br);
void exynos_panel_debugfs_create_cmdset(struct exynos_panel *ctx,
struct dentry *parent,
const struct exynos_dsi_cmd_set *cmdset,
const char *name);
void exynos_panel_send_cmd_set_flags(struct exynos_panel *ctx, const struct exynos_dsi_cmd_set *cmd_set,
u32 flags);
static inline void exynos_panel_send_cmd_set(struct exynos_panel *ctx,
const struct exynos_dsi_cmd_set *cmd_set)
{
exynos_panel_send_cmd_set_flags(ctx, cmd_set, 0);
}
void exynos_panel_set_lp_mode(struct exynos_panel *ctx, const struct exynos_panel_mode *pmode);
void exynos_panel_set_binned_lp(struct exynos_panel *ctx, const u16 brightness);
int exynos_panel_common_init(struct mipi_dsi_device *dsi,
struct exynos_panel *ctx);
ssize_t exynos_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
const void *data, size_t len, u16 flags);
int exynos_panel_probe(struct mipi_dsi_device *dsi);
int exynos_panel_remove(struct mipi_dsi_device *dsi);
#endif /* _PANEL_SAMSUNG_DRV_ */