Files
luban-lite-t3e-pro/packages/artinchip/mpp/vin/mpp_vin_dev.c
刘可亮 7bbc029dae v1.0.0
2023-08-30 16:21:18 +08:00

679 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020-2023 ArtInChip Technology Co., Ltd.
* Authors: Matteo <duanmt@artinchip.com>
*
* The device mode of MPP video in
*/
#include "aic_common.h"
#include "aic_errno.h"
#include "aic_log.h"
#include "aic_osal.h"
#include "mpp_vin.h"
#include "mpp_vin_dev.h"
#ifdef CONFIG_ARTINCHIP_MDI
#include "hal_mdi.h"
#include "mdi.h"
#include "artinchip_fb.h"
#include "display_support.h"
#ifdef CONFIG_ARTINCHIP_GE
#include "mpp_ge.h"
#endif
#define VIN_DEBUG_SHOW_FRAMERATE
#define VIN_DEBUG_DISP_ENABLE
struct mpp_vin_dev {
struct mpp_size in_size;
u32 in_stride;
enum mpp_pixel_format out_fmt; /* only suport RGB565 & RGB888 */
u32 frame_cnt;
struct vin_video_buf vb;
u32 ge_enable;
u32 scale_enable;
#ifdef CONFIG_ARTINCHIP_GE
u32 rot_angle;
u32 ge_out_stride;
struct mpp_size ge_out_size;
struct mpp_ge *ge_dev;
struct ge_bitblt ge_blt;
dma_addr_t fb_buf[2];
#endif
s32 de_inited;
struct aicfb_layer_data de_layer;
struct aic_panel *de_panel;
aicos_mutex_t lock;
aicos_thread_t thid;
};
static struct mpp_vin_dev g_vin_dev = {0};
static char *g_vin_buf = NULL; /* Must 8Byte align */
static char *g_vin_buf_raw = NULL; /* Process the unaligned buf address */
static void mpp_mdi_update_out_cfg(void)
{
struct mpp_buf *de = &g_vin_dev.de_layer.buf;
#ifdef CONFIG_ARTINCHIP_GE
struct ge_bitblt *ge_blt = &g_vin_dev.ge_blt;
#endif
/* Case 1: MDI -> DE, so out_cfg is decided by DE */
if (!g_vin_dev.ge_enable)
return;
/* Case 2: MDI -> GE -> DE */
#ifdef CONFIG_ARTINCHIP_GE
/* Case 2.1 Need scale. out_cfg is decided by DE */
if (g_vin_dev.scale_enable) {
g_vin_dev.ge_out_size = de->size;
g_vin_dev.ge_out_stride = de->stride[0];
}
/* Case 2.2 No scale, no rotate or rotate 180. out_cfg is same as input */
else if (!g_vin_dev.rot_angle || g_vin_dev.rot_angle == MPP_ROTATION_180) {
g_vin_dev.ge_out_size = g_vin_dev.in_size;
g_vin_dev.ge_out_stride = g_vin_dev.in_stride;
}
/* Case 2.3 No scale, rotate 90/270. out_cfg swap the width and height */
else {
g_vin_dev.ge_out_size.width = g_vin_dev.in_size.height;
g_vin_dev.ge_out_size.height = g_vin_dev.in_size.width;
if (de->format == MPP_FMT_RGB_565)
g_vin_dev.ge_out_stride = ALIGN_8B(g_vin_dev.in_size.height * 2);
else
g_vin_dev.ge_out_stride = ALIGN_8B(g_vin_dev.in_size.height * 3);
}
ge_blt->src_buf.size = g_vin_dev.in_size;
ge_blt->src_buf.stride[0] = g_vin_dev.in_stride;
ge_blt->src_buf.format = de->format;
ge_blt->dst_buf.crop_en = 1;
ge_blt->dst_buf.crop.width = g_vin_dev.ge_out_size.width;
ge_blt->dst_buf.crop.height = g_vin_dev.ge_out_size.height;
ge_blt->dst_buf.stride[0] = de->stride[0];
ge_blt->dst_buf.format = de->format;
printf("GE: %d(%d) * %d -> %d * %d, canvas %d(%d) * %d\n",
ge_blt->src_buf.size.width, ge_blt->src_buf.stride[0],
ge_blt->src_buf.size.height,
ge_blt->dst_buf.crop.width, ge_blt->dst_buf.crop.height,
ge_blt->dst_buf.size.width, ge_blt->dst_buf.stride[0],
ge_blt->dst_buf.size.height);
#endif
}
static int mpp_mdi_request_buf(void)
{
int i, imagesize = 0;
char *video_buf = g_vin_buf;
struct vin_video_buf *vb = &g_vin_dev.vb;
struct mpp_buf *de = &g_vin_dev.de_layer.buf;
if (g_vin_dev.ge_enable) {
imagesize = de->size.height * de->stride[0];
g_vin_dev.fb_buf[0] = (dma_addr_t)g_vin_buf;
g_vin_dev.fb_buf[1] = (dma_addr_t)(g_vin_buf + imagesize);
video_buf = g_vin_buf + imagesize * 2;
printf("\nAllocated double framebuffer for DE: %#lx, %#lx\n",
(long)g_vin_dev.fb_buf[0], (long)g_vin_dev.fb_buf[1]);
}
if (aic_mdi_req_buf(video_buf, VIN_RESERVED_MEM_SIZE - imagesize * 2, vb))
return -1;
printf("\nAllocated %d video buffer for MDI:\n", vb->num_buffers);
printf("Buf Plane[0] size Plane[1] size\n");
for (i = 0; i < vb->num_buffers; i++) {
printf("%3d %#x %8d %#x %8d\n", i,
vb->planes[i * VIN_MAX_PLANE_NUM].buf,
vb->planes[i * VIN_MAX_PLANE_NUM].len,
vb->planes[i * VIN_MAX_PLANE_NUM + 1].buf,
vb->planes[i * VIN_MAX_PLANE_NUM + 1].len);
}
/* Queue all the buffer, prepare to accept DBI data */
for (i = 0; i < vb->num_buffers; i++) {
if (aic_mdi_q_buf(i) < 0)
return -1;
}
return 0;
}
static void mpp_mdi_release_buf(void)
{
}
static dma_addr_t mpp_mdi_get_tail_buf(void)
{
if (g_vin_dev.ge_enable)
return g_vin_dev.fb_buf[1];
else
return g_vin_dev.vb.planes[(g_vin_dev.vb.num_buffers - 1) * VIN_MAX_PLANE_NUM].buf;
}
static int dbi_cmd_soft_reset(u8 code, u8 *data)
{
aic_mdi_reset();
return 0;
}
static int dbi_cmd_disp_on(u8 code, u8 *data)
{
if (!g_vin_dev.de_inited) {
#ifdef VIN_DEBUG_DISP_ENABLE
struct aicfb_layer_data *layer = &g_vin_dev.de_layer;
#endif
/* 1. Prepare the video buffer & framebuffer */
if (mpp_mdi_request_buf())
return -1;
/* 2.1 Open GE */
if (g_vin_dev.ge_enable) {
#ifdef CONFIG_ARTINCHIP_GE
g_vin_dev.ge_dev = mpp_ge_open();
if (!g_vin_dev.ge_dev)
return -1;
#endif
}
#ifdef VIN_DEBUG_DISP_ENABLE
/* 2.2 Open DE */
display_panel_probe();
display_interface_probe();
display_engine_probe(0, 0);
layer->enable = 1;
/* Set a temporary buffer to DE, and the buffer should be valid */
layer->buf.phy_addr[0] = mpp_mdi_get_tail_buf();
display_ioctl(AICFB_UPDATE_LAYER_CONFIG, layer);
#endif
g_vin_dev.de_inited = 1;
}
#ifdef VIN_DEBUG_DISP_ENABLE
/* 3. Open panel */
display_ioctl(AICFB_ENABLE_PANEL, NULL);
#endif
/* 4. Start the video buffer */
aic_mdi_stream_on();
/* 5. Start the MDI thread */
aicos_thread_resume(g_vin_dev.thid);
pr_info("Turn on DE\n");
return 0;
}
static int dbi_cmd_disp_off(u8 code, u8 *data)
{
aicos_mutex_take(g_vin_dev.lock, AIC_OSAL_WAIT_FOREVER);
if (!g_vin_dev.de_inited) {
pr_err("Should init DE first.\n");
return -1;
}
g_vin_dev.de_inited = 0;
g_vin_dev.de_layer.enable = 0;
#ifdef VIN_DEBUG_DISP_ENABLE
display_ioctl(AICFB_UPDATE_LAYER_CONFIG, &g_vin_dev.de_layer);
#endif
aicos_mutex_give(g_vin_dev.lock);
aic_mdi_stream_off();
aicos_thread_suspend(g_vin_dev.thid);
if (g_vin_dev.ge_enable) {
#ifdef CONFIG_ARTINCHIP_GE
mpp_ge_close(g_vin_dev.ge_dev);
g_vin_dev.ge_dev = NULL;
#endif
}
pr_info("Turn off DE\n");
return 0;
}
static int dbi_cmd_width_set(u8 code, u8 *data)
{
u16 start = dbi_byte2short(data[0], data[1]);
u16 end = dbi_byte2short(data[2], data[3]);
u16 size = 0;
if (start >= end) {
pr_err("Invalid width: %d -> %d\n", start, end);
return -1;
}
size = end - start + 1;
printf("Recv width: %d (%d - %d)\n", size, start, end);
if (size > MDI_MAX_WIDTH) {
pr_warn("Recv width %d is too large!\n", size);
size = MDI_MAX_WIDTH;
}
aic_mdi_in_width_set(size);
g_vin_dev.in_size.width = size;
return 0;
}
static int dbi_cmd_height_set(u8 code, u8 *data)
{
u16 start = dbi_byte2short(data[0], data[1]);
u16 end = dbi_byte2short(data[2], data[3]);
u16 size = 0;
if (start >= end) {
pr_err("Invalid height: %d -> %d\n", start, end);
return -1;
}
size = end - start + 1;
printf("Recv height: %d (%d - %d)\n", size, start, end);
if (size > MDI_MAX_HEIGHT) {
pr_warn("Recv height %d is too large!\n", size);
size = MDI_MAX_HEIGHT;
}
aic_mdi_in_height_set(size);
g_vin_dev.in_size.height = size;
return 0;
}
static int dbi_cmd_pixel_fmt_set(u8 code, u8 *data)
{
u8 dpi = getbits(DBI_CMD_DPI_MASK, DBI_CMD_DPI_SHIFT, data[0]);
u8 dbi = getbits(DBI_CMD_DBI_MASK, DBI_CMD_DBI_SHIFT, data[0]);
u8 flag = getbit(DBI_CMD_DBI_FMT_FLAG, data[0]);
struct mpp_buf *de = &g_vin_dev.de_layer.buf;
char *bits[] = {"", "", "", "", "", "16bits", "18bits", "24bits"};
u32 imagesize = 0;
if ((dpi != DPI_RGB_IF_16BIT) && (dpi != DPI_RGB_IF_24BIT)) {
pr_err("Unsupported DPI format %d\n", dpi);
return -1;
}
if (dbi < DBI_MCU_IF_16BIT) {
pr_err("Unsupported DBI format %d\n", dbi);
return -1;
}
aicos_mutex_take(g_vin_dev.lock, AIC_OSAL_WAIT_FOREVER);
if (dbi == DBI_MCU_IF_16BIT)
g_vin_dev.in_stride = ALIGN_8B(g_vin_dev.in_size.width * 2);
else
g_vin_dev.in_stride = ALIGN_8B(g_vin_dev.in_size.width * 3);
if (dpi == DPI_RGB_IF_16BIT) {
de->format = MPP_FMT_RGB_565;
de->stride[0] = ALIGN_8B(de->size.width * 2);
imagesize = de->stride[0] * de->size.height;
} else {
de->format = MPP_FMT_RGB_888;
de->stride[0] = ALIGN_8B(de->size.width * 3);
imagesize = de->stride[0] * de->size.height;
}
g_vin_dev.out_fmt = de->format;
mpp_mdi_update_out_cfg();
aicos_mutex_give(g_vin_dev.lock);
printf("Recv DBI %s(%d) -> DPI %s(%d), Flag %d\n",
bits[dbi], dbi, bits[dpi], dpi, flag);
aic_mdi_in_fmt_set(dbi, flag);
/* Consider the MDI output is DE temporary.
* The output should changed to GE after CMD DBI_CMD_AIC_GE_CTL */
aic_mdi_out_pixel_set(de->stride[0], imagesize);
return 0;
}
static int dbi_cmd_bright_set(u8 code, u8 *data)
{
pr_info("Unsupported cmd %#x\n", code);
return 0;
}
static int dbi_cmd_ge_ctl(u8 code, u8 *data)
{
u8 rotate = data[0] & DBI_CMD_GE_ROT_MASK;
u32 *flag = &g_vin_dev.ge_blt.ctrl.flags;
*flag = 0;
if (data[0] & DBI_CMD_GE_H_FLIP)
*flag |= MPP_FLIP_H;
if (data[0] & DBI_CMD_GE_V_FLIP)
*flag |= MPP_FLIP_V;
if (data[0] & DBI_CMD_GE_SCALE)
g_vin_dev.scale_enable = 1;
*flag |= rotate;
g_vin_dev.rot_angle = rotate;
g_vin_dev.ge_enable = 1;
printf("Recv GE ctl: H flip %s, V flip %s, Scale %s, Rotate %d\n",
*flag & MPP_FLIP_H ? "enable" : "disable",
*flag & MPP_FLIP_V ? "enable" : "disable",
g_vin_dev.scale_enable ? "enable" : "disable", rotate * 90);
mpp_mdi_update_out_cfg();
aic_mdi_out_pixel_set(g_vin_dev.in_stride,
g_vin_dev.in_stride * g_vin_dev.in_size.height);
return 0;
}
static int dbi_cmd_fr_set(u8 code, u8 *data)
{
u8 fr = getbits(DBI_CMD_FR_MASK, DBI_CMD_FR_SHIFT, data[0]);
u32 pixclk = fr;
struct display_timing *t = g_vin_dev.de_panel->timing;
aicos_mutex_take(g_vin_dev.lock, AIC_OSAL_WAIT_FOREVER);
pixclk *= (t->hactive + t->hfront_porch + t->hback_porch + t->hsync_len) *
(t->vactive + t->vfront_porch + t->vback_porch + t->vsync_len);
if (pixclk > MDI_MAX_PIXCLK) {
pr_info("pixclk %d is too large\n", pixclk);
pixclk = MDI_MAX_PIXCLK;
}
t->pixelclock = pixclk;
aicos_mutex_give(g_vin_dev.lock);
printf("Recv framerate %d, pixclk should be %d\n", fr, pixclk);
return 0;
}
static int dbi_cmd_porch_set(u8 code, u8 *data)
{
struct display_timing *t = g_vin_dev.de_panel->timing;
aicos_mutex_take(g_vin_dev.lock, AIC_OSAL_WAIT_FOREVER);
t->vfront_porch = data[0] & DBI_CMD_VP_MASK;
t->vback_porch = data[1] & DBI_CMD_VP_MASK;
t->hfront_porch = data[2];
t->hback_porch = data[3];
t->hsync_len = 2;
t->vsync_len = 2;
aicos_mutex_give(g_vin_dev.lock);
printf("Recv blank porch:\n\t hfp %d, hbp %d, vfp %d, vbp %d\n",
t->hfront_porch, t->hback_porch, t->vfront_porch, t->vback_porch);
return 0;
}
static int dbi_cmd_unsupported(u8 code, u8 *data)
{
pr_info("Unsupported cmd %#x\n", code);
return 0;
}
static struct aic_dbi_cmd g_dbi_cmds[] = {
{DBI_CMD_SOFT_RESET, 0, "Soft reset", dbi_cmd_soft_reset},
{DBI_CMD_SLEEP_OUT, 0, "Sleep out", dbi_cmd_unsupported},
{DBI_CMD_DISP_OFF, 0, "Display off", dbi_cmd_disp_off},
{DBI_CMD_DISP_ON, 0, "Display on", dbi_cmd_disp_on},
{DBI_CMD_COL_ADDR_SET, 4, "Column addr set", dbi_cmd_width_set},
{DBI_CMD_PAGE_ADDR_SET, 4, "Page addr set", dbi_cmd_height_set},
{DBI_CMD_PIXEL_FMT, 1, "Pixel format", dbi_cmd_pixel_fmt_set},
{DBI_CMD_BRIGHTNESS, 1, "Brightness set", dbi_cmd_bright_set},
{DBI_CMD_AIC_GE_CTL, 1, "AIC GE control", dbi_cmd_ge_ctl},
{DBI_CMD_FR_CTL, 2, "Frame rate", dbi_cmd_fr_set},
{DBI_CMD_BLANK_PORCH_CTL, 4, "Blank porch", dbi_cmd_porch_set},
{0x33, 6, "ili94 Ver Scr", dbi_cmd_unsupported},
{0x35, 1, "ili94 Tear ON", dbi_cmd_unsupported},
{0x36, 1, "ili94 Mem Acc", dbi_cmd_unsupported},
{0x37, 2, "ili94 Ver Addr", dbi_cmd_unsupported},
{0x44, 2, "ili94 Wr Tear", dbi_cmd_unsupported},
{0x50, 0, "ili94 cmd", dbi_cmd_unsupported},
{0xc0, 2, "ili94 Pwr ctl1", dbi_cmd_unsupported},
{0xc1, 1, "ili94 Pwr ctl2", dbi_cmd_unsupported},
{0xc5, 3, "ili94 VCOM ctl", dbi_cmd_unsupported},
{0xb4, 1, "ili94 Disp Inv", dbi_cmd_unsupported},
{0xb6, 2, "ili94 Disp Func", dbi_cmd_unsupported}, // data len is 3?
{0xb7, 1, "ili94 Entry Mod", dbi_cmd_unsupported},
{0xbe, 2, "ili94 HS Lane", dbi_cmd_unsupported},
{0xe0, 15, "ili94 Pos GAM", dbi_cmd_unsupported},
{0xe1, 15, "ili94 Neg GAM", dbi_cmd_unsupported},
{0xe9, 1, "ili94 Set Img", dbi_cmd_unsupported},
{0xec, 4, "ili94 cmd", dbi_cmd_unsupported},
{0xf4, 3, "ili94 cmd", dbi_cmd_unsupported},
{0xf7, 4, "ili94 Adj ctl", dbi_cmd_unsupported},
{0xe7, 1, "ST77903 cmd", dbi_cmd_unsupported},
{0xf0, 1, "ST77903 cmd", dbi_cmd_unsupported},
};
static s32 dbi_cmd_process(u8 code)
{
u8 i, ret;
u8 data[DBI_DAT_MAX_LEN] = {0};
struct aic_dbi_cmd *cmd = g_dbi_cmds;
for (i = 0; i < ARRAY_SIZE(g_dbi_cmds); i++, cmd++) {
if (code != cmd->code)
continue;
pr_debug("Recv cmd %#x (%s)\n", cmd->code, cmd->name);
if (!cmd->data_len)
return cmd->proc(code, NULL);
ret = aich_mdi_rd_fifo(data, cmd->data_len);
if (!ret || ret != cmd->data_len) {
pr_warn("CMD %#x (%s): Failed to read the data %d/%d\n",
cmd->code, cmd->name, ret, cmd->data_len);
return -1;
}
return cmd->proc(code, data);
}
pr_warn("unknown command %#x\n", code);
aich_mdi_rd_fifo(data, DBI_DAT_MAX_LEN);
return -1;
}
#ifdef CONFIG_ARTINCHIP_GE
static int mpp_mdi_preprocess(s32 index, s32 pingpang)
{
s32 ret = 0;
struct ge_bitblt *ge_blt = &g_vin_dev.ge_blt;
ge_blt->src_buf.phy_addr[0] = g_vin_dev.vb.planes[index * VIN_MAX_PLANE_NUM].buf;
ge_blt->dst_buf.phy_addr[0] = g_vin_dev.fb_buf[pingpang];
ret = mpp_ge_bitblt(g_vin_dev.ge_dev, ge_blt);
if (ret < 0) {
pr_err("GE bitblt failed\n");
return ret;
}
ret = mpp_ge_emit(g_vin_dev.ge_dev);
if (ret < 0) {
pr_err("GE emit failed\n");
return ret;
}
ret = mpp_ge_sync(g_vin_dev.ge_dev);
if (ret < 0) {
pr_err("GE sync failed!\n");
return ret;
}
return 0;
}
#endif
#ifdef VIN_DEBUG_SHOW_FRAMERATE
#define NS_PER_SEC 1000000000
static void show_fps(struct timespec *start, struct timespec *end, int cnt)
{
double diff;
if (end->tv_nsec < start->tv_nsec) {
diff = (double)(NS_PER_SEC + end->tv_nsec - start->tv_nsec)/NS_PER_SEC;
diff += end->tv_sec - 1 - start->tv_sec;
} else {
diff = (double)(end->tv_nsec - start->tv_nsec)/NS_PER_SEC;
diff += end->tv_sec - start->tv_sec;
}
printf("MDI frame rate: %.1f (%d / %.1fs)\n", (double)cnt/diff, cnt, diff);
}
#endif
static void mpp_mdi_thread(void *arg)
{
u32 cnt = 0, index = 0;
struct vin_video_buf *vb = &g_vin_dev.vb;
struct aicfb_layer_data *layer = &g_vin_dev.de_layer;
#ifdef CONFIG_ARTINCHIP_GE
s32 pingpang = 1;
#endif
#ifdef VIN_DEBUG_SHOW_FRAMERATE
struct timespec begin, now;
clock_gettime(CLOCK_MONOTONIC, &begin);
#endif
while (1) {
if (!g_vin_dev.de_inited) {
aos_msleep(10);
continue;
}
cnt++;
if ((g_vin_dev.frame_cnt) && (cnt >= g_vin_dev.frame_cnt))
break;
if (aic_mdi_dq_buf(&index) < 0)
break;
if (g_vin_dev.ge_enable) {
#ifdef CONFIG_ARTINCHIP_GE
pingpang = !pingpang;
if (mpp_mdi_preprocess(index, pingpang))
break;
#endif
}
aicos_mutex_take(g_vin_dev.lock, AIC_OSAL_WAIT_FOREVER);
layer->enable = 1;
if (g_vin_dev.ge_enable)
layer->buf.phy_addr[0] = g_vin_dev.fb_buf[pingpang];
else
layer->buf.phy_addr[0] = vb->planes[index * VIN_MAX_PLANE_NUM].buf;
#ifdef VIN_DEBUG_DISP_ENABLE
display_ioctl(AICFB_UPDATE_LAYER_CONFIG, &g_vin_dev.de_layer);
display_ioctl(AICFB_WAIT_FOR_VSYNC, NULL);
#endif
aicos_mutex_give(g_vin_dev.lock);
aic_mdi_q_buf(index);
#ifdef VIN_DEBUG_SHOW_FRAMERATE
if (cnt && (cnt % 1000 == 0)) {
clock_gettime(CLOCK_MONOTONIC, &now);
show_fps(&begin, &now, cnt);
clock_gettime(CLOCK_MONOTONIC, &begin);
cnt = 0;
}
#endif
}
#ifdef VIN_DEBUG_SHOW_FRAMERATE
clock_gettime(CLOCK_MONOTONIC, &now);
show_fps(&begin, &now, cnt);
#endif
mpp_mdi_release_buf();
mpp_vin_dev_deinit();
pr_info("MDI thread exit!\n");
}
static int mpp_vin_malloc_align(void)
{
g_vin_buf_raw = (char *)aicos_malloc(MEM_CMA, VIN_RESERVED_MEM_SIZE + 8);
if (!g_vin_buf_raw) {
pr_err("Failed to malloc %d buffer\n", VIN_RESERVED_MEM_SIZE);
return -1;
}
if ((long)g_vin_buf_raw % 8)
g_vin_buf = (char *)((long)(g_vin_buf_raw + 7) & (~0x7));
else
g_vin_buf = g_vin_buf_raw;
memset(g_vin_buf, 0, VIN_RESERVED_MEM_SIZE);
pr_debug("MPP VIN buffer base: %#lx\n", (long)g_vin_buf);
return 0;
}
int mpp_vin_dev_init(u32 cnt)
{
struct mpp_buf *de = &g_vin_dev.de_layer.buf;
#ifdef CONFIG_ARTINCHIP_GE
struct ge_bitblt *ge_blt = &g_vin_dev.ge_blt;
#endif
if (aic_mdi_open(dbi_cmd_process))
return -1;
if (g_vin_buf) {
pr_info("MDI buffer is already alloced: %#lx\n", (long)g_vin_buf);
return 0;
}
if (mpp_vin_malloc_align())
return -1;
g_vin_dev.de_panel = aic_open_panel();
if (!g_vin_dev.de_panel)
return -1;
g_vin_dev.de_layer.layer_id = AICFB_LAYER_TYPE_UI;
de->buf_type = MPP_PHY_ADDR;
de->format = MPP_FMT_RGB_888;
de->size.width = APP_FB_WIDTH;
de->size.height = APP_FB_HEIGHT;
de->stride[0] = ALIGN_8B(APP_FB_WIDTH * 3);
#ifdef CONFIG_ARTINCHIP_GE
ge_blt->src_buf.buf_type = MPP_PHY_ADDR;
ge_blt->dst_buf.buf_type = MPP_PHY_ADDR;
ge_blt->dst_buf.size = de->size;
ge_blt->dst_buf.stride[0] = de->stride[0];
ge_blt->dst_buf.format = de->format;
#endif
g_vin_dev.frame_cnt = cnt;
g_vin_dev.lock = aicos_mutex_create();
g_vin_dev.thid = aicos_thread_create("mpp_mdi", 4096, AOS_DEFAULT_APP_PRI,
mpp_mdi_thread, NULL);
if (g_vin_dev.thid == NULL) {
pr_err("Failed to create MDI thread\n");
return -1;
}
aicos_thread_suspend(g_vin_dev.thid);
return 0;
}
void mpp_vin_dev_deinit(void)
{
if (g_vin_buf) {
aicos_free(MEM_CMA, g_vin_buf_raw);
g_vin_buf = NULL;
}
aic_mdi_close();
}
#endif