video/drm: Sync MIPI DSI Bus helper from Linux 4.9
This imports drivers/gpu/drm/drm_mipi_dsi.c from Linux kernel 4.9. It can be very helpful when porting Linux mipi dsi driver to U-Boot. DSI hosts expose operations which can be used by DSI peripheral drivers to access associated devices. Change-Id: Iccfa9d946f33458867f4d4db0ce04aeb1918e855 Signed-off-by: Wyon Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
parent
c5bb939d42
commit
1953e61947
|
|
@ -13,7 +13,8 @@ menuconfig DRM_ROCKCHIP
|
|||
|
||||
config DRM_ROCKCHIP_PANEL
|
||||
bool "Rockchip Panel Support"
|
||||
select DRM_ROCKCHIP_MIPI_DSI
|
||||
depends on DRM_ROCKCHIP
|
||||
select DRM_MIPI_DSI
|
||||
|
||||
config DRM_ROCKCHIP_DW_HDMI
|
||||
bool "Rockchip specific extensions for Synopsys DW HDMI"
|
||||
|
|
@ -52,13 +53,14 @@ config DRM_ROCKCHIP_INNO_VIDEO_COMBO_PHY
|
|||
Enable this to support the Rockchip MIPI/LVDS/TTL PHY
|
||||
with Innosilicon IP block.
|
||||
|
||||
config DRM_ROCKCHIP_MIPI_DSI
|
||||
config DRM_MIPI_DSI
|
||||
bool
|
||||
depends on DRM_ROCKCHIP
|
||||
|
||||
config DRM_ROCKCHIP_DW_MIPI_DSI
|
||||
tristate "Rockchip specific extensions for Synopsys DW MIPI DSI"
|
||||
depends on DRM_ROCKCHIP
|
||||
select DRM_ROCKCHIP_MIPI_DSI
|
||||
select DRM_MIPI_DSI
|
||||
select DRM_ROCKCHIP_PANEL
|
||||
help
|
||||
This selects support for Rockchip SoC specific extensions
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
obj-y += rockchip_display.o rockchip_crtc.o rockchip_phy.o rockchip_bridge.o \
|
||||
rockchip_vop.o rockchip_vop_reg.o bmp_helper.o
|
||||
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_MIPI_DSI) += rockchip_mipi_dsi.o
|
||||
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_DW_MIPI_DSI) += dw_mipi_dsi.o
|
||||
obj-$(CONFIG_DRM_ROCKCHIP_DW_HDMI) += rockchip_dw_hdmi.o dw_hdmi.o
|
||||
obj-$(CONFIG_ROCKCHIP_INNO_HDMI_PHY) += rockchip-inno-hdmi-phy.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,744 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* MIPI DSI Bus
|
||||
*
|
||||
* Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
|
||||
* Andrzej Hajda <a.hajda@samsung.com>
|
||||
*/
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
|
||||
/**
|
||||
* mipi_dsi_attach - attach a DSI device to its DSI host
|
||||
* @dsi: DSI peripheral
|
||||
*/
|
||||
int mipi_dsi_attach(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
|
||||
if (!ops || !ops->attach)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->attach(dsi->host, dsi);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_detach - detach a DSI device from its DSI host
|
||||
* @dsi: DSI peripheral
|
||||
*/
|
||||
int mipi_dsi_detach(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
|
||||
if (!ops || !ops->detach)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->detach(dsi->host, dsi);
|
||||
}
|
||||
|
||||
static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi,
|
||||
struct mipi_dsi_msg *msg)
|
||||
{
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
|
||||
if (!ops || !ops->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
|
||||
msg->flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
return ops->transfer(dsi->host, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_packet_format_is_short - check if a packet is of the short format
|
||||
* @type: MIPI DSI data type of the packet
|
||||
*
|
||||
* Return: true if the packet for the given data type is a short packet, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool mipi_dsi_packet_format_is_short(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_V_SYNC_START:
|
||||
case MIPI_DSI_V_SYNC_END:
|
||||
case MIPI_DSI_H_SYNC_START:
|
||||
case MIPI_DSI_H_SYNC_END:
|
||||
case MIPI_DSI_END_OF_TRANSMISSION:
|
||||
case MIPI_DSI_COLOR_MODE_OFF:
|
||||
case MIPI_DSI_COLOR_MODE_ON:
|
||||
case MIPI_DSI_SHUTDOWN_PERIPHERAL:
|
||||
case MIPI_DSI_TURN_ON_PERIPHERAL:
|
||||
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_READ_REQUEST_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_DCS_READ:
|
||||
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_packet_format_is_long - check if a packet is of the long format
|
||||
* @type: MIPI DSI data type of the packet
|
||||
*
|
||||
* Return: true if the packet for the given data type is a long packet, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool mipi_dsi_packet_format_is_long(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_NULL_PACKET:
|
||||
case MIPI_DSI_BLANKING_PACKET:
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_30:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_36:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_18:
|
||||
case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_24:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_create_packet - create a packet from a message according to the
|
||||
* DSI protocol
|
||||
* @packet: pointer to a DSI packet structure
|
||||
* @msg: message to translate into a packet
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
if (!packet || !msg)
|
||||
return -EINVAL;
|
||||
|
||||
/* do some minimum sanity checking */
|
||||
if (!mipi_dsi_packet_format_is_short(msg->type) &&
|
||||
!mipi_dsi_packet_format_is_long(msg->type))
|
||||
return -EINVAL;
|
||||
|
||||
if (msg->channel > 3)
|
||||
return -EINVAL;
|
||||
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
|
||||
if (mipi_dsi_packet_format_is_long(msg->type)) {
|
||||
packet->header[1] = (msg->tx_len >> 0) & 0xff;
|
||||
packet->header[2] = (msg->tx_len >> 8) & 0xff;
|
||||
|
||||
packet->payload_length = msg->tx_len;
|
||||
packet->payload = msg->tx_buf;
|
||||
} else {
|
||||
const u8 *tx = msg->tx_buf;
|
||||
|
||||
packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
|
||||
packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
|
||||
}
|
||||
|
||||
packet->size = sizeof(packet->header) + packet->payload_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_shutdown_peripheral() - sends a Shutdown Peripheral command
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
|
||||
.tx_buf = (u8 [2]) { 0, 0 },
|
||||
.tx_len = 2,
|
||||
};
|
||||
int ret = mipi_dsi_device_transfer(dsi, &msg);
|
||||
|
||||
return (ret < 0) ? ret : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_turn_on_peripheral() - sends a Turn On Peripheral command
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_TURN_ON_PERIPHERAL,
|
||||
.tx_buf = (u8 [2]) { 0, 0 },
|
||||
.tx_len = 2,
|
||||
};
|
||||
int ret = mipi_dsi_device_transfer(dsi, &msg);
|
||||
|
||||
return (ret < 0) ? ret : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
|
||||
* the payload in a long packet transmitted from the peripheral back to the
|
||||
* host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @value: the maximum size of the payload
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
||||
u16 value)
|
||||
{
|
||||
u8 tx[2] = { value & 0xff, value >> 8 };
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
|
||||
.tx_len = sizeof(tx),
|
||||
.tx_buf = tx,
|
||||
};
|
||||
int ret = mipi_dsi_device_transfer(dsi, &msg);
|
||||
|
||||
return (ret < 0) ? ret : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_generic_write() - transmit data using a generic write packet
|
||||
* @dsi: DSI peripheral device
|
||||
* @payload: buffer containing the payload
|
||||
* @size: size of payload buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the payload length.
|
||||
*
|
||||
* Return: The number of bytes transmitted on success or a negative error code
|
||||
* on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
||||
size_t size)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_buf = payload,
|
||||
.tx_len = size
|
||||
};
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
|
||||
break;
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
|
||||
break;
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
|
||||
break;
|
||||
default:
|
||||
msg.type = MIPI_DSI_GENERIC_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_generic_read() - receive data using a generic read packet
|
||||
* @dsi: DSI peripheral device
|
||||
* @params: buffer containing the request parameters
|
||||
* @num_params: number of request parameters
|
||||
* @data: buffer in which to return the received data
|
||||
* @size: size of receive buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the number of parameters passed in.
|
||||
*
|
||||
* Return: The number of bytes successfully read or a negative error code on
|
||||
* failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
||||
size_t num_params, void *data, size_t size)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_len = num_params,
|
||||
.tx_buf = params,
|
||||
.rx_len = size,
|
||||
.rx_buf = data
|
||||
};
|
||||
|
||||
switch (num_params) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload
|
||||
* @dsi: DSI peripheral device
|
||||
* @data: buffer containing data to be transmitted
|
||||
* @len: size of transmission buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the command payload length.
|
||||
*
|
||||
* Return: The number of bytes successfully transmitted or a negative error
|
||||
* code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_buf = data,
|
||||
.tx_len = len
|
||||
};
|
||||
|
||||
switch (len) {
|
||||
case 0:
|
||||
return -EINVAL;
|
||||
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg.type = MIPI_DSI_DCS_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_write() - send DCS write command
|
||||
* @dsi: DSI peripheral device
|
||||
* @cmd: DCS command
|
||||
* @data: buffer containing the command payload
|
||||
* @len: command payload length
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the command payload length.
|
||||
*
|
||||
* Return: The number of bytes successfully transmitted or a negative error
|
||||
* code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
ssize_t err;
|
||||
size_t size;
|
||||
u8 *tx;
|
||||
|
||||
if (len > 0) {
|
||||
size = 1 + len;
|
||||
|
||||
tx = malloc(size);
|
||||
if (!tx)
|
||||
return -ENOMEM;
|
||||
|
||||
/* concatenate the DCS command byte and the payload */
|
||||
tx[0] = cmd;
|
||||
memcpy(&tx[1], data, len);
|
||||
} else {
|
||||
tx = &cmd;
|
||||
size = 1;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_write_buffer(dsi, tx, size);
|
||||
|
||||
if (len > 0)
|
||||
free(tx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_read() - send DCS read request command
|
||||
* @dsi: DSI peripheral device
|
||||
* @cmd: DCS command
|
||||
* @data: buffer in which to receive data
|
||||
* @len: size of receive buffer
|
||||
* Return: The number of bytes read or a negative error code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
||||
size_t len)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_DCS_READ,
|
||||
.tx_buf = &cmd,
|
||||
.tx_len = 1,
|
||||
.rx_buf = data,
|
||||
.rx_len = len
|
||||
};
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_nop() - send DCS nop packet
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_soft_reset() - perform a software reset of the display module
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_get_power_mode() - query the display module's current power
|
||||
* mode
|
||||
* @dsi: DSI peripheral device
|
||||
* @mode: return location for the current power mode
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode,
|
||||
sizeof(*mode));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image
|
||||
* data used by the interface
|
||||
* @dsi: DSI peripheral device
|
||||
* @format: return location for the pixel format
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format,
|
||||
sizeof(*format));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the
|
||||
* display module except interface communication
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
|
||||
* module
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_display_off() - stop displaying the image data on the
|
||||
* display device
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_display_on() - start displaying the image data on the
|
||||
* display device
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_column_address() - define the column extent of the frame
|
||||
* memory accessed by the host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @start: first column of frame memory
|
||||
* @end: last column of frame memory
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end)
|
||||
{
|
||||
u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
|
||||
sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_page_address() - define the page extent of the frame
|
||||
* memory accessed by the host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @start: first page of frame memory
|
||||
* @end: last page of frame memory
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end)
|
||||
{
|
||||
u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
|
||||
sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect
|
||||
* output signal on the TE signal line
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
|
||||
* output signal on the TE signal line.
|
||||
* @dsi: DSI peripheral device
|
||||
* @mode: the Tearing Effect Output Line mode
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
|
||||
enum mipi_dsi_dcs_tear_mode mode)
|
||||
{
|
||||
u8 value = mode;
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
|
||||
sizeof(value));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
|
||||
* data used by the interface
|
||||
* @dsi: DSI peripheral device
|
||||
* @format: pixel format
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
|
||||
sizeof(format));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for
|
||||
* the Tearing Effect output signal of the display module
|
||||
* @dsi: DSI peripheral device
|
||||
* @scanline: scanline to use as trigger
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline)
|
||||
{
|
||||
u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8,
|
||||
scanline & 0xff };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the
|
||||
* display
|
||||
* @dsi: DSI peripheral device
|
||||
* @brightness: brightness value
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi,
|
||||
u16 brightness)
|
||||
{
|
||||
u8 payload[2] = { brightness & 0xff, brightness >> 8 };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
|
||||
payload, sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_get_display_brightness() - gets the current brightness value
|
||||
* of the display
|
||||
* @dsi: DSI peripheral device
|
||||
* @brightness: brightness value
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi,
|
||||
u16 *brightness)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
|
||||
brightness, sizeof(*brightness));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -15,13 +17,15 @@
|
|||
#include <dm/of_access.h>
|
||||
#include <syscon.h>
|
||||
#include <asm/arch-rockchip/clock.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "rockchip_display.h"
|
||||
#include "rockchip_crtc.h"
|
||||
#include "rockchip_connector.h"
|
||||
#include "rockchip_panel.h"
|
||||
#include "rockchip_phy.h"
|
||||
#include "rockchip_mipi_dsi.h"
|
||||
|
||||
#define UPDATE(v, h, l) (((v) << (l)) & GENMASK((h), (l)))
|
||||
|
||||
#define DSI_VERSION 0x00
|
||||
#define DSI_PWR_UP 0x04
|
||||
|
|
@ -300,7 +304,7 @@ static int genif_wait_w_pld_fifo_not_full(struct dw_mipi_dsi *dsi)
|
|||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
|
||||
sts, !(sts & GEN_PLD_W_FULL), 10,
|
||||
sts, !(sts & GEN_PLD_W_FULL),
|
||||
CMD_PKT_STATUS_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
printf("generic write payload fifo is full\n");
|
||||
|
|
@ -316,7 +320,7 @@ static int genif_wait_cmd_fifo_not_full(struct dw_mipi_dsi *dsi)
|
|||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
|
||||
sts, !(sts & GEN_CMD_FULL), 10,
|
||||
sts, !(sts & GEN_CMD_FULL),
|
||||
CMD_PKT_STATUS_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
printf("generic write cmd fifo is full\n");
|
||||
|
|
@ -334,7 +338,7 @@ static int genif_wait_write_fifo_empty(struct dw_mipi_dsi *dsi)
|
|||
|
||||
mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
|
||||
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
|
||||
sts, (sts & mask) == mask, 10,
|
||||
sts, (sts & mask) == mask,
|
||||
CMD_PKT_STATUS_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
printf("generic write fifo is full\n");
|
||||
|
|
@ -469,8 +473,7 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi)
|
|||
}
|
||||
|
||||
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
|
||||
val, val & PHY_LOCK,
|
||||
1000, PHY_STATUS_TIMEOUT_US);
|
||||
val, val & PHY_LOCK, PHY_STATUS_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
dev_err(dsi->dev, "PHY is not locked\n");
|
||||
return ret;
|
||||
|
|
@ -481,7 +484,7 @@ static int mipi_dphy_power_on(struct dw_mipi_dsi *dsi)
|
|||
mask = PHY_STOPSTATELANE;
|
||||
ret = readl_poll_timeout(dsi->base + DSI_PHY_STATUS,
|
||||
val, (val & mask) == mask,
|
||||
1000, PHY_STATUS_TIMEOUT_US);
|
||||
PHY_STATUS_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
dev_err(dsi->dev, "lane module is not in stop state\n");
|
||||
return ret;
|
||||
|
|
@ -525,7 +528,7 @@ static void dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
|
|||
testif_write(dsi, 0x44, HSFREQRANGE(hsfreqrange));
|
||||
|
||||
txbyteclkhs = dsi->lane_mbps >> 3;
|
||||
counter = txbyteclkhs * 60 / NSEC_PER_USEC;
|
||||
counter = txbyteclkhs * 60 / 1000;
|
||||
testif_write(dsi, 0x60, 0x80 | counter);
|
||||
testif_write(dsi, 0x70, 0x80 | counter);
|
||||
|
||||
|
|
@ -549,7 +552,7 @@ static unsigned long dw_mipi_dsi_get_lane_rate(struct dw_mipi_dsi *dsi)
|
|||
/* optional override of the desired bandwidth */
|
||||
value = dev_read_u32_default(dsi->dev, "rockchip,lane-rate", 0);
|
||||
if (value > 0)
|
||||
return value * USEC_PER_SEC;
|
||||
return value * 1000 * 1000;
|
||||
|
||||
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
|
||||
if (bpp < 0)
|
||||
|
|
@ -629,7 +632,7 @@ static void dw_mipi_dsi_set_pll(struct dw_mipi_dsi *dsi, unsigned long rate)
|
|||
}
|
||||
}
|
||||
|
||||
dsi->lane_mbps = best_freq / USEC_PER_SEC;
|
||||
dsi->lane_mbps = best_freq / 1000 / 1000;
|
||||
dsi->dphy.input_div = best_prediv;
|
||||
dsi->dphy.feedback_div = best_fbdiv;
|
||||
if (dsi->slave) {
|
||||
|
|
@ -648,7 +651,7 @@ static int dw_mipi_dsi_read_from_fifo(struct dw_mipi_dsi *dsi,
|
|||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
|
||||
val, !(val & GEN_RD_CMD_BUSY), 50, 5000);
|
||||
val, !(val & GEN_RD_CMD_BUSY), 5000);
|
||||
if (ret) {
|
||||
printf("entire response isn't stored in the FIFO\n");
|
||||
return ret;
|
||||
|
|
@ -657,8 +660,7 @@ static int dw_mipi_dsi_read_from_fifo(struct dw_mipi_dsi *dsi,
|
|||
/* Receive payload */
|
||||
for (length = msg->rx_len; length; length -= 4) {
|
||||
ret = readl_poll_timeout(dsi->base + DSI_CMD_PKT_STATUS,
|
||||
val, !(val & GEN_PLD_R_EMPTY),
|
||||
50, 5000);
|
||||
val, !(val & GEN_PLD_R_EMPTY), 5000);
|
||||
if (ret) {
|
||||
printf("Read payload FIFO is empty\n");
|
||||
return ret;
|
||||
|
|
@ -713,7 +715,7 @@ static ssize_t dw_mipi_dsi_transfer(struct dw_mipi_dsi *dsi,
|
|||
int ret;
|
||||
int val;
|
||||
|
||||
if (dsi->mode_flags & MIPI_DSI_MODE_LPM) {
|
||||
if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
|
||||
dsi_update_bits(dsi, DSI_VID_MODE_CFG, LP_CMD_EN, LP_CMD_EN);
|
||||
dsi_update_bits(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS, 0);
|
||||
} else {
|
||||
|
|
@ -858,15 +860,6 @@ static ssize_t dw_mipi_dsi_transfer(struct dw_mipi_dsi *dsi,
|
|||
return msg->rx_len ? msg->rx_len : msg->tx_len;
|
||||
}
|
||||
|
||||
static ssize_t dw_mipi_dsi_connector_transfer(struct display_state *state,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
struct dw_mipi_dsi *dsi = dev_get_priv(conn_state->dev);
|
||||
|
||||
return dw_mipi_dsi_transfer(dsi, msg);
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi)
|
||||
{
|
||||
u32 val = LP_VACT_EN | LP_VFP_EN | LP_VBP_EN | LP_VSA_EN |
|
||||
|
|
@ -1017,7 +1010,7 @@ static int dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi,
|
|||
{
|
||||
u32 lbcc;
|
||||
|
||||
lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8;
|
||||
lbcc = hcomponent * dsi->lane_mbps * 1000 / 8;
|
||||
|
||||
if (dsi->mode->clock == 0) {
|
||||
printf("dsi mode clock is 0!\n");
|
||||
|
|
@ -1089,20 +1082,9 @@ static int dw_mipi_dsi_connector_init(struct display_state *state)
|
|||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
struct dw_mipi_dsi *dsi = dev_get_priv(conn_state->dev);
|
||||
struct rockchip_panel *panel = state_get_panel(state);
|
||||
|
||||
dsi->dphy.phy = conn_state->phy;
|
||||
|
||||
dsi->lanes = dev_read_u32_default(panel->dev, "dsi,lanes", 4);
|
||||
dsi->format = dev_read_u32_default(panel->dev, "dsi,format",
|
||||
MIPI_DSI_FMT_RGB888);
|
||||
dsi->mode_flags = dev_read_u32_default(panel->dev, "dsi,flags",
|
||||
MIPI_DSI_MODE_VIDEO |
|
||||
MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_LPM |
|
||||
MIPI_DSI_MODE_EOT_PACKET);
|
||||
dsi->channel = dev_read_u32_default(panel->dev, "reg", 0);
|
||||
|
||||
conn_state->output_mode = ROCKCHIP_OUT_MODE_P888;
|
||||
conn_state->color_space = V4L2_COLORSPACE_DEFAULT;
|
||||
conn_state->type = DRM_MODE_CONNECTOR_DSI;
|
||||
|
|
@ -1122,7 +1104,7 @@ static int dw_mipi_dsi_connector_init(struct display_state *state)
|
|||
static void dw_mipi_dsi_set_hs_clk(struct dw_mipi_dsi *dsi, unsigned long rate)
|
||||
{
|
||||
rate = rockchip_phy_set_pll(dsi->dphy.phy, rate);
|
||||
dsi->lane_mbps = rate / USEC_PER_SEC;
|
||||
dsi->lane_mbps = rate / 1000 / 1000;
|
||||
}
|
||||
|
||||
static void dw_mipi_dsi_host_init(struct dw_mipi_dsi *dsi)
|
||||
|
|
@ -1256,7 +1238,6 @@ static const struct rockchip_connector_funcs dw_mipi_dsi_connector_funcs = {
|
|||
.unprepare = dw_mipi_dsi_connector_unprepare,
|
||||
.enable = dw_mipi_dsi_connector_enable,
|
||||
.disable = dw_mipi_dsi_connector_disable,
|
||||
.transfer = dw_mipi_dsi_connector_transfer,
|
||||
};
|
||||
|
||||
static int dw_mipi_dsi_dual_channel_probe(struct dw_mipi_dsi *master)
|
||||
|
|
@ -1515,11 +1496,89 @@ static const struct udevice_id dw_mipi_dsi_ids[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
struct dw_mipi_dsi *dsi = dev_get_priv(host->dev);
|
||||
|
||||
return dw_mipi_dsi_transfer(dsi, msg);
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
struct mipi_dsi_device *device)
|
||||
{
|
||||
struct dw_mipi_dsi *dsi = dev_get_priv(host->dev);
|
||||
|
||||
if (device->lanes < 1 || device->lanes > 8)
|
||||
return -EINVAL;
|
||||
|
||||
dsi->lanes = device->lanes;
|
||||
dsi->channel = device->channel;
|
||||
dsi->format = device->format;
|
||||
dsi->mode_flags = device->mode_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mipi_dsi_host_ops dw_mipi_dsi_host_ops = {
|
||||
.attach = dw_mipi_dsi_host_attach,
|
||||
.transfer = dw_mipi_dsi_host_transfer,
|
||||
};
|
||||
|
||||
static int dw_mipi_dsi_bind(struct udevice *dev)
|
||||
{
|
||||
struct mipi_dsi_host *host = dev_get_platdata(dev);
|
||||
|
||||
host->dev = dev;
|
||||
host->ops = &dw_mipi_dsi_host_ops;
|
||||
|
||||
return dm_scan_fdt_dev(dev);
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_child_post_bind(struct udevice *dev)
|
||||
{
|
||||
struct mipi_dsi_host *host = dev_get_platdata(dev->parent);
|
||||
struct mipi_dsi_device *device = dev_get_parent_platdata(dev);
|
||||
|
||||
device->dev = dev;
|
||||
device->host = host;
|
||||
device->lanes = dev_read_u32_default(dev, "dsi,lanes", 4);
|
||||
device->format = dev_read_u32_default(dev, "dsi,format",
|
||||
MIPI_DSI_FMT_RGB888);
|
||||
device->mode_flags = dev_read_u32_default(dev, "dsi,flags",
|
||||
MIPI_DSI_MODE_VIDEO |
|
||||
MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_VIDEO_HBP |
|
||||
MIPI_DSI_MODE_LPM |
|
||||
MIPI_DSI_MODE_EOT_PACKET);
|
||||
device->channel = dev_read_u32_default(dev, "reg", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_mipi_dsi_child_pre_probe(struct udevice *dev)
|
||||
{
|
||||
struct mipi_dsi_device *device = dev_get_parent_platdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = mipi_dsi_attach(device);
|
||||
if (ret) {
|
||||
dev_err(dev, "mipi_dsi_attach() failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(dw_mipi_dsi) = {
|
||||
.name = "dw_mipi_dsi",
|
||||
.id = UCLASS_DISPLAY,
|
||||
.of_match = dw_mipi_dsi_ids,
|
||||
.probe = dw_mipi_dsi_probe,
|
||||
.bind = dm_scan_fdt_dev,
|
||||
.bind = dw_mipi_dsi_bind,
|
||||
.priv_auto_alloc_size = sizeof(struct dw_mipi_dsi),
|
||||
.per_child_platdata_auto_alloc_size = sizeof(struct mipi_dsi_device),
|
||||
.platdata_auto_alloc_size = sizeof(struct mipi_dsi_host),
|
||||
.child_post_bind = dw_mipi_dsi_child_post_bind,
|
||||
.child_pre_probe = dw_mipi_dsi_child_pre_probe,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,11 +20,10 @@
|
|||
|
||||
#include "rockchip_display.h"
|
||||
#include "rockchip_crtc.h"
|
||||
#include "rockchip_connector.h"
|
||||
#include "rockchip_phy.h"
|
||||
|
||||
#define INNO_HDMI_PHY_TIMEOUT_LOOP_COUNT 1000
|
||||
/*#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))*/
|
||||
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
|
||||
|
||||
/* REG: 0x00 */
|
||||
#define PRE_PLL_REFCLK_SEL_MASK BIT(0)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
#ifndef _ROCKCHIP_CONNECTOR_H_
|
||||
#define _ROCKCHIP_CONNECTOR_H_
|
||||
|
||||
#include "rockchip_mipi_dsi.h"
|
||||
|
||||
struct rockchip_connector {
|
||||
const struct rockchip_connector_funcs *funcs;
|
||||
|
||||
|
|
@ -58,9 +56,6 @@ struct rockchip_connector_funcs {
|
|||
* Save data to dts, then you can share data to kernel space.
|
||||
*/
|
||||
int (*fixup_dts)(struct display_state *state, void *blob);
|
||||
/* transmit a DSI packet */
|
||||
ssize_t (*transfer)(struct display_state *state,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
};
|
||||
|
||||
const struct rockchip_connector *
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@
|
|||
#include "rockchip_connector.h"
|
||||
#include "rockchip_phy.h"
|
||||
#include "rockchip_panel.h"
|
||||
#include "rockchip_lvds.h"
|
||||
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16))
|
||||
|
||||
#define PX30_GRF_PD_VO_CON1 0x0438
|
||||
#define PX30_LVDS_SELECT(x) HIWORD_UPDATE(x, 14, 13)
|
||||
|
|
|
|||
|
|
@ -1,340 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "rockchip_display.h"
|
||||
#include "rockchip_crtc.h"
|
||||
#include "rockchip_connector.h"
|
||||
#include "rockchip_mipi_dsi.h"
|
||||
|
||||
void mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
|
||||
unsigned long period)
|
||||
{
|
||||
/* Global Operation Timing Parameters */
|
||||
timing->clkmiss = 0;
|
||||
timing->clkpost = 70 + 52 * period;
|
||||
timing->clkpre = 8 * period;
|
||||
timing->clkprepare = 65;
|
||||
timing->clksettle = 95;
|
||||
timing->clktermen = 0;
|
||||
timing->clktrail = 80;
|
||||
timing->clkzero = 260;
|
||||
timing->dtermen = 0;
|
||||
timing->eot = 0;
|
||||
timing->hsexit = 120;
|
||||
timing->hsprepare = 65 + 4 * period;
|
||||
timing->hszero = 145 + 6 * period;
|
||||
timing->hssettle = 85 + 6 * period;
|
||||
timing->hsskip = 40;
|
||||
timing->hstrail = max(8 * period, 60 + 4 * period);
|
||||
timing->init = 100000;
|
||||
timing->lpx = 60;
|
||||
timing->taget = 5 * timing->lpx;
|
||||
timing->tago = 4 * timing->lpx;
|
||||
timing->tasure = 2 * timing->lpx;
|
||||
timing->wakeup = 1000000;
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_generic_write(struct display_state *state,
|
||||
const void *payload, size_t size)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
if (!connector || !connector->funcs || !connector->funcs->transfer) {
|
||||
printf("%s: failed to find connector transfer funcs\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.channel = 0;
|
||||
msg.tx_buf = payload;
|
||||
msg.tx_len = size;
|
||||
msg.flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
|
||||
break;
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
|
||||
break;
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
|
||||
break;
|
||||
default:
|
||||
msg.type = MIPI_DSI_GENERIC_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_dcs_write(struct display_state *state,
|
||||
const void *payload, size_t size)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
if (!connector || !connector->funcs || !connector->funcs->transfer) {
|
||||
printf("%s: failed to find connector transfer funcs\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.channel = 0;
|
||||
msg.tx_buf = payload;
|
||||
msg.tx_len = size;
|
||||
msg.flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
return -EINVAL;
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE;
|
||||
break;
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
|
||||
break;
|
||||
default:
|
||||
msg.type = MIPI_DSI_DCS_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_generic_read(struct display_state *state, const void *params,
|
||||
size_t num_params, void *data, size_t size)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
if (!connector || !connector->funcs || !connector->funcs->transfer) {
|
||||
printf("%s: failed to find connector transfer funcs\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.channel = 0;
|
||||
msg.tx_buf = params;
|
||||
msg.tx_len = num_params;
|
||||
msg.rx_len = size;
|
||||
msg.rx_buf = data;
|
||||
msg.flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
switch (num_params) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
|
||||
break;
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
|
||||
break;
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_dcs_read(struct display_state *state, u8 cmd, void *data,
|
||||
size_t len)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg;
|
||||
|
||||
if (!connector || !connector->funcs || !connector->funcs->transfer) {
|
||||
printf("%s: failed to find connector transfer funcs\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.channel = 0;
|
||||
msg.type = MIPI_DSI_DCS_READ;
|
||||
msg.tx_buf = &cmd;
|
||||
msg.tx_len = 1;
|
||||
msg.rx_len = len;
|
||||
msg.rx_buf = data;
|
||||
msg.flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_shutdown_peripheral(struct display_state *state)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = 0,
|
||||
.type = MIPI_DSI_SHUTDOWN_PERIPHERAL,
|
||||
.tx_buf = (u8 [2]) { 0, 0 },
|
||||
.tx_len = 2,
|
||||
.flags = MIPI_DSI_MSG_USE_LPM,
|
||||
};
|
||||
|
||||
if (!connector)
|
||||
return -ENODEV;
|
||||
|
||||
if (!connector->funcs || !connector->funcs->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
ssize_t mipi_dsi_turn_on_peripheral(struct display_state *state)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = 0,
|
||||
.type = MIPI_DSI_TURN_ON_PERIPHERAL,
|
||||
.tx_buf = (u8 [2]) { 0, 0 },
|
||||
.tx_len = 2,
|
||||
.flags = MIPI_DSI_MSG_USE_LPM,
|
||||
};
|
||||
|
||||
if (!connector)
|
||||
return -ENODEV;
|
||||
|
||||
if (!connector->funcs || !connector->funcs->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
int mipi_dsi_dcs_get_power_mode(struct display_state *state, u8 *mode)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(state, MIPI_DCS_GET_POWER_MODE, mode,
|
||||
sizeof(*mode));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct display_state *state,
|
||||
u16 value)
|
||||
{
|
||||
struct connector_state *conn_state = &state->conn_state;
|
||||
const struct rockchip_connector *connector = conn_state->connector;
|
||||
u8 tx[2] = { value & 0xff, value >> 8 };
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = 0,
|
||||
.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
|
||||
.tx_len = sizeof(tx),
|
||||
.tx_buf = tx,
|
||||
};
|
||||
|
||||
if (!connector)
|
||||
return -ENODEV;
|
||||
|
||||
if (!connector->funcs || !connector->funcs->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
return connector->funcs->transfer(state, &msg);
|
||||
}
|
||||
|
||||
static bool mipi_dsi_packet_format_is_short(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_V_SYNC_START:
|
||||
case MIPI_DSI_V_SYNC_END:
|
||||
case MIPI_DSI_H_SYNC_START:
|
||||
case MIPI_DSI_H_SYNC_END:
|
||||
case MIPI_DSI_END_OF_TRANSMISSION:
|
||||
case MIPI_DSI_COLOR_MODE_OFF:
|
||||
case MIPI_DSI_COLOR_MODE_ON:
|
||||
case MIPI_DSI_SHUTDOWN_PERIPHERAL:
|
||||
case MIPI_DSI_TURN_ON_PERIPHERAL:
|
||||
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_READ_REQUEST_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_DCS_READ:
|
||||
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mipi_dsi_packet_format_is_long(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_NULL_PACKET:
|
||||
case MIPI_DSI_BLANKING_PACKET:
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_30:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_36:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_18:
|
||||
case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_24:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
if (!packet || !msg)
|
||||
return -EINVAL;
|
||||
|
||||
/* do some minimum sanity checking */
|
||||
if (!mipi_dsi_packet_format_is_short(msg->type) &&
|
||||
!mipi_dsi_packet_format_is_long(msg->type))
|
||||
return -EINVAL;
|
||||
|
||||
if (msg->channel > 3)
|
||||
return -EINVAL;
|
||||
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
|
||||
if (mipi_dsi_packet_format_is_long(msg->type)) {
|
||||
packet->header[1] = (msg->tx_len >> 0) & 0xff;
|
||||
packet->header[2] = (msg->tx_len >> 8) & 0xff;
|
||||
packet->payload_length = msg->tx_len;
|
||||
packet->payload = msg->tx_buf;
|
||||
} else {
|
||||
const u8 *tx = msg->tx_buf;
|
||||
packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
|
||||
packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
|
||||
}
|
||||
|
||||
packet->size = sizeof(packet->header) + packet->payload_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __ROCKCHIP_MIPI_DSI_H__
|
||||
#define __ROCKCHIP_MIPI_DSI_H__
|
||||
|
||||
#include <mipi_display.h>
|
||||
|
||||
#define MSEC_PER_SEC 1000L
|
||||
#define USEC_PER_MSEC 1000L
|
||||
#define NSEC_PER_USEC 1000L
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
#define USEC_PER_SEC 1000000L
|
||||
#define NSEC_PER_SEC 1000000000L
|
||||
#define FSEC_PER_SEC 1000000000000000LL
|
||||
|
||||
#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
|
||||
#define UPDATE(v, h, l) (((v) << (l)) & GENMASK((h), (l)))
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16))
|
||||
|
||||
#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
|
||||
({ \
|
||||
int try = 100; \
|
||||
for (;;) { \
|
||||
(val) = readl(addr); \
|
||||
if (cond) \
|
||||
break; \
|
||||
try--; \
|
||||
if (!try) \
|
||||
break; \
|
||||
if (sleep_us) \
|
||||
udelay(sleep_us >> 2); \
|
||||
} \
|
||||
(cond) ? 0 : -ETIMEDOUT; \
|
||||
})
|
||||
|
||||
/* 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)
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_msg - read/write DSI buffer
|
||||
* @channel: virtual channel id
|
||||
* @type: payload data type
|
||||
* @flags: flags controlling this message transmission
|
||||
* @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;
|
||||
u16 flags;
|
||||
|
||||
size_t tx_len;
|
||||
const void *tx_buf;
|
||||
|
||||
size_t rx_len;
|
||||
void *rx_buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
||||
/* 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 */
|
||||
#define MIPI_DSI_MODE_VIDEO_HFP BIT(5)
|
||||
/* disable hback-porch area */
|
||||
#define MIPI_DSI_MODE_VIDEO_HBP BIT(6)
|
||||
/* disable hsync-active area */
|
||||
#define MIPI_DSI_MODE_VIDEO_HSA BIT(7)
|
||||
/* flush display FIFO on vsync pulse */
|
||||
#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
||||
/* disable EoT packets in HS mode */
|
||||
#define MIPI_DSI_MODE_EOT_PACKET BIT(9)
|
||||
/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
||||
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
|
||||
/* transmit data in low power */
|
||||
#define MIPI_DSI_MODE_LPM BIT(11)
|
||||
|
||||
enum mipi_dsi_pixel_format {
|
||||
MIPI_DSI_FMT_RGB888,
|
||||
MIPI_DSI_FMT_RGB666,
|
||||
MIPI_DSI_FMT_RGB666_PACKED,
|
||||
MIPI_DSI_FMT_RGB565,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
|
||||
#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)
|
||||
|
||||
struct mipi_dphy_timing {
|
||||
unsigned int clkmiss;
|
||||
unsigned int clkpost;
|
||||
unsigned int clkpre;
|
||||
unsigned int clkprepare;
|
||||
unsigned int clksettle;
|
||||
unsigned int clktermen;
|
||||
unsigned int clktrail;
|
||||
unsigned int clkzero;
|
||||
unsigned int dtermen;
|
||||
unsigned int eot;
|
||||
unsigned int hsexit;
|
||||
unsigned int hsprepare;
|
||||
unsigned int hszero;
|
||||
unsigned int hssettle;
|
||||
unsigned int hsskip;
|
||||
unsigned int hstrail;
|
||||
unsigned int init;
|
||||
unsigned int lpx;
|
||||
unsigned int taget;
|
||||
unsigned int tago;
|
||||
unsigned int tasure;
|
||||
unsigned int wakeup;
|
||||
};
|
||||
|
||||
void mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
|
||||
unsigned long period);
|
||||
ssize_t mipi_dsi_dcs_write(struct display_state *state,
|
||||
const void *payload, size_t size);
|
||||
ssize_t mipi_dsi_generic_write(struct display_state *state,
|
||||
const void *payload, size_t size);
|
||||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
ssize_t mipi_dsi_dcs_read(struct display_state *state, u8 cmd, void *data,
|
||||
size_t len);
|
||||
ssize_t mipi_dsi_generic_read(struct display_state *state, const void *params,
|
||||
size_t num_params, void *data, size_t size);
|
||||
ssize_t mipi_dsi_shutdown_peripheral(struct display_state *state);
|
||||
ssize_t mipi_dsi_turn_on_peripheral(struct display_state *state);
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct display_state *state,
|
||||
u16 value);
|
||||
int mipi_dsi_dcs_get_pixel_format(struct display_state *state, u8 *format);
|
||||
#endif /* __ROCKCHIP_MIPI_DSI__ */
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -21,7 +23,6 @@
|
|||
#include "rockchip_display.h"
|
||||
#include "rockchip_crtc.h"
|
||||
#include "rockchip_connector.h"
|
||||
#include "rockchip_mipi_dsi.h"
|
||||
#include "rockchip_panel.h"
|
||||
|
||||
struct rockchip_cmd_header {
|
||||
|
|
@ -209,7 +210,7 @@ static int rockchip_panel_send_spi_cmds(struct display_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_panel_send_dsi_cmds(struct display_state *state,
|
||||
static int rockchip_panel_send_dsi_cmds(struct mipi_dsi_device *dsi,
|
||||
struct rockchip_panel_cmds *cmds)
|
||||
{
|
||||
int i, ret;
|
||||
|
|
@ -219,24 +220,25 @@ static int rockchip_panel_send_dsi_cmds(struct display_state *state,
|
|||
|
||||
for (i = 0; i < cmds->cmd_cnt; i++) {
|
||||
struct rockchip_cmd_desc *desc = &cmds->cmds[i];
|
||||
const struct rockchip_cmd_header *header = &desc->header;
|
||||
|
||||
switch (desc->header.data_type) {
|
||||
switch (header->data_type) {
|
||||
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:
|
||||
ret = mipi_dsi_generic_write(state, desc->payload,
|
||||
desc->header.payload_length);
|
||||
ret = mipi_dsi_generic_write(dsi, desc->payload,
|
||||
header->payload_length);
|
||||
break;
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
ret = mipi_dsi_dcs_write(state, desc->payload,
|
||||
desc->header.payload_length);
|
||||
ret = mipi_dsi_dcs_write_buffer(dsi, desc->payload,
|
||||
header->payload_length);
|
||||
break;
|
||||
default:
|
||||
printf("unsupport command data type: %d\n",
|
||||
desc->header.data_type);
|
||||
header->data_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -245,8 +247,8 @@ static int rockchip_panel_send_dsi_cmds(struct display_state *state,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (desc->header.delay_ms)
|
||||
mdelay(desc->header.delay_ms);
|
||||
if (header->delay_ms)
|
||||
mdelay(header->delay_ms);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -256,6 +258,7 @@ static void panel_simple_prepare(struct rockchip_panel *panel)
|
|||
{
|
||||
struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev);
|
||||
struct rockchip_panel_priv *priv = dev_get_priv(panel->dev);
|
||||
struct mipi_dsi_device *dsi = dev_get_parent_platdata(panel->dev);
|
||||
int ret;
|
||||
|
||||
if (priv->prepared)
|
||||
|
|
@ -290,8 +293,7 @@ static void panel_simple_prepare(struct rockchip_panel *panel)
|
|||
ret = rockchip_panel_send_mcu_cmds(panel->state,
|
||||
plat->on_cmds);
|
||||
else
|
||||
ret = rockchip_panel_send_dsi_cmds(panel->state,
|
||||
plat->on_cmds);
|
||||
ret = rockchip_panel_send_dsi_cmds(dsi, plat->on_cmds);
|
||||
if (ret)
|
||||
printf("failed to send on cmds: %d\n", ret);
|
||||
}
|
||||
|
|
@ -303,6 +305,7 @@ static void panel_simple_unprepare(struct rockchip_panel *panel)
|
|||
{
|
||||
struct rockchip_panel_plat *plat = dev_get_platdata(panel->dev);
|
||||
struct rockchip_panel_priv *priv = dev_get_priv(panel->dev);
|
||||
struct mipi_dsi_device *dsi = dev_get_parent_platdata(panel->dev);
|
||||
int ret;
|
||||
|
||||
if (!priv->prepared)
|
||||
|
|
@ -316,8 +319,7 @@ static void panel_simple_unprepare(struct rockchip_panel *panel)
|
|||
ret = rockchip_panel_send_mcu_cmds(panel->state,
|
||||
plat->off_cmds);
|
||||
else
|
||||
ret = rockchip_panel_send_dsi_cmds(panel->state,
|
||||
plat->off_cmds);
|
||||
ret = rockchip_panel_send_dsi_cmds(dsi, plat->off_cmds);
|
||||
if (ret)
|
||||
printf("failed to send off cmds: %d\n", ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include "rockchip_connector.h"
|
||||
#include "rockchip_phy.h"
|
||||
|
||||
#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16))
|
||||
|
||||
#define PX30_GRF_PD_VO_CON1 0x0438
|
||||
#define PX30_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3)
|
||||
#define PX30_RGB_VOP_SEL(v) HIWORD_UPDATE(v, 2, 2)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,252 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* 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 <mipi_display.h>
|
||||
#include <dm/device.h>
|
||||
|
||||
struct mipi_dsi_host;
|
||||
struct mipi_dsi_device;
|
||||
|
||||
/* 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)
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_msg - read/write DSI buffer
|
||||
* @channel: virtual channel id
|
||||
* @type: payload data type
|
||||
* @flags: flags controlling this message transmission
|
||||
* @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;
|
||||
u16 flags;
|
||||
|
||||
size_t tx_len;
|
||||
const void *tx_buf;
|
||||
|
||||
size_t rx_len;
|
||||
void *rx_buf;
|
||||
};
|
||||
|
||||
bool mipi_dsi_packet_format_is_short(u8 type);
|
||||
bool mipi_dsi_packet_format_is_long(u8 type);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_host_ops - DSI bus operations
|
||||
* @attach: attach DSI device to DSI host
|
||||
* @detach: detach DSI device from DSI host
|
||||
* @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.
|
||||
*/
|
||||
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,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_host - DSI host device
|
||||
* @dev: driver model device node for this DSI host
|
||||
* @ops: DSI host operations
|
||||
* @list: list management
|
||||
*/
|
||||
struct mipi_dsi_host {
|
||||
struct udevice *dev;
|
||||
const struct mipi_dsi_host_ops *ops;
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
#define MIPI_DSI_MODE_VIDEO_HFP BIT(5)
|
||||
/* disable hback-porch area */
|
||||
#define MIPI_DSI_MODE_VIDEO_HBP BIT(6)
|
||||
/* disable hsync-active area */
|
||||
#define MIPI_DSI_MODE_VIDEO_HSA BIT(7)
|
||||
/* flush display FIFO on vsync pulse */
|
||||
#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8)
|
||||
/* disable EoT packets in HS mode */
|
||||
#define MIPI_DSI_MODE_EOT_PACKET BIT(9)
|
||||
/* device supports non-continuous clock behavior (DSI spec 5.6.1) */
|
||||
#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10)
|
||||
/* transmit data in low power */
|
||||
#define MIPI_DSI_MODE_LPM BIT(11)
|
||||
|
||||
enum mipi_dsi_pixel_format {
|
||||
MIPI_DSI_FMT_RGB888,
|
||||
MIPI_DSI_FMT_RGB666,
|
||||
MIPI_DSI_FMT_RGB666_PACKED,
|
||||
MIPI_DSI_FMT_RGB565,
|
||||
};
|
||||
|
||||
#define DSI_DEV_NAME_SIZE 20
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_device - DSI peripheral device
|
||||
* @host: DSI host for this peripheral
|
||||
* @dev: driver model device node for this peripheral
|
||||
* @name: DSI peripheral chip type
|
||||
* @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
|
||||
* @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
|
||||
*/
|
||||
struct mipi_dsi_device {
|
||||
struct mipi_dsi_host *host;
|
||||
struct udevice *dev;
|
||||
|
||||
char name[DSI_DEV_NAME_SIZE];
|
||||
unsigned int channel;
|
||||
unsigned int lanes;
|
||||
enum mipi_dsi_pixel_format format;
|
||||
unsigned long mode_flags;
|
||||
unsigned long hs_rate;
|
||||
unsigned long lp_rate;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_shutdown_peripheral(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_turn_on_peripheral(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
||||
u16 value);
|
||||
|
||||
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
||||
size_t size);
|
||||
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
||||
size_t num_params, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
|
||||
#define MIPI_DSI_DCS_POWER_MODE_DISPLAY BIT(2)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_NORMAL BIT(3)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_SLEEP BIT(4)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_PARTIAL BIT(5)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_IDLE BIT(6)
|
||||
|
||||
ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
||||
const void *data, size_t len);
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
||||
const void *data, size_t len);
|
||||
ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
||||
size_t len);
|
||||
int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode);
|
||||
int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
|
||||
int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline);
|
||||
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);
|
||||
|
||||
#endif /* __DRM_MIPI_DSI__ */
|
||||
Loading…
Reference in New Issue