2019-06-04 08:11:33 +00:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2013-12-04 15:35:12 +00:00
|
|
|
/*
|
|
|
|
* MIPI DSI Bus
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
|
|
|
|
* Andrzej Hajda <a.hajda@samsung.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __DRM_MIPI_DSI_H__
|
|
|
|
#define __DRM_MIPI_DSI_H__
|
|
|
|
|
|
|
|
#include <linux/device.h>
|
|
|
|
|
|
|
|
struct mipi_dsi_host;
|
|
|
|
struct mipi_dsi_device;
|
2019-10-28 15:00:47 +00:00
|
|
|
struct drm_dsc_picture_parameter_set;
|
2013-12-04 15:35:12 +00:00
|
|
|
|
2014-03-28 11:52:36 +00:00
|
|
|
/* request ACK from peripheral */
|
|
|
|
#define MIPI_DSI_MSG_REQ_ACK BIT(0)
|
|
|
|
/* use Low Power Mode to transmit message */
|
|
|
|
#define MIPI_DSI_MSG_USE_LPM BIT(1)
|
|
|
|
|
2013-12-04 15:35:12 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_msg - read/write DSI buffer
|
|
|
|
* @channel: virtual channel id
|
|
|
|
* @type: payload data type
|
2014-08-05 08:41:13 +00:00
|
|
|
* @flags: flags controlling this message transmission
|
2013-12-04 15:35:12 +00:00
|
|
|
* @tx_len: length of @tx_buf
|
|
|
|
* @tx_buf: data to be written
|
|
|
|
* @rx_len: length of @rx_buf
|
|
|
|
* @rx_buf: data to be read, or NULL
|
|
|
|
*/
|
|
|
|
struct mipi_dsi_msg {
|
|
|
|
u8 channel;
|
|
|
|
u8 type;
|
2014-03-28 11:52:36 +00:00
|
|
|
u16 flags;
|
2013-12-04 15:35:12 +00:00
|
|
|
|
|
|
|
size_t tx_len;
|
|
|
|
const void *tx_buf;
|
|
|
|
|
|
|
|
size_t rx_len;
|
|
|
|
void *rx_buf;
|
|
|
|
};
|
|
|
|
|
2014-11-04 13:59:14 +00:00
|
|
|
bool mipi_dsi_packet_format_is_short(u8 type);
|
|
|
|
bool mipi_dsi_packet_format_is_long(u8 type);
|
|
|
|
|
2014-10-16 11:44:02 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format
|
|
|
|
* @size: size (in bytes) of the packet
|
|
|
|
* @header: the four bytes that make up the header (Data ID, Word Count or
|
|
|
|
* Packet Data, and ECC)
|
|
|
|
* @payload_length: number of bytes in the payload
|
|
|
|
* @payload: a pointer to a buffer containing the payload, if any
|
|
|
|
*/
|
|
|
|
struct mipi_dsi_packet {
|
|
|
|
size_t size;
|
|
|
|
u8 header[4];
|
|
|
|
size_t payload_length;
|
|
|
|
const u8 *payload;
|
|
|
|
};
|
|
|
|
|
|
|
|
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
|
|
|
const struct mipi_dsi_msg *msg);
|
|
|
|
|
2013-12-04 15:35:12 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_host_ops - DSI bus operations
|
|
|
|
* @attach: attach DSI device to DSI host
|
|
|
|
* @detach: detach DSI device from DSI host
|
2014-08-05 08:41:13 +00:00
|
|
|
* @transfer: transmit a DSI packet
|
|
|
|
*
|
|
|
|
* DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
|
|
|
|
* structures. This structure contains information about the type of packet
|
|
|
|
* being transmitted as well as the transmit and receive buffers. When an
|
|
|
|
* error is encountered during transmission, this function will return a
|
|
|
|
* negative error code. On success it shall return the number of bytes
|
|
|
|
* transmitted for write packets or the number of bytes received for read
|
|
|
|
* packets.
|
|
|
|
*
|
|
|
|
* Note that typically DSI packet transmission is atomic, so the .transfer()
|
|
|
|
* function will seldomly return anything other than the number of bytes
|
|
|
|
* contained in the transmit buffer on success.
|
2021-06-16 14:15:29 +00:00
|
|
|
*
|
|
|
|
* Also note that those callbacks can be called no matter the state the
|
|
|
|
* host is in. Drivers that need the underlying device to be powered to
|
|
|
|
* perform these operations will first need to make sure it's been
|
|
|
|
* properly enabled.
|
2013-12-04 15:35:12 +00:00
|
|
|
*/
|
|
|
|
struct mipi_dsi_host_ops {
|
|
|
|
int (*attach)(struct mipi_dsi_host *host,
|
|
|
|
struct mipi_dsi_device *dsi);
|
|
|
|
int (*detach)(struct mipi_dsi_host *host,
|
|
|
|
struct mipi_dsi_device *dsi);
|
|
|
|
ssize_t (*transfer)(struct mipi_dsi_host *host,
|
2014-08-05 09:27:56 +00:00
|
|
|
const struct mipi_dsi_msg *msg);
|
2013-12-04 15:35:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* struct mipi_dsi_host - DSI host device
|
|
|
|
* @dev: driver model device node for this DSI host
|
|
|
|
* @ops: DSI host operations
|
2016-02-12 09:18:34 +00:00
|
|
|
* @list: list management
|
2013-12-04 15:35:12 +00:00
|
|
|
*/
|
|
|
|
struct mipi_dsi_host {
|
|
|
|
struct device *dev;
|
|
|
|
const struct mipi_dsi_host_ops *ops;
|
2016-02-12 09:18:34 +00:00
|
|
|
struct list_head list;
|
2013-12-04 15:35:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
int mipi_dsi_host_register(struct mipi_dsi_host *host);
|
|
|
|
void mipi_dsi_host_unregister(struct mipi_dsi_host *host);
|
2016-02-12 09:18:34 +00:00
|
|
|
struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node);
|
2013-12-04 15:35:12 +00:00
|
|
|
|
|
|
|
/* DSI mode flags */
|
|
|
|
|
|
|
|
/* video mode */
|
|
|
|
#define MIPI_DSI_MODE_VIDEO BIT(0)
|
|
|
|
/* video burst mode */
|
|
|
|
#define MIPI_DSI_MODE_VIDEO_BURST BIT(1)
|
|
|
|
/* video pulse mode */
|
|
|
|
#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2)
|
|
|
|
/* enable auto vertical count mode */
|
|
|
|
#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3)
|
|
|
|
/* enable hsync-end packets in vsync-pulse and v-porch area */
|
|
|
|
#define MIPI_DSI_MODE_VIDEO_HSE BIT(4)
|
|
|
|
/* disable hfront-porch area */
|
2021-07-27 01:45:21 +00:00
|
|
|
#define MIPI_DSI_MODE_VIDEO_NO_HFP BIT(5)
|
2013-12-04 15:35:12 +00:00
|
|
|
/* disable hback-porch area */
|
2021-07-27 01:45:21 +00:00
|
|
|
#define MIPI_DSI_MODE_VIDEO_NO_HBP BIT(6)
|
2013-12-04 15:35:12 +00:00
|
|
|
/* disable hsync-active area */
|
2021-07-27 01:45:21 +00:00
|
|
|
#define MIPI_DSI_MODE_VIDEO_NO_HSA BIT(7)
|
2013-12-04 15:35:12 +00:00
|
|
|
/* flush display FIFO on vsync pulse */
|
|
|
|
#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
|
|
|
/* disable EoT packets in HS mode */
|
2021-07-27 01:45:21 +00:00
|
|
|
#define MIPI_DSI_MODE_NO_EOT_PACKET BIT(9)
|
2014-07-08 12:32:11 +00:00
|
|
|
/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
|
|
|
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
|
2014-08-13 07:38:23 +00:00
|
|
|
/* transmit data in low power */
|
|
|
|
#define MIPI_DSI_MODE_LPM BIT(11)
|
2022-03-09 07:36:35 +00:00
|
|
|
/* transmit data ending at the same time for all lanes within one hsync */
|
|
|
|
#define MIPI_DSI_HS_PKT_END_ALIGNED BIT(12)
|
2013-12-04 15:35:12 +00:00
|
|
|
|
|
|
|
enum mipi_dsi_pixel_format {
|
|
|
|
MIPI_DSI_FMT_RGB888,
|
|
|
|
MIPI_DSI_FMT_RGB666,
|
|
|
|
MIPI_DSI_FMT_RGB666_PACKED,
|
|
|
|
MIPI_DSI_FMT_RGB565,
|
|
|
|
};
|
|
|
|
|
2016-02-12 09:18:32 +00:00
|
|
|
#define DSI_DEV_NAME_SIZE 20
|
|
|
|
|
|
|
|
/**
|
2016-02-12 09:18:31 +00:00
|
|
|
* struct mipi_dsi_device_info - template for creating a mipi_dsi_device
|
2016-02-12 09:18:32 +00:00
|
|
|
* @type: DSI peripheral chip type
|
2016-02-12 09:18:31 +00:00
|
|
|
* @channel: DSI virtual channel assigned to peripheral
|
2016-02-12 09:18:32 +00:00
|
|
|
* @node: pointer to OF device node or NULL
|
2016-02-12 09:18:31 +00:00
|
|
|
*
|
|
|
|
* This is populated and passed to mipi_dsi_device_new to create a new
|
|
|
|
* DSI device
|
|
|
|
*/
|
|
|
|
struct mipi_dsi_device_info {
|
2016-02-12 09:18:32 +00:00
|
|
|
char type[DSI_DEV_NAME_SIZE];
|
2016-02-12 09:18:31 +00:00
|
|
|
u32 channel;
|
|
|
|
struct device_node *node;
|
|
|
|
};
|
|
|
|
|
2013-12-04 15:35:12 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_device - DSI peripheral device
|
|
|
|
* @host: DSI host for this peripheral
|
|
|
|
* @dev: driver model device node for this peripheral
|
drm/mipi-dsi: Fix detach call without attach
It's been reported that DSI host driver's detach can be called without
the attach ever happening:
https://lore.kernel.org/all/20230412073954.20601-1-tony@atomide.com/
After reading the code, I think this is what happens:
We have a DSI host defined in the device tree and a DSI peripheral under
that host (i.e. an i2c device using the DSI as data bus doesn't exhibit
this behavior).
The host driver calls mipi_dsi_host_register(), which causes (via a few
functions) mipi_dsi_device_add() to be called for the DSI peripheral. So
now we have a DSI device under the host, but attach hasn't been called.
Normally the probing of the devices continues, and eventually the DSI
peripheral's driver will call mipi_dsi_attach(), attaching the
peripheral.
However, if the host driver's probe encounters an error after calling
mipi_dsi_host_register(), and before the peripheral has called
mipi_dsi_attach(), the host driver will do cleanups and return an error
from its probe function. The cleanups include calling
mipi_dsi_host_unregister().
mipi_dsi_host_unregister() will call two functions for all its DSI
peripheral devices: mipi_dsi_detach() and mipi_dsi_device_unregister().
The latter makes sense, as the device exists, but the former may be
wrong as attach has not necessarily been done.
To fix this, track the attached state of the peripheral, and only detach
from mipi_dsi_host_unregister() if the peripheral was attached.
Note that I have only tested this with a board with an i2c DSI
peripheral, not with a "pure" DSI peripheral.
However, slightly related, the unregister machinery still seems broken.
E.g. if the DSI host driver is unbound, it'll detach and unregister the
DSI peripherals. After that, when the DSI peripheral driver unbound
it'll call detach either directly or using the devm variant, leading to
a crash. And probably the driver will crash if it happens, for some
reason, to try to send a message via the DSI bus.
But that's another topic.
Tested-by: H. Nikolaus Schaller <hns@goldelico.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230921-dsi-detach-fix-v1-1-d0de2d1621d9@ideasonboard.com
2023-09-21 10:50:32 +00:00
|
|
|
* @attached: the DSI device has been successfully attached
|
2016-02-12 09:18:32 +00:00
|
|
|
* @name: DSI peripheral chip type
|
2013-12-04 15:35:12 +00:00
|
|
|
* @channel: virtual channel assigned to the peripheral
|
|
|
|
* @format: pixel format for video mode
|
|
|
|
* @lanes: number of active data lanes
|
|
|
|
* @mode_flags: DSI operation mode related flags
|
2018-10-23 07:24:22 +00:00
|
|
|
* @hs_rate: maximum lane frequency for high speed mode in hertz, this should
|
|
|
|
* be set to the real limits of the hardware, zero is only accepted for
|
|
|
|
* legacy drivers
|
|
|
|
* @lp_rate: maximum lane frequency for low power mode in hertz, this should
|
|
|
|
* be set to the real limits of the hardware, zero is only accepted for
|
|
|
|
* legacy drivers
|
2022-07-11 09:43:17 +00:00
|
|
|
* @dsc: panel/bridge DSC pps payload to be sent
|
2013-12-04 15:35:12 +00:00
|
|
|
*/
|
|
|
|
struct mipi_dsi_device {
|
|
|
|
struct mipi_dsi_host *host;
|
|
|
|
struct device dev;
|
drm/mipi-dsi: Fix detach call without attach
It's been reported that DSI host driver's detach can be called without
the attach ever happening:
https://lore.kernel.org/all/20230412073954.20601-1-tony@atomide.com/
After reading the code, I think this is what happens:
We have a DSI host defined in the device tree and a DSI peripheral under
that host (i.e. an i2c device using the DSI as data bus doesn't exhibit
this behavior).
The host driver calls mipi_dsi_host_register(), which causes (via a few
functions) mipi_dsi_device_add() to be called for the DSI peripheral. So
now we have a DSI device under the host, but attach hasn't been called.
Normally the probing of the devices continues, and eventually the DSI
peripheral's driver will call mipi_dsi_attach(), attaching the
peripheral.
However, if the host driver's probe encounters an error after calling
mipi_dsi_host_register(), and before the peripheral has called
mipi_dsi_attach(), the host driver will do cleanups and return an error
from its probe function. The cleanups include calling
mipi_dsi_host_unregister().
mipi_dsi_host_unregister() will call two functions for all its DSI
peripheral devices: mipi_dsi_detach() and mipi_dsi_device_unregister().
The latter makes sense, as the device exists, but the former may be
wrong as attach has not necessarily been done.
To fix this, track the attached state of the peripheral, and only detach
from mipi_dsi_host_unregister() if the peripheral was attached.
Note that I have only tested this with a board with an i2c DSI
peripheral, not with a "pure" DSI peripheral.
However, slightly related, the unregister machinery still seems broken.
E.g. if the DSI host driver is unbound, it'll detach and unregister the
DSI peripherals. After that, when the DSI peripheral driver unbound
it'll call detach either directly or using the devm variant, leading to
a crash. And probably the driver will crash if it happens, for some
reason, to try to send a message via the DSI bus.
But that's another topic.
Tested-by: H. Nikolaus Schaller <hns@goldelico.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230921-dsi-detach-fix-v1-1-d0de2d1621d9@ideasonboard.com
2023-09-21 10:50:32 +00:00
|
|
|
bool attached;
|
2013-12-04 15:35:12 +00:00
|
|
|
|
2016-02-12 09:18:32 +00:00
|
|
|
char name[DSI_DEV_NAME_SIZE];
|
2013-12-04 15:35:12 +00:00
|
|
|
unsigned int channel;
|
|
|
|
unsigned int lanes;
|
|
|
|
enum mipi_dsi_pixel_format format;
|
|
|
|
unsigned long mode_flags;
|
2018-10-23 07:24:22 +00:00
|
|
|
unsigned long hs_rate;
|
|
|
|
unsigned long lp_rate;
|
2022-07-11 09:43:17 +00:00
|
|
|
struct drm_dsc_config *dsc;
|
2013-12-04 15:35:12 +00:00
|
|
|
};
|
|
|
|
|
2024-05-14 17:20:55 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_multi_context - Context to call multiple MIPI DSI funcs in a row
|
|
|
|
*/
|
|
|
|
struct mipi_dsi_multi_context {
|
|
|
|
/**
|
|
|
|
* @dsi: Pointer to the MIPI DSI device
|
|
|
|
*/
|
|
|
|
struct mipi_dsi_device *dsi;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @accum_err: Storage for the accumulated error over the multiple calls
|
|
|
|
*
|
|
|
|
* Init to 0. If a function encounters an error then the error code
|
|
|
|
* will be stored here. If you call a function and this points to a
|
|
|
|
* non-zero value then the function will be a noop. This allows calling
|
|
|
|
* a function many times in a row and just checking the error at the
|
|
|
|
* end to see if any of them failed.
|
|
|
|
*/
|
|
|
|
int accum_err;
|
|
|
|
};
|
|
|
|
|
2016-06-03 12:23:00 +00:00
|
|
|
#define MIPI_DSI_MODULE_PREFIX "mipi-dsi:"
|
|
|
|
|
2023-01-11 11:30:14 +00:00
|
|
|
#define to_mipi_dsi_device(__dev) container_of_const(__dev, struct mipi_dsi_device, dev)
|
2013-12-04 15:35:12 +00:00
|
|
|
|
2015-11-20 08:15:30 +00:00
|
|
|
/**
|
|
|
|
* mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
|
|
|
|
* given pixel format defined by the MIPI DSI
|
|
|
|
* specification
|
|
|
|
* @fmt: MIPI DSI pixel format
|
|
|
|
*
|
|
|
|
* Returns: The number of bits per pixel of the given pixel format.
|
|
|
|
*/
|
|
|
|
static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
|
|
|
|
{
|
|
|
|
switch (fmt) {
|
|
|
|
case MIPI_DSI_FMT_RGB888:
|
|
|
|
case MIPI_DSI_FMT_RGB666:
|
|
|
|
return 24;
|
|
|
|
|
|
|
|
case MIPI_DSI_FMT_RGB666_PACKED:
|
|
|
|
return 18;
|
|
|
|
|
|
|
|
case MIPI_DSI_FMT_RGB565:
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2024-04-07 23:53:52 +00:00
|
|
|
enum mipi_dsi_compression_algo {
|
|
|
|
MIPI_DSI_COMPRESSION_DSC = 0,
|
|
|
|
MIPI_DSI_COMPRESSION_VENDOR = 3,
|
|
|
|
/* other two values are reserved, DSI 1.3 */
|
|
|
|
};
|
|
|
|
|
2016-02-12 09:18:31 +00:00
|
|
|
struct mipi_dsi_device *
|
|
|
|
mipi_dsi_device_register_full(struct mipi_dsi_host *host,
|
|
|
|
const struct mipi_dsi_device_info *info);
|
2016-02-12 09:18:33 +00:00
|
|
|
void mipi_dsi_device_unregister(struct mipi_dsi_device *dsi);
|
2021-09-10 10:11:57 +00:00
|
|
|
struct mipi_dsi_device *
|
|
|
|
devm_mipi_dsi_device_register_full(struct device *dev, struct mipi_dsi_host *host,
|
|
|
|
const struct mipi_dsi_device_info *info);
|
2014-08-06 06:53:39 +00:00
|
|
|
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
|
2013-12-04 15:35:12 +00:00
|
|
|
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
2021-09-10 10:11:58 +00:00
|
|
|
int devm_mipi_dsi_attach(struct device *dev, struct mipi_dsi_device *dsi);
|
2015-10-31 00:38:26 +00:00
|
|
|
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
|
2014-08-05 07:27:15 +00:00
|
|
|
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
|
|
|
u16 value);
|
2024-04-07 23:53:51 +00:00
|
|
|
int mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable);
|
2024-04-07 23:53:52 +00:00
|
|
|
int mipi_dsi_compression_mode_ext(struct mipi_dsi_device *dsi, bool enable,
|
|
|
|
enum mipi_dsi_compression_algo algo,
|
|
|
|
unsigned int pps_selector);
|
2024-04-07 23:53:51 +00:00
|
|
|
int mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi,
|
|
|
|
const struct drm_dsc_picture_parameter_set *pps);
|
2014-08-05 08:36:21 +00:00
|
|
|
|
2024-05-11 23:00:19 +00:00
|
|
|
void mipi_dsi_compression_mode_ext_multi(struct mipi_dsi_multi_context *ctx,
|
|
|
|
bool enable,
|
|
|
|
enum mipi_dsi_compression_algo algo,
|
|
|
|
unsigned int pps_selector);
|
|
|
|
void mipi_dsi_picture_parameter_set_multi(struct mipi_dsi_multi_context *ctx,
|
|
|
|
const struct drm_dsc_picture_parameter_set *pps);
|
|
|
|
|
2014-08-05 08:36:21 +00:00
|
|
|
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
|
|
|
size_t size);
|
2024-05-14 17:20:54 +00:00
|
|
|
int mipi_dsi_generic_write_chatty(struct mipi_dsi_device *dsi,
|
|
|
|
const void *payload, size_t size);
|
2024-05-14 17:20:55 +00:00
|
|
|
void mipi_dsi_generic_write_multi(struct mipi_dsi_multi_context *ctx,
|
|
|
|
const void *payload, size_t size);
|
2014-08-05 08:36:21 +00:00
|
|
|
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
|
|
|
size_t num_params, void *data, size_t size);
|
|
|
|
|
2024-05-11 23:00:19 +00:00
|
|
|
#define mipi_dsi_msleep(ctx, delay) \
|
|
|
|
do { \
|
2024-06-12 13:35:43 +00:00
|
|
|
if (!(ctx)->accum_err) \
|
2024-05-11 23:00:19 +00:00
|
|
|
msleep(delay); \
|
|
|
|
} while (0)
|
|
|
|
|
2014-08-05 08:38:31 +00:00
|
|
|
/**
|
|
|
|
* enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
|
|
|
|
* @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
|
|
|
|
* information only
|
|
|
|
* @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
|
|
|
|
* V-Blanking and H-Blanking information
|
|
|
|
*/
|
|
|
|
enum mipi_dsi_dcs_tear_mode {
|
|
|
|
MIPI_DSI_DCS_TEAR_MODE_VBLANK,
|
|
|
|
MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
|
|
|
|
};
|
|
|
|
|
2014-08-05 09:17:06 +00:00
|
|
|
#define MIPI_DSI_DCS_POWER_MODE_DISPLAY (1 << 2)
|
|
|
|
#define MIPI_DSI_DCS_POWER_MODE_NORMAL (1 << 3)
|
|
|
|
#define MIPI_DSI_DCS_POWER_MODE_SLEEP (1 << 4)
|
|
|
|
#define MIPI_DSI_DCS_POWER_MODE_PARTIAL (1 << 5)
|
|
|
|
#define MIPI_DSI_DCS_POWER_MODE_IDLE (1 << 6)
|
|
|
|
|
2014-07-21 13:47:10 +00:00
|
|
|
ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
|
|
|
const void *data, size_t len);
|
2024-05-14 17:20:54 +00:00
|
|
|
int mipi_dsi_dcs_write_buffer_chatty(struct mipi_dsi_device *dsi,
|
|
|
|
const void *data, size_t len);
|
2024-05-14 17:20:55 +00:00
|
|
|
void mipi_dsi_dcs_write_buffer_multi(struct mipi_dsi_multi_context *ctx,
|
|
|
|
const void *data, size_t len);
|
2014-07-21 13:47:10 +00:00
|
|
|
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
|
|
|
const void *data, size_t len);
|
2014-07-21 10:28:25 +00:00
|
|
|
ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
|
|
|
size_t len);
|
2014-08-05 09:14:02 +00:00
|
|
|
int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi);
|
2014-08-05 09:15:15 +00:00
|
|
|
int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi);
|
2014-08-05 09:17:06 +00:00
|
|
|
int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode);
|
2014-08-05 09:18:46 +00:00
|
|
|
int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format);
|
2014-08-05 08:38:31 +00:00
|
|
|
int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
|
2014-08-05 09:20:25 +00:00
|
|
|
int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
|
|
|
|
u16 end);
|
|
|
|
int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
|
|
|
|
u16 end);
|
2014-08-05 08:38:31 +00:00
|
|
|
int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi);
|
|
|
|
int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
|
|
|
|
enum mipi_dsi_dcs_tear_mode mode);
|
2014-08-05 09:18:46 +00:00
|
|
|
int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
|
2016-08-24 11:28:39 +00:00
|
|
|
int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
|
2016-07-31 15:15:22 +00:00
|
|
|
int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
|
|
|
u16 brightness);
|
|
|
|
int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
|
|
|
u16 *brightness);
|
2023-01-16 22:49:07 +00:00
|
|
|
int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi,
|
|
|
|
u16 brightness);
|
|
|
|
int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi,
|
|
|
|
u16 *brightness);
|
2013-12-04 15:35:12 +00:00
|
|
|
|
2024-05-11 23:00:19 +00:00
|
|
|
void mipi_dsi_dcs_nop_multi(struct mipi_dsi_multi_context *ctx);
|
|
|
|
void mipi_dsi_dcs_enter_sleep_mode_multi(struct mipi_dsi_multi_context *ctx);
|
|
|
|
void mipi_dsi_dcs_exit_sleep_mode_multi(struct mipi_dsi_multi_context *ctx);
|
|
|
|
void mipi_dsi_dcs_set_display_off_multi(struct mipi_dsi_multi_context *ctx);
|
|
|
|
void mipi_dsi_dcs_set_display_on_multi(struct mipi_dsi_multi_context *ctx);
|
|
|
|
void mipi_dsi_dcs_set_tear_on_multi(struct mipi_dsi_multi_context *ctx,
|
|
|
|
enum mipi_dsi_dcs_tear_mode mode);
|
|
|
|
|
2023-01-02 20:25:42 +00:00
|
|
|
/**
|
|
|
|
* mipi_dsi_generic_write_seq - transmit data using a generic write packet
|
2024-05-14 17:20:54 +00:00
|
|
|
*
|
|
|
|
* This macro will print errors for you and will RETURN FROM THE CALLING
|
|
|
|
* FUNCTION (yes this is non-intuitive) upon error.
|
|
|
|
*
|
2024-05-14 17:20:55 +00:00
|
|
|
* Because of the non-intuitive return behavior, THIS MACRO IS DEPRECATED.
|
|
|
|
* Please replace calls of it with mipi_dsi_generic_write_seq_multi().
|
|
|
|
*
|
2023-01-02 20:25:42 +00:00
|
|
|
* @dsi: DSI peripheral device
|
|
|
|
* @seq: buffer containing the payload
|
|
|
|
*/
|
2024-05-14 17:20:54 +00:00
|
|
|
#define mipi_dsi_generic_write_seq(dsi, seq...) \
|
|
|
|
do { \
|
|
|
|
static const u8 d[] = { seq }; \
|
|
|
|
int ret; \
|
|
|
|
ret = mipi_dsi_generic_write_chatty(dsi, d, ARRAY_SIZE(d)); \
|
|
|
|
if (ret < 0) \
|
|
|
|
return ret; \
|
2023-01-02 20:25:42 +00:00
|
|
|
} while (0)
|
|
|
|
|
2024-05-14 17:20:55 +00:00
|
|
|
/**
|
|
|
|
* mipi_dsi_generic_write_seq_multi - transmit data using a generic write packet
|
|
|
|
*
|
|
|
|
* This macro will print errors for you and error handling is optimized for
|
|
|
|
* callers that call this multiple times in a row.
|
|
|
|
*
|
|
|
|
* @ctx: Context for multiple DSI transactions
|
|
|
|
* @seq: buffer containing the payload
|
|
|
|
*/
|
|
|
|
#define mipi_dsi_generic_write_seq_multi(ctx, seq...) \
|
|
|
|
do { \
|
|
|
|
static const u8 d[] = { seq }; \
|
|
|
|
mipi_dsi_generic_write_multi(ctx, d, ARRAY_SIZE(d)); \
|
|
|
|
} while (0)
|
|
|
|
|
2022-06-01 08:24:09 +00:00
|
|
|
/**
|
|
|
|
* mipi_dsi_dcs_write_seq - transmit a DCS command with payload
|
2024-05-14 17:20:54 +00:00
|
|
|
*
|
|
|
|
* This macro will print errors for you and will RETURN FROM THE CALLING
|
|
|
|
* FUNCTION (yes this is non-intuitive) upon error.
|
|
|
|
*
|
2024-05-14 17:20:55 +00:00
|
|
|
* Because of the non-intuitive return behavior, THIS MACRO IS DEPRECATED.
|
|
|
|
* Please replace calls of it with mipi_dsi_dcs_write_seq_multi().
|
|
|
|
*
|
2022-06-01 08:24:09 +00:00
|
|
|
* @dsi: DSI peripheral device
|
|
|
|
* @cmd: Command
|
|
|
|
* @seq: buffer containing data to be transmitted
|
|
|
|
*/
|
2024-05-14 17:20:54 +00:00
|
|
|
#define mipi_dsi_dcs_write_seq(dsi, cmd, seq...) \
|
|
|
|
do { \
|
|
|
|
static const u8 d[] = { cmd, seq }; \
|
|
|
|
int ret; \
|
|
|
|
ret = mipi_dsi_dcs_write_buffer_chatty(dsi, d, ARRAY_SIZE(d)); \
|
|
|
|
if (ret < 0) \
|
|
|
|
return ret; \
|
2022-06-01 08:24:09 +00:00
|
|
|
} while (0)
|
|
|
|
|
2024-05-14 17:20:55 +00:00
|
|
|
/**
|
|
|
|
* mipi_dsi_dcs_write_seq_multi - transmit a DCS command with payload
|
|
|
|
*
|
|
|
|
* This macro will print errors for you and error handling is optimized for
|
|
|
|
* callers that call this multiple times in a row.
|
|
|
|
*
|
|
|
|
* @ctx: Context for multiple DSI transactions
|
|
|
|
* @cmd: Command
|
|
|
|
* @seq: buffer containing data to be transmitted
|
|
|
|
*/
|
|
|
|
#define mipi_dsi_dcs_write_seq_multi(ctx, cmd, seq...) \
|
|
|
|
do { \
|
|
|
|
static const u8 d[] = { cmd, seq }; \
|
|
|
|
mipi_dsi_dcs_write_buffer_multi(ctx, d, ARRAY_SIZE(d)); \
|
|
|
|
} while (0)
|
|
|
|
|
2013-12-04 15:35:12 +00:00
|
|
|
/**
|
|
|
|
* struct mipi_dsi_driver - DSI driver
|
|
|
|
* @driver: device driver model driver
|
|
|
|
* @probe: callback for device binding
|
|
|
|
* @remove: callback for device unbinding
|
2014-04-29 15:19:57 +00:00
|
|
|
* @shutdown: called at shutdown time to quiesce the device
|
2013-12-04 15:35:12 +00:00
|
|
|
*/
|
|
|
|
struct mipi_dsi_driver {
|
|
|
|
struct device_driver driver;
|
|
|
|
int(*probe)(struct mipi_dsi_device *dsi);
|
2022-07-08 09:49:22 +00:00
|
|
|
void (*remove)(struct mipi_dsi_device *dsi);
|
2014-04-29 15:19:57 +00:00
|
|
|
void (*shutdown)(struct mipi_dsi_device *dsi);
|
2013-12-04 15:35:12 +00:00
|
|
|
};
|
|
|
|
|
2014-08-05 07:01:32 +00:00
|
|
|
static inline struct mipi_dsi_driver *
|
|
|
|
to_mipi_dsi_driver(struct device_driver *driver)
|
|
|
|
{
|
|
|
|
return container_of(driver, struct mipi_dsi_driver, driver);
|
|
|
|
}
|
2013-12-04 15:35:12 +00:00
|
|
|
|
|
|
|
static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi)
|
|
|
|
{
|
|
|
|
return dev_get_drvdata(&dsi->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dsi, void *data)
|
|
|
|
{
|
|
|
|
dev_set_drvdata(&dsi->dev, data);
|
|
|
|
}
|
|
|
|
|
2014-11-04 15:09:56 +00:00
|
|
|
int mipi_dsi_driver_register_full(struct mipi_dsi_driver *driver,
|
|
|
|
struct module *owner);
|
2013-12-04 15:35:12 +00:00
|
|
|
void mipi_dsi_driver_unregister(struct mipi_dsi_driver *driver);
|
|
|
|
|
2014-11-04 15:09:56 +00:00
|
|
|
#define mipi_dsi_driver_register(driver) \
|
|
|
|
mipi_dsi_driver_register_full(driver, THIS_MODULE)
|
|
|
|
|
2013-12-04 15:35:12 +00:00
|
|
|
#define module_mipi_dsi_driver(__mipi_dsi_driver) \
|
|
|
|
module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
|
|
|
|
mipi_dsi_driver_unregister)
|
|
|
|
|
|
|
|
#endif /* __DRM_MIPI_DSI__ */
|