mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
drm/rockchip: ebc: Add support for ebc dma-buf exporter
In previous versions, the ebc driver share ebc framebuffer with user space using mmap. But it cannot be shared across multiple subsystems (e.g., GPU, RGA) or user processes. This patch adds support for ebc dma-buf, which exports contiguous ebc framebuffer as a dma-buf, and other modules can process the ebc framebuffer using dma-buf related operations. Signed-off-by: Chaoyi Chen <chaoyi.chen@rock-chips.com> Change-Id: I22ccc68c311490deca57fd1ab0726d53e7e02c6e
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
menuconfig ROCKCHIP_EBC_DEV
|
||||
bool "Rockchip eBook Device Driver"
|
||||
select DMA_SHARED_BUFFER
|
||||
help
|
||||
Rockchip eBook Device Dirver could help to driver the electronic ink screen.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += rkebc.o ebc_public.o
|
||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += rkebc.o ebc_public.o ebc_dma_buf.o
|
||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += epdlut/
|
||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += bufmanage/
|
||||
obj-$(CONFIG_ROCKCHIP_EBC_DEV) += pmic/
|
||||
|
||||
147
drivers/gpu/drm/rockchip/ebc-dev/ebc_dma_buf.c
Normal file
147
drivers/gpu/drm/rockchip/ebc-dev/ebc_dma_buf.c
Normal file
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include "ebc_dma_buf.h"
|
||||
|
||||
struct ebc_dmabuf {
|
||||
phys_addr_t phy_addr;
|
||||
size_t size;
|
||||
int npages;
|
||||
struct page *pages[];
|
||||
};
|
||||
|
||||
static inline struct ebc_dmabuf *to_ebc_dmabuf(struct dma_buf *buf)
|
||||
{
|
||||
return buf->priv;
|
||||
}
|
||||
|
||||
static struct sg_table *ebc_map_dma_buf(struct dma_buf_attachment *attachment,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct ebc_dmabuf *ebcbuf = to_ebc_dmabuf(attachment->dmabuf);
|
||||
struct sg_table *st;
|
||||
int ret;
|
||||
|
||||
st = kzalloc(sizeof(*st), GFP_KERNEL);
|
||||
if (!st)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = sg_alloc_table_from_pages(st, ebcbuf->pages, ebcbuf->npages, 0,
|
||||
ebcbuf->npages << PAGE_SHIFT, GFP_KERNEL);
|
||||
if (ret)
|
||||
goto err_free_st;
|
||||
|
||||
ret = dma_map_sgtable(attachment->dev, st, dir, 0);
|
||||
if (ret)
|
||||
goto err_free_table;
|
||||
|
||||
return st;
|
||||
|
||||
err_free_table:
|
||||
sg_free_table(st);
|
||||
err_free_st:
|
||||
kfree(st);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void ebc_unmap_dma_buf(struct dma_buf_attachment *attachment, struct sg_table *st,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
dma_unmap_sgtable(attachment->dev, st, dir, 0);
|
||||
sg_free_table(st);
|
||||
kfree(st);
|
||||
}
|
||||
|
||||
static int ebc_dmabuf_vmap(struct dma_buf *dma_buf, struct iosys_map *map)
|
||||
{
|
||||
struct ebc_dmabuf *ebcbuf = to_ebc_dmabuf(dma_buf);
|
||||
void *vaddr;
|
||||
|
||||
vaddr = vmap(ebcbuf->pages, ebcbuf->npages, VM_MAP, pgprot_writecombine(PAGE_KERNEL));
|
||||
if (!vaddr)
|
||||
return -ENOMEM;
|
||||
iosys_map_set_vaddr(map, vaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ebc_dmabuf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map)
|
||||
{
|
||||
vunmap(map->vaddr);
|
||||
iosys_map_clear(map);
|
||||
}
|
||||
|
||||
static int ebc_dmabuf_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
|
||||
{
|
||||
struct ebc_dmabuf *ebcbuf = to_ebc_dmabuf(dma_buf);
|
||||
unsigned long pfn;
|
||||
int ret;
|
||||
|
||||
pfn = ((unsigned long)(ebcbuf->phy_addr) >> PAGE_SHIFT);
|
||||
|
||||
vm_flags_set(vma, VM_IO | VM_DONTEXPAND | VM_DONTDUMP);
|
||||
|
||||
ret = remap_pfn_range(vma, vma->vm_start, pfn, vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot);
|
||||
if (ret)
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ebc_dmabuf_release(struct dma_buf *dma_buf)
|
||||
{
|
||||
struct ebc_dmabuf *ebcbuf = to_ebc_dmabuf(dma_buf);
|
||||
|
||||
kfree(ebcbuf);
|
||||
}
|
||||
|
||||
static const struct dma_buf_ops ebc_dmabuf_ops = {
|
||||
.map_dma_buf = ebc_map_dma_buf,
|
||||
.unmap_dma_buf = ebc_unmap_dma_buf,
|
||||
.release = ebc_dmabuf_release,
|
||||
.mmap = ebc_dmabuf_mmap,
|
||||
.vmap = ebc_dmabuf_vmap,
|
||||
.vunmap = ebc_dmabuf_vunmap,
|
||||
};
|
||||
|
||||
struct dma_buf *ebc_get_dma_buf(phys_addr_t phy_addr, size_t size)
|
||||
{
|
||||
struct ebc_dmabuf *ebcbuf;
|
||||
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
|
||||
struct dma_buf *dmabuf;
|
||||
int i, npages;
|
||||
|
||||
if (size % PAGE_SIZE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
npages = size / PAGE_SIZE;
|
||||
ebcbuf = kmalloc(sizeof(*ebcbuf) + npages * sizeof(struct page *), GFP_KERNEL);
|
||||
if (!ebcbuf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
for (i = 0; i < npages; i++)
|
||||
ebcbuf->pages[i] = phys_to_page(phy_addr + i * PAGE_SIZE);
|
||||
|
||||
ebcbuf->phy_addr = phy_addr;
|
||||
ebcbuf->size = size;
|
||||
ebcbuf->npages = npages;
|
||||
|
||||
exp_info.ops = &ebc_dmabuf_ops;
|
||||
exp_info.size = npages * PAGE_SIZE;
|
||||
exp_info.flags = O_RDWR;
|
||||
exp_info.priv = ebcbuf;
|
||||
|
||||
dmabuf = dma_buf_export(&exp_info);
|
||||
if (IS_ERR(dmabuf))
|
||||
goto err;
|
||||
|
||||
return dmabuf;
|
||||
|
||||
err:
|
||||
kfree(ebcbuf);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL(ebc_get_dma_buf);
|
||||
21
drivers/gpu/drm/rockchip/ebc-dev/ebc_dma_buf.h
Normal file
21
drivers/gpu/drm/rockchip/ebc-dev/ebc_dma_buf.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef EBC_DMA_BUF_H
|
||||
#define EBC_DMA_BUF_H
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
|
||||
/**
|
||||
* ebc_get_dma_buf - Convert ebc buffer to dma_buf
|
||||
* @phy_addr: Physical address of the ebc buffer
|
||||
* @size: Size of the ebc buffer
|
||||
*
|
||||
* The caller must ensure that the physical address and size of the ebc buffer
|
||||
* are aligned to PAGE_SIZE.
|
||||
*/
|
||||
struct dma_buf *ebc_get_dma_buf(phys_addr_t phy_addr, size_t size);
|
||||
|
||||
#endif /* EBC_DMA_BUF_H */
|
||||
Reference in New Issue
Block a user