ARGB8888 --> ARGB4444&Other Formats

本文详细介绍了如何将ARGB8888色彩空间转换为ARGB4444、RGB555及RGB565色彩空间的具体实现方法。通过位操作和移位指令,实现了不同色彩空间之间的高效转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

int argb8888;
int a=(argb8888 & 0xff000000)>>24;
int r=(argb8888 & 0x00ff0000)>>16;
int g=(argb8888 & 0x0000ff00)>>8;
int b=(argb8888 & 0x000000ff)>>0;
 
short argb4444=((a>>4)<<12)|((r>>4)<<8)|((g>>4)<<4)|((b>>4)<<0);
short rgb555=((r>>3)<<10)|((g>>3)<<5)|((b>>3)<<0); 
short rgb565=((r>>3)<<11)|((g>>2)<<5)|(b>>3); 

 
/* * SEMIDRIVE Copyright Statement * Copyright (c) SEMIDRIVE. All rights reserved * This software and all rights therein are owned by SEMIDRIVE, * and are protected by copyright law and other relevant laws, regulations and protection. * Without SEMIDRIVE’s prior written consent and /or related rights, * please do not use this software or any potion thereof in any form or by any means. * You may not reproduce, modify or distribute this software except in compliance with the License. * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * You should have received a copy of the License along with this program. * If not, see <http://www.semidrive.com/licenses/>. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/component.h> #include <linux/fs.h> #include <linux/dma-buf.h> #include <linux/interrupt.h> #include <linux/iommu.h> #include <linux/pm_runtime.h> #include <linux/bitops.h> #include <linux/uaccess.h> #include <linux/list.h> #include <linux/string.h> #include <linux/bug.h> #include <linux/errno.h> #include <asm/current.h> #ifdef CONFIG_OF #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_device.h> #include <linux/of_platform.h> #else #include <linux/slab.h> #include <linux/io.h> #include <linux/irq.h> #endif #include "sdrv_g2d.h" #include "g2d_common.h" static DEFINE_MUTEX(m_init); extern const struct g2d_ops g2d_normal_ops; extern const struct g2d_ops g2d_lite_ops; extern struct ops_entry spipe_g2d_entry; extern struct ops_entry gpipe_mid_g2d_entry; extern struct ops_entry gpipe_high_g2d_entry; extern int g2d_dump_registers(struct sdrv_g2d *dev); extern int g2d_post_config(struct sdrv_g2d *dev, struct g2d_input *ins); extern int g2d_fastcopy_set(struct sdrv_g2d *dev, addr_t iaddr, u32 width, u32 height, u32 istride, addr_t oaddr, u32 ostride); extern int g2d_fill_rect(struct sdrv_g2d *dev, struct g2d_bg_cfg *bgcfg, struct g2d_output_cfg *output); extern int g2d_set_coefficients_table(struct sdrv_g2d *gd, struct g2d_coeff_table *table); extern struct attribute *sdrv_g2d_attrs[]; static const struct attribute_group *sdrv_g2d_groups[]; ATTRIBUTE_GROUPS(sdrv_g2d); static int wait_timeout = 500; module_param(wait_timeout, int, 0660); MODULE_PARM_DESC(wait_timeout, "wait timeout (ms)"); static int dump_register_g2d = 0; module_param(dump_register_g2d, int, 0660); MODULE_PARM_DESC(dump_register_g2d, "dump register g2d 0:off 1:on"); int debug_g2d = 0; EXPORT_SYMBOL(debug_g2d); module_param(debug_g2d, int, 0660); MODULE_PARM_DESC(debug_g2d, "debug g2d 0:off 1:on"); static char *version = KO_VERSION; module_param(version, charp, S_IRUGO); LIST_HEAD(g2d_pipe_list_head); int g2d_major = 227; int g2d_minor = -1; static struct sdrv_g2d *g_g2d[G2D_NR_DEVS]; const char *PIPE_TYPE_STRING[] = { GP_ECHO_NAME, GP_MID_NAME, GP_HIGH_NAME, SPIPE_NAME }; struct sdrv_g2d_data g2d_data[] = { {.version = "g2dlite-r0p0", .ops = &g2d_lite_ops}, {.version = "g2d-r0p1", .ops = &g2d_normal_ops}, {}, }; static void dump_input(struct g2d_input *input) { struct g2d_output_cfg *output = &input->output; struct g2d_layer *layer; struct g2d_bg_cfg *bg = &input->bg_layer; int i = 0; if (bg->en) { G2D_ERROR("[dump bg layer] en:%d, color:0x%x, g_alpha:0x%x, zorder:%d, bpa:0x%x, \ astride:%d, rect(%d, %d, %d, %d), pd_type:%d, fd:%d \n", bg->en, bg->color, bg->g_alpha, bg->zorder, bg->bpa, bg->astride, bg->x, bg->y, bg->width, bg->height, bg->pd_type, bg->abufs.fd); } for (i = 0; i < input->layer_num; i++) { layer = &input->layer[i]; G2D_ERROR("[dumplayer] index = %d, *ENABLE = %d*, format: %c%c%c%c source (%d, %d, %d, %d) => dest (%d, %d, %d, %d)\n", layer->index, layer->enable, layer->format & 0xff, (layer->format >> 8) & 0xff, (layer->format >> 16) & 0xff, (layer->format >> 24) & 0xff, layer->src_x, layer->src_y, layer->src_w, layer->src_h, layer->dst_x, layer->dst_y, layer->dst_w, layer->dst_h); } G2D_ERROR("[dump output]: w,h(%d,%d) format:%c%c%c%c rota:%d nplanes:%d\n", output->width, output->height, output->fmt & 0xff, (output->fmt >> 8) & 0xff, (output->fmt >> 16) & 0xff, (output->fmt >> 24) & 0xff, output->rotation, output->nplanes); return; } struct sdrv_g2d *get_g2d_by_id(int id) { return g_g2d[id]; } int g2d_ops_register(struct ops_entry *entry, struct list_head *head) { struct ops_list *list; list = kzalloc(sizeof(struct ops_list), GFP_KERNEL); if (!list) return -ENOMEM; list->entry = entry; list_add(&list->head, head); return 0; } void *g2d_ops_attach(const char *str, struct list_head *head) { struct ops_list *list; const char *ver; list_for_each_entry(list, head, head) { ver = list->entry->ver; if (!strcmp(str, ver)) return list->entry->ops; } G2D_ERROR("attach disp ops %s failed\n", str); return NULL; } irqreturn_t sdrv_g2d_irq_handler(int irq, void *data) { struct sdrv_g2d *gd = data; uint32_t val; if (!gd->du_inited) { G2D_ERROR("g2d du_inited does not init\n"); return IRQ_HANDLED; } val = gd->ops->irq_handler(gd); if (val & G2D_INT_MASK_FRM_DONE) { G2D_DBG("frame done\n"); gd->frame_done = true; wake_up(&gd->wq); } return IRQ_HANDLED; } int g2d_choose_pipe(struct sdrv_g2d *gd, int hwid, int type, uint32_t offset) { struct g2d_pipe *p = NULL; p = devm_kzalloc(&gd->pdev->dev, sizeof(struct g2d_pipe), GFP_KERNEL); if (!p) return -ENOMEM; p->type = type; p->name = PIPE_TYPE_STRING[type]; p->ops = (struct pipe_operation*)g2d_pipe_ops_attach(p->name); if (!p->ops) { G2D_ERROR("error ops attached\n"); return -EINVAL; } p->regs = gd->regs + (ulong)offset; p->iomem_regs = gd->iomem_regs + (ulong)offset; p->reg_offset = offset; p->id = hwid; p->gd = gd; gd->pipes[gd->num_pipe] = p; gd->num_pipe++; p->ops->init(p); G2D_DBG("pipe %d name %s registered\n", p->id, p->name); return 0; } #ifdef CONFIG_OF int sdrv_g2d_init(struct sdrv_g2d *gd, struct device_node *np) { int i, ret; int irq_num; struct resource res; const char *str; const struct sdrv_g2d_data *data; static int g2d_cnt = 0; if (!np || !gd) return -ENODEV; if(!of_device_is_available(np)) { G2D_ERROR("OF node %s not available or match\n", np->name); return -ENODEV; } if (!of_property_read_string(np, "sdrv,ip", &str)) { gd->name = str; } else { G2D_ERROR("sdrv,ip can not found\n"); return -ENODEV; } if (of_address_to_resource(np, 0, &res)) { G2D_ERROR("parse dt base address failed\n"); return -ENODEV; } G2D_INFO("got %s res 0x%lx\n", gd->name, (unsigned long)res.start); gd->regs = (void *)res.start; gd->iomem_regs = devm_ioremap_nocache(&gd->pdev->dev, res.start, resource_size(&res)); if(IS_ERR(gd->iomem_regs)) { G2D_ERROR("Cannot find g2d regs 001\n"); return PTR_ERR(gd->regs); } irq_num = irq_of_parse_and_map(np, 0); if (!irq_num) { G2D_ERROR("error: g2d parse irq num failed\n"); return -EINVAL; } G2D_INFO("g2d irq_num = %d\n", irq_num); data = of_device_get_match_data(&gd->pdev->dev); for (i = 0; i < 3; i++) { if (!strcmp(gd->name, data[i].version)) { gd->ops = data[i].ops; G2D_INFO("%s ops[%d] attached\n", gd->name, i); break; } } if (gd->ops == NULL) { G2D_ERROR("core ops attach failed, have checked %d times\n", i); return -1; } gd->num_pipe = 0; // g2d init gd->ops->init(gd); gd->irq = irq_num; gd->cap.num_pipe = gd->num_pipe; for (i = 0; i < gd->num_pipe; i++) { memcpy(&gd->cap.pipe_caps[i], gd->pipes[i]->cap, sizeof(struct g2d_pipe_capability)); } gd->id = g2d_cnt; irq_set_status_flags(gd->irq, IRQ_NOAUTOEN); ret = devm_request_irq(&gd->pdev->dev, gd->irq, sdrv_g2d_irq_handler, 0, dev_name(&gd->pdev->dev), gd); //IRQF_SHARED if(ret) { G2D_ERROR("Failed to request DC IRQ: %d\n", gd->irq); return -ENODEV; } //wait queue init_waitqueue_head(&gd->wq); gd->frame_done = false; g2d_cnt++; return 0; } #else int sdrv_g2d_init(struct sdrv_g2d *gd, struct platform_device *pdev) { int i, ret; int irq_num; struct device *dev = &pdev->dev; struct resource *res; const char *str; const struct sdrv_g2d_data *data; struct g2d_platform_data *pdata; static int g2d_cnt = 0; if (!pdev || !gd) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gd->regs = (void *)res->start; gd->iomem_regs = devm_ioremap_nocache(&gd->pdev->dev, res->start, resource_size(res)); if(IS_ERR(gd->iomem_regs)) { G2D_ERROR("Cannot find g2d regs 001\n"); return PTR_ERR(gd->regs); } pdata = (struct g2d_platform_data *)platform_get_drvdata(pdev); gd->name = "g2d-r0p1"; if (!gd->name) { G2D_ERROR("sdrv,ip can not found\n"); return -ENODEV; } G2D_INFO("got %s res 0x%lx\n", gd->name, (unsigned long)gd->regs); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq_num = (int) res->start; if (!irq_num) { G2D_ERROR("error: g2d parse irq num failed\n"); return -EINVAL; } G2D_INFO("g2d irq_num = %d\n", irq_num); data = g2d_data; for (i = 0; i < 16; i++) { if (!strcmp(gd->name, data[i].version)) { gd->ops = data[i].ops; G2D_DBG("%s ops[%d] attached\n", gd->name, i); break; } } if (gd->ops == NULL) { G2D_ERROR("core ops attach failed, have checked %d times\n", i); return -1; } gd->num_pipe = 0; // g2d init gd->ops->init(gd); gd->irq = irq_num; gd->cap.num_pipe = gd->num_pipe; for (i = 0; i < gd->num_pipe; i++) { memcpy(&gd->cap.pipe_caps[i], gd->pipes[i]->cap, sizeof(struct g2d_pipe_capability)); } gd->id = g2d_cnt; irq_set_status_flags(gd->irq, IRQ_NOAUTOEN); ret = devm_request_irq(&gd->pdev->dev, gd->irq, sdrv_g2d_irq_handler, 0, dev_name(&gd->pdev->dev), gd); //IRQF_SHARED if(ret) { G2D_ERROR("Failed to request DC IRQ: %d\n", gd->irq); return -ENODEV; } //wait queue init_waitqueue_head(&gd->wq); gd->frame_done = false; g2d_cnt++; return 0; } #endif static void sdrv_g2d_unit(struct sdrv_g2d *gd) { if (!gd) return; // if (gd->ops->uninit) // gd->ops->uninit(gd); } static int sdrv_g2d_open(struct inode *node, struct file *file) { int i; struct sdrv_g2d *gd = NULL; int num = MINOR(node->i_rdev); if (num < 0) return -ENODEV; for (i = 0; i < G2D_NR_DEVS; i++){ gd = get_g2d_by_id(i); if (gd->mdev.minor == num) break; } file->private_data = gd; G2D_DBG("open node %s\n", gd->name); return 0; } static int sdrv_init_iommu(struct sdrv_g2d *gd) { struct device *dev = &gd->pdev->dev; struct device_node *iommu = NULL; struct property *prop = NULL; struct iommu_domain_geometry *geometry; u64 start, end; int ret = 0; gd->iommu_enable = false; iommu = of_parse_phandle(dev->of_node, "iommus", 0); if(!iommu) { G2D_DBG("iommu not specified\n"); return ret; } if (!of_device_is_available(iommu)) { G2D_DBG("smmu disabled\n"); return ret; } prop = of_find_property(dev->of_node, "smmu", NULL); if(!prop) { G2D_DBG("smmu bypassed\n"); return ret; } gd->domain = iommu_get_domain_for_dev(dev); if(!gd->domain) { ret = -ENOMEM; goto err_free_mm;; } geometry = &gd->domain->geometry; start = geometry->aperture_start; end = GENMASK(37, 0);// 38 bits address for KUNLUN G2D rdma G2D_DBG("IOMMU context initialized: %#llx - %#llx\n", start, end); gd->iommu_enable = true; of_node_put(iommu); return ret; err_free_mm: of_node_put(iommu); return ret; } static void sdrv_iommu_cleanup(struct sdrv_g2d *gd) { if(!gd->iommu_enable) return; iommu_domain_free(gd->domain); } static unsigned long _get_contiguous_size(struct sg_table *sgt) { struct scatterlist *s; dma_addr_t expected = sg_dma_address(sgt->sgl); unsigned int i; unsigned long size = 0; for_each_sg(sgt->sgl, s, sgt->nents, i) { if (sg_dma_address(s) != expected) break; expected = sg_dma_address(s) + sg_dma_len(s); size += sg_dma_len(s); } return size; } static int g2d_dmabuf_import(struct sdrv_g2d *gd, struct g2d_buf *buf) { struct dma_buf_attachment *attach; struct sg_table *sgt; struct dma_buf *dmabuf; int ret = 0; if (buf->fd < 0) { G2D_ERROR("dmabuf handle invalid: %d\n", buf->fd); return -EINVAL; } buf->vaddr = (unsigned long)NULL; dmabuf = dma_buf_get(buf->fd); if (IS_ERR_OR_NULL(dmabuf)) { G2D_ERROR("g2d get dmabuf err from buf fd %d\n", buf->fd); return PTR_ERR(dmabuf); } attach = dma_buf_attach(dmabuf, &gd->pdev->dev); if (IS_ERR(attach)) { G2D_ERROR("dma buf attach devices faild\n"); goto out_put; } sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); G2D_ERROR("Error getting dmabuf scatterlist: errno %ld\n", PTR_ERR(sgt)); goto fail_detach; } buf->attach = attach; buf->size = _get_contiguous_size(sgt); buf->dma_addr = sg_dma_address(sgt->sgl); buf->sgt = sgt; buf->vaddr = (unsigned long)NULL; G2D_DBG("buf->size = 0x%llx \n", buf->size); if (!buf->size) { G2D_ERROR("dma buf map attachment faild, buf->size = %lld \n", buf->size); ret = -EINVAL; goto fail_unmap; } goto out_put; fail_unmap: dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dmabuf, attach); out_put: dma_buf_put(dmabuf); return ret; } static void g2d_dmabuf_release(struct sdrv_g2d *gd, struct g2d_buf *buf) { struct sg_table *sgt = buf->sgt; struct dma_buf *dmabuf; if (IS_ERR_OR_NULL(sgt)) { G2D_ERROR("dmabuf buffer is already unpinned \n"); return; } if (IS_ERR_OR_NULL(buf->attach)) { G2D_ERROR("trying to unpin a not attached buffer\n"); return; } dmabuf = dma_buf_get(buf->fd); if (IS_ERR_OR_NULL(dmabuf)) { G2D_ERROR("invalid dmabuf from dma_buf_get: %d", buf->fd); return; } G2D_DBG("buf->vaddr = 0x%ld\n", (unsigned long)buf->vaddr); if (buf->vaddr) { dma_buf_vunmap(dmabuf, (void *)buf->vaddr); buf->vaddr = (unsigned long)NULL; } dma_buf_unmap_attachment(buf->attach, sgt, 0); buf->dma_addr = 0; buf->sgt = NULL; dma_buf_detach(dmabuf, buf->attach); dma_buf_put(dmabuf); } static int g2d_alph_layer_mmap(struct sdrv_g2d *gd, struct g2d_bg_cfg *bgcfg) { int ret = 0; struct g2d_buf *buf = &bgcfg->abufs; if (buf->fd > 0) { ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d alph layer mmap faild \n"); return ret; } bgcfg->aaddr = buf->dma_addr; G2D_DBG("alph layer used, fd is valid: fd = %d , phy addr = 0x%llx\n", buf->fd, bgcfg->aaddr); } else { G2D_DBG("alph layer used, fd is invalid, aaddr = 0x%llx \n", bgcfg->aaddr); } return ret; } static int g2d_layer_mmap(struct sdrv_g2d *gd, struct g2d_layer *layer) { int ret, i, j; struct g2d_buf *buf = &layer->bufs[0]; uint32_t tmp_addr_h; uint32_t tmp_addr_l; if (buf->fd <= 0) { G2D_ERROR("input layer buf fd invaild, fd(%d) <= 0\n", buf->fd); return -EINVAL; } ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d input layer mmap faild \n"); return ret; } G2D_DBG("layer->nplanes = %d\n", layer->nplanes); for (i = 0; i < layer->nplanes; i++) { unsigned long addr = buf->dma_addr + layer->offsets[i]; layer->addr_l[i] = get_l_addr(addr); layer->addr_h[i] = get_h_addr(addr); G2D_DBG("layer[%d] addr_l[%d] = 0x%x addr_h[%d] = 0x%x\n", layer->index, i, layer->addr_l[i], i, layer->addr_h[i]); } if(layer->format == DRM_FORMAT_BGR888_PLANE) { if (layer->nplanes != 3) { G2D_ERROR("format set : DRM_FORMAT_BGR888_PLANE, but nplanes(%d) != 3 \n", layer->nplanes); return -1; } tmp_addr_l = layer->addr_l[0]; tmp_addr_h = layer->addr_h[0]; layer->addr_l[0] = layer->addr_l[2]; layer->addr_h[0] = layer->addr_h[2]; layer->addr_l[2] = tmp_addr_l; layer->addr_h[2] = tmp_addr_h; for (j = 0; j < layer->nplanes; j++) { G2D_DBG("layer[%d] addr_l[%d] = 0x%x addr_h[%d] = 0x%x\n", layer->index, j, layer->addr_l[j], j, layer->addr_h[j]); } } return 0; } int g2d_output_layer_mmap(struct sdrv_g2d *gd, struct g2d_output_cfg *layer) { int ret; int j; uint64_t tmp_addr; struct g2d_buf *buf = &layer->bufs[0]; if (buf->fd <= 0) { G2D_ERROR("output layer buf fd invaild, fd(%d) <= 0\n", buf->fd); return -EINVAL; } ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d output layer mmap faild \n"); return ret; } for (j = 0; j < layer->nplanes; j++) { layer->addr[j] = buf->dma_addr + layer->offsets[j]; G2D_DBG("layer->addr[%d] = 0x%llx \n", j, layer->addr[j]); } if(layer->fmt == DRM_FORMAT_BGR888_PLANE) { if (layer->nplanes != 3) { G2D_ERROR("fmt set : DRM_FORMAT_BGR888_PLANE, but nplanes(%d) != 3 \n", layer->nplanes); return -1; } tmp_addr = layer->addr[0]; layer->addr[0] = layer->addr[2]; layer->addr[2] = tmp_addr; for (j = 0; j < layer->nplanes; j++) { G2D_DBG("fmt == DRM_FORMAT_BGR888_PLANE : layer->addr[%d] = 0x%llx \n", j, layer->addr[j]); } } return 0; } void g2d_alph_layer_unmap(struct sdrv_g2d *gd, struct g2d_bg_cfg *bgcfg) { struct g2d_buf *buf = &bgcfg->abufs; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } void g2d_layer_unmap(struct sdrv_g2d *gd, struct g2d_layer *layer) { struct g2d_buf *buf = &layer->bufs[0]; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } void g2d_output_layer_unmap(struct sdrv_g2d *gd, struct g2d_output_cfg *layer) { struct g2d_buf *buf = &layer->bufs[0]; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } static int g2d_ioctl_begin(struct sdrv_g2d *gd, struct g2d_input *input) { int i; int ret; set_user_nice(current, -12); /*bg layer*/ if (input->bg_layer.en) { ret = g2d_alph_layer_mmap(gd, &input->bg_layer); if (ret) { return ret; } } /*input layer*/ for (i = 0; i < input->layer_num; i++) { struct g2d_layer *l = &input->layer[i]; if (!l->enable) continue; ret = g2d_layer_mmap(gd, l); if (ret) { return ret; } } /*output layer*/ ret = g2d_output_layer_mmap(gd, &input->output); if (ret) { return ret; } return 0; } static void g2d_ioctl_finish(struct sdrv_g2d *gd, struct g2d_input *input) { int i; /*bg layer*/ if (input->bg_layer.en) { g2d_alph_layer_unmap(gd, &input->bg_layer); } /*input layer*/ for (i = 0; i < input->layer_num; i++) { struct g2d_layer *l = &input->layer[i]; if (!l->enable) continue; g2d_layer_unmap(gd, l); } /*output layer*/ g2d_output_layer_unmap(gd, &input->output); } static int g2d_wait(struct sdrv_g2d *gd) { int status = 0; int rc; //g2d_dump_registers(gd); /* wait for stop done interrupt wait_event_timeout */ rc = wait_event_timeout(gd->wq, (gd->frame_done == true), msecs_to_jiffies(wait_timeout)); gd->frame_done = false; if (!rc) { status = -1; G2D_ERROR("g2d operation wait timeout %d\n", wait_timeout); g2d_dump_registers(gd); } else { if (dump_register_g2d == 1) { g2d_dump_registers(gd); } G2D_DBG("wait time %d\n", rc); } if (gd->ops->reset) gd->ops->reset(gd); return status; } static int g2d_fill_rect_ioctl(struct sdrv_g2d *gd, struct g2d_input *input) { int ret; ret = g2d_fill_rect(gd, &input->bg_layer, &input->output); if (ret < 0) { G2D_ERROR("g2d fill rect set register err \n"); goto OUT; } ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int g2d_fastcopy_dmabuf(struct sdrv_g2d *gd, struct g2d_input *input) { int ret = -1; addr_t iaddr, oaddr; struct g2d_output_cfg *out_layer = &input->output; struct g2d_bg_cfg *bg_layer = &input->bg_layer; struct g2d_buf *buf; if (!bg_layer->en) { G2D_ERROR("bg_layer en is %d, fast copy cannot be used\n", bg_layer->en); return ret; } iaddr = bg_layer->aaddr; buf = &out_layer->bufs[0]; oaddr = buf->dma_addr + out_layer->offsets[0]; if (iaddr % 4) { G2D_ERROR("The phy-addr(0x%lx) of the input needs to be 4-byte aligned\n", iaddr); return ret; } if (oaddr % 4) { G2D_ERROR("The phy-addr(0x%lx) of the output needs to be 4-byte aligned\n", oaddr); return ret; } if ((iaddr <= 0) || (oaddr <= 0)) { G2D_ERROR("input iaddr(0x%lx) or oaddr(0x%lx) = null\n", iaddr, oaddr); return ret; } ret = g2d_fastcopy_set(gd, iaddr, out_layer->width, out_layer->height, bg_layer->astride, oaddr, out_layer->stride[0]); if (ret < 0) { G2D_ERROR("g2d_fastcopy set register err \n"); goto OUT; } ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int sdrv_g2d_post_config(struct sdrv_g2d *gd, struct g2d_input *input) { int ret = 0; ret = g2d_post_config(gd, input); if(ret < 0) goto OUT; ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int sdrv_g2d_tasks(struct sdrv_g2d *gd, unsigned int cmd, struct g2d_input *input) { int ret; mutex_lock(&gd->m_lock); if (gd->monitor.is_monitor) gd->monitor.g2d_on_task = true; if (input->tables.set_tables) {//set filter tables g2d_set_coefficients_table(gd, &input->tables); } switch (cmd) { case G2D_IOCTL_POST_CONFIG: ret = sdrv_g2d_post_config(gd, input); G2D_DBG(" G2D_IOCTL_POST_CONFIG ret = %d\n", ret); break; case G2D_IOCTL_FAST_COPY: ret = g2d_fastcopy_dmabuf(gd, input); G2D_DBG("G2D_IOCTL_FAST_COPY end ret = %d\n", ret); break; case G2D_IOCTL_FILL_RECT: ret = g2d_fill_rect_ioctl(gd, input); G2D_DBG("G2D_IOCTL_FILL_RECT end ret = %d\n", ret); break; default: G2D_ERROR("Invalid ioctl cmd: 0x%x\n", cmd); ret = -EINVAL; break; } if (input->tables.set_tables) {//reset filter tables input->tables.set_tables = false; g2d_set_coefficients_table(gd, &input->tables); } if (gd->monitor.is_monitor) gd->monitor.g2d_on_task = false; mutex_unlock(&gd->m_lock); return ret; } void sdrv_dpc_to_g2d_layer(struct dpc_layer *int_layer, struct g2d_layer *out_layer) { out_layer->index = int_layer->index; //plane index out_layer->enable = int_layer->enable; out_layer->nplanes = int_layer->nplanes; out_layer->src_x = int_layer->src_x; out_layer->src_y = int_layer->src_y; out_layer->src_w = int_layer->src_w; out_layer->src_h = int_layer->src_h; out_layer->dst_x = int_layer->dst_x; out_layer->dst_y = int_layer->dst_y; out_layer->dst_w = int_layer->dst_w; out_layer->dst_h = int_layer->dst_h; out_layer->format = int_layer->format; out_layer->alpha = int_layer->alpha; out_layer->blend_mode = int_layer->blend_mode; out_layer->rotation = int_layer->rotation; out_layer->zpos = int_layer->zpos; out_layer->xfbc = int_layer->xfbc; out_layer->modifier = int_layer->modifier; out_layer->width = int_layer->width; out_layer->height = int_layer->height; memcpy(out_layer->addr_l, int_layer->addr_l, sizeof(out_layer->addr_l)); memcpy(out_layer->addr_h, int_layer->addr_h, sizeof(out_layer->addr_h)); memcpy(out_layer->pitch, int_layer->pitch, sizeof(out_layer->pitch)); memcpy(&out_layer->comp, &int_layer->comp, sizeof(struct pix_g2dcomp)); memcpy(&out_layer->ctx, &int_layer->ctx, sizeof(struct tile_ctx)); } int sdrv_g2d_convert_format(struct dpc_layer *layer, uint32_t g2d_out_format) { int ret = 0, i = 0; struct sdrv_g2d *gd = g_g2d[0]; struct g2d_input *input = NULL; uint32_t size = 0; static dma_addr_t paddr[2]; static void *vaddr[2]; static uint8_t index = 0; if (!gd) { G2D_ERROR("g2d hasn't exist\n"); return -ENODEV; } input = kzalloc(sizeof(struct g2d_input), GFP_KERNEL); if (!input) { G2D_ERROR("alloc input error\n"); return -ENOMEM; } size = layer->src_w * layer->src_h * 2; size = round_up(size, PAGE_SIZE); if (!vaddr[0]) { for (i = 0; i < 2; i++) { vaddr[i] = dma_alloc_wc(&gd->pdev->dev, size, &paddr[i], GFP_KERNEL | __GFP_NOWARN); if(!vaddr[i]) { G2D_ERROR("failed to allocate buffer of size %u\n", size); goto alloc_dma_err; } pr_info("dma addr[%d]:0x%llx vaddr[%d]:0x%p\n", i ,paddr[i], i, vaddr[i]); } } input->layer_num = 1; memcpy(&input->layer[0], layer, sizeof(struct g2d_layer)); sdrv_dpc_to_g2d_layer(layer, &input->layer[0]); pr_debug("format:%x, w:%d, h:%d s:%d al:%x\n", layer->format, layer->src_w, layer->src_h, layer->pitch[0], layer->addr_l[0]); input->output.width = layer->dst_w; input->output.height = layer->dst_h; input->output.stride[0] = layer->dst_w * 2; input->output.fmt = g2d_out_format; input->output.nplanes = 1; input->output.addr[0] = paddr[index]; pr_debug("o format:%x, w:%d, h:%d s:%d a:%llx\n", input->output.fmt, input->output.width, input->output.height, input->output.stride[0], input->output.addr[0]); mutex_lock(&gd->m_lock); ret = sdrv_g2d_post_config(gd, input); if (ret) { mutex_unlock(&gd->m_lock); goto out; } mutex_unlock(&gd->m_lock); layer->addr_l[0] = get_l_addr(input->output.addr[0]); layer->addr_h[0] = get_h_addr(input->output.addr[0]); layer->src_h = input->output.height; layer->src_w = input->output.width; layer->dst_h = input->output.height; layer->dst_w = input->output.width; layer->pitch[0] = input->output.stride[0]; index ++; if (index >= 2) index = 0; out: kfree(input); return ret; alloc_dma_err: while (i) { dma_free_wc(&gd->pdev->dev, size, vaddr[i], paddr[i]); i--; } kfree(input); return -ENOMEM; } EXPORT_SYMBOL(sdrv_g2d_convert_format); static int sdrv_g2d_func_work(struct sdrv_g2d *gd, unsigned int cmd, struct g2d_input *input) { int ret; if (!gd || !input) { G2D_ERROR("dev or input isn't inited.[dev:%p, ins:%p]\n", gd, input); return -EINVAL; } if ((input->output.height <= 0) || (input->output.width <= 0)) { G2D_ERROR("output input->output.height = %d, input->output.width = %d\n", input->output.height, input->output.width); return -EINVAL; } G2D_DBG("\r\n"); ret = g2d_ioctl_begin(gd, input); if (ret) { G2D_ERROR("input parameter err\n"); goto finish_out; } ret = sdrv_g2d_tasks(gd, cmd, input); finish_out: g2d_ioctl_finish(gd, input); return ret; } int sdrv_g2d_dma_copy(dma_addr_t dst, dma_addr_t src, size_t data_size) { int ret = 0; struct g2d_input *input; struct sdrv_g2d *gd = g_g2d[0]; int width, height, stride; width = 32; stride = width * 4; height = (data_size / stride) + ((data_size % stride) ? 1 : 0); G2D_DBG("data_size, width, stride, height : (%ld, %d, %d, %d)\n", data_size, width, stride, height); input = kzalloc(sizeof(struct g2d_input), GFP_ATOMIC | GFP_DMA); if (!input) { G2D_ERROR("kzalloc input failed\n"); return -EFAULT; } input->bg_layer.en = 1; input->bg_layer.width = width; input->bg_layer.height = height; input->bg_layer.astride = stride; input->bg_layer.aaddr = (uint64_t)src; input->output.bufs[0].dma_addr = (uint64_t)dst; input->output.width = width; input->output.height = height; input->output.stride[0] = stride; ret = sdrv_g2d_tasks(gd, G2D_IOCTL_FAST_COPY, input); kfree(input); return ret; } EXPORT_SYMBOL(sdrv_g2d_dma_copy); static long sdrv_g2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -1; int i=0, n = 0; struct sdrv_g2d *gd = file->private_data; struct g2d_input *input; struct g2d_inputx *inputx; if (_IOC_TYPE(cmd) != G2D_IOCTL_BASE) return -EINVAL; if (_IOC_NR(cmd) > 4) return -EINVAL; if (_IOC_DIR(cmd) & _IOC_READ) { ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_WRITE) { ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; } inputx = kzalloc(sizeof(struct g2d_inputx), GFP_ATOMIC | GFP_DMA); if (!inputx) { G2D_ERROR("kzalloc input failed\n"); return -EFAULT; } input = kzalloc(sizeof(struct g2d_input), GFP_ATOMIC | GFP_DMA); if (!input) { G2D_ERROR("kzalloc input failed\n"); if (inputx) kfree(inputx); return -EFAULT; } memset(inputx,0,sizeof(struct g2d_inputx)); memset(input,0,sizeof(struct g2d_input)); if (cmd == G2D_IOCTL_GET_CAPABILITIES) { ret = copy_to_user((struct g2d_capability __user *)arg, &gd->cap, sizeof(struct g2d_capability)); if (ret) { G2D_ERROR("get capabilities err \n"); ret = -EFAULT; } } else { ret = copy_from_user(inputx, (struct g2d_inputx __user *)arg, sizeof(struct g2d_inputx)); if (ret) { G2D_ERROR("copy_from_user failed\n"); ret = -EFAULT; goto unlock_out; } //for 32bit and 64 bit capibility; input->layer_num = inputx->layer_num; memcpy((void *)(&input->bg_layer),(void *)(&inputx->bg_layer),sizeof(struct g2d_bg_cfg_x)); input->bg_layer.abufs.dma_addr = input->bg_layer.cfg_buf.dma_addr; input->bg_layer.abufs.fd = input->bg_layer.cfg_buf.fd; input->bg_layer.abufs.size = input->bg_layer.cfg_buf.size; input->bg_layer.abufs.vaddr = input->bg_layer.cfg_buf.vaddr; memcpy((void *)(&input->output), (void *)(&inputx->output),sizeof(struct g2d_output_cfg_x)); for (i = 0; i < 4; i++) { input->output.bufs[i].dma_addr = input->output.out_buf[i].dma_addr; input->output.bufs[i].fd = input->output.out_buf[i].fd; input->output.bufs[i].size = input->output.out_buf[i].size; input->output.bufs[i].vaddr = input->output.out_buf[i].vaddr; } memcpy((void *)(&input->tables), (void *)(&inputx->tables),sizeof(struct g2d_coeff_table)); for (n = 0; n < G2D_LAYER_MAX_NUM;n ++) { memcpy((void *)(&input->layer[n]),(void *)(&inputx->layer[n]),sizeof(struct g2d_layer_x)); for (i = 0; i < 4; i++) { input->layer[n].bufs[i].dma_addr = input->layer[n].in_buf[i].dma_addr; input->layer[n].bufs[i].fd = input->layer[n].in_buf[i].fd; input->layer[n].bufs[i].size = input->layer[n].in_buf[i].size; input->layer[n].bufs[i].vaddr = input->layer[n].in_buf[i].vaddr; } } ret = sdrv_g2d_func_work(gd, cmd, input); } unlock_out: if (input) kfree(input); if (inputx) kfree(inputx); return (long)ret; } #if defined(CONFIG_COMPAT) static long sdrv_g2d_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return sdrv_g2d_ioctl(file, cmd, arg); } #endif /* defined(CONFIG_COMPAT) */ ssize_t sdrv_g2d_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct sdrv_g2d *gd = file->private_data; char str[64] = {0}; ssize_t sz = sprintf(str, "read from %s\n", gd->name); if (copy_to_user(buf, str, sz)){ G2D_ERROR("copy to user failed: %s\n", gd->name); } return sz; } static const struct file_operations g2d_fops = { .owner = THIS_MODULE, .open = sdrv_g2d_open, .read = sdrv_g2d_read, .unlocked_ioctl = sdrv_g2d_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = sdrv_g2d_compat_ioctl, #endif }; static int g2d_misc_init(struct sdrv_g2d *gd) { int ret; struct miscdevice *m = &gd->mdev;; m->minor = MISC_DYNAMIC_MINOR; m->name = kasprintf(GFP_KERNEL, "g2d%d", gd->id); m->fops = &g2d_fops; m->parent = NULL; m->groups = sdrv_g2d_groups; ret = misc_register(m); if (ret) { G2D_ERROR("failed to register miscdev\n"); return ret; } G2D_INFO("%s misc register \n", m->name); return ret; } static int sdrv_g2d_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sdrv_g2d *gd = NULL; static int pipe_registered = 0; dma_addr_t dma_handle; int ret = 0, i; mutex_lock(&m_init); G2D_INFO("G2D BUILD VERSION : %s \n", version); // 38 bits address for KUNLUN G2D rdma,use G2D_CPU_WRITE config 38bit; use G2D_CMD_WRITE config 32bit dma_set_mask(dev, DMA_BIT_MASK(32)); dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); gd = devm_kzalloc(&pdev->dev, sizeof(struct sdrv_g2d), GFP_KERNEL); if (!gd) { G2D_ERROR("kalloc sdrv_g2d failed\n"); ret = -1; goto OUT; } gd->du_inited = false; gd->pdev = pdev; if (!pipe_registered) { pipe_registered++; g2d_pipe_ops_register(&spipe_g2d_entry); g2d_pipe_ops_register(&gpipe_high_g2d_entry); g2d_pipe_ops_register(&gpipe_mid_g2d_entry); } /*cmdfile init*/ gd->cmd_info[0].arg = (unsigned int*)dma_alloc_coherent(dev, G2D_CMDFILE_MAX_MEM * sizeof(unsigned int), &dma_handle, GFP_KERNEL); gd->dma_buf = (unsigned long)dma_handle; if (gd->cmd_info[0].arg == NULL) { G2D_ERROR("malloc cmd_info failed\n"); goto OUT; } G2D_INFO("gd->cmd_info[0].arg virtual address = 0x%lx, phy address 0x%lx,dma alloc coherent len = %ld\n", (unsigned long)gd->cmd_info[0].arg, gd->dma_buf, G2D_CMDFILE_MAX_MEM * sizeof(unsigned int)); for (i = 1 ; i < G2D_CMDFILE_MAX_NUM; i++) { gd->cmd_info[i].arg = gd->cmd_info[i - 1].arg + G2D_CMDFILE_MAX_MEM / G2D_CMDFILE_MAX_NUM; } #ifdef CONFIG_OF G2D_INFO("CONFIG_OF scope\n"); sdrv_init_iommu(gd); ret = sdrv_g2d_init(gd, dev->of_node); #else G2D_INFO("CONFIG_OF is closed\n"); ret = sdrv_g2d_init(gd, pdev); #endif if (ret) goto OUT; mutex_init(&gd->m_lock); gd->monitor.sampling_time = 5; ret = g2d_misc_init(gd); if (ret) goto OUT; else printk("%s : semidrive g2d driver registered.\n", __func__); platform_set_drvdata(pdev, gd); g_g2d[gd->id] = gd; gd->du_inited = true; enable_irq(gd->irq); ret = 0; OUT: mutex_unlock(&m_init); return ret; } static int sdrv_g2d_remove(struct platform_device *pdev) { struct sdrv_g2d *gd = platform_get_drvdata(pdev); G2D_DBG("remove g2d %s\n", gd->name); if (gd) { sdrv_iommu_cleanup(gd); sdrv_g2d_unit(gd); misc_deregister(&gd->mdev); } return 0; } #ifdef CONFIG_OF static const struct of_device_id g2d_of_table[] = { {.compatible = "semidrive,g2d", .data = g2d_data}, {.compatible = "semidrive,g2d_lite", .data = g2d_data}, {}, }; #endif static int sdrv_g2d_suspend(struct device *dev) { struct sdrv_g2d *gd = dev_get_drvdata(dev); G2D_INFO("%s start\n", __func__); gd->ops->reset(gd); G2D_INFO("gd->du_inited = %d, gd->num_pipe = %d\n", gd->du_inited, gd->num_pipe); G2D_INFO("%s end\n", __func__); return 0; } static int sdrv_g2d_resume(struct device *dev) { struct sdrv_g2d *gd = dev_get_drvdata(dev); struct g2d_pipe *p = NULL; int i; G2D_INFO("%s start\n", __func__); G2D_INFO("gd->du_inited = %d, gd->num_pipe = %d\n", gd->du_inited, gd->num_pipe); gd->ops->init(gd); for (i = 0; i < gd->num_pipe; i++) { p = gd->pipes[i]; if (p && p->ops->init) p->ops->init(p); else G2D_ERROR("p or p->ops->init is null\n"); } gd->ops->reset(gd); G2D_INFO("%s end\n", __func__); return 0; } static const struct dev_pm_ops sdrv_g2d_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sdrv_g2d_suspend, sdrv_g2d_resume) }; static struct platform_driver g2d_driver = { .probe = sdrv_g2d_probe, .remove = sdrv_g2d_remove, .driver = { .name = "semidrive-g2d", .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = g2d_of_table, #endif .pm = &sdrv_g2d_pm_ops, }, }; module_platform_driver(g2d_driver); MODULE_AUTHOR("Semidrive Semiconductor"); MODULE_DESCRIPTION("Semidrive g2d"); MODULE_LICENSE("GPL"); 以上是linux内核g2d驱动文件sdrv_g2d.c #ifndef __SDRV_G2D_H__ #define __SDRV_G2D_H__ #include <linux/platform_device.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <linux/list.h> #include <asm/io.h> #include <linux/iommu.h> #include <linux/wait.h> #include <uapi/drm/drm_fourcc.h> #include <uapi/drm/sdrv_g2d_cfg.h> #include "g2d_common.h" #define PR_INFO pr_info #define ERROR pr_err typedef unsigned long int addr_t; #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif extern int debug_g2d; #define G2D_INFO(fmt, args...) do {\ PR_INFO("[g2d] [%20s] " fmt, __func__, ##args);\ }while(0) #define G2D_DBG(fmt, args...) do {\ if (debug_g2d >= 1) {\ PR_INFO("[g2d] <%d> [%20s] " fmt, __LINE__, __func__, ##args);}\ }while(0) #define G2D_ERROR(fmt, args...) ERROR("[g2d] <%d> [%20s] Error: " fmt, __LINE__, __func__, ##args) #define DDBG(x) G2D_DBG(#x " -> %d\n", x) #define XDBG(x) G2D_DBG(#x " -> 0x%x\n", x) #define PDBG(x) G2D_DBG(#x " -> %p\n", x) #define ENTRY() G2D_DBG("call <%d>\n", __LINE__) #define GP_ECHO_NAME "g2d_gpipe_echo" #define GP_MID_NAME "g2d_gpipe_mid" #define GP_HIGH_NAME "g2d_gpipe_high" #define SPIPE_NAME "g2d_spipe" #define G2D_NR_DEVS 4 /*Kunlun DP layer format TILE vsize*/ enum { TILE_VSIZE_1 = 0b000, TILE_VSIZE_2 = 0b001, TILE_VSIZE_4 = 0b010, TILE_VSIZE_8 = 0b011, TILE_VSIZE_16 = 0b100, }; /*Kunlun DP layer format TILE hsize*/ enum { TILE_HSIZE_1 = 0b000, TILE_HSIZE_8 = 0b001, TILE_HSIZE_16 = 0b010, TILE_HSIZE_32 = 0b011, TILE_HSIZE_64 = 0b100, TILE_HSIZE_128 = 0b101, }; /**/ enum { FBDC_U8U8U8U8 = 0xc, FBDC_U16 = 0x9, FBDC_R5G6B5 = 0x5, FBDC_U8 = 0x0, FBDC_NV21 = 0x37, FBDC_YUV420_16PACK = 0x65 }; enum kunlun_plane_property { PLANE_PROP_ALPHA, PLANE_PROP_BLEND_MODE, PLANE_PROP_FBDC_HSIZE_Y, PLANE_PROP_FBDC_HSIZE_UV, PLANE_PROP_CAP_MASK, PLANE_PROP_MAX_NUM }; enum { DRM_MODE_BLEND_PIXEL_NONE = 0, DRM_MODE_BLEND_PREMULTI, DRM_MODE_BLEND_COVERAGE }; enum { PLANE_DISABLE, PLANE_ENABLE }; enum { PROP_PLANE_CAP_RGB = 0, PROP_PLANE_CAP_YUV, PROP_PLANE_CAP_XFBC, PROP_PLANE_CAP_YUV_FBC, PROP_PLANE_CAP_ROTATION, PROP_PLANE_CAP_SCALING, }; enum { TYPE_GP_ECHO = 0, TYPE_GP_MID, TYPE_GP_HIGH, TYPE_SPIPE }; struct g2d_pipe; struct pipe_operation { int (*init)(struct g2d_pipe *); int (*set)(struct g2d_pipe *, int , struct g2d_layer *); void (*csc_coef_set)(struct g2d_pipe *, struct g2d_coeff_table *); }; struct g2d_pipe { void __iomem *iomem_regs; void __iomem *regs; unsigned long reg_offset; int id; // the ordered id from 0 struct sdrv_g2d *gd; const char *name; int type; struct pipe_operation *ops; struct g2d_pipe_capability *cap; struct g2d_pipe *next; }; struct g2d_monitor { int is_monitor; int is_init; ktime_t timeout; struct hrtimer timer; bool g2d_on_task; int occupancy_rate; int timer_count; int valid_times; int sampling_time; }; struct sdrv_g2d { struct platform_device *pdev; struct cdev cdev; struct miscdevice mdev; void __iomem *iomem_regs; void __iomem *regs; bool iommu_enable; struct iommu_domain *domain; struct mutex m_lock; struct wait_queue_head wq; bool frame_done; int id; const char *name; int irq; int write_mode; cmdfile_info cmd_info[G2D_CMDFILE_MAX_NUM]; unsigned long dma_buf; const struct g2d_ops *ops; struct g2d_capability cap; struct g2d_pipe *pipes[PIPE_MAX]; int num_pipe; int du_inited; struct g2d_monitor monitor; }; struct g2d_ops { int (*init)(struct sdrv_g2d *); int (*enable)(struct sdrv_g2d*, int); int (*reset)(struct sdrv_g2d *); int (*mlc_set)(struct sdrv_g2d *, int , struct g2d_input *); int (*fill_rect)(struct sdrv_g2d *, struct g2d_bg_cfg *, struct g2d_output_cfg *); int (*fastcopy)(struct sdrv_g2d *, addr_t , u32 , u32 , u32 , addr_t , u32); int (*config)(struct sdrv_g2d *); int (*irq_handler)(struct sdrv_g2d *); int (*rwdma)(struct sdrv_g2d *, struct g2d_input *); void (*close_fastcopy)(struct sdrv_g2d *); int (*wpipe_set)(struct sdrv_g2d *, int, struct g2d_output_cfg *); int (*check_stroke)(struct g2d_input *); int (*scaler_coef_set)(struct sdrv_g2d *, struct g2d_coeff_table *); }; struct sdrv_g2d_data { const char *version; const struct g2d_ops* ops; }; struct ops_entry { const char *ver; void *ops; }; int g2d_get_capability(struct g2d_capability *cap); unsigned int get_compval_from_comp(struct pix_g2dcomp *comp); unsigned int get_frm_ctrl_from_comp(struct pix_g2dcomp *comp); int sdrv_wpipe_pix_comp(uint32_t format, struct pix_g2dcomp *comp); int sdrv_pix_comp(uint32_t format, struct pix_g2dcomp *comp); bool g2d_format_is_yuv(uint32_t format); int g2d_format_wpipe_bypass(uint32_t format); struct ops_list { struct list_head head; struct ops_entry *entry; }; extern struct list_head g2d_pipe_list_head; int g2d_ops_register(struct ops_entry *entry, struct list_head *head); void *g2d_ops_attach(const char *str, struct list_head *head); #define g2d_pipe_ops_register(entry) g2d_ops_register(entry, &g2d_pipe_list_head) #define g2d_pipe_ops_attach(str) g2d_ops_attach(str, &g2d_pipe_list_head) int g2d_choose_pipe(struct sdrv_g2d *gd, int hwid, int type, uint32_t offset); struct sdrv_g2d *get_g2d_by_id(int id); extern struct ops_entry gpipe_mid_g2d_entry; extern struct ops_entry gpipe_high_g2d_entry; extern struct ops_entry spipe_g2d_entry; #endif //__SDRV_G2D_H__ 以上是linux内核的g2d驱动的头文件sdrv_g2d.h #ifndef __SDRV_G2D_CFG_H #define __SDRV_G2D_CFG_H #include "sdrv_drm.h" #ifdef __YOCTO_G2D_TEST__ typedef __u8 uint8_t; typedef __u16 uint16_t; typedef __u32 uint32_t; typedef unsigned long uint64_t; #endif #define G2D_LAYER_MAX_NUM 6 #ifndef G2DLITE_API_USE typedef enum { SWAP_A_RGB = 0b0000, SWAP_A_RBG = 0b0001, SWAP_A_GBR = 0b0010, SWAP_A_GRB = 0b0011, SWAP_A_BGR = 0b0100, SWAP_A_BRG = 0b0101, SWAP_B_ARG = 0b1000, SWAP_B_AGR = 0b1001, SWAP_B_RGA = 0b1010, SWAP_B_RAG = 0b1011, SWAP_B_GRA = 0b1100, SWAP_B_GAR = 0b1101 } COMP_SWAP_MODE; typedef enum { UV_YUV444_RGB = 0b00, UV_YUV422 = 0b01, UV_YUV440 = 0b10, UV_YUV420 = 0b11 } DATA_UV_MODE; typedef enum { LINEAR_MODE = 0b000, RLE_COMPR_MODE = 0b001, GPU_RAW_TILE_MODE = 0b010, GPU_CPS_TILE_MODE = 0b011, VPU_RAW_TILE_MODE = 0b100, VPU_CPS_TILE_MODE = 0b101, VPU_RAW_TILE_988_MODE = 0b110, } DATA_MODE; typedef enum { FMT_INTERLEAVED = 0b00, FMT_MONOTONIC = 0b01, FMT_SEMI_PLANAR = 0b10, FMT_PLANAR = 0b11 } FRM_BUF_STR_FMT; typedef enum { ROT_DEFAULT = 0b000, ROT_ROT = 0b001, ROT_VFLIP = 0b010, ROT_HFLIP = 0b100 } ROT_TYPE; #endif #ifndef G2DLITE_API_USE enum { BLEND_PIXEL_NONE = 0, BLEND_PIXEL_PREMULTI, BLEND_PIXEL_COVERAGE }; typedef enum { ROTATION_TYPE_NONE = 0b000, ROTATION_TYPE_ROT_90 = 0b001, ROTATION_TYPE_HFLIP = 0b010, ROTATION_TYPE_VFLIP = 0b100, ROTATION_TYPE_ROT_180 = ROTATION_TYPE_VFLIP | ROTATION_TYPE_HFLIP, ROTATION_TYPE_ROT_270 = ROTATION_TYPE_ROT_90 | ROTATION_TYPE_VFLIP | ROTATION_TYPE_HFLIP, ROTATION_TYPE_VF_90 = ROTATION_TYPE_VFLIP | ROTATION_TYPE_ROT_90, ROTATION_TYPE_HF_90 = ROTATION_TYPE_HFLIP | ROTATION_TYPE_ROT_90, } rotation_type; #endif typedef enum { PD_NONE = 0, PD_SRC = 0x1, PD_DST = 0x2 } PD_LAYER_TYPE; struct g2d_output_cfg{ uint32_t width; uint32_t height; uint32_t fmt; uint64_t addr[4]; uint32_t stride[4]; uint32_t rotation; uint32_t nplanes; uint32_t offsets[4]; struct tile_ctx out_ctx; struct g2d_buf_info out_buf[4]; struct g2d_buf bufs[4]; }; struct g2d_bg_cfg { uint32_t en; uint32_t color; uint8_t g_alpha; uint8_t zorder; uint64_t aaddr; uint8_t bpa; uint32_t astride; uint32_t x; uint32_t y; uint32_t width; uint32_t height; PD_LAYER_TYPE pd_type; struct g2d_buf_info cfg_buf; struct g2d_buf abufs; }; struct g2d_coeff_table { int set_tables; int hcoef_set; int hcoef[33][5]; int vcoef_set; int vcoef[33][4]; int csc_coef_set; int csc_coef[15]; }; struct g2d_input{ unsigned char layer_num; struct g2d_bg_cfg bg_layer; struct g2d_layer layer[G2D_LAYER_MAX_NUM]; struct g2d_output_cfg output; struct g2d_coeff_table tables; }; struct g2d_pipe_capability { uint32_t formats[100]; int nformats; int layer_type; int rotation; int scaling; int yuv; int yuv_fbc; int xfbc; }; struct g2d_capability { int num_pipe; struct g2d_pipe_capability pipe_caps[G2D_LAYER_MAX_NUM]; }; struct g2d_layer_x { __u8 index; //plane index __u8 enable; __u8 nplanes; __u32 addr_l[4]; __u32 addr_h[4]; __u32 pitch[4]; __u32 offsets[4]; __s16 src_x; __s16 src_y; __s16 src_w; __s16 src_h; __s16 dst_x; __s16 dst_y; __u16 dst_w; __u16 dst_h; __u32 format; struct pix_g2dcomp comp; struct tile_ctx ctx; __u32 alpha; __u32 blend_mode; __u32 rotation; __u32 zpos; __u32 xfbc; __u64 modifier; __u32 width; __u32 height; struct g2d_buf_info in_buf[4]; }; struct g2d_output_cfg_x{ uint32_t width; uint32_t height; uint32_t fmt; uint64_t addr[4]; uint32_t stride[4]; uint32_t rotation; uint32_t nplanes; uint32_t offsets[4]; struct tile_ctx out_ctx; struct g2d_buf_info out_buf[4]; }; struct g2d_bg_cfg_x { uint32_t en; uint32_t color; uint8_t g_alpha; uint8_t zorder; uint64_t aaddr; uint8_t bpa; uint32_t astride; uint32_t x; uint32_t y; uint32_t width; uint32_t height; PD_LAYER_TYPE pd_type; struct g2d_buf_info cfg_buf; }; struct g2d_inputx{ unsigned char layer_num; struct g2d_bg_cfg_x bg_layer; struct g2d_layer_x layer[G2D_LAYER_MAX_NUM]; struct g2d_output_cfg_x output; struct g2d_coeff_table tables; }; #define G2D_COMMAND_BASE 0x00 #define G2D_IOCTL_BASE 'g' #define G2D_IO(nr) _IO(G2D_IOCTL_BASE,nr) #define G2D_IOR(nr,type) _IOR(G2D_IOCTL_BASE,nr,type) #define G2D_IOW(nr,type) _IOW(G2D_IOCTL_BASE,nr,type) #define G2D_IOWR(nr,type) _IOWR(G2D_IOCTL_BASE,nr,type) #define G2D_IOCTL_GET_CAPABILITIES G2D_IOWR(G2D_COMMAND_BASE + 1, struct g2d_capability) #define G2D_IOCTL_POST_CONFIG G2D_IOWR(G2D_COMMAND_BASE + 2, struct g2d_inputx) #define G2D_IOCTL_FAST_COPY G2D_IOWR(G2D_COMMAND_BASE + 3, struct g2d_inputx) #define G2D_IOCTL_FILL_RECT G2D_IOWR(G2D_COMMAND_BASE + 4, struct g2d_inputx) #endif //__SDRV_G2D_CFG_H 以上是linux内核提供给linux应用层调用的头文件。 请提供所有文件的中文详细注释,并结合lvgl 9.2.2版版本源码和/dev/g2d0设备,实现调用g2d硬件资源进行图形绘制linux应用代码。
最新发布
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值