465 lines
11 KiB
C
465 lines
11 KiB
C
/**
|
|
* @file sdrv_dispss.c
|
|
* @brief sdrv display driver source.
|
|
*
|
|
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <board.h>
|
|
#include <clock_ip.h>
|
|
#include <dispss/disp.h>
|
|
#include <dispss/disp_data_type.h>
|
|
#include <dispss/dispss_log.h>
|
|
#include <irq.h>
|
|
#include <sdrv_ckgen.h>
|
|
#include <string.h>
|
|
#include <udelay/udelay.h>
|
|
|
|
extern struct sdrv_panel *sdrv_panels[];
|
|
|
|
/**
|
|
* @brief sdrv display rgb565 logo.
|
|
*
|
|
* This function display a static logo.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] width logo width.
|
|
* @param [in] height logo height.
|
|
* @param [in] addr the memory addr of logo data.
|
|
*
|
|
*/
|
|
void sdrv_display_rgb565_logo(struct dc_dev *dev, unsigned int width,
|
|
unsigned int height, unsigned char const *addr)
|
|
{
|
|
struct post_cfg post;
|
|
struct surface layer[2] = {0};
|
|
int panel_width = dev->panel->timing->hactive;
|
|
int panel_height = dev->panel->timing->vactive;
|
|
sdrv_display_set_bg_color(dev, 0x3fffffff);
|
|
|
|
layer[0].id = 1;
|
|
layer[0].dirty = 1;
|
|
layer[0].en = 1;
|
|
layer[0].fmt = COLOR_RGB565;
|
|
|
|
layer[0].src.x = 0;
|
|
layer[0].src.y = 0;
|
|
layer[0].src.w = width;
|
|
layer[0].src.h = height;
|
|
|
|
layer[0].start.x = 0;
|
|
layer[0].start.y = 0;
|
|
layer[0].start.w = width;
|
|
layer[0].start.h = height;
|
|
|
|
layer[0].addr[0] = (unsigned long)addr;
|
|
layer[0].src_stride[0] = width * 2;
|
|
|
|
layer[0].dst.x = (panel_width - width) / 2;
|
|
layer[0].dst.y = (panel_height - height) / 2;
|
|
layer[0].dst.w = width;
|
|
layer[0].dst.h = height;
|
|
|
|
layer[0].z_order = 0;
|
|
layer[0].alpha_en = 1;
|
|
layer[0].alpha = 0xff;
|
|
layer[0].ckey_en = 0;
|
|
|
|
post.num_layers = 1;
|
|
post.layers = layer;
|
|
|
|
dev->ops->update(dev, &post);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
sdrv_display_set_bg_color(dev, 0x0);
|
|
}
|
|
|
|
/**
|
|
* @brief sdrv display blank.
|
|
*
|
|
* This function display a blank frame.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
*/
|
|
void sdrv_display_blank(struct dc_dev *dev)
|
|
{
|
|
struct post_cfg post;
|
|
struct surface layer[2] = {0};
|
|
int width = dev->panel->timing->hactive;
|
|
int height = dev->panel->timing->vactive;
|
|
|
|
layer[0].id = 1;
|
|
layer[0].dirty = 0;
|
|
layer[0].en = 0;
|
|
layer[0].fmt = COLOR_RGB565;
|
|
|
|
layer[0].src.x = 0;
|
|
layer[0].src.y = 0;
|
|
layer[0].src.w = width;
|
|
layer[0].src.h = height;
|
|
|
|
layer[0].start.x = 0;
|
|
layer[0].start.y = 0;
|
|
layer[0].start.w = width;
|
|
layer[0].start.h = height;
|
|
|
|
layer[0].addr[0] = 0;
|
|
layer[0].src_stride[0] = width * 2;
|
|
|
|
layer[0].dst.x = 0;
|
|
layer[0].dst.y = 0;
|
|
layer[0].dst.w = width;
|
|
layer[0].dst.h = height;
|
|
|
|
layer[0].z_order = 0;
|
|
layer[0].alpha_en = 1;
|
|
layer[0].alpha = 0xff;
|
|
layer[0].ckey_en = 0;
|
|
|
|
post.num_layers = 1;
|
|
post.layers = layer;
|
|
|
|
dev->ops->update(dev, &post);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
}
|
|
|
|
/**
|
|
* @brief get display width.
|
|
*
|
|
* This function obtains display width.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @return the hactive of tcon timing.
|
|
*/
|
|
int sdrv_display_get_width(struct dc_dev *dev)
|
|
{
|
|
return dev->panel->timing->hactive;
|
|
}
|
|
|
|
/**
|
|
* @brief get display height.
|
|
*
|
|
* This function obtains display height.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @return the vactive of tcon timing.
|
|
*/
|
|
int sdrv_display_get_height(struct dc_dev *dev)
|
|
{
|
|
return dev->panel->timing->vactive;
|
|
}
|
|
|
|
/**
|
|
* @brief set display background color.
|
|
*
|
|
* This function set the background color of display.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] color background color value.
|
|
*/
|
|
void sdrv_display_set_bg_color(struct dc_dev *dev, int color)
|
|
{
|
|
dev->ops->set_bg_color(dev, color);
|
|
}
|
|
|
|
/**
|
|
* @brief refresh display single surface.
|
|
*
|
|
* This function implements display configuration and refresh display.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] layer display surface param.
|
|
*
|
|
* @return SDRV_DISPSS_STATUS_OK display surface successfully,
|
|
* SDRV_DISPSS_STATUS_TIMEOUT display surface timeout.
|
|
*/
|
|
status_t sdrv_display_surface(struct dc_dev *dev, struct surface *layer)
|
|
{
|
|
int i = 0;
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
|
|
dev->ops->update_layer(dev, layer);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
|
|
while (dev->ops->check_triggle_status(dev)) {
|
|
|
|
udelay(100);
|
|
i++;
|
|
if (i == 1000) {
|
|
ret = SDRV_DISPSS_STATUS_TIMEOUT;
|
|
DISPSS_LOG_INFO("sdrv_display_surface timeout for 100ms !");
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief noblock refresh display surface.
|
|
*
|
|
* This function implements display configuration and nonblock refresh display
|
|
* surface.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] layer surface param.
|
|
*
|
|
* @return SDRV_DISPSS_STATUS_OK display surface successfully,
|
|
* SDRV_DISPSS_STATUS_FAIL display surface fail.
|
|
*/
|
|
status_t sdrv_display_surface_noblock(struct dc_dev *dev, struct surface *layer)
|
|
{
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
|
|
if (dev->ops->check_triggle_status(dev)) {
|
|
ret = SDRV_DISPSS_STATUS_FAIL;
|
|
} else {
|
|
dev->ops->update_layer(dev, layer);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief refresh display.
|
|
*
|
|
* This function implements display configuration and refresh display.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] post display config param.
|
|
*
|
|
* @return SDRV_DISPSS_STATUS_OK display successfully,
|
|
* SDRV_DISPSS_STATUS_TIMEOUT display timeout.
|
|
*/
|
|
status_t sdrv_display_post(struct dc_dev *dev, struct post_cfg *post)
|
|
{
|
|
int i = 0;
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
|
|
dev->ops->update(dev, post);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
|
|
while (dev->ops->check_triggle_status(dev)) {
|
|
|
|
udelay(100);
|
|
i++;
|
|
if (i == 1000) {
|
|
ret = SDRV_DISPSS_STATUS_TIMEOUT;
|
|
DISPSS_LOG_INFO("sdrv_display_post timeout for 100ms !");
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief noblock refresh display.
|
|
*
|
|
* This function implements display configuration and nonblock refresh display.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] post display config param.
|
|
*
|
|
* @return SDRV_DISPSS_STATUS_OK display successfully,
|
|
* SDRV_DISPSS_STATUS_FAIL display fail.
|
|
*/
|
|
status_t sdrv_display_post_noblock(struct dc_dev *dev, struct post_cfg *post)
|
|
{
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
if (dev->ops->check_triggle_status(dev)) {
|
|
ret = SDRV_DISPSS_STATUS_FAIL;
|
|
} else {
|
|
dev->ops->update(dev, post);
|
|
dev->ops->triggle(dev);
|
|
dev->ops->enable(dev);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief asw-dc handshake mode enable with update layer.
|
|
*
|
|
* This function implements display configuration and enable asw-dc handshake
|
|
* mode.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] mode HSDK MODE:
|
|
* 0:BUF_SIZE_8LINES; 1: BUF_SIZE_16LINES; 2:BUF_SIZE_32LINES;
|
|
* 3:BUF_SIZE_64LINES
|
|
* @param [in] layer surface param.
|
|
*/
|
|
void sdrv_dc_handshake_enable(struct dc_dev *dev, int mode,
|
|
struct surface *layer)
|
|
{
|
|
dev->ops->update_layer(dev, layer);
|
|
dev->ops->hsdk_enable(dev, mode, true);
|
|
dev->ops->triggle(dev);
|
|
}
|
|
|
|
/**
|
|
* @brief asw-dc handshake mode disable with g-pipe disable.
|
|
*
|
|
* This function enable asw-dc handshake mode.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @param [in] mode HSDK MODE:
|
|
* 0:BUF_SIZE_8LINES; 1: BUF_SIZE_16LINES; 2:BUF_SIZE_32LINES;
|
|
* 3:BUF_SIZE_64LINES
|
|
* @param [in] zorder g-pipe layer zorder
|
|
*/
|
|
void sdrv_dc_handshake_disable(struct dc_dev *dev, int mode, uint8_t zorder)
|
|
{
|
|
dev->ops->clear_layers(dev, CLEAR_GPIPE_LAYER, zorder);
|
|
dev->ops->hsdk_enable(dev, mode, false);
|
|
dev->ops->triggle(dev);
|
|
}
|
|
|
|
void sdrv_update_csi_detect(struct dc_dev *dev, struct surface *layer,
|
|
int mask_count, int ratio, bool enable,
|
|
bool pll_mode)
|
|
{
|
|
dev->ops->update_csi_detect(dev, layer, mask_count, ratio, enable,
|
|
pll_mode);
|
|
}
|
|
|
|
void sdrv_tcon_auto_adj_enable(struct dc_dev *dev, bool enable)
|
|
{
|
|
dev->ops->tcon_auto_adj_enable(dev, enable);
|
|
}
|
|
|
|
/**
|
|
* @brief sdrv disp interface init.
|
|
*
|
|
* This function init display interface.
|
|
*
|
|
* @param [in] panel display panel param.
|
|
* @return SDRV_DISPSS_STATUS_OK panel probe successfully,
|
|
* SDRV_DISPSS_STATUS_INVALID_PARAM panel is invalid param.
|
|
*/
|
|
status_t sdrv_panel_probe(struct sdrv_panel *panel)
|
|
{
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
|
|
if (panel != NULL) {
|
|
switch (panel->if_type) {
|
|
case IF_TYPE_LVDS:
|
|
ret = sdrv_lvds_init(panel);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
ret = SDRV_DISPSS_STATUS_INVALID_PARAM;
|
|
DISPSS_LOG_INFO("sdrv_panel is NULL!");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdrv display clk set.
|
|
*
|
|
* This function set display pixel clk.
|
|
*
|
|
* @param [in] clk lvds pixel clk.
|
|
* @return SDRV_DISPSS_STATUS_OK display clk set successfully,
|
|
* SDRV_DISPSS_STATUS_INVALID_PARAM clk is invalid param.
|
|
*/
|
|
status_t sdrv_display_set_pixelclk(int clk)
|
|
{
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
int root_clk;
|
|
|
|
if ((clk <= 0) || (clk * 7 > PLL_LVDS_MAX)) {
|
|
DISPSS_LOG_INFO("clk value is invalid");
|
|
ret = SDRV_DISPSS_STATUS_INVALID_PARAM;
|
|
return ret;
|
|
} else if (clk * 7 * 2 > PLL_LVDS_MAX) {
|
|
root_clk = clk * 7;
|
|
} else {
|
|
root_clk = clk * 7 * 2;
|
|
}
|
|
|
|
DISPSS_LOG_INFO("set display pixel clk is %dHz", clk);
|
|
sdrv_ckgen_node_t *clk_root = CLK_NODE(g_pll_lvds_root);
|
|
sdrv_ckgen_node_t *clk_nodiv = CLK_NODE(g_pll_lvds_nodiv);
|
|
sdrv_ckgen_node_t *clk_div2 = CLK_NODE(g_pll_lvds_div2);
|
|
sdrv_ckgen_node_t *clk_div7 = CLK_NODE(g_pll_lvds_div7);
|
|
|
|
sdrv_pll_set_rate(clk_root, root_clk);
|
|
sdrv_pll_set_rate(clk_nodiv, root_clk);
|
|
sdrv_pll_set_rate(clk_div2, clk * 7);
|
|
sdrv_pll_set_rate(clk_div7, clk);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief sdrv display clk init.
|
|
*
|
|
* This function init display clk and timing.
|
|
*
|
|
* @param [in] timing display timing param.
|
|
*/
|
|
static void sdrv_display_clk_init(struct display_timing *timing)
|
|
{
|
|
int clk = 0;
|
|
if (timing == NULL) {
|
|
DISPSS_LOG_INFO("display_timing is NULL!");
|
|
} else {
|
|
clk = (int)((timing->hactive + timing->hfront_porch +
|
|
timing->hback_porch + timing->hsync_len) *
|
|
(timing->vactive + timing->vfront_porch +
|
|
timing->vback_porch + timing->vsync_len) *
|
|
(timing->fps / 1000));
|
|
|
|
sdrv_display_set_pixelclk(clk);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief sdrv display init.
|
|
*
|
|
* This function init display hardware.
|
|
*
|
|
* @param [in] dev DC device struct.
|
|
* @return SDRV_DISPSS_STATUS_OK display init successfully.
|
|
*/
|
|
status_t sdrv_display_init(struct dc_dev *dev)
|
|
{
|
|
status_t ret = SDRV_DISPSS_STATUS_OK;
|
|
DISPSS_LOG_FUNC();
|
|
|
|
/* clk set */
|
|
sdrv_display_clk_init(dev->panel->timing);
|
|
|
|
/* disp mux */
|
|
sdrv_disp_mux_init(dev->panel);
|
|
|
|
/* init interface */
|
|
ret = sdrv_panel_probe(dev->panel);
|
|
|
|
/* init dc */
|
|
dev->ops->init(dev);
|
|
dev->ops->vsync_enable(dev, true);
|
|
|
|
DISPSS_LOG_INFO("init done!");
|
|
return ret;
|
|
}
|
|
|
|
void sdrv_dc_probe(struct dc_dev *dev, const struct dc_config *dc_cfg)
|
|
{
|
|
dev->base = dc_cfg->base;
|
|
dev->irq = dc_cfg->irq;
|
|
dev->ops = &dc_ops;
|
|
dev->panel = sdrv_panels[0];
|
|
dev->app.id = 0;
|
|
dev->crc32 = dc_cfg->crc32;
|
|
irq_attach(dev->irq, dev->ops->irq_handler, dev);
|
|
irq_enable(dev->irq);
|
|
}
|