Files
6CAR/drivers/source/dispss/sdrv_dispss.c
2026-04-18 09:16:58 +08:00

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);
}