Kernel: Add video memory driver

This commit is contained in:
Mingzheng Xing
2023-06-16 22:16:52 +08:00
committed by Han Gao
parent 06b8b8d9f0
commit 3eeff2b39d
16 changed files with 2567 additions and 0 deletions

View File

@@ -5,6 +5,8 @@
menu "Graphics support"
source "drivers/video/video_memory/Kconfig"
if HAS_IOMEM
config HAVE_FB_ATMEL

View File

@@ -13,3 +13,5 @@ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
endif
obj-$(CONFIG_VIDEO_MEMORY) += video_memory/driver/

View File

@@ -0,0 +1,4 @@
config VIDEO_MEMORY
tristate "Video memory driver support"
default m

View File

@@ -0,0 +1,116 @@
##
# Copyright (C) 2020 Alibaba Group Holding Limited
##
ifneq ($(wildcard ../.param),)
include ../.param
endif
#CONFIG_DEBUG_MODE=1
CONFIG_OUT_ENV=hwlinux
CONFIG_BUILD_DRV_EXTRA_PARAM:=""
CONFIG_BUILD_LIB_EXTRA_PARAM:=""
CONFIG_BUILD_TST_EXTRA_PARAM:=""
DIR_TARGET_BASE=bsp/vidmem
DIR_TARGET_KO =bsp/vidmem/ko
DIR_TARGET_TEST=bsp/vidmem/test
MODULE_NAME=vidmem
BUILD_LOG_START="\033[47;30m>>> $(MODULE_NAME) $@ begin\033[0m"
BUILD_LOG_END ="\033[47;30m<<< $(MODULE_NAME) $@ end\033[0m"
#
# Do a parallel build with multiple jobs, based on the number of CPUs online
# in this system: 'make -j8' on a 8-CPU system, etc.
#
# (To override it, run 'make JOBS=1' and similar.)
#
ifeq ($(JOBS),)
JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
ifeq ($(JOBS),)
JOBS := 1
endif
endif
all: info driver lib test install_local_output install_rootfs
.PHONY: info driver lib test install_local_output install_rootfs \
install_prepare install_addons clean_driver clean_test clean_output clean
info:
@echo $(BUILD_LOG_START)
@echo " ====== Build Info from repo project ======"
@echo " BUILDROOT_DIR="$(BUILDROOT_DIR)
@echo " CROSS_COMPILE="$(CROSS_COMPILE)
@echo " LINUX_DIR="$(LINUX_DIR)
@echo " ARCH="$(ARCH)
@echo " BOARD_NAME="$(BOARD_NAME)
@echo " KERNEL_ID="$(KERNELVERSION)
@echo " KERNEL_DIR="$(LINUX_DIR)
@echo " INSTALL_DIR_ROOTFS="$(INSTALL_DIR_ROOTFS)
@echo " INSTALL_DIR_SDK="$(INSTALL_DIR_SDK)
@echo " ====== Build configuration by settings ======"
# @echo " CONFIG_DEBUG_MODE="$(CONFIG_DEBUG_MODE)
@echo " CONFIG_OUT_ENV="$(CONFIG_OUT_ENV)
@echo " JOBS="$(JOBS)
@echo $(BUILD_LOG_END)
driver:
@echo $(BUILD_LOG_START)
make -C $(LINUX_DIR) M=$(PWD)/driver ARCH=$(ARCH) modules
@echo $(BUILD_LOG_END)
clean_driver:
@echo $(BUILD_LOG_START)
make -C driver KDIR=$(LINUX_DIR) clean
@echo $(BUILD_LOG_END)
lib:
@echo $(BUILD_LOG_START)
make -w -C lib
@echo $(BUILD_LOG_END)
clean_lib:
@echo $(BUILD_LOG_START)
make -C lib KDIR=$(LINUX_DIR) clean
@echo $(BUILD_LOG_END)
test: driver
@echo $(BUILD_LOG_START)
make -w -C test hwlinux
@echo $(BUILD_LOG_END)
clean_test:
@echo $(BUILD_LOG_START)
make clean -C test
@echo $(BUILD_LOG_END)
install_prepare:
mkdir -p ./output/rootfs/$(DIR_TARGET_KO)
mkdir -p ./output/rootfs/$(DIR_TARGET_TEST)
install_addons: install_prepare
@echo $(BUILD_LOG_START)
@echo $(BUILD_LOG_END)
install_local_output: driver lib test install_addons
@echo $(BUILD_LOG_START)
find ./driver -name "*.ko" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_KO)
cp -f ./test/vidmem_test ./output/rootfs/$(DIR_TARGET_TEST)
@if [ `command -v tree` != "" ]; then \
tree ./output/rootfs; \
fi
@echo $(BUILD_LOG_END)
install_rootfs: install_local_output
@echo $(BUILD_LOG_START)
@echo $(BUILD_LOG_END)
clean_output:
@echo $(BUILD_LOG_START)
rm -rf ./output
@echo $(BUILD_LOG_END)
clean: clean_output clean_driver clean_lib clean_test

View File

@@ -0,0 +1,3 @@
# How to build
# Description of each directories

View File

@@ -0,0 +1,47 @@
# Copyright 2018 VeriSilicon. All Rights Reserved.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
DEBUG ?= n
ifeq ($(DEBUG),y)
DEBFLAGS = -O -g -DVIDMEM_DEBUG
else
DEBFLAGS = -O2
endif
EXTRA_CFLAGS += $(DEBFLAGS)
ifneq ($(KERNELRELEASE),)
# recursive call from kernel build system
vidmem-objs := video_memory.o rsvmem_pool.o
obj-m += vidmem.o
else
#KDIR := /export/Testing/Board_Version_Control/SW_Common/SOCLE_MDK-3D/openlinux/2.6.29/v0_5/android_linux-2.6.29
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod
rm -rf modules.order Module.symvers

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2022 Alibaba Group. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/mman.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/dma-mapping.h>
#include <linux/dma-buf.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/genalloc.h>
#include "rsvmem_pool.h"
/* 12 bits (4096 bytes) */
#define GEN_POOL_ALLOC_ORDER 12
static rsvmem_pool_info_t rsvmem_pool_regions[MAX_RSVMEM_REGION_COUNT];
int rsvmem_pool_create(struct device *dev)
{
struct device_node *np = dev->of_node;
struct device_node *rsvmem_node;
struct resource res;
int pool_id = 0;
int ret;
if (!dev || !dev->of_node)
return -EINVAL;
rsvmem_node = of_parse_phandle(np, "memory-region", 0);
if (!rsvmem_node) {
dev_notice(dev, "No memory region node\n");
return -ENODEV;
}
while (pool_id < MAX_RSVMEM_REGION_COUNT &&
of_address_to_resource(rsvmem_node, pool_id, &res) == 0) {
struct gen_pool *pool = gen_pool_create(GEN_POOL_ALLOC_ORDER, -1);
if (pool == NULL) {
dev_err(dev, "Failed to create reserved memory pool region[%d]\n", pool_id);
return -ENOMEM;
}
ret = gen_pool_add(pool, res.start, resource_size(&res), -1);
if (ret) {
dev_err(dev, "%s: gen_pool_add failed\n", __func__);
gen_pool_destroy(pool);
return ret;
}
rsvmem_pool_regions[pool_id].pool = pool;
rsvmem_pool_regions[pool_id].base = res.start;
rsvmem_pool_regions[pool_id].size = resource_size(&res);
dev_err(dev, "%s: rsvmem_pool_region[%d] = {pool=%px, base=0x%llx, size=0x%llx}\n",
__func__, pool_id, rsvmem_pool_regions[pool_id].pool,
rsvmem_pool_regions[pool_id].base, rsvmem_pool_regions[pool_id].size);
pool_id ++;
}
return 0;
}
void rsvmem_pool_destroy(void)
{
int i;
for (i = 0; i < MAX_RSVMEM_REGION_COUNT; i++) {
if (rsvmem_pool_regions[i].pool != NULL) {
gen_pool_destroy(rsvmem_pool_regions[i].pool);
memset(&rsvmem_pool_regions[i], 0, sizeof(rsvmem_pool_info_t));
}
}
}
unsigned long rsvmem_pool_alloc(int region_id, size_t size)
{
struct gen_pool *pool;
unsigned long addr;
if (region_id < 0 || region_id >= MAX_RSVMEM_REGION_COUNT) {
pr_err("%s: region_id(%d) is invalid\n", __func__, region_id);
return 0;
}
pool = rsvmem_pool_regions[region_id].pool;
if (pool == NULL) {
pr_err("%s: pool region[%d] is invalid\n", __func__, region_id);
return 0;
}
addr = gen_pool_alloc(pool, size);
pr_debug("%s: Allocated %zu bytes from pool region[%d]: 0x%08lx\n", __func__, size, region_id, addr);
return addr;
}
void rsvmem_pool_free(int region_id, size_t size, unsigned long addr)
{
struct gen_pool *pool;
if (region_id < 0 || region_id >= MAX_RSVMEM_REGION_COUNT) {
pr_err("%s: region_id(%d) is invalid\n", __func__, region_id);
return;
}
pool = rsvmem_pool_regions[region_id].pool;
if (pool == NULL) {
pr_err("%s: rsvmem pool region[%d] is invalid\n", __func__, region_id);
return;
}
gen_pool_free(pool, addr, size);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2022 Alibaba Group. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __RSVMEM_POOL_H_
#define __RSVMEM_POOL_H_
#define MAX_RSVMEM_REGION_COUNT 16
typedef struct rsvmem_pool_info
{
struct gen_pool *pool; // NULL means unavalible
resource_size_t base;
resource_size_t size;
} rsvmem_pool_info_t;
int rsvmem_pool_create(struct device *dev);
void rsvmem_pool_destroy(void);
unsigned long rsvmem_pool_alloc(int region_id, size_t size);
void rsvmem_pool_free(int region_id, size_t size, unsigned long addr);
#endif /* __RSVMEM_POOL_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2021 - 2022 Alibaba Group. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __VIDEO_MEMORY_H_
#define __VIDEO_MEMORY_H_
#define IN
#define OUT
#define INOUT
#define OPTIONAL
/* No special needs. */
#define ALLOC_FLAG_NONE 0x00000000
/* Physical contiguous. */
#define ALLOC_FLAG_CONTIGUOUS 0x00000001
/* Physical non contiguous. */
#define ALLOC_FLAG_NON_CONTIGUOUS 0x00000002
/* Need 32bit address. */
#define ALLOC_FLAG_4GB_ADDR 0x00000004
/* CMA priority */
#define ALLOC_FLAG_CMA 0x00000008
/* Use VI reserved memory */
#define ALLOC_FLAG_VI 0x00000010
/* Alloc rsvmem pool region id should be 0~15 */
#define SET_ALLOC_FLAG_REGION(flag, region_id) (flag & 0x00ffffff) | (region_id << 24)
#define GET_ALLOC_FLAG_REGION(flag) (flag >> 24)
#define MEMORY_IOC_MAGIC 'a'
#define MEMORY_IOC_ALLOCATE _IOWR(MEMORY_IOC_MAGIC, 1, VidmemParams *)
#define MEMORY_IOC_FREE _IOWR(MEMORY_IOC_MAGIC, 2, VidmemParams *)
#define MEMORY_IOC_DMABUF_EXPORT _IOWR(MEMORY_IOC_MAGIC, 3, VidmemParams *)
#define MEMORY_IOC_DMABUF_IMPORT _IOWR(MEMORY_IOC_MAGIC, 4, VidmemParams *)
#define MEMORY_IOC_DMABUF_RELEASE _IOWR(MEMORY_IOC_MAGIC, 5, VidmemParams *)
#define MEMORY_IOC_MAXNR 5
typedef struct {
unsigned long bus_address;
unsigned int size;
unsigned long translation_offset;
int fd;
int flags;
} VidmemParams;
#endif /* __VIDEO_MEMORY_H_ */

View File

@@ -0,0 +1,16 @@
CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
INCLUDE += -I../driver
SRCS = video_mem.c
OUT_PATH = ../output/rootfs/bsp/vidmem/lib
TARGET = $(OUT_PATH)/libvmem.so
$(TARGET):
$(shell if [ ! -e $(OUT_PATH) ];then mkdir -p $(OUT_PATH); fi)
$(CC) $(SRCS) $(CFLAGS) $(INCLUDE) -shared -o $(TARGET)
clean:
$(RM) -r $(OUT_PATH)

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed 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.
*
*/
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include "video_memory.h"
#include "video_mem.h"
#define VMEM_PRINT(level, ...) \
{ \
if (log_level >= VMEM_LOG_##level) \
{ \
printf("VMEM[%d] %s: ", pid, #level); \
printf(__VA_ARGS__); \
} \
}
#define VMEM_LOGE(...) VMEM_PRINT(ERROR, __VA_ARGS__)
#define VMEM_LOGW(...) VMEM_PRINT(WARNING, __VA_ARGS__)
#define VMEM_LOGI(...) VMEM_PRINT(INFO, __VA_ARGS__)
#define VMEM_LOGD(...) VMEM_PRINT(DEBUG, __VA_ARGS__)
#define VMEM_LOGT(...) VMEM_PRINT(TRACE, __VA_ARGS__)
typedef enum _VmemLogLevel
{
VMEM_LOG_QUIET = 0,
VMEM_LOG_ERROR,
VMEM_LOG_WARNING,
VMEM_LOG_INFO,
VMEM_LOG_DEBUG,
VMEM_LOG_TRACE,
VMEM_LOG_MAX
} VmemLogLevel;
typedef struct _VmemContext
{
int fd_alloc;
} VmemContext;
int log_level = VMEM_LOG_ERROR;
int pid = 0;
static int getLogLevel();
VmemStatus
VMEM_create(void **vmem)
{
VmemContext *ctx = NULL;
log_level = getLogLevel();
pid = getpid();
if (vmem == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)malloc(sizeof(*ctx));
if (ctx == NULL)
return VMEM_STATUS_NO_MEMORY;
*vmem = (void *)ctx;
ctx->fd_alloc = open("/dev/vidmem", O_RDWR);
if (ctx->fd_alloc == -1)
{
VMEM_LOGE("Failed to open /dev/vidmem\n");
return VMEM_STATUS_ERROR;
}
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_allocate(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
VidmemParams p;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
params->phy_address = 0;
params->vir_address = NULL;
params->fd = -1;
memset(&p, 0, sizeof(p));
p.size = params->size;
p.flags = params->flags;
ioctl(ctx->fd_alloc, MEMORY_IOC_ALLOCATE, &p);
if (p.bus_address == 0)
{
VMEM_LOGE("Failed to allocate memory\n");
return VMEM_STATUS_NO_MEMORY;
}
params->phy_address = p.bus_address;
VMEM_LOGI("Allocated %d bytes, phy addr 0x%08x\n",
params->size, params->phy_address);
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_mmap(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
void *vir_addr;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
if (params->vir_address != NULL)
return VMEM_STATUS_OK;
ctx = (VmemContext *)vmem;
int fd = params->fd > 0 ? params->fd : ctx->fd_alloc;
unsigned int offset = params->fd > 0 ? 0 : params->phy_address;
vir_addr = mmap(0, params->size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset);
if (vir_addr == MAP_FAILED)
{
VMEM_LOGE("Failed to mmap physical address: 0x%08x, using fd %d\n",
params->phy_address, fd);
return VMEM_STATUS_ERROR;
}
params->vir_address = vir_addr;
VMEM_LOGI("Mapped phy addr 0x%08x to vir addr %p, size %d\n",
params->phy_address, params->vir_address, params->size);
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_free(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
VidmemParams p;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
VMEM_LOGI("Free virt addr %p, phy addr 0x%08x, size %d\n",
params->vir_address, params->phy_address, params->size);
if (params->vir_address != MAP_FAILED && params->vir_address != NULL)
munmap(params->vir_address, params->size);
params->vir_address = NULL;
if (params->phy_address != 0)
{
memset(&p, 0, sizeof(p));
p.bus_address = params->phy_address;
ioctl(ctx->fd_alloc, MEMORY_IOC_FREE, &p);
params->phy_address = 0;
}
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_destroy(void *vmem)
{
if (vmem != NULL)
{
VmemContext *ctx = (VmemContext *)vmem;
if (ctx->fd_alloc != -1)
close(ctx->fd_alloc);
free(vmem);
}
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_export(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
VidmemParams p;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
memset(&p, 0, sizeof(p));
p.bus_address = params->phy_address;
p.flags = O_RDWR;
ioctl(ctx->fd_alloc, MEMORY_IOC_DMABUF_EXPORT, &p);
if (p.fd < 0) {
VMEM_LOGE("Failed to export memory\n");
return VMEM_STATUS_ERROR;
}
params->fd = p.fd;
VMEM_LOGI("Exported phy addr 0x%08x to fd %d, size %d\n",
params->phy_address, params->fd, params->size);
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_import(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
VidmemParams p;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
memset(&p, 0, sizeof(p));
p.fd = params->fd;
ioctl(ctx->fd_alloc, MEMORY_IOC_DMABUF_IMPORT, &p);
if (p.bus_address == 0 || p.size == 0) {
VMEM_LOGE("Failed to import memory\n");
return VMEM_STATUS_ERROR;
}
params->phy_address = p.bus_address;
params->size = p.size;
VMEM_LOGI("Imported fd %d to phy addr 0x%08x, size %d\n",
params->fd, params->phy_address, params->size);
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_release(void *vmem, VmemParams *params)
{
VmemContext *ctx = NULL;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
VMEM_LOGI("Released imported phy addr 0x%08x, fd %d, size %d\n",
params->phy_address, params->fd, params->size);
if (params->vir_address != MAP_FAILED && params->vir_address != NULL)
munmap(params->vir_address, params->size);
params->vir_address = NULL;
if (params->phy_address != 0) {
VidmemParams p;
memset(&p, 0, sizeof(p));
p.bus_address = params->phy_address;
ioctl(ctx->fd_alloc, MEMORY_IOC_DMABUF_RELEASE, &p);
params->phy_address = 0;
}
return VMEM_STATUS_OK;
}
static int getLogLevel()
{
char *env = getenv("VMEM_LOG_LEVEL");
if (env == NULL)
return VMEM_LOG_ERROR;
else
{
int level = atoi(env);
if (level >= VMEM_LOG_MAX || level < VMEM_LOG_QUIET)
return VMEM_LOG_ERROR;
else
return level;
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed 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.
*
*/
#ifndef _VIDEO_MEM_H_
#define _VIDEO_MEM_H_
#ifdef __cplusplus
extern "C" {
#endif
/* No special needs. */
#define VMEM_FLAG_NONE 0x00000000
/* Physical contiguous. */
#define VMEM_FLAG_CONTIGUOUS 0x00000001
/* Physical non contiguous. */
#define VMEM_FLAG_NON_CONTIGUOUS 0x00000002
/* Need 32bit address. */
#define VMEM_FLAG_4GB_ADDR 0x00000004
/* CMA priority */
#define VMEM_FLAG_CMA 0x00000008
/* Use VI reserved memory */
#define VMEM_FLAG_VI 0x00000010
/* Alloc rsvmem pool region id should be 0~15 */
#define SET_ALLOC_FLAG_REGION(flag, region_id) (flag & 0x00ffffff) | (region_id << 24)
#define GET_ALLOC_FLAG_REGION(flag) (flag >> 24)
typedef enum _VmemStatus
{
VMEM_STATUS_OK = 0,
VMEM_STATUS_ERROR = -1, /* general error */
VMEM_STATUS_NO_MEMORY = -2, /* not enough memory to allocate buffer */
} VmemStatus;
typedef struct _VmemParams
{
int size;
int flags;
unsigned int phy_address;
void *vir_address;
int fd;
} VmemParams;
VmemStatus VMEM_create(void **vmem);
VmemStatus VMEM_allocate(void *vmem, VmemParams *params);
VmemStatus VMEM_mmap(void *vmem, VmemParams *params);
VmemStatus VMEM_free(void *vmem, VmemParams *params);
VmemStatus VMEM_destroy(void *vmem);
VmemStatus VMEM_export(void *vmem, VmemParams *params);
VmemStatus VMEM_import(void *vmem, VmemParams *params);
VmemStatus VMEM_release(void *vmem, VmemParams *params);
#ifdef __cplusplus
}
#endif
#endif /* !_VIDEO_MEM_H_ */

View File

@@ -0,0 +1,70 @@
CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
INCLUDE += -I../lib
SRCS = video_memory_test.c
OBJS = $(SRCS:.c=.o)
#source search path
vpath %.c
# name of the outputfile (library)
TARGET = vidmem_test
#Here are rules for building codes and generating object library.
all: tags
@echo ---------------------------------------
@echo "Usage: make [ system | testdata | versatile | integrator | android]"
@echo "system - PC system model (== pclinux)"
@echo "testdata - PC system model for test data creation"
@echo "eval - PC system model for evaluation with frame limit"
@echo "versatile - ARM versatile with FPGA HW"
@echo "integrator - ARM integrator with FPGA HW"
@echo "android - ARM android"
@echo "NOTE! Make sure to do 'make clean'"
@echo "between compiling to different targets!"
@echo ---------------------------------------
.PHONY: system_lib system testdata clean depend
evaluation: eval
eval: system
system_static: testdata
system: testdata
# for libva
system_lib: system
testdata: .depend
.PHONY: hwlinux
hwlinux:
hwlinux: .depend $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -L../output/rootfs/bsp/vidmem/lib -lvmem -lm -lpthread -o $(TARGET)
%.o: %.c
$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
clean:
$(RM) $(TARGET)
$(RM) .depend
$(RM) *.o *.gcno *.gcda
tags:
ctags ../kernel_mode/*h ./*[ch]
depend .depend: $(SRCS)
@echo "[CC] $@"
@$(CC) -M $(DEBFLAGS) $(INCLUDE) $^ > .depend
ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
ifeq (.depend, $(wildcard .depend))
include .depend
endif
endif

Binary file not shown.

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
* License-Identifier: Apache-2.0
*
* Licensed 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.
*
*/
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include "video_mem.h"
typedef enum MemType
{
MEM_TYPE_CONTIGUOUS,
MEM_TYPE_NONCONTIGUOUS,
MEM_TYPE_CMA,
MEM_TYPE_VI,
MEM_TYPE_MAX
} MemType;
int alloc_flags[MEM_TYPE_MAX] =
{
VMEM_FLAG_CONTIGUOUS | VMEM_FLAG_4GB_ADDR,
VMEM_FLAG_NON_CONTIGUOUS,
VMEM_FLAG_CMA,
VMEM_FLAG_VI
};
int alloc_num[MEM_TYPE_MAX] = {3, 3, 3, 3};
void printUsage(char *name)
{
printf(" \
Usage: %s [buf_size|-h]\n\
buf_size: buffer size to be allocated, in unit of 4K pages\n\
-h: print this message\n",
name);
}
int main(int argc, char **argv)
{
int fd_alloc = -1;
int size = 1920*1080*3/2;
int pgsize = getpagesize();
void *vmem = NULL;
VmemParams *vmparams[MEM_TYPE_MAX] = {0};
int err = 0;
if (argc > 1)
{
if (strcmp(argv[1], "-h") == 0)
{
printUsage(argv[0]);
return 0;
}
else
size = atoi(argv[1]) * pgsize;
}
if (size <= 0)
{
printf("ERROR: invalid size: %d\n", size);
printUsage(argv[0]);
return -1;
}
do
{
if (VMEM_create(&vmem) != VMEM_STATUS_OK)
break;
VmemParams imp_params;
for (int type = 0; type < MEM_TYPE_MAX; type++)
{
vmparams[type] = malloc(sizeof(VmemParams)*alloc_num[type]);
if (vmparams[type] == NULL)
{
printf("ERROR: Failed to allocate VmemParams\n");
err = 1;
break;
}
for (int i = 0; i < alloc_num[type]; i++)
{
VmemParams *params = &vmparams[type][i];
memset(params, 0, sizeof(*params));
params->size = size;
params->flags = alloc_flags[type];
int vi_rsvmem_pool_region_id = i; // only for type == MEM_TYPE_VI
if (type == MEM_TYPE_VI)
{
params->flags = SET_ALLOC_FLAG_REGION(params->flags, vi_rsvmem_pool_region_id);
}
if (VMEM_allocate(vmem, params) != VMEM_STATUS_OK)
{
if (type == MEM_TYPE_VI)
printf("ERROR: Failed to allocate memory type %d, region_id=%d\n",
type, vi_rsvmem_pool_region_id);
else
printf("ERROR: Failed to allocate memory type %d\n", type);
break;
}
if (VMEM_mmap(vmem, params) != VMEM_STATUS_OK)
{
printf("ERROR: Failed to mmap busAddress: 0x%08x\n",
params->phy_address);
err = 1;
break;
}
if (VMEM_export(vmem, params) != VMEM_STATUS_OK)
{
printf("ERROR: Failed to export buffer: 0x%08x\n",
params->phy_address);
err = 1;
break;
}
printf("Allocated buffer %d of type %d at paddr 0x%08x vaddr %p size %d fd %d\n",
i, type, params->phy_address, params->vir_address, size, params->fd);
memset(&imp_params, 0, sizeof(imp_params));
imp_params.fd = params->fd;
if (VMEM_import(vmem, &imp_params) != VMEM_STATUS_OK)
{
printf("ERROR: Failed to import fd %d\n", params->fd);
err = 1;
break;
}
printf("Imported fd %d: paddr 0x%08x vaddr %p size %d\n",
params->fd, params->phy_address, params->vir_address, size);
VMEM_release(vmem, &imp_params);
}
if (err)
break;
}
} while (0);
for (int type = 0; type < MEM_TYPE_MAX; type++)
{
for (int i = 0; i < alloc_num[type]; i++)
{
VmemParams *params = &vmparams[type][i];
VMEM_free(vmem, params);
memset(params, 0, sizeof(*params));
}
if (vmparams[type])
free(vmparams[type]);
}
VMEM_destroy(vmem);
return 0;
}