diff options
Diffstat (limited to 'drivers/media/platform/ti-vpe/cal.c')
-rw-r--r-- | drivers/media/platform/ti-vpe/cal.c | 278 |
1 files changed, 189 insertions, 89 deletions
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 76fe7a8b33f6..8e469d518a74 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -290,11 +290,42 @@ void cal_quickdump_regs(struct cal_dev *cal) * ------------------------------------------------------------------ */ +#define CAL_MAX_PIX_PROC 4 + +static int cal_reserve_pix_proc(struct cal_dev *cal) +{ + unsigned long ret; + + spin_lock(&cal->v4l2_dev.lock); + + ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC); + + if (ret == CAL_MAX_PIX_PROC) { + spin_unlock(&cal->v4l2_dev.lock); + return -ENOSPC; + } + + cal->reserved_pix_proc_mask |= BIT(ret); + + spin_unlock(&cal->v4l2_dev.lock); + + return ret; +} + +static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num) +{ + spin_lock(&cal->v4l2_dev.lock); + + cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num); + + spin_unlock(&cal->v4l2_dev.lock); +} + static void cal_ctx_csi2_config(struct cal_ctx *ctx) { u32 val; - val = cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)); + val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)); cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); /* * DT type: MIPI CSI-2 Specs @@ -304,15 +335,16 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx) * 0x2A: RAW8 1 pixel = 1 byte * 0x1E: YUV422 2 pixels = 4 bytes */ - cal_set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK); - cal_set_field(&val, 0, CAL_CSI2_CTX_VC_MASK); + cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK); + cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, CAL_CSI2_CTX_PACK_MODE_MASK); - cal_write(ctx->cal, CAL_CSI2_CTX0(ctx->index), val); - ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index))); + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val); + ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n", + ctx->phy->instance, ctx->csi2_ctx, + cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx))); } static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) @@ -354,16 +386,16 @@ static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) break; } - val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)); + val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)); cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); - cal_write(ctx->cal, CAL_PIX_PROC(ctx->index), val); - ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_PIX_PROC(ctx->index))); + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val); + ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc, + cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc))); } static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) @@ -371,27 +403,25 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline; u32 val; - val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_WR_DMA_CTRL_YSIZE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, CAL_WR_DMA_CTRL_DTAG_MASK); - cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, - CAL_WR_DMA_CTRL_MODE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, CAL_WR_DMA_CTRL_PATTERN_MASK); cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index))); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx))); - cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->index), + cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx), stride / 16, CAL_WR_DMA_OFST_MASK); - ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index))); + ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx))); - val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)); /* 64 bit word means no skipping */ cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); /* @@ -400,34 +430,32 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) * written per line. */ cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index))); - - val = cal_read(ctx->cal, CAL_CTRL); - cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, - CAL_CTRL_BURSTSIZE_MASK); - cal_set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK); - cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, - CAL_CTRL_POSTED_WRITES_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK); - cal_write(ctx->cal, CAL_CTRL, val); - ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL)); + cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx))); } void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) { - cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), addr); + cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); +} + +static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx) +{ + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + + cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, + CAL_WR_DMA_CTRL_MODE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); } static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) { - u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS, CAL_WR_DMA_CTRL_MODE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); } static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) @@ -441,6 +469,31 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) return stopped; } +int cal_ctx_prepare(struct cal_ctx *ctx) +{ + int ret; + + ctx->use_pix_proc = !ctx->fmtinfo->meta; + + if (ctx->use_pix_proc) { + ret = cal_reserve_pix_proc(ctx->cal); + if (ret < 0) { + ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); + return ret; + } + + ctx->pix_proc = ret; + } + + return 0; +} + +void cal_ctx_unprepare(struct cal_ctx *ctx) +{ + if (ctx->use_pix_proc) + cal_release_pix_proc(ctx->cal, ctx->pix_proc); +} + void cal_ctx_start(struct cal_ctx *ctx) { ctx->sequence = 0; @@ -448,14 +501,17 @@ void cal_ctx_start(struct cal_ctx *ctx) /* Configure the CSI-2, pixel processing and write DMA contexts. */ cal_ctx_csi2_config(ctx); - cal_ctx_pix_proc_config(ctx); + if (ctx->use_pix_proc) + cal_ctx_pix_proc_config(ctx); cal_ctx_wr_dma_config(ctx); /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); + + cal_ctx_wr_dma_enable(ctx); } void cal_ctx_stop(struct cal_ctx *ctx) @@ -479,11 +535,18 @@ void cal_ctx_stop(struct cal_ctx *ctx) /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); ctx->dma.state = CAL_DMA_STOPPED; + + /* Disable CSI2 context */ + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); + + /* Disable pix proc */ + if (ctx->use_pix_proc) + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); } /* ------------------------------------------------------------------ @@ -577,6 +640,16 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), cio_stat); } + + if (status & CAL_HL_IRQ_VC_MASK(i)) { + u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); + + dev_err_ratelimited(cal->dev, + "CIO%u VC error: %#08x\n", + i, vc_stat); + + cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat); + } } } @@ -588,8 +661,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(1), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) cal_irq_wdma_end(cal->ctx[i]); } } @@ -602,8 +675,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(2), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) cal_irq_wdma_start(cal->ctx[i]); } } @@ -635,20 +708,20 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, int pad; int ret; - if (phy->sensor) { + if (phy->source) { phy_info(phy, "Rejecting subdev %s (Already set!!)", subdev->name); return 0; } - phy->sensor = subdev; - phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name); + phy->source = subdev; + phy_dbg(1, phy, "Using source %s for capture\n", subdev->name); pad = media_entity_get_fwnode_pad(&subdev->entity, - of_fwnode_handle(phy->sensor_ep_node), + of_fwnode_handle(phy->source_ep_node), MEDIA_PAD_FL_SOURCE); if (pad < 0) { - phy_err(phy, "Sensor %s has no connected source pad\n", + phy_err(phy, "Source %s has no connected source pad\n", subdev->name); return pad; } @@ -658,7 +731,7 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); if (ret) { - phy_err(phy, "Failed to create media link for sensor %s\n", + phy_err(phy, "Failed to create media link for source %s\n", subdev->name); return ret; } @@ -670,15 +743,30 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) { struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); unsigned int i; - int ret = 0; + int ret; - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (cal->ctx[i]) - cal_ctx_v4l2_register(cal->ctx[i]); + for (i = 0; i < cal->num_contexts; ++i) { + ret = cal_ctx_v4l2_register(cal->ctx[i]); + if (ret) + goto err_ctx_unreg; } - if (cal_mc_api) - ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (!cal_mc_api) + return 0; + + ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (ret) + goto err_ctx_unreg; + + return 0; + +err_ctx_unreg: + for (; i > 0; --i) { + if (!cal->ctx[i - 1]) + continue; + + cal_ctx_v4l2_unregister(cal->ctx[i - 1]); + } return ret; } @@ -701,10 +789,10 @@ static int cal_async_notifier_register(struct cal_dev *cal) struct cal_v4l2_async_subdev *casd; struct fwnode_handle *fwnode; - if (!phy->sensor_node) + if (!phy->source_node) continue; - fwnode = of_fwnode_handle(phy->sensor_node); + fwnode = of_fwnode_handle(phy->source_node); casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier, fwnode, struct cal_v4l2_async_subdev); @@ -777,10 +865,8 @@ static void cal_media_unregister(struct cal_dev *cal) unsigned int i; /* Unregister all the V4L2 video devices. */ - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_unregister(cal->ctx[i]); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_unregister(cal->ctx[i]); cal_async_notifier_unregister(cal); media_device_unregister(&cal->mdev); @@ -825,13 +911,6 @@ static int cal_media_init(struct cal_dev *cal) */ static void cal_media_cleanup(struct cal_dev *cal) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_cleanup(cal->ctx[i]); - } - v4l2_device_unregister(&cal->v4l2_dev); media_device_cleanup(&cal->mdev); @@ -848,14 +927,17 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) struct cal_ctx *ctx; int ret; - ctx = devm_kzalloc(cal->dev, sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL; ctx->cal = cal; ctx->phy = cal->phy[inst]; - ctx->index = inst; + ctx->dma_ctx = inst; + ctx->csi2_ctx = inst; ctx->cport = inst; + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; ret = cal_ctx_v4l2_init(ctx); if (ret) @@ -864,6 +946,13 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) return ctx; } +static void cal_ctx_destroy(struct cal_ctx *ctx) +{ + cal_ctx_v4l2_cleanup(ctx); + + kfree(ctx); +} + static const struct of_device_id cal_of_match[] = { { .compatible = "ti,dra72-cal", @@ -976,7 +1065,6 @@ static int cal_init_camerarx_regmap(struct cal_dev *cal) static int cal_probe(struct platform_device *pdev) { struct cal_dev *cal; - struct cal_ctx *ctx; bool connected = false; unsigned int i; int ret; @@ -1045,7 +1133,7 @@ static int cal_probe(struct platform_device *pdev) goto error_camerarx; } - if (cal->phy[i]->sensor_node) + if (cal->phy[i]->source_node) connected = true; } @@ -1057,15 +1145,17 @@ static int cal_probe(struct platform_device *pdev) /* Create contexts. */ for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (!cal->phy[i]->sensor_node) + if (!cal->phy[i]->source_node) continue; - cal->ctx[i] = cal_ctx_create(cal, i); - if (!cal->ctx[i]) { - cal_err(cal, "Failed to create context %u\n", i); + cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i); + if (!cal->ctx[cal->num_contexts]) { + cal_err(cal, "Failed to create context %u\n", cal->num_contexts); ret = -ENODEV; goto error_context; } + + cal->num_contexts++; } /* Register the media device. */ @@ -1076,11 +1166,8 @@ static int cal_probe(struct platform_device *pdev) return 0; error_context: - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - ctx = cal->ctx[i]; - if (ctx) - cal_ctx_v4l2_cleanup(ctx); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); error_camerarx: for (i = 0; i < cal->data->num_csi2_phy; i++) @@ -1106,16 +1193,17 @@ static int cal_remove(struct platform_device *pdev) cal_media_unregister(cal); - for (i = 0; i < ARRAY_SIZE(cal->phy); i++) { - if (cal->phy[i]) - cal_camerarx_disable(cal->phy[i]); - } + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_disable(cal->phy[i]); - cal_media_cleanup(cal); + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); for (i = 0; i < cal->data->num_csi2_phy; i++) cal_camerarx_destroy(cal->phy[i]); + cal_media_cleanup(cal); + if (ret >= 0) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1127,6 +1215,7 @@ static int cal_runtime_resume(struct device *dev) { struct cal_dev *cal = dev_get_drvdata(dev); unsigned int i; + u32 val; if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { /* @@ -1143,6 +1232,17 @@ static int cal_runtime_resume(struct device *dev) */ cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); + val = cal_read(cal, CAL_CTRL); + cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, + CAL_CTRL_BURSTSIZE_MASK); + cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK); + cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, + CAL_CTRL_POSTED_WRITES_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK); + cal_write(cal, CAL_CTRL, val); + cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL)); + return 0; } |