1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624 |
- /*
- * Copyright (c) 2020 Actions Technology Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <soc.h>
- #include <spicache.h>
- #include <drivers/display.h>
- #include <drivers/display/display_controller.h>
- #include <drivers/display/display_engine.h>
- #include <assert.h>
- #include <string.h>
- #include <sys/byteorder.h>
- #include <tracing/tracing.h>
- #include "../de_common.h"
- #include "../de_device.h"
- #include "de_leopard.h"
- #define DEV_DBG(...) //printk("[DE][D]: " __VA_ARGS__);
- #define DEV_INF(...) //printk("[DE][I]: " __VA_ARGS__);
- #define DEV_WRN(...) printk("[DE][W]: " __VA_ARGS__);
- #define DEV_ERR(...) printk("[DE][E]: " __VA_ARGS__);
- #define CONFIG_DE_RESET_DEV_AFTER_WB 1
- #define CONFIG_DE_USE_DEV_HALFULL 0 /* using halfull interrupt to post display */
- #define CONFIG_DE_ALPHA_SSAA 0
- #ifdef CONFIG_LCDC_Y_FLIP
- # define CONFIG_DE_DEV_Y_FLIP CONFIG_LCDC_Y_FLIP
- #else
- # define CONFIG_DE_DEV_Y_FLIP 0
- #endif
- #define CONFIG_DE_WB_Y_FLIP 0
- #define MAX_NUM_OVERLAYS 5
- #define MAX_WIDTH 512
- #define MAX_HEIGHT 512
- #define MAX_PITCH 4095
- #define MIN_WB_WIDTH 2
- #define SSAA_PIXEL_FORMATS \
- (PIXEL_FORMAT_A2 | PIXEL_FORMAT_A1 | PIXEL_FORMAT_A1_LE)
- #define ALPHA_PIXEL_FORMATS \
- (PIXEL_FORMAT_A8 | PIXEL_FORMAT_A4 | PIXEL_FORMAT_A4_LE | \
- PIXEL_FORMAT_A2 | PIXEL_FORMAT_A1 | PIXEL_FORMAT_A1_LE)
- #define ABMP_BITS_PIXEL_FORMATS \
- (PIXEL_FORMAT_A4 | PIXEL_FORMAT_A4_LE | PIXEL_FORMAT_A2 | \
- PIXEL_FORMAT_A1 | PIXEL_FORMAT_A1_LE | PIXEL_FORMAT_I4 | \
- PIXEL_FORMAT_I2 | PIXEL_FORMAT_I1)
- #define ABMP_PIXEL_FORMATS \
- (ALPHA_PIXEL_FORMATS | PIXEL_FORMAT_I8 | \
- PIXEL_FORMAT_I4 | PIXEL_FORMAT_I2 | PIXEL_FORMAT_I1)
- #define SUPPORTED_SCALING_PIXEL_FORMATS \
- (SUPPORTED_OUTPUT_PIXEL_FORMATS | ABMP_PIXEL_FORMATS | PIXEL_FORMAT_BGR_888 | \
- PIXEL_FORMAT_BGRA_5658 | PIXEL_FORMAT_BGRA_6666 | PIXEL_FORMAT_RGBA_6666 | PIXEL_FORMAT_BGR_565)
- #define SUPPORTED_ROTATE_PIXEL_FORMATS (PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_XRGB_8888 | PIXEL_FORMAT_BGR_565)
- #define SUPPORTED_OUTPUT_PIXEL_FORMATS \
- (PIXEL_FORMAT_ARGB_8888 | PIXEL_FORMAT_XRGB_8888 | PIXEL_FORMAT_RGB_888 | PIXEL_FORMAT_BGR_565)
- #define SUPPORTED_INPUT_PIXEL_FORMATS \
- (SUPPORTED_SCALING_PIXEL_FORMATS | PIXEL_FORMAT_BGRA_5551)
- #define GUESS_PITCH(buffer, bits_per_pixel) \
- ((buffer)->desc.pitch > 0 ? (buffer)->desc.pitch : ((buffer)->desc.width * (bits_per_pixel) / 8))
- #define GUESS_PITCH_BYTES(buffer, bytes_per_pixel) \
- ((buffer)->desc.pitch > 0 ? (buffer)->desc.pitch : ((buffer)->desc.width * (bytes_per_pixel)))
- struct de_priv_data {
- #if CONFIG_DE_RESET_DEV_AFTER_WB
- bool last_ovl_is_wb;
- #endif
- int8_t clken_count;
- bool nor_locked;
- };
- #define DE ((DE_Type *)DE_REG_BASE)
- static DE_LAYER_Type * const DE_LX[3] = {
- &DE->LX_CTL[0], &DE->LX_CTL[1], &DE->L2_CTL,
- };
- static struct de_priv_data de_priv_data __in_section_unique(ram.noinit.drv_de.data);
- __de_func static void de_clk_set_en(bool en)
- {
- unsigned int key = irq_lock();
- if (en) {
- if (de_priv_data.clken_count++ == 0)
- acts_clock_peripheral_enable(CLOCK_ID_DE);
- } else {
- if (--de_priv_data.clken_count == 0)
- acts_clock_peripheral_disable(CLOCK_ID_DE);
- }
- DEV_DBG("de: clk en %d, cnt %d\n", en, clken_count);
- irq_unlock(key);
- }
- __de_func static void de_set_nor_locked(bool locked)
- {
- if (locked != de_priv_data.nor_locked) {
- nor_xip_set_locked(locked);
- de_priv_data.nor_locked = locked;
- DEV_DBG("de: nor locked %d\n", locked);
- }
- }
- static void de_reset(struct de_data *data)
- {
- acts_reset_peripheral_assert(RESET_ID_DE);
- de_clk_set_en(true);
- acts_reset_peripheral_deassert(RESET_ID_DE);
- #if CONFIG_DE_RESET_DEV_AFTER_WB
- de_priv_data.last_ovl_is_wb = false;
- #endif
- DE->MEM_OPT = (DE->MEM_OPT & ~DE_MEM_BURST_LEN_MASK) | DE_MEM_BURST_32;
- DE->ALPHA_POS = DE_ALPHA_POS(0, 0);
- #if CONFIG_DE_USE_DEV_HALFULL
- DE->IRQ_CTL = data->display_sync_en ?
- DE_IRQ_WB_FTC | DE_IRQ_DEV_FTC | DE_IRQ_DEV_FIFO_HF | DE_IRQ_DEV_FIFO_UDF :
- DE_IRQ_WB_FTC | DE_IRQ_DEV_FTC | DE_IRQ_DEV_FIFO_HF;
- #else
- DE->IRQ_CTL = data->display_sync_en ?
- DE_IRQ_WB_FTC | DE_IRQ_DEV_FTC | DE_IRQ_DEV_FIFO_UDF :
- DE_IRQ_WB_FTC | DE_IRQ_DEV_FTC;
- #endif /* CONFIG_DE_USE_DEV_HALFULL */
- /* keep clock disabled */
- de_clk_set_en(false);
- }
- static int de_open(const struct device *dev, uint32_t flags)
- {
- struct de_data *data = dev->data;
- int inst = -EMFILE;
- if (data->display_sync_en && !(flags & DISPLAY_ENGINE_FLAG_POST)) {
- DEV_WRN("de busy in lcd-sync\n");
- return -1;
- }
- k_mutex_lock(&data->mutex, K_FOREVER);
- inst = de_alloc_instance(flags);
- if (inst < 0)
- goto out_unlock;
- if (data->open_count++ == 0) {
- de_reset(data);
- }
- out_unlock:
- k_mutex_unlock(&data->mutex);
- return inst;
- }
- static int de_close(const struct device *dev, int inst)
- {
- struct de_data *data = dev->data;
- int ret = -EBUSY;
- ret = de_instance_poll(inst, -1);
- if (ret < 0)
- return ret;
- k_mutex_lock(&data->mutex, K_FOREVER);
- de_free_instance(inst);
- k_mutex_unlock(&data->mutex);
- return 0;
- }
- void de_dump(void)
- {
- int i;
- de_clk_set_en(true);
- printk("de regs:\n");
- printk("\t ctl 0x%08x\n", DE->CTL);
- printk("\t gate_ctl 0x%08x\n", DE->GAT_CTL);
- printk("\t reg_ud 0x%08x\n", DE->REG_UD);
- printk("\t irq_ctl 0x%08x\n", DE->IRQ_CTL);
- printk("\t bg_size 0x%08x\n", DE->BG_SIZE);
- printk("\t bg_color 0x%08x\n", DE->BG_COLOR);
- printk("\t mem_opt 0x%08x\n", DE->MEM_OPT);
- printk("\t en 0x%08x\n", DE->EN);
- printk("\t ctl2 0x%08x\n", DE->CTL2);
- printk("\t ctl1 0x%08x\n", DE->CTL1);
- for (i = 0; i < ARRAY_SIZE(DE_LX); i++) {
- printk("\t l%d_pos 0x%08x\n", i, DE_LX[i]->POS);
- printk("\t l%d_size 0x%08x\n", i, DE_LX[i]->SIZE);
- printk("\t l%d_addr 0x%08x\n", i, DE_LX[i]->ADDR);
- printk("\t l%d_stride 0x%08x\n", i, DE_LX[i]->STRIDE);
- printk("\t l%d_length 0x%08x\n", i, DE_LX[i]->LENGTH);
- printk("\t l%d_def_color 0x%08x\n", i, DE_LX[i]->DEF_COLOR);
- }
- printk("\t alpha_ctl 0x%08x\n", DE->ALPHA_CTL);
- printk("\t alpha_pos 0x%08x\n", DE->ALPHA_POS);
- printk("\t alpha_size 0x%08x\n", DE->ALPHA_SIZE);
- printk("\t sta 0x%08x\n", DE->STA);
- printk("\t wb_addr 0x%08x\n", DE->WB_MEM_ADR);
- printk("\t wb_stride 0x%08x\n", DE->WB_MEM_STRIDE);
- printk("\t color_fill_pos 0x%08x\n", DE->COLOR_FILL_POS);
- printk("\t color_fill_size 0x%08x\n", DE->COLOR_FILL_SIZE);
- printk("\t fill_color 0x%08x\n", DE->FILL_COLOR);
- printk("\t lx_abmp_ctl 0x%08x\n", DE->LX_ABMP_CTL);
- printk("\t sc_lx_src_img_size 0x%08x\n", DE->SC_LX_SRC_IMG_SIZE);
- printk("\t sc_lx_rate 0x%08x\n", DE->SC_LX_RATE);
- printk("\t sc_lx_pos 0x%08x\n", DE->SC_LX_POS);
- #if 1
- printk("\t rt_ctl 0x%08x\n", DE->RT_CTL);
- printk("\t rt_img_size 0x%08x\n", DE->RT_IMG_SIZE);
- printk("\t rt_src_addr 0x%08x\n", DE->RT_SRC_ADDR);
- printk("\t rt_src_stride 0x%08x\n", DE->RT_SRC_STRIDE);
- printk("\t rt_dst_addr 0x%08x\n", DE->RT_DST_ADDR);
- printk("\t rt_dst_stride 0x%08x\n", DE->RT_DST_STRIDE);
- printk("\t rt_start_height 0x%08x\n", DE->RT_START_HEIGHT);
- printk("\t rt_sw_x_xy 0x%08x\n", DE->RT_SW_X_XY);
- printk("\t rt_sw_y_xy 0x%08x\n", DE->RT_SW_Y_XY);
- printk("\t rt_sw_x0 0x%08x\n", DE->RT_SW_X0);
- printk("\t rt_sw_y0 0x%08x\n", DE->RT_SW_Y0);
- printk("\t rt_sw_first_dist 0x%08x\n", DE->RT_SW_FIRST_DIST);
- printk("\t rt_r1m2 0x%08x\n", DE->RT_R1M2);
- printk("\t rt_r0m2 0x%08x\n", DE->RT_R0M2);
- printk("\t rt_fill_color 0x%08x\n", DE->RT_FILL_COLOR);
- printk("\t rt_src_img_size 0x%08x\n", DE->RT_SRC_IMG_SIZE);
- #endif
- de_clk_set_en(false);
- }
- __de_func static void de_apply_overlay(struct de_data *data, struct de_command_entry *entry)
- {
- de_overlay_cfg_t *cfg = (de_overlay_cfg_t *)entry->cfg;
- display_rect_t area = {
- .x = cfg->x, .y = cfg->y,
- .w = cfg->w, .h = cfg->h,
- };
- int8_t idx;
- sys_trace_u32x3(SYS_TRACE_ID_DE_DRAW, entry->cmd, cfg->w, cfg->h);
- if (cfg->wb_addr == 0) {
- #if CONFIG_DE_RESET_DEV_AFTER_WB
- if (de_priv_data.last_ovl_is_wb) {
- de_priv_data.last_ovl_is_wb = false;
- de_reset(data);
- }
- #endif
- if (data->prepare_fn)
- data->prepare_fn(data->prepare_fn_arg, &area);
- } else {
- #if CONFIG_DE_RESET_DEV_AFTER_WB
- de_priv_data.last_ovl_is_wb = true;
- #endif
- DE->WB_MEM_ADR = cfg->wb_addr;
- DE->WB_MEM_STRIDE = cfg->wb_stride;
- }
- if (cfg->ctl & DE_CTL_OUT_COLOR_FILL_EN) {
- DE->FILL_COLOR = cfg->fill_color;
- DE->COLOR_FILL_POS = cfg->color_fill_pos;
- DE->COLOR_FILL_SIZE = cfg->color_fill_size;
- }
- /* set default bg */
- DE->CTL = cfg->ctl;
- DE->CTL1 = cfg->ctl1;
- DE->GAT_CTL = DE_OVERLAY_GAT_EN;
- DE->BG_COLOR = cfg->bg_color;
- DE->BG_SIZE = DE_BG_SIZE(cfg->w, cfg->h);
- DE->ALPHA_CTL = cfg->alpha_ctl;
- if (cfg->n_layers == 0) {
- goto out_exit;
- }
- #if 0
- if (cfg->blend_idx > 0) {
- /* keep the same as blend layer area */
- DE->ALPHA_POS = cfg->layers[cfg->blend_idx].pos;
- DE->ALPHA_SIZE = cfg->layers[cfg->blend_idx].size;
- }
- #else
- DE->ALPHA_SIZE = DE_BG_SIZE(cfg->w, cfg->h);
- #endif
- DE->LX_ABMP_CTL = cfg->lx_abmp_ctl;
- for (idx = 2; cfg->n_layers > 0; cfg->n_layers--, idx--) {
- DE_LX[idx]->POS = cfg->layers[idx].pos;
- DE_LX[idx]->SIZE = cfg->layers[idx].size;
- DE_LX[idx]->ADDR = cfg->layers[idx].addr;
- DE_LX[idx]->STRIDE = cfg->layers[idx].stride;
- DE_LX[idx]->LENGTH = cfg->layers[idx].length;
- DE_LX[idx]->DEF_COLOR = cfg->layers[idx].def_color;
- }
- /* only one rotation regs mapping */
- if (cfg->has_rotation) {
- DE_LX[2]->RT_SRC_SIZE = cfg->rotate.src_size;
- DE_LX[2]->RT_SW_X_XY = cfg->rotate.sw_x_xy;
- DE_LX[2]->RT_SW_Y_XY = cfg->rotate.sw_y_xy;
- DE_LX[2]->RT_SW_X0 = cfg->rotate.sw_x0;
- DE_LX[2]->RT_SW_Y0 = cfg->rotate.sw_y0;
- }
- if (cfg->has_scaling) {
- DE->SC_LX_SRC_IMG_SIZE = cfg->scaling.sc_lx_src_size;
- DE->SC_LX_RATE = cfg->scaling.sc_lx_rate;
- DE->SC_LX_POS = cfg->scaling.sc_lx_pos;
- }
- if (cfg->has_nor_access)
- de_set_nor_locked(true);
- out_exit:
- /*
- * sequence:
- * 1) modify configuration registers
- * 2) modify REG_UD=1
- * 3) modify EN=1
- * 4) make sure EN is really 1 (read and compare with 1)
- * 5) REG_UD becomes 0
- * 6) hw START
- **/
- DE->REG_UD = 1;
- if (DE->EN == 0) {
- if (data->display_sync_en == 0) {
- k_work_schedule(&data->timeout_work,
- K_MSEC(CONFIG_DISPLAY_ENGINE_COMMAND_TIMEOUT_MS));
- }
- DE->EN = 1;
- while (DE->EN == 0);
- /* REG_UD (active after EN) and CTL2 written must be close enough */
- DE->CTL2 = DE_CTL2_RGB_CVT_LOW | DE_CTL2_START;
- #if CONFIG_DE_USE_DEV_HALFULL == 0
- if (cfg->wb_addr == 0 && data->start_fn) {
- data->start_fn(data->start_fn_arg);
- }
- #endif /* CONFIG_DE_USE_DEV_HALFULL */
- }
- }
- __de_func static void de_apply_transform(struct de_data *data, struct de_command_entry *entry)
- {
- de_transform_cfg_t *cfg = (de_transform_cfg_t *)entry->cfg;
- sys_trace_u32x3(SYS_TRACE_ID_DE_DRAW, DE_CMD_ROTATE_CIRCLE,
- cfg->img_size & 0x1FF, (cfg->img_size >> 16) - cfg->start_height);
- DE->GAT_CTL = DE_ROTATE_GAT_EN;
- DE->EN = 1;
- DE->RT_DST_ADDR = cfg->dst_addr;
- DE->RT_DST_STRIDE = cfg->dst_stride;
- DE->RT_FILL_COLOR = cfg->fill_color;
- DE->RT_IMG_SIZE = cfg->img_size;
- if (entry->cmd != DE_CMD_ROTATE_FILL) {
- if (entry->cmd == DE_CMD_ROTATE_RECT) {
- DE->RT_SRC_IMG_SIZE = cfg->src_img_size;
- DE->RT_START_HEIGHT = 0;
- } else {
- DE->RT_R1M2 = cfg->r1m2;
- DE->RT_R0M2 = cfg->r0m2;
- DE->RT_SW_FIRST_DIST = cfg->sw_first_dist;
- DE->RT_START_HEIGHT = cfg->start_height;
- }
- DE->RT_SRC_ADDR = cfg->src_addr;
- DE->RT_SRC_STRIDE = cfg->src_stride;
- DE->RT_SW_X_XY = cfg->sw_x_xy;
- DE->RT_SW_Y_XY = cfg->sw_y_xy;
- DE->RT_SW_X0 = cfg->sw_x0;
- DE->RT_SW_Y0 = cfg->sw_y0;
- }
- k_work_schedule(&data->timeout_work,
- K_MSEC(CONFIG_DISPLAY_ENGINE_COMMAND_TIMEOUT_MS));
- DE->RT_CTL = cfg->ctl;
- }
- __de_func static void de_apply_clut(struct de_data *data, struct de_command_entry *entry)
- {
- de_clut_cfg_t *cfg = (de_clut_cfg_t *)entry->cfg;
- //DE->GAT_CTL = DE_OVERLAY_GAT_EN;
- //DE->LX_ABMP_CTL = BIT(3) | BIT(11) | BIT(19); /* all layer clut enabled */
- DE->CLUT_CTL = DE_CLUT_TAB_SEL(cfg->layer_idx) | DE_CLUT_TAB_IDX(0);
- for (; cfg->size > 0; cfg->size--) {
- DE->CLUT_DATA = *cfg->clut++;
- }
- //DE->GAT_CTL = 0;
- }
- __de_func static void de_process_next_cmd(struct de_data *data, bool skipped)
- {
- struct de_command_entry *entry;
- sys_snode_t *node = NULL;
- bool is_sw_cmd;
- do {
- is_sw_cmd = skipped;
- #ifdef CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE
- if (data->cmd_node) {
- node = sys_slist_peek_head(&data->high_cmd_list);
- if (node == data->cmd_node) {
- sys_slist_remove(&data->high_cmd_list, NULL, data->cmd_node);
- } else {
- assert(data->cmd_node == sys_slist_peek_head(&data->cmd_list));
- sys_slist_remove(&data->cmd_list, NULL, data->cmd_node);
- }
- data->cmd_num--;
- }
- #else /* CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE */
- if (data->cmd_node) {
- assert(data->cmd_node == sys_slist_peek_head(&data->cmd_list));
- sys_slist_remove(&data->cmd_list, NULL, data->cmd_node);
- data->cmd_num--;
- }
- #endif /* CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE */
- /* find and execute next command */
- #ifdef CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE
- node = sys_slist_peek_head(&data->high_cmd_list);
- if (!node)
- node = sys_slist_peek_head(&data->cmd_list);
- #else /* CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE */
- node = sys_slist_peek_head(&data->cmd_list);
- #endif /* CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE */
- /* unlock nor access */
- de_set_nor_locked(false);
- if (node) {
- if (data->cmd_node == NULL) /* new command from idle */
- de_clk_set_en(true);
- entry = CONTAINER_OF(node, struct de_command_entry, node);
- if (skipped == false) {
- switch (entry->cmd) {
- case DE_CMD_ROTATE_FILL:
- case DE_CMD_ROTATE_RECT:
- case DE_CMD_ROTATE_CIRCLE:
- de_apply_transform(data, entry);
- break;
- case DE_CMD_SET_CLUT:
- de_apply_clut(data, entry);
- data->cmd_status = 0;
- is_sw_cmd = true;
- break;
- default:
- de_apply_overlay(data, entry);
- break;
- }
- }
- } else { /* no more commands, become idle */
- de_clk_set_en(false);
- if (data->waiting) {
- data->waiting = 0;
- k_sem_give(&data->wait_sem);
- }
- }
- /* free previous command entry */
- if (data->cmd_node) {
- entry = CONTAINER_OF(data->cmd_node, struct de_command_entry, node);
- de_instance_notify(entry, data->cmd_status);
- de_instance_free_entry(entry);
- }
- /* point to the new command */
- data->cmd_node = node;
- } while (is_sw_cmd);
- }
- __de_func static void de_complete_cmd(struct de_data *data, int status)
- {
- sys_trace_end_call(SYS_TRACE_ID_DE_DRAW);
- if (data->display_sync_en == 0) {
- DE->EN = 0;
- DE->RT_CTL = RT_STAT_COMPLETE;
- DE->GAT_CTL = 0;
- }
- data->cmd_status = status;
- de_process_next_cmd(data, false);
- }
- static void de_cleanup_all_cmd(struct de_data *data)
- {
- unsigned int key = irq_lock();
- while (data->cmd_num > 0) {
- de_process_next_cmd(data, true);
- }
- irq_unlock(key);
- }
- __de_func static void de_append_cmd(struct de_data *data, struct de_command_entry *entry, bool high_prio)
- {
- unsigned int key = irq_lock();
- #ifdef CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE
- if (high_prio) {
- sys_slist_append(&data->high_cmd_list, &entry->node);
- } else {
- sys_slist_append(&data->cmd_list, &entry->node);
- }
- #else
- sys_slist_append(&data->cmd_list, &entry->node);
- #endif
- if (++data->cmd_num == 1) {
- de_process_next_cmd(data, false);
- }
- irq_unlock(key);
- }
- __de_func static int _validate_layers(const display_layer_t *layers, uint8_t num_ovls, bool *allow_ssaa)
- {
- bool has_rotation = false;
- bool has_scaling = false;
- uint8_t bpp;
- /* validate layer parameters */
- for (int i = 0; i < num_ovls; i++) {
- if (!layers[i].buffer) {
- continue;
- }
- if ((layers[i].buffer->desc.pixel_format & SUPPORTED_INPUT_PIXEL_FORMATS) == 0) {
- DEV_WRN("L%d format 0x%x unsupported\n", i, layers[i].buffer->desc.pixel_format);
- return -EINVAL;
- }
- if (layers[i].buffer->desc.width > MAX_WIDTH ||
- layers[i].buffer->desc.height > MAX_HEIGHT ||
- layers[i].buffer->desc.pitch > MAX_PITCH) {
- DEV_WRN("L%d size %dx%d pitch %d too large\n", i, layers[i].buffer->desc.width,
- layers[i].buffer->desc.height, layers[i].buffer->desc.pitch);
- return -EINVAL;
- }
- bpp = display_format_get_bits_per_pixel(layers[i].buffer->desc.pixel_format);
- if ((bpp == 16 && ((layers[i].buffer->addr & 0x1) || (layers[i].buffer->desc.pitch & 0x1))) ||
- (bpp == 32 && ((layers[i].buffer->addr & 0x3) || (layers[i].buffer->desc.pitch & 0x3)))) {
- DEV_WRN("L%d format 0x%x addr 0x%x pitch %d unaligned\n", i,
- layers[i].buffer->desc.pixel_format, layers[i].buffer->addr,
- layers[i].buffer->desc.pitch);
- return -EINVAL;
- }
- if (layers[i].frame.w <= 0 || layers[i].frame.w > MAX_WIDTH ||
- layers[i].frame.h <= 0 || layers[i].frame.h > MAX_HEIGHT) {
- DEV_WRN("L%d size %u x %u invalid\n", i, layers[i].frame.w, layers[i].frame.h);
- return -EINVAL;
- }
- if (layers[i].matrix) {
- if (has_rotation || (i == 0 && num_ovls >= 3)) {
- DEV_WRN("L%d already has or unsupport rotation\n", i);
- return -EINVAL;
- }
- if ((layers[i].buffer->desc.pixel_format & SUPPORTED_ROTATE_PIXEL_FORMATS) == 0) {
- DEV_WRN("L%d format 0x%x not support rotation\n", i, layers[i].buffer->desc.pixel_format);
- return -EINVAL;
- }
- has_rotation = true;
- /* no need to check scaling */
- continue;
- }
- if (layers[i].frame.w != layers[i].buffer->desc.width ||
- layers[i].frame.h != layers[i].buffer->desc.height) {
- if (has_scaling || (i == 0 && num_ovls >= 3)) {
- DEV_WRN("L%d already has or unsupport scaling\n", i);
- return -EINVAL;
- }
- if ((layers[i].buffer->desc.pixel_format & SUPPORTED_SCALING_PIXEL_FORMATS) == 0) {
- DEV_WRN("L%d format 0x%x not support scaling\n", i, layers[i].buffer->desc.pixel_format);
- return -EINVAL;
- }
- /* only need to check scaling down factor */
- if (layers[i].frame.w * 15 < layers[i].buffer->desc.width ||
- layers[i].frame.h * 15 < layers[i].buffer->desc.height) {
- DEV_WRN("L%d scaling exceed [1/15, 4096]: (%u, %u) -> (%u, %u)\n", i,
- layers[i].buffer->desc.width, layers[i].buffer->desc.height,
- layers[i].frame.w, layers[i].frame.h);
- return -EINVAL;
- }
- if (layers[i].buffer->desc.pixel_format & ABMP_BITS_PIXEL_FORMATS) {
- uint16_t width_bits = layers[i].buffer->desc.width * bpp;
- if (layers[i].buffer->desc.pitch == 0 && (width_bits & 0x7)) {
- DEV_WRN("L%d format %x not support both scaling and no-stride\n", i,
- layers[i].buffer->desc.pixel_format);
- return -EINVAL;
- }
- }
- has_scaling = true;
- }
- if (layers[i].buffer->desc.pixel_format & ABMP_BITS_PIXEL_FORMATS) {
- if (layers[i].buffer->px_ofs * bpp >= 8 ||
- (layers[i].buffer->px_ofs > 0 && layers[i].buffer->desc.pitch == 0)) {
- DEV_WRN("L%d format %x px_ofs %u invalid\n", i,
- layers[i].buffer->desc.pixel_format, layers[i].buffer->px_ofs);
- return -EINVAL;
- }
- }
- }
- #if CONFIG_DE_ALPHA_SSAA
- *allow_ssaa = !has_scaling;
- #endif
- return 0;
- }
- __de_func static void _config_layer_scaling(de_overlay_cfg_t *cfg, const display_layer_t *layer, uint8_t idx)
- {
- uint16_t x_off = 0;
- uint16_t y_off = 0;
- uint16_t h_rate = 4096, v_rate = 4096;
- if (layer->buffer->desc.width == layer->frame.w && layer->buffer->desc.height == layer->frame.h) {
- x_off = 1024; /* SSAA: offset 1/4 pixel */
- y_off = 1024;
- } else {
- if (layer->frame.w > 1)
- h_rate = ((layer->buffer->desc.width - 1) * 4096 - x_off) / (layer->frame.w - 1);
- if (layer->frame.h > 1)
- v_rate = ((layer->buffer->desc.height - 1) * 4096 - y_off) / (layer->frame.h - 1);
- }
- cfg->scaling.sc_lx_rate = SC_LX_RATE(h_rate, v_rate);
- cfg->scaling.sc_lx_src_size = SC_LX_SRC_IMG_SIZE(layer->buffer->desc.width, layer->buffer->desc.height);
- cfg->scaling.sc_lx_pos = SC_LX_POS(x_off, y_off);
- cfg->has_scaling = 1;
- }
- __de_func static void _config_layer_rotation(de_overlay_cfg_t *cfg, const display_layer_t *layer,
- uint8_t idx, uint8_t bpp, bool y_flip)
- {
- const display_matrix_t *matrix = layer->matrix;
- const display_buffer_t *buffer = layer->buffer;
- int32_t pitch = GUESS_PITCH(buffer, bpp);
- if (y_flip) {
- cfg->rotate.sw_x0 = matrix->tx + (layer->frame.h - 1) * matrix->shx;
- cfg->rotate.sw_y0 = matrix->ty + (layer->frame.h - 1) * matrix->sy;
- cfg->rotate.sw_y_xy = DE_LX_RT_DELTA_XY(-matrix->shx, -matrix->sy);
- } else {
- cfg->rotate.sw_x0 = matrix->tx;
- cfg->rotate.sw_y0 = matrix->ty;
- cfg->rotate.sw_y_xy = DE_LX_RT_DELTA_XY(matrix->shx, matrix->sy);
- }
- cfg->rotate.sw_x_xy = DE_LX_RT_DELTA_XY(matrix->sx, matrix->shy);
- cfg->layers[idx].addr += (cfg->rotate.sw_y0 >> 12) * pitch +
- (cfg->rotate.sw_x0 >> 12) * bpp / 8;
- cfg->rotate.src_size = DE_LX_RT_SRC_SIZE(buffer->desc.width, buffer->desc.height);
- cfg->has_rotation = 1;
- }
- __de_func static void _config_layers(de_overlay_cfg_t *cfg, const display_layer_t *layer,
- uint8_t idx, bool y_flip, bool allow_ssaa)
- {
- static const struct {
- uint32_t pixel_format;
- uint32_t lx_format[3];
- uint32_t abmp_format[3];
- uint8_t bpp;
- } layer_formats[] = {
- {
- PIXEL_FORMAT_ARGB_8888,
- { DE_L0_FORMAT_ARGB_8888, DE_L1_FORMAT_ARGB_8888, DE_L2_FORMAT_ARGB_8888 },
- { 0, 0, 0 }, 32,
- },
- {
- PIXEL_FORMAT_XRGB_8888,
- { DE_L0_FORMAT_XRGB_8888, DE_L1_FORMAT_XRGB_8888, DE_L2_FORMAT_XRGB_8888 },
- { 0, 0, 0 }, 32,
- },
- {
- PIXEL_FORMAT_BGRA_5658,
- { DE_L0_FORMAT_ARGB_8565, DE_L1_FORMAT_ARGB_8565, DE_L2_FORMAT_ARGB_8565 },
- { 0, 0, 0 }, 24,
- },
- {
- PIXEL_FORMAT_BGRA_6666,
- { DE_L0_FORMAT_ARGB_6666, DE_L1_FORMAT_ARGB_6666, DE_L2_FORMAT_ARGB_6666 },
- { 0, 0, 0 }, 24,
- },
- {
- PIXEL_FORMAT_RGBA_6666,
- { DE_L0_FORMAT_ABGR_6666, DE_L1_FORMAT_ABGR_6666, DE_L2_FORMAT_ABGR_6666 },
- { 0, 0, 0 }, 24,
- },
- {
- PIXEL_FORMAT_BGR_565,
- { DE_L0_FORMAT_RGB_565, DE_L1_FORMAT_RGB_565, DE_L2_FORMAT_RGB_565 },
- { 0, 0, 0 }, 16,
- },
- {
- PIXEL_FORMAT_RGB_565,
- { DE_L0_FORMAT_RGB_565_SWAP, DE_L1_FORMAT_RGB_565_SWAP, DE_L2_FORMAT_RGB_565_SWAP },
- { 0, 0, 0 }, 16,
- },
- {
- PIXEL_FORMAT_RGB_888,
- { DE_L0_FORMAT_RGB_888, DE_L1_FORMAT_RGB_888, DE_L2_FORMAT_RGB_888 },
- { 0, 0, 0 }, 24,
- },
- {
- PIXEL_FORMAT_BGR_888,
- { DE_L0_FORMAT_BGR_888, DE_L1_FORMAT_BGR_888, DE_L2_FORMAT_BGR_888 },
- { 0, 0, 0 }, 24,
- },
- {
- PIXEL_FORMAT_BGRA_5551,
- { DE_L0_FORMAT_ARGB_1555, DE_L1_FORMAT_ARGB_1555, DE_L2_FORMAT_ARGB_1555 },
- { 0, 0, 0 }, 16,
- },
- {
- PIXEL_FORMAT_I8,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_INDEX_8, DE_L1_INDEX_8, DE_L2_INDEX_8 },
- 8,
- },
- {
- PIXEL_FORMAT_I4,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_INDEX_4, DE_L1_INDEX_4, DE_L2_INDEX_4 },
- 4,
- },
- {
- PIXEL_FORMAT_I2,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_INDEX_2, DE_L1_INDEX_2, DE_L2_INDEX_2 },
- 2,
- },
- {
- PIXEL_FORMAT_I1,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_INDEX_1, DE_L1_INDEX_1, DE_L2_INDEX_1 },
- 1,
- },
- {
- PIXEL_FORMAT_A8,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_8, DE_L1_ALPHA_8, DE_L2_ALPHA_8 },
- 8,
- },
- {
- PIXEL_FORMAT_A4,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_4, DE_L1_ALPHA_4, DE_L2_ALPHA_4 },
- 4,
- },
- {
- PIXEL_FORMAT_A2,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_2, DE_L1_ALPHA_2, DE_L2_ALPHA_2 },
- 2,
- },
- {
- PIXEL_FORMAT_A1,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_1, DE_L1_ALPHA_1, DE_L2_ALPHA_1 },
- 1,
- },
- {
- PIXEL_FORMAT_A4_LE,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_4_LE, DE_L1_ALPHA_4_LE, DE_L2_ALPHA_4_LE },
- 4,
- },
- {
- PIXEL_FORMAT_A1_LE,
- { DE_L0_FORMAT_ABMP_INDEX, DE_L1_FORMAT_ABMP_INDEX, DE_L2_FORMAT_ABMP_INDEX },
- { DE_L0_ALPHA_1_LE, DE_L1_ALPHA_1_LE, DE_L2_ALPHA_1_LE },
- 1,
- },
- };
- const display_buffer_t *buffer = layer->buffer;
- bool has_transform = false;
- uint32_t lx_format = 0;
- uint32_t abmp_format = 0;
- uint8_t fill_en = 0;
- uint8_t no_stride_en = 0;
- uint8_t abmp_bitofs = 0;
- uint8_t i;
- if (buffer) {
- uint16_t pitch_bits, width_bits;
- for (i = 0; i < ARRAY_SIZE(layer_formats); i++) {
- if (buffer->desc.pixel_format == layer_formats[i].pixel_format) {
- break;
- }
- }
- __ASSERT(i < ARRAY_SIZE(layer_formats), "format 0x%x support not added", buffer->desc.pixel_format);
- if (i >= ARRAY_SIZE(layer_formats)) { /* Make Klocwork Static Code check happpy */
- k_panic();
- return;
- }
- lx_format = layer_formats[i].lx_format[idx];
- abmp_format = layer_formats[i].abmp_format[idx];
- has_transform = layer->matrix || (buffer->desc.width != layer->frame.w) ||
- (buffer->desc.height != layer->frame.h);
- if ((buffer->desc.pixel_format & ABMP_BITS_PIXEL_FORMATS))
- abmp_bitofs = buffer->px_ofs * layer_formats[i].bpp;
- width_bits = buffer->desc.width * layer_formats[i].bpp;
- pitch_bits = (buffer->desc.pitch > 0) ? (buffer->desc.pitch * 8) : width_bits;
- #if CONFIG_DE_ALPHA_SSAA
- if (!has_transform && (buffer->desc.pixel_format & SSAA_PIXEL_FORMATS)) {
- if (allow_ssaa && !cfg->has_scaling && idx > 0 && !(pitch_bits & 0x7)) {
- has_transform = true;
- }
- }
- #endif
- no_stride_en = (!y_flip && !has_transform && pitch_bits == width_bits && abmp_bitofs == 0);
- cfg->lx_abmp_ctl |= abmp_format;
- if (buf_is_nor((void *)buffer->addr)) {
- cfg->has_nor_access = 1;
- cfg->layers[idx].addr = (uint32_t)cache_to_uncache_by_master(
- (void *)buffer->addr, SPI0_CACHE_MASTER_DE);
- } else {
- cfg->layers[idx].addr = (uint32_t)cache_to_uncache((void *)buffer->addr);
- }
- cfg->layers[idx].stride = pitch_bits / 8; /* only used by stride mode */
- cfg->layers[idx].length = ((uint32_t)pitch_bits * buffer->desc.height + 7) / 8; /* only used by no-stride mode */
- cfg->layers[idx].def_color = (layer->color.full & 0xFFFFFF); /* donot double use the alpha for the global alpha */
- } else {
- fill_en = 1;
- cfg->layers[idx].addr = 0;
- cfg->layers[idx].def_color = layer->color.full;
- }
- if (idx == 0) {
- cfg->lx_abmp_ctl |= DE_L0_ABMP_BITOFS(abmp_bitofs);
- cfg->ctl |= DE_L0_EN | lx_format | DE_L0_NO_STRIDE_EN(no_stride_en) | DE_L0_COLOR_FILL_EN(fill_en);
- } else {
- if (idx == 1) {
- cfg->lx_abmp_ctl |= DE_L1_ABMP_BITOFS(abmp_bitofs);
- cfg->ctl |= DE_L1_EN | lx_format | DE_L1_NO_STRIDE_EN(no_stride_en) | DE_L1_COLOR_FILL_EN(fill_en);
- if (has_transform)
- cfg->ctl |= layer->matrix ? DE_L1_RT_EN : DE_L1_SC_EN;
- } else {
- cfg->lx_abmp_ctl |= DE_L2_ABMP_BITOFS(abmp_bitofs);
- cfg->ctl1 = DE_L2_EN | lx_format | DE_L2_NO_STRIDE_EN(no_stride_en) | DE_L2_COLOR_FILL_EN(fill_en);
- if (has_transform)
- cfg->ctl1 |= layer->matrix ? DE_L2_RT_EN : DE_L2_SC_EN;
- }
- /* configure blending */
- if (layer->blending != DISPLAY_BLENDING_NONE) {
- if (cfg->blend_idx == 0) {
- uint32_t alpha_mode = (layer->blending == DISPLAY_BLENDING_PREMULT) ?
- DE_ALPHA_PREMULTIPLIED : DE_ALPHA_COVERAGE;
- /* don't double use the color alpha */
- uint8_t alpha = buffer ? layer->color.a : 255;
- /* DE will only blend the pixels both inside ALPHA_AREA and L0 & L1 & L2 */
- cfg->alpha_ctl = DE_ALPHA_EN | alpha_mode | DE_ALPHA_PLANE_ALPHA(alpha);
- cfg->blend_idx = idx;
- }
- }
- }
- if (y_flip) {
- cfg->layers[idx].pos = DE_LX_POS(layer->frame.x - cfg->x,
- cfg->h - (layer->frame.y - cfg->y) - layer->frame.h);
- if (buffer && layer->matrix == NULL) {
- cfg->layers[idx].addr += cfg->layers[idx].stride * (buffer->desc.height - 1);
- }
- } else {
- cfg->layers[idx].pos = DE_LX_POS(layer->frame.x - cfg->x, layer->frame.y - cfg->y);
- }
- cfg->layers[idx].size = DE_LX_SIZE(layer->frame.w, layer->frame.h);
- if (has_transform) {
- if (layer->matrix) {
- _config_layer_rotation(cfg, layer, idx, layer_formats[i].bpp, y_flip);
- } else {
- _config_layer_scaling(cfg, layer, idx);
- }
- }
- }
- __de_func static void _config_overlay_output(struct de_data *data, de_overlay_cfg_t *cfg,
- const display_buffer_t *dest,
- struct display_rect *area, bool y_flip)
- {
- uint32_t out_format;
- if (dest) {
- uint8_t bytes_per_pixel = display_format_get_bits_per_pixel(dest->desc.pixel_format) / 8;
- uint16_t pitch = GUESS_PITCH_BYTES(dest, bytes_per_pixel);
- uint8_t no_stride_en = 0;
- cfg->wb_stride = pitch;
- cfg->wb_addr = dest->addr + area->y * cfg->wb_stride + area->x * bytes_per_pixel;
- cfg->wb_addr = (uint32_t)cache_to_uncache((void *)cfg->wb_addr);
- if (y_flip) {
- cfg->wb_addr += cfg->wb_stride * (area->h - 1);
- } else {
- /* no-stride requires both the address and stride 4-byte aligned */
- no_stride_en = !(cfg->wb_addr & 0x3) && !(cfg->wb_stride & 0x3) &&
- (cfg->wb_stride == area->w * bytes_per_pixel);
- }
- cfg->ctl = DE_CTL_TRANSFER_MODE_TRIGGER | DE_CTL_OUT_MODE_WB |
- DE_CTL_WB_NO_STRIDE_EN(no_stride_en) | DE_CTL_OUT_WB_YFLIP_EN(y_flip);
- out_format = dest->desc.pixel_format;
- } else {
- cfg->wb_addr = 0; /* flag */
- cfg->ctl = DE_CTL_OUT_MODE_DISPLAY | (data->display_sync_en ?
- DE_CTL_TRANSFER_MODE_CONTINUE : DE_CTL_TRANSFER_MODE_TRIGGER) |
- DE_CTL_OUT_DISPLY_YFLIP_EN(y_flip);
- out_format = data->display_format;
- }
- switch (out_format) {
- case PIXEL_FORMAT_BGR_565:
- cfg->ctl |= DE_CTL_OUT_FORMAT_RGB565;
- break;
- case PIXEL_FORMAT_ARGB_8888:
- cfg->ctl |= DE_CTL_OUT_FORMAT_RGB888_WB_ARGB8888;
- break;
- case PIXEL_FORMAT_XRGB_8888:
- cfg->ctl |= DE_CTL_OUT_FORMAT_RGB888_WB_XRGB8888;
- break;
- case PIXEL_FORMAT_RGB_888:
- default:
- cfg->ctl |= DE_CTL_OUT_FORMAT_RGB888;
- break;
- }
- /* set default bg */
- cfg->w = area->w;
- cfg->h = area->h;
- }
- __de_func static int de_insert_overlay_cmd(const struct device *dev, int inst,
- const display_buffer_t *dest,
- const display_layer_t *layers, uint8_t num_ovls,
- uint8_t cmd)
- {
- struct de_data *data = dev->data;
- struct de_command_entry *entry;
- de_overlay_cfg_t *cfg;
- struct display_rect dest_rect;
- int8_t top_idx = num_ovls - 1;
- /* FIXME: writeback never uses y-flip ? */
- bool wb_y_flip = dest ? CONFIG_DE_WB_Y_FLIP : false;
- bool dev_y_flip = dest ? false : CONFIG_DE_DEV_Y_FLIP;
- bool allow_ssaa = false; /* using bilinear interpolation */
- int i;
- if (sizeof(de_overlay_cfg_t) > sizeof(((struct de_command_entry *)0)->cfg)) {
- DEV_ERR("must increase command cfg size to %u\n", sizeof(de_overlay_cfg_t));
- return -ENOMEM;
- }
- if (dest != NULL && data->op_mode != DISPLAY_ENGINE_MODE_DEFAULT) {
- DEV_WRN("de display-only\n");
- return -EBUSY;
- }
- if (_validate_layers(layers, num_ovls, &allow_ssaa)) {
- return -EINVAL;
- }
- /* validate dest area */
- memcpy(&dest_rect, &layers[0].frame, sizeof(dest_rect));
- for (i = 1; i < num_ovls; i++) {
- display_rect_merge(&dest_rect, &layers[i].frame);
- }
- if (display_rect_get_width(&dest_rect) < MIN_WB_WIDTH) {
- DEV_INF("bg width less than 2\n");
- return -EINVAL;
- }
- /* validate dest parameters */
- if (dest) {
- if ((dest->desc.pixel_format & SUPPORTED_OUTPUT_PIXEL_FORMATS) == 0) {
- DEV_WRN("dest format 0x%x unsupported\n", dest->desc.pixel_format);
- return -EINVAL;
- }
- if (dest->desc.width > MAX_WIDTH || dest->desc.height > MAX_HEIGHT || dest->desc.pitch > MAX_PITCH) {
- DEV_WRN("dest size %dx%d pitch %d too large\n", dest->desc.width,
- dest->desc.height, dest->desc.pitch);
- return -EINVAL;
- }
- } else {
- if (data->display_format == 0) {
- DEV_WRN("display mode not configured\n");
- return -EINVAL;
- }
- }
- entry = de_instance_alloc_entry(inst);
- if (!entry)
- return -EBUSY;
- cfg = (de_overlay_cfg_t *)entry->cfg;
- cfg->x = dest_rect.x;
- cfg->y = dest_rect.y;
- cfg->n_layers = 0;
- cfg->blend_idx = 0;
- cfg->has_rotation = 0;
- cfg->has_scaling = 0;
- cfg->has_nor_access = 0;
- cfg->bg_color = 0;
- cfg->ctl1 = 0;
- cfg->alpha_ctl = 0;
- cfg->lx_abmp_ctl = DE_LX_AA_P0_COFF_3_4;
- _config_overlay_output(data, cfg, dest, &dest_rect, wb_y_flip || dev_y_flip);
- /* 1 fill color layer */
- if (layers[top_idx].buffer == NULL &&
- (top_idx == 0 || layers[top_idx].blending == DISPLAY_BLENDING_NONE)) {
- cfg->ctl |= DE_CTL_OUT_COLOR_FILL_EN;
- cfg->fill_color = layers[top_idx].color.full;
- if (dev_y_flip) {
- cfg->color_fill_pos = DE_COLOR_FILL_POS(layers[top_idx].frame.x - dest_rect.x,
- cfg->h - (layers[top_idx].frame.y - dest_rect.y) - layers[top_idx].frame.h);
- } else {
- cfg->color_fill_pos = DE_COLOR_FILL_POS(layers[top_idx].frame.x - dest_rect.x,
- layers[top_idx].frame.y - dest_rect.y);
- }
- cfg->color_fill_size = DE_COLOR_FILL_SIZE(
- layers[top_idx].frame.w, layers[top_idx].frame.h);
- if (--top_idx < 0)
- goto out_exit;
- }
- /* 1 background layer */
- if (layers[0].buffer == NULL &&
- (top_idx == 0 || layers[1].blending == DISPLAY_BLENDING_NONE)) {
- cfg->bg_color = layers[0].color.full;
- layers++;
- if (--top_idx < 0)
- goto out_exit;
- }
- for (int8_t layer_idx = 2; layer_idx >= 0 && top_idx >= 0; top_idx--, layer_idx--) {
- _config_layers(cfg, &layers[top_idx], layer_idx, dev_y_flip, allow_ssaa);
- cfg->n_layers++;
- }
- if (cfg->blend_idx > 0 && dest == NULL)
- cfg->alpha_ctl |= DE_ALPHA_FCV_EN;
- out_exit:
- entry->cmd = cmd;
- de_append_cmd(data, entry, de_instance_has_flag(inst, DISPLAY_ENGINE_FLAG_HIGH_PRIO));
- return entry->seq;
- }
- __de_func static int de_fill(const struct device *dev, int inst, const display_buffer_t *dest,
- display_color_t color)
- {
- struct de_data *data = dev->data;
- display_layer_t layer = {
- .buffer = NULL,
- .color = color,
- .frame = (display_rect_t) { 0, 0, dest->desc.width, dest->desc.height },
- };
- if (data->op_mode != DISPLAY_ENGINE_MODE_DEFAULT) {
- DEV_WRN("de display-only\n");
- return -EBUSY;
- }
- if (dest->desc.pixel_format == PIXEL_FORMAT_BGR_565) {
- uint16_t pitch;
- if (dest->desc.width < 2 || (dest->desc.pitch & 0x1)) {
- DEV_INF("fill width less than 2\n");
- return -EINVAL;
- }
- pitch = GUESS_PITCH_BYTES(dest, 2);
- if (!(pitch & 0x3) && !(dest->addr & 0x3) &&
- !(dest->desc.width & 0x1) && (dest->desc.width >= MIN_WB_WIDTH * 2)) {
- display_buffer_t dest_argb8888 = {
- .addr = dest->addr,
- .desc = {
- .pixel_format = PIXEL_FORMAT_ARGB_8888,
- .width = dest->desc.width / 2,
- .height = dest->desc.height,
- .pitch = pitch,
- },
- };
- layer.frame.w = dest_argb8888.desc.width;
- layer.color.c16[0] = ((color.r & 0xf8) << 8) | ((color.g & 0xfc) << 3) | (color.b >> 3);
- layer.color.c16[1] = layer.color.c16[0];
- return de_insert_overlay_cmd(dev, inst, &dest_argb8888, &layer, 1, DE_CMD_FILL);
- }
- /* BUGFIX: cannot access crossing RAM9 and RAM10 (0x30000000 - ?) */
- uint32_t dst_end = dest->addr + (dest->desc.height - 1) * pitch + dest->desc.width * 2;
- if (dest->addr >= 0x30000000 || dst_end <= 0x30000000) {
- struct de_command_entry *entry = de_instance_alloc_entry(inst);
- if (!entry)
- return -EBUSY;
- de_transform_cfg_t *cfg = (de_transform_cfg_t *)entry->cfg;
- cfg->img_size = RT_IMG_WIDTH(dest->desc.width) | RT_END_HEIGHT(dest->desc.height);
- cfg->dst_addr = (uint32_t)cache_to_uncache((void *)dest->addr);
- cfg->dst_stride = pitch;
- cfg->fill_color = RT_COLOR_RGB_565(color.r, color.g, color.b);
- cfg->ctl = RT_EN | RT_IRQ_EN | RT_COLOR_FILL_START | RT_COLOR_FILL_BURST_16;
- entry->cmd = DE_CMD_ROTATE_FILL;
- de_append_cmd(data, entry, de_instance_has_flag(inst, DISPLAY_ENGINE_FLAG_HIGH_PRIO));
- return entry->seq;
- }
- }
- return de_insert_overlay_cmd(dev, inst, dest, &layer, 1, DE_CMD_FILL);
- }
- __de_func static int de_blit(const struct device *dev, int inst, const display_buffer_t *dest,
- const display_buffer_t *src)
- {
- display_layer_t layer = {
- .buffer = src,
- .color = { .a = 0xff, .r = 0, .g = 0, .b = 0, },
- .frame = { 0, 0, dest->desc.width, dest->desc.height },
- };
- return de_insert_overlay_cmd(dev, inst, dest, &layer, 1, DE_CMD_BLIT);
- }
- __de_func static int de_blend(const struct device *dev, int inst, const display_buffer_t *dest,
- const display_buffer_t *fg, display_color_t fg_color,
- const display_buffer_t *bg, display_color_t bg_color)
- {
- display_layer_t layers[2] = {
- {
- .buffer = bg,
- .color = bg_color,
- .frame = { 0, 0, dest->desc.width, dest->desc.height },
- },
- {
- .buffer = fg,
- .color = fg_color,
- .blending = DISPLAY_BLENDING_COVERAGE,
- .frame = { 0, 0, dest->desc.width, dest->desc.height },
- },
- };
- return de_insert_overlay_cmd(dev, inst, dest, layers, 2, fg ? DE_CMD_BLEND : DE_CMD_BLEND_FG);
- }
- __de_func static int de_compose(const struct device *dev, int inst, const display_buffer_t *dest,
- const display_layer_t *layers, int num_ovls)
- {
- uint8_t cmd = dest ? DE_CMD_COMPOSE_WB : DE_CMD_COMPOSE;
- if (num_ovls > MAX_NUM_OVERLAYS || num_ovls <= 0) {
- DEV_WRN("unsupported ovl num %d\n", num_ovls);
- return -EINVAL;
- }
- return de_insert_overlay_cmd(dev, inst, dest, layers, num_ovls, cmd);
- }
- __de_func static int de_transform(const struct device *dev, int inst, const display_buffer_t *dest,
- const display_buffer_t *src,
- const display_engine_transform_param_t *param)
- {
- struct de_data *data = dev->data;
- struct de_command_entry *entry;
- de_transform_cfg_t *cfg;
- uint8_t bytes_per_pixel;
- if (data->op_mode != DISPLAY_ENGINE_MODE_DEFAULT) {
- DEV_WRN("de display-only\n");
- return -EBUSY;
- }
- if ((src->desc.pixel_format & SUPPORTED_ROTATE_PIXEL_FORMATS) == 0) {
- DEV_WRN("unsupported rotation format %u\n", src->desc.pixel_format);
- return -EINVAL;
- }
- if (param->is_circle) {
- if (src->desc.pixel_format != PIXEL_FORMAT_BGR_565 || (src->desc.width & 0x1)) {
- DEV_WRN("src width %d and format 0x%x must meet circle rotation\n",
- src->desc.width, src->desc.pixel_format);
- return -EINVAL;
- }
- if (src->desc.pixel_format != dest->desc.pixel_format ||
- src->desc.width != dest->desc.width ||
- src->desc.width != src->desc.height) {
- DEV_WRN("src and dest must meet circle rotation\n");
- return -EINVAL;
- }
- if (param->circle.line_start + dest->desc.height > src->desc.width) {
- DEV_WRN("circle rotation line range exceed\n");
- return -EINVAL;
- }
- } else {
- bool use_layer = param->blend_en || (src->desc.pixel_format != dest->desc.pixel_format) ||
- (src->desc.pixel_format != PIXEL_FORMAT_BGR_565) || (dest->desc.width & 0x1);
- if (use_layer) {
- display_layer_t layers[2] = {
- {
- .buffer = dest,
- .frame = { 0, 0, dest->desc.width, dest->desc.height },
- },
- {
- .buffer = src,
- .blending = param->blend_en ? DISPLAY_BLENDING_COVERAGE : DISPLAY_BLENDING_NONE,
- .frame = { 0, 0, dest->desc.width, dest->desc.height },
- .matrix = ¶m->matrix,
- .color = param->color,
- },
- };
- return de_insert_overlay_cmd(dev, inst, dest, layers, 2, DE_CMD_BLEND);
- }
- }
- entry = de_instance_alloc_entry(inst);
- if (!entry)
- return -EBUSY;
- cfg = (de_transform_cfg_t *)entry->cfg;
- if (param->is_circle) {
- uint16_t outer_diameter = src->desc.width - 1;
- cfg->start_height = param->circle.line_start;
- cfg->r1m2 = param->circle.outer_radius_sq;
- cfg->r0m2 = param->circle.inner_radius_sq;
- cfg->sw_first_dist = outer_diameter * outer_diameter +
- (outer_diameter - 2 * param->circle.line_start) *
- (outer_diameter - 2 * param->circle.line_start);
- cfg->ctl = RT_MODE_CIRCLE | RT_EN | RT_IRQ_EN | RT_FILTER_BILINEAR | RT_COLOR_FILL_BURST_16;
- } else {
- cfg->start_height = 0;
- cfg->src_img_size = RT_SRC_IMG_SIZE(src->desc.width, src->desc.height);
- cfg->ctl = RT_MODE_RECT | RT_EN | RT_IRQ_EN | RT_FILTER_BILINEAR | RT_COLOR_FILL_BURST_16;
- }
- cfg->img_size = RT_IMG_WIDTH(dest->desc.width) |
- RT_END_HEIGHT(cfg->start_height + dest->desc.height);
- cfg->sw_x0 = param->matrix.tx;
- cfg->sw_y0 = param->matrix.ty;
- cfg->sw_x_xy = RT_SW_DELTA_XY(param->matrix.sx, param->matrix.shy);
- cfg->sw_y_xy = RT_SW_DELTA_XY(param->matrix.shx, param->matrix.sy);
- bytes_per_pixel = display_format_get_bits_per_pixel(src->desc.pixel_format) / 8;
- cfg->src_stride = GUESS_PITCH_BYTES(src, bytes_per_pixel);
- cfg->src_addr = buf_is_nor((void *)src->addr) ?
- (uint32_t)cache_to_uncache_by_master((void *)src->addr, SPI0_CACHE_MASTER_DE) :
- (uint32_t)cache_to_uncache((void *)src->addr);
- cfg->src_addr += (cfg->sw_y0 >> 12) * (int32_t)cfg->src_stride + (cfg->sw_x0 >> 12) * bytes_per_pixel;
- cfg->dst_stride = GUESS_PITCH_BYTES(dest, bytes_per_pixel);
- cfg->dst_addr = (uint32_t)cache_to_uncache((void *)dest->addr);
- cfg->fill_color = param->color.full & 0xFFFFFF;
- if (src->desc.pixel_format == PIXEL_FORMAT_BGR_565) {
- cfg->ctl |= RT_FORMAT_RGB565 | RT_COLOR_FILL_EN;
- } else {
- cfg->ctl |= RT_FORMAT_ARGB8888 | RT_COLOR_FILL_EN;
- }
- entry->cmd = param->is_circle ? DE_CMD_ROTATE_CIRCLE : DE_CMD_ROTATE_RECT;
- de_append_cmd(data, entry, de_instance_has_flag(inst, DISPLAY_ENGINE_FLAG_HIGH_PRIO));
- return entry->seq;
- }
- __de_func static int de_set_clut(const struct device *dev, int inst, uint16_t layer_idx,
- uint16_t size, const uint32_t *clut)
- {
- struct de_data *data = dev->data;
- struct de_command_entry *entry;
- de_clut_cfg_t *cfg;
- if (data->op_mode != DISPLAY_ENGINE_MODE_DEFAULT) {
- DEV_WRN("de display-only\n");
- return -EBUSY;
- }
- if (clut == NULL || layer_idx >= 3/*MAX_NUM_OVERLAYS*/ || size > 256) {
- DEV_WRN("invalid clut %p, idx %d, size %u\n", clut, layer_idx, size);
- return -EINVAL;
- }
- entry = de_instance_alloc_entry(inst);
- if (!entry)
- return -EBUSY;
- cfg = (de_clut_cfg_t *)entry->cfg;
- cfg->layer_idx = layer_idx;
- cfg->size = size;
- cfg->clut = clut;
- entry->cmd = DE_CMD_SET_CLUT;
- de_append_cmd(data, entry, de_instance_has_flag(inst, DISPLAY_ENGINE_FLAG_HIGH_PRIO));
- return entry->seq;
- }
- static int de_poll(const struct device *dev, int inst, int timeout_ms)
- {
- if (inst >= 0) {
- return de_instance_poll(inst, timeout_ms);
- }
- return -EINVAL;
- }
- static int de_register_callback(const struct device *dev,
- int inst, display_engine_instance_callback_t callback, void *user_data)
- {
- struct de_data *data = dev->data;
- int res;
- k_mutex_lock(&data->mutex, K_FOREVER);
- res = de_instance_register_callback(inst, callback, user_data);
- k_mutex_unlock(&data->mutex);
- return res;
- }
- static void de_get_capabilities(const struct device *dev,
- struct display_engine_capabilities *capabilities)
- {
- capabilities->max_width = MAX_WIDTH;
- capabilities->max_height = MAX_HEIGHT;
- capabilities->max_pitch = MAX_PITCH;
- capabilities->num_overlays = 3;/*MAX_NUM_OVERLAYS*/;
- capabilities->support_fill = 1;
- capabilities->support_blend = 1;
- capabilities->support_blend_fg = 1;
- capabilities->support_blend_bg = 0;
- capabilities->supported_output_pixel_formats = SUPPORTED_OUTPUT_PIXEL_FORMATS;
- capabilities->supported_input_pixel_formats = SUPPORTED_INPUT_PIXEL_FORMATS;
- capabilities->supported_rotate_pixel_formats = SUPPORTED_ROTATE_PIXEL_FORMATS;
- }
- static int de_control(const struct device *dev, int cmd, void *arg1, void *arg2)
- {
- struct de_data *data = dev->data;
- int ret = 0;
- switch (cmd) {
- case DISPLAY_ENGINE_CTRL_DISPLAY_PREPARE_CB:
- data->prepare_fn_arg = arg2;
- data->prepare_fn = arg1;
- break;
- case DISPLAY_ENGINE_CTRL_DISPLAY_START_CB:
- data->start_fn_arg = arg2;
- data->start_fn = arg1;
- break;
- case DISPLAY_ENGINE_CTRL_DISPLAY_MODE:
- data->display_format = ((struct display_videomode *)arg1)->pixel_format;
- data->display_bytes_per_pixel = display_format_get_bits_per_pixel(data->display_format) / 8;
- break;
- case DISPLAY_ENGINE_CTRL_DISPLAY_PORT:
- data->display_sync_en =
- (((struct display_videoport *)arg1)->type == DISPLAY_PORT_QSPI_SYNC);
- if (data->display_sync_en) {
- data->op_mode = DISPLAY_ENGINE_MODE_DISPLAY_ONLY;
- }
- break;
- case DISPLAY_ENGINE_CTRL_DISPLAY_SYNC_STOP:
- if (data->display_sync_en) {
- int32_t wait_ms = (int32_t)arg1;
- /* wait command queue empty */
- data->display_sync_en = 0;
- while (data->cmd_num > 0 && wait_ms > 0) {
- k_msleep(2);
- wait_ms -= 2;
- }
- if (data->cmd_num > 0) {
- DEV_ERR("de sync stop timeout (stat=0x%x)\n", DE->STA);
- de_cleanup_all_cmd(data);
- ret = -ETIME;
- }
- data->display_sync_en = 1;
- /* FIXME: any better way to do this ? */
- de_reset(data);
- }
- break;
- case DISPLAY_ENGINE_CTRL_WORK_MODE:
- if (!data->display_sync_en) {
- uint8_t mode = (uint8_t)((intptr_t)arg1);
- if (mode != data->op_mode) {
- data->op_mode = mode;
- if (mode == DISPLAY_ENGINE_MODE_DISPLAY_ONLY) {
- unsigned int key = irq_lock();
- data->waiting = (data->cmd_num > 0);
- irq_unlock(key);
- if (data->waiting) {
- k_sem_take(&data->wait_sem, K_MSEC(5000));
- }
- }
- }
- }
- break;
- default:
- return -EINVAL;
- }
- return ret;
- }
- __de_func void de_isr(const void *arg)
- {
- const struct device *dev = arg;
- struct de_data *data = dev->data;
- uint32_t status = DE->STA;
- uint32_t rt_stat = DE->RT_CTL;
- bool completed = false;
- DE->STA = status;
- DEV_DBG("de sta 0x%08x\n", status);
- if (rt_stat & RT_STAT_COMPLETE) {
- DEV_DBG("de rt complete 0x%08x\n", rt_stat);
- completed = true;
- }
- if (status & (DE_STAT_WB_FTC | DE_STAT_DEV_FTC)) {
- DEV_DBG("de ovl complete 0x%08x\n", status);
- completed = true;
- }
- if (completed) {
- if (data->display_sync_en == 0)
- k_work_cancel_delayable(&data->timeout_work);
- if (data->display_sync_en == 0 || data->cmd_num > 1)
- de_complete_cmd(data, 0);
- }
- if (status & DE_STAT_DEV_FIFO_HF) {
- DEV_DBG("de dev halfull\n");
- #if CONFIG_DE_USE_DEV_HALFULL
- if (data->start_fn) {
- data->start_fn(data->start_fn_arg);
- }
- #endif /* CONFIG_DE_USE_DEV_HALFULL */
- }
- if (status & DE_STAT_DEV_FIFO_UDF) {
- if (data->display_sync_en) {
- DEV_ERR("de dev underflow 0x%08x\n", status);
- de_reset(data);
- de_complete_cmd(data, DE_STAT_DEV_FIFO_UDF);
- }
- }
- /* RGB and SPI_QUAD_SYNC have vsync signal*/
- if (status & DE_STAT_DEV_VSYNC) {
- /* TODO: refresh frames */
- DEV_DBG("vsync arrived\n");
- }
- /* update frames for those do not have vsync signal */
- if (status & DE_STAT_PRELINE) {
- /* TODO: refresh frames */
- DEV_DBG("preline arrived\n");
- }
- }
- static void de_timeout_work_handler(struct k_work *work)
- {
- struct de_data *data = CONTAINER_OF(work, struct de_data, timeout_work);
- printk("de timeout\n");
- de_dump();
- de_complete_cmd(data, -ETIME);
- }
- int de_init(const struct device *dev)
- {
- struct de_data *data = dev->data;
- memset(data, 0, sizeof(*data));
- memset(&de_priv_data, 0, sizeof(de_priv_data));
- k_sem_init(&data->wait_sem, 0, 1);
- k_mutex_init(&data->mutex);
- k_work_init_delayable(&data->timeout_work, de_timeout_work_handler);
- sys_slist_init(&data->cmd_list);
- #ifdef CONFIG_DISPLAY_ENGINE_HIHG_PRIO_INSTANCE
- sys_slist_init(&data->high_cmd_list);
- #endif
- de_command_pools_init();
- return 0;
- }
- #ifdef CONFIG_PM_DEVICE
- int de_pm_control(const struct device *dev, enum pm_device_action action)
- {
- struct de_data *data = dev->data;
- int ret = 0;
- switch (action) {
- case PM_DEVICE_ACTION_SUSPEND:
- case PM_DEVICE_ACTION_FORCE_SUSPEND:
- ret = (data->cmd_num > 0) ? -EBUSY : 0;
- break;
- case PM_DEVICE_ACTION_RESUME:
- de_reset(data);
- break;
- default:
- break;
- }
- return ret;
- }
- #endif /* CONFIG_PM_DEVICE */
- const struct display_engine_driver_api de_drv_api = {
- .control = de_control,
- .open = de_open,
- .close = de_close,
- .get_capabilities = de_get_capabilities,
- .register_callback = de_register_callback,
- .fill = de_fill,
- .blit = de_blit,
- .blend = de_blend,
- .compose = de_compose,
- .transform = de_transform,
- .set_clut = de_set_clut,
- .poll = de_poll,
- };
- struct de_data de_drv_data __in_section_unique(ram.noinit.drv_de.data);
|