void omap_get_vrfb_buffer(__u32 paddr) { int i = 0; int j = 0; if (have_vrfb_ctx >= VRFB_NUM_SLOTS) return; for (i = 0; i < VRFB_NUM_SLOTS; i++) { if (ion_vrfb_t[i].ba == 0) { if (omap_vrfb_request_ctx (&ion_vrfb_t[i].vrfb_context)) { pr_err("%s:VRFB allocation failed\n", __func__); for (j = 0; j < VRFB_NUM_SLOTS; j++) if (ion_vrfb_t[j].ba) { omap_vrfb_release_ctx( &ion_vrfb_t[j].vrfb_context); ion_vrfb_t[j].ba = 0; ion_vrfb_t[j].ismapped = 0; have_vrfb_ctx--; } return ; } ion_vrfb_t[i].ba = paddr; ion_vrfb_t[i].ismapped = 0; have_vrfb_ctx++; break; } } return; }
/* * Release the VRFB context once the module exits */ void omap_vout_release_vrfb(struct omap_vout_device *vout) { int i; for (i = 0; i < VRFB_NUM_BUFS; i++) omap_vrfb_release_ctx(&vout->vrfb_context[i]); if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) { vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; omap_free_dma(vout->vrfb_dma_tx.dma_ch); } }
int omap_vrfb_request_ctx(struct vrfb *vrfb) { int rot; u32 paddr; u8 ctx; int r; DBG("request ctx\n"); mutex_lock(&ctx_lock); for (ctx = 0; ctx < num_ctxs; ++ctx) if ((ctx_map & (1 << ctx)) == 0) break; if (ctx == num_ctxs) { pr_err("vrfb: no free contexts\n"); r = -EBUSY; goto out; } DBG("found free ctx %d\n", ctx); set_bit(ctx, &ctx_map); memset(vrfb, 0, sizeof(*vrfb)); vrfb->context = ctx; for (rot = 0; rot < 4; ++rot) { paddr = ctxs[ctx].base + SMS_ROT_VIRT_BASE(rot); if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) { pr_err("vrfb: failed to reserve VRFB " "area for ctx %d, rotation %d\n", ctx, rot * 90); omap_vrfb_release_ctx(vrfb); r = -ENOMEM; goto out; } vrfb->paddr[rot] = paddr; DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]); } r = 0; out: mutex_unlock(&ctx_lock); return r; }
static int omapvout_dss_release_vrfb(struct omapvout_device *vout) { int rc = 0; int size; struct omapvout_dss_vrfb *vrfb; /* It is assumed that the caller has locked the vout mutex */ vrfb = &vout->dss->vrfb; if (vrfb->req_status == DMA_CHAN_ALLOTED) { vrfb->req_status = DMA_CHAN_NOT_ALLOTED; omap_free_dma(vrfb->dma_ch); /* FIXME: de-init the wait queue? */ size = vrfb->size; omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size); omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size); omap_vrfb_release_ctx(&vrfb->ctx[0]); omap_vrfb_release_ctx(&vrfb->ctx[1]); } return rc; }
void omap_free_vrfb_buffer(__u32 paddr) { int j = 0; if (!have_vrfb_ctx) return; for (j = 0; j < VRFB_NUM_SLOTS; j++) { if (ion_vrfb_t[j].ba == paddr) { omap_vrfb_release_ctx(&ion_vrfb_t[j].vrfb_context); ion_vrfb_t[j].ba = 0; ion_vrfb_t[j].ismapped = 0; have_vrfb_ctx--; break; } } }
int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, bool static_vrfb_allocation) { int ret = 0, i, j; struct omap_vout_device *vout; struct video_device *vfd; int image_width, image_height; int vrfb_num_bufs = VRFB_NUM_BUFS; struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); vout = vid_dev->vouts[vid_num]; vfd = vout->vfd; for (i = 0; i < VRFB_NUM_BUFS; i++) { if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) { dev_info(&pdev->dev, ": VRFB allocation failed\n"); for (j = 0; j < i; j++) omap_vrfb_release_ctx(&vout->vrfb_context[j]); ret = -ENOMEM; goto free_buffers; } } /* Calculate VRFB memory size */ /* allocate for worst case size */ image_width = VID_MAX_WIDTH / TILE_SIZE; if (VID_MAX_WIDTH % TILE_SIZE) image_width++; image_width = image_width * TILE_SIZE; image_height = VID_MAX_HEIGHT / TILE_SIZE; if (VID_MAX_HEIGHT % TILE_SIZE) image_height++; image_height = image_height * TILE_SIZE; vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2); /* * Request and Initialize DMA, for DMA based VRFB transfer */ vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE; vout->vrfb_dma_tx.dma_ch = -1; vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED; ret = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX", omap_vout_vrfb_dma_tx_callback, (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); if (ret < 0) { vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; dev_info(&pdev->dev, ": failed to allocate DMA Channel for" " video%d\n", vfd->minor); } init_waitqueue_head(&vout->vrfb_dma_tx.wait); /* statically allocated the VRFB buffer is done through commands line aruments */ if (static_vrfb_allocation) { if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) { ret = -ENOMEM; goto release_vrfb_ctx; } vout->vrfb_static_allocation = 1; } return 0; release_vrfb_ctx: for (j = 0; j < VRFB_NUM_BUFS; j++) omap_vrfb_release_ctx(&vout->vrfb_context[j]); free_buffers: omap_vout_free_buffers(vout); return ret; }
static int omapvout_dss_acquire_vrfb(struct omapvout_device *vout) { int rc = 0; int size; int w, h; int max_pixels; struct omapvout_dss_vrfb *vrfb; /* It is assumed that the caller has locked the vout mutex */ vrfb = &vout->dss->vrfb; vrfb->dma_id = OMAP_DMA_NO_DEVICE; vrfb->dma_ch = -1; vrfb->req_status = DMA_CHAN_NOT_ALLOTED; vrfb->next = 0; rc = omap_vrfb_request_ctx(&vrfb->ctx[0]); if (rc != 0) { DBG("VRFB context allocation 0 failed %d\n", rc); goto failed_ctx0; } rc = omap_vrfb_request_ctx(&vrfb->ctx[1]); if (rc != 0) { DBG("VRFB context allocation 1 failed %d\n", rc); goto failed_ctx1; } /* Determine the VFRB buffer size by oversizing for the VRFB */ w = vout->max_video_width; h = vout->max_video_height; max_pixels = w * h; w += 32; /* Oversize as typical for VRFB */ h += 32; size = PAGE_ALIGN(w * h * (vout->max_video_buffer_size / max_pixels)); vrfb->size = size; rc = omapvout_mem_alloc(size, &vrfb->phy_addr[0], &vrfb->virt_addr[0]); if (rc != 0) { DBG("VRFB buffer alloc 0 failed %d\n", rc); goto failed_mem0; } rc = omapvout_mem_alloc(size, &vrfb->phy_addr[1], &vrfb->virt_addr[1]); if (rc != 0) { DBG("VRFB buffer alloc 1 failed %d\n", rc); goto failed_mem1; } rc = omap_request_dma(vrfb->dma_id, "VRFB DMA", omapvout_dss_vrfb_dma_cb, (void *)vrfb, &vrfb->dma_ch); if (rc != 0) { printk(KERN_INFO "No VRFB DMA channel for %d\n", vout->id); goto failed_dma; } vrfb->req_status = DMA_CHAN_ALLOTED; init_waitqueue_head(&vrfb->wait); return rc; failed_dma: omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size); failed_mem1: omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size); failed_mem0: omap_vrfb_release_ctx(&vrfb->ctx[1]); failed_ctx1: omap_vrfb_release_ctx(&vrfb->ctx[0]); failed_ctx0: return rc; }