void rot_dump_registers(struct rot_dev *rot) { unsigned int tmp, i; rot_dbg("dump rotator registers\n"); for (i = 0; i <= ROTATOR_DST; i += 0x4) { tmp = readl(rot->regs + i); rot_dbg("0x%08x: 0x%08x", i, tmp); } }
int rot_v4l2_g_fmt_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct rot_ctx *ctx = priv; struct rot_fmt *rot_fmt; struct rot_frame *frame; struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; int i; frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) return PTR_ERR(frame); rot_fmt = frame->rot_fmt; pixm->width = frame->pix_mp.width; pixm->height = frame->pix_mp.height; pixm->pixelformat = frame->pix_mp.pixelformat; pixm->field = V4L2_FIELD_NONE; pixm->num_planes = frame->rot_fmt->num_planes; pixm->colorspace = 0; for (i = 0; i < pixm->num_planes; ++i) { pixm->plane_fmt[i].bytesperline = (pixm->width * rot_fmt->bitperpixel[i]) >> 3; pixm->plane_fmt[i].sizeimage = pixm->plane_fmt[i].bytesperline * pixm->height; rot_dbg("[%d] plane: bytesperline %d, sizeimage %d\n", i, pixm->plane_fmt[i].bytesperline, pixm->plane_fmt[i].sizeimage); } return 0; }
void rot_watchdog(unsigned long arg) { struct rot_dev *rot = (struct rot_dev *)arg; rot_dbg("timeout watchdog\n"); if (test_bit(DEV_RUN, &rot->state)) { atomic_inc(&rot->wdt.cnt); rot_err("rotator is still running\n"); rot->wdt.timer.expires = jiffies + ROT_TIMEOUT; add_timer(&rot->wdt.timer); } else { rot_dbg("rotator finished job\n"); } if (atomic_read(&rot->wdt.cnt) >= ROT_WDT_CNT) queue_work(rot->wq, &rot->ws); }
static int rot_release(struct file *file) { struct rot_ctx *ctx = file->private_data; struct rot_dev *rot = ctx->rot_dev; rot_dbg("refcnt= %d", atomic_read(&rot->m2m.in_use)); v4l2_m2m_ctx_release(ctx->m2m_ctx); kfree(ctx); atomic_dec(&rot->m2m.in_use); return 0; }
int rot_v4l2_try_fmt_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct rot_ctx *ctx = priv; struct rot_fmt *rot_fmt; struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; int i; if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { rot_err("not supported format type\n"); return -EINVAL; } rot_fmt = rot_find_format(f); if (!rot_fmt) { rot_err("not supported format values\n"); return -EINVAL; } rot_bound_align_image(ctx, rot_fmt, &pixm->width, &pixm->height); pixm->num_planes = rot_fmt->num_planes; pixm->colorspace = 0; for (i = 0; i < pixm->num_planes; ++i) { pixm->plane_fmt[i].bytesperline = (pixm->width * rot_fmt->bitperpixel[i]) >> 3; pixm->plane_fmt[i].sizeimage = pixm->plane_fmt[i].bytesperline * pixm->height; rot_dbg("[%d] plane: bytesperline %d, sizeimage %d\n", i, pixm->plane_fmt[i].bytesperline, pixm->plane_fmt[i].sizeimage); } return 0; }
void rot_work(struct work_struct *work) { struct rot_dev *rot = container_of(work, struct rot_dev, ws); struct rot_ctx *ctx; unsigned long flags; struct vb2_buffer *src_vb, *dst_vb; spin_lock_irqsave(&rot->slock, flags); if (atomic_read(&rot->wdt.cnt) >= ROT_WDT_CNT) { rot_dbg("wakeup blocked process\n"); ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev); if (!ctx || !ctx->m2m_ctx) { rot_err("current ctx is NULL\n"); goto wq_unlock; } src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); if (src_vb && dst_vb) { v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR); v4l2_m2m_job_finish(rot->m2m.m2m_dev, ctx->m2m_ctx); } rot->m2m.ctx = NULL; atomic_set(&rot->wdt.cnt, 0); clear_bit(DEV_RUN, &rot->state); clear_bit(CTX_RUN, &ctx->flags); } wq_unlock: spin_unlock_irqrestore(&rot->slock, flags); pm_runtime_put(&rot->pdev->dev); }
static irqreturn_t rot_irq_handler(int irq, void *priv) { struct rot_dev *rot = priv; struct rot_ctx *ctx; struct vb2_buffer *src_vb, *dst_vb; unsigned int irq_src; spin_lock(&rot->slock); clear_bit(DEV_RUN, &rot->state); if (timer_pending(&rot->wdt.timer)) del_timer(&rot->wdt.timer); rot_hwget_irq_src(rot, &irq_src); rot_hwset_irq_clear(rot, &irq_src); if (irq_src != ISR_PEND_DONE) { rot_err("####################\n"); rot_err("set SFR illegally\n"); rot_err("maybe the result is wrong\n"); rot_err("####################\n"); rot_dump_register(rot); } ctx = v4l2_m2m_get_curr_priv(rot->m2m.m2m_dev); if (!ctx || !ctx->m2m_ctx) { rot_err("current ctx is NULL\n"); goto isr_unlock; } clear_bit(CTX_RUN, &ctx->flags); rot->m2m.ctx = NULL; src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); if (src_vb && dst_vb) { v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); if (test_bit(DEV_SUSPEND, &rot->state)) { rot_dbg("wake up blocked process by suspend\n"); wake_up(&rot->irq.wait); } else { v4l2_m2m_job_finish(rot->m2m.m2m_dev, ctx->m2m_ctx); } /* Wake up from CTX_ABORT state */ if (test_and_clear_bit(CTX_ABORT, &ctx->flags)) wake_up(&rot->irq.wait); queue_work(rot->wq, &rot->ws); } else { rot_err("failed to get the buffer done\n"); } isr_unlock: spin_unlock(&rot->slock); return IRQ_HANDLED; }
static void rot_m2m_device_run(void *priv) { struct rot_ctx *ctx = priv; struct rot_frame *s_frame, *d_frame; struct rot_dev *rot; unsigned long flags, tmp; u32 degree = 0, flip = 0; spin_lock_irqsave(&ctx->slock, flags); rot = ctx->rot_dev; if (test_bit(DEV_RUN, &rot->state)) { rot_err("Rotate is already in progress\n"); goto run_unlock; } if (test_bit(DEV_SUSPEND, &rot->state)) { rot_err("Rotate is in suspend state\n"); goto run_unlock; } if (test_bit(CTX_ABORT, &ctx->flags)) { rot_dbg("aborted rot device run\n"); goto run_unlock; } pm_runtime_get_sync(&ctx->rot_dev->pdev->dev); if (rot->m2m.ctx != ctx) rot->m2m.ctx = ctx; s_frame = &ctx->s_frame; d_frame = &ctx->d_frame; /* Configuration rotator registers */ rot_hwset_image_format(rot, s_frame->rot_fmt->pixelformat); rot_mapping_flip(ctx, °ree, &flip); rot_hwset_flip(rot, flip); rot_hwset_rotation(rot, degree); if (ctx->rotation == 90 || ctx->rotation == 270) { tmp = d_frame->pix_mp.height; d_frame->pix_mp.height = d_frame->pix_mp.width; d_frame->pix_mp.width = tmp; } rot_hwset_src_imgsize(rot, s_frame); rot_hwset_dst_imgsize(rot, d_frame); rot_hwset_src_crop(rot, &s_frame->crop); rot_hwset_dst_crop(rot, &d_frame->crop); rot_set_frame_addr(ctx); /* Enable rotator interrupt */ rot_hwset_irq_frame_done(rot, 1); rot_hwset_irq_illegal_config(rot, 1); set_bit(DEV_RUN, &rot->state); set_bit(CTX_RUN, &ctx->flags); /* Start rotate operation */ rot_hwset_start(rot); /* Start watchdog timer */ rot->wdt.timer.expires = jiffies + ROT_TIMEOUT; if (timer_pending(&rot->wdt.timer) == 0) add_timer(&rot->wdt.timer); else mod_timer(&rot->wdt.timer, rot->wdt.timer.expires); run_unlock: spin_unlock_irqrestore(&ctx->slock, flags); }