KernelNanopiR5S/drivers/media/platform/rockchip/isp/rkisp_tb_helper.c
2024-09-10 09:59:09 +02:00

300 lines
6.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2020 Rockchip Electronics Co., Ltd. */
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/dma-buf.h>
#include <linux/highmem.h>
#include <linux/soc/rockchip/rockchip_thunderboot_service.h>
#include "rkisp_tb_helper.h"
static struct platform_device *rkisp_tb_pdev;
static struct clk_bulk_data *rkisp_tb_clk;
static int rkisp_tb_clk_num;
static struct rk_tb_client tb_cl;
struct shm_data {
int npages;
struct page *pages[];
};
static struct sg_table *shm_map_dma_buf(struct dma_buf_attachment *attachment,
enum dma_data_direction dir)
{
struct shm_data *data = attachment->dmabuf->priv;
struct sg_table *table;
struct scatterlist *sg;
int i;
table = kmalloc(sizeof(*table), GFP_KERNEL);
if (!table)
return ERR_PTR(-ENOMEM);
sg_alloc_table(table, data->npages, GFP_KERNEL);
sg = table->sgl;
for (i = 0; i < data->npages; i++) {
sg_set_page(sg, data->pages[i], PAGE_SIZE, 0);
sg = sg_next(sg);
}
dma_map_sg_attrs(attachment->dev, table->sgl, table->nents, dir, DMA_ATTR_SKIP_CPU_SYNC);
return table;
}
static void shm_unmap_dma_buf(struct dma_buf_attachment *attachment,
struct sg_table *table,
enum dma_data_direction dir)
{
dma_unmap_sg(attachment->dev, table->sgl, table->nents, dir);
sg_free_table(table);
kfree(table);
}
static void shm_release(struct dma_buf *dma_buf)
{
struct shm_data *data = dma_buf->priv;
kfree(data);
}
static void *shm_vmap(struct dma_buf *dma_buf)
{
struct shm_data *data = dma_buf->priv;
return vm_map_ram(data->pages, data->npages, 0);
}
static void shm_vunmap(struct dma_buf *dma_buf, void *vaddr)
{
struct shm_data *data = dma_buf->priv;
vm_unmap_ram(vaddr, data->npages);
}
static int shm_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma)
{
struct shm_data *data = dma_buf->priv;
unsigned long vm_start = vma->vm_start;
int i;
for (i = 0; i < data->npages; i++) {
remap_pfn_range(vma, vm_start, page_to_pfn(data->pages[i]),
PAGE_SIZE, vma->vm_page_prot);
vm_start += PAGE_SIZE;
}
return 0;
}
static int shm_begin_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir)
{
struct dma_buf_attachment *attachment;
struct sg_table *table;
attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node);
table = attachment->priv;
dma_sync_sg_for_cpu(NULL, table->sgl, table->nents, dir);
return 0;
}
static int shm_end_cpu_access(struct dma_buf *dmabuf, enum dma_data_direction dir)
{
struct dma_buf_attachment *attachment;
struct sg_table *table;
attachment = list_first_entry(&dmabuf->attachments, struct dma_buf_attachment, node);
table = attachment->priv;
dma_sync_sg_for_device(NULL, table->sgl, table->nents, dir);
return 0;
}
static const struct dma_buf_ops shm_dmabuf_ops = {
.map_dma_buf = shm_map_dma_buf,
.unmap_dma_buf = shm_unmap_dma_buf,
.release = shm_release,
.mmap = shm_mmap,
.vmap = shm_vmap,
.vunmap = shm_vunmap,
.begin_cpu_access = shm_begin_cpu_access,
.end_cpu_access = shm_end_cpu_access,
};
static struct dma_buf *shm_alloc(struct rkisp_thunderboot_shmem *shmem)
{
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
struct dma_buf *dmabuf;
struct shm_data *data;
int i, npages;
npages = PAGE_ALIGN(shmem->shm_size) / PAGE_SIZE;
data = kmalloc(sizeof(*data) + npages * sizeof(struct page *), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
data->npages = npages;
for (i = 0; i < npages; i++)
data->pages[i] = phys_to_page(shmem->shm_start + i * PAGE_SIZE);
exp_info.ops = &shm_dmabuf_ops;
exp_info.size = npages * PAGE_SIZE;
exp_info.flags = O_RDWR;
exp_info.priv = data;
dmabuf = dma_buf_export(&exp_info);
return dmabuf;
}
static int __maybe_unused rkisp_tb_clocks_loader_protect(void)
{
int ret = 0;
if (rkisp_tb_pdev) {
pm_runtime_enable(&rkisp_tb_pdev->dev);
pm_runtime_get_sync(&rkisp_tb_pdev->dev);
if (rkisp_tb_clk_num) {
ret = clk_bulk_prepare_enable(rkisp_tb_clk_num, rkisp_tb_clk);
if (ret)
dev_err(&rkisp_tb_pdev->dev, "Cannot enable clock\n");
}
}
return ret;
}
static int __maybe_unused rkisp_tb_clocks_loader_unprotect(void)
{
if (rkisp_tb_pdev) {
if (rkisp_tb_clk_num)
clk_bulk_disable_unprepare(rkisp_tb_clk_num, rkisp_tb_clk);
pm_runtime_put_sync(&rkisp_tb_pdev->dev);
pm_runtime_disable(&rkisp_tb_pdev->dev);
}
return 0;
}
static void rkisp_tb_cb(void *data)
{
rkisp_tb_clocks_loader_unprotect();
}
static int __maybe_unused rkisp_tb_runtime_suspend(struct device *dev)
{
return 0;
}
static int __maybe_unused rkisp_tb_runtime_resume(struct device *dev)
{
return 0;
}
static const struct dev_pm_ops rkisp_tb_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rkisp_tb_runtime_suspend,
rkisp_tb_runtime_resume, NULL)
};
static const struct of_device_id rkisp_tb_plat_of_match[] = {
{
.compatible = "rockchip,thunder-boot-rkisp",
},
{},
};
static int rkisp_tb_plat_probe(struct platform_device *pdev)
{
rkisp_tb_pdev = pdev;
rkisp_tb_clk_num = devm_clk_bulk_get_all(&pdev->dev, &rkisp_tb_clk);
if (rkisp_tb_clk_num <= 0) {
dev_warn(&pdev->dev, "get clk fail:%d\n", rkisp_tb_clk_num);
rkisp_tb_clk_num = 0;
}
rkisp_tb_clocks_loader_protect();
if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE)) {
tb_cl.cb = rkisp_tb_cb;
return rk_tb_client_register_cb(&tb_cl);
}
return 0;
}
static int rkisp_tb_plat_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver __maybe_unused rkisp_tb_plat_drv = {
.driver = {
.name = "rkisp_thunderboot",
.of_match_table = of_match_ptr(rkisp_tb_plat_of_match),
.pm = &rkisp_tb_plat_pm_ops,
},
.probe = rkisp_tb_plat_probe,
.remove = rkisp_tb_plat_remove,
};
static int __init rkisp_tb_plat_drv_init(void)
{
return platform_driver_register(&rkisp_tb_plat_drv);
}
arch_initcall_sync(rkisp_tb_plat_drv_init);
long rkisp_tb_shm_ioctl(struct rkisp_thunderboot_shmem *shmem)
{
struct dma_buf *dmabuf;
int fd, ret;
dmabuf = shm_alloc(shmem);
if (IS_ERR(dmabuf)) {
ret = PTR_ERR(dmabuf);
return ret;
}
fd = dma_buf_fd(dmabuf, O_CLOEXEC);
shmem->shm_fd = fd;
return 0;
}
void rkisp_tb_unprotect_clk(void)
{
if (IS_ENABLED(CONFIG_ROCKCHIP_THUNDER_BOOT_SERVICE))
return;
rkisp_tb_clocks_loader_unprotect();
}
EXPORT_SYMBOL(rkisp_tb_unprotect_clk);
static enum rkisp_tb_state tb_state;
void rkisp_tb_set_state(enum rkisp_tb_state result)
{
tb_state = result;
}
EXPORT_SYMBOL(rkisp_tb_set_state);
enum rkisp_tb_state rkisp_tb_get_state(void)
{
return tb_state;
}
EXPORT_SYMBOL(rkisp_tb_get_state);