mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
[media] bdisp: 2D blitter driver using v4l2 mem2mem framework
This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC. It uses the v4l2 mem2mem framework. The following features are supported and tested: - Color format conversion (RGB32, RGB24, RGB16, NV12, YUV420P) - Copy - Scale - Flip - Deinterlace - Wide (4K) picture support - Crop Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> [hans.verkuil@cisco.com: added missing slab.h include to bdisp-v4l2.c] Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
This commit is contained in:
parent
5a54cd2a3f
commit
28ffeebbb7
9 changed files with 2979 additions and 0 deletions
|
@ -212,6 +212,16 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
|
||||||
help
|
help
|
||||||
This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
|
This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
|
||||||
|
|
||||||
|
config VIDEO_STI_BDISP
|
||||||
|
tristate "STMicroelectronics BDISP 2D blitter driver"
|
||||||
|
depends on VIDEO_DEV && VIDEO_V4L2
|
||||||
|
depends on ARCH_STI || COMPILE_TEST
|
||||||
|
depends on HAS_DMA
|
||||||
|
select VIDEOBUF2_DMA_CONTIG
|
||||||
|
select V4L2_MEM2MEM_DEV
|
||||||
|
help
|
||||||
|
This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC.
|
||||||
|
|
||||||
config VIDEO_SH_VEU
|
config VIDEO_SH_VEU
|
||||||
tristate "SuperH VEU mem2mem video processing driver"
|
tristate "SuperH VEU mem2mem video processing driver"
|
||||||
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
|
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
|
||||||
|
|
|
@ -34,6 +34,8 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/
|
||||||
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/
|
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/
|
||||||
obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/
|
obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/
|
||||||
|
|
||||||
|
obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/
|
||||||
|
|
||||||
obj-$(CONFIG_BLACKFIN) += blackfin/
|
obj-$(CONFIG_BLACKFIN) += blackfin/
|
||||||
|
|
||||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
|
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
|
||||||
|
|
9
drivers/media/platform/sti/bdisp/Kconfig
Normal file
9
drivers/media/platform/sti/bdisp/Kconfig
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
config VIDEO_STI_BDISP
|
||||||
|
tristate "STMicroelectronics BDISP 2D blitter driver"
|
||||||
|
depends on VIDEO_DEV && VIDEO_V4L2
|
||||||
|
select VIDEOBUF2_DMA_CONTIG
|
||||||
|
select V4L2_MEM2MEM_DEV
|
||||||
|
help
|
||||||
|
This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC.
|
||||||
|
To compile this driver as a module, choose M here: the module will
|
||||||
|
be called bdisp.ko.
|
3
drivers/media/platform/sti/bdisp/Makefile
Normal file
3
drivers/media/platform/sti/bdisp/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
obj-$(CONFIG_VIDEO_STI_BDISP) := bdisp.o
|
||||||
|
|
||||||
|
bdisp-objs := bdisp-v4l2.o bdisp-hw.o
|
346
drivers/media/platform/sti/bdisp/bdisp-filter.h
Normal file
346
drivers/media/platform/sti/bdisp/bdisp-filter.h
Normal file
|
@ -0,0 +1,346 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) STMicroelectronics SA 2014
|
||||||
|
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
|
||||||
|
* License terms: GNU General Public License (GPL), version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BDISP_HF_NB 64
|
||||||
|
#define BDISP_VF_NB 40
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_filter_h_spec - Horizontal filter specification
|
||||||
|
*
|
||||||
|
* @min: min scale factor for this filter (6.10 fixed point)
|
||||||
|
* @max: max scale factor for this filter (6.10 fixed point)
|
||||||
|
* coef: filter coefficients
|
||||||
|
*/
|
||||||
|
struct bdisp_filter_h_spec {
|
||||||
|
const u16 min;
|
||||||
|
const u16 max;
|
||||||
|
const u8 coef[BDISP_HF_NB];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bdisp_filter_h_spec bdisp_h_spec[] = {
|
||||||
|
{
|
||||||
|
.min = 0,
|
||||||
|
.max = 921,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0xff, 0x07, 0x3d, 0xfc, 0x01, 0x00,
|
||||||
|
0x00, 0x01, 0xfd, 0x11, 0x36, 0xf9, 0x02, 0x00,
|
||||||
|
0x00, 0x01, 0xfb, 0x1b, 0x2e, 0xf9, 0x02, 0x00,
|
||||||
|
0x00, 0x01, 0xf9, 0x26, 0x26, 0xf9, 0x01, 0x00,
|
||||||
|
0x00, 0x02, 0xf9, 0x30, 0x19, 0xfb, 0x01, 0x00,
|
||||||
|
0x00, 0x02, 0xf9, 0x39, 0x0e, 0xfd, 0x01, 0x00,
|
||||||
|
0x00, 0x01, 0xfc, 0x3e, 0x06, 0xff, 0x00, 0x00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 921,
|
||||||
|
.max = 1024,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
|
||||||
|
0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
|
||||||
|
0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
|
||||||
|
0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
|
||||||
|
0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1024,
|
||||||
|
.max = 1126,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
|
||||||
|
0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
|
||||||
|
0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
|
||||||
|
0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
|
||||||
|
0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1126,
|
||||||
|
.max = 1228,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0x03, 0xfd, 0x08, 0x3e, 0xf9, 0x04, 0xfe,
|
||||||
|
0xfd, 0x06, 0xf8, 0x13, 0x3b, 0xf4, 0x07, 0xfc,
|
||||||
|
0xfb, 0x08, 0xf5, 0x1f, 0x34, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x2b, 0x2a, 0xf1, 0x09, 0xfb,
|
||||||
|
0xfb, 0x09, 0xf2, 0x35, 0x1e, 0xf4, 0x08, 0xfb,
|
||||||
|
0xfc, 0x07, 0xf5, 0x3c, 0x12, 0xf7, 0x06, 0xfd,
|
||||||
|
0xfe, 0x04, 0xfa, 0x3f, 0x07, 0xfc, 0x03, 0xff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1228,
|
||||||
|
.max = 1331,
|
||||||
|
.coef = {
|
||||||
|
0xfd, 0x04, 0xfc, 0x05, 0x39, 0x05, 0xfc, 0x04,
|
||||||
|
0xfc, 0x06, 0xf9, 0x0c, 0x39, 0xfe, 0x00, 0x02,
|
||||||
|
0xfb, 0x08, 0xf6, 0x17, 0x35, 0xf9, 0x02, 0x00,
|
||||||
|
0xfc, 0x08, 0xf4, 0x20, 0x30, 0xf4, 0x05, 0xff,
|
||||||
|
0xfd, 0x07, 0xf4, 0x29, 0x28, 0xf3, 0x07, 0xfd,
|
||||||
|
0xff, 0x05, 0xf5, 0x31, 0x1f, 0xf3, 0x08, 0xfc,
|
||||||
|
0x00, 0x02, 0xf9, 0x38, 0x14, 0xf6, 0x08, 0xfb,
|
||||||
|
0x02, 0x00, 0xff, 0x3a, 0x0b, 0xf8, 0x06, 0xfc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1331,
|
||||||
|
.max = 1433,
|
||||||
|
.coef = {
|
||||||
|
0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06,
|
||||||
|
0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05,
|
||||||
|
0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04,
|
||||||
|
0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02,
|
||||||
|
0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00,
|
||||||
|
0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff,
|
||||||
|
0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe,
|
||||||
|
0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1433,
|
||||||
|
.max = 1536,
|
||||||
|
.coef = {
|
||||||
|
0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06,
|
||||||
|
0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06,
|
||||||
|
0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06,
|
||||||
|
0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04,
|
||||||
|
0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03,
|
||||||
|
0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01,
|
||||||
|
0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00,
|
||||||
|
0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1536,
|
||||||
|
.max = 2048,
|
||||||
|
.coef = {
|
||||||
|
0x05, 0xfd, 0xfb, 0x13, 0x25, 0x13, 0xfb, 0xfd,
|
||||||
|
0x05, 0xfc, 0xfd, 0x17, 0x24, 0x0f, 0xf9, 0xff,
|
||||||
|
0x04, 0xfa, 0xff, 0x1b, 0x24, 0x0b, 0xf9, 0x00,
|
||||||
|
0x03, 0xf9, 0x01, 0x1f, 0x23, 0x08, 0xf8, 0x01,
|
||||||
|
0x02, 0xf9, 0x04, 0x22, 0x20, 0x04, 0xf9, 0x02,
|
||||||
|
0x01, 0xf8, 0x08, 0x25, 0x1d, 0x01, 0xf9, 0x03,
|
||||||
|
0x00, 0xf9, 0x0c, 0x25, 0x1a, 0xfe, 0xfa, 0x04,
|
||||||
|
0xff, 0xf9, 0x10, 0x26, 0x15, 0xfc, 0xfc, 0x05
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 2048,
|
||||||
|
.max = 3072,
|
||||||
|
.coef = {
|
||||||
|
0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd,
|
||||||
|
0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc,
|
||||||
|
0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc,
|
||||||
|
0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb,
|
||||||
|
0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb,
|
||||||
|
0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb,
|
||||||
|
0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb,
|
||||||
|
0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 3072,
|
||||||
|
.max = 4096,
|
||||||
|
.coef = {
|
||||||
|
0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02,
|
||||||
|
0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01,
|
||||||
|
0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00,
|
||||||
|
0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00,
|
||||||
|
0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00,
|
||||||
|
0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00,
|
||||||
|
0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff,
|
||||||
|
0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 4096,
|
||||||
|
.max = 5120,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04,
|
||||||
|
0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04,
|
||||||
|
0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03,
|
||||||
|
0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03,
|
||||||
|
0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02,
|
||||||
|
0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02,
|
||||||
|
0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01,
|
||||||
|
0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 5120,
|
||||||
|
.max = 65535,
|
||||||
|
.coef = {
|
||||||
|
0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06,
|
||||||
|
0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
|
||||||
|
0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05,
|
||||||
|
0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04,
|
||||||
|
0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04,
|
||||||
|
0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04,
|
||||||
|
0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03,
|
||||||
|
0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_filter_v_spec - Vertical filter specification
|
||||||
|
*
|
||||||
|
* @min: min scale factor for this filter (6.10 fixed point)
|
||||||
|
* @max: max scale factor for this filter (6.10 fixed point)
|
||||||
|
* coef: filter coefficients
|
||||||
|
*/
|
||||||
|
struct bdisp_filter_v_spec {
|
||||||
|
const u16 min;
|
||||||
|
const u16 max;
|
||||||
|
const u8 coef[BDISP_VF_NB];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bdisp_filter_v_spec bdisp_v_spec[] = {
|
||||||
|
{
|
||||||
|
.min = 0,
|
||||||
|
.max = 1024,
|
||||||
|
.coef = {
|
||||||
|
0x00, 0x00, 0x40, 0x00, 0x00,
|
||||||
|
0x00, 0x06, 0x3d, 0xfd, 0x00,
|
||||||
|
0xfe, 0x0f, 0x38, 0xfb, 0x00,
|
||||||
|
0xfd, 0x19, 0x2f, 0xfb, 0x00,
|
||||||
|
0xfc, 0x24, 0x24, 0xfc, 0x00,
|
||||||
|
0xfb, 0x2f, 0x19, 0xfd, 0x00,
|
||||||
|
0xfb, 0x38, 0x0f, 0xfe, 0x00,
|
||||||
|
0xfd, 0x3d, 0x06, 0x00, 0x00
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1024,
|
||||||
|
.max = 1331,
|
||||||
|
.coef = {
|
||||||
|
0xfc, 0x05, 0x3e, 0x05, 0xfc,
|
||||||
|
0xf8, 0x0e, 0x3b, 0xff, 0x00,
|
||||||
|
0xf5, 0x18, 0x38, 0xf9, 0x02,
|
||||||
|
0xf4, 0x21, 0x31, 0xf5, 0x05,
|
||||||
|
0xf4, 0x2a, 0x27, 0xf4, 0x07,
|
||||||
|
0xf6, 0x30, 0x1e, 0xf4, 0x08,
|
||||||
|
0xf9, 0x35, 0x15, 0xf6, 0x07,
|
||||||
|
0xff, 0x37, 0x0b, 0xf9, 0x06
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1331,
|
||||||
|
.max = 1433,
|
||||||
|
.coef = {
|
||||||
|
0xf8, 0x0a, 0x3c, 0x0a, 0xf8,
|
||||||
|
0xf6, 0x12, 0x3b, 0x02, 0xfb,
|
||||||
|
0xf4, 0x1b, 0x35, 0xfd, 0xff,
|
||||||
|
0xf4, 0x23, 0x30, 0xf8, 0x01,
|
||||||
|
0xf6, 0x29, 0x27, 0xf6, 0x04,
|
||||||
|
0xf9, 0x2e, 0x1e, 0xf5, 0x06,
|
||||||
|
0xfd, 0x31, 0x16, 0xf6, 0x06,
|
||||||
|
0x02, 0x32, 0x0d, 0xf8, 0x07
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1433,
|
||||||
|
.max = 1536,
|
||||||
|
.coef = {
|
||||||
|
0xf6, 0x0e, 0x38, 0x0e, 0xf6,
|
||||||
|
0xf5, 0x15, 0x38, 0x06, 0xf8,
|
||||||
|
0xf5, 0x1d, 0x33, 0x00, 0xfb,
|
||||||
|
0xf6, 0x23, 0x2d, 0xfc, 0xfe,
|
||||||
|
0xf9, 0x28, 0x26, 0xf9, 0x00,
|
||||||
|
0xfc, 0x2c, 0x1e, 0xf7, 0x03,
|
||||||
|
0x00, 0x2e, 0x18, 0xf6, 0x04,
|
||||||
|
0x05, 0x2e, 0x11, 0xf7, 0x05
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 1536,
|
||||||
|
.max = 2048,
|
||||||
|
.coef = {
|
||||||
|
0xfb, 0x13, 0x24, 0x13, 0xfb,
|
||||||
|
0xfd, 0x17, 0x23, 0x0f, 0xfa,
|
||||||
|
0xff, 0x1a, 0x23, 0x0b, 0xf9,
|
||||||
|
0x01, 0x1d, 0x22, 0x07, 0xf9,
|
||||||
|
0x04, 0x20, 0x1f, 0x04, 0xf9,
|
||||||
|
0x07, 0x22, 0x1c, 0x01, 0xfa,
|
||||||
|
0x0b, 0x24, 0x17, 0xff, 0xfb,
|
||||||
|
0x0f, 0x24, 0x14, 0xfd, 0xfc
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 2048,
|
||||||
|
.max = 3072,
|
||||||
|
.coef = {
|
||||||
|
0x05, 0x10, 0x16, 0x10, 0x05,
|
||||||
|
0x06, 0x11, 0x16, 0x0f, 0x04,
|
||||||
|
0x08, 0x13, 0x15, 0x0e, 0x02,
|
||||||
|
0x09, 0x14, 0x16, 0x0c, 0x01,
|
||||||
|
0x0b, 0x15, 0x15, 0x0b, 0x00,
|
||||||
|
0x0d, 0x16, 0x13, 0x0a, 0x00,
|
||||||
|
0x0f, 0x17, 0x13, 0x08, 0xff,
|
||||||
|
0x11, 0x18, 0x12, 0x07, 0xfe
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 3072,
|
||||||
|
.max = 4096,
|
||||||
|
.coef = {
|
||||||
|
0x09, 0x0f, 0x10, 0x0f, 0x09,
|
||||||
|
0x09, 0x0f, 0x12, 0x0e, 0x08,
|
||||||
|
0x0a, 0x10, 0x11, 0x0e, 0x07,
|
||||||
|
0x0b, 0x11, 0x11, 0x0d, 0x06,
|
||||||
|
0x0c, 0x11, 0x12, 0x0c, 0x05,
|
||||||
|
0x0d, 0x12, 0x11, 0x0c, 0x04,
|
||||||
|
0x0e, 0x12, 0x11, 0x0b, 0x04,
|
||||||
|
0x0f, 0x13, 0x11, 0x0a, 0x03
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 4096,
|
||||||
|
.max = 5120,
|
||||||
|
.coef = {
|
||||||
|
0x0a, 0x0e, 0x10, 0x0e, 0x0a,
|
||||||
|
0x0b, 0x0e, 0x0f, 0x0e, 0x0a,
|
||||||
|
0x0b, 0x0f, 0x10, 0x0d, 0x09,
|
||||||
|
0x0c, 0x0f, 0x10, 0x0d, 0x08,
|
||||||
|
0x0d, 0x0f, 0x0f, 0x0d, 0x08,
|
||||||
|
0x0d, 0x10, 0x10, 0x0c, 0x07,
|
||||||
|
0x0e, 0x10, 0x0f, 0x0c, 0x07,
|
||||||
|
0x0f, 0x10, 0x10, 0x0b, 0x06
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.min = 5120,
|
||||||
|
.max = 65535,
|
||||||
|
.coef = {
|
||||||
|
0x0b, 0x0e, 0x0e, 0x0e, 0x0b,
|
||||||
|
0x0b, 0x0e, 0x0f, 0x0d, 0x0b,
|
||||||
|
0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
|
||||||
|
0x0c, 0x0e, 0x0f, 0x0d, 0x0a,
|
||||||
|
0x0d, 0x0f, 0x0e, 0x0d, 0x09,
|
||||||
|
0x0d, 0x0f, 0x0f, 0x0c, 0x09,
|
||||||
|
0x0e, 0x0f, 0x0e, 0x0c, 0x09,
|
||||||
|
0x0e, 0x0f, 0x0f, 0x0c, 0x08
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NB_H_FILTER ARRAY_SIZE(bdisp_h_spec)
|
||||||
|
#define NB_V_FILTER ARRAY_SIZE(bdisp_v_spec)
|
||||||
|
|
||||||
|
/* RGB YUV 601 standard conversion */
|
||||||
|
static const u32 bdisp_rgb_to_yuv[] = {
|
||||||
|
0x0e1e8bee, 0x08420419, 0xfb5ed471, 0x08004080,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u32 bdisp_yuv_to_rgb[] = {
|
||||||
|
0x3324a800, 0xe604ab9c, 0x0004a957, 0x32121eeb,
|
||||||
|
};
|
783
drivers/media/platform/sti/bdisp/bdisp-hw.c
Normal file
783
drivers/media/platform/sti/bdisp/bdisp-hw.c
Normal file
|
@ -0,0 +1,783 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) STMicroelectronics SA 2014
|
||||||
|
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
|
||||||
|
* License terms: GNU General Public License (GPL), version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include "bdisp.h"
|
||||||
|
#include "bdisp-filter.h"
|
||||||
|
#include "bdisp-reg.h"
|
||||||
|
|
||||||
|
/* Max width of the source frame in a single node */
|
||||||
|
#define MAX_SRC_WIDTH 2048
|
||||||
|
|
||||||
|
/* Reset & boot poll config */
|
||||||
|
#define POLL_RST_MAX 50
|
||||||
|
#define POLL_RST_DELAY_MS 20
|
||||||
|
|
||||||
|
enum bdisp_target_plan {
|
||||||
|
BDISP_RGB,
|
||||||
|
BDISP_Y,
|
||||||
|
BDISP_CBCR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bdisp_op_cfg {
|
||||||
|
bool cconv; /* RGB - YUV conversion */
|
||||||
|
bool hflip; /* Horizontal flip */
|
||||||
|
bool vflip; /* Vertical flip */
|
||||||
|
bool wide; /* Wide (>MAX_SRC_WIDTH) */
|
||||||
|
bool scale; /* Scale */
|
||||||
|
u16 h_inc; /* Horizontal increment in 6.10 format */
|
||||||
|
u16 v_inc; /* Vertical increment in 6.10 format */
|
||||||
|
bool src_interlaced; /* is the src an interlaced buffer */
|
||||||
|
u8 src_nbp; /* nb of planes of the src */
|
||||||
|
bool src_yuv; /* is the src a YUV color format */
|
||||||
|
bool src_420; /* is the src 4:2:0 chroma subsampled */
|
||||||
|
u8 dst_nbp; /* nb of planes of the dst */
|
||||||
|
bool dst_yuv; /* is the dst a YUV color format */
|
||||||
|
bool dst_420; /* is the dst 4:2:0 chroma subsampled */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bdisp_filter_addr {
|
||||||
|
u16 min; /* Filter min scale factor (6.10 fixed point) */
|
||||||
|
u16 max; /* Filter max scale factor (6.10 fixed point) */
|
||||||
|
void *virt; /* Virtual address for filter table */
|
||||||
|
dma_addr_t paddr; /* Physical address for filter table */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bdisp_filter_addr bdisp_h_filter[NB_H_FILTER];
|
||||||
|
static struct bdisp_filter_addr bdisp_v_filter[NB_V_FILTER];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_reset
|
||||||
|
* @bdisp: bdisp entity
|
||||||
|
*
|
||||||
|
* Resets HW
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success.
|
||||||
|
*/
|
||||||
|
int bdisp_hw_reset(struct bdisp_dev *bdisp)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
dev_dbg(bdisp->dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
/* Mask Interrupt */
|
||||||
|
writel(0, bdisp->regs + BLT_ITM0);
|
||||||
|
|
||||||
|
/* Reset */
|
||||||
|
writel(readl(bdisp->regs + BLT_CTL) | BLT_CTL_RESET,
|
||||||
|
bdisp->regs + BLT_CTL);
|
||||||
|
writel(0, bdisp->regs + BLT_CTL);
|
||||||
|
|
||||||
|
/* Wait for reset done */
|
||||||
|
for (i = 0; i < POLL_RST_MAX; i++) {
|
||||||
|
if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
|
||||||
|
break;
|
||||||
|
msleep(POLL_RST_DELAY_MS);
|
||||||
|
}
|
||||||
|
if (i == POLL_RST_MAX)
|
||||||
|
dev_err(bdisp->dev, "Reset timeout\n");
|
||||||
|
|
||||||
|
return (i == POLL_RST_MAX) ? -EAGAIN : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_and_clear_irq
|
||||||
|
* @bdisp: bdisp entity
|
||||||
|
*
|
||||||
|
* Read then reset interrupt status
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 if expected interrupt was raised.
|
||||||
|
*/
|
||||||
|
int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp)
|
||||||
|
{
|
||||||
|
u32 its;
|
||||||
|
|
||||||
|
its = readl(bdisp->regs + BLT_ITS);
|
||||||
|
|
||||||
|
/* Check for the only expected IT: LastNode of AQ1 */
|
||||||
|
if (!(its & BLT_ITS_AQ1_LNA)) {
|
||||||
|
dev_dbg(bdisp->dev, "Unexpected IT status: 0x%08X\n", its);
|
||||||
|
writel(its, bdisp->regs + BLT_ITS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear and mask */
|
||||||
|
writel(its, bdisp->regs + BLT_ITS);
|
||||||
|
writel(0, bdisp->regs + BLT_ITM0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_free_nodes
|
||||||
|
* @ctx: bdisp context
|
||||||
|
*
|
||||||
|
* Free node memory
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* None
|
||||||
|
*/
|
||||||
|
void bdisp_hw_free_nodes(struct bdisp_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (ctx && ctx->node[0]) {
|
||||||
|
DEFINE_DMA_ATTRS(attrs);
|
||||||
|
|
||||||
|
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||||
|
dma_free_attrs(ctx->bdisp_dev->dev,
|
||||||
|
sizeof(struct bdisp_node) * MAX_NB_NODE,
|
||||||
|
ctx->node[0], ctx->node_paddr[0], &attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_alloc_nodes
|
||||||
|
* @ctx: bdisp context
|
||||||
|
*
|
||||||
|
* Allocate dma memory for nodes
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct device *dev = ctx->bdisp_dev->dev;
|
||||||
|
unsigned int i, node_size = sizeof(struct bdisp_node);
|
||||||
|
void *base;
|
||||||
|
dma_addr_t paddr;
|
||||||
|
DEFINE_DMA_ATTRS(attrs);
|
||||||
|
|
||||||
|
/* Allocate all the nodes within a single memory page */
|
||||||
|
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||||
|
base = dma_alloc_attrs(dev, node_size * MAX_NB_NODE, &paddr,
|
||||||
|
GFP_KERNEL | GFP_DMA, &attrs);
|
||||||
|
if (!base) {
|
||||||
|
dev_err(dev, "%s no mem\n", __func__);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(base, 0, node_size * MAX_NB_NODE);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_NB_NODE; i++) {
|
||||||
|
ctx->node[i] = base;
|
||||||
|
ctx->node_paddr[i] = paddr;
|
||||||
|
dev_dbg(dev, "node[%d]=0x%p (paddr=%pad)\n", i, ctx->node[i],
|
||||||
|
&paddr);
|
||||||
|
base += node_size;
|
||||||
|
paddr += node_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_free_filters
|
||||||
|
* @dev: device
|
||||||
|
*
|
||||||
|
* Free filters memory
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* None
|
||||||
|
*/
|
||||||
|
void bdisp_hw_free_filters(struct device *dev)
|
||||||
|
{
|
||||||
|
int size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
|
||||||
|
|
||||||
|
if (bdisp_h_filter[0].virt) {
|
||||||
|
DEFINE_DMA_ATTRS(attrs);
|
||||||
|
|
||||||
|
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||||
|
dma_free_attrs(dev, size, bdisp_h_filter[0].virt,
|
||||||
|
bdisp_h_filter[0].paddr, &attrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_alloc_filters
|
||||||
|
* @dev: device
|
||||||
|
*
|
||||||
|
* Allocate dma memory for filters
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
int bdisp_hw_alloc_filters(struct device *dev)
|
||||||
|
{
|
||||||
|
unsigned int i, size;
|
||||||
|
void *base;
|
||||||
|
dma_addr_t paddr;
|
||||||
|
DEFINE_DMA_ATTRS(attrs);
|
||||||
|
|
||||||
|
/* Allocate all the filters within a single memory page */
|
||||||
|
size = (BDISP_HF_NB * NB_H_FILTER) + (BDISP_VF_NB * NB_V_FILTER);
|
||||||
|
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||||
|
base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs);
|
||||||
|
if (!base)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Setup filter addresses */
|
||||||
|
for (i = 0; i < NB_H_FILTER; i++) {
|
||||||
|
bdisp_h_filter[i].min = bdisp_h_spec[i].min;
|
||||||
|
bdisp_h_filter[i].max = bdisp_h_spec[i].max;
|
||||||
|
memcpy(base, bdisp_h_spec[i].coef, BDISP_HF_NB);
|
||||||
|
bdisp_h_filter[i].virt = base;
|
||||||
|
bdisp_h_filter[i].paddr = paddr;
|
||||||
|
base += BDISP_HF_NB;
|
||||||
|
paddr += BDISP_HF_NB;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NB_V_FILTER; i++) {
|
||||||
|
bdisp_v_filter[i].min = bdisp_v_spec[i].min;
|
||||||
|
bdisp_v_filter[i].max = bdisp_v_spec[i].max;
|
||||||
|
memcpy(base, bdisp_v_spec[i].coef, BDISP_VF_NB);
|
||||||
|
bdisp_v_filter[i].virt = base;
|
||||||
|
bdisp_v_filter[i].paddr = paddr;
|
||||||
|
base += BDISP_VF_NB;
|
||||||
|
paddr += BDISP_VF_NB;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_hf_addr
|
||||||
|
* @inc: resize increment
|
||||||
|
*
|
||||||
|
* Find the horizontal filter table that fits the resize increment
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* table physical address
|
||||||
|
*/
|
||||||
|
static dma_addr_t bdisp_hw_get_hf_addr(u16 inc)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = NB_H_FILTER - 1; i > 0; i--)
|
||||||
|
if ((bdisp_h_filter[i].min < inc) &&
|
||||||
|
(inc <= bdisp_h_filter[i].max))
|
||||||
|
break;
|
||||||
|
|
||||||
|
return bdisp_h_filter[i].paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_vf_addr
|
||||||
|
* @inc: resize increment
|
||||||
|
*
|
||||||
|
* Find the vertical filter table that fits the resize increment
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* table physical address
|
||||||
|
*/
|
||||||
|
static dma_addr_t bdisp_hw_get_vf_addr(u16 inc)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = NB_V_FILTER - 1; i > 0; i--)
|
||||||
|
if ((bdisp_v_filter[i].min < inc) &&
|
||||||
|
(inc <= bdisp_v_filter[i].max))
|
||||||
|
break;
|
||||||
|
|
||||||
|
return bdisp_v_filter[i].paddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_inc
|
||||||
|
* @from: input size
|
||||||
|
* @to: output size
|
||||||
|
* @inc: resize increment in 6.10 format
|
||||||
|
*
|
||||||
|
* Computes the increment (inverse of scale) in 6.10 format
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
static int bdisp_hw_get_inc(u32 from, u32 to, u16 *inc)
|
||||||
|
{
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
if (!to)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (to == from) {
|
||||||
|
*inc = 1 << 10;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = (from << 10) / to;
|
||||||
|
if ((tmp > 0xFFFF) || (!tmp))
|
||||||
|
/* overflow (downscale x 63) or too small (upscale x 1024) */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*inc = (u16)tmp;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_hv_inc
|
||||||
|
* @ctx: device context
|
||||||
|
* @h_inc: horizontal increment
|
||||||
|
* @v_inc: vertical increment
|
||||||
|
*
|
||||||
|
* Computes the horizontal & vertical increments (inverse of scale)
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc)
|
||||||
|
{
|
||||||
|
u32 src_w, src_h, dst_w, dst_h;
|
||||||
|
|
||||||
|
src_w = ctx->src.crop.width;
|
||||||
|
src_h = ctx->src.crop.height;
|
||||||
|
dst_w = ctx->dst.width;
|
||||||
|
dst_h = ctx->dst.height;
|
||||||
|
|
||||||
|
if (bdisp_hw_get_inc(src_w, dst_w, h_inc) ||
|
||||||
|
bdisp_hw_get_inc(src_h, dst_h, v_inc)) {
|
||||||
|
dev_err(ctx->bdisp_dev->dev,
|
||||||
|
"scale factors failed (%dx%d)->(%dx%d)\n",
|
||||||
|
src_w, src_h, dst_w, dst_h);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_get_op_cfg
|
||||||
|
* @ctx: device context
|
||||||
|
* @c: operation configuration
|
||||||
|
*
|
||||||
|
* Check which blitter operations are expected and sets the scaling increments
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
static int bdisp_hw_get_op_cfg(struct bdisp_ctx *ctx, struct bdisp_op_cfg *c)
|
||||||
|
{
|
||||||
|
struct device *dev = ctx->bdisp_dev->dev;
|
||||||
|
struct bdisp_frame *src = &ctx->src;
|
||||||
|
struct bdisp_frame *dst = &ctx->dst;
|
||||||
|
|
||||||
|
if (src->width > MAX_SRC_WIDTH * MAX_VERTICAL_STRIDES) {
|
||||||
|
dev_err(dev, "Image width out of HW caps\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->wide = src->width > MAX_SRC_WIDTH;
|
||||||
|
|
||||||
|
c->hflip = ctx->hflip;
|
||||||
|
c->vflip = ctx->vflip;
|
||||||
|
|
||||||
|
c->src_interlaced = (src->field == V4L2_FIELD_INTERLACED);
|
||||||
|
|
||||||
|
c->src_nbp = src->fmt->nb_planes;
|
||||||
|
c->src_yuv = (src->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
|
||||||
|
(src->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
|
||||||
|
c->src_420 = c->src_yuv;
|
||||||
|
|
||||||
|
c->dst_nbp = dst->fmt->nb_planes;
|
||||||
|
c->dst_yuv = (dst->fmt->pixelformat == V4L2_PIX_FMT_NV12) ||
|
||||||
|
(dst->fmt->pixelformat == V4L2_PIX_FMT_YUV420);
|
||||||
|
c->dst_420 = c->dst_yuv;
|
||||||
|
|
||||||
|
c->cconv = (c->src_yuv != c->dst_yuv);
|
||||||
|
|
||||||
|
if (bdisp_hw_get_hv_inc(ctx, &c->h_inc, &c->v_inc)) {
|
||||||
|
dev_err(dev, "Scale factor out of HW caps\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deinterlacing adjustment : stretch a field to a frame */
|
||||||
|
if (c->src_interlaced)
|
||||||
|
c->v_inc /= 2;
|
||||||
|
|
||||||
|
if ((c->h_inc != (1 << 10)) || (c->v_inc != (1 << 10)))
|
||||||
|
c->scale = true;
|
||||||
|
else
|
||||||
|
c->scale = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_color_format
|
||||||
|
* @pixelformat: v4l2 pixel format
|
||||||
|
*
|
||||||
|
* v4l2 to bdisp pixel format convert
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* bdisp pixel format
|
||||||
|
*/
|
||||||
|
static u32 bdisp_hw_color_format(u32 pixelformat)
|
||||||
|
{
|
||||||
|
u32 ret;
|
||||||
|
|
||||||
|
switch (pixelformat) {
|
||||||
|
case V4L2_PIX_FMT_YUV420:
|
||||||
|
ret = (BDISP_YUV_3B << BLT_TTY_COL_SHIFT);
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_NV12:
|
||||||
|
ret = (BDISP_NV12 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_RGB565:
|
||||||
|
ret = (BDISP_RGB565 << BLT_TTY_COL_SHIFT);
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_XBGR32: /* This V4L format actually refers to xRGB */
|
||||||
|
ret = (BDISP_XRGB8888 << BLT_TTY_COL_SHIFT);
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_RGB24: /* RGB888 format */
|
||||||
|
ret = (BDISP_RGB888 << BLT_TTY_COL_SHIFT) | BLT_TTY_BIG_END;
|
||||||
|
break;
|
||||||
|
case V4L2_PIX_FMT_ABGR32: /* This V4L format actually refers to ARGB */
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = (BDISP_ARGB8888 << BLT_TTY_COL_SHIFT) | BLT_TTY_ALPHA_R;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_build_node
|
||||||
|
* @ctx: device context
|
||||||
|
* @cfg: operation configuration
|
||||||
|
* @node: node to be set
|
||||||
|
* @t_plan: whether the node refers to a RGB/Y or a CbCr plane
|
||||||
|
* @src_x_offset: x offset in the source image
|
||||||
|
*
|
||||||
|
* Build a node
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* None
|
||||||
|
*/
|
||||||
|
static void bdisp_hw_build_node(struct bdisp_ctx *ctx,
|
||||||
|
struct bdisp_op_cfg *cfg,
|
||||||
|
struct bdisp_node *node,
|
||||||
|
enum bdisp_target_plan t_plan, int src_x_offset)
|
||||||
|
{
|
||||||
|
struct bdisp_frame *src = &ctx->src;
|
||||||
|
struct bdisp_frame *dst = &ctx->dst;
|
||||||
|
u16 h_inc, v_inc, yh_inc, yv_inc;
|
||||||
|
struct v4l2_rect src_rect = src->crop;
|
||||||
|
struct v4l2_rect dst_rect = dst->crop;
|
||||||
|
int dst_x_offset;
|
||||||
|
s32 dst_width = dst->crop.width;
|
||||||
|
u32 src_fmt, dst_fmt;
|
||||||
|
const u32 *ivmx;
|
||||||
|
|
||||||
|
dev_dbg(ctx->bdisp_dev->dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
memset(node, 0, sizeof(*node));
|
||||||
|
|
||||||
|
/* Adjust src and dst areas wrt src_x_offset */
|
||||||
|
src_rect.left += src_x_offset;
|
||||||
|
src_rect.width -= src_x_offset;
|
||||||
|
src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width);
|
||||||
|
|
||||||
|
dst_x_offset = (src_x_offset * dst->width) / ctx->src.crop.width;
|
||||||
|
dst_rect.left += dst_x_offset;
|
||||||
|
dst_rect.width = (src_rect.width * dst->width) / ctx->src.crop.width;
|
||||||
|
|
||||||
|
/* General */
|
||||||
|
src_fmt = src->fmt->pixelformat;
|
||||||
|
dst_fmt = dst->fmt->pixelformat;
|
||||||
|
|
||||||
|
node->nip = 0;
|
||||||
|
node->cic = BLT_CIC_ALL_GRP;
|
||||||
|
node->ack = BLT_ACK_BYPASS_S2S3;
|
||||||
|
|
||||||
|
switch (cfg->src_nbp) {
|
||||||
|
case 1:
|
||||||
|
/* Src2 = RGB / Src1 = Src3 = off */
|
||||||
|
node->ins = BLT_INS_S1_OFF | BLT_INS_S2_MEM | BLT_INS_S3_OFF;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* Src3 = Y
|
||||||
|
* Src2 = CbCr or ColorFill if writing the Y plane
|
||||||
|
* Src1 = off */
|
||||||
|
node->ins = BLT_INS_S1_OFF | BLT_INS_S3_MEM;
|
||||||
|
if (t_plan == BDISP_Y)
|
||||||
|
node->ins |= BLT_INS_S2_CF;
|
||||||
|
else
|
||||||
|
node->ins |= BLT_INS_S2_MEM;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
/* Src3 = Y
|
||||||
|
* Src2 = Cb or ColorFill if writing the Y plane
|
||||||
|
* Src1 = Cr or ColorFill if writing the Y plane */
|
||||||
|
node->ins = BLT_INS_S3_MEM;
|
||||||
|
if (t_plan == BDISP_Y)
|
||||||
|
node->ins |= BLT_INS_S2_CF | BLT_INS_S1_CF;
|
||||||
|
else
|
||||||
|
node->ins |= BLT_INS_S2_MEM | BLT_INS_S1_MEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Color convert */
|
||||||
|
node->ins |= cfg->cconv ? BLT_INS_IVMX : 0;
|
||||||
|
/* Scale needed if scaling OR 4:2:0 up/downsampling */
|
||||||
|
node->ins |= (cfg->scale || cfg->src_420 || cfg->dst_420) ?
|
||||||
|
BLT_INS_SCALE : 0;
|
||||||
|
|
||||||
|
/* Target */
|
||||||
|
node->tba = (t_plan == BDISP_CBCR) ? dst->paddr[1] : dst->paddr[0];
|
||||||
|
|
||||||
|
node->tty = dst->bytesperline;
|
||||||
|
node->tty |= bdisp_hw_color_format(dst_fmt);
|
||||||
|
node->tty |= BLT_TTY_DITHER;
|
||||||
|
node->tty |= (t_plan == BDISP_CBCR) ? BLT_TTY_CHROMA : 0;
|
||||||
|
node->tty |= cfg->hflip ? BLT_TTY_HSO : 0;
|
||||||
|
node->tty |= cfg->vflip ? BLT_TTY_VSO : 0;
|
||||||
|
|
||||||
|
if (cfg->dst_420 && (t_plan == BDISP_CBCR)) {
|
||||||
|
/* 420 chroma downsampling */
|
||||||
|
dst_rect.height /= 2;
|
||||||
|
dst_rect.width /= 2;
|
||||||
|
dst_rect.left /= 2;
|
||||||
|
dst_rect.top /= 2;
|
||||||
|
dst_x_offset /= 2;
|
||||||
|
dst_width /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->txy = cfg->vflip ? (dst_rect.height - 1) : dst_rect.top;
|
||||||
|
node->txy <<= 16;
|
||||||
|
node->txy |= cfg->hflip ? (dst_width - dst_x_offset - 1) :
|
||||||
|
dst_rect.left;
|
||||||
|
|
||||||
|
node->tsz = dst_rect.height << 16 | dst_rect.width;
|
||||||
|
|
||||||
|
if (cfg->src_interlaced) {
|
||||||
|
/* handle only the top field which is half height of a frame */
|
||||||
|
src_rect.top /= 2;
|
||||||
|
src_rect.height /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->src_nbp == 1) {
|
||||||
|
/* Src 2 : RGB */
|
||||||
|
node->s2ba = src->paddr[0];
|
||||||
|
|
||||||
|
node->s2ty = src->bytesperline;
|
||||||
|
if (cfg->src_interlaced)
|
||||||
|
node->s2ty *= 2;
|
||||||
|
|
||||||
|
node->s2ty |= bdisp_hw_color_format(src_fmt);
|
||||||
|
|
||||||
|
node->s2xy = src_rect.top << 16 | src_rect.left;
|
||||||
|
node->s2sz = src_rect.height << 16 | src_rect.width;
|
||||||
|
} else {
|
||||||
|
/* Src 2 : Cb or CbCr */
|
||||||
|
if (cfg->src_420) {
|
||||||
|
/* 420 chroma upsampling */
|
||||||
|
src_rect.top /= 2;
|
||||||
|
src_rect.left /= 2;
|
||||||
|
src_rect.width /= 2;
|
||||||
|
src_rect.height /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->s2ba = src->paddr[1];
|
||||||
|
|
||||||
|
node->s2ty = src->bytesperline;
|
||||||
|
if (cfg->src_nbp == 3)
|
||||||
|
node->s2ty /= 2;
|
||||||
|
if (cfg->src_interlaced)
|
||||||
|
node->s2ty *= 2;
|
||||||
|
|
||||||
|
node->s2ty |= bdisp_hw_color_format(src_fmt);
|
||||||
|
|
||||||
|
node->s2xy = src_rect.top << 16 | src_rect.left;
|
||||||
|
node->s2sz = src_rect.height << 16 | src_rect.width;
|
||||||
|
|
||||||
|
if (cfg->src_nbp == 3) {
|
||||||
|
/* Src 1 : Cr */
|
||||||
|
node->s1ba = src->paddr[2];
|
||||||
|
|
||||||
|
node->s1ty = node->s2ty;
|
||||||
|
node->s1xy = node->s2xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Src 3 : Y */
|
||||||
|
node->s3ba = src->paddr[0];
|
||||||
|
|
||||||
|
node->s3ty = src->bytesperline;
|
||||||
|
if (cfg->src_interlaced)
|
||||||
|
node->s3ty *= 2;
|
||||||
|
node->s3ty |= bdisp_hw_color_format(src_fmt);
|
||||||
|
|
||||||
|
if ((t_plan != BDISP_CBCR) && cfg->src_420) {
|
||||||
|
/* No chroma upsampling for output RGB / Y plane */
|
||||||
|
node->s3xy = node->s2xy * 2;
|
||||||
|
node->s3sz = node->s2sz * 2;
|
||||||
|
} else {
|
||||||
|
/* No need to read Y (Src3) when writing Chroma */
|
||||||
|
node->s3ty |= BLT_S3TY_BLANK_ACC;
|
||||||
|
node->s3xy = node->s2xy;
|
||||||
|
node->s3sz = node->s2sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize (scale OR 4:2:0: chroma up/downsampling) */
|
||||||
|
if (node->ins & BLT_INS_SCALE) {
|
||||||
|
/* no need to compute Y when writing CbCr from RGB input */
|
||||||
|
bool skip_y = (t_plan == BDISP_CBCR) && !cfg->src_yuv;
|
||||||
|
|
||||||
|
/* FCTL */
|
||||||
|
if (cfg->scale) {
|
||||||
|
node->fctl = BLT_FCTL_HV_SCALE;
|
||||||
|
if (!skip_y)
|
||||||
|
node->fctl |= BLT_FCTL_Y_HV_SCALE;
|
||||||
|
} else {
|
||||||
|
node->fctl = BLT_FCTL_HV_SAMPLE;
|
||||||
|
if (!skip_y)
|
||||||
|
node->fctl |= BLT_FCTL_Y_HV_SAMPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RSF - Chroma may need to be up/downsampled */
|
||||||
|
h_inc = cfg->h_inc;
|
||||||
|
v_inc = cfg->v_inc;
|
||||||
|
if (!cfg->src_420 && cfg->dst_420 && (t_plan == BDISP_CBCR)) {
|
||||||
|
/* RGB to 4:2:0 for Chroma: downsample */
|
||||||
|
h_inc *= 2;
|
||||||
|
v_inc *= 2;
|
||||||
|
} else if (cfg->src_420 && !cfg->dst_420) {
|
||||||
|
/* 4:2:0: to RGB: upsample*/
|
||||||
|
h_inc /= 2;
|
||||||
|
v_inc /= 2;
|
||||||
|
}
|
||||||
|
node->rsf = v_inc << 16 | h_inc;
|
||||||
|
|
||||||
|
/* RZI */
|
||||||
|
node->rzi = BLT_RZI_DEFAULT;
|
||||||
|
|
||||||
|
/* Filter table physical addr */
|
||||||
|
node->hfp = bdisp_hw_get_hf_addr(h_inc);
|
||||||
|
node->vfp = bdisp_hw_get_vf_addr(v_inc);
|
||||||
|
|
||||||
|
/* Y version */
|
||||||
|
if (!skip_y) {
|
||||||
|
yh_inc = cfg->h_inc;
|
||||||
|
yv_inc = cfg->v_inc;
|
||||||
|
|
||||||
|
node->y_rsf = yv_inc << 16 | yh_inc;
|
||||||
|
node->y_rzi = BLT_RZI_DEFAULT;
|
||||||
|
node->y_hfp = bdisp_hw_get_hf_addr(yh_inc);
|
||||||
|
node->y_vfp = bdisp_hw_get_vf_addr(yv_inc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Versatile matrix for RGB / YUV conversion */
|
||||||
|
if (cfg->cconv) {
|
||||||
|
ivmx = cfg->src_yuv ? bdisp_yuv_to_rgb : bdisp_rgb_to_yuv;
|
||||||
|
|
||||||
|
node->ivmx0 = ivmx[0];
|
||||||
|
node->ivmx1 = ivmx[1];
|
||||||
|
node->ivmx2 = ivmx[2];
|
||||||
|
node->ivmx3 = ivmx[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_build_all_nodes
|
||||||
|
* @ctx: device context
|
||||||
|
*
|
||||||
|
* Build all the nodes for the blitter operation
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
static int bdisp_hw_build_all_nodes(struct bdisp_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct bdisp_op_cfg cfg;
|
||||||
|
unsigned int i, nid = 0;
|
||||||
|
int src_x_offset = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_NB_NODE; i++)
|
||||||
|
if (!ctx->node[i]) {
|
||||||
|
dev_err(ctx->bdisp_dev->dev, "node %d is null\n", i);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get configuration (scale, flip, ...) */
|
||||||
|
if (bdisp_hw_get_op_cfg(ctx, &cfg))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Split source in vertical strides (HW constraint) */
|
||||||
|
for (i = 0; i < MAX_VERTICAL_STRIDES; i++) {
|
||||||
|
/* Build RGB/Y node and link it to the previous node */
|
||||||
|
bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
|
||||||
|
cfg.dst_nbp == 1 ? BDISP_RGB : BDISP_Y,
|
||||||
|
src_x_offset);
|
||||||
|
if (nid)
|
||||||
|
ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
|
||||||
|
nid++;
|
||||||
|
|
||||||
|
/* Build additional Cb(Cr) node, link it to the previous one */
|
||||||
|
if (cfg.dst_nbp > 1) {
|
||||||
|
bdisp_hw_build_node(ctx, &cfg, ctx->node[nid],
|
||||||
|
BDISP_CBCR, src_x_offset);
|
||||||
|
ctx->node[nid - 1]->nip = ctx->node_paddr[nid];
|
||||||
|
nid++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next stride until full width covered */
|
||||||
|
src_x_offset += MAX_SRC_WIDTH;
|
||||||
|
if (src_x_offset >= ctx->src.crop.width)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark last node as the last */
|
||||||
|
ctx->node[nid - 1]->nip = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bdisp_hw_update
|
||||||
|
* @ctx: device context
|
||||||
|
*
|
||||||
|
* Send the request to the HW
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 on success
|
||||||
|
*/
|
||||||
|
int bdisp_hw_update(struct bdisp_ctx *ctx)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct bdisp_dev *bdisp = ctx->bdisp_dev;
|
||||||
|
struct device *dev = bdisp->dev;
|
||||||
|
unsigned int node_id;
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
/* build nodes */
|
||||||
|
ret = bdisp_hw_build_all_nodes(ctx);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "cannot build nodes (%d)\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure interrupt to 'Last Node Reached for AQ1' */
|
||||||
|
writel(BLT_AQ1_CTL_CFG, bdisp->regs + BLT_AQ1_CTL);
|
||||||
|
writel(BLT_ITS_AQ1_LNA, bdisp->regs + BLT_ITM0);
|
||||||
|
|
||||||
|
/* Write first node addr */
|
||||||
|
writel(ctx->node_paddr[0], bdisp->regs + BLT_AQ1_IP);
|
||||||
|
|
||||||
|
/* Find and write last node addr : this starts the HW processing */
|
||||||
|
for (node_id = 0; node_id < MAX_NB_NODE - 1; node_id++) {
|
||||||
|
if (!ctx->node[node_id]->nip)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
writel(ctx->node_paddr[node_id], bdisp->regs + BLT_AQ1_LNA);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
235
drivers/media/platform/sti/bdisp/bdisp-reg.h
Normal file
235
drivers/media/platform/sti/bdisp/bdisp-reg.h
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) STMicroelectronics SA 2014
|
||||||
|
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
|
||||||
|
* License terms: GNU General Public License (GPL), version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct bdisp_node {
|
||||||
|
/* 0 - General */
|
||||||
|
u32 nip;
|
||||||
|
u32 cic;
|
||||||
|
u32 ins;
|
||||||
|
u32 ack;
|
||||||
|
/* 1 - Target */
|
||||||
|
u32 tba;
|
||||||
|
u32 tty;
|
||||||
|
u32 txy;
|
||||||
|
u32 tsz;
|
||||||
|
/* 2 - Color Fill */
|
||||||
|
u32 s1cf;
|
||||||
|
u32 s2cf;
|
||||||
|
/* 3 - Source 1 */
|
||||||
|
u32 s1ba;
|
||||||
|
u32 s1ty;
|
||||||
|
u32 s1xy;
|
||||||
|
u32 s1sz_tsz;
|
||||||
|
/* 4 - Source 2 */
|
||||||
|
u32 s2ba;
|
||||||
|
u32 s2ty;
|
||||||
|
u32 s2xy;
|
||||||
|
u32 s2sz;
|
||||||
|
/* 5 - Source 3 */
|
||||||
|
u32 s3ba;
|
||||||
|
u32 s3ty;
|
||||||
|
u32 s3xy;
|
||||||
|
u32 s3sz;
|
||||||
|
/* 6 - Clipping */
|
||||||
|
u32 cwo;
|
||||||
|
u32 cws;
|
||||||
|
/* 7 - CLUT */
|
||||||
|
u32 cco;
|
||||||
|
u32 cml;
|
||||||
|
/* 8 - Filter & Mask */
|
||||||
|
u32 fctl;
|
||||||
|
u32 pmk;
|
||||||
|
/* 9 - Chroma Filter */
|
||||||
|
u32 rsf;
|
||||||
|
u32 rzi;
|
||||||
|
u32 hfp;
|
||||||
|
u32 vfp;
|
||||||
|
/* 10 - Luma Filter */
|
||||||
|
u32 y_rsf;
|
||||||
|
u32 y_rzi;
|
||||||
|
u32 y_hfp;
|
||||||
|
u32 y_vfp;
|
||||||
|
/* 11 - Flicker */
|
||||||
|
u32 ff0;
|
||||||
|
u32 ff1;
|
||||||
|
u32 ff2;
|
||||||
|
u32 ff3;
|
||||||
|
/* 12 - Color Key */
|
||||||
|
u32 key1;
|
||||||
|
u32 key2;
|
||||||
|
/* 14 - Static Address & User */
|
||||||
|
u32 sar;
|
||||||
|
u32 usr;
|
||||||
|
/* 15 - Input Versatile Matrix */
|
||||||
|
u32 ivmx0;
|
||||||
|
u32 ivmx1;
|
||||||
|
u32 ivmx2;
|
||||||
|
u32 ivmx3;
|
||||||
|
/* 16 - Output Versatile Matrix */
|
||||||
|
u32 ovmx0;
|
||||||
|
u32 ovmx1;
|
||||||
|
u32 ovmx2;
|
||||||
|
u32 ovmx3;
|
||||||
|
/* 17 - Pace */
|
||||||
|
u32 pace;
|
||||||
|
/* 18 - VC1R & DEI */
|
||||||
|
u32 vc1r;
|
||||||
|
u32 dei;
|
||||||
|
/* 19 - Gradient Fill */
|
||||||
|
u32 hgf;
|
||||||
|
u32 vgf;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* HW registers : static */
|
||||||
|
#define BLT_CTL 0x0A00
|
||||||
|
#define BLT_ITS 0x0A04
|
||||||
|
#define BLT_STA1 0x0A08
|
||||||
|
#define BLT_AQ1_CTL 0x0A60
|
||||||
|
#define BLT_AQ1_IP 0x0A64
|
||||||
|
#define BLT_AQ1_LNA 0x0A68
|
||||||
|
#define BLT_AQ1_STA 0x0A6C
|
||||||
|
#define BLT_ITM0 0x0AD0
|
||||||
|
/* HW registers : plugs */
|
||||||
|
#define BLT_PLUGS1_OP2 0x0B04
|
||||||
|
#define BLT_PLUGS1_CHZ 0x0B08
|
||||||
|
#define BLT_PLUGS1_MSZ 0x0B0C
|
||||||
|
#define BLT_PLUGS1_PGZ 0x0B10
|
||||||
|
#define BLT_PLUGS2_OP2 0x0B24
|
||||||
|
#define BLT_PLUGS2_CHZ 0x0B28
|
||||||
|
#define BLT_PLUGS2_MSZ 0x0B2C
|
||||||
|
#define BLT_PLUGS2_PGZ 0x0B30
|
||||||
|
#define BLT_PLUGS3_OP2 0x0B44
|
||||||
|
#define BLT_PLUGS3_CHZ 0x0B48
|
||||||
|
#define BLT_PLUGS3_MSZ 0x0B4C
|
||||||
|
#define BLT_PLUGS3_PGZ 0x0B50
|
||||||
|
#define BLT_PLUGT_OP2 0x0B84
|
||||||
|
#define BLT_PLUGT_CHZ 0x0B88
|
||||||
|
#define BLT_PLUGT_MSZ 0x0B8C
|
||||||
|
#define BLT_PLUGT_PGZ 0x0B90
|
||||||
|
/* HW registers : node */
|
||||||
|
#define BLT_NIP 0x0C00
|
||||||
|
#define BLT_CIC 0x0C04
|
||||||
|
#define BLT_INS 0x0C08
|
||||||
|
#define BLT_ACK 0x0C0C
|
||||||
|
#define BLT_TBA 0x0C10
|
||||||
|
#define BLT_TTY 0x0C14
|
||||||
|
#define BLT_TXY 0x0C18
|
||||||
|
#define BLT_TSZ 0x0C1C
|
||||||
|
#define BLT_S1BA 0x0C28
|
||||||
|
#define BLT_S1TY 0x0C2C
|
||||||
|
#define BLT_S1XY 0x0C30
|
||||||
|
#define BLT_S2BA 0x0C38
|
||||||
|
#define BLT_S2TY 0x0C3C
|
||||||
|
#define BLT_S2XY 0x0C40
|
||||||
|
#define BLT_S2SZ 0x0C44
|
||||||
|
#define BLT_S3BA 0x0C48
|
||||||
|
#define BLT_S3TY 0x0C4C
|
||||||
|
#define BLT_S3XY 0x0C50
|
||||||
|
#define BLT_S3SZ 0x0C54
|
||||||
|
#define BLT_FCTL 0x0C68
|
||||||
|
#define BLT_RSF 0x0C70
|
||||||
|
#define BLT_RZI 0x0C74
|
||||||
|
#define BLT_HFP 0x0C78
|
||||||
|
#define BLT_VFP 0x0C7C
|
||||||
|
#define BLT_Y_RSF 0x0C80
|
||||||
|
#define BLT_Y_RZI 0x0C84
|
||||||
|
#define BLT_Y_HFP 0x0C88
|
||||||
|
#define BLT_Y_VFP 0x0C8C
|
||||||
|
#define BLT_IVMX0 0x0CC0
|
||||||
|
#define BLT_IVMX1 0x0CC4
|
||||||
|
#define BLT_IVMX2 0x0CC8
|
||||||
|
#define BLT_IVMX3 0x0CCC
|
||||||
|
#define BLT_OVMX0 0x0CD0
|
||||||
|
#define BLT_OVMX1 0x0CD4
|
||||||
|
#define BLT_OVMX2 0x0CD8
|
||||||
|
#define BLT_OVMX3 0x0CDC
|
||||||
|
#define BLT_DEI 0x0CEC
|
||||||
|
/* HW registers : filters */
|
||||||
|
#define BLT_HFC_N 0x0D00
|
||||||
|
#define BLT_VFC_N 0x0D90
|
||||||
|
#define BLT_Y_HFC_N 0x0E00
|
||||||
|
#define BLT_Y_VFC_N 0x0E90
|
||||||
|
#define BLT_NB_H_COEF 16
|
||||||
|
#define BLT_NB_V_COEF 10
|
||||||
|
|
||||||
|
/* Registers values */
|
||||||
|
#define BLT_CTL_RESET BIT(31) /* Global soft reset */
|
||||||
|
|
||||||
|
#define BLT_ITS_AQ1_LNA BIT(12) /* AQ1 LNA reached */
|
||||||
|
|
||||||
|
#define BLT_STA1_IDLE BIT(0) /* BDISP idle */
|
||||||
|
|
||||||
|
#define BLT_AQ1_CTL_CFG 0x80400003 /* Enable, P3, LNA reached */
|
||||||
|
|
||||||
|
#define BLT_INS_S1_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||||
|
#define BLT_INS_S1_OFF 0x00000000 /* src1 disabled */
|
||||||
|
#define BLT_INS_S1_MEM 0x00000001 /* src1 fetched from memory */
|
||||||
|
#define BLT_INS_S1_CF 0x00000003 /* src1 color fill */
|
||||||
|
#define BLT_INS_S1_COPY 0x00000004 /* src1 direct copy */
|
||||||
|
#define BLT_INS_S1_FILL 0x00000007 /* src1 firect fill */
|
||||||
|
#define BLT_INS_S2_MASK (BIT(3) | BIT(4))
|
||||||
|
#define BLT_INS_S2_OFF 0x00000000 /* src2 disabled */
|
||||||
|
#define BLT_INS_S2_MEM 0x00000008 /* src2 fetched from memory */
|
||||||
|
#define BLT_INS_S2_CF 0x00000018 /* src2 color fill */
|
||||||
|
#define BLT_INS_S3_MASK BIT(5)
|
||||||
|
#define BLT_INS_S3_OFF 0x00000000 /* src3 disabled */
|
||||||
|
#define BLT_INS_S3_MEM 0x00000020 /* src3 fetched from memory */
|
||||||
|
#define BLT_INS_IVMX BIT(6) /* Input versatile matrix */
|
||||||
|
#define BLT_INS_CLUT BIT(7) /* Color Look Up Table */
|
||||||
|
#define BLT_INS_SCALE BIT(8) /* Scaling */
|
||||||
|
#define BLT_INS_FLICK BIT(9) /* Flicker filter */
|
||||||
|
#define BLT_INS_CLIP BIT(10) /* Clipping */
|
||||||
|
#define BLT_INS_CKEY BIT(11) /* Color key */
|
||||||
|
#define BLT_INS_OVMX BIT(12) /* Output versatile matrix */
|
||||||
|
#define BLT_INS_DEI BIT(13) /* Deinterlace */
|
||||||
|
#define BLT_INS_PMASK BIT(14) /* Plane mask */
|
||||||
|
#define BLT_INS_VC1R BIT(17) /* VC1 Range mapping */
|
||||||
|
#define BLT_INS_ROTATE BIT(18) /* Rotation */
|
||||||
|
#define BLT_INS_GRAD BIT(19) /* Gradient fill */
|
||||||
|
#define BLT_INS_AQLOCK BIT(29) /* AQ lock */
|
||||||
|
#define BLT_INS_PACE BIT(30) /* Pace down */
|
||||||
|
#define BLT_INS_IRQ BIT(31) /* Raise IRQ when node done */
|
||||||
|
#define BLT_CIC_ALL_GRP 0x000FDFFC /* all valid groups present */
|
||||||
|
#define BLT_ACK_BYPASS_S2S3 0x00000007 /* Bypass src2 and src3 */
|
||||||
|
|
||||||
|
#define BLT_TTY_COL_SHIFT 16 /* Color format */
|
||||||
|
#define BLT_TTY_COL_MASK 0x001F0000 /* Color format mask */
|
||||||
|
#define BLT_TTY_ALPHA_R BIT(21) /* Alpha range */
|
||||||
|
#define BLT_TTY_CR_NOT_CB BIT(22) /* CR not Cb */
|
||||||
|
#define BLT_TTY_MB BIT(23) /* MB frame / field*/
|
||||||
|
#define BLT_TTY_HSO BIT(24) /* H scan order */
|
||||||
|
#define BLT_TTY_VSO BIT(25) /* V scan order */
|
||||||
|
#define BLT_TTY_DITHER BIT(26) /* Dithering */
|
||||||
|
#define BLT_TTY_CHROMA BIT(27) /* Write chroma / luma */
|
||||||
|
#define BLT_TTY_BIG_END BIT(30) /* Big endianness */
|
||||||
|
|
||||||
|
#define BLT_S1TY_A1_SUBSET BIT(22) /* A1 subset */
|
||||||
|
#define BLT_S1TY_CHROMA_EXT BIT(26) /* Chroma Extended */
|
||||||
|
#define BTL_S1TY_SUBBYTE BIT(28) /* Sub-byte fmt, pixel order */
|
||||||
|
#define BLT_S1TY_RGB_EXP BIT(29) /* RGB expansion mode */
|
||||||
|
|
||||||
|
#define BLT_S2TY_A1_SUBSET BIT(22) /* A1 subset */
|
||||||
|
#define BLT_S2TY_CHROMA_EXT BIT(26) /* Chroma Extended */
|
||||||
|
#define BTL_S2TY_SUBBYTE BIT(28) /* Sub-byte fmt, pixel order */
|
||||||
|
#define BLT_S2TY_RGB_EXP BIT(29) /* RGB expansion mode */
|
||||||
|
|
||||||
|
#define BLT_S3TY_BLANK_ACC BIT(26) /* Blank access */
|
||||||
|
|
||||||
|
#define BLT_FCTL_HV_SCALE 0x00000055 /* H/V resize + color filter */
|
||||||
|
#define BLT_FCTL_Y_HV_SCALE 0x33000000 /* Luma version */
|
||||||
|
|
||||||
|
#define BLT_FCTL_HV_SAMPLE 0x00000044 /* H/V resize */
|
||||||
|
#define BLT_FCTL_Y_HV_SAMPLE 0x22000000 /* Luma version */
|
||||||
|
|
||||||
|
#define BLT_RZI_DEFAULT 0x20003000 /* H/VNB_repeat = 3/2 */
|
||||||
|
|
||||||
|
/* Color format */
|
||||||
|
#define BDISP_RGB565 0x00 /* RGB565 */
|
||||||
|
#define BDISP_RGB888 0x01 /* RGB888 */
|
||||||
|
#define BDISP_XRGB8888 0x02 /* RGB888_32 */
|
||||||
|
#define BDISP_ARGB8888 0x05 /* ARGB888 */
|
||||||
|
#define BDISP_NV12 0x16 /* YCbCr42x R2B */
|
||||||
|
#define BDISP_YUV_3B 0x1E /* YUV (3 buffer) */
|
1405
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
Normal file
1405
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
Normal file
File diff suppressed because it is too large
Load diff
186
drivers/media/platform/sti/bdisp/bdisp.h
Normal file
186
drivers/media/platform/sti/bdisp/bdisp.h
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) STMicroelectronics SA 2014
|
||||||
|
* Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
|
||||||
|
* License terms: GNU General Public License (GPL), version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include <media/v4l2-ctrls.h>
|
||||||
|
#include <media/v4l2-device.h>
|
||||||
|
#include <media/v4l2-mem2mem.h>
|
||||||
|
|
||||||
|
#include <media/videobuf2-dma-contig.h>
|
||||||
|
|
||||||
|
#define BDISP_NAME "bdisp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Max nb of nodes in node-list:
|
||||||
|
* - 2 nodes to handle wide 4K pictures
|
||||||
|
* - 2 nodes to handle two planes (Y & CbCr) */
|
||||||
|
#define MAX_OUTPUT_PLANES 2
|
||||||
|
#define MAX_VERTICAL_STRIDES 2
|
||||||
|
#define MAX_NB_NODE (MAX_OUTPUT_PLANES * MAX_VERTICAL_STRIDES)
|
||||||
|
|
||||||
|
/* struct bdisp_ctrls - bdisp control set
|
||||||
|
* @hflip: horizontal flip
|
||||||
|
* @vflip: vertical flip
|
||||||
|
*/
|
||||||
|
struct bdisp_ctrls {
|
||||||
|
struct v4l2_ctrl *hflip;
|
||||||
|
struct v4l2_ctrl *vflip;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_fmt - driver's internal color format data
|
||||||
|
* @pixelformat:fourcc code for this format
|
||||||
|
* @nb_planes: number of planes (ex: [0]=RGB/Y - [1]=Cb/Cr, ...)
|
||||||
|
* @bpp: bits per pixel (general)
|
||||||
|
* @bpp_plane0: byte per pixel for the 1st plane
|
||||||
|
* @w_align: width alignment in pixel (multiple of)
|
||||||
|
* @h_align: height alignment in pixel (multiple of)
|
||||||
|
*/
|
||||||
|
struct bdisp_fmt {
|
||||||
|
u32 pixelformat;
|
||||||
|
u8 nb_planes;
|
||||||
|
u8 bpp;
|
||||||
|
u8 bpp_plane0;
|
||||||
|
u8 w_align;
|
||||||
|
u8 h_align;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_frame - frame properties
|
||||||
|
*
|
||||||
|
* @width: frame width (including padding)
|
||||||
|
* @height: frame height (including padding)
|
||||||
|
* @fmt: pointer to frame format descriptor
|
||||||
|
* @field: frame / field type
|
||||||
|
* @bytesperline: stride of the 1st plane
|
||||||
|
* @sizeimage: image size in bytes
|
||||||
|
* @colorspace: colorspace
|
||||||
|
* @crop: crop area
|
||||||
|
* @paddr: image physical addresses per plane ([0]=RGB/Y - [1]=Cb/Cr, ...)
|
||||||
|
*/
|
||||||
|
struct bdisp_frame {
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
const struct bdisp_fmt *fmt;
|
||||||
|
enum v4l2_field field;
|
||||||
|
u32 bytesperline;
|
||||||
|
u32 sizeimage;
|
||||||
|
enum v4l2_colorspace colorspace;
|
||||||
|
struct v4l2_rect crop;
|
||||||
|
dma_addr_t paddr[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_request - bdisp request
|
||||||
|
*
|
||||||
|
* @src: source frame properties
|
||||||
|
* @dst: destination frame properties
|
||||||
|
* @hflip: horizontal flip
|
||||||
|
* @vflip: vertical flip
|
||||||
|
* @nb_req: number of run request
|
||||||
|
*/
|
||||||
|
struct bdisp_request {
|
||||||
|
struct bdisp_frame src;
|
||||||
|
struct bdisp_frame dst;
|
||||||
|
unsigned int hflip:1;
|
||||||
|
unsigned int vflip:1;
|
||||||
|
int nb_req;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_ctx - device context data
|
||||||
|
*
|
||||||
|
* @src: source frame properties
|
||||||
|
* @dst: destination frame properties
|
||||||
|
* @state: flags to keep track of user configuration
|
||||||
|
* @hflip: horizontal flip
|
||||||
|
* @vflip: vertical flip
|
||||||
|
* @bdisp_dev: the device this context applies to
|
||||||
|
* @node: node array
|
||||||
|
* @node_paddr: node physical address array
|
||||||
|
* @fh: v4l2 file handle
|
||||||
|
* @ctrl_handler: v4l2 controls handler
|
||||||
|
* @bdisp_ctrls: bdisp control set
|
||||||
|
* @ctrls_rdy: true if the control handler is initialized
|
||||||
|
*/
|
||||||
|
struct bdisp_ctx {
|
||||||
|
struct bdisp_frame src;
|
||||||
|
struct bdisp_frame dst;
|
||||||
|
u32 state;
|
||||||
|
unsigned int hflip:1;
|
||||||
|
unsigned int vflip:1;
|
||||||
|
struct bdisp_dev *bdisp_dev;
|
||||||
|
struct bdisp_node *node[MAX_NB_NODE];
|
||||||
|
dma_addr_t node_paddr[MAX_NB_NODE];
|
||||||
|
struct v4l2_fh fh;
|
||||||
|
struct v4l2_ctrl_handler ctrl_handler;
|
||||||
|
struct bdisp_ctrls bdisp_ctrls;
|
||||||
|
bool ctrls_rdy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_m2m_device - v4l2 memory-to-memory device data
|
||||||
|
*
|
||||||
|
* @vdev: video device node for v4l2 m2m mode
|
||||||
|
* @m2m_dev: v4l2 m2m device data
|
||||||
|
* @ctx: hardware context data
|
||||||
|
* @refcnt: reference counter
|
||||||
|
*/
|
||||||
|
struct bdisp_m2m_device {
|
||||||
|
struct video_device *vdev;
|
||||||
|
struct v4l2_m2m_dev *m2m_dev;
|
||||||
|
struct bdisp_ctx *ctx;
|
||||||
|
int refcnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bdisp_dev - abstraction for bdisp entity
|
||||||
|
*
|
||||||
|
* @v4l2_dev: v4l2 device
|
||||||
|
* @vdev: video device
|
||||||
|
* @pdev: platform device
|
||||||
|
* @dev: device
|
||||||
|
* @lock: mutex protecting this data structure
|
||||||
|
* @slock: spinlock protecting this data structure
|
||||||
|
* @id: device index
|
||||||
|
* @m2m: memory-to-memory V4L2 device information
|
||||||
|
* @state: flags used to synchronize m2m and capture mode operation
|
||||||
|
* @alloc_ctx: videobuf2 memory allocator context
|
||||||
|
* @clock: IP clock
|
||||||
|
* @regs: registers
|
||||||
|
* @irq_queue: interrupt handler waitqueue
|
||||||
|
* @work_queue: workqueue to handle timeouts
|
||||||
|
* @timeout_work: IRQ timeout structure
|
||||||
|
*/
|
||||||
|
struct bdisp_dev {
|
||||||
|
struct v4l2_device v4l2_dev;
|
||||||
|
struct video_device vdev;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct device *dev;
|
||||||
|
spinlock_t slock;
|
||||||
|
struct mutex lock;
|
||||||
|
u16 id;
|
||||||
|
struct bdisp_m2m_device m2m;
|
||||||
|
unsigned long state;
|
||||||
|
struct vb2_alloc_ctx *alloc_ctx;
|
||||||
|
struct clk *clock;
|
||||||
|
void __iomem *regs;
|
||||||
|
wait_queue_head_t irq_queue;
|
||||||
|
struct workqueue_struct *work_queue;
|
||||||
|
struct delayed_work timeout_work;
|
||||||
|
};
|
||||||
|
|
||||||
|
void bdisp_hw_free_nodes(struct bdisp_ctx *ctx);
|
||||||
|
int bdisp_hw_alloc_nodes(struct bdisp_ctx *ctx);
|
||||||
|
void bdisp_hw_free_filters(struct device *dev);
|
||||||
|
int bdisp_hw_alloc_filters(struct device *dev);
|
||||||
|
int bdisp_hw_reset(struct bdisp_dev *bdisp);
|
||||||
|
int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp);
|
||||||
|
int bdisp_hw_update(struct bdisp_ctx *ctx);
|
Loading…
Reference in a new issue