2020-08-28 13:20:27

by Kévin L'hôpital

[permalink] [raw]
Subject: [PATCH v2 0/4] Support of MIPI CSI-2 for A83T

This series adds the support for the MIPI CSI-2 controller for the A83T SoC.
The CSI controller is the same as the V3s SoC that's why I put the A83T
MIPI CSI-2 driver in sun6i-csi.
My work is based on the Allwinner BSP for A83T and also on MIPI CSI-2
specification for the A83T given by Allwinner.

v4l2-compliance SHA: not available, 32 bits

Compliance test for sun6i-video device /dev/video0:

Driver Info:
Driver name : sun6i-video
Card type : sun6i-csi
Bus info : platform:camera
Driver version : 5.5.0
Capabilities : 0x84200001
Video Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format
Media Driver Info:
Driver name : sun6i-csi
Model : Allwinner Video Capture Device
Serial :
Bus info :
Media version : 5.5.0
Hardware revision: 0x00000000 (0)
Driver version : 5.5.0
Interface Info:
ID : 0x03000003
Type : V4L Video
Entity Info:
ID : 0x00000001 (1)
Name : sun6i-csi
Function : V4L2 I/O
Pad 0x01000002 : 0: Sink, Must Connect
Link 0x02000007: from remote pad 0x1000006 of entity 'ov8865 1-0036': Data, Enabled, Immutable

Required ioctls:
test MC information (see 'Media Driver Info' above): OK
test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
test second /dev/video0 open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK

Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK

Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 1 Audio Inputs: 0 Tuners: 0

Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)

Control ioctls (Input 0):
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 7 Private Controls: 0

Format ioctls (Input 0):
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK

Codec ioctls (Input 0):
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls (Input 0):
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK
test Requests: OK (Not Supported)

Total for sun6i-video device /dev/video0: 45, Succeeded: 45, Failed: 0, Warnings: 0

Changes since V1:
- Add more details in the cover letter.
- Add a test to get the clocks to avoid an error for the platform without MIPI
CSI-2.
- Add more details in the register assignations.
- Removed the support of multiple virtual channels because there is only one
channel support in the CSI driver.

Kévin L'hôpital (4):
media: sun6i-csi: Fix the bpp for 10-bit bayer formats
media: sunxi: sun6i-csi: Move the sun6i_csi_dev structure to the
common header
media: sunxi: sun6i-csi: Add support of MIPI CSI-2 for A83T
ARM: dts: sun8i: a83t: Add support for the MIPI CSI-2 in CSI node

arch/arm/boot/dts/sun8i-a83t.dtsi | 11 +-
.../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 96 +++++---
.../platform/sunxi/sun6i-csi/sun6i_csi.h | 14 +-
.../sunxi/sun6i-csi/sun8i_a83t_dphy.c | 39 ++++
.../sunxi/sun6i-csi/sun8i_a83t_dphy.h | 16 ++
.../sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h | 39 ++++
.../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c | 217 ++++++++++++++++++
.../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h | 16 ++
.../sun6i-csi/sun8i_a83t_mipi_csi2_reg.h | 179 +++++++++++++++
10 files changed, 595 insertions(+), 34 deletions(-)
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h

--
2.17.1


2020-08-28 13:21:19

by Kévin L'hôpital

[permalink] [raw]
Subject: [PATCH v2 1/4] media: sun6i-csi: Fix the bpp for 10-bit bayer formats

10-bit bayer formats are aligned to 16 bits in memory, so this is what
needs to be used as bpp for calculating the size of the buffers to
allocate.
This function is only used to generate the number of bytes per line.

Fixes: 5cc7522d8965 ("media: sun6i: Add support for Allwinner CSI V3s")
Signed-off-by: Kévin L'hôpital <[email protected]>
---
drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
index c626821aaedb..8b83d15de0d0 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
@@ -100,7 +100,7 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat)
case V4L2_PIX_FMT_SGBRG10:
case V4L2_PIX_FMT_SGRBG10:
case V4L2_PIX_FMT_SRGGB10:
- return 10;
+ return 16;
case V4L2_PIX_FMT_SBGGR12:
case V4L2_PIX_FMT_SGBRG12:
case V4L2_PIX_FMT_SGRBG12:
--
2.17.1

2020-08-28 13:22:12

by Kévin L'hôpital

[permalink] [raw]
Subject: [PATCH v2 4/4] ARM: dts: sun8i: a83t: Add support for the MIPI CSI-2 in CSI node

Add in the CSI device node the MIPI CSI2 clocks, interrupt and
increase the memory size in order to add the support of the
MIPI CSI-2 for A83T

Signed-off-by: Kévin L'hôpital <[email protected]>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 53c38deb8a08..5e6421eb8e28 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -1025,12 +1025,15 @@

csi: camera@1cb0000 {
compatible = "allwinner,sun8i-a83t-csi";
- reg = <0x01cb0000 0x1000>;
- interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0x01cb0000 0x2000>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_CSI>,
<&ccu CLK_CSI_SCLK>,
- <&ccu CLK_DRAM_CSI>;
- clock-names = "bus", "mod", "ram";
+ <&ccu CLK_DRAM_CSI>,
+ <&ccu CLK_MIPI_CSI>,
+ <&ccu CLK_CSI_MISC>;
+ clock-names = "bus", "mod", "ram", "mipi", "misc";
resets = <&ccu RST_BUS_CSI>;
status = "disabled";

--
2.17.1

2020-08-28 13:22:56

by Kévin L'hôpital

[permalink] [raw]
Subject: [PATCH v2 3/4] media: sunxi: sun6i-csi: Add support of MIPI CSI-2 for A83T

This patch add the support only for the Allwinner A83T MIPI CSI-2.
Currently, the driver does not support the V3s MIPI CSI-2 controller.
On the A83T, the CSI controller is the same as the other V3s Soc, but
the MIPI CSI2 controller is not.

It was tested with the ov8865 image sensor.

Signed-off-by: Kévin L'hôpital <[email protected]>
---
.../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
.../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++--
.../sunxi/sun6i-csi/sun8i_a83t_dphy.c | 39 ++++
.../sunxi/sun6i-csi/sun8i_a83t_dphy.h | 16 ++
.../sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h | 39 ++++
.../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c | 217 ++++++++++++++++++
.../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h | 16 ++
.../sun6i-csi/sun8i_a83t_mipi_csi2_reg.h | 179 +++++++++++++++
8 files changed, 575 insertions(+), 17 deletions(-)
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h

diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile
index e7e315347804..0f3849790463 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/Makefile
+++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-sun6i-csi-y += sun6i_video.o sun6i_csi.o
+sun6i-csi-y += sun6i_video.o sun6i_csi.o sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o

obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 680fa31f380a..cf346e536959 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -26,6 +26,7 @@

#include "sun6i_csi.h"
#include "sun6i_csi_reg.h"
+#include "sun8i_a83t_mipi_csi2.h"

#define MODULE_NAME "sun6i-csi"

@@ -160,10 +161,14 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);

clk_disable_unprepare(sdev->clk_ram);
+
if (of_device_is_compatible(dev->of_node,
"allwinner,sun50i-a64-csi"))
clk_rate_exclusive_put(sdev->clk_mod);
clk_disable_unprepare(sdev->clk_mod);
+ if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+ sun6i_mipi_csi_clk_disable(csi);
+
reset_control_assert(sdev->rstc_bus);
return 0;
}
@@ -189,10 +194,18 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
goto clk_ram_disable;
}

+ if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
+ ret = sun6i_mipi_csi_clk_enable(csi);
+ if (ret)
+ goto reset_control_assert;
+ }
+
regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);

return 0;

+reset_control_assert:
+ reset_control_assert(sdev->rstc_bus);
clk_ram_disable:
clk_disable_unprepare(sdev->clk_ram);
clk_mod_disable:
@@ -421,27 +434,34 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
break;
+ case V4L2_MBUS_CSI2_DPHY:
+ cfg |= CSI_IF_CFG_MIPI_IF_MIPI;
+ sun6i_mipi_csi_setup_bus(csi);
+ break;
default:
dev_warn(sdev->dev, "Unsupported bus type: %d\n",
endpoint->bus_type);
break;
}

- switch (bus_width) {
- case 8:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
- break;
- case 10:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
- break;
- case 12:
- cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
- break;
- case 16: /* No need to configure DATA_WIDTH for 16bit */
- break;
- default:
- dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
- break;
+ /* Bus width only applies to parallel bus. */
+ if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) {
+ switch (bus_width) {
+ case 8:
+ cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
+ break;
+ case 10:
+ cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
+ break;
+ case 12:
+ cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
+ break;
+ case 16: /* No need to configure DATA_WIDTH for 16bit */
+ break;
+ default:
+ dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
+ break;
+ }
}

regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
@@ -593,6 +613,9 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
struct regmap *regmap = sdev->regmap;

if (!enable) {
+ if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+ sun6i_mipi_csi_set_stream(csi, 0);
+
regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
return;
@@ -609,6 +632,9 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)

regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
CSI_CAP_CH0_VCAP_ON);
+
+ if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+ sun6i_mipi_csi_set_stream(csi, 1);
}

/* -----------------------------------------------------------------------------
@@ -685,6 +711,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
struct v4l2_async_subdev *asd)
{
struct sun6i_csi *csi = dev_get_drvdata(dev);
+ struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);

if (vep->base.port || vep->base.id) {
dev_warn(dev, "Only support a single port with one endpoint\n");
@@ -692,6 +719,17 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
}

switch (vep->bus_type) {
+ case V4L2_MBUS_CSI2_DPHY:
+ if (!sdev->clk_mipi) {
+ dev_err(sdev->dev, "Use MIPI-CSI2 device with no MIPI clock\n");
+ return -ENOTCONN;
+ }
+ if (!sdev->clk_misc) {
+ dev_err(sdev->dev, "Use MIPI-CSI2 device with no misc clock\n");
+ return -ENOTCONN;
+ }
+ csi->v4l2_ep = *vep;
+ return 0;
case V4L2_MBUS_PARALLEL:
case V4L2_MBUS_BT656:
csi->v4l2_ep = *vep;
@@ -812,12 +850,13 @@ static const struct regmap_config sun6i_csi_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = 0x9c,
+ .max_register = 0x2000,
};

static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
struct platform_device *pdev)
{
+ struct device *dev = sdev->dev;
struct resource *res;
void __iomem *io_base;
int ret;
@@ -847,6 +886,19 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
return PTR_ERR(sdev->clk_ram);
}

+ if (of_device_is_compatible(dev->of_node, "allwinner,sun8i-a83t-csi")) {
+ sdev->clk_mipi = devm_clk_get(&pdev->dev, "mipi");
+ if (IS_ERR(sdev->clk_mipi)) {
+ sdev->clk_mipi = NULL;
+ dev_warn(&pdev->dev, "Unable to acquire mipi clock. No mipi support\n");
+ }
+
+ sdev->clk_misc = devm_clk_get(&pdev->dev, "misc");
+ if (IS_ERR(sdev->clk_misc)) {
+ sdev->clk_misc = NULL;
+ dev_warn(&pdev->dev, "Unable to acquire misc clock. No mipi support\n");
+ }
+ }
sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
if (IS_ERR(sdev->rstc_bus)) {
dev_err(&pdev->dev, "Cannot get reset controller\n");
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
new file mode 100644
index 000000000000..bb9599c3bde9
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sun6i_dphy.c
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#include "sun8i_a83t_dphy.h"
+#include "sun8i_a83t_dphy_reg.h"
+
+/* First initialization to turn on the dphy for the MIPI CSI2 controller
+ * initialization.
+ */
+
+void sun6i_dphy_first_init(struct sun6i_csi_dev *sdev)
+{
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_DBG,
+ DPHY_CTRL_REG_DBG);
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_SHUT, 0);
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_RSTN,
+ DPHY_CTRL_REG_RSTN);
+}
+
+/* Second initialization to turn off the dphy and do its initialization. */
+void sun6i_dphy_second_init(struct sun6i_csi_dev *sdev)
+{
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_DBG, 0);
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_SHUT,
+ DPHY_CTRL_REG_SHUT);
+ regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_RSTN,
+ DPHY_CTRL_REG_RSTN);
+ regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_SNK_MASK,
+ DPHY_ANA0_REG_SNK(0x02));
+ regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_RINT_MASK,
+ DPHY_ANA0_REG_RINT(0x02));
+ regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_REXT, 0);
+ regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_ENREXT,
+ DPHY_ANA0_REG_ENREXT);
+}
+
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
new file mode 100644
index 000000000000..f776ed098cb3
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * sun6i_dphy.h
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#ifndef __SUN8I_A83T_DPHY_H__
+#define __SUN8I_A83T_DPHY_H__
+
+#include <linux/regmap.h>
+#include "sun6i_csi.h"
+
+void sun6i_dphy_first_init(struct sun6i_csi_dev *sdev);
+void sun6i_dphy_second_init(struct sun6i_csi_dev *sdev);
+
+#endif /* __SUN8I_A83T_DPHY_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
new file mode 100644
index 000000000000..815692b112d2
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allwinner A83t DPHY register description
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#ifndef __SUN8I_A83T_DPHY_REG_H__
+#define __SUN8I_A83T_DPHY_REG_H__
+
+
+#define DPHY_OFFSET 0x1000
+
+#define DPHY_CTRL_REG (DPHY_OFFSET + 0x010)
+#define DPHY_CTRL_REG_RSTN BIT(31)
+#define DPHY_CTRL_REG_SHUT BIT(15)
+#define DPHY_CTRL_REG_DBG BIT(8)
+
+#define DPHY_STATUS_REG (DPHY_OFFSET + 0x014)
+#define DPHY_STATUS_REG_CLK_STOP BIT(10)
+#define DPHY_STATUS_REG_CLK_UPLS BIT(9)
+#define DPHY_STATUS_REG_HSCLK BIT(8)
+#define DPHY_STATUS_REG_D3_STOP BIT(7)
+#define DPHY_STATUS_REG_D2_STOP BIT(6)
+#define DPHY_STATUS_REG_D1_STOP BIT(5)
+#define DPHY_STATUS_REG_D0_STOP BIT(4)
+#define DPHY_STATUS_REG_D3_UPLS BIT(3)
+#define DPHY_STATUS_REG_D2_UPLS BIT(2)
+#define DPHY_STATUS_REG_D1_UPLS BIT(1)
+#define DPHY_STATUS_REG_D0_UPLS BIT(0)
+
+#define DPHY_ANA0_REG (DPHY_OFFSET + 0x030)
+#define DPHY_ANA0_REG_ENREXT BIT(31)
+#define DPHY_ANA0_REG_REXT BIT(30)
+#define DPHY_ANA0_REG_RINT_MASK GENMASK(29, 28)
+#define DPHY_ANA0_REG_RINT(v) ((v) << 28)
+#define DPHY_ANA0_REG_SNK_MASK GENMASK(22, 20)
+#define DPHY_ANA0_REG_SNK(v) ((v) << 20)
+
+#endif /* __SUN8I_A83T_DPHY_REG_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
new file mode 100644
index 000000000000..2933238cbc95
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner A83t MIPI Camera Sensor Interface 2 driver
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#include <linux/clk.h>
+#include "sun8i_a83t_mipi_csi2.h"
+#include "sun8i_a83t_mipi_csi2_reg.h"
+#include "sun8i_a83t_dphy.h"
+#include <linux/delay.h>
+
+#define IS_FLAG(x, y) (((x) & (y)) == y)
+
+enum mipi_csi2_pkt_fmt {
+ MIPI_FS = 0X00,
+ MIPI_FE = 0X01,
+ MIPI_LS = 0X02,
+ MIPI_LE = 0X03,
+ MIPI_SDAT0 = 0X08,
+ MIPI_SDAT1 = 0X09,
+ MIPI_SDAT2 = 0X0A,
+ MIPI_SDAT3 = 0X0B,
+ MIPI_SDAT4 = 0X0C,
+ MIPI_SDAT5 = 0X0D,
+ MIPI_SDAT6 = 0X0E,
+ MIPI_SDAT7 = 0X0F,
+ MIPI_BLK = 0X11,
+ MIPI_EMBD = 0X12,
+ MIPI_YUV420 = 0X18,
+ MIPI_YUV420_10 = 0X19,
+ MIPI_YUV420_CSP = 0X1C,
+ MIPI_YUV420_CSP_10 = 0X1D,
+ MIPI_YUV422 = 0X1E,
+ MIPI_YUV422_10 = 0X1F,
+ MIPI_RGB565 = 0X22,
+ MIPI_RGB888 = 0X24,
+ MIPI_RAW8 = 0X2A,
+ MIPI_RAW10 = 0X2B,
+ MIPI_RAW12 = 0X2C,
+ MIPI_USR_DAT0 = 0X30,
+ MIPI_USR_DAT1 = 0X31,
+ MIPI_USR_DAT2 = 0X32,
+ MIPI_USR_DAT3 = 0X33,
+ MIPI_USR_DAT4 = 0X34,
+ MIPI_USR_DAT5 = 0X35,
+ MIPI_USR_DAT6 = 0X36,
+ MIPI_USR_DAT7 = 0X37,
+};
+
+static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
+{
+ return container_of(csi, struct sun6i_csi_dev, csi);
+}
+
+static enum mipi_csi2_pkt_fmt get_pkt_fmt(u16 bus_pix_code)
+{
+ switch (bus_pix_code) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ return MIPI_RGB565;
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ return MIPI_YUV422;
+ case MEDIA_BUS_FMT_UYVY10_2X10:
+ return MIPI_YUV422_10;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ return MIPI_RGB888;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ return MIPI_RAW8;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ return MIPI_RAW10;
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ case MEDIA_BUS_FMT_SGBRG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
+ return MIPI_RAW12;
+ default:
+ return MIPI_RAW8;
+ }
+}
+
+void sun6i_mipi_csi_set_stream(struct sun6i_csi *csi, bool enable)
+{
+ struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+
+ if (enable)
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_EN,
+ MIPI_CSI2_CFG_REG_SYNC_EN);
+ else
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_EN, 0);
+}
+
+void sun6i_mipi_csi_init(struct sun6i_csi_dev *sdev)
+{
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CTRL_REG,
+ MIPI_CSI2_CTRL_REG_RSTN, MIPI_CSI2_CTRL_REG_RSTN);
+ regmap_write(sdev->regmap, MIPI_CSI2_RX_PKT_NUM_REG, 0xb8d257f8);
+ sun6i_dphy_first_init(sdev);
+ regmap_write(sdev->regmap, MIPI_CSI2_RSVD1_REG,
+ HW_LOCK_REGISTER_VALUE_1);
+ regmap_write(sdev->regmap, MIPI_CSI2_RSVD2_REG,
+ HW_LOCK_REGISTER_VALUE_2);
+ regmap_write(sdev->regmap, MIPI_CSI2_RX_PKT_NUM_REG, 0);
+ regmap_write(sdev->regmap, MIPI_CSI2_VCDT0_REG, 0);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK,
+ MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(0x11));
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_N_BYTE, 0);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_YC_SWAB, 0);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE,
+ MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_UNPKT_EN,
+ MIPI_CSI2_CFG_REG_UNPKT_EN);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_BYPASS_ECC_EN,
+ MIPI_CSI2_CFG_REG_BYPASS_ECC_EN);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_EN,
+ MIPI_CSI2_CFG_REG_SYNC_EN);
+ sun6i_dphy_second_init(sdev);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CTRL_REG,
+ MIPI_CSI2_CTRL_REG_RSTN, MIPI_CSI2_CTRL_REG_RSTN);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK,
+ MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(0x08));
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE, 0);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_BYPASS_ECC_EN, 0);
+ regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_SYNC_EN, 0);
+}
+
+void sun6i_mipi_csi_setup_bus(struct sun6i_csi *csi)
+{
+ struct v4l2_fwnode_endpoint *endpoint = &csi->v4l2_ep;
+ struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+ int lane_num = endpoint->bus.mipi_csi2.num_data_lanes;
+ int flags = endpoint->bus.mipi_csi2.flags;
+ int total_rx_ch = 0;
+ int vc;
+
+ sun6i_mipi_csi_init(sdev);
+
+ if (IS_FLAG(flags, V4L2_MBUS_CSI2_CHANNEL_0)) {
+ vc = 0;
+ total_rx_ch++;
+ }
+
+ if (!total_rx_ch) {
+ dev_dbg(sdev->dev,
+ "No receive channel assigned, using channel 0.\n");
+ vc = 0;
+ total_rx_ch++;
+ }
+ /* Set lane. */
+ regmap_write_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_N_LANE_MASK, (lane_num - 1) <<
+ MIPI_CSI2_CFG_REG_N_LANE_SHIFT);
+ /* Set total channels. */
+ regmap_write_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
+ MIPI_CSI2_CFG_REG_N_CHANNEL_MASK, (total_rx_ch - 1) <<
+ MIPI_CSI2_CFG_REG_N_CHANNEL_SHIFT);
+
+ regmap_write_bits(sdev->regmap, MIPI_CSI2_VCDT0_REG,
+ MIPI_CSI2_VCDT0_REG_CH0_DT_MASK,
+ get_pkt_fmt(csi->config.code));
+ regmap_write_bits(sdev->regmap, MIPI_CSI2_VCDT0_REG,
+ MIPI_CSI2_VCDT0_REG_CH0_VC_MASK,
+ vc << MIPI_CSI2_VCDT0_REG_CH0_VC_SHIFT);
+}
+
+int sun6i_mipi_csi_clk_enable(struct sun6i_csi *csi)
+{
+ struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+ int ret;
+
+ ret = clk_prepare_enable(sdev->clk_mipi);
+ if (ret) {
+ dev_err(sdev->dev, "Enable clk_mipi clk err %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(sdev->clk_misc);
+ if (ret) {
+ dev_err(sdev->dev, "Enable clk_misc clk err %d\n", ret);
+ goto clk_mipi_disable;
+ }
+
+ return 0;
+
+clk_mipi_disable:
+ clk_disable_unprepare(sdev->clk_mipi);
+ return ret;
+}
+
+void sun6i_mipi_csi_clk_disable(struct sun6i_csi *csi)
+{
+ struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
+
+ clk_disable_unprepare(sdev->clk_misc);
+ clk_disable_unprepare(sdev->clk_mipi);
+}
+
+
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
new file mode 100644
index 000000000000..a94c69ccee39
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#ifndef __SUN8I_A83T_MIPI_CSI2_H__
+#define __SUN8I_A83T_MIPI_CSI2_H__
+#include <linux/regmap.h>
+#include "sun6i_csi.h"
+
+void sun6i_mipi_csi_set_stream(struct sun6i_csi *csi, bool enable);
+void sun6i_mipi_csi_setup_bus(struct sun6i_csi *csi);
+int sun6i_mipi_csi_clk_enable(struct sun6i_csi *csi);
+void sun6i_mipi_csi_clk_disable(struct sun6i_csi *csi);
+
+#endif /* __SUN8I_A83T_MIPI_CSI2_H__ */
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
new file mode 100644
index 000000000000..43cc46ea1aec
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allwinner A83t MIPI CSI-2 register description
+ * Copyright Kévin L'hôpital (C) 2020
+ */
+
+#ifndef __SUN8I_A83T_MIPI_CSI2_REG_H__
+#define __SUN8I_A83T_MIPI_CSI2_REG_H__
+
+
+#define MIPI_CSI2_OFFSET 0x1000
+
+#define MIPI_CSI2_VERSION_REG (MIPI_CSI2_OFFSET + 0x000)
+#define MIPI_CSI2_CTRL_REG (MIPI_CSI2_OFFSET + 0x004)
+#define MIPI_CSI2_CTRL_REG_RSTN BIT(31)
+
+#define MIPI_CSI2_RX_PKT_NUM_REG (MIPI_CSI2_OFFSET + 0x008)
+#define MIPI_CSI2_RSVD0_REG (MIPI_CSI2_OFFSET + 0x00c)
+
+#define MIPI_CSI2_RSVD1_REG (MIPI_CSI2_OFFSET + 0x018)
+/* Value found in the BSP and need to be present but it is not describe in the
+ * datasheet.
+ */
+#define HW_LOCK_REGISTER_VALUE_1 0xb8c8a30c
+#define MIPI_CSI2_RSVD2_REG (MIPI_CSI2_OFFSET + 0x01c)
+/* Value found in the BSP and need to be present but it is not describe in the
+ * datasheet.
+ */
+#define HW_LOCK_REGISTER_VALUE_2 0xb8df8ad7
+
+#define MIPI_CSI2_INT_STA0_REG (MIPI_CSI2_OFFSET + 0x020)
+#define MIPI_CSI2_INT_STA0_REG_ECC_ERR_DBL BIT(28)
+#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC3 BIT(27)
+#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC2 BIT(26)
+#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC1 BIT(25)
+#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC0 BIT(24)
+#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT3 BIT(23)
+#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT2 BIT(22)
+#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT1 BIT(21)
+#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT0 BIT(20)
+#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT3 BIT(19)
+#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT2 BIT(18)
+#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT1 BIT(17)
+#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT0 BIT(16)
+#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC3 BIT(15)
+#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC2 BIT(14)
+#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC1 BIT(13)
+#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC0 BIT(12)
+#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC3 BIT(11)
+#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC2 BIT(10)
+#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC1 BIT(9)
+#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC0 BIT(8)
+#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC3 BIT(7)
+#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC2 BIT(6)
+#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC1 BIT(5)
+#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC0 BIT(4)
+#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_3 BIT(3)
+#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_2 BIT(2)
+#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_1 BIT(1)
+#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_0 BIT(0)
+
+#define MIPI_CSI2_INT_STA1_REG (MIPI_CSI2_OFFSET + 0x024)
+#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT7 BIT(23)
+#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT6 BIT(22)
+#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT5 BIT(21)
+#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT4 BIT(20)
+#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT7 BIT(19)
+#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT6 BIT(18)
+#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT5 BIT(17)
+#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT4 BIT(16)
+#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC3 BIT(15)
+#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC2 BIT(14)
+#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC1 BIT(13)
+#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC0 BIT(12)
+#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC3 BIT(11)
+#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC2 BIT(10)
+#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC1 BIT(9)
+#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC0 BIT(8)
+#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_3 BIT(7)
+#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_2 BIT(6)
+#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_1 BIT(5)
+#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_0 BIT(4)
+#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_3 BIT(3)
+#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_2 BIT(2)
+#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_1 BIT(1)
+#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_0 BIT(0)
+
+#define MIPI_CSI2_INT_MSK0_REG (MIPI_CSI2_OFFSET + 0x028)
+#define MIPI_CSI2_INT_MSK0_REG_ECC_ERR_DBL_MSK BIT(28)
+#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC3_MSK BIT(27)
+#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC2_MSK BIT(26)
+#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC1_MSK BIT(25)
+#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC0_MSK BIT(24)
+#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT3_MSK BIT(23)
+#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT2_MSK BIT(22)
+#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT1_MSK BIT(21)
+#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT0_MSK BIT(20)
+#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT3_MSK BIT(19)
+#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT2_MSK BIT(18)
+#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT1_MSK BIT(17)
+#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT0_MSK BIT(16)
+#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC3_MSK BIT(15)
+#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC2_MSK BIT(14)
+#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC1_MSK BIT(13)
+#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC0_MSK BIT(12)
+#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC3_MSK BIT(11)
+#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC2_MSK BIT(10)
+#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC1_MSK BIT(9)
+#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC0_MSK BIT(8)
+#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC3_MSK BIT(7)
+#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC2_MSK BIT(6)
+#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC1_MSK BIT(5)
+#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC0_MSK BIT(4)
+#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_3_MSK BIT(3)
+#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_2_MSK BIT(2)
+#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_1_MSK BIT(1)
+#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_0_MSK BIT(0)
+
+#define MIPI_CSI2_INT_MSK1_REG (MIPI_CSI2_OFFSET + 0x02c)
+#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC3_MSK BIT(15)
+#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC2_MSK BIT(14)
+#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC1_MSK BIT(13)
+#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC0_MSK BIT(12)
+#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC3_MSK BIT(11)
+#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC2_MSK BIT(10)
+#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC1_MSK BIT(9)
+#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC0_MSK BIT(8)
+#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_3_MSK BIT(7)
+#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_2_MSK BIT(6)
+#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_1_MSK BIT(5)
+#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_0_MSK BIT(4)
+#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_3_MSK BIT(3)
+#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_2_MSK BIT(2)
+#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_1_MSK BIT(1)
+#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_0_MSK BIT(0)
+
+#define MIPI_CSI2_CFG_REG (MIPI_CSI2_OFFSET + 0x100)
+#define MIPI_CSI2_CFG_REG_SYNC_EN BIT(31)
+#define MIPI_CSI2_CFG_REG_BYPASS_ECC_EN BIT(29)
+#define MIPI_CSI2_CFG_REG_UNPKT_EN BIT(28)
+#define MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE BIT(27)
+#define MIPI_CSI2_CFG_REG_YC_SWAB BIT(26)
+#define MIPI_CSI2_CFG_REG_N_BYTE BIT(24)
+#define MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(v) ((v) << 18)
+#define MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK GENMASK(22, 18)
+#define MIPI_CSI2_CFG_REG_N_CHANNEL_MASK GENMASK(17, 16)
+#define MIPI_CSI2_CFG_REG_N_CHANNEL_SHIFT 16
+#define MIPI_CSI2_CFG_REG_N_LANE_MASK GENMASK(5, 4)
+#define MIPI_CSI2_CFG_REG_N_LANE_SHIFT 4
+
+#define MIPI_CSI2_VCDT0_REG (MIPI_CSI2_OFFSET + 0x104)
+#define MIPI_CSI2_VCDT0_REG_DEFAULT 0xc0804000
+#define MIPI_CSI2_VCDT0_REG_CH3_VC_MASK GENMASK(31, 30)
+#define MIPI_CSI2_VCDT0_REG_CH3_VC_SHIFT 30
+#define MIPI_CSI2_VCDT0_REG_CH3_DT_MASK GENMASK(29, 24)
+#define MIPI_CSI2_VCDT0_REG_CH3_DT_SHIFT 24
+#define MIPI_CSI2_VCDT0_REG_CH2_VC_MASK GENMASK(23, 22)
+#define MIPI_CSI2_VCDT0_REG_CH2_VC_SHIFT 22
+#define MIPI_CSI2_VCDT0_REG_CH2_DT_MASK GENMASK(21, 16)
+#define MIPI_CSI2_VCDT0_REG_CH2_DT_SHIFT 16
+#define MIPI_CSI2_VCDT0_REG_CH1_VC_MASK GENMASK(15, 14)
+#define MIPI_CSI2_VCDT0_REG_CH1_VC_SHIFT 14
+#define MIPI_CSI2_VCDT0_REG_CH1_DT_MASK GENMASK(13, 8)
+#define MIPI_CSI2_VCDT0_REG_CH1_DT_SHIFT 8
+#define MIPI_CSI2_VCDT0_REG_CH0_VC_MASK GENMASK(7, 6)
+#define MIPI_CSI2_VCDT0_REG_CH0_VC_SHIFT 6
+#define MIPI_CSI2_VCDT0_REG_CH0_DT_MASK GENMASK(5, 0)
+
+#define MIPI_CSI2_VCDT1_REG (MIPI_CSI2_OFFSET + 0x108)
+#define MIPI_CSI2_VCDT1_REG_CH7_VC_MASK GENMASK(31, 30)
+#define MIPI_CSI2_VCDT1_REG_CH7_DT_MASK GENMASK(29, 24)
+#define MIPI_CSI2_VCDT1_REG_CH6_VC_MASK GENMASK(23, 22)
+#define MIPI_CSI2_VCDT1_REG_CH6_DT_MASK GENMASK(21, 16)
+#define MIPI_CSI2_VCDT1_REG_CH5_VC_MASK GENMASK(15, 14)
+#define MIPI_CSI2_VCDT1_REG_CH5_DT_MASK GENMASK(13, 8)
+#define MIPI_CSI2_VCDT1_REG_CH4_VC_MASK GENMASK(7, 6)
+#define MIPI_CSI2_VCDT1_REG_CH4_DT_MASK GENMASK(5, 0)
+
+#endif /* __SUN8I_A83T_MIPI_CSI2_REG_H__ */
--
2.17.1

2020-08-28 14:16:09

by Paul Kocialkowski

[permalink] [raw]
Subject: Re: [PATCH v2 0/4] Support of MIPI CSI-2 for A83T

Hi everyone,

On Fri 28 Aug 20, 15:17, Kévin L'hôpital wrote:
> This series adds the support for the MIPI CSI-2 controller for the A83T SoC.
> The CSI controller is the same as the V3s SoC that's why I put the A83T
> MIPI CSI-2 driver in sun6i-csi.
> My work is based on the Allwinner BSP for A83T and also on MIPI CSI-2
> specification for the A83T given by Allwinner.

To give a bit of context here, Kevin is our intern who worked on MIPI CSI-2
support on the A83t this summer. As we were approaching the end of the
internship, we wanted to publish the current state of the work as a working
reference and base for mainline support.

However, we are well aware that there are significant design issues in this
series, such as:
- not supporting the fwnode graph;
- not working with the DPHY API;
- adding MIPI CSI-2 support under the same dt compatible as parallel CSI;

and probably other things.

Bootlin is currently working on V3s MIPI CSI-2 support and we intend to respin
this series when submitting V3s MIPI CSI-2 support, with fixes to these design
issues.

So we hope you keep this in mind when reviewing the series, which is not meant
to be merged in its current state.

Thanks!

Paul

> v4l2-compliance SHA: not available, 32 bits
>
> Compliance test for sun6i-video device /dev/video0:
>
> Driver Info:
> Driver name : sun6i-video
> Card type : sun6i-csi
> Bus info : platform:camera
> Driver version : 5.5.0
> Capabilities : 0x84200001
> Video Capture
> Streaming
> Extended Pix Format
> Device Capabilities
> Device Caps : 0x04200001
> Video Capture
> Streaming
> Extended Pix Format
> Media Driver Info:
> Driver name : sun6i-csi
> Model : Allwinner Video Capture Device
> Serial :
> Bus info :
> Media version : 5.5.0
> Hardware revision: 0x00000000 (0)
> Driver version : 5.5.0
> Interface Info:
> ID : 0x03000003
> Type : V4L Video
> Entity Info:
> ID : 0x00000001 (1)
> Name : sun6i-csi
> Function : V4L2 I/O
> Pad 0x01000002 : 0: Sink, Must Connect
> Link 0x02000007: from remote pad 0x1000006 of entity 'ov8865 1-0036': Data, Enabled, Immutable
>
> Required ioctls:
> test MC information (see 'Media Driver Info' above): OK
> test VIDIOC_QUERYCAP: OK
>
> Allow for multiple opens:
> test second /dev/video0 open: OK
> test VIDIOC_QUERYCAP: OK
> test VIDIOC_G/S_PRIORITY: OK
> test for unlimited opens: OK
>
> Debug ioctls:
> test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> test VIDIOC_LOG_STATUS: OK
>
> Input ioctls:
> test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> test VIDIOC_ENUMAUDIO: OK (Not Supported)
> test VIDIOC_G/S/ENUMINPUT: OK
> test VIDIOC_G/S_AUDIO: OK (Not Supported)
> Inputs: 1 Audio Inputs: 0 Tuners: 0
>
> Output ioctls:
> test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> Outputs: 0 Audio Outputs: 0 Modulators: 0
>
> Input/Output configuration ioctls:
> test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> test VIDIOC_G/S_EDID: OK (Not Supported)
>
> Control ioctls (Input 0):
> test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
> test VIDIOC_QUERYCTRL: OK
> test VIDIOC_G/S_CTRL: OK
> test VIDIOC_G/S/TRY_EXT_CTRLS: OK
> test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
> test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> Standard Controls: 7 Private Controls: 0
>
> Format ioctls (Input 0):
> test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
> test VIDIOC_G/S_PARM: OK (Not Supported)
> test VIDIOC_G_FBUF: OK (Not Supported)
> test VIDIOC_G_FMT: OK
> test VIDIOC_TRY_FMT: OK
> test VIDIOC_S_FMT: OK
> test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
> test Cropping: OK (Not Supported)
> test Composing: OK (Not Supported)
> test Scaling: OK
>
> Codec ioctls (Input 0):
> test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
> test VIDIOC_G_ENC_INDEX: OK (Not Supported)
> test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
>
> Buffer ioctls (Input 0):
> test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
> test VIDIOC_EXPBUF: OK
> test Requests: OK (Not Supported)
>
> Total for sun6i-video device /dev/video0: 45, Succeeded: 45, Failed: 0, Warnings: 0
>
> Changes since V1:
> - Add more details in the cover letter.
> - Add a test to get the clocks to avoid an error for the platform without MIPI
> CSI-2.
> - Add more details in the register assignations.
> - Removed the support of multiple virtual channels because there is only one
> channel support in the CSI driver.
>
> Kévin L'hôpital (4):
> media: sun6i-csi: Fix the bpp for 10-bit bayer formats
> media: sunxi: sun6i-csi: Move the sun6i_csi_dev structure to the
> common header
> media: sunxi: sun6i-csi: Add support of MIPI CSI-2 for A83T
> ARM: dts: sun8i: a83t: Add support for the MIPI CSI-2 in CSI node
>
> arch/arm/boot/dts/sun8i-a83t.dtsi | 11 +-
> .../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 96 +++++---
> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 14 +-
> .../sunxi/sun6i-csi/sun8i_a83t_dphy.c | 39 ++++
> .../sunxi/sun6i-csi/sun8i_a83t_dphy.h | 16 ++
> .../sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h | 39 ++++
> .../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c | 217 ++++++++++++++++++
> .../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h | 16 ++
> .../sun6i-csi/sun8i_a83t_mipi_csi2_reg.h | 179 +++++++++++++++
> 10 files changed, 595 insertions(+), 34 deletions(-)
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
>
> --
> 2.17.1
>

--
Paul Kocialkowski, Bootlin
Embedded Linux and kernel engineering
https://bootlin.com


Attachments:
(No filename) (15.80 kB)
signature.asc (499.00 B)
Download all attachments

2020-08-31 10:48:15

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH v2 1/4] media: sun6i-csi: Fix the bpp for 10-bit bayer formats

Hi K?vin,

Thanks for the patch.

On Fri, Aug 28, 2020 at 03:17:33PM +0200, K?vin L'h?pital wrote:
> 10-bit bayer formats are aligned to 16 bits in memory, so this is what
> needs to be used as bpp for calculating the size of the buffers to
> allocate.
> This function is only used to generate the number of bytes per line.
>
> Fixes: 5cc7522d8965 ("media: sun6i: Add support for Allwinner CSI V3s")
> Signed-off-by: K?vin L'h?pital <[email protected]>
> ---
> drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> index c626821aaedb..8b83d15de0d0 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h
> @@ -100,7 +100,7 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat)
> case V4L2_PIX_FMT_SGBRG10:
> case V4L2_PIX_FMT_SGRBG10:
> case V4L2_PIX_FMT_SRGGB10:
> - return 10;
> + return 16;

Does the same also apply to the 12-bit formats below?

> case V4L2_PIX_FMT_SBGGR12:
> case V4L2_PIX_FMT_SGBRG12:
> case V4L2_PIX_FMT_SGRBG12:

--
Sakari Ailus

2020-08-31 11:30:11

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] media: sunxi: sun6i-csi: Add support of MIPI CSI-2 for A83T

Hi K?vin,

On Fri, Aug 28, 2020 at 03:17:35PM +0200, K?vin L'h?pital wrote:
> This patch add the support only for the Allwinner A83T MIPI CSI-2.
> Currently, the driver does not support the V3s MIPI CSI-2 controller.
> On the A83T, the CSI controller is the same as the other V3s Soc, but
> the MIPI CSI2 controller is not.
>
> It was tested with the ov8865 image sensor.
>
> Signed-off-by: K?vin L'h?pital <[email protected]>
> ---
> .../media/platform/sunxi/sun6i-csi/Makefile | 2 +-
> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++--
> .../sunxi/sun6i-csi/sun8i_a83t_dphy.c | 39 ++++
> .../sunxi/sun6i-csi/sun8i_a83t_dphy.h | 16 ++
> .../sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h | 39 ++++
> .../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c | 217 ++++++++++++++++++
> .../sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h | 16 ++
> .../sun6i-csi/sun8i_a83t_mipi_csi2_reg.h | 179 +++++++++++++++
> 8 files changed, 575 insertions(+), 17 deletions(-)
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
> create mode 100644 drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
>
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/Makefile b/drivers/media/platform/sunxi/sun6i-csi/Makefile
> index e7e315347804..0f3849790463 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/Makefile
> +++ b/drivers/media/platform/sunxi/sun6i-csi/Makefile
> @@ -1,4 +1,4 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -sun6i-csi-y += sun6i_video.o sun6i_csi.o
> +sun6i-csi-y += sun6i_video.o sun6i_csi.o sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o
>
> obj-$(CONFIG_VIDEO_SUN6I_CSI) += sun6i-csi.o
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> index 680fa31f380a..cf346e536959 100644
> --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
> @@ -26,6 +26,7 @@
>
> #include "sun6i_csi.h"
> #include "sun6i_csi_reg.h"
> +#include "sun8i_a83t_mipi_csi2.h"
>
> #define MODULE_NAME "sun6i-csi"
>
> @@ -160,10 +161,14 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
> regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
>
> clk_disable_unprepare(sdev->clk_ram);
> +
> if (of_device_is_compatible(dev->of_node,
> "allwinner,sun50i-a64-csi"))
> clk_rate_exclusive_put(sdev->clk_mod);
> clk_disable_unprepare(sdev->clk_mod);
> + if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
> + sun6i_mipi_csi_clk_disable(csi);
> +
> reset_control_assert(sdev->rstc_bus);
> return 0;
> }
> @@ -189,10 +194,18 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
> goto clk_ram_disable;
> }
>
> + if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
> + ret = sun6i_mipi_csi_clk_enable(csi);
> + if (ret)
> + goto reset_control_assert;
> + }
> +
> regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
>
> return 0;
>
> +reset_control_assert:
> + reset_control_assert(sdev->rstc_bus);
> clk_ram_disable:
> clk_disable_unprepare(sdev->clk_ram);
> clk_mod_disable:
> @@ -421,27 +434,34 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
> if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
> cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
> break;
> + case V4L2_MBUS_CSI2_DPHY:
> + cfg |= CSI_IF_CFG_MIPI_IF_MIPI;
> + sun6i_mipi_csi_setup_bus(csi);
> + break;
> default:
> dev_warn(sdev->dev, "Unsupported bus type: %d\n",
> endpoint->bus_type);
> break;
> }
>
> - switch (bus_width) {
> - case 8:
> - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
> - break;
> - case 10:
> - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
> - break;
> - case 12:
> - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
> - break;
> - case 16: /* No need to configure DATA_WIDTH for 16bit */
> - break;
> - default:
> - dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
> - break;
> + /* Bus width only applies to parallel bus. */
> + if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) {
> + switch (bus_width) {
> + case 8:
> + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
> + break;
> + case 10:
> + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
> + break;
> + case 12:
> + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
> + break;
> + case 16: /* No need to configure DATA_WIDTH for 16bit */
> + break;
> + default:
> + dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
> + break;
> + }
> }
>
> regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
> @@ -593,6 +613,9 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
> struct regmap *regmap = sdev->regmap;
>
> if (!enable) {
> + if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
> + sun6i_mipi_csi_set_stream(csi, 0);
> +
> regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
> regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
> return;
> @@ -609,6 +632,9 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
>
> regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
> CSI_CAP_CH0_VCAP_ON);
> +
> + if (csi->v4l2_ep.bus_type == V4L2_MBUS_CSI2_DPHY)
> + sun6i_mipi_csi_set_stream(csi, 1);
> }
>
> /* -----------------------------------------------------------------------------
> @@ -685,6 +711,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
> struct v4l2_async_subdev *asd)
> {
> struct sun6i_csi *csi = dev_get_drvdata(dev);
> + struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
>
> if (vep->base.port || vep->base.id) {
> dev_warn(dev, "Only support a single port with one endpoint\n");
> @@ -692,6 +719,17 @@ static int sun6i_csi_fwnode_parse(struct device *dev,
> }
>
> switch (vep->bus_type) {
> + case V4L2_MBUS_CSI2_DPHY:
> + if (!sdev->clk_mipi) {
> + dev_err(sdev->dev, "Use MIPI-CSI2 device with no MIPI clock\n");
> + return -ENOTCONN;
> + }
> + if (!sdev->clk_misc) {
> + dev_err(sdev->dev, "Use MIPI-CSI2 device with no misc clock\n");
> + return -ENOTCONN;
> + }
> + csi->v4l2_ep = *vep;
> + return 0;
> case V4L2_MBUS_PARALLEL:
> case V4L2_MBUS_BT656:
> csi->v4l2_ep = *vep;
> @@ -812,12 +850,13 @@ static const struct regmap_config sun6i_csi_regmap_config = {
> .reg_bits = 32,
> .reg_stride = 4,
> .val_bits = 32,
> - .max_register = 0x9c,
> + .max_register = 0x2000,
> };
>
> static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
> struct platform_device *pdev)
> {
> + struct device *dev = sdev->dev;
> struct resource *res;
> void __iomem *io_base;
> int ret;
> @@ -847,6 +886,19 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
> return PTR_ERR(sdev->clk_ram);
> }
>
> + if (of_device_is_compatible(dev->of_node, "allwinner,sun8i-a83t-csi")) {

It'd be cleaner to rely on of_device_get_match_data() attached to a
compatible string instead.

> + sdev->clk_mipi = devm_clk_get(&pdev->dev, "mipi");
> + if (IS_ERR(sdev->clk_mipi)) {
> + sdev->clk_mipi = NULL;
> + dev_warn(&pdev->dev, "Unable to acquire mipi clock. No mipi support\n");
> + }
> +
> + sdev->clk_misc = devm_clk_get(&pdev->dev, "misc");
> + if (IS_ERR(sdev->clk_misc)) {
> + sdev->clk_misc = NULL;
> + dev_warn(&pdev->dev, "Unable to acquire misc clock. No mipi support\n");
> + }
> + }
> sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
> if (IS_ERR(sdev->rstc_bus)) {
> dev_err(&pdev->dev, "Cannot get reset controller\n");
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
> new file mode 100644
> index 000000000000..bb9599c3bde9
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.c
> @@ -0,0 +1,39 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * sun6i_dphy.c
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#include "sun8i_a83t_dphy.h"
> +#include "sun8i_a83t_dphy_reg.h"
> +
> +/* First initialization to turn on the dphy for the MIPI CSI2 controller
> + * initialization.
> + */
> +
> +void sun6i_dphy_first_init(struct sun6i_csi_dev *sdev)
> +{
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_DBG,
> + DPHY_CTRL_REG_DBG);
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_SHUT, 0);
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_RSTN,
> + DPHY_CTRL_REG_RSTN);
> +}
> +
> +/* Second initialization to turn off the dphy and do its initialization. */
> +void sun6i_dphy_second_init(struct sun6i_csi_dev *sdev)
> +{
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_DBG, 0);
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_SHUT,
> + DPHY_CTRL_REG_SHUT);
> + regmap_update_bits(sdev->regmap, DPHY_CTRL_REG, DPHY_CTRL_REG_RSTN,
> + DPHY_CTRL_REG_RSTN);
> + regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_SNK_MASK,
> + DPHY_ANA0_REG_SNK(0x02));
> + regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_RINT_MASK,
> + DPHY_ANA0_REG_RINT(0x02));
> + regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_REXT, 0);
> + regmap_update_bits(sdev->regmap, DPHY_ANA0_REG, DPHY_ANA0_REG_ENREXT,
> + DPHY_ANA0_REG_ENREXT);
> +}
> +
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
> new file mode 100644
> index 000000000000..f776ed098cb3
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * sun6i_dphy.h
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#ifndef __SUN8I_A83T_DPHY_H__
> +#define __SUN8I_A83T_DPHY_H__
> +
> +#include <linux/regmap.h>
> +#include "sun6i_csi.h"
> +
> +void sun6i_dphy_first_init(struct sun6i_csi_dev *sdev);
> +void sun6i_dphy_second_init(struct sun6i_csi_dev *sdev);
> +
> +#endif /* __SUN8I_A83T_DPHY_H__ */
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
> new file mode 100644
> index 000000000000..815692b112d2
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_dphy_reg.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Allwinner A83t DPHY register description
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#ifndef __SUN8I_A83T_DPHY_REG_H__
> +#define __SUN8I_A83T_DPHY_REG_H__
> +
> +
> +#define DPHY_OFFSET 0x1000
> +
> +#define DPHY_CTRL_REG (DPHY_OFFSET + 0x010)
> +#define DPHY_CTRL_REG_RSTN BIT(31)
> +#define DPHY_CTRL_REG_SHUT BIT(15)
> +#define DPHY_CTRL_REG_DBG BIT(8)
> +
> +#define DPHY_STATUS_REG (DPHY_OFFSET + 0x014)
> +#define DPHY_STATUS_REG_CLK_STOP BIT(10)
> +#define DPHY_STATUS_REG_CLK_UPLS BIT(9)
> +#define DPHY_STATUS_REG_HSCLK BIT(8)
> +#define DPHY_STATUS_REG_D3_STOP BIT(7)
> +#define DPHY_STATUS_REG_D2_STOP BIT(6)
> +#define DPHY_STATUS_REG_D1_STOP BIT(5)
> +#define DPHY_STATUS_REG_D0_STOP BIT(4)
> +#define DPHY_STATUS_REG_D3_UPLS BIT(3)
> +#define DPHY_STATUS_REG_D2_UPLS BIT(2)
> +#define DPHY_STATUS_REG_D1_UPLS BIT(1)
> +#define DPHY_STATUS_REG_D0_UPLS BIT(0)
> +
> +#define DPHY_ANA0_REG (DPHY_OFFSET + 0x030)
> +#define DPHY_ANA0_REG_ENREXT BIT(31)
> +#define DPHY_ANA0_REG_REXT BIT(30)
> +#define DPHY_ANA0_REG_RINT_MASK GENMASK(29, 28)
> +#define DPHY_ANA0_REG_RINT(v) ((v) << 28)
> +#define DPHY_ANA0_REG_SNK_MASK GENMASK(22, 20)
> +#define DPHY_ANA0_REG_SNK(v) ((v) << 20)
> +
> +#endif /* __SUN8I_A83T_DPHY_REG_H__ */
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
> new file mode 100644
> index 000000000000..2933238cbc95
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.c
> @@ -0,0 +1,217 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Allwinner A83t MIPI Camera Sensor Interface 2 driver
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#include <linux/clk.h>
> +#include "sun8i_a83t_mipi_csi2.h"
> +#include "sun8i_a83t_mipi_csi2_reg.h"
> +#include "sun8i_a83t_dphy.h"
> +#include <linux/delay.h>
> +
> +#define IS_FLAG(x, y) (((x) & (y)) == y)
> +
> +enum mipi_csi2_pkt_fmt {
> + MIPI_FS = 0X00,
> + MIPI_FE = 0X01,
> + MIPI_LS = 0X02,
> + MIPI_LE = 0X03,
> + MIPI_SDAT0 = 0X08,
> + MIPI_SDAT1 = 0X09,
> + MIPI_SDAT2 = 0X0A,
> + MIPI_SDAT3 = 0X0B,
> + MIPI_SDAT4 = 0X0C,
> + MIPI_SDAT5 = 0X0D,
> + MIPI_SDAT6 = 0X0E,
> + MIPI_SDAT7 = 0X0F,
> + MIPI_BLK = 0X11,
> + MIPI_EMBD = 0X12,
> + MIPI_YUV420 = 0X18,
> + MIPI_YUV420_10 = 0X19,
> + MIPI_YUV420_CSP = 0X1C,
> + MIPI_YUV420_CSP_10 = 0X1D,
> + MIPI_YUV422 = 0X1E,
> + MIPI_YUV422_10 = 0X1F,
> + MIPI_RGB565 = 0X22,
> + MIPI_RGB888 = 0X24,
> + MIPI_RAW8 = 0X2A,
> + MIPI_RAW10 = 0X2B,
> + MIPI_RAW12 = 0X2C,
> + MIPI_USR_DAT0 = 0X30,
> + MIPI_USR_DAT1 = 0X31,
> + MIPI_USR_DAT2 = 0X32,
> + MIPI_USR_DAT3 = 0X33,
> + MIPI_USR_DAT4 = 0X34,
> + MIPI_USR_DAT5 = 0X35,
> + MIPI_USR_DAT6 = 0X36,
> + MIPI_USR_DAT7 = 0X37,
> +};
> +
> +static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
> +{
> + return container_of(csi, struct sun6i_csi_dev, csi);
> +}
> +
> +static enum mipi_csi2_pkt_fmt get_pkt_fmt(u16 bus_pix_code)
> +{
> + switch (bus_pix_code) {
> + case MEDIA_BUS_FMT_RGB565_1X16:
> + return MIPI_RGB565;
> + case MEDIA_BUS_FMT_UYVY8_2X8:
> + case MEDIA_BUS_FMT_UYVY8_1X16:
> + return MIPI_YUV422;
> + case MEDIA_BUS_FMT_UYVY10_2X10:
> + return MIPI_YUV422_10;
> + case MEDIA_BUS_FMT_RGB888_1X24:
> + return MIPI_RGB888;
> + case MEDIA_BUS_FMT_SBGGR8_1X8:
> + case MEDIA_BUS_FMT_SGBRG8_1X8:
> + case MEDIA_BUS_FMT_SGRBG8_1X8:
> + case MEDIA_BUS_FMT_SRGGB8_1X8:
> + return MIPI_RAW8;
> + case MEDIA_BUS_FMT_SBGGR10_1X10:
> + case MEDIA_BUS_FMT_SGBRG10_1X10:
> + case MEDIA_BUS_FMT_SGRBG10_1X10:
> + case MEDIA_BUS_FMT_SRGGB10_1X10:
> + return MIPI_RAW10;
> + case MEDIA_BUS_FMT_SBGGR12_1X12:
> + case MEDIA_BUS_FMT_SGBRG12_1X12:
> + case MEDIA_BUS_FMT_SGRBG12_1X12:
> + case MEDIA_BUS_FMT_SRGGB12_1X12:
> + return MIPI_RAW12;
> + default:
> + return MIPI_RAW8;
> + }
> +}
> +
> +void sun6i_mipi_csi_set_stream(struct sun6i_csi *csi, bool enable)
> +{
> + struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
> +
> + if (enable)
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_EN,
> + MIPI_CSI2_CFG_REG_SYNC_EN);
> + else
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_EN, 0);
> +}
> +
> +void sun6i_mipi_csi_init(struct sun6i_csi_dev *sdev)
> +{
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CTRL_REG,
> + MIPI_CSI2_CTRL_REG_RSTN, MIPI_CSI2_CTRL_REG_RSTN);
> + regmap_write(sdev->regmap, MIPI_CSI2_RX_PKT_NUM_REG, 0xb8d257f8);
> + sun6i_dphy_first_init(sdev);
> + regmap_write(sdev->regmap, MIPI_CSI2_RSVD1_REG,
> + HW_LOCK_REGISTER_VALUE_1);
> + regmap_write(sdev->regmap, MIPI_CSI2_RSVD2_REG,
> + HW_LOCK_REGISTER_VALUE_2);
> + regmap_write(sdev->regmap, MIPI_CSI2_RX_PKT_NUM_REG, 0);
> + regmap_write(sdev->regmap, MIPI_CSI2_VCDT0_REG, 0);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK,
> + MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(0x11));
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_N_BYTE, 0);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_YC_SWAB, 0);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE,
> + MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_UNPKT_EN,
> + MIPI_CSI2_CFG_REG_UNPKT_EN);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_BYPASS_ECC_EN,
> + MIPI_CSI2_CFG_REG_BYPASS_ECC_EN);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_EN,
> + MIPI_CSI2_CFG_REG_SYNC_EN);
> + sun6i_dphy_second_init(sdev);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CTRL_REG,
> + MIPI_CSI2_CTRL_REG_RSTN, MIPI_CSI2_CTRL_REG_RSTN);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK,
> + MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(0x08));
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE, 0);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_BYPASS_ECC_EN, 0);
> + regmap_update_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_SYNC_EN, 0);
> +}
> +
> +void sun6i_mipi_csi_setup_bus(struct sun6i_csi *csi)
> +{
> + struct v4l2_fwnode_endpoint *endpoint = &csi->v4l2_ep;
> + struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
> + int lane_num = endpoint->bus.mipi_csi2.num_data_lanes;
> + int flags = endpoint->bus.mipi_csi2.flags;
> + int total_rx_ch = 0;
> + int vc;
> +
> + sun6i_mipi_csi_init(sdev);
> +
> + if (IS_FLAG(flags, V4L2_MBUS_CSI2_CHANNEL_0)) {
> + vc = 0;
> + total_rx_ch++;
> + }
> +
> + if (!total_rx_ch) {
> + dev_dbg(sdev->dev,
> + "No receive channel assigned, using channel 0.\n");
> + vc = 0;
> + total_rx_ch++;
> + }
> + /* Set lane. */
> + regmap_write_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_N_LANE_MASK, (lane_num - 1) <<
> + MIPI_CSI2_CFG_REG_N_LANE_SHIFT);
> + /* Set total channels. */
> + regmap_write_bits(sdev->regmap, MIPI_CSI2_CFG_REG,
> + MIPI_CSI2_CFG_REG_N_CHANNEL_MASK, (total_rx_ch - 1) <<
> + MIPI_CSI2_CFG_REG_N_CHANNEL_SHIFT);
> +
> + regmap_write_bits(sdev->regmap, MIPI_CSI2_VCDT0_REG,
> + MIPI_CSI2_VCDT0_REG_CH0_DT_MASK,
> + get_pkt_fmt(csi->config.code));
> + regmap_write_bits(sdev->regmap, MIPI_CSI2_VCDT0_REG,
> + MIPI_CSI2_VCDT0_REG_CH0_VC_MASK,
> + vc << MIPI_CSI2_VCDT0_REG_CH0_VC_SHIFT);
> +}
> +
> +int sun6i_mipi_csi_clk_enable(struct sun6i_csi *csi)
> +{
> + struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
> + int ret;
> +
> + ret = clk_prepare_enable(sdev->clk_mipi);
> + if (ret) {
> + dev_err(sdev->dev, "Enable clk_mipi clk err %d\n", ret);
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(sdev->clk_misc);
> + if (ret) {
> + dev_err(sdev->dev, "Enable clk_misc clk err %d\n", ret);
> + goto clk_mipi_disable;
> + }
> +
> + return 0;
> +
> +clk_mipi_disable:
> + clk_disable_unprepare(sdev->clk_mipi);
> + return ret;
> +}
> +
> +void sun6i_mipi_csi_clk_disable(struct sun6i_csi *csi)
> +{
> + struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
> +
> + clk_disable_unprepare(sdev->clk_misc);
> + clk_disable_unprepare(sdev->clk_mipi);
> +}
> +
> +
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
> new file mode 100644
> index 000000000000..a94c69ccee39
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#ifndef __SUN8I_A83T_MIPI_CSI2_H__
> +#define __SUN8I_A83T_MIPI_CSI2_H__
> +#include <linux/regmap.h>
> +#include "sun6i_csi.h"
> +
> +void sun6i_mipi_csi_set_stream(struct sun6i_csi *csi, bool enable);
> +void sun6i_mipi_csi_setup_bus(struct sun6i_csi *csi);
> +int sun6i_mipi_csi_clk_enable(struct sun6i_csi *csi);
> +void sun6i_mipi_csi_clk_disable(struct sun6i_csi *csi);
> +
> +#endif /* __SUN8I_A83T_MIPI_CSI2_H__ */
> diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
> new file mode 100644
> index 000000000000..43cc46ea1aec
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/sun6i-csi/sun8i_a83t_mipi_csi2_reg.h
> @@ -0,0 +1,179 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Allwinner A83t MIPI CSI-2 register description
> + * Copyright K?vin L'h?pital (C) 2020
> + */
> +
> +#ifndef __SUN8I_A83T_MIPI_CSI2_REG_H__
> +#define __SUN8I_A83T_MIPI_CSI2_REG_H__
> +
> +
> +#define MIPI_CSI2_OFFSET 0x1000
> +
> +#define MIPI_CSI2_VERSION_REG (MIPI_CSI2_OFFSET + 0x000)
> +#define MIPI_CSI2_CTRL_REG (MIPI_CSI2_OFFSET + 0x004)
> +#define MIPI_CSI2_CTRL_REG_RSTN BIT(31)
> +
> +#define MIPI_CSI2_RX_PKT_NUM_REG (MIPI_CSI2_OFFSET + 0x008)
> +#define MIPI_CSI2_RSVD0_REG (MIPI_CSI2_OFFSET + 0x00c)
> +
> +#define MIPI_CSI2_RSVD1_REG (MIPI_CSI2_OFFSET + 0x018)
> +/* Value found in the BSP and need to be present but it is not describe in the
> + * datasheet.
> + */
> +#define HW_LOCK_REGISTER_VALUE_1 0xb8c8a30c
> +#define MIPI_CSI2_RSVD2_REG (MIPI_CSI2_OFFSET + 0x01c)
> +/* Value found in the BSP and need to be present but it is not describe in the
> + * datasheet.
> + */
> +#define HW_LOCK_REGISTER_VALUE_2 0xb8df8ad7
> +
> +#define MIPI_CSI2_INT_STA0_REG (MIPI_CSI2_OFFSET + 0x020)
> +#define MIPI_CSI2_INT_STA0_REG_ECC_ERR_DBL BIT(28)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC3 BIT(27)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC2 BIT(26)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC1 BIT(25)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_CKSM_ERR_VC0 BIT(24)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT3 BIT(23)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT2 BIT(22)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT1 BIT(21)
> +#define MIPI_CSI2_INT_STA0_REG_LINE_SEQ_ERR_DT0 BIT(20)
> +#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT3 BIT(19)
> +#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT2 BIT(18)
> +#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT1 BIT(17)
> +#define MIPI_CSI2_INT_STA0_REG_LS_LE_ERR_DT0 BIT(16)
> +#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC3 BIT(15)
> +#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC2 BIT(14)
> +#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC1 BIT(13)
> +#define MIPI_CSI2_INT_STA0_REG_CRC_ERR_VC0 BIT(12)
> +#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC3 BIT(11)
> +#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC2 BIT(10)
> +#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC1 BIT(9)
> +#define MIPI_CSI2_INT_STA0_REG_FRM_SEQ_ERR_VC0 BIT(8)
> +#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC3 BIT(7)
> +#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC2 BIT(6)
> +#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC1 BIT(5)
> +#define MIPI_CSI2_INT_STA0_REG_FS_FE_ERR_VC0 BIT(4)
> +#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_3 BIT(3)
> +#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_2 BIT(2)
> +#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_1 BIT(1)
> +#define MIPI_CSI2_INT_STA0_REG_SOT_SYNC_ERR_0 BIT(0)
> +
> +#define MIPI_CSI2_INT_STA1_REG (MIPI_CSI2_OFFSET + 0x024)
> +#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT7 BIT(23)
> +#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT6 BIT(22)
> +#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT5 BIT(21)
> +#define MIPI_CSI2_INT_STA1_REG_LINE_SEQ_ERR_DT4 BIT(20)
> +#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT7 BIT(19)
> +#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT6 BIT(18)
> +#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT5 BIT(17)
> +#define MIPI_CSI2_INT_STA1_REG_LS_LE_ERR_DT4 BIT(16)
> +#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC3 BIT(15)
> +#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC2 BIT(14)
> +#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC1 BIT(13)
> +#define MIPI_CSI2_INT_STA1_REG_DT_ERR_VC0 BIT(12)
> +#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC3 BIT(11)
> +#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC2 BIT(10)
> +#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC1 BIT(9)
> +#define MIPI_CSI2_INT_STA1_REG_ECC_ERR1_VC0 BIT(8)
> +#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_3 BIT(7)
> +#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_2 BIT(6)
> +#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_1 BIT(5)
> +#define MIPI_CSI2_INT_STA1_REG_SOT_ERR_0 BIT(4)
> +#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_3 BIT(3)
> +#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_2 BIT(2)
> +#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_1 BIT(1)
> +#define MIPI_CSI2_INT_STA1_REG_ESC_ENTRY_ERR_0 BIT(0)
> +
> +#define MIPI_CSI2_INT_MSK0_REG (MIPI_CSI2_OFFSET + 0x028)
> +#define MIPI_CSI2_INT_MSK0_REG_ECC_ERR_DBL_MSK BIT(28)
> +#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC3_MSK BIT(27)
> +#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC2_MSK BIT(26)
> +#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC1_MSK BIT(25)
> +#define MIPI_CSI2_INT_MSK0_REG_CKSM_ERR_VC0_MSK BIT(24)
> +#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT3_MSK BIT(23)
> +#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT2_MSK BIT(22)
> +#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT1_MSK BIT(21)
> +#define MIPI_CSI2_INT_MSK0_REG_LINE_SEQ_ERR_DT0_MSK BIT(20)
> +#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT3_MSK BIT(19)
> +#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT2_MSK BIT(18)
> +#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT1_MSK BIT(17)
> +#define MIPI_CSI2_INT_MSK0_REG_LS_LE_ERR_DT0_MSK BIT(16)
> +#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC3_MSK BIT(15)
> +#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC2_MSK BIT(14)
> +#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC1_MSK BIT(13)
> +#define MIPI_CSI2_INT_MSK0_REG_CRC_ERR_VC0_MSK BIT(12)
> +#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC3_MSK BIT(11)
> +#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC2_MSK BIT(10)
> +#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC1_MSK BIT(9)
> +#define MIPI_CSI2_INT_MSK0_REG_FRM_SEQ_ERR_VC0_MSK BIT(8)
> +#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC3_MSK BIT(7)
> +#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC2_MSK BIT(6)
> +#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC1_MSK BIT(5)
> +#define MIPI_CSI2_INT_MSK0_REG_FS_FE_ERR_VC0_MSK BIT(4)
> +#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_3_MSK BIT(3)
> +#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_2_MSK BIT(2)
> +#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_1_MSK BIT(1)
> +#define MIPI_CSI2_INT_MSK0_REG_SOT_SYNC_ERR_0_MSK BIT(0)
> +
> +#define MIPI_CSI2_INT_MSK1_REG (MIPI_CSI2_OFFSET + 0x02c)
> +#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC3_MSK BIT(15)
> +#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC2_MSK BIT(14)
> +#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC1_MSK BIT(13)
> +#define MIPI_CSI2_INT_MSK1_REG_DT_ERR_VC0_MSK BIT(12)
> +#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC3_MSK BIT(11)
> +#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC2_MSK BIT(10)
> +#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC1_MSK BIT(9)
> +#define MIPI_CSI2_INT_MSK1_REG_ECC_ERR1_VC0_MSK BIT(8)
> +#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_3_MSK BIT(7)
> +#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_2_MSK BIT(6)
> +#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_1_MSK BIT(5)
> +#define MIPI_CSI2_INT_MSK1_REG_SOT_ERR_0_MSK BIT(4)
> +#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_3_MSK BIT(3)
> +#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_2_MSK BIT(2)
> +#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_1_MSK BIT(1)
> +#define MIPI_CSI2_INT_MSK1_REG_ESC_ENTRY_ERR_0_MSK BIT(0)
> +
> +#define MIPI_CSI2_CFG_REG (MIPI_CSI2_OFFSET + 0x100)
> +#define MIPI_CSI2_CFG_REG_SYNC_EN BIT(31)
> +#define MIPI_CSI2_CFG_REG_BYPASS_ECC_EN BIT(29)
> +#define MIPI_CSI2_CFG_REG_UNPKT_EN BIT(28)
> +#define MIPI_CSI2_CFG_REG_NONE_UNPKT_RX_MODE BIT(27)
> +#define MIPI_CSI2_CFG_REG_YC_SWAB BIT(26)
> +#define MIPI_CSI2_CFG_REG_N_BYTE BIT(24)
> +#define MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE(v) ((v) << 18)
> +#define MIPI_CSI2_CFG_REG_SYNC_DLY_CYCLE_MASK GENMASK(22, 18)
> +#define MIPI_CSI2_CFG_REG_N_CHANNEL_MASK GENMASK(17, 16)
> +#define MIPI_CSI2_CFG_REG_N_CHANNEL_SHIFT 16
> +#define MIPI_CSI2_CFG_REG_N_LANE_MASK GENMASK(5, 4)
> +#define MIPI_CSI2_CFG_REG_N_LANE_SHIFT 4
> +
> +#define MIPI_CSI2_VCDT0_REG (MIPI_CSI2_OFFSET + 0x104)
> +#define MIPI_CSI2_VCDT0_REG_DEFAULT 0xc0804000
> +#define MIPI_CSI2_VCDT0_REG_CH3_VC_MASK GENMASK(31, 30)
> +#define MIPI_CSI2_VCDT0_REG_CH3_VC_SHIFT 30
> +#define MIPI_CSI2_VCDT0_REG_CH3_DT_MASK GENMASK(29, 24)
> +#define MIPI_CSI2_VCDT0_REG_CH3_DT_SHIFT 24
> +#define MIPI_CSI2_VCDT0_REG_CH2_VC_MASK GENMASK(23, 22)
> +#define MIPI_CSI2_VCDT0_REG_CH2_VC_SHIFT 22
> +#define MIPI_CSI2_VCDT0_REG_CH2_DT_MASK GENMASK(21, 16)
> +#define MIPI_CSI2_VCDT0_REG_CH2_DT_SHIFT 16
> +#define MIPI_CSI2_VCDT0_REG_CH1_VC_MASK GENMASK(15, 14)
> +#define MIPI_CSI2_VCDT0_REG_CH1_VC_SHIFT 14
> +#define MIPI_CSI2_VCDT0_REG_CH1_DT_MASK GENMASK(13, 8)
> +#define MIPI_CSI2_VCDT0_REG_CH1_DT_SHIFT 8
> +#define MIPI_CSI2_VCDT0_REG_CH0_VC_MASK GENMASK(7, 6)
> +#define MIPI_CSI2_VCDT0_REG_CH0_VC_SHIFT 6
> +#define MIPI_CSI2_VCDT0_REG_CH0_DT_MASK GENMASK(5, 0)
> +
> +#define MIPI_CSI2_VCDT1_REG (MIPI_CSI2_OFFSET + 0x108)
> +#define MIPI_CSI2_VCDT1_REG_CH7_VC_MASK GENMASK(31, 30)
> +#define MIPI_CSI2_VCDT1_REG_CH7_DT_MASK GENMASK(29, 24)
> +#define MIPI_CSI2_VCDT1_REG_CH6_VC_MASK GENMASK(23, 22)
> +#define MIPI_CSI2_VCDT1_REG_CH6_DT_MASK GENMASK(21, 16)
> +#define MIPI_CSI2_VCDT1_REG_CH5_VC_MASK GENMASK(15, 14)
> +#define MIPI_CSI2_VCDT1_REG_CH5_DT_MASK GENMASK(13, 8)
> +#define MIPI_CSI2_VCDT1_REG_CH4_VC_MASK GENMASK(7, 6)
> +#define MIPI_CSI2_VCDT1_REG_CH4_DT_MASK GENMASK(5, 0)
> +
> +#endif /* __SUN8I_A83T_MIPI_CSI2_REG_H__ */

--
Kind regards,

Sakari Ailus

2020-08-31 13:07:55

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH v2 0/4] Support of MIPI CSI-2 for A83T

Hi Paul,

On Fri, Aug 28, 2020 at 04:12:03PM +0200, Paul Kocialkowski wrote:
> Hi everyone,
>
> On Fri 28 Aug 20, 15:17, K?vin L'h?pital wrote:
> > This series adds the support for the MIPI CSI-2 controller for the A83T SoC.
> > The CSI controller is the same as the V3s SoC that's why I put the A83T
> > MIPI CSI-2 driver in sun6i-csi.
> > My work is based on the Allwinner BSP for A83T and also on MIPI CSI-2
> > specification for the A83T given by Allwinner.
>
> To give a bit of context here, Kevin is our intern who worked on MIPI CSI-2
> support on the A83t this summer. As we were approaching the end of the
> internship, we wanted to publish the current state of the work as a working
> reference and base for mainline support.
>
> However, we are well aware that there are significant design issues in this
> series, such as:
> - not supporting the fwnode graph;
> - not working with the DPHY API;
> - adding MIPI CSI-2 support under the same dt compatible as parallel CSI;
>
> and probably other things.
>
> Bootlin is currently working on V3s MIPI CSI-2 support and we intend to respin
> this series when submitting V3s MIPI CSI-2 support, with fixes to these design
> issues.

It's great to have that clarification, but it really doesn't address any
of the questions I had in the v1:

> There's a bunch of things that would need to be explained and / or
> argued for here, in particular:
> - Why did you need to plumb it into sun6i-csi?
> - You're naming the CSI part as the A83t CSI, while MIPI-CSI has been
> supported since the A31(?), is there a reason for that?
> - This is not documented anywhere, what did you base this work on?

You're also mentioning the v3s, without really stating why this driver
wouldn't be able to drive it.

> So we hope you keep this in mind when reviewing the series, which is
> not meant to be merged in its current state.

I mean, if the current code needs to be redesigned, and you provide no
details whatsoever on the hardware, I'm not really sure what kind of
input you're expecting.

Maxime


Attachments:
(No filename) (2.06 kB)
signature.asc (235.00 B)
Download all attachments