Files
base/drivers/source/asw/sdrv_asw.c
2025-11-07 09:57:14 +08:00

547 lines
16 KiB
C

/**
* @file sdrv_asw.c
* @brief sdrv asw driver source.
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <armv7-r/cache.h>
#include <asw/asw.h>
#include <asw/asw_log.h>
#include <dispss/disp_data_type.h>
#include <g2dlite/g2dlite.h>
#include <irq.h>
#include <stdlib.h>
#include <string.h>
#include <udelay/udelay.h>
extern struct asw_operations sdrv_asw_ops;
#define TRI_SRC_W 1024
#define TRI_SRC_H 2
int tri_src[TRI_SRC_W * TRI_SRC_H * 4] = {0};
#define FILL_SRC_W 16
#define FILL_SRC_H 16
int fill_src[FILL_SRC_W * FILL_SRC_H * 4] = {0};
#define FILL_EX_W 35
#define FILL_EX_H 35
int blut_ext[FILL_EX_W * FILL_EX_H * 4 * 6] = {0};
static void asw_done(struct asw_dev *dev)
{
#if CONFIG_OS_FREERTOS
BaseType_t xReturn = xSemaphoreTake(dev->wdone_sema, pdMS_TO_TICKS(2000));
if (pdTRUE != xReturn) {
ASW_LOG_ERR("timeout for 2s !");
}
#else
int cnt = 0;
while (!dev->asw_done) {
udelay(10);
if (++cnt == 200000) {
ASW_LOG_ERR("timeout for 2s !");
break;
}
}
#endif
}
static int is_need_twice(double angle)
{
if ((angle > 45 && angle < 135) || (angle > 225 && angle < 315))
return 1;
return 0;
}
static int get_fmt_bpp(int fmt)
{
switch (fmt) {
case FMT_MONOTONIC_8BIT:
return 1;
case FMT_RGB565:
case FMT_ARGB1555:
case FMT_RGBA5551:
return 2;
case FMT_RGB_YUV888:
return 3;
case FMT_RGBA8888:
case FMT_ARGB8888:
return 4;
default:
ASW_LOG_ERR("can't support this fmt");
return -1;
}
}
static int color_to_bgcolor(int color)
{
int b, g, r, a;
b = (color >> 24) & 0xFF;
g = (color >> 16) & 0xFF;
r = (color >> 8) & 0xFF;
a = color & 0xFF;
return ((a << 24) | (b << 16) | (g << 8) | r);
}
void sdrv_asw_build_input(
struct asw_dev *dev, struct asw_input *input, int work_mode, int lut_mode,
int dst_fmt, int dst_hsize, int dst_vsize, int dst_ba, int dst_stride,
int dst_bg_color, int dst_flip, int src_fmt, int src_hsize, int src_vsize,
int src_ry_ba, int src_gu_ba, int src_bv_ba, int src_ry_stride,
int src_gu_stride, int src_bv_stride, int src_flip, int asw_lut_hsize,
int asw_lut_vsize, int cache_entry_type, int cache_way_n)
{
input->work_mode = work_mode;
input->lut_mode = lut_mode;
input->dst.dst_fmt = dst_fmt;
input->dst.dst_hsize = dst_hsize;
input->dst.dst_vsize = dst_vsize;
input->dst.dst_ba = dst_ba;
input->dst.dst_stride = dst_stride;
input->dst.dst_bg_color = dst_bg_color;
input->dst.dst_flip = dst_flip;
input->src.src_fmt = src_fmt;
input->src.src_hsize = src_hsize;
input->src.src_vsize = src_vsize;
input->src.src_ry_ba = src_ry_ba;
input->src.src_gu_ba = src_gu_ba;
input->src.src_bv_ba = src_bv_ba;
input->src.src_ry_stride = src_ry_stride;
input->src.src_gu_stride = src_gu_stride;
input->src.src_bv_stride = src_bv_stride;
input->src.src_flip = src_flip;
input->lut.asw_lut_hsize = asw_lut_hsize;
input->lut.asw_lut_vsize = asw_lut_vsize;
input->cache_entry_type = cache_entry_type;
input->cache_way_n = cache_way_n;
dev->input = input;
}
void sdrv_asw_bilinear_ftob32(const float *faddr, int *b32, int len)
{
for (int i = 0; i < len; i++) {
int tmp = (int)(faddr[i] * 256);
tmp = (tmp > 524287) ? 524287 : (tmp < -524288) ? -524288 : tmp;
b32[i] = tmp;
}
}
void sdrv_asw_bilinear_ftob16(const float *faddr, short *b16, int len)
{
for (int i = 0; i < len; i++) {
int tmp16 = (int)(faddr[i] * 16);
tmp16 = (tmp16 > 32767) ? 32767 : (tmp16 < -32768) ? -32768 : tmp16;
b16[i] = (short)tmp16;
}
}
void sdrv_asw_probe(struct asw_dev *dev, const struct asw_config *asw_cfg)
{
dev->base = asw_cfg->base;
dev->irq = asw_cfg->irq;
dev->ops = &sdrv_asw_ops;
dev->app.id = 0;
irq_attach(dev->irq, (irq_handler)dev->ops->irq_handler, dev);
irq_enable(dev->irq);
#if CONFIG_OS_FREERTOS
dev->wdone_sema = xSemaphoreCreateBinary();
#endif
}
void sdrv_asw_cubic(struct asw_input *input)
{
struct asw_dev *dev = &aswdev;
dev->ops->soft_reset(dev);
dev->input = input;
dev->ops->cubic_cfg(dev);
asw_done(dev);
}
void sdrv_asw_cubic_with_hvkt(struct asw_input *input, struct hvkt_param *hvkt)
{
struct asw_dev *dev = &aswdev;
dev->ops->soft_reset(dev);
dev->input = input;
dev->ops->cubic_cfg_with_hvkt(dev, hvkt);
asw_done(dev);
}
void sdrv_asw_bilinear(struct asw_input *input)
{
struct asw_dev *dev = &aswdev;
dev->ops->soft_reset(dev);
dev->input = input;
dev->ops->bilinear_cfg(dev);
asw_done(dev);
}
void sdrv_asw_bilinear_noblock(struct asw_input *input)
{
struct asw_dev *dev = &aswdev;
dev->ops->soft_reset(dev);
dev->input = input;
dev->ops->bilinear_cfg(dev);
}
void sdrv_asw_bilinear_with_hvkt(struct asw_input *input,
struct hvkt_param *hvkt)
{
struct asw_dev *dev = &aswdev;
dev->ops->soft_reset(dev);
dev->input = input;
dev->ops->bilinear_cfg_with_hvkt(dev, hvkt);
asw_done(dev);
}
void sdrv_asw_bilinear_rotation(struct asw_rot *rot)
{
struct asw_dev *dev = &aswdev;
struct asw_input input = {0};
struct hvkt_param hvkt = {0};
int twice;
double rot1, rot2;
int offstep;
static void *ext_addr;
static bool inited = false;
rot->angle = (int)rot->angle % 360 + (rot->angle - (int)rot->angle);
rot1 = rot->angle;
input.work_mode = WORK_MODE_M_TO_M;
input.hdsk_mode = BUF_SIZE_16LINES;
input.lut_mode = LUT_MODE_BILINEAR;
input.ext_lut_fmt = EXT_LUT_FORMAT_32BIT;
input.dst.dst_fmt = rot->dst_fmt;
input.dst.dst_hsize = rot->hsize;
input.dst.dst_vsize = rot->vsize;
twice = is_need_twice(rot->angle);
if (twice) {
if (!rot->t_buf) {
ASW_LOG_ERR("t_buf is null when twice operation!");
return;
}
input.dst.dst_ba = rot->t_buf;
input.dst.dst_stride = rot->t_stride;
if ((rot->angle > 45) && (rot->angle <= 90)) rot1 = 45;
else if ((rot->angle > 90) && (rot->angle <=135)) rot1 = 135;
else if ((rot->angle > 225) && (rot->angle <=270)) rot1 = 225;
else rot1 = 315;
rot2 = rot->angle - rot1;
} else {
input.dst.dst_ba = rot->dst_ba;
input.dst.dst_stride = rot->dst_stride;
}
input.dst.dst_bg_color = rot->bg_color;
input.src.src_fmt = rot->src_fmt;
input.src.src_hsize = rot->hsize;
input.src.src_vsize = rot->vsize;
input.src.src_ry_ba = rot->src_ba[0];
input.src.src_gu_ba = rot->src_ba[1];
input.src.src_bv_ba = rot->src_ba[2];
input.src.src_ry_stride = rot->src_stride[0];
input.src.src_gu_stride = rot->src_stride[1];
input.src.src_bv_stride = rot->src_stride[2];
input.lut.asw_lut_hsize = 35;
input.lut.asw_lut_vsize = 35;
offstep = 35 * 35 * 4;
if (!inited) {
ext_addr = (void *)blut_ext;
inited = true;
}
input.ext.ext_mlut_rx_ba = (int)ext_addr;
input.ext.ext_mlut_ry_ba = (int)ext_addr + offstep;
input.ext.ext_mlut_gx_ba = (int)ext_addr + offstep * 2;
input.ext.ext_mlut_gy_ba = (int)ext_addr + offstep * 3;
input.ext.ext_mlut_bx_ba = (int)ext_addr + offstep * 4;
input.ext.ext_mlut_by_ba = (int)ext_addr + offstep * 5;
input.ext.ext_mlut_rx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_ry_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_gx_stride = input.lut.asw_lut_hsize * 4,
input.ext.ext_mlut_gy_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_bx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_by_stride = input.lut.asw_lut_hsize * 4;
input.cache_entry_type = C_ENTRY_TYPE_16X4;
input.cache_way_n = 10;
/*hvkt*/
hvkt.chn = 1;
hvkt.is_external_lut = true;
hvkt.fw_map = false;
hvkt.external_lut_format = input.ext_lut_fmt; /* 32bits*/
hvkt.hsize = input.dst.dst_hsize;
hvkt.vsize = input.dst.dst_vsize;
hvkt.hsize_in = input.src.src_hsize;
hvkt.vsize_in = input.src.src_vsize;
hvkt.lut_h_size = input.lut.asw_lut_hsize;
hvkt.lut_v_size = input.lut.asw_lut_vsize;
hvkt.extend = 1;
dev->ops->soft_reset(dev);
dev->input = &input;
dev->ops->bilinear_rotation(dev, rot1, &hvkt);
asw_done(dev);
if (twice) {
input.src.src_fmt = rot->dst_fmt;
input.src.src_ry_ba = input.dst.dst_ba;
input.src.src_ry_stride = input.dst.dst_stride;
input.dst.dst_ba = rot->dst_ba;
input.dst.dst_stride = rot->dst_stride;
dev->ops->bilinear_rotation(dev, rot2, &hvkt);
asw_done(dev);
}
}
void sdrv_asw_ra_triangle(struct asw_ratria *info)
{
struct asw_input input = {0};
float lutx[4], luty[4];
int s_w, s_h, size;
int *src = NULL;
char *src8 = NULL;
int offstep;
int exaddr = 0;
int bpp;
s_w = TRI_SRC_W;
s_h = TRI_SRC_H;
size = s_w * s_h;
src = tri_src;
src8 = (char *)src;
for (int i = 0; i < size; i++) {
if (info->fmt == FMT_MONOTONIC_8BIT)
src8[i] = info->color & 0xFF;
else
src[i] = info->color;
}
arch_clean_cache_range((addr_t)src, size * 4);
bpp = get_fmt_bpp(info->fmt);
input.work_mode = WORK_MODE_M_TO_M;
input.hdsk_mode = BUF_SIZE_16LINES;
input.lut_mode = LUT_MODE_BILINEAR;
input.ext_lut_fmt = EXT_LUT_FORMAT_32BIT;
input.dst.dst_fmt = info->fmt;
input.dst.dst_hsize = info->hsize;
input.dst.dst_vsize = info->vsize;
input.dst.dst_ba =
info->addr + info->pos_y * info->stride + info->pos_x * bpp;
input.dst.dst_stride = info->stride;
input.dst.dst_bg_color = 0x0;
if (info->fmt == FMT_MONOTONIC_8BIT) {
input.src.src_fmt = FMT_MONOTONIC_8BIT;
input.src.src_ry_stride = s_w;
} else {
input.src.src_fmt = FMT_ARGB8888;
input.src.src_ry_stride = s_w * 4;
}
input.src.src_hsize = s_w;
input.src.src_vsize = s_h;
input.src.src_ry_ba = (int)src;
input.src.src_gu_ba = 0;
input.src.src_bv_ba = 0;
input.src.src_gu_stride = 0;
input.src.src_bv_stride = 0;
input.lut.asw_lut_hsize = 2;
input.lut.asw_lut_vsize = 2;
offstep = input.lut.asw_lut_hsize * input.lut.asw_lut_vsize * 4;
exaddr = (int)blut_ext;
input.ext.ext_mlut_rx_ba = exaddr;
input.ext.ext_mlut_ry_ba = exaddr + offstep;
input.ext.ext_mlut_gx_ba = exaddr + offstep * 2;
input.ext.ext_mlut_gy_ba = exaddr + offstep * 3;
input.ext.ext_mlut_bx_ba = exaddr + offstep * 4;
input.ext.ext_mlut_by_ba = exaddr + offstep * 5;
input.ext.ext_mlut_rx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_ry_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_gx_stride = input.lut.asw_lut_hsize * 4,
input.ext.ext_mlut_gy_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_bx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_by_stride = input.lut.asw_lut_hsize * 4;
input.cache_entry_type = C_ENTRY_TYPE_16X4;
input.cache_way_n = 6;
switch (info->type) {
case TRIAG_LEFT_TOP:
lutx[0] = 0;
lutx[1] = s_w - 1;
lutx[2] = s_w - 1;
lutx[3] = 2 * s_w - 1;
luty[0] = 0;
luty[1] = 0;
luty[2] = 1;
luty[3] = 1;
break;
case TRIAG_LEFT_BOTTOM:
lutx[0] = s_w - 1;
lutx[1] = 2 * s_w - 1;
lutx[2] = 0;
lutx[3] = s_w - 1;
luty[0] = 0;
luty[1] = 0;
luty[2] = 1;
luty[3] = 1;
break;
case TRIAG_TYPE_RIGHT_TOP:
lutx[0] = 0;
lutx[1] = s_w - 1;
lutx[2] = 1 - s_w;
lutx[3] = 0;
luty[0] = 0;
luty[1] = 0;
luty[2] = 1;
luty[3] = 1;
break;
case TRIAG_TYPE_RIGHT_BOTTOM:
lutx[0] = 1 - s_w;
lutx[1] = 0;
lutx[2] = 0;
lutx[3] = s_w - 1;
luty[0] = 0;
luty[1] = 0;
luty[2] = 1;
luty[3] = 1;
break;
default:
ASW_LOG_ERR("Not Support This TYPE(%d)", info->type);
return;
}
sdrv_asw_bilinear_ftob32(lutx, (int *)input.ext.ext_mlut_rx_ba, 4);
sdrv_asw_bilinear_ftob32(luty, (int *)input.ext.ext_mlut_ry_ba, 4);
arch_clean_cache_range((addr_t)input.ext.ext_mlut_rx_ba, offstep * 6);
sdrv_asw_bilinear(&input);
}
void sdrv_asw_fill_rect(int fmt, int color, int hsize, int vsize, int pos_x,
int pos_y, int addr, int stride)
{
struct asw_input input = {0};
float lutx[4], luty[4];
int s_w, s_h, size;
int *src = NULL;
char *src8 = NULL;
int offstep;
int exaddr = 0;
int bpp;
s_w = FILL_SRC_W;
s_h = FILL_SRC_H;
size = s_w * s_h;
src = fill_src;
src8 = (char *)src;
for (int i = 0; i < size; i++) {
if (fmt == FMT_MONOTONIC_8BIT)
src8[i] = color & 0xFF;
else
src[i] = color;
}
arch_clean_cache_range((addr_t)src, size * 4);
bpp = get_fmt_bpp(fmt);
input.work_mode = WORK_MODE_M_TO_M;
input.hdsk_mode = BUF_SIZE_16LINES;
input.lut_mode = LUT_MODE_BILINEAR;
input.ext_lut_fmt = EXT_LUT_FORMAT_32BIT;
input.dst.dst_fmt = fmt;
input.dst.dst_hsize = hsize;
input.dst.dst_vsize = vsize;
input.dst.dst_ba = addr + pos_y * stride + pos_x * bpp;
input.dst.dst_stride = stride;
input.dst.dst_bg_color = color_to_bgcolor(color);
if (fmt == FMT_MONOTONIC_8BIT) {
input.src.src_fmt = FMT_MONOTONIC_8BIT;
input.src.src_ry_stride = s_w;
} else {
input.src.src_fmt = FMT_ARGB8888;
input.src.src_ry_stride = s_w * 4;
}
input.src.src_hsize = s_w;
input.src.src_vsize = s_h;
input.src.src_ry_ba = (int)src;
input.src.src_gu_ba = 0;
input.src.src_bv_ba = 0;
input.src.src_gu_stride = 0;
input.src.src_bv_stride = 0;
input.lut.asw_lut_hsize = 2;
input.lut.asw_lut_vsize = 2;
offstep = input.lut.asw_lut_hsize * input.lut.asw_lut_vsize * 4;
exaddr = (int)blut_ext;
input.ext.ext_mlut_rx_ba = exaddr;
input.ext.ext_mlut_ry_ba = exaddr + offstep;
input.ext.ext_mlut_gx_ba = exaddr + offstep * 2;
input.ext.ext_mlut_gy_ba = exaddr + offstep * 3;
input.ext.ext_mlut_bx_ba = exaddr + offstep * 4;
input.ext.ext_mlut_by_ba = exaddr + offstep * 5;
input.ext.ext_mlut_rx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_ry_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_gx_stride = input.lut.asw_lut_hsize * 4,
input.ext.ext_mlut_gy_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_bx_stride = input.lut.asw_lut_hsize * 4;
input.ext.ext_mlut_by_stride = input.lut.asw_lut_hsize * 4;
input.cache_entry_type = C_ENTRY_TYPE_16X4;
input.cache_way_n = 6;
/* top-left*/
lutx[0] = 0;
luty[0] = 0;
/* top-right*/
lutx[1] = s_w - 1;
luty[1] = 0;
/* bottom-left*/
lutx[2] = 0;
luty[2] = s_h - 1;
/* bottom-right*/
lutx[3] = s_w - 1;
luty[3] = s_h - 1;
sdrv_asw_bilinear_ftob32(lutx, (int *)input.ext.ext_mlut_rx_ba, 4);
sdrv_asw_bilinear_ftob32(luty, (int *)input.ext.ext_mlut_ry_ba, 4);
arch_clean_cache_range((addr_t)input.ext.ext_mlut_rx_ba, offstep * 6);
sdrv_asw_bilinear(&input);
}