cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sun4i_dma.c (11609B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2016 NextThing Co
      4 * Copyright (C) 2016-2019 Bootlin
      5 *
      6 * Author: Maxime Ripard <maxime.ripard@bootlin.com>
      7 */
      8
      9#include <linux/device.h>
     10#include <linux/interrupt.h>
     11#include <linux/list.h>
     12#include <linux/mutex.h>
     13#include <linux/spinlock.h>
     14#include <media/videobuf2-dma-contig.h>
     15#include <media/videobuf2-v4l2.h>
     16
     17#include "sun4i_csi.h"
     18
     19struct sun4i_csi_buffer {
     20	struct vb2_v4l2_buffer	vb;
     21	struct list_head	list;
     22};
     23
     24static inline struct sun4i_csi_buffer *
     25vb2_v4l2_to_csi_buffer(const struct vb2_v4l2_buffer *p)
     26{
     27	return container_of(p, struct sun4i_csi_buffer, vb);
     28}
     29
     30static inline struct sun4i_csi_buffer *
     31vb2_to_csi_buffer(const struct vb2_buffer *p)
     32{
     33	return vb2_v4l2_to_csi_buffer(to_vb2_v4l2_buffer(p));
     34}
     35
     36static void sun4i_csi_capture_start(struct sun4i_csi *csi)
     37{
     38	writel(CSI_CPT_CTRL_VIDEO_START, csi->regs + CSI_CPT_CTRL_REG);
     39}
     40
     41static void sun4i_csi_capture_stop(struct sun4i_csi *csi)
     42{
     43	writel(0, csi->regs + CSI_CPT_CTRL_REG);
     44}
     45
     46static int sun4i_csi_queue_setup(struct vb2_queue *vq,
     47				 unsigned int *nbuffers,
     48				 unsigned int *nplanes,
     49				 unsigned int sizes[],
     50				 struct device *alloc_devs[])
     51{
     52	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
     53	unsigned int num_planes = csi->fmt.num_planes;
     54	unsigned int i;
     55
     56	if (*nplanes) {
     57		if (*nplanes != num_planes)
     58			return -EINVAL;
     59
     60		for (i = 0; i < num_planes; i++)
     61			if (sizes[i] < csi->fmt.plane_fmt[i].sizeimage)
     62				return -EINVAL;
     63		return 0;
     64	}
     65
     66	*nplanes = num_planes;
     67	for (i = 0; i < num_planes; i++)
     68		sizes[i] = csi->fmt.plane_fmt[i].sizeimage;
     69
     70	return 0;
     71};
     72
     73static int sun4i_csi_buffer_prepare(struct vb2_buffer *vb)
     74{
     75	struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
     76	unsigned int i;
     77
     78	for (i = 0; i < csi->fmt.num_planes; i++) {
     79		unsigned long size = csi->fmt.plane_fmt[i].sizeimage;
     80
     81		if (vb2_plane_size(vb, i) < size) {
     82			dev_err(csi->dev, "buffer too small (%lu < %lu)\n",
     83				vb2_plane_size(vb, i), size);
     84			return -EINVAL;
     85		}
     86
     87		vb2_set_plane_payload(vb, i, size);
     88	}
     89
     90	return 0;
     91}
     92
     93static int sun4i_csi_setup_scratch_buffer(struct sun4i_csi *csi,
     94					  unsigned int slot)
     95{
     96	dma_addr_t addr = csi->scratch.paddr;
     97	unsigned int plane;
     98
     99	dev_dbg(csi->dev,
    100		"No more available buffer, using the scratch buffer\n");
    101
    102	for (plane = 0; plane < csi->fmt.num_planes; plane++) {
    103		writel(addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
    104		addr += csi->fmt.plane_fmt[plane].sizeimage;
    105	}
    106
    107	csi->current_buf[slot] = NULL;
    108	return 0;
    109}
    110
    111static int sun4i_csi_buffer_fill_slot(struct sun4i_csi *csi, unsigned int slot)
    112{
    113	struct sun4i_csi_buffer *c_buf;
    114	struct vb2_v4l2_buffer *v_buf;
    115	unsigned int plane;
    116
    117	/*
    118	 * We should never end up in a situation where we overwrite an
    119	 * already filled slot.
    120	 */
    121	if (WARN_ON(csi->current_buf[slot]))
    122		return -EINVAL;
    123
    124	if (list_empty(&csi->buf_list))
    125		return sun4i_csi_setup_scratch_buffer(csi, slot);
    126
    127	c_buf = list_first_entry(&csi->buf_list, struct sun4i_csi_buffer, list);
    128	list_del_init(&c_buf->list);
    129
    130	v_buf = &c_buf->vb;
    131	csi->current_buf[slot] = v_buf;
    132
    133	for (plane = 0; plane < csi->fmt.num_planes; plane++) {
    134		dma_addr_t buf_addr;
    135
    136		buf_addr = vb2_dma_contig_plane_dma_addr(&v_buf->vb2_buf,
    137							 plane);
    138		writel(buf_addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
    139	}
    140
    141	return 0;
    142}
    143
    144static int sun4i_csi_buffer_fill_all(struct sun4i_csi *csi)
    145{
    146	unsigned int slot;
    147	int ret;
    148
    149	for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
    150		ret = sun4i_csi_buffer_fill_slot(csi, slot);
    151		if (ret)
    152			return ret;
    153	}
    154
    155	return 0;
    156}
    157
    158static void sun4i_csi_buffer_mark_done(struct sun4i_csi *csi,
    159				       unsigned int slot,
    160				       unsigned int sequence)
    161{
    162	struct vb2_v4l2_buffer *v_buf;
    163
    164	if (!csi->current_buf[slot]) {
    165		dev_dbg(csi->dev, "Scratch buffer was used, ignoring..\n");
    166		return;
    167	}
    168
    169	v_buf = csi->current_buf[slot];
    170	v_buf->field = csi->fmt.field;
    171	v_buf->sequence = sequence;
    172	v_buf->vb2_buf.timestamp = ktime_get_ns();
    173	vb2_buffer_done(&v_buf->vb2_buf, VB2_BUF_STATE_DONE);
    174
    175	csi->current_buf[slot] = NULL;
    176}
    177
    178static int sun4i_csi_buffer_flip(struct sun4i_csi *csi, unsigned int sequence)
    179{
    180	u32 reg = readl(csi->regs + CSI_BUF_CTRL_REG);
    181	unsigned int next;
    182
    183	/* Our next buffer is not the current buffer */
    184	next = !(reg & CSI_BUF_CTRL_DBS);
    185
    186	/* Report the previous buffer as done */
    187	sun4i_csi_buffer_mark_done(csi, next, sequence);
    188
    189	/* Put a new buffer in there */
    190	return sun4i_csi_buffer_fill_slot(csi, next);
    191}
    192
    193static void sun4i_csi_buffer_queue(struct vb2_buffer *vb)
    194{
    195	struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
    196	struct sun4i_csi_buffer *buf = vb2_to_csi_buffer(vb);
    197	unsigned long flags;
    198
    199	spin_lock_irqsave(&csi->qlock, flags);
    200	list_add_tail(&buf->list, &csi->buf_list);
    201	spin_unlock_irqrestore(&csi->qlock, flags);
    202}
    203
    204static void return_all_buffers(struct sun4i_csi *csi,
    205			       enum vb2_buffer_state state)
    206{
    207	struct sun4i_csi_buffer *buf, *node;
    208	unsigned int slot;
    209
    210	list_for_each_entry_safe(buf, node, &csi->buf_list, list) {
    211		vb2_buffer_done(&buf->vb.vb2_buf, state);
    212		list_del(&buf->list);
    213	}
    214
    215	for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
    216		struct vb2_v4l2_buffer *v_buf = csi->current_buf[slot];
    217
    218		if (!v_buf)
    219			continue;
    220
    221		vb2_buffer_done(&v_buf->vb2_buf, state);
    222		csi->current_buf[slot] = NULL;
    223	}
    224}
    225
    226static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
    227{
    228	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
    229	struct v4l2_mbus_config_parallel *bus = &csi->bus;
    230	const struct sun4i_csi_format *csi_fmt;
    231	unsigned long href_pol, pclk_pol, vref_pol;
    232	unsigned long flags;
    233	unsigned int i;
    234	int ret;
    235
    236	csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL);
    237	if (!csi_fmt)
    238		return -EINVAL;
    239
    240	dev_dbg(csi->dev, "Starting capture\n");
    241
    242	csi->sequence = 0;
    243
    244	/*
    245	 * We need a scratch buffer in case where we'll not have any
    246	 * more buffer queued so that we don't error out. One of those
    247	 * cases is when you end up at the last frame to capture, you
    248	 * don't havea any buffer queued any more, and yet it doesn't
    249	 * really matter since you'll never reach the next buffer.
    250	 *
    251	 * Since we support the multi-planar API, we need to have a
    252	 * buffer for each plane. Allocating a single one large enough
    253	 * to hold all the buffers is simpler, so let's go for that.
    254	 */
    255	csi->scratch.size = 0;
    256	for (i = 0; i < csi->fmt.num_planes; i++)
    257		csi->scratch.size += csi->fmt.plane_fmt[i].sizeimage;
    258
    259	csi->scratch.vaddr = dma_alloc_coherent(csi->dev,
    260						csi->scratch.size,
    261						&csi->scratch.paddr,
    262						GFP_KERNEL);
    263	if (!csi->scratch.vaddr) {
    264		dev_err(csi->dev, "Failed to allocate scratch buffer\n");
    265		ret = -ENOMEM;
    266		goto err_clear_dma_queue;
    267	}
    268
    269	ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe);
    270	if (ret < 0)
    271		goto err_free_scratch_buffer;
    272
    273	spin_lock_irqsave(&csi->qlock, flags);
    274
    275	/* Setup timings */
    276	writel(CSI_WIN_CTRL_W_ACTIVE(csi->fmt.width * 2),
    277	       csi->regs + CSI_WIN_CTRL_W_REG);
    278	writel(CSI_WIN_CTRL_H_ACTIVE(csi->fmt.height),
    279	       csi->regs + CSI_WIN_CTRL_H_REG);
    280
    281	/*
    282	 * This hardware uses [HV]REF instead of [HV]SYNC. Based on the
    283	 * provided timing diagrams in the manual, positive polarity
    284	 * equals active high [HV]REF.
    285	 *
    286	 * When the back porch is 0, [HV]REF is more or less equivalent
    287	 * to [HV]SYNC inverted.
    288	 */
    289	href_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
    290	vref_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
    291	pclk_pol = !!(bus->flags & V4L2_MBUS_PCLK_SAMPLE_RISING);
    292	writel(CSI_CFG_INPUT_FMT(csi_fmt->input) |
    293	       CSI_CFG_OUTPUT_FMT(csi_fmt->output) |
    294	       CSI_CFG_VREF_POL(vref_pol) |
    295	       CSI_CFG_HREF_POL(href_pol) |
    296	       CSI_CFG_PCLK_POL(pclk_pol),
    297	       csi->regs + CSI_CFG_REG);
    298
    299	/* Setup buffer length */
    300	writel(csi->fmt.plane_fmt[0].bytesperline,
    301	       csi->regs + CSI_BUF_LEN_REG);
    302
    303	/* Prepare our buffers in hardware */
    304	ret = sun4i_csi_buffer_fill_all(csi);
    305	if (ret) {
    306		spin_unlock_irqrestore(&csi->qlock, flags);
    307		goto err_disable_pipeline;
    308	}
    309
    310	/* Enable double buffering */
    311	writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG);
    312
    313	/* Clear the pending interrupts */
    314	writel(CSI_INT_FRM_DONE, csi->regs + 0x34);
    315
    316	/* Enable frame done interrupt */
    317	writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG);
    318
    319	sun4i_csi_capture_start(csi);
    320
    321	spin_unlock_irqrestore(&csi->qlock, flags);
    322
    323	ret = v4l2_subdev_call(csi->src_subdev, video, s_stream, 1);
    324	if (ret < 0 && ret != -ENOIOCTLCMD)
    325		goto err_disable_device;
    326
    327	return 0;
    328
    329err_disable_device:
    330	sun4i_csi_capture_stop(csi);
    331
    332err_disable_pipeline:
    333	media_pipeline_stop(&csi->vdev.entity);
    334
    335err_free_scratch_buffer:
    336	dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
    337			  csi->scratch.paddr);
    338
    339err_clear_dma_queue:
    340	spin_lock_irqsave(&csi->qlock, flags);
    341	return_all_buffers(csi, VB2_BUF_STATE_QUEUED);
    342	spin_unlock_irqrestore(&csi->qlock, flags);
    343
    344	return ret;
    345}
    346
    347static void sun4i_csi_stop_streaming(struct vb2_queue *vq)
    348{
    349	struct sun4i_csi *csi = vb2_get_drv_priv(vq);
    350	unsigned long flags;
    351
    352	dev_dbg(csi->dev, "Stopping capture\n");
    353
    354	v4l2_subdev_call(csi->src_subdev, video, s_stream, 0);
    355	sun4i_csi_capture_stop(csi);
    356
    357	/* Release all active buffers */
    358	spin_lock_irqsave(&csi->qlock, flags);
    359	return_all_buffers(csi, VB2_BUF_STATE_ERROR);
    360	spin_unlock_irqrestore(&csi->qlock, flags);
    361
    362	media_pipeline_stop(&csi->vdev.entity);
    363
    364	dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
    365			  csi->scratch.paddr);
    366}
    367
    368static const struct vb2_ops sun4i_csi_qops = {
    369	.queue_setup		= sun4i_csi_queue_setup,
    370	.buf_prepare		= sun4i_csi_buffer_prepare,
    371	.buf_queue		= sun4i_csi_buffer_queue,
    372	.start_streaming	= sun4i_csi_start_streaming,
    373	.stop_streaming		= sun4i_csi_stop_streaming,
    374	.wait_prepare		= vb2_ops_wait_prepare,
    375	.wait_finish		= vb2_ops_wait_finish,
    376};
    377
    378static irqreturn_t sun4i_csi_irq(int irq, void *data)
    379{
    380	struct sun4i_csi *csi = data;
    381	u32 reg;
    382
    383	reg = readl(csi->regs + CSI_INT_STA_REG);
    384
    385	/* Acknowledge the interrupts */
    386	writel(reg, csi->regs + CSI_INT_STA_REG);
    387
    388	if (!(reg & CSI_INT_FRM_DONE))
    389		return IRQ_HANDLED;
    390
    391	spin_lock(&csi->qlock);
    392	if (sun4i_csi_buffer_flip(csi, csi->sequence++)) {
    393		dev_warn(csi->dev, "%s: Flip failed\n", __func__);
    394		sun4i_csi_capture_stop(csi);
    395	}
    396	spin_unlock(&csi->qlock);
    397
    398	return IRQ_HANDLED;
    399}
    400
    401int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
    402{
    403	struct vb2_queue *q = &csi->queue;
    404	int ret;
    405	int i;
    406
    407	spin_lock_init(&csi->qlock);
    408	mutex_init(&csi->lock);
    409
    410	INIT_LIST_HEAD(&csi->buf_list);
    411	for (i = 0; i < CSI_MAX_BUFFER; i++)
    412		csi->current_buf[i] = NULL;
    413
    414	q->min_buffers_needed = 3;
    415	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    416	q->io_modes = VB2_MMAP | VB2_DMABUF;
    417	q->lock = &csi->lock;
    418	q->drv_priv = csi;
    419	q->buf_struct_size = sizeof(struct sun4i_csi_buffer);
    420	q->ops = &sun4i_csi_qops;
    421	q->mem_ops = &vb2_dma_contig_memops;
    422	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
    423	q->dev = csi->dev;
    424
    425	ret = vb2_queue_init(q);
    426	if (ret < 0) {
    427		dev_err(csi->dev, "failed to initialize VB2 queue\n");
    428		goto err_free_mutex;
    429	}
    430
    431	ret = v4l2_device_register(csi->dev, &csi->v4l);
    432	if (ret) {
    433		dev_err(csi->dev, "Couldn't register the v4l2 device\n");
    434		goto err_free_mutex;
    435	}
    436
    437	ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0,
    438			       dev_name(csi->dev), csi);
    439	if (ret) {
    440		dev_err(csi->dev, "Couldn't register our interrupt\n");
    441		goto err_unregister_device;
    442	}
    443
    444	return 0;
    445
    446err_unregister_device:
    447	v4l2_device_unregister(&csi->v4l);
    448
    449err_free_mutex:
    450	mutex_destroy(&csi->lock);
    451	return ret;
    452}
    453
    454void sun4i_csi_dma_unregister(struct sun4i_csi *csi)
    455{
    456	v4l2_device_unregister(&csi->v4l);
    457	mutex_destroy(&csi->lock);
    458}