Commit d77182ad authored by Jernej Skrabec's avatar Jernej Skrabec Committed by Mauro Carvalho Chehab

media: sun8i: Add Allwinner A83T Rotate driver

Allwinner A83T contains rotation core which can rotate and flip images.

Add a driver for it.
Signed-off-by: default avatarJernej Skrabec <jernej.skrabec@siol.net>
[hverkuil-cisco@xs4all.nl: MAINTAINERS paths were out of date, fix that]
[hverkuil-cisco@xs4all.nl: VFL_TYPE_GRABBER -> _VIDEO]
[hverkuil-cisco@xs4all.nl: Fix module build]
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 02fd2782
......@@ -14363,6 +14363,14 @@ F: include/net/rose.h
F: include/uapi/linux/rose.h
F: net/rose/
ROTATION DRIVER FOR ALLWINNER A83T
M: Jernej Skrabec <jernej.skrabec@siol.net>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/platform/sunxi/sun8i-rotate/
F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
RTL2830 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
......
......@@ -507,6 +507,18 @@ config VIDEO_SUN8I_DEINTERLACE
capability found on some SoCs, like H3.
To compile this driver as a module choose m here.
config VIDEO_SUN8I_ROTATE
tristate "Allwinner DE2 rotation driver"
depends on VIDEO_DEV && VIDEO_V4L2
depends on ARCH_SUNXI || COMPILE_TEST
depends on COMMON_CLK && OF
depends on PM
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
Support for the Allwinner DE2 rotation unit.
To compile this driver as a module choose m here.
endif # V4L_MEM2MEM_DRIVERS
# TI VIDEO PORT Helper Modules
......
obj-y += sun4i-csi/
obj-y += sun6i-csi/
obj-y += sun8i-di/
obj-y += sun8i-rotate/
# SPDX-License-Identifier: GPL-2.0
sun8i-rotate-y += sun8i_rotate.o
sun8i-rotate-y += sun8i_formats.o
obj-$(CONFIG_VIDEO_SUN8I_ROTATE) += sun8i-rotate.o
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
#ifndef _SUN8I_FORMATS_H_
#define _SUN8I_FORMATS_H_
#include <linux/videodev2.h>
#define ROTATE_FLAG_YUV BIT(0)
#define ROTATE_FLAG_OUTPUT BIT(1)
struct rotate_format {
u32 fourcc;
u32 hw_format;
int planes;
int bpp[3];
int hsub;
int vsub;
unsigned int flags;
};
const struct rotate_format *rotate_find_format(u32 pixelformat);
int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst);
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Allwinner DE2 rotation driver
*
* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net>
*/
#ifndef _SUN8I_ROTATE_H_
#define _SUN8I_ROTATE_H_
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
#include <linux/platform_device.h>
#define ROTATE_NAME "sun8i-rotate"
#define ROTATE_GLB_CTL 0x00
#define ROTATE_GLB_CTL_START BIT(31)
#define ROTATE_GLB_CTL_RESET BIT(30)
#define ROTATE_GLB_CTL_BURST_LEN(x) ((x) << 16)
#define ROTATE_GLB_CTL_HFLIP BIT(7)
#define ROTATE_GLB_CTL_VFLIP BIT(6)
#define ROTATE_GLB_CTL_ROTATION(x) ((x) << 4)
#define ROTATE_GLB_CTL_MODE(x) ((x) << 0)
#define ROTATE_INT 0x04
#define ROTATE_INT_FINISH_IRQ_EN BIT(16)
#define ROTATE_INT_FINISH_IRQ BIT(0)
#define ROTATE_IN_FMT 0x20
#define ROTATE_IN_FMT_FORMAT(x) ((x) << 0)
#define ROTATE_IN_SIZE 0x24
#define ROTATE_IN_PITCH0 0x30
#define ROTATE_IN_PITCH1 0x34
#define ROTATE_IN_PITCH2 0x38
#define ROTATE_IN_ADDRL0 0x40
#define ROTATE_IN_ADDRH0 0x44
#define ROTATE_IN_ADDRL1 0x48
#define ROTATE_IN_ADDRH1 0x4c
#define ROTATE_IN_ADDRL2 0x50
#define ROTATE_IN_ADDRH2 0x54
#define ROTATE_OUT_SIZE 0x84
#define ROTATE_OUT_PITCH0 0x90
#define ROTATE_OUT_PITCH1 0x94
#define ROTATE_OUT_PITCH2 0x98
#define ROTATE_OUT_ADDRL0 0xA0
#define ROTATE_OUT_ADDRH0 0xA4
#define ROTATE_OUT_ADDRL1 0xA8
#define ROTATE_OUT_ADDRH1 0xAC
#define ROTATE_OUT_ADDRL2 0xB0
#define ROTATE_OUT_ADDRH2 0xB4
#define ROTATE_BURST_8 0x07
#define ROTATE_BURST_16 0x0f
#define ROTATE_BURST_32 0x1f
#define ROTATE_BURST_64 0x3f
#define ROTATE_MODE_COPY_ROTATE 0x01
#define ROTATE_FORMAT_ARGB32 0x00
#define ROTATE_FORMAT_ABGR32 0x01
#define ROTATE_FORMAT_RGBA32 0x02
#define ROTATE_FORMAT_BGRA32 0x03
#define ROTATE_FORMAT_XRGB32 0x04
#define ROTATE_FORMAT_XBGR32 0x05
#define ROTATE_FORMAT_RGBX32 0x06
#define ROTATE_FORMAT_BGRX32 0x07
#define ROTATE_FORMAT_RGB24 0x08
#define ROTATE_FORMAT_BGR24 0x09
#define ROTATE_FORMAT_RGB565 0x0a
#define ROTATE_FORMAT_BGR565 0x0b
#define ROTATE_FORMAT_ARGB4444 0x0c
#define ROTATE_FORMAT_ABGR4444 0x0d
#define ROTATE_FORMAT_RGBA4444 0x0e
#define ROTATE_FORMAT_BGRA4444 0x0f
#define ROTATE_FORMAT_ARGB1555 0x10
#define ROTATE_FORMAT_ABGR1555 0x11
#define ROTATE_FORMAT_RGBA5551 0x12
#define ROTATE_FORMAT_BGRA5551 0x13
#define ROTATE_FORMAT_YUYV 0x20
#define ROTATE_FORMAT_UYVY 0x21
#define ROTATE_FORMAT_YVYU 0x22
#define ROTATE_FORMAT_VYUV 0x23
#define ROTATE_FORMAT_NV61 0x24
#define ROTATE_FORMAT_NV16 0x25
#define ROTATE_FORMAT_YUV422P 0x26
#define ROTATE_FORMAT_NV21 0x28
#define ROTATE_FORMAT_NV12 0x29
#define ROTATE_FORMAT_YUV420P 0x2A
#define ROTATE_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
#define ROTATE_MIN_WIDTH 8U
#define ROTATE_MIN_HEIGHT 8U
#define ROTATE_MAX_WIDTH 4096U
#define ROTATE_MAX_HEIGHT 4096U
struct rotate_ctx {
struct v4l2_fh fh;
struct rotate_dev *dev;
struct v4l2_pix_format src_fmt;
struct v4l2_pix_format dst_fmt;
struct v4l2_ctrl_handler ctrl_handler;
u32 hflip;
u32 vflip;
u32 rotate;
};
struct rotate_dev {
struct v4l2_device v4l2_dev;
struct video_device vfd;
struct device *dev;
struct v4l2_m2m_dev *m2m_dev;
/* Device file mutex */
struct mutex dev_mutex;
void __iomem *base;
struct clk *bus_clk;
struct clk *mod_clk;
struct reset_control *rstc;
};
#endif
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
#include "sun8i-formats.h"
#include "sun8i-rotate.h"
/*
* Formats not included in array:
* ROTATE_FORMAT_BGR565
* ROTATE_FORMAT_VYUV
*/
static const struct rotate_format rotate_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB32,
.hw_format = ROTATE_FORMAT_ARGB32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_ABGR32,
.hw_format = ROTATE_FORMAT_ABGR32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGBA32,
.hw_format = ROTATE_FORMAT_RGBA32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_BGRA32,
.hw_format = ROTATE_FORMAT_BGRA32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_XRGB32,
.hw_format = ROTATE_FORMAT_XRGB32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_XBGR32,
.hw_format = ROTATE_FORMAT_XBGR32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGB32,
.hw_format = ROTATE_FORMAT_RGBX32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_BGR32,
.hw_format = ROTATE_FORMAT_BGRX32,
.planes = 1,
.bpp = { 4, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGB24,
.hw_format = ROTATE_FORMAT_RGB24,
.planes = 1,
.bpp = { 3, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_BGR24,
.hw_format = ROTATE_FORMAT_BGR24,
.planes = 1,
.bpp = { 3, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGB565,
.hw_format = ROTATE_FORMAT_RGB565,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_ARGB444,
.hw_format = ROTATE_FORMAT_ARGB4444,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_ABGR444,
.hw_format = ROTATE_FORMAT_ABGR4444,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGBA444,
.hw_format = ROTATE_FORMAT_RGBA4444,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_BGRA444,
.hw_format = ROTATE_FORMAT_BGRA4444,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_ARGB555,
.hw_format = ROTATE_FORMAT_ARGB1555,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_ABGR555,
.hw_format = ROTATE_FORMAT_ABGR1555,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_RGBA555,
.hw_format = ROTATE_FORMAT_RGBA5551,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_BGRA555,
.hw_format = ROTATE_FORMAT_BGRA5551,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 1,
.vsub = 1,
.flags = ROTATE_FLAG_OUTPUT
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.hw_format = ROTATE_FORMAT_YVYU,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.hw_format = ROTATE_FORMAT_UYVY,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
.hw_format = ROTATE_FORMAT_YUYV,
.planes = 1,
.bpp = { 2, 0, 0 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_NV61,
.hw_format = ROTATE_FORMAT_NV61,
.planes = 2,
.bpp = { 1, 2, 0 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_NV16,
.hw_format = ROTATE_FORMAT_NV16,
.planes = 2,
.bpp = { 1, 2, 0 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
.hw_format = ROTATE_FORMAT_YUV422P,
.planes = 3,
.bpp = { 1, 1, 1 },
.hsub = 2,
.vsub = 1,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_NV21,
.hw_format = ROTATE_FORMAT_NV21,
.planes = 2,
.bpp = { 1, 2, 0 },
.hsub = 2,
.vsub = 2,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_NV12,
.hw_format = ROTATE_FORMAT_NV12,
.planes = 2,
.bpp = { 1, 2, 0 },
.hsub = 2,
.vsub = 2,
.flags = ROTATE_FLAG_YUV
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
.hw_format = ROTATE_FORMAT_YUV420P,
.planes = 3,
.bpp = { 1, 1, 1 },
.hsub = 2,
.vsub = 2,
.flags = ROTATE_FLAG_YUV | ROTATE_FLAG_OUTPUT
},
};
const struct rotate_format *rotate_find_format(u32 pixelformat)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rotate_formats); i++)
if (rotate_formats[i].fourcc == pixelformat)
return &rotate_formats[i];
return NULL;
}
int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst)
{
int i, index;
index = 0;
for (i = 0; i < ARRAY_SIZE(rotate_formats); i++) {
/* not all formats can be used for capture buffers */
if (dst && !(rotate_formats[i].flags & ROTATE_FLAG_OUTPUT))
continue;
if (index == f->index) {
f->pixelformat = rotate_formats[i].fourcc;
return 0;
}
index++;
}
return -EINVAL;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment