/** * @file sdrv_dispss.c * @brief sdrv display driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include 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); }