Commit e3185e1d authored by Paul Kocialkowski's avatar Paul Kocialkowski Committed by Mauro Carvalho Chehab

media: staging: media: Add support for the Allwinner A31 ISP

Some Allwinner platforms come with an Image Signal Processor, which
supports various features in order to enhance and transform data
received by image sensors into good-looking pictures. In most cases,
the data is raw bayer, which gets internally converted to RGB and
finally YUV, which is what the hardware produces.

This driver supports ISPs that are similar to the A31 ISP, which was
the first standalone ISP found in Allwinner platforms. Simpler ISP
blocks were found in the A10 and A20, where they are tied to a CSI
controller. Newer generations of Allwinner SoCs (starting with the
H6, H616, etc) come with a new camera subsystem and revised ISP.
Even though these previous and next-generation ISPs are somewhat
similar to the A31 ISP, they have enough significant differences to
be out of the scope of this driver.

While the ISP supports many features, including 3A and many
enhancement blocks, this implementation is limited to the following:
- V3s (V3/S3) platform support;
- Bayer media bus formats as input;
- Semi-planar YUV (NV12/NV21) as output;
- Debayering with per-component gain and offset configuration;
- 2D noise filtering with configurable coefficients.

Since many features are missing from the associated uAPI, the driver
is aimed to integrate staging until all features are properly
described.

On the technical side, it uses the v4l2 and media controller APIs,
with a video node for capture, a processor subdev and a video node
for parameters submission. A specific uAPI structure and associated
v4l2 meta format are used to configure parameters of the supported
modules.

One particular thing about the hardware is that configuration for
module registers needs to be stored in a DMA buffer and gets copied
to actual registers by the hardware at the next vsync, when instructed
by a flag. This is handled by the "state" mechanism in the driver.
Signed-off-by: default avatarPaul Kocialkowski <paul.kocialkowski@bootlin.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 4c6f0bc1
......@@ -12,5 +12,6 @@ config VIDEO_SUNXI
if VIDEO_SUNXI
source "drivers/staging/media/sunxi/cedrus/Kconfig"
source "drivers/staging/media/sunxi/sun6i-isp/Kconfig"
endif
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus/
obj-$(CONFIG_VIDEO_SUN6I_ISP) += sun6i-isp/
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_SUN6I_ISP
tristate "Allwinner A31 Image Signal Processor (ISP) Driver"
depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV
depends on ARCH_SUNXI || COMPILE_TEST
depends on PM && COMMON_CLK && HAS_DMA
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
select V4L2_FWNODE
select REGMAP_MMIO
help
Support for the Allwinner A31 Image Signal Processor (ISP), also
found on other platforms such as the A80, A83T or V3/V3s.
# SPDX-License-Identifier: GPL-2.0-only
sun6i-isp-y += sun6i_isp.o sun6i_isp_proc.o sun6i_isp_capture.o sun6i_isp_params.o
obj-$(CONFIG_VIDEO_SUN6I_ISP) += sun6i-isp.o
Unstaging requirements:
- Add uAPI support and documentation for the configuration of all the hardware
modules and description of the statistics data structures;
- Add support for statistics reporting;
- Add userspace support in libcamera which demonstrates the ability to receive
statistics and adapt hardware modules configuration accordingly;
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2021-2022 Bootlin
* Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
#ifndef _SUN6I_ISP_H_
#define _SUN6I_ISP_H_
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>
#include "sun6i_isp_capture.h"
#include "sun6i_isp_params.h"
#include "sun6i_isp_proc.h"
#define SUN6I_ISP_NAME "sun6i-isp"
#define SUN6I_ISP_DESCRIPTION "Allwinner A31 ISP Device"
enum sun6i_isp_port {
SUN6I_ISP_PORT_CSI0 = 0,
SUN6I_ISP_PORT_CSI1 = 1,
};
struct sun6i_isp_buffer {
struct vb2_v4l2_buffer v4l2_buffer;
struct list_head list;
};
struct sun6i_isp_v4l2 {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
};
struct sun6i_isp_table {
void *data;
dma_addr_t address;
unsigned int size;
};
struct sun6i_isp_tables {
struct sun6i_isp_table load;
struct sun6i_isp_table save;
struct sun6i_isp_table lut;
struct sun6i_isp_table drc;
struct sun6i_isp_table stats;
};
struct sun6i_isp_device {
struct device *dev;
struct sun6i_isp_tables tables;
struct sun6i_isp_v4l2 v4l2;
struct sun6i_isp_proc proc;
struct sun6i_isp_capture capture;
struct sun6i_isp_params params;
struct regmap *regmap;
struct clk *clock_mod;
struct clk *clock_ram;
struct reset_control *reset;
spinlock_t state_lock; /* State helpers lock. */
};
struct sun6i_isp_variant {
unsigned int table_load_save_size;
unsigned int table_lut_size;
unsigned int table_drc_size;
unsigned int table_stats_size;
};
/* Helpers */
u32 sun6i_isp_load_read(struct sun6i_isp_device *isp_dev, u32 offset);
void sun6i_isp_load_write(struct sun6i_isp_device *isp_dev, u32 offset,
u32 value);
u32 sun6i_isp_address_value(dma_addr_t address);
/* State */
void sun6i_isp_state_update(struct sun6i_isp_device *isp_dev, bool ready_hold);
/* Tables */
void sun6i_isp_tables_configure(struct sun6i_isp_device *isp_dev);
#endif
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2021-2022 Bootlin
* Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
#ifndef _SUN6I_ISP_CAPTURE_H_
#define _SUN6I_ISP_CAPTURE_H_
#include <media/v4l2-device.h>
#define SUN6I_ISP_CAPTURE_NAME "sun6i-isp-capture"
#define SUN6I_ISP_CAPTURE_WIDTH_MIN 16
#define SUN6I_ISP_CAPTURE_WIDTH_MAX 3264
#define SUN6I_ISP_CAPTURE_HEIGHT_MIN 16
#define SUN6I_ISP_CAPTURE_HEIGHT_MAX 2448
struct sun6i_isp_device;
struct sun6i_isp_capture_format {
u32 pixelformat;
u8 output_format;
};
#undef current
struct sun6i_isp_capture_state {
struct list_head queue;
spinlock_t lock; /* Queue and buffers lock. */
struct sun6i_isp_buffer *pending;
struct sun6i_isp_buffer *current;
struct sun6i_isp_buffer *complete;
unsigned int sequence;
bool streaming;
};
struct sun6i_isp_capture {
struct sun6i_isp_capture_state state;
struct video_device video_dev;
struct vb2_queue queue;
struct mutex lock; /* Queue lock. */
struct media_pad pad;
struct v4l2_format format;
};
/* Helpers */
void sun6i_isp_capture_dimensions(struct sun6i_isp_device *isp_dev,
unsigned int *width, unsigned int *height);
void sun6i_isp_capture_format(struct sun6i_isp_device *isp_dev,
u32 *pixelformat);
/* Format */
const struct sun6i_isp_capture_format *
sun6i_isp_capture_format_find(u32 pixelformat);
/* Capture */
void sun6i_isp_capture_configure(struct sun6i_isp_device *isp_dev);
/* State */
void sun6i_isp_capture_state_update(struct sun6i_isp_device *isp_dev,
bool *update);
void sun6i_isp_capture_state_complete(struct sun6i_isp_device *isp_dev);
void sun6i_isp_capture_finish(struct sun6i_isp_device *isp_dev);
/* Capture */
int sun6i_isp_capture_setup(struct sun6i_isp_device *isp_dev);
void sun6i_isp_capture_cleanup(struct sun6i_isp_device *isp_dev);
#endif
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2021-2022 Bootlin
* Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
#ifndef _SUN6I_ISP_PARAMS_H_
#define _SUN6I_ISP_PARAMS_H_
#include <media/v4l2-device.h>
#define SUN6I_ISP_PARAMS_NAME "sun6i-isp-params"
struct sun6i_isp_device;
struct sun6i_isp_params_state {
struct list_head queue; /* Queue and buffers lock. */
spinlock_t lock;
struct sun6i_isp_buffer *pending;
bool configured;
bool streaming;
};
struct sun6i_isp_params {
struct sun6i_isp_params_state state;
struct video_device video_dev;
struct vb2_queue queue;
struct mutex lock; /* Queue lock. */
struct media_pad pad;
struct v4l2_format format;
};
/* Params */
void sun6i_isp_params_configure(struct sun6i_isp_device *isp_dev);
/* State */
void sun6i_isp_params_state_update(struct sun6i_isp_device *isp_dev,
bool *update);
void sun6i_isp_params_state_complete(struct sun6i_isp_device *isp_dev);
/* Params */
int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev);
void sun6i_isp_params_cleanup(struct sun6i_isp_device *isp_dev);
#endif
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2021-2022 Bootlin
* Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
*/
#ifndef _SUN6I_ISP_PROC_H_
#define _SUN6I_ISP_PROC_H_
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#define SUN6I_ISP_PROC_NAME "sun6i-isp-proc"
enum sun6i_isp_proc_pad {
SUN6I_ISP_PROC_PAD_SINK_CSI = 0,
SUN6I_ISP_PROC_PAD_SINK_PARAMS = 1,
SUN6I_ISP_PROC_PAD_SOURCE = 2,
SUN6I_ISP_PROC_PAD_COUNT = 3,
};
struct sun6i_isp_device;
struct sun6i_isp_proc_format {
u32 mbus_code;
u8 input_format;
u8 input_yuv_seq;
};
struct sun6i_isp_proc_source {
struct v4l2_subdev *subdev;
struct v4l2_fwnode_endpoint endpoint;
bool expected;
};
struct sun6i_isp_proc_async_subdev {
struct v4l2_async_subdev async_subdev;
struct sun6i_isp_proc_source *source;
};
struct sun6i_isp_proc {
struct v4l2_subdev subdev;
struct media_pad pads[3];
struct v4l2_async_notifier notifier;
struct v4l2_mbus_framefmt mbus_format;
struct mutex lock; /* Mbus format lock. */
struct sun6i_isp_proc_source source_csi0;
struct sun6i_isp_proc_source source_csi1;
};
/* Helpers */
void sun6i_isp_proc_dimensions(struct sun6i_isp_device *isp_dev,
unsigned int *width, unsigned int *height);
/* Format */
const struct sun6i_isp_proc_format *sun6i_isp_proc_format_find(u32 mbus_code);
/* Proc */
int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev);
void sun6i_isp_proc_cleanup(struct sun6i_isp_device *isp_dev);
#endif
This diff is collapsed.
/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR MIT) */
/*
* Allwinner A31 ISP Configuration
*/
#ifndef _UAPI_SUN6I_ISP_CONFIG_H
#define _UAPI_SUN6I_ISP_CONFIG_H
#include <linux/types.h>
#define V4L2_META_FMT_SUN6I_ISP_PARAMS v4l2_fourcc('S', '6', 'I', 'P') /* Allwinner A31 ISP Parameters */
#define SUN6I_ISP_MODULE_BAYER (1U << 0)
#define SUN6I_ISP_MODULE_BDNF (1U << 1)
struct sun6i_isp_params_config_bayer {
__u16 offset_r;
__u16 offset_gr;
__u16 offset_gb;
__u16 offset_b;
__u16 gain_r;
__u16 gain_gr;
__u16 gain_gb;
__u16 gain_b;
};
struct sun6i_isp_params_config_bdnf {
__u8 in_dis_min;
__u8 in_dis_max;
__u8 coefficients_g[7];
__u8 coefficients_rb[5];
};
struct sun6i_isp_params_config {
__u32 modules_used;
struct sun6i_isp_params_config_bayer bayer;
struct sun6i_isp_params_config_bdnf bdnf;
};
#endif /* _UAPI_SUN6I_ISP_CONFIG_H */
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