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