nuttx/drivers/video/goldfish_fb.c
Xiang Xiao ee3d2d1c0d video/goldfish: Remove the vsync residual code
forget from patch:
commit bbf5b0bb6d
Author: jianglianfang <jianglianfang@xiaomi.com>
Date:   Tue Aug 15 19:47:14 2023 +0800

    driver/video: adapting Goldfish FB to VSync optimized FB driver

    The circbuf part is implemented by the fb driver, and goldfish needs to
    delete the part related to circbuf and adapt to the interface of the fb
    driver.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2023-09-26 22:51:12 +08:00

338 lines
10 KiB
C

/****************************************************************************
* drivers/video/goldfish_fb.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <debug.h>
#include <nuttx/config.h>
#include <nuttx/video/fb.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
#ifndef putreg32
#define putreg32(v, x) (*(volatile uint32_t *)(x) = (v))
#endif
#ifndef getreg32
#define getreg32(x) (*(uint32_t *)(x))
#endif
/****************************************************************************
* Private Types
****************************************************************************/
enum
{
GOLDFISH_FB_GET_WIDTH = 0x00,
GOLDFISH_FB_GET_HEIGHT = 0x04,
GOLDFISH_FB_INT_STATUS = 0x08,
GOLDFISH_FB_INT_ENABLE = 0x0c,
GOLDFISH_FB_SET_BASE = 0x10,
GOLDFISH_FB_SET_ROTATION = 0x14,
GOLDFISH_FB_SET_BLANK = 0x18,
GOLDFISH_FB_GET_PHYS_WIDTH = 0x1c,
GOLDFISH_FB_GET_PHYS_HEIGHT = 0x20,
GOLDFISH_FB_GET_FORMAT = 0x24,
GOLDFISH_FB_INT_VSYNC = 1U << 0,
GOLDFISH_FB_INT_UPDATE_DONE = 1U << 1,
GOLDFISH_FB_FORMAT_BRGA_8888 = 1,
GOLDFISH_FB_FORMAT_RGBX_8888 = 2,
GOLDFISH_FB_FORMAT_RGB_888 = 3,
GOLDFISH_FB_FORMAT_RGB_565 = 4,
GOLDFISH_FB_FORMAT_BGRA_8888 = 5,
GOLDFISH_FB_FORMAT_RGBA_5551 = 6,
GOLDFISH_FB_FORMAT_RGBA_4444 = 8
};
struct goldfish_fb_format_s
{
uint8_t fmt;
uint8_t bpp;
};
struct goldfish_fb_s
{
struct fb_vtable_s vtable;
struct fb_planeinfo_s planeinfo;
struct fb_videoinfo_s videoinfo;
FAR void *base;
int irq;
};
/****************************************************************************
* Private Data
****************************************************************************/
static FAR struct goldfish_fb_s *g_goldfish_fb;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int goldfish_getvideoinfo(FAR struct fb_vtable_s *vtable,
FAR struct fb_videoinfo_s *vinfo);
static int goldfish_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
FAR struct fb_planeinfo_s *pinfo);
static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg);
static void goldfish_fb_vsync_irq(FAR struct goldfish_fb_s *fb);
static void goldfish_fb_framedone_irq(FAR struct goldfish_fb_s *fb);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: goldfish_fb_vsync_irq
****************************************************************************/
static void goldfish_fb_vsync_irq(FAR struct goldfish_fb_s *fb)
{
union fb_paninfo_u info;
#ifdef CONFIG_GOLDFISH_FB_VIDEO_MODE
int count;
count = fb_paninfo_count(&fb->vtable, FB_NO_OVERLAY);
if (count <= 0)
{
return;
}
if (count > 1)
{
fb_remove_paninfo(&fb->vtable, FB_NO_OVERLAY);
}
#endif
if (fb_peek_paninfo(&fb->vtable, &info, FB_NO_OVERLAY) == OK)
{
uintptr_t buf = (uintptr_t)(fb->planeinfo.fbmem +
fb->planeinfo.stride *
info.planeinfo.yoffset);
/* Send buffer addr to GOLDFISH */
putreg32(buf, fb->base + GOLDFISH_FB_SET_BASE);
}
}
/****************************************************************************
* Name: goldfish_fb_framedone_irq
****************************************************************************/
static void goldfish_fb_framedone_irq(FAR struct goldfish_fb_s *fb)
{
#ifndef CONFIG_GOLDFISH_FB_VIDEO_MODE
/* After the sending is completed, remove it from the panbuf queue.
*/
fb_remove_paninfo(&fb->vtable, FB_NO_OVERLAY);
#endif
}
/****************************************************************************
* Name: goldfish_fb_interrupt
****************************************************************************/
static int goldfish_fb_interrupt(int irq, FAR void *dev_id, FAR void *arg)
{
FAR struct goldfish_fb_s *fb = arg;
irqstate_t flags;
uint32_t status;
flags = enter_critical_section();
status = getreg32(fb->base + GOLDFISH_FB_INT_STATUS);
if (status & GOLDFISH_FB_INT_VSYNC)
{
goldfish_fb_vsync_irq(fb);
}
else if (status & GOLDFISH_FB_INT_UPDATE_DONE)
{
goldfish_fb_framedone_irq(fb);
}
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: goldfish_getvideoinfo
****************************************************************************/
static int goldfish_getvideoinfo(FAR struct fb_vtable_s *vtable,
FAR struct fb_videoinfo_s *vinfo)
{
FAR struct goldfish_fb_s *fb = (FAR struct goldfish_fb_s *)vtable;
ginfo("vtable=%p vinfo=%p\n", vtable, vinfo);
if (fb && vinfo)
{
memcpy(vinfo, &fb->videoinfo, sizeof(struct fb_videoinfo_s));
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
/****************************************************************************
* Name: goldfish_getplaneinfo
****************************************************************************/
static int goldfish_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno,
FAR struct fb_planeinfo_s *pinfo)
{
FAR struct goldfish_fb_s *fb = (FAR struct goldfish_fb_s *)vtable;
ginfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo);
if (fb && planeno == 0 && pinfo)
{
memcpy(pinfo, &fb->planeinfo, sizeof(struct fb_planeinfo_s));
return OK;
}
gerr("ERROR: Returning EINVAL\n");
return -EINVAL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_fbinitialize
****************************************************************************/
int up_fbinitialize(int display)
{
FAR struct goldfish_fb_s *fb;
uint32_t fmt;
int ret = OK;
const struct goldfish_fb_format_s format_map[] =
{
[GOLDFISH_FB_FORMAT_BRGA_8888] =
{FB_FMT_RGBA32, 32},
[GOLDFISH_FB_FORMAT_RGBX_8888] =
{FB_FMT_RGB32, 32},
[GOLDFISH_FB_FORMAT_RGB_888] =
{FB_FMT_RGB24, 24},
[GOLDFISH_FB_FORMAT_RGB_565] =
{FB_FMT_RGB16_565, 16},
[GOLDFISH_FB_FORMAT_BGRA_8888] =
{FB_FMT_RGBA32, 32},
[GOLDFISH_FB_FORMAT_RGBA_5551] =
{FB_FMT_RGB16_555, 16},
[GOLDFISH_FB_FORMAT_RGBA_4444] =
{FB_FMT_RGBA16, 16},
};
fb = kmm_zalloc(sizeof(*fb));
if (fb == NULL)
{
return -ENOMEM;
}
fb->base = (FAR void *)CONFIG_GOLDFISH_FB_BASE;
fb->irq = CONFIG_GOLDFISH_FB_IRQ;
fmt = getreg32(fb->base + GOLDFISH_FB_GET_FORMAT);
fb->videoinfo.xres = getreg32(fb->base + GOLDFISH_FB_GET_WIDTH);
fb->videoinfo.yres = getreg32(fb->base + GOLDFISH_FB_GET_HEIGHT);
fb->videoinfo.nplanes = 1;
fb->videoinfo.fmt = format_map[fmt].fmt;
fb->planeinfo.bpp = format_map[fmt].bpp;
fb->planeinfo.stride = fb->videoinfo.xres * (fb->planeinfo.bpp >> 3);
fb->planeinfo.yres_virtual = fb->videoinfo.yres *
CONFIG_GOLDFISH_FB_FRAME_NBUFFER;
fb->planeinfo.xres_virtual = fb->videoinfo.xres;
fb->planeinfo.fblen = fb->planeinfo.stride * fb->planeinfo.yres_virtual;
fb->planeinfo.fbmem = kmm_zalloc(fb->planeinfo.fblen);
if (fb->planeinfo.fbmem == NULL)
{
gerr("ERROR: Failed to allocate framebuffer memory: %zu KB\n",
fb->planeinfo.fblen / 1024);
ret = -ENOMEM;
goto err_fbmem_alloc_failed;
}
fb->vtable.getplaneinfo = goldfish_getplaneinfo;
fb->vtable.getvideoinfo = goldfish_getvideoinfo;
ret = irq_attach(fb->irq, goldfish_fb_interrupt, fb);
if (ret < 0)
{
goto err_irq_attach_failed;
}
up_enable_irq(fb->irq);
putreg32(GOLDFISH_FB_INT_VSYNC | GOLDFISH_FB_INT_UPDATE_DONE,
fb->base + GOLDFISH_FB_INT_ENABLE);
/* Updates base */
putreg32((uintptr_t)fb->planeinfo.fbmem,
fb->base + GOLDFISH_FB_SET_BASE);
g_goldfish_fb = fb;
return OK;
err_irq_attach_failed:
kmm_free(fb->planeinfo.fbmem);
err_fbmem_alloc_failed:
kmm_free(fb);
return ret;
}
/****************************************************************************
* Name: up_fbgetvplane
****************************************************************************/
FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane)
{
return vplane || display ? NULL : &(g_goldfish_fb->vtable);
}
/****************************************************************************
* Name: up_fbuninitialize
****************************************************************************/
void up_fbuninitialize(int display)
{
if (display == 0)
{
FAR struct goldfish_fb_s *fb = g_goldfish_fb;
irq_detach(fb->irq);
kmm_free(fb->planeinfo.fbmem);
kmm_free(fb);
g_goldfish_fb = NULL;
}
}