cregit-Linux how code gets into the kernel

Release 4.7 drivers/media/platform/sti/bdisp/bdisp-hw.c

/*
 * Copyright (C) STMicroelectronics SA 2014
 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
 * License terms:  GNU General Public License (GPL), version 2
 */

#include <linux/delay.h>

#include "bdisp.h"
#include "bdisp-filter.h"
#include "bdisp-reg.h"

/* Max width of the source frame in a single node */

#define MAX_SRC_WIDTH           2048

/* Reset & boot poll config */

#define POLL_RST_MAX            50

#define POLL_RST_DELAY_MS       20


enum bdisp_target_plan {
	
BDISP_RGB,
	
BDISP_Y,
	
BDISP_CBCR
};


struct bdisp_op_cfg {
	
bool cconv;          /* RGB - YUV conversion */
	
bool hflip;          /* Horizontal flip */
	
bool vflip;          /* Vertical flip */
	
bool wide;           /* Wide (>MAX_SRC_WIDTH) */
	
bool scale;          /* Scale */
	
u16  h_inc;          /* Horizontal increment in 6.10 format */
	
u16  v_inc;          /* Vertical increment in 6.10 format */
	
bool src_interlaced; /* is the src an interlaced buffer */
	
u8   src_nbp;        /* nb of planes of the src */
	
bool src_yuv;        /* is the src a YUV color format */
	
bool src_420;        /* is the src 4:2:0 chroma subsampled */
	
u8   dst_nbp;        /* nb of planes of the dst */
	
bool dst_yuv;        /* is the dst a YUV color format */
	
bool dst_420;        /* is the dst 4:2:0 chroma subsampled */
};


struct bdisp_filter_addr {
	
u16 min;             /* Filter min scale factor (6.10 fixed point) */
	
u16 max;             /* Filter max scale factor (6.10 fixed point) */
	
void *virt;          /* Virtual address for filter table */
	
dma_addr_t paddr;    /* Physical address for filter table */
};


static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];

static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];

/**
 * bdisp_hw_reset
 * @bdisp:      bdisp entity
 *
 * Resets HW
 *
 * RETURNS:
 * 0 on success.
 */

int bdisp_hw_reset(struct bdisp_dev *bdisp) { unsigned int i; dev_dbg(bdisp->dev, "%s\n", __func__); /* Mask Interrupt */ writel(0, bdisp->regs + BLT_ITM0); /* Reset */ writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET, bdisp->regs + BLT_CTL); writel(0, bdisp->regs + BLT_CTL); /* Wait for reset done */ for (i = 0; i < POLL_RST_MAX; i++) { if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE) break; msleep(POLL_RST_DELAY_MS); } if (i == POLL_RST_MAX) dev_err(bdisp->dev, "Reset timeout\n"); return (i == POLL_RST_MAX) ? -EAGAIN : 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne131100.00%1100.00%
Total131100.00%1100.00%

/** * bdisp_hw_get_and_clear_irq * @bdisp: bdisp entity * * Read then reset interrupt status * * RETURNS: * 0 if expected interrupt was raised. */
int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp) { u32 its; its = readl(bdisp->regs + BLT_ITS); /* Check for the only expected IT: LastNode of AQ1 */ if (!(its & BLT_ITS_AQ1_LNA)) { dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its); writel(its, bdisp->regs + BLT_ITS); return -1; } /* Clear and mask */ writel(its, bdisp->regs + BLT_ITS); writel(0, bdisp->regs + BLT_ITM0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne88100.00%1100.00%
Total88100.00%1100.00%

/** * bdisp_hw_free_nodes * @ctx: bdisp context * * Free node memory * * RETURNS: * None */
void bdisp_hw_free_nodes(struct bdisp_ctx *ctx) { if (ctx && ctx->node[0]) { DEFINE_DMA_ATTRS(attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); dma_free_attrs(ctx->bdisp_dev->dev, sizeof(struct bdisp_node) * MAX_NB_NODE, ctx->node[0], ctx->node_paddr[0], &attrs); } }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne70100.00%1100.00%
Total70100.00%1100.00%

/** * bdisp_hw_alloc_nodes * @ctx: bdisp context * * Allocate dma memory for nodes * * RETURNS: * 0 on success */
int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx) { struct device *dev = ctx->bdisp_dev->dev; unsigned int i, node_size = sizeof(struct bdisp_node); void *base; dma_addr_t paddr; DEFINE_DMA_ATTRS(attrs); /* Allocate all the nodes within a single memory page */ dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr, GFP_KERNEL | GFP_DMA, &attrs); if (!base) { dev_err(dev, "%s no mem\n", __func__); return -ENOMEM; } memset(base, 0, node_size * MAX_NB_NODE); for (i = 0; i < MAX_NB_NODE; i++) { ctx->node[i] = base; ctx->node_paddr[i] = paddr; dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i], &paddr); base += node_size; paddr += node_size; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne169100.00%1100.00%
Total169100.00%1100.00%

/** * bdisp_hw_free_filters * @dev: device * * Free filters memory * * RETURNS: * None */
void bdisp_hw_free_filters(struct device *dev) { int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER); if (bdisp_h_filter[0].virt) { DEFINE_DMA_ATTRS(attrs); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); dma_free_attrs(dev, size, bdisp_h_filter[0].virt, bdisp_h_filter[0].paddr, &attrs); } }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne73100.00%1100.00%
Total73100.00%1100.00%

/** * bdisp_hw_alloc_filters * @dev: device * * Allocate dma memory for filters * * RETURNS: * 0 on success */
int bdisp_hw_alloc_filters(struct device *dev) { unsigned int i, size; void *base; dma_addr_t paddr; DEFINE_DMA_ATTRS(attrs); /* Allocate all the filters within a single memory page */ size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER); dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs); if (!base) return -ENOMEM; /* Setup filter addresses */ for (i = 0; i < NB_H_FILTER; i++) { bdisp_h_filter[i].min = bdisp_h_spec[i].min; bdisp_h_filter[i].max = bdisp_h_spec[i].max; memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB); bdisp_h_filter[i].virt = base; bdisp_h_filter[i].paddr = paddr; base += BDISP_HF_NB; paddr += BDISP_HF_NB; } for (i = 0; i < NB_V_FILTER; i++) { bdisp_v_filter[i].min = bdisp_v_spec[i].min; bdisp_v_filter[i].max = bdisp_v_spec[i].max; memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB); bdisp_v_filter[i].virt = base; bdisp_v_filter[i].paddr = paddr; base += BDISP_VF_NB; paddr += BDISP_VF_NB; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne249100.00%1100.00%
Total249100.00%1100.00%

/** * bdisp_hw_get_hf_addr * @inc: resize increment * * Find the horizontal filter table that fits the resize increment * * RETURNS: * table physical address */
static dma_addr_t bdisp_hw_get_hf_addr(u16 inc) { unsigned int i; for (i = NB_H_FILTER - 1; i > 0; i--) if ((bdisp_h_filter[i].min < inc) && (inc <= bdisp_h_filter[i].max)) break; return bdisp_h_filter[i].paddr; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne61100.00%1100.00%
Total61100.00%1100.00%

/** * bdisp_hw_get_vf_addr * @inc: resize increment * * Find the vertical filter table that fits the resize increment * * RETURNS: * table physical address */
static dma_addr_t bdisp_hw_get_vf_addr(u16 inc) { unsigned int i; for (i = NB_V_FILTER - 1; i > 0; i--) if ((bdisp_v_filter[i].min < inc) && (inc <= bdisp_v_filter[i].max)) break; return bdisp_v_filter[i].paddr; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne61100.00%1100.00%
Total61100.00%1100.00%

/** * bdisp_hw_get_inc * @from: input size * @to: output size * @inc: resize increment in 6.10 format * * Computes the increment (inverse of scale) in 6.10 format * * RETURNS: * 0 on success */
static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc) { u32 tmp; if (!to) return -EINVAL; if (to == from) { *inc = 1 << 10; return 0; } tmp = (from << 10) / to; if ((tmp > 0xFFFF) || (!tmp)) /* overflow (downscale x 63) or too small (upscale x 1024) */ return -EINVAL; *inc = (u16)tmp; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne85100.00%1100.00%
Total85100.00%1100.00%

/** * bdisp_hw_get_hv_inc * @ctx: device context * @h_inc: horizontal increment * @v_inc: vertical increment * * Computes the horizontal & vertical increments (inverse of scale) * * RETURNS: * 0 on success */
static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc) { u32 src_w, src_h, dst_w, dst_h; src_w = ctx->src.crop.width; src_h = ctx->src.crop.height; dst_w = ctx->dst.crop.width; dst_h = ctx->dst.crop.height; if (bdisp_hw_get_inc(src_w, dst_w, h_inc) || bdisp_hw_get_inc(src_h, dst_h, v_inc)) { dev_err(ctx->bdisp_dev->dev, "scale factors failed (%dx%d)->(%dx%d)\n", src_w, src_h, dst_w, dst_h); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne116100.00%2100.00%
Total116100.00%2100.00%

/** * bdisp_hw_get_op_cfg * @ctx: device context * @c: operation configuration * * Check which blitter operations are expected and sets the scaling increments * * RETURNS: * 0 on success */
static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c) { struct device *dev = ctx->bdisp_dev->dev; struct bdisp_frame *src = &ctx->src; struct bdisp_frame *dst = &ctx->dst; if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) { dev_err(dev, "Image width out of HW caps\n"); return -EINVAL; } c->wide = src->width > MAX_SRC_WIDTH; c->hflip = ctx->hflip; c->vflip = ctx->vflip; c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED); c->src_nbp = src->fmt->nb_planes; c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) || (src->fmt->pixelformat == V4L2_PIX_FMT_YUV420); c->src_420 = c->src_yuv; c->dst_nbp = dst->fmt->nb_planes; c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) || (dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420); c->dst_420 = c->dst_yuv; c->cconv = (c->src_yuv != c->dst_yuv); if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) { dev_err(dev, "Scale factor out of HW caps\n"); return -EINVAL; } /* Deinterlacing adjustment : stretch a field to a frame */ if (c->src_interlaced) c->v_inc /= 2; if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10))) c->scale = true; else c->scale = false; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne291100.00%1100.00%
Total291100.00%1100.00%

/** * bdisp_hw_color_format * @pixelformat: v4l2 pixel format * * v4l2 to bdisp pixel format convert * * RETURNS: * bdisp pixel format */
static u32 bdisp_hw_color_format(u32 pixelformat) { u32 ret; switch (pixelformat) { case V4L2_PIX_FMT_YUV420: ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT); break; case V4L2_PIX_FMT_NV12: ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END; break; case V4L2_PIX_FMT_RGB565: ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT); break; case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */ ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT); break; case V4L2_PIX_FMT_RGB24: /* RGB888 format */ ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END; break; case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */ default: ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R; break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne103100.00%1100.00%
Total103100.00%1100.00%

/** * bdisp_hw_build_node * @ctx: device context * @cfg: operation configuration * @node: node to be set * @t_plan: whether the node refers to a RGB/Y or a CbCr plane * @src_x_offset: x offset in the source image * * Build a node * * RETURNS: * None */
static void bdisp_hw_build_node(struct bdisp_ctx *ctx, struct bdisp_op_cfg *cfg, struct bdisp_node *node, enum bdisp_target_plan t_plan, int src_x_offset) { struct bdisp_frame *src = &ctx->src; struct bdisp_frame *dst = &ctx->dst; u16 h_inc, v_inc, yh_inc, yv_inc; struct v4l2_rect src_rect = src->crop; struct v4l2_rect dst_rect = dst->crop; int dst_x_offset; s32 dst_width = dst->crop.width; u32 src_fmt, dst_fmt; const u32 *ivmx; dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__); memset(node, 0, sizeof(*node)); /* Adjust src and dst areas wrt src_x_offset */ src_rect.left += src_x_offset; src_rect.width -= src_x_offset; src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width); dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width; dst_rect.left += dst_x_offset; dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width; /* General */ src_fmt = src->fmt->pixelformat; dst_fmt = dst->fmt->pixelformat; node->nip = 0; node->cic = BLT_CIC_ALL_GRP; node->ack = BLT_ACK_BYPASS_S2S3; switch (cfg->src_nbp) { case 1: /* Src2 = RGB / Src1 = Src3 = off */ node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF; break; case 2: /* Src3 = Y * Src2 = CbCr or ColorFill if writing the Y plane * Src1 = off */ node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM; if (t_plan == BDISP_Y) node->ins |= BLT_INS_S2_CF; else node->ins |= BLT_INS_S2_MEM; break; case 3: default: /* Src3 = Y * Src2 = Cb or ColorFill if writing the Y plane * Src1 = Cr or ColorFill if writing the Y plane */ node->ins = BLT_INS_S3_MEM; if (t_plan == BDISP_Y) node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF; else node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM; break; } /* Color convert */ node->ins |= cfg->cconv ? BLT_INS_IVMX : 0; /* Scale needed if scaling OR 4:2:0 up/downsampling */ node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ? BLT_INS_SCALE : 0; /* Target */ node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0]; node->tty = dst->bytesperline; node->tty |= bdisp_hw_color_format(dst_fmt); node->tty |= BLT_TTY_DITHER; node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0; node->tty |= cfg->hflip ? BLT_TTY_HSO : 0; node->tty |= cfg->vflip ? BLT_TTY_VSO : 0; if (cfg->dst_420 && (t_plan == BDISP_CBCR)) { /* 420 chroma downsampling */ dst_rect.height /= 2; dst_rect.width /= 2; dst_rect.left /= 2; dst_rect.top /= 2; dst_x_offset /= 2; dst_width /= 2; } node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top; node->txy <<= 16; node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) : dst_rect.left; node->tsz = dst_rect.height << 16 | dst_rect.width; if (cfg->src_interlaced) { /* handle only the top field which is half height of a frame */ src_rect.top /= 2; src_rect.height /= 2; } if (cfg->src_nbp == 1) { /* Src 2 : RGB */ node->s2ba = src->paddr[0]; node->s2ty = src->bytesperline; if (cfg->src_interlaced) node->s2ty *= 2; node->s2ty |= bdisp_hw_color_format(src_fmt); node->s2xy = src_rect.top << 16 | src_rect.left; node->s2sz = src_rect.height << 16 | src_rect.width; } else { /* Src 2 : Cb or CbCr */ if (cfg->src_420) { /* 420 chroma upsampling */ src_rect.top /= 2; src_rect.left /= 2; src_rect.width /= 2; src_rect.height /= 2; } node->s2ba = src->paddr[1]; node->s2ty = src->bytesperline; if (cfg->src_nbp == 3) node->s2ty /= 2; if (cfg->src_interlaced) node->s2ty *= 2; node->s2ty |= bdisp_hw_color_format(src_fmt); node->s2xy = src_rect.top << 16 | src_rect.left; node->s2sz = src_rect.height << 16 | src_rect.width; if (cfg->src_nbp == 3) { /* Src 1 : Cr */ node->s1ba = src->paddr[2]; node->s1ty = node->s2ty; node->s1xy = node->s2xy; } /* Src 3 : Y */ node->s3ba = src->paddr[0]; node->s3ty = src->bytesperline; if (cfg->src_interlaced) node->s3ty *= 2; node->s3ty |= bdisp_hw_color_format(src_fmt); if ((t_plan != BDISP_CBCR) && cfg->src_420) { /* No chroma upsampling for output RGB / Y plane */ node->s3xy = node->s2xy * 2; node->s3sz = node->s2sz * 2; } else { /* No need to read Y (Src3) when writing Chroma */ node->s3ty |= BLT_S3TY_BLANK_ACC; node->s3xy = node->s2xy; node->s3sz = node->s2sz; } } /* Resize (scale OR 4:2:0: chroma up/downsampling) */ if (node->ins & BLT_INS_SCALE) { /* no need to compute Y when writing CbCr from RGB input */ bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv; /* FCTL */ if (cfg->scale) { node->fctl = BLT_FCTL_HV_SCALE; if (!skip_y) node->fctl |= BLT_FCTL_Y_HV_SCALE; } else { node->fctl = BLT_FCTL_HV_SAMPLE; if (!skip_y) node->fctl |= BLT_FCTL_Y_HV_SAMPLE; } /* RSF - Chroma may need to be up/downsampled */ h_inc = cfg->h_inc; v_inc = cfg->v_inc; if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) { /* RGB to 4:2:0 for Chroma: downsample */ h_inc *= 2; v_inc *= 2; } else if (cfg->src_420 && !cfg->dst_420) { /* 4:2:0: to RGB: upsample*/ h_inc /= 2; v_inc /= 2; } node->rsf = v_inc << 16 | h_inc; /* RZI */ node->rzi = BLT_RZI_DEFAULT; /* Filter table physical addr */ node->hfp = bdisp_hw_get_hf_addr(h_inc); node->vfp = bdisp_hw_get_vf_addr(v_inc); /* Y version */ if (!skip_y) { yh_inc = cfg->h_inc; yv_inc = cfg->v_inc; node->y_rsf = yv_inc << 16 | yh_inc; node->y_rzi = BLT_RZI_DEFAULT; node->y_hfp = bdisp_hw_get_hf_addr(yh_inc); node->y_vfp = bdisp_hw_get_vf_addr(yv_inc); } } /* Versatile matrix for RGB / YUV conversion */ if (cfg->cconv) { ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv; node->ivmx0 = ivmx[0]; node->ivmx1 = ivmx[1]; node->ivmx2 = ivmx[2]; node->ivmx3 = ivmx[3]; } }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne1185100.00%2100.00%
Total1185100.00%2100.00%

/** * bdisp_hw_build_all_nodes * @ctx: device context * * Build all the nodes for the blitter operation * * RETURNS: * 0 on success */
static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx) { struct bdisp_op_cfg cfg; unsigned int i, nid = 0; int src_x_offset = 0; for (i = 0; i < MAX_NB_NODE; i++) if (!ctx->node[i]) { dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i); return -EINVAL; } /* Get configuration (scale, flip, ...) */ if (bdisp_hw_get_op_cfg(ctx, &cfg)) return -EINVAL; /* Split source in vertical strides (HW constraint) */ for (i = 0; i < MAX_VERTICAL_STRIDES; i++) { /* Build RGB/Y node and link it to the previous node */ bdisp_hw_build_node(ctx, &cfg, ctx->node[nid], cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y, src_x_offset); if (nid) ctx->node[nid - 1]->nip = ctx->node_paddr[nid]; nid++; /* Build additional Cb(Cr) node, link it to the previous one */ if (cfg.dst_nbp > 1) { bdisp_hw_build_node(ctx, &cfg, ctx->node[nid], BDISP_CBCR, src_x_offset); ctx->node[nid - 1]->nip = ctx->node_paddr[nid]; nid++; } /* Next stride until full width covered */ src_x_offset += MAX_SRC_WIDTH; if (src_x_offset >= ctx->src.crop.width) break; } /* Mark last node as the last */ ctx->node[nid - 1]->nip = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne240100.00%1100.00%
Total240100.00%1100.00%

/** * bdisp_hw_save_request * @ctx: device context * * Save a copy of the request and of the built nodes * * RETURNS: * None */
static void bdisp_hw_save_request(struct bdisp_ctx *ctx) { struct bdisp_node **copy_node = ctx->bdisp_dev->dbg.copy_node; struct bdisp_request *request = &ctx->bdisp_dev->dbg.copy_request; struct bdisp_node **node = ctx->node; int i; /* Request copy */ request->src = ctx->src; request->dst = ctx->dst; request->hflip = ctx->hflip; request->vflip = ctx->vflip; request->nb_req++; /* Nodes copy */ for (i = 0; i < MAX_NB_NODE; i++) { /* Allocate memory if not done yet */ if (!copy_node[i]) { copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev, sizeof(*copy_node[i]), GFP_KERNEL); if (!copy_node[i]) return; } *copy_node[i] = *node[i]; } }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne163100.00%2100.00%
Total163100.00%2100.00%

/** * bdisp_hw_update * @ctx: device context * * Send the request to the HW * * RETURNS: * 0 on success */
int bdisp_hw_update(struct bdisp_ctx *ctx) { int ret; struct bdisp_dev *bdisp = ctx->bdisp_dev; struct device *dev = bdisp->dev; unsigned int node_id; dev_dbg(dev, "%s\n", __func__); /* build nodes */ ret = bdisp_hw_build_all_nodes(ctx); if (ret) { dev_err(dev, "cannot build nodes (%d)\n", ret); return ret; } /* Save a copy of the request */ bdisp_hw_save_request(ctx); /* Configure interrupt to 'Last Node Reached for AQ1' */ writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL); writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0); /* Write first node addr */ writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP); /* Find and write last node addr : this starts the HW processing */ for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) { if (!ctx->node[node_id]->nip) break; } writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne166100.00%2100.00%
Total166100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
fabien dessennefabien dessenne3403100.00%4100.00%
Total3403100.00%4100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}