pinctrl-0 = <&i2c4_pins>;
status = "okay";
- ov5640: ov5640@3c {
- compatible = "ovti,ov5640";
- reg = <0x3c>;
- clocks = <&clk_ext_camera>;
- clock-names = "xclk";
- //DOVDD-supply = <&v2v8>;
- rotation = <180>;
- port {
- // Parallel bus endpoint
- ov5640_to_parallel: endpoint {
- remote-endpoint = <¶llel_from_ov5640>;
- bus-type = <5>; /* Parallel */
- bus-width = <8>;
- data-shift = <2>; /* lines 13:6 are used */
- hsync-active = <0>;
- vsync-active = <1>;
- pclk-sample = <1>;
- };
- };
- };
-
sc2235: sc2235@30 {
compatible = "sc2235";
reg = <0x30>;
};
};
- ov13850@10 {
- compatible = "ovti,ov13850";
+ imx219@10 {
+ compatible = "imx219";
reg = <0x10>;
clocks = <&clk_ext_camera>;
clock-names = "xclk";
//reset-gpio = <&gpio 18 0>;
+ //DOVDD-supply = <&v2v8>;
rotation = <0>;
+ orientation = <1>; //CAMERA_ORIENTATION_BACK
port {
/* CSI2 bus endpoint */
- ov13850_to_csi2rx0: endpoint {
- remote-endpoint = <&csi2rx0_from_ov13850>;
+ imx219_to_csi2rx0: endpoint {
+ remote-endpoint = <&csi2rx0_from_imx219>;
bus-type = <4>; /* MIPI CSI-2 D-PHY */
- clock-lanes = <2>;
- data-lanes = <0 1>;
+ clock-lanes = <0>;
+ data-lanes = <2 1>;
+ lane-polarities = <1 1 1>;
+ link-frequencies = /bits/ 64 <456000000>;
};
};
};
#size-cells = <0>;
/* Parallel bus endpoint */
- parallel_from_ov5640: endpoint@0 {
+ parallel_from_sc2235: endpoint@0 {
reg = <0>;
- remote-endpoint = <&ov5640_to_parallel>;
- bus-type = <5>; /* Parallel */
- bus-width = <8>;
- data-shift = <2>; /* lines 9:2 are used */
- hsync-active = <1>;
- vsync-active = <0>;
- pclk-sample = <1>;
- status = "failed";
- };
-
- /* Parallel bus endpoint */
- parallel_from_sc2235: endpoint@1 {
- reg = <1>;
remote-endpoint = <&sc2235_to_parallel>;
bus-type = <5>; /* Parallel */
bus-width = <8>;
#size-cells = <0>;
/* CSI2 bus endpoint */
- csi2rx0_from_ov13850: endpoint@0 {
+ csi2rx0_from_ov4689: endpoint@0 {
reg = <0>;
- remote-endpoint = <&ov13850_to_csi2rx0>;
+ remote-endpoint = <&ov4689_to_csi2rx0>;
bus-type = <4>; /* MIPI CSI-2 D-PHY */
clock-lanes = <0>;
data-lanes = <1 2 3 4>;
- status = "failed";
+ status = "okay";
};
/* CSI2 bus endpoint */
- csi2rx0_from_ov4689: endpoint@1 {
+ csi2rx0_from_imx219: endpoint@1 {
reg = <1>;
- remote-endpoint = <&ov4689_to_csi2rx0>;
+ remote-endpoint = <&imx219_to_csi2rx0>;
bus-type = <4>; /* MIPI CSI-2 D-PHY */
clock-lanes = <0>;
- data-lanes = <1 2 3 4>;
+ data-lanes = <2 1>;
+ lane-polarities = <1 1 1>;
status = "okay";
};
};
reg = <1>;
remote-endpoint = <&hdmi_in_lcdc>;
};
-
+
dc_out_dpi2: endpoint@2 {
reg = <2>;
remote-endpoint = <&mipi_in>;
<0x0 0x19830000 0x0 0x10000>,
<0x0 0x19840000 0x0 0x10000>,
<0x0 0x19870000 0x0 0x30000>,
- <0x0 0x198a0000 0x0 0x30000>,
<0x0 0x11840000 0x0 0x10000>,
<0x0 0x17030000 0x0 0x10000>,
<0x0 0x13020000 0x0 0x10000>;
reg-names = "mipi0", "vclk", "vrst", "mipi1", "sctrl",
- "isp0", "isp1", "trst", "pmu", "syscrg";
+ "isp", "trst", "pmu", "syscrg";
clocks = <&clkisp JH7110_DOM4_APB_FUNC>,
<&clkisp JH7110_U0_VIN_PCLK>,
<&clkisp JH7110_U0_VIN_SYS_CLK>,
"rst_pixel_clk_if1", "rst_pixel_clk_if2", "rst_pixel_clk_if3",
"rst_m31dphy_hw", "rst_m31dphy_b09_always_on",
"rst_isp_top_n", "rst_isp_top_axi";
- interrupts = <92 87>;
power-domains = <&pwrc JH7110_PD_ISP>;
+ /* irq nr: vin, isp, isp_csi, isp_scd, isp_csiline */
+ interrupts = <92 87 88 89 90>;
status = "disabled";
};
CONFIG_VIDEO_STF_VIN=y
CONFIG_VIN_SENSOR_SC2235=y
CONFIG_VIN_SENSOR_OV4689=y
+CONFIG_VIN_SENSOR_IMX219=y
CONFIG_DRM=y
CONFIG_DRM_VERISILICON=y
CONFIG_STARFIVE_INNO_HDMI=y
#
# VIN sensor driver configuration
#
+
config VIN_SENSOR_OV5640
- bool "VIN SENSOR support OV5640"
+ tristate "VIN SENSOR support OV5640"
depends on VIDEO_STF_VIN
select V4L2_FWNODE
default n
Say Y here if you want to have support for VIN sensor OV5640
config VIN_SENSOR_SC2235
- bool "VIN SENSOR support SC2235"
+ tristate "VIN SENSOR support SC2235"
depends on VIDEO_STF_VIN
select V4L2_FWNODE
default n
Say Y here if you want to have support for VIN sensor SC2235
config VIN_SENSOR_OV4689
- bool "VIN SENSOR support OV4689"
+ tristate "VIN SENSOR support OV4689"
depends on VIDEO_STF_VIN
select V4L2_FWNODE
default n
select V4L2_FWNODE
default n
help
- Say Y here if you want to have support for VIN sensor OV13850
\ No newline at end of file
+ Say Y here if you want to have support for VIN sensor OV13850
+
+config VIN_SENSOR_IMX219
+ bool "VIN SENSOR support IMX219"
+ depends on VIDEO_STF_VIN
+ select V4L2_FWNODE
+ default n
+ help
+ Say Y here if you want to have support for VIN sensor IMX219
obj-$(CONFIG_VIN_SENSOR_SC2235) += v4l2_driver/sc2235.o
obj-$(CONFIG_VIN_SENSOR_OV4689) += v4l2_driver/ov4689_mipi.o
obj-$(CONFIG_VIN_SENSOR_OV13850) += v4l2_driver/ov13850_mipi.o
+obj-$(CONFIG_VIN_SENSOR_IMX219) += v4l2_driver/imx219_mipi.o
-obj-$(CONFIG_VIDEO_STF_VIN) += v4l2_driver/stfcamss.o \
+starfivecamss-objs += v4l2_driver/stfcamss.o \
v4l2_driver/stf_event.o \
v4l2_driver/stf_dvp.o \
v4l2_driver/stf_csi.o \
v4l2_driver/stf_csi_hw_ops.o \
v4l2_driver/stf_csiphy_hw_ops.o \
v4l2_driver/stf_isp_hw_ops.o \
- v4l2_driver/stf_dvp_hw_ops.o
+ v4l2_driver/stf_dvp_hw_ops.o \
+ v4l2_driver/stf_dmabuf.o
+
+
+obj-$(CONFIG_VIDEO_STF_VIN) += starfivecamss.o \
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Sony IMX219 cameras.
+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
+ *
+ * Based on Sony imx258 camera driver
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
+ * Copyright 2018 Qtechnology A/S
+ *
+ * Flip handling taken from the Sony IMX319 driver.
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <asm/unaligned.h>
+
+#define IMX219_REG_VALUE_08BIT 1
+#define IMX219_REG_VALUE_16BIT 2
+
+#define IMX219_REG_MODE_SELECT 0x0100
+#define IMX219_MODE_STANDBY 0x00
+#define IMX219_MODE_STREAMING 0x01
+
+/* Chip ID */
+#define IMX219_REG_CHIP_ID 0x0000
+#define IMX219_CHIP_ID 0x0219
+
+/* External clock frequency is 24.0M */
+#define IMX219_XCLK_FREQ 24000000
+
+/* Pixel rate is fixed at 182.4M for all the modes */
+#define IMX219_PIXEL_RATE 182400000
+
+#define IMX219_DEFAULT_LINK_FREQ 456000000
+
+/* V_TIMING internal */
+#define IMX219_REG_VTS 0x0160
+#define IMX219_VTS_15FPS 0x0dc6
+#define IMX219_VTS_30FPS_1080P 0x06e3
+#define IMX219_VTS_30FPS_BINNED 0x06e3
+#define IMX219_VTS_30FPS_640x480 0x06e3
+#define IMX219_VTS_MAX 0xffff
+
+#define IMX219_VBLANK_MIN 4
+
+/*Frame Length Line*/
+#define IMX219_FLL_MIN 0x08a6
+#define IMX219_FLL_MAX 0xffff
+#define IMX219_FLL_STEP 1
+#define IMX219_FLL_DEFAULT 0x0c98
+
+/* HBLANK control - read only */
+#define IMX219_PPL_DEFAULT 3448
+
+/* Exposure control */
+#define IMX219_REG_EXPOSURE 0x015a
+#define IMX219_EXPOSURE_MIN 4
+#define IMX219_EXPOSURE_STEP 1
+#define IMX219_EXPOSURE_DEFAULT 0x640
+#define IMX219_EXPOSURE_MAX 65535
+
+/* Analog gain control */
+#define IMX219_REG_ANALOG_GAIN 0x0157
+#define IMX219_ANA_GAIN_MIN 0
+#define IMX219_ANA_GAIN_MAX 232
+#define IMX219_ANA_GAIN_STEP 1
+#define IMX219_ANA_GAIN_DEFAULT 0xd0
+
+/* Digital gain control */
+#define IMX219_REG_DIGITAL_GAIN 0x0158
+#define IMX219_DGTL_GAIN_MIN 0x0100
+#define IMX219_DGTL_GAIN_MAX 0x0fff
+#define IMX219_DGTL_GAIN_DEFAULT 0x0100
+#define IMX219_DGTL_GAIN_STEP 1
+
+#define IMX219_REG_ORIENTATION 0x0172
+
+/* Test Pattern Control */
+#define IMX219_REG_TEST_PATTERN 0x0600
+#define IMX219_TEST_PATTERN_DISABLE 0
+#define IMX219_TEST_PATTERN_SOLID_COLOR 1
+#define IMX219_TEST_PATTERN_COLOR_BARS 2
+#define IMX219_TEST_PATTERN_GREY_COLOR 3
+#define IMX219_TEST_PATTERN_PN9 4
+
+/* Test pattern colour components */
+#define IMX219_REG_TESTP_RED 0x0602
+#define IMX219_REG_TESTP_GREENR 0x0604
+#define IMX219_REG_TESTP_BLUE 0x0606
+#define IMX219_REG_TESTP_GREENB 0x0608
+#define IMX219_TESTP_COLOUR_MIN 0
+#define IMX219_TESTP_COLOUR_MAX 0x03ff
+#define IMX219_TESTP_COLOUR_STEP 1
+#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX
+#define IMX219_TESTP_GREENR_DEFAULT 0
+#define IMX219_TESTP_BLUE_DEFAULT 0
+#define IMX219_TESTP_GREENB_DEFAULT 0
+
+/* IMX219 native and active pixel array size. */
+#define IMX219_NATIVE_WIDTH 3296U
+#define IMX219_NATIVE_HEIGHT 2480U
+#define IMX219_PIXEL_ARRAY_LEFT 8U
+#define IMX219_PIXEL_ARRAY_TOP 8U
+#define IMX219_PIXEL_ARRAY_WIDTH 3280U
+#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
+
+struct imx219_reg {
+ u16 address;
+ u8 val;
+};
+
+struct imx219_reg_list {
+ unsigned int num_of_regs;
+ const struct imx219_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx219_mode {
+ /* Frame width */
+ unsigned int width;
+ /* Frame height */
+ unsigned int height;
+
+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+
+ /* V-timing */
+ unsigned int vts_def;
+
+ /* Default register values */
+ struct imx219_reg_list reg_list;
+};
+
+/*
+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
+ * driver.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
+ */
+static const struct imx219_reg mode_3280x2464_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x0c},
+ {0x30eb, 0x05},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0164, 0x00},
+ {0x0165, 0x00},
+ {0x0166, 0x0c},
+ {0x0167, 0xcf},
+ {0x0168, 0x00},
+ {0x0169, 0x00},
+ {0x016a, 0x09},
+ {0x016b, 0x9f},
+ {0x016c, 0x0c},
+ {0x016d, 0xd0},
+ {0x016e, 0x09},
+ {0x016f, 0xa0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x00},
+ {0x0175, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x0c},
+ {0x0625, 0xd0},
+ {0x0626, 0x09},
+ {0x0627, 0xa0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_1920_1080_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x05},
+ {0x30eb, 0x0c},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+ {0x0164, 0x02},
+ {0x0165, 0xa8},
+ {0x0166, 0x0a},
+ {0x0167, 0x27},
+ {0x0168, 0x02},
+ {0x0169, 0xb4},
+ {0x016a, 0x06},
+ {0x016b, 0xeb},
+ {0x016c, 0x07},
+ {0x016d, 0x80},
+ {0x016e, 0x04},
+ {0x016f, 0x38},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x00},
+ {0x0175, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x07},
+ {0x0625, 0x80},
+ {0x0626, 0x04},
+ {0x0627, 0x38},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+};
+
+static const struct imx219_reg mode_1640_1232_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x0c},
+ {0x30eb, 0x05},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0164, 0x00},
+ {0x0165, 0x00},
+ {0x0166, 0x0c},
+ {0x0167, 0xcf},
+ {0x0168, 0x00},
+ {0x0169, 0x00},
+ {0x016a, 0x09},
+ {0x016b, 0x9f},
+ {0x016c, 0x06},
+ {0x016d, 0x68},
+ {0x016e, 0x04},
+ {0x016f, 0xd0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x01},
+ {0x0175, 0x01},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x06},
+ {0x0625, 0x68},
+ {0x0626, 0x04},
+ {0x0627, 0xd0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_640_480_regs[] = {
+ {0x0100, 0x00},
+ {0x30eb, 0x05},
+ {0x30eb, 0x0c},
+ {0x300a, 0xff},
+ {0x300b, 0xff},
+ {0x30eb, 0x05},
+ {0x30eb, 0x09},
+ {0x0114, 0x01},
+ {0x0128, 0x00},
+ {0x012a, 0x18},
+ {0x012b, 0x00},
+ {0x0162, 0x0d},
+ {0x0163, 0x78},
+ {0x0164, 0x03},
+ {0x0165, 0xe8},
+ {0x0166, 0x08},
+ {0x0167, 0xe7},
+ {0x0168, 0x02},
+ {0x0169, 0xf0},
+ {0x016a, 0x06},
+ {0x016b, 0xaf},
+ {0x016c, 0x02},
+ {0x016d, 0x80},
+ {0x016e, 0x01},
+ {0x016f, 0xe0},
+ {0x0170, 0x01},
+ {0x0171, 0x01},
+ {0x0174, 0x03},
+ {0x0175, 0x03},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0304, 0x03},
+ {0x0305, 0x03},
+ {0x0306, 0x00},
+ {0x0307, 0x39},
+ {0x030b, 0x01},
+ {0x030c, 0x00},
+ {0x030d, 0x72},
+ {0x0624, 0x06},
+ {0x0625, 0x68},
+ {0x0626, 0x04},
+ {0x0627, 0xd0},
+ {0x455e, 0x00},
+ {0x471e, 0x4b},
+ {0x4767, 0x0f},
+ {0x4750, 0x14},
+ {0x4540, 0x00},
+ {0x47b4, 0x14},
+ {0x4713, 0x30},
+ {0x478b, 0x10},
+ {0x478f, 0x10},
+ {0x4793, 0x10},
+ {0x4797, 0x0e},
+ {0x479b, 0x0e},
+};
+
+static const struct imx219_reg raw8_framefmt_regs[] = {
+ {0x018c, 0x08},
+ {0x018d, 0x08},
+ {0x0309, 0x08},
+};
+
+static const struct imx219_reg raw10_framefmt_regs[] = {
+ {0x018c, 0x0a},
+ {0x018d, 0x0a},
+ {0x0309, 0x0a},
+};
+
+static const s64 imx219_link_freq_menu[] = {
+ IMX219_DEFAULT_LINK_FREQ,
+};
+
+static const char * const imx219_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Solid Color",
+ "Grey Color Bars",
+ "PN9"
+};
+
+static const int imx219_test_pattern_val[] = {
+ IMX219_TEST_PATTERN_DISABLE,
+ IMX219_TEST_PATTERN_COLOR_BARS,
+ IMX219_TEST_PATTERN_SOLID_COLOR,
+ IMX219_TEST_PATTERN_GREY_COLOR,
+ IMX219_TEST_PATTERN_PN9,
+};
+
+/* regulator supplies */
+static const char * const imx219_supply_name[] = {
+ /* Supplies can be enabled in any order */
+ "VANA", /* Analog (2.8V) supply */
+ "VDIG", /* Digital Core (1.8V) supply */
+ "VDDL", /* IF (1.2V) supply */
+};
+
+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
+
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+};
+
+/*
+ * Initialisation delay between XCLR low->high and the moment when the sensor
+ * can start capture (i.e. can leave software stanby) must be not less than:
+ * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>)
+ * where
+ * t4 is fixed, and is max 200uS,
+ * t5 is fixed, and is 6000uS,
+ * t6 depends on the sensor external clock, and is max 32000 clock periods.
+ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
+ * So for any acceptable external clock t6 is always within the range of
+ * 1185 to 5333 uS, and is always less than t5.
+ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
+ * initialize the sensor over I2C, and then exit the software standby.
+ *
+ * This start-up time can be optimized a bit more, if we start the writes
+ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
+ * initialization over I2C may complete before (t4+t5) expires, and we must
+ * ensure that capture is not started before (t4+t5).
+ *
+ * This delay doesn't account for the power supply startup time. If needed,
+ * this should be taken care of via the regulator framework. E.g. in the
+ * case of DT for regulator-fixed one should define the startup-delay-us
+ * property.
+ */
+#define IMX219_XCLR_MIN_DELAY_US 6200
+#define IMX219_XCLR_DELAY_RANGE_US 1000
+
+/* Mode configs */
+static const struct imx219_mode supported_modes[] = {
+ {
+ /* 8MPix 15fps mode */
+ .width = 3280,
+ .height = 2464,
+ .crop = {
+ .left = IMX219_PIXEL_ARRAY_LEFT,
+ .top = IMX219_PIXEL_ARRAY_TOP,
+ .width = 3280,
+ .height = 2464
+ },
+ .vts_def = IMX219_VTS_15FPS,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
+ .regs = mode_3280x2464_regs,
+ },
+ },
+ {
+ /* 1080P 30fps cropped */
+ .width = 1920,
+ .height = 1080,
+ .crop = {
+ .left = 688,
+ .top = 700,
+ .width = 1920,
+ .height = 1080
+ },
+ .vts_def = IMX219_VTS_30FPS_1080P,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
+ .regs = mode_1920_1080_regs,
+ },
+ },
+ {
+ /* 2x2 binned 30fps mode */
+ .width = 1640,
+ .height = 1232,
+ .crop = {
+ .left = IMX219_PIXEL_ARRAY_LEFT,
+ .top = IMX219_PIXEL_ARRAY_TOP,
+ .width = 3280,
+ .height = 2464
+ },
+ .vts_def = IMX219_VTS_30FPS_BINNED,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
+ .regs = mode_1640_1232_regs,
+ },
+ },
+ {
+ /* 640x480 30fps mode */
+ .width = 640,
+ .height = 480,
+ .crop = {
+ .left = 1008,
+ .top = 760,
+ .width = 1280,
+ .height = 960
+ },
+ .vts_def = IMX219_VTS_30FPS_640x480,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_640_480_regs),
+ .regs = mode_640_480_regs,
+ },
+ },
+};
+#define MODE_COUNT_MAX ARRAY_SIZE(supported_modes)
+static int imx219_fps[MODE_COUNT_MAX] = {15, 30, 30, 30};
+
+struct imx219 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ //struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
+
+ struct v4l2_mbus_framefmt fmt;
+
+ struct clk *xclk; /* system clock to IMX219 */
+ u32 xclk_freq;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ /* V4L2 Controls */
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+
+ /* Current mode */
+ const struct imx219_mode *mode;
+
+ /*
+ * Mutex for serialized access:
+ * Protect sensor module set pad format and start/stop streaming safely.
+ */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ int streaming;
+};
+
+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct imx219, sd);
+}
+
+/* Read registers up to 2 at a time */
+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ struct i2c_msg msgs[2];
+ u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+ u8 data_buf[4] = { 0, };
+ int ret;
+
+ if (len > 4)
+ return -EINVAL;
+
+ /* Write register address */
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = ARRAY_SIZE(addr_buf);
+ msgs[0].buf = addr_buf;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = &data_buf[4 - len];
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ *val = get_unaligned_be32(data_buf);
+
+ return 0;
+}
+
+/* Write registers up to 2 at a time */
+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ u8 buf[6];
+
+ if (len > 4)
+ return -EINVAL;
+
+ put_unaligned_be16(reg, buf);
+ put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+ if (i2c_master_send(client, buf, len + 2) != len + 2)
+ return -EIO;
+
+ return 0;
+}
+
+/* Write a list of registers */
+static int imx219_write_regs(struct imx219 *imx219,
+ const struct imx219_reg *regs, u32 len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < len; i++) {
+ ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
+ if (ret) {
+ dev_err_ratelimited(&client->dev,
+ "Failed to write reg 0x%4.4x. error = %d\n",
+ regs[i].address, ret);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
+{
+ unsigned int i;
+
+ lockdep_assert_held(&imx219->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(codes); i++)
+ if (codes[i] == code)
+ break;
+
+ if (i >= ARRAY_SIZE(codes))
+ i = 0;
+
+ i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
+ (imx219->hflip->val ? 1 : 0);
+
+ return codes[i];
+}
+
+static void imx219_set_default_format(struct imx219 *imx219)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = &imx219->fmt;
+ fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ fmt->colorspace, fmt->ycbcr_enc);
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+ fmt->width = supported_modes[0].width;
+ fmt->height = supported_modes[0].height;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(sd, fh->state, 0);
+ struct v4l2_rect *try_crop;
+
+ mutex_lock(&imx219->mutex);
+
+ /* Initialize try_fmt */
+ try_fmt->width = supported_modes[0].width;
+ try_fmt->height = supported_modes[0].height;
+ try_fmt->code = imx219_get_format_code(imx219, MEDIA_BUS_FMT_SRGGB10_1X10);
+ try_fmt->field = V4L2_FIELD_NONE;
+
+ /* Initialize try_crop rectangle. */
+ try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
+ try_crop->top = IMX219_PIXEL_ARRAY_TOP;
+ try_crop->left = IMX219_PIXEL_ARRAY_LEFT;
+ try_crop->width = IMX219_PIXEL_ARRAY_WIDTH;
+ try_crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
+
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+}
+
+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx219 *imx219 =
+ container_of(ctrl->handler, struct imx219, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exposure_max, exposure_def;
+
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = imx219->mode->height + ctrl->val - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx219->exposure, imx219->exposure->minimum,
+ exposure_max, imx219->exposure->step, exposure_def);
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
+ IMX219_REG_VALUE_08BIT, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
+ IMX219_REG_VALUE_16BIT, imx219_test_pattern_val[ctrl->val]);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
+ imx219->hflip->val | imx219->vflip->val << 1);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = imx219_write_reg(imx219, IMX219_REG_VTS, IMX219_REG_VALUE_16BIT,
+ imx219->mode->height + ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_RED:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENR:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_BLUE:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENB:
+ ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
+ IMX219_REG_VALUE_16BIT, ctrl->val);
+ break;
+ default:
+ dev_info(&client->dev,
+ "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val);
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
+ .s_ctrl = imx219_set_ctrl,
+};
+
+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+
+ if (code->index >= (ARRAY_SIZE(codes) / 4))
+ return -EINVAL;
+
+ mutex_lock(&imx219->mutex);
+ code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+}
+
+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ u32 code;
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ mutex_lock(&imx219->mutex);
+ code = imx219_get_format_code(imx219, fse->code);
+ mutex_unlock(&imx219->mutex);
+ if (fse->code != code)
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+static int imx219_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ u32 code;
+ int i = 0;
+
+ if (fie->index >= ARRAY_SIZE(supported_modes) || fie->index)
+ return -EINVAL;
+
+ mutex_lock(&imx219->mutex);
+ code = imx219_get_format_code(imx219, fie->code);
+ mutex_unlock(&imx219->mutex);
+ if (fie->code != code)
+ return -EINVAL;
+
+ pr_debug("fie->width = %d, fie->height = %d\n", fie->width, fie->height);
+ for (i = 0; i < MODE_COUNT_MAX; i++) {
+ if (fie->width == supported_modes[i].width &&
+ fie->height == supported_modes[i].height)
+ break;
+ }
+ if (i == MODE_COUNT_MAX)
+ return -ENOTTY;
+
+ fie->interval.denominator = imx219_fps[i];
+ fie->interval.numerator = 1;
+ fie->code = code;
+ fie->width = supported_modes[i].width;
+ fie->height = supported_modes[i].height;
+
+ return 0;
+}
+
+static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ fmt->colorspace, fmt->ycbcr_enc);
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+}
+
+static void imx219_update_pad_format(struct imx219 *imx219,
+ const struct imx219_mode *mode,
+ struct v4l2_subdev_format *fmt)
+{
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+ imx219_reset_colorspace(&fmt->format);
+}
+
+static int __imx219_get_pad_format(struct imx219 *imx219,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(&imx219->sd, state, fmt->pad);
+ /* update the code which could change due to vflip or hflip: */
+ try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
+ fmt->format = *try_fmt;
+ } else {
+ imx219_update_pad_format(imx219, imx219->mode, fmt);
+ fmt->format.code = imx219_get_format_code(imx219, imx219->fmt.code);
+ }
+
+ return 0;
+}
+
+static int imx219_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ mutex_lock(&imx219->mutex);
+ ret = __imx219_get_pad_format(imx219, state, fmt);
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+}
+
+static int imx219_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ const struct imx219_mode *mode;
+ struct v4l2_mbus_framefmt *framefmt;
+ int exposure_max, exposure_def, hblank;
+ unsigned int i;
+
+ mutex_lock(&imx219->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(codes); i++)
+ if (codes[i] == fmt->format.code)
+ break;
+ if (i >= ARRAY_SIZE(codes))
+ i = 0;
+
+ /* Bayer order varies with flips */
+ fmt->format.code = imx219_get_format_code(imx219, codes[i]);
+
+ mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes),
+ width, height, fmt->format.width, fmt->format.height);
+ imx219_update_pad_format(imx219, mode, fmt);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ framefmt = v4l2_subdev_get_try_format(sd, state, fmt->pad);
+ *framefmt = fmt->format;
+ } else if (imx219->mode != mode ||
+ imx219->fmt.code != fmt->format.code) {
+ imx219->fmt = fmt->format;
+ imx219->mode = mode;
+ /* Update limits and set FPS to default */
+ __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
+ IMX219_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+ __v4l2_ctrl_s_ctrl(imx219->vblank, mode->vts_def - mode->height);
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = mode->vts_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx219->exposure, imx219->exposure->minimum,
+ exposure_max, imx219->exposure->step, exposure_def);
+ /*
+ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
+ * depends on mode->width only, and is not changeble in any
+ * way other than changing the mode.
+ */
+ hblank = IMX219_PPL_DEFAULT - mode->width;
+ __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, hblank);
+ }
+
+ mutex_unlock(&imx219->mutex);
+
+ return 0;
+}
+
+static int imx219_set_framefmt(struct imx219 *imx219)
+{
+ switch (imx219->fmt.code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return imx219_write_regs(imx219, raw8_framefmt_regs,
+ ARRAY_SIZE(raw8_framefmt_regs));
+
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ return imx219_write_regs(imx219, raw10_framefmt_regs,
+ ARRAY_SIZE(raw10_framefmt_regs));
+ }
+
+ return -EINVAL;
+}
+
+static const struct v4l2_rect *
+__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_state *state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&imx219->sd, state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &imx219->mode->crop;
+ }
+
+ return NULL;
+}
+
+static int imx219_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct imx219 *imx219 = to_imx219(sd);
+
+ mutex_lock(&imx219->mutex);
+ sel->r = *__imx219_get_pad_crop(imx219, state, sel->pad, sel->which);
+ mutex_unlock(&imx219->mutex);
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX219_NATIVE_WIDTH;
+ sel->r.height = IMX219_NATIVE_HEIGHT;
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX219_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx219_start_streaming(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ const struct imx219_reg_list *reg_list;
+ int ret;
+
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &imx219->mode->reg_list;
+ ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ goto err_rpm_put;
+ }
+
+ ret = imx219_set_framefmt(imx219);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set frame format: %d\n",
+ __func__, ret);
+ goto err_rpm_put;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
+ if (ret)
+ goto err_rpm_put;
+
+ /* set stream on register */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+ if (ret)
+ goto err_rpm_put;
+
+ /* vflip and hflip cannot change during streaming */
+ __v4l2_ctrl_grab(imx219->vflip, true);
+ __v4l2_ctrl_grab(imx219->hflip, true);
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put(&client->dev);
+ return ret;
+}
+
+static void imx219_stop_streaming(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+
+ /* set stream off register */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+ if (ret)
+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
+
+ __v4l2_ctrl_grab(imx219->vflip, false);
+ __v4l2_ctrl_grab(imx219->hflip, false);
+
+ pm_runtime_put(&client->dev);
+}
+
+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret = 0;
+
+ mutex_lock(&imx219->mutex);
+ if (imx219->streaming && enable)
+ goto unlock;
+
+ if (enable) {
+ /*
+ * Apply default & customized values
+ * and then start streaming.
+ */
+ ret = imx219_start_streaming(imx219);
+ if (ret)
+ goto err_unlock;
+ } else {
+ imx219_stop_streaming(imx219);
+ }
+
+unlock:
+ imx219->streaming += enable ? 1 : -1;
+ WARN_ON(imx219->streaming < 0);
+
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+
+err_unlock:
+ mutex_unlock(&imx219->mutex);
+
+ return ret;
+}
+
+/* Power/clock management functions */
+static int imx219_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, imx219->supplies);
+ if (ret) {
+ dev_err(dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(imx219->xclk);
+ if (ret) {
+ dev_err(dev, "%s: failed to enable clock\n", __func__);
+ goto reg_off;
+ }
+
+ gpiod_set_value_cansleep(imx219->reset_gpio, 1);
+ usleep_range(IMX219_XCLR_MIN_DELAY_US,
+ IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
+
+ return 0;
+
+reg_off:
+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+
+ return ret;
+}
+
+static int imx219_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ gpiod_set_value_cansleep(imx219->reset_gpio, 0);
+ regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+ clk_disable_unprepare(imx219->xclk);
+
+ return 0;
+}
+
+static int __maybe_unused imx219_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ if (imx219->streaming)
+ imx219_stop_streaming(imx219);
+
+ return 0;
+}
+
+static int __maybe_unused imx219_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx219 *imx219 = to_imx219(sd);
+ int ret;
+
+ if (imx219->streaming) {
+ ret = imx219_start_streaming(imx219);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ imx219_stop_streaming(imx219);
+ imx219->streaming = false;
+
+ return ret;
+}
+
+static int imx219_get_regulators(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ unsigned int i;
+
+ for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
+ imx219->supplies[i].supply = imx219_supply_name[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ IMX219_NUM_SUPPLIES, imx219->supplies);
+}
+
+/* Verify chip ID */
+static int imx219_identify_module(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ int ret;
+ u32 val;
+
+ ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
+ IMX219_REG_VALUE_16BIT, &val);
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id %x\n",
+ IMX219_CHIP_ID);
+ return ret;
+ }
+
+ if (val != IMX219_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ IMX219_CHIP_ID, val);
+ return -EIO;
+ }
+
+ dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",
+ __func__, IMX219_CHIP_ID);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx219_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx219_video_ops = {
+ .s_stream = imx219_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
+ .enum_mbus_code = imx219_enum_mbus_code,
+ .get_fmt = imx219_get_pad_format,
+ .set_fmt = imx219_set_pad_format,
+ .get_selection = imx219_get_selection,
+ .enum_frame_size = imx219_enum_frame_size,
+ .enum_frame_interval = imx219_enum_frame_interval,
+};
+
+static const struct v4l2_subdev_ops imx219_subdev_ops = {
+ .core = &imx219_core_ops,
+ .video = &imx219_video_ops,
+ .pad = &imx219_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
+ .open = imx219_open,
+};
+
+/* Initialize control handlers */
+static int imx219_init_controls(struct imx219 *imx219)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ unsigned int height = imx219->mode->height;
+ struct v4l2_fwnode_device_properties props;
+ int exposure_max, exposure_def, hblank;
+ int i, ret;
+
+ ctrl_hdlr = &imx219->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
+ if (ret)
+ return ret;
+
+ mutex_init(&imx219->mutex);
+ ctrl_hdlr->lock = &imx219->mutex;
+
+ /* By default, PIXEL_RATE is read only */
+ imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, IMX219_PIXEL_RATE,
+ IMX219_PIXEL_RATE, 1, IMX219_PIXEL_RATE);
+
+ imx219->link_freq =
+ v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(imx219_link_freq_menu) - 1, 0, imx219_link_freq_menu);
+ if (imx219->link_freq)
+ imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* Initial vblank/hblank/exposure parameters based on current mode */
+ imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
+ IMX219_VTS_MAX - height, 1,
+ imx219->mode->vts_def - height);
+ hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
+ imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank, 1, hblank);
+ if (imx219->hblank)
+ imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ exposure_max = imx219->mode->vts_def - 4;
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX219_EXPOSURE_DEFAULT;
+ imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_EXPOSURE, IMX219_EXPOSURE_MIN, exposure_max,
+ IMX219_EXPOSURE_STEP, exposure_def);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
+ IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
+ IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
+
+ imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx219->hflip)
+ imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx219->vflip)
+ imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx219_test_pattern_menu) - 1,
+ 0, 0, imx219_test_pattern_menu);
+ for (i = 0; i < 4; i++) {
+ /*
+ * The assumption is that
+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+ */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+ V4L2_CID_TEST_PATTERN_RED + i,
+ IMX219_TESTP_COLOUR_MIN,
+ IMX219_TESTP_COLOUR_MAX,
+ IMX219_TESTP_COLOUR_STEP,
+ IMX219_TESTP_COLOUR_MAX);
+ /* The "Solid color" pattern is white by default */
+ }
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(&client->dev, "%s control init failed (%d)\n",
+ __func__, ret);
+ goto error;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, &props);
+ if (ret)
+ goto error;
+
+ imx219->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ mutex_destroy(&imx219->mutex);
+
+ return ret;
+}
+
+static void imx219_free_controls(struct imx219 *imx219)
+{
+ v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
+ mutex_destroy(&imx219->mutex);
+}
+
+static int imx219_check_hwcfg(struct device *dev)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint ep_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ int ret = -EINVAL;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto error_out;
+ }
+
+ /* Check the number of MIPI CSI2 data lanes */
+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+ dev_err(dev, "only 2 data lanes are currently supported\n");
+ goto error_out;
+ }
+
+ /* Check the link frequency set in device tree */
+ if (!ep_cfg.nr_of_link_frequencies) {
+ dev_err(dev, "link-frequency property not found in DT\n");
+ goto error_out;
+ }
+
+ if (ep_cfg.nr_of_link_frequencies != 1 ||
+ ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
+ dev_err(dev, "Link frequency not supported: %lld\n",
+ ep_cfg.link_frequencies[0]);
+ goto error_out;
+ }
+
+ ret = 0;
+
+error_out:
+ v4l2_fwnode_endpoint_free(&ep_cfg);
+ fwnode_handle_put(endpoint);
+
+ return ret;
+}
+
+static int imx219_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct imx219 *imx219;
+ int ret;
+
+ imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
+ if (!imx219)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
+
+ /* Check the hardware configuration in device tree */
+ if (imx219_check_hwcfg(dev))
+ return -EINVAL;
+
+ /* Get system clock (xclk) */
+ imx219->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(imx219->xclk)) {
+ dev_err(dev, "failed to get xclk\n");
+ return PTR_ERR(imx219->xclk);
+ }
+
+ imx219->xclk_freq = clk_get_rate(imx219->xclk);
+ if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
+ imx219->xclk_freq);
+ return -EINVAL;
+ }
+
+ ret = imx219_get_regulators(imx219);
+ if (ret) {
+ dev_err(dev, "failed to get regulators\n");
+ return ret;
+ }
+
+ /* Request optional enable pin */
+ imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+
+ /*
+ * The sensor must be powered for imx219_identify_module()
+ * to be able to read the CHIP_ID register
+ */
+ ret = imx219_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = imx219_identify_module(imx219);
+ if (ret)
+ goto error_power_off;
+
+ /* Set default mode to max resolution */
+ imx219->mode = &supported_modes[0];
+
+ /* sensor doesn't enter LP-11 state upon power up until and unless
+ * streaming is started, so upon power up switch the modes to:
+ * streaming -> standby
+ */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+ if (ret < 0)
+ goto error_power_off;
+ usleep_range(100, 110);
+
+ /* put sensor back to standby mode */
+ ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+ IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+ if (ret < 0)
+ goto error_power_off;
+ usleep_range(100, 110);
+
+ ret = imx219_init_controls(imx219);
+ if (ret)
+ goto error_power_off;
+
+ /* Initialize subdev */
+ imx219->sd.internal_ops = &imx219_internal_ops;
+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+ /* Initialize default format */
+ imx219_set_default_format(imx219);
+
+ ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
+ if (ret) {
+ dev_err(dev, "failed to init entity pads: %d\n", ret);
+ goto error_handler_free;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&imx219->sd);
+ if (ret < 0) {
+ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* Enable runtime PM and turn off the device */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
+ return 0;
+
+error_media_entity:
+ media_entity_cleanup(&imx219->sd.entity);
+
+error_handler_free:
+ imx219_free_controls(imx219);
+
+error_power_off:
+ imx219_power_off(dev);
+
+ return ret;
+}
+
+static int imx219_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx219 *imx219 = to_imx219(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ imx219_free_controls(imx219);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ imx219_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ return 0;
+}
+
+static const struct of_device_id imx219_dt_ids[] = {
+ { .compatible = "imx219" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
+
+static const struct dev_pm_ops imx219_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
+ SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
+};
+
+static struct i2c_driver imx219_i2c_driver = {
+ .driver = {
+ .name = "imx219",
+ .of_match_table = imx219_dt_ids,
+ .pm = &imx219_pm_ops,
+ },
+ .probe_new = imx219_probe,
+ .remove = imx219_remove,
+};
+
+module_i2c_driver(imx219_i2c_driver);
+
+MODULE_AUTHOR("David.li");
+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
+MODULE_LICENSE("GPL v2");
u32 ae_low, ae_high, ae_target;
bool pending_mode_change;
- bool streaming;
+ int streaming;
};
static inline struct ov4689_dev *to_ov4689_dev(struct v4l2_subdev *sd)
{
const struct ov4689_mode_info *mode = sensor->current_mode;
//const struct ov4689_mode_info *orig_mode = sensor->last_mode;
+
int ret = 0;
ret = ov4689_set_mode_direct(sensor, mode);
ret = ov4689_stream_start(sensor, enable);
- if (!ret)
- sensor->streaming = enable;
+ if (ret)
+ goto out;
}
+ sensor->streaming += enable ? 1 : -1;
+ WARN_ON(sensor->streaming < 0);
out:
mutex_unlock(&sensor->lock);
return ret;
u32 ae_low, ae_high, ae_target;
bool pending_mode_change;
- bool streaming;
+ int streaming;
};
static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
else
ret = ov5640_set_stream_dvp(sensor, enable);
- if (!ret)
- sensor->streaming = enable;
+ if (ret)
+ goto out;
}
+ sensor->streaming += enable ? 1 : -1;
+ WARN_ON(sensor->streaming < 0);
out:
mutex_unlock(&sensor->lock);
return ret;
u32 ae_low, ae_high, ae_target;
bool pending_mode_change;
- bool streaming;
+ int streaming;
};
static inline struct sc2235_dev *to_sc2235_dev(struct v4l2_subdev *sd)
u8 mask, val;
int ret = 0;
- st_info(ST_SENSOR, "%s, mode = 0x%x\n", __func__, mode->id);
for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
delay_ms = regs->delay_ms;
reg_addr = regs->reg_addr;
}
#ifdef UNUSED_CODE
+static int sc2235_get_sysclk(struct sc2235_dev *sensor)
+{
+ return 0;
+}
+
+static int sc2235_set_night_mode(struct sc2235_dev *sensor)
+{
+ return 0;
+}
+
static int sc2235_get_hts(struct sc2235_dev *sensor)
{
u16 hts;
{
return sc2235_write_reg16(sensor, SC2235_REG_TIMING_VTS, vts);
}
+
+static int sc2235_get_light_freq(struct sc2235_dev *sensor)
+{
+ return 0;
+}
+
+static int sc2235_set_bandingfilter(struct sc2235_dev *sensor)
+{
+ return 0;
+}
+
+static int sc2235_set_ae_target(struct sc2235_dev *sensor, int target)
+{
+ return 0;
+}
+
+static int sc2235_get_binning(struct sc2235_dev *sensor)
+{
+ return 0;
+}
+
+static int sc2235_set_binning(struct sc2235_dev *sensor, bool enable)
+{
+ return 0;
+}
+
#endif
static const struct sc2235_mode_info *
sc2235_calc_sys_clk(sensor, rate, &prediv, &mult,
&sysdiv);
- st_info(ST_SENSOR, "%s, prediv = %d, mult = %d, sysdiv = %d\n",
- __func__, prediv, mult, sysdiv);
-
- ret = sc2235_mod_reg(sensor, SC2235_REG_SC_PLL_CTRL0, 0x7f,
- (sysdiv << 4) | (prediv << 1) | ((mult & 0x20) >> 5));
- if (ret)
- return ret;
- return sc2235_mod_reg(sensor, SC2235_REG_SC_PLL_CTRL1,
- 0xf8, mult << 3);
+ return ret;
}
/*
sensor->pending_fmt_change = false;
}
- if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL)
+ if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL) {
+ ret = sc2235_set_gain(sensor, 0x10);
+ ret = sc2235_set_exposure(sensor, (360 * 2));
ret = sc2235_set_stream_dvp(sensor, enable);
+ }
- if (!ret)
- sensor->streaming = enable;
+ if (ret)
+ goto out;
}
+ sensor->streaming += enable ? 1 : -1;
+ WARN_ON(sensor->streaming < 0);
out:
mutex_unlock(&sensor->lock);
sensor->i2c_client = client;
fmt = &sensor->fmt;
- fmt->code = MEDIA_BUS_FMT_SGBRG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
// #define STF_DEBUG
-#define USE_CSIDPHY_ONE_CLK_MODE 1
+// #define USE_CSIDPHY_ONE_CLK_MODE 1
enum {
ST_DVP = 0x0001,
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define STF_CSI_NAME "stf_csi"
-
static const struct csi_format csi_formats_st7110[] = {
{ MEDIA_BUS_FMT_YUYV8_2X8, 16},
{ MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
- { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
- { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
- { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
- { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
};
static int csi_find_format(u32 code,
break;
if (i >= csi_dev->nformats)
- fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
+ fmt->code = csi_dev->formats[0].code;
fmt->width = clamp_t(u32,
fmt->width,
- 1,
+ STFCAMSS_FRAME_MIN_WIDTH,
STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32,
fmt->height,
- 1,
- STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+ STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
+
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
if (format == NULL)
return -EINVAL;
- csi_try_format(csi_dev, state, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
+ mutex_lock(&csi_dev->stream_lock);
+ if (csi_dev->stream_count) {
+ fmt->format = *format;
+ mutex_unlock(&csi_dev->stream_lock);
+ goto out;
+ } else {
+ csi_try_format(csi_dev, state, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+ }
+ mutex_unlock(&csi_dev->stream_lock);
/* Propagate the format from sink to source */
if (fmt->pad == STF_CSI_PAD_SINK) {
csi_try_format(csi_dev, state, STF_CSI_PAD_SRC, format,
fmt->which);
}
-
+out:
return 0;
}
line = v4l2_get_subdevdata(sd);
if (line->sdev_type == VIN_DEV_TYPE)
csi_dev->s_type = SENSOR_VIN;
- if (line->sdev_type == ISP0_DEV_TYPE)
- csi_dev->s_type = SENSOR_ISP0;
- if (line->sdev_type == ISP1_DEV_TYPE)
- csi_dev->s_type = SENSOR_ISP1;
+ if (line->sdev_type == ISP_DEV_TYPE)
+ csi_dev->s_type = SENSOR_ISP;
st_info(ST_CSI, "CSI%d device sensor type: %d\n",
csi_dev->id, csi_dev->s_type);
}
csiphy_dev = v4l2_get_subdevdata(sd);
csi_dev->csiphy_id = csiphy_dev->id;
- st_info(ST_SENSOR, "CSI%d link to csiphy%d\n",
+ st_info(ST_CSI, "CSI%d link to csiphy%d\n",
csi_dev->id, csi_dev->csiphy_id);
}
#include <media/media-entity.h>
#include <video/stf-vin.h>
+#define STF_CSI_NAME "stf_csi"
+
#define STF_CSI_PAD_SINK 0
#define STF_CSI_PAD_SRC 1
#define STF_CSI_PADS_NUM 2
case SENSOR_VIN:
st_err(ST_CSI, "%s, %d: need todo\n", __func__, __LINE__);
break;
- case SENSOR_ISP0:
+ case SENSOR_ISP:
reg_set_bit(vin->clkgen_base,
- CLK_ISP0_MIPI_CTRL,
+ CLK_ISP_MIPI_CTRL,
BIT(24), csi_dev->id << 24);
reg_set_bit(vin->clkgen_base,
- CLK_C_ISP0_CTRL,
+ CLK_C_ISP_CTRL,
BIT(25) | BIT(24),
csi_dev->id << 24);
SYSCTRL_VIN_SRC_CHAN_SEL,
0xF, mipi_channel_sel);
break;
- case SENSOR_ISP1:
- reg_set_bit(vin->clkgen_base,
- CLK_ISP1_MIPI_CTRL,
- BIT(24), csi_dev->id << 24);
-
- reg_set_bit(vin->clkgen_base,
- CLK_C_ISP1_CTRL,
- BIT(25) | BIT(24),
- csi_dev->id << 24);
-
- mipi_channel_sel = csi_dev->id * 4 + mipi_vc;
- reg_set_bit(vin->sysctrl_base,
- SYSCTRL_VIN_SRC_CHAN_SEL,
- 0xF << 4, mipi_channel_sel << 4);
default:
break;
}
case SENSOR_VIN:
st_err(ST_CSI, "%s, %d: need todo\n", __func__, __LINE__);
break;
- case SENSOR_ISP0:
+ case SENSOR_ISP:
if (is_raw10)
reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
BIT(12),
- 1<<12);
+ 1 << 12);
break;
- case SENSOR_ISP1:
- st_err(ST_CSI, "please check csi_dev s_type:%d\n", csi_dev->s_type);
default:
break;
}
reg = csiphy->num_data_lanes << 8;
for (i = 0; i < csiphy->num_data_lanes; i++) {
+#ifndef USE_CSIDPHY_ONE_CLK_MODE
reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csiphy->data_lanes[i]);
set_bit(csiphy->data_lanes[i] - 1, &lanes_used);
+#else
+ reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1);
+ set_bit(i, &lanes_used);
+#endif
}
/*
// 0x40 DPHY_LANE_CONTROL
reg = 0;
-
+#ifndef USE_CSIDPHY_ONE_CLK_MODE
+ for (i = 0; i < csiphy->num_data_lanes; i++)
+ reg |= 1 << (csiphy->data_lanes[i] - 1)
+ | 1 << (csiphy->data_lanes[i] + 11);
+#else
for (i = 0; i < csiphy->num_data_lanes; i++)
reg |= 1 << i | 1 << (i + 12); //data_clane
+#endif
reg |= 1 << 4 | 1 << 16; //clk_lane
writel(reg, reg_base + CSI2RX_DPHY_LANE_CONTROL);
BIT(12)|BIT(11)|BIT(10)|BIT(9)|BIT(8)|BIT(7)|BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2),
(1920 / 4 - 1)<<2); //u0_vin_cnfg_axiwr0_pix_cnt_end
break;
- case SENSOR_ISP0:
+ case SENSOR_ISP:
clk_set_parent(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk,
stfcamss->sys_clk[STFCLK_MIPI_RX0_PXL].clk);
reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
BIT(7)|BIT(6),
- 0<<6); //u0_vin_cnfg_mipi_byte_en_isp0
+ 0<<6); //u0_vin_cnfg_mipi_byte_en_isp
reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
BIT(11)|BIT(10)|BIT(9)|BIT(8),
0<<8); //u0_vin_cnfg_mipi_channel_sel0
BIT(16)|BIT(15)|BIT(14)|BIT(13),
0<<13); //u0_vin_cnfg_pix_num
break;
- case SENSOR_ISP1:
- st_err(ST_CSI, "please check csi_dev s_type:%d\n", csi_dev->s_type);
- break;
default:
break;
}
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define STF_CSIPHY_NAME "stf_csiphy"
-
static const struct csiphy_format csiphy_formats_st7110[] = {
{ MEDIA_BUS_FMT_YUYV8_2X8, 16},
{ MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
- { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
- { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
- { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
- { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
};
int stf_csiphy_subdev_init(struct stfcamss *stfcamss, int id)
break;
if (i >= csiphy_dev->nformats)
- fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
+ fmt->code = csiphy_dev->formats[0].code;
fmt->width = clamp_t(u32,
fmt->width,
- 1,
+ STFCAMSS_FRAME_MIN_WIDTH,
STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32,
fmt->height,
- 1,
- STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+ STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
if (format == NULL)
return -EINVAL;
- csiphy_try_format(csiphy_dev, state, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
+ mutex_lock(&csiphy_dev->stream_lock);
+ if (csiphy_dev->stream_count) {
+ fmt->format = *format;
+ mutex_unlock(&csiphy_dev->stream_lock);
+ goto out;
+ } else {
+ csiphy_try_format(csiphy_dev, state, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+ }
+ mutex_unlock(&csiphy_dev->stream_lock);
/* Propagate the format from sink to source */
if (fmt->pad == STF_CSIPHY_PAD_SINK) {
csiphy_try_format(csiphy_dev, state, STF_CSIPHY_PAD_SRC, format,
fmt->which);
}
-
+out:
return 0;
}
#include <media/media-entity.h>
#include <video/stf-vin.h>
+#define STF_CSIPHY_NAME "stf_csiphy"
+
#define STF_CSIPHY_PAD_SINK 0
#define STF_CSIPHY_PAD_SRC 1
#define STF_CSIPHY_PADS_NUM 2
static int stf_csiphy_clk_set(struct stf_csiphy_dev *csiphy_dev, int on)
{
struct stfcamss *stfcamss = csiphy_dev->stfcamss;
- struct stf_vin_dev *vin = csiphy_dev->stfcamss->vin;
static int init_flag;
static struct mutex count_lock;
static int count;
reset_control_deassert(stfcamss->sys_rst[STFRST_M31DPHY_HW].rstc);
reset_control_deassert(stfcamss->sys_rst[STFRST_M31DPHY_B09_ALWAYS_ON].rstc);
- reg_set_bit(vin->rstgen_base,
- M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(6), BIT(6));
-//need to check one or two mipi input
-#ifdef USE_CSIDPHY_ONE_CLK_MODE //one mipi input
- reg_set_bit(vin->rstgen_base,
- M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(7), BIT(7));
-#else //two mipi input
- reg_set_bit(vin->rstgen_base,
- M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(7), 0x2<<7);
-#endif
count++;
} else {
if (count == 0)
{
int i = 0;
+ cfg->clock_lane = 0;
+ cfg->clock1_lane = 5;
+ cfg->data_lanes[0] = 1;
+ cfg->data_lanes[1] = 2;
+ cfg->data_lanes[2] = 3;
+ cfg->data_lanes[3] = 4;
+
if (cfg0 && cfg1) {
st_debug(ST_CSIPHY, "CSIPHY use 2 clk mode\n");
cfg->num_clks = 2;
static int csi2rx_dphy_config(struct stf_vin_dev *vin,
struct stf_csiphy_dev *csiphy_dev)
{
- struct csi2phy_cfg *cfg;
+ struct csi2phy_cfg2 cfg2 = {0};
+ struct csi2phy_cfg2 *cfg = &cfg2;
struct stf_csiphy_dev *csiphy0_dev =
&csiphy_dev->stfcamss->csiphy_dev[0];
+ struct stf_csiphy_dev *csiphy1_dev =
+ &csiphy_dev->stfcamss->csiphy_dev[1];
struct csi2phy_cfg *phy0cfg = csiphy0_dev->csiphy;
+ struct csi2phy_cfg *phy1cfg = csiphy1_dev->csiphy;
int id = csiphy_dev->id;
- if (!phy0cfg)
+ st_debug(ST_CSIPHY, "%s, csiphy id = %d\n",
+ __func__, id);
+
+ if (!phy0cfg && !phy1cfg)
return -EINVAL;
- if (id == 0)
- cfg = phy0cfg;
+#ifdef USE_CSIDPHY_ONE_CLK_MODE
+ if (id == 0) {
+ phy0cfg = csiphy0_dev->csiphy;
+ phy1cfg = NULL;
+ } else {
+ phy0cfg = NULL;
+ phy1cfg = csiphy1_dev->csiphy;
+ }
+#endif
+
+ if (try_cfg(cfg, phy0cfg, phy1cfg))
+ return -EINVAL;
reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_4, 0x0);
reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_8, 0x0);
- reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_12, 0xff0);
+ reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_12, 0xfff0);
reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_16, 0x0);
reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_20, 0x0);
reg_write(vin->rstgen_base, M31DPHY_APBCFGSAIF__SYSCFG_24, 0x0);
reg_set_bit(vin->rstgen_base, //dpdn_swap_clk0
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(0), 0<<0);
+ BIT(0), cfg->lane_polarities[0]<<0);
reg_set_bit(vin->rstgen_base, //dpdn_swap_clk1
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(1), 0<<1);
+ BIT(1), cfg->lane_polarities[1]<<1);
reg_set_bit(vin->rstgen_base, //dpdn_swap_lan0
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(2), 0<<2);
+ BIT(2), cfg->lane_polarities[2]<<2);
reg_set_bit(vin->rstgen_base, //dpdn_swap_lan1
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(3), 0<<3);
+ BIT(3), cfg->lane_polarities[3]<<3);
reg_set_bit(vin->rstgen_base, //dpdn_swap_lan2
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(4), 0<<4);
+ BIT(4), cfg->lane_polarities[4]<<4);
reg_set_bit(vin->rstgen_base, //dpdn_swap_lan3
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(5), 0<<5);
-
- reg_set_bit(vin->rstgen_base, //endable lan0
+ BIT(5), cfg->lane_polarities[5]<<5);
+ reg_set_bit(vin->rstgen_base, //enable clk0
+ M31DPHY_APBCFGSAIF__SYSCFG_188,
+ BIT(6), 1<<6);
+ reg_set_bit(vin->rstgen_base, //enable clk1
+ M31DPHY_APBCFGSAIF__SYSCFG_188,
+ BIT(7), 1<<7);
+ reg_set_bit(vin->rstgen_base, //enable lan0
M31DPHY_APBCFGSAIF__SYSCFG_188,
BIT(8), 1<<8);
- reg_set_bit(vin->rstgen_base, //endable lan1
+ reg_set_bit(vin->rstgen_base, //enable lan1
M31DPHY_APBCFGSAIF__SYSCFG_188,
BIT(9), 1<<9);
- reg_set_bit(vin->rstgen_base, //endable lan2
+ reg_set_bit(vin->rstgen_base, //enable lan2
M31DPHY_APBCFGSAIF__SYSCFG_188,
BIT(10), 1<<10);
- reg_set_bit(vin->rstgen_base, //endable lan3
+ reg_set_bit(vin->rstgen_base, //enable lan3
M31DPHY_APBCFGSAIF__SYSCFG_188,
BIT(11), 1<<11);
reg_set_bit(vin->rstgen_base, //gpi_en
BIT(22)|BIT(21)|BIT(20), cfg->clock_lane<<20); //clock lane 0
reg_set_bit(vin->rstgen_base,
M31DPHY_APBCFGSAIF__SYSCFG_188,
- BIT(25)|BIT(24)|BIT(23), 5<<23); //clock lane 1
+ BIT(25)|BIT(24)|BIT(23), cfg->clock1_lane<<23); //clock lane 1
reg_set_bit(vin->rstgen_base,
M31DPHY_APBCFGSAIF__SYSCFG_188,
{
struct stf_vin_dev *vin = csiphy_dev->stfcamss->vin;
u32 mipi_channel_sel, mipi_vc = 0;
- enum sensor_type s_type = SENSOR_ISP0;
+ enum sensor_type s_type = SENSOR_ISP;
switch (s_type) {
case SENSOR_VIN:
break;
- case SENSOR_ISP0:
+ case SENSOR_ISP:
reg_set_bit(vin->clkgen_base,
- CLK_ISP0_MIPI_CTRL,
+ CLK_ISP_MIPI_CTRL,
BIT(24), csiphy_dev->id << 24);
reg_set_bit(vin->clkgen_base,
- CLK_C_ISP0_CTRL,
+ CLK_C_ISP_CTRL,
BIT(25) | BIT(24),
csiphy_dev->id << 24);
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/dma-buf.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "stf_isp_ioctl.h"
+#include "stf_dmabuf.h"
+
+#define TOTAL_SIZE_LIMIT (64 * 1024 * 1024)
+
+static size_t total_size;
+static struct vb2_queue vb2_queue = {
+ .dma_attrs = 0,
+ .gfp_flags = 0,
+ .dma_dir = DMA_TO_DEVICE,
+};
+static struct vb2_buffer vb = {
+ .vb2_queue = &vb2_queue,
+};
+
+static int dmabuf_create(struct device *dev,
+ struct dmabuf_create *head)
+{
+ struct dma_buf *dmabuf = NULL;
+ void *mem_priv = NULL;
+ dma_addr_t *paddr = NULL;
+ int ret = 0;
+
+ mem_priv = vb2_dma_contig_memops.alloc(dev, vb.vb2_queue->dma_attrs,
+ head->size, vb.vb2_queue->dma_dir, vb.vb2_queue->gfp_flags);
+ if (IS_ERR_OR_NULL(mem_priv)) {
+ if (mem_priv)
+ ret = PTR_ERR(mem_priv);
+ goto exit;
+ }
+
+ dmabuf = vb2_dma_contig_memops.get_dmabuf(mem_priv, O_RDWR);
+ if (IS_ERR(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ goto free;
+ }
+
+ head->fd = dma_buf_fd(dmabuf, O_CLOEXEC);
+ if (head->fd < 0) {
+ dma_buf_put(dmabuf);
+ ret = head->fd;
+ goto free;
+ }
+
+ paddr = vb2_dma_contig_memops.cookie(mem_priv);
+ head->paddr = *paddr;
+ return 0;
+free:
+ vb2_dma_contig_memops.put(mem_priv);
+exit:
+ return ret;
+}
+
+int stf_dmabuf_ioctl_alloc(struct device *dev, void *arg)
+{
+ struct dmabuf_create *head = arg;
+ int ret = -EINVAL;
+
+ if (IS_ERR_OR_NULL(head))
+ return -EFAULT;
+
+ head->size = PAGE_ALIGN(head->size);
+ if (!head->size)
+ return -EINVAL;
+ if ((head->size + total_size) > TOTAL_SIZE_LIMIT)
+ return -ENOMEM;
+
+ ret = dmabuf_create(dev, head);
+ if (ret)
+ return -EFAULT;
+
+ total_size += head->size;
+ return ret;
+}
+
+int stf_dmabuf_ioctl_free(struct device *dev, void *arg)
+{
+ struct dmabuf_create *head = arg;
+ struct dma_buf *dmabuf = NULL;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(head))
+ return -EFAULT;
+ if (head->size != PAGE_ALIGN(head->size))
+ return -EINVAL;
+ if (head->size > total_size)
+ return -EINVAL;
+
+ dmabuf = dma_buf_get(head->fd);
+ if (IS_ERR_OR_NULL(dmabuf))
+ return -EINVAL;
+
+ dma_buf_put(dmabuf);
+ vb2_dma_contig_memops.put(dmabuf->priv);
+ total_size -= head->size;
+ return ret;
+}
+
+int stf_dmabuf_ioctl(struct device *dev, unsigned int cmd, void *arg)
+{
+ int ret = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case VIDIOC_STF_DMABUF_ALLOC:
+ ret = stf_dmabuf_ioctl_alloc(dev, arg);
+ break;
+ case VIDIOC_STF_DMABUF_FREE:
+ ret = stf_dmabuf_ioctl_free(dev, arg);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#ifndef STF_DMABUF_H
+#define STF_DMABUF_H
+
+extern int stf_dmabuf_ioctl(struct device *dev, unsigned int cmd, void *arg);
+
+#endif /* STF_DMABUF_H */
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define STF_DVP_NAME "stf_dvp"
-
static const struct dvp_format dvp_formats_st7110[] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, 16},
- { MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
- { MEDIA_BUS_FMT_SRGGB10_1X10, 16},
- { MEDIA_BUS_FMT_SGRBG10_1X10, 16},
- { MEDIA_BUS_FMT_SGBRG10_1X10, 16},
- { MEDIA_BUS_FMT_SBGGR10_1X10, 16},
+ { MEDIA_BUS_FMT_YUYV8_2X8, 8},
+ { MEDIA_BUS_FMT_RGB565_2X8_LE, 8},
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 8},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 8},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 8},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 8},
};
static int dvp_find_format(u32 code,
break;
if (i >= dvp_dev->nformats)
- fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
+ fmt->code = dvp_dev->formats[0].code;
fmt->width = clamp_t(u32,
- fmt->width, 1, STFCAMSS_FRAME_MAX_WIDTH);
+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
+ STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32,
- fmt->height, 1, STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
if (format == NULL)
return -EINVAL;
- dvp_try_format(dvp_dev, state, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
+ mutex_lock(&dvp_dev->stream_lock);
+ if (dvp_dev->stream_count) {
+ fmt->format = *format;
+ mutex_unlock(&dvp_dev->stream_lock);
+ goto out;
+ } else {
+ dvp_try_format(dvp_dev, state, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+ }
+ mutex_unlock(&dvp_dev->stream_lock);
/* Propagate the format from sink to source */
if (fmt->pad == STF_DVP_PAD_SINK) {
fmt->which);
}
+out:
return 0;
}
line = v4l2_get_subdevdata(sd);
if (line->sdev_type == VIN_DEV_TYPE)
dvp_dev->s_type = SENSOR_VIN;
- if (line->sdev_type == ISP0_DEV_TYPE)
- dvp_dev->s_type = SENSOR_ISP0;
- if (line->sdev_type == ISP1_DEV_TYPE)
- dvp_dev->s_type = SENSOR_ISP1;
+ if (line->sdev_type == ISP_DEV_TYPE)
+ dvp_dev->s_type = SENSOR_ISP;
st_info(ST_DVP, "DVP device sensor type: %d\n", dvp_dev->s_type);
}
#include <media/media-entity.h>
#include <video/stf-vin.h>
+#define STF_DVP_NAME "stf_dvp"
+
#define STF_DVP_PAD_SINK 0
#define STF_DVP_PAD_SRC 1
#define STF_DVP_PADS_NUM 2
U0_VIN_CNFG_AXI_DVP_EN,
!!on<<2);
break;
- case SENSOR_ISP0:
+ case SENSOR_ISP:
clk_set_parent(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk,
stfcamss->sys_clk[STFCLK_DVP_INV].clk);
U0_VIN_CNFG_GEN_EN_AXIRD,
0);
break;
- case SENSOR_ISP1:
- st_err(ST_DVP, "please check dvp_dev s_type:%d\n", dvp_dev->s_type);
- break;
default:
break;
}
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include <linux/firmware.h>
+#include "stf_isp_ioctl.h"
+#include "stf_dmabuf.h"
-#define STF_ISP_NAME "stf_isp"
+static int user_config_isp;
+static int isp_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel);
+
+static struct v4l2_rect *
+__isp_get_compose(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which);
+
+static struct v4l2_rect *
+__isp_get_crop(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which);
+
+static struct v4l2_rect *
+__isp_get_scale(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel);
+
+static struct v4l2_rect *
+__isp_get_itiws(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which);
+
+// sink format and raw format must one by one
+static const struct isp_format isp_formats_st7110_sink[] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+};
-static const struct isp_format isp_formats_st7110[] = {
- { MEDIA_BUS_FMT_YUYV8_2X8, 16},
- { MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
- { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
- { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
- { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
- { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+static const struct isp_format isp_formats_st7110_raw[] = {
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
};
-int stf_isp_subdev_init(struct stfcamss *stfcamss, int id)
+static const struct isp_format isp_formats_st7110_compat_10bit_raw[] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+};
+
+static const struct isp_format isp_formats_st7110_compat_8bit_raw[] = {
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
+};
+
+static const struct isp_format isp_formats_st7110_uo[] = {
+ { MEDIA_BUS_FMT_Y12_1X12, 8},
+};
+
+static const struct isp_format isp_formats_st7110_iti[] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+ { MEDIA_BUS_FMT_Y12_1X12, 8},
+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+#define SINK_FORMATS_INDEX 0
+#define UO_FORMATS_INDEX 1
+#define ITI_FORMATS_INDEX 2
+#define RAW_FORMATS_INDEX 3
+
+static const struct isp_format_table isp_formats_st7110[] = {
+ { isp_formats_st7110_sink, ARRAY_SIZE(isp_formats_st7110_sink) }, // 0
+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) }, // 1
+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) }, // 2
+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) }, // 3
+};
+
+int stf_isp_subdev_init(struct stfcamss *stfcamss)
{
- struct stf_isp_dev *isp_dev = &stfcamss->isp_dev[id];
+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
- atomic_set(&isp_dev->ref_count, 0);
- isp_dev->sdev_type = id == 0 ? ISP0_DEV_TYPE : ISP1_DEV_TYPE;
- isp_dev->id = id;
+ isp_dev->sdev_type = ISP_DEV_TYPE;
isp_dev->hw_ops = &isp_ops;
isp_dev->stfcamss = stfcamss;
isp_dev->formats = isp_formats_st7110;
isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110);
mutex_init(&isp_dev->stream_lock);
+ mutex_init(&isp_dev->power_lock);
mutex_init(&isp_dev->setfile_lock);
+ atomic_set(&isp_dev->shadow_count, 0);
return 0;
}
* not apply any controls to H/W at this time. Instead
* the controls will be restored right after power-up.
*/
- if (!atomic_read(&isp_dev->ref_count))
+ mutex_lock(&isp_dev->power_lock);
+ if (isp_dev->power_count == 0) {
+ mutex_unlock(&isp_dev->power_lock);
return 0;
+ }
+ mutex_unlock(&isp_dev->power_lock);
switch (ctrl->id) {
case V4L2_CID_AUTOGAIN:
static int isp_set_power(struct v4l2_subdev *sd, int on)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
-
- if (on)
- atomic_inc(&isp_dev->ref_count);
- else
- atomic_dec(&isp_dev->ref_count);
+ struct stf_vin2_dev *vin_dev = isp_dev->stfcamss->vin_dev;
+
+ st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
+ mutex_lock(&isp_dev->power_lock);
+ if (on) {
+ if (isp_dev->power_count == 0) {
+ /* Needs to enable vin clock before access ISP. */
+ vin_dev->hw_ops->vin_top_clk_init(vin_dev);
+ vin_dev->hw_ops->vin_clk_enable(vin_dev);
+ isp_dev->hw_ops->isp_clk_enable(isp_dev);
+ if (!user_config_isp)
+ isp_dev->hw_ops->isp_config_set(isp_dev);
+ }
+ isp_dev->power_count++;
+ } else {
+ if (isp_dev->power_count == 0)
+ goto exit;
+ if (isp_dev->power_count == 1)
+ isp_dev->hw_ops->isp_clk_disable(isp_dev);
+ isp_dev->power_count--;
+ }
+exit:
+ mutex_unlock(&isp_dev->power_lock);
return 0;
}
return &isp_dev->fmt[pad];
}
+static int isp_get_interface_type(struct media_entity *entity)
+{
+ struct v4l2_subdev *subdev;
+ struct media_pad *pad = &entity->pads[0];
+
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ return -EINVAL;
+
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return -EINVAL;
+
+ subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+ st_debug(ST_ISP, "interface subdev name %s\n", subdev->name);
+ if (!strncmp(subdev->name, STF_CSI_NAME, strlen(STF_CSI_NAME)))
+ return CSI_SENSOR;
+ if (!strncmp(subdev->name, STF_DVP_NAME, strlen(STF_DVP_NAME)))
+ return DVP_SENSOR;
+ return -EINVAL;
+}
+
static int isp_set_stream(struct v4l2_subdev *sd, int enable)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
- int ret = 0;
+ int ret = 0, interface_type;
struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_event src_ch = { 0 };
fmt = __isp_get_format(isp_dev, NULL, STF_ISP_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
mutex_lock(&isp_dev->stream_lock);
if (enable) {
if (isp_dev->stream_count == 0) {
- isp_dev->hw_ops->isp_clk_enable(isp_dev);
- isp_dev->hw_ops->isp_reset(isp_dev);
+ interface_type = isp_get_interface_type(&sd->entity);
+ if (interface_type < 0) {
+ st_err(ST_ISP, "%s, pipeline not config\n", __func__);
+ goto exit;
+ }
isp_dev->hw_ops->isp_set_format(isp_dev,
- &isp_dev->crop, fmt->code);
- // format->width, format->height);
- isp_dev->hw_ops->isp_config_set(isp_dev);
+ isp_dev->rect, fmt->code, interface_type);
+ isp_dev->hw_ops->isp_reset(isp_dev);
isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
+ user_config_isp = 0;
}
isp_dev->stream_count++;
} else {
if (isp_dev->stream_count == 0)
goto exit;
- if (isp_dev->stream_count == 1) {
+ if (isp_dev->stream_count == 1)
isp_dev->hw_ops->isp_stream_set(isp_dev, enable);
- isp_dev->hw_ops->isp_clk_disable(isp_dev);
- }
isp_dev->stream_count--;
}
+ src_ch.type = V4L2_EVENT_SOURCE_CHANGE,
+ src_ch.u.src_change.changes = isp_dev->stream_count,
+
+ v4l2_subdev_notify_event(sd, &src_ch);
exit:
mutex_unlock(&isp_dev->stream_lock);
- if (enable && atomic_read(&isp_dev->ref_count) == 1) {
- /* restore controls */
+ mutex_lock(&isp_dev->power_lock);
+ /* restore controls */
+ if (enable && isp_dev->power_count == 1) {
+ mutex_unlock(&isp_dev->power_lock);
ret = v4l2_ctrl_handler_setup(&isp_dev->ctrls.handler);
- }
+ } else
+ mutex_unlock(&isp_dev->power_lock);
return ret;
}
+/*Try to match sensor format with sink, and then get the index as default.*/
+static int isp_match_sensor_format_get_index(struct stf_isp_dev *isp_dev)
+{
+ int ret, idx;
+ struct media_entity *sensor;
+ struct v4l2_subdev *subdev;
+ struct v4l2_subdev_format fmt;
+ const struct isp_format_table *formats;
+
+ if (!isp_dev)
+ return -EINVAL;
+
+ sensor = stfcamss_find_sensor(&isp_dev->subdev.entity);
+ if (!sensor)
+ return -EINVAL;
+
+ subdev = media_entity_to_v4l2_subdev(sensor);
+ st_debug(ST_ISP, "Found sensor = %s\n", sensor->name);
+
+ fmt.pad = 0;
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret) {
+ st_warn(ST_ISP, "Sonser get format failed !!\n");
+ return -EINVAL;
+ }
+
+ st_debug(ST_ISP, "Got sensor format 0x%x !!\n", fmt.format.code);
+
+ formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+ for (idx = 0; idx < formats->nfmts; idx++) {
+ if (formats->fmts[idx].code == fmt.format.code) {
+ st_info(ST_ISP,
+ "Match sensor format to isp_formats_st7110_sink index %d !!\n",
+ idx);
+ return idx;
+ }
+ }
+ return -ERANGE;
+}
+
+static int isp_match_format_get_index(const struct isp_format_table *f_table,
+ __u32 mbus_code,
+ unsigned int pad)
+{
+ int i;
+
+ for (i = 0; i < f_table->nfmts; i++) {
+ if (mbus_code == f_table->fmts[i].code) {
+ break;
+ } else {
+ if (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y) {
+ if (mbus_code == (isp_formats_st7110_compat_10bit_raw[i].code ||
+ isp_formats_st7110_compat_8bit_raw[i].code))
+ break;
+ }
+ }
+ }
+
+ return i;
+}
+
static void isp_try_format(struct stf_isp_dev *isp_dev,
struct v4l2_subdev_state *state,
unsigned int pad,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
+ const struct isp_format_table *formats;
unsigned int i;
+ u32 code = fmt->code;
+ u32 bpp;
switch (pad) {
case STF_ISP_PAD_SINK:
/* Set format on sink pad */
- for (i = 0; i < isp_dev->nformats; i++)
- if (fmt->code == isp_dev->formats[i].code)
- break;
-
- if (i >= isp_dev->nformats)
- fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
-
+ formats = &isp_dev->formats[SINK_FORMATS_INDEX];
fmt->width = clamp_t(u32,
- fmt->width, 8, STFCAMSS_FRAME_MAX_WIDTH);
- fmt->width &= ~0x7;
+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
+ STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32,
- fmt->height, 1, STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
+ fmt->height &= ~0x1;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
break;
case STF_ISP_PAD_SRC:
+ case STF_ISP_PAD_SRC_SS0:
+ case STF_ISP_PAD_SRC_SS1:
+ formats = &isp_dev->formats[UO_FORMATS_INDEX];
+ break;
+
+ case STF_ISP_PAD_SRC_ITIW:
+ case STF_ISP_PAD_SRC_ITIR:
+ formats = &isp_dev->formats[ITI_FORMATS_INDEX];
+ break;
+ case STF_ISP_PAD_SRC_RAW:
+ case STF_ISP_PAD_SRC_SCD_Y:
+ formats = &isp_dev->formats[RAW_FORMATS_INDEX];
+ break;
+ }
+
+ i = isp_match_format_get_index(formats, fmt->code, pad);
+ st_debug(ST_ISP, "isp_match_format_get_index = %d\n", i);
+
+ if (i >= formats->nfmts &&
+ (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y)) {
+ int sensor_idx;
+
+ sensor_idx = isp_match_sensor_format_get_index(isp_dev);
+ if (sensor_idx)
+ i = sensor_idx;
+ }
+
+ if (pad != STF_ISP_PAD_SINK)
*fmt = *__isp_get_format(isp_dev, state, STF_ISP_PAD_SINK, which);
+ if (i >= formats->nfmts) {
+ fmt->code = formats->fmts[0].code;
+ bpp = formats->fmts[0].bpp;
+ st_info(ST_ISP, "Use default index 0 format = 0x%x\n", fmt->code);
+ } else {
+ // sink format and raw format must one by one
+ if (pad == STF_ISP_PAD_SRC_RAW || pad == STF_ISP_PAD_SRC_SCD_Y) {
+ fmt->code = formats->fmts[i].code;
+ bpp = formats->fmts[i].bpp;
+ st_info(ST_ISP, "Use mapping format from sink index %d = 0x%x\n",
+ i, fmt->code);
+ } else {
+ fmt->code = code;
+ bpp = formats->fmts[i].bpp;
+ st_info(ST_ISP, "Use input format = 0x%x\n", fmt->code);
+ }
+ }
+
+ switch (pad) {
+ case STF_ISP_PAD_SINK:
+ break;
+ case STF_ISP_PAD_SRC:
+ isp_dev->rect[ISP_COMPOSE].bpp = bpp;
+ break;
+ case STF_ISP_PAD_SRC_SS0:
+ isp_dev->rect[ISP_SCALE_SS0].bpp = bpp;
+ break;
+ case STF_ISP_PAD_SRC_SS1:
+ isp_dev->rect[ISP_SCALE_SS1].bpp = bpp;
+ break;
+ case STF_ISP_PAD_SRC_ITIW:
+ case STF_ISP_PAD_SRC_ITIR:
+ isp_dev->rect[ISP_ITIWS].bpp = bpp;
+ break;
+ case STF_ISP_PAD_SRC_RAW:
+ isp_dev->rect[ISP_CROP].bpp = bpp;
+ break;
+ case STF_ISP_PAD_SRC_SCD_Y:
break;
}
}
struct v4l2_subdev_mbus_code_enum *code)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ const struct isp_format_table *formats;
if (code->index >= isp_dev->nformats)
return -EINVAL;
if (code->pad == STF_ISP_PAD_SINK) {
- code->code = isp_dev->formats[code->index].code;
+ formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+ code->code = formats->fmts[code->index].code;
} else {
struct v4l2_mbus_framefmt *sink_fmt;
return 0;
}
-static int isp_set_selection(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_selection *sel);
-
static int isp_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_selection sel = { 0 };
+ struct v4l2_rect *rect = NULL;
+ int ret;
format = __isp_get_format(isp_dev, state, fmt->pad, fmt->which);
if (format == NULL)
return -EINVAL;
- isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count) {
+ fmt->format = *format;
+ if (fmt->reserved[0] != 0) {
+ sel.which = fmt->which;
+ sel.pad = fmt->reserved[0];
+
+ switch (fmt->reserved[0]) {
+ case STF_ISP_PAD_SRC:
+ rect = __isp_get_compose(isp_dev, state, fmt->which);
+ break;
+ case STF_ISP_PAD_SRC_SS0:
+ case STF_ISP_PAD_SRC_SS1:
+ rect = __isp_get_scale(isp_dev, state, &sel);
+ break;
+ case STF_ISP_PAD_SRC_ITIW:
+ case STF_ISP_PAD_SRC_ITIR:
+ rect = __isp_get_itiws(isp_dev, state, fmt->which);
+ break;
+ case STF_ISP_PAD_SRC_RAW:
+ case STF_ISP_PAD_SRC_SCD_Y:
+ rect = __isp_get_crop(isp_dev, state, fmt->which);
+ break;
+ default:
+ break;
+ }
+ if (rect != NULL) {
+ fmt->format.width = rect->width;
+ fmt->format.height = rect->height;
+ }
+ }
+ mutex_unlock(&isp_dev->stream_lock);
+ goto out;
+ } else {
+ isp_try_format(isp_dev, state, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+ }
+ mutex_unlock(&isp_dev->stream_lock);
/* Propagate the format from sink to source */
if (fmt->pad == STF_ISP_PAD_SINK) {
- struct v4l2_subdev_selection sel = { 0 };
- int ret;
-
- format = __isp_get_format(isp_dev, state, STF_ISP_PAD_SRC,
- fmt->which);
-
- *format = fmt->format;
- isp_try_format(isp_dev, state, STF_ISP_PAD_SRC, format,
- fmt->which);
-
/* Reset sink pad compose selection */
sel.which = fmt->which;
sel.pad = STF_ISP_PAD_SINK;
- sel.target = V4L2_SEL_TGT_COMPOSE;
+ sel.target = V4L2_SEL_TGT_CROP;
sel.r.width = fmt->format.width;
sel.r.height = fmt->format.height;
ret = isp_set_selection(sd, state, &sel);
if (ret < 0)
return ret;
-
}
+out:
return 0;
}
return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
STF_ISP_PAD_SINK);
- return &isp_dev->compose;
+
+ return &isp_dev->rect[ISP_COMPOSE].rect;
}
static struct v4l2_rect *
__isp_get_crop(struct stf_isp_dev *isp_dev,
- struct v4l2_subdev_state *state,
- enum v4l2_subdev_format_whence which)
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_crop(&isp_dev->subdev, state,
- STF_ISP_PAD_SRC);
+ STF_ISP_PAD_SINK);
- return &isp_dev->crop;
+ return &isp_dev->rect[ISP_CROP].rect;
}
-static void isp_try_compose(struct stf_isp_dev *isp_dev,
+static struct v4l2_rect *
+__isp_get_scale(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ int pad;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_compose(&isp_dev->subdev, state,
+ STF_ISP_PAD_SINK);
+ if (sel->pad != STF_ISP_PAD_SRC_SS0 && sel->pad != STF_ISP_PAD_SRC_SS1)
+ return NULL;
+
+ pad = sel->pad == STF_ISP_PAD_SRC_SS0 ? ISP_SCALE_SS0 : ISP_SCALE_SS1;
+ return &isp_dev->rect[pad].rect;
+}
+
+static struct v4l2_rect *
+__isp_get_itiws(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(&isp_dev->subdev, state, STF_ISP_PAD_SINK);
+
+ return &isp_dev->rect[ISP_ITIWS].rect;
+}
+
+static void isp_try_crop(struct stf_isp_dev *isp_dev,
struct v4l2_subdev_state *state,
struct v4l2_rect *rect,
enum v4l2_subdev_format_whence which)
if (rect->width > fmt->width)
rect->width = fmt->width;
+ if (rect->width + rect->left > fmt->width)
+ rect->left = fmt->width - rect->width;
+
if (rect->height > fmt->height)
rect->height = fmt->height;
- if (fmt->width > rect->width * SCALER_RATIO_MAX)
- rect->width = (fmt->width + SCALER_RATIO_MAX - 1) /
- SCALER_RATIO_MAX;
-
- rect->width &= ~0x7;
-
- if (fmt->height > rect->height * SCALER_RATIO_MAX)
- rect->height = (fmt->height + SCALER_RATIO_MAX - 1) /
- SCALER_RATIO_MAX;
+ if (rect->height + rect->top > fmt->height)
+ rect->top = fmt->height - rect->height;
- if (rect->width < 16)
- rect->width = 16;
+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
+ rect->left = 0;
+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+ }
- if (rect->height < 4)
- rect->height = 4;
+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
+ rect->top = 0;
+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+ }
+ rect->height &= ~0x1;
}
-static void isp_try_crop(struct stf_isp_dev *isp_dev,
+static void isp_try_compose(struct stf_isp_dev *isp_dev,
struct v4l2_subdev_state *state,
struct v4l2_rect *rect,
enum v4l2_subdev_format_whence which)
{
+ struct v4l2_rect *crop;
+
+ crop = __isp_get_crop(isp_dev, state, which);
+
+ if (rect->width > crop->width)
+ rect->width = crop->width;
+
+ if (rect->height > crop->height)
+ rect->height = crop->height;
+
+ if (crop->width > rect->width * SCALER_RATIO_MAX)
+ rect->width = (crop->width + SCALER_RATIO_MAX - 1) /
+ SCALER_RATIO_MAX;
+
+ if (crop->height > rect->height * SCALER_RATIO_MAX)
+ rect->height = (crop->height + SCALER_RATIO_MAX - 1) /
+ SCALER_RATIO_MAX;
+
+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH)
+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+
+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT)
+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+ rect->height &= ~0x1;
+}
+
+static void isp_try_scale(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_rect *rect,
+ enum v4l2_subdev_format_whence which)
+{
struct v4l2_rect *compose;
compose = __isp_get_compose(isp_dev, state, which);
if (rect->height + rect->top > compose->height)
rect->top = compose->height - rect->height;
- // /* isp in line based mode writes multiple of 16 horizontally */
- rect->left &= ~0x1;
- rect->top &= ~0x1;
- rect->width &= ~0x7;
+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
+ rect->left = 0;
+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
+ }
+
+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
+ rect->top = 0;
+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
+ }
+ rect->height &= ~0x1;
+}
+
+static void isp_try_itiws(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_rect *rect,
+ enum v4l2_subdev_format_whence which)
+{
+ struct v4l2_rect *crop;
+
+ crop = __isp_get_crop(isp_dev, state, which);
+
+ if (rect->width > crop->width)
+ rect->width = crop->width;
+
+ if (rect->width + rect->left > crop->width)
+ rect->left = crop->width - rect->width;
- if (rect->width < 16) {
+ if (rect->height > crop->height)
+ rect->height = crop->height;
+
+ if (rect->height + rect->top > crop->height)
+ rect->top = crop->height - rect->height;
+
+ if (rect->width < STFCAMSS_FRAME_MIN_WIDTH) {
rect->left = 0;
- rect->width = 16;
+ rect->width = STFCAMSS_FRAME_MIN_WIDTH;
}
- if (rect->height < 4) {
+ if (rect->height < STFCAMSS_FRAME_MIN_HEIGHT) {
rect->top = 0;
- rect->height = 4;
+ rect->height = STFCAMSS_FRAME_MIN_HEIGHT;
}
+ rect->height &= ~0x1;
}
static int isp_get_selection(struct v4l2_subdev *sd,
int ret;
switch (sel->target) {
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
fmt.pad = sel->pad;
fmt.which = sel->which;
ret = isp_get_format(sd, state, &fmt);
sel->r.width = fmt.format.width;
sel->r.height = fmt.format.height;
break;
- case V4L2_SEL_TGT_COMPOSE:
- rect = __isp_get_compose(isp_dev, state, sel->which);
+ case V4L2_SEL_TGT_CROP:
+ rect = __isp_get_crop(isp_dev, state, sel->which);
if (rect == NULL)
return -EINVAL;
sel->r = *rect;
break;
- case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
- rect = __isp_get_compose(isp_dev, state, sel->which);
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ if (sel->pad > STF_ISP_PAD_SRC_ITIR)
+ return -EINVAL;
+ rect = __isp_get_crop(isp_dev, state, sel->which);
if (rect == NULL)
return -EINVAL;
sel->r.width = rect->width;
sel->r.height = rect->height;
break;
- case V4L2_SEL_TGT_CROP:
- rect = __isp_get_crop(isp_dev, state, sel->which);
- if (rect == NULL)
+ case V4L2_SEL_TGT_COMPOSE:
+ if (sel->pad > STF_ISP_PAD_SRC_ITIR)
return -EINVAL;
-
+ if (sel->pad == STF_ISP_PAD_SRC_SS0
+ || sel->pad == STF_ISP_PAD_SRC_SS1) {
+ rect = __isp_get_scale(isp_dev, state, sel);
+ if (rect == NULL)
+ return -EINVAL;
+ } else if (sel->pad == STF_ISP_PAD_SRC_ITIW
+ || sel->pad == STF_ISP_PAD_SRC_ITIR) {
+ rect = __isp_get_itiws(isp_dev, state, sel->which);
+ if (rect == NULL)
+ return -EINVAL;
+ } else {
+ rect = __isp_get_compose(isp_dev, state, sel->which);
+ if (rect == NULL)
+ return -EINVAL;
+ }
sel->r = *rect;
break;
default:
return -EINVAL;
}
- st_info(ST_ISP, "get left = %d, %d, %d, %d\n",
- sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+ st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
+ __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
return 0;
}
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
struct v4l2_rect *rect;
- int ret;
+ int ret = 0;
- st_info(ST_ISP, "left = %d, %d, %d, %d\n",
- sel->r.left, sel->r.top, sel->r.width, sel->r.height);
- if (sel->target == V4L2_SEL_TGT_COMPOSE) {
- struct v4l2_subdev_selection crop = { 0 };
+ if (sel->target == V4L2_SEL_TGT_COMPOSE &&
+ ((sel->pad == STF_ISP_PAD_SINK)
+ || (sel->pad == STF_ISP_PAD_SRC))) {
+ struct v4l2_subdev_format fmt = { 0 };
+ int i;
rect = __isp_get_compose(isp_dev, state, sel->which);
if (rect == NULL)
return -EINVAL;
- isp_try_compose(isp_dev, state, &sel->r, sel->which);
- *rect = sel->r;
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count) {
+ sel->r = *rect;
+ mutex_unlock(&isp_dev->stream_lock);
+ ret = 0;
+ goto out;
+ } else {
+ isp_try_compose(isp_dev, state, &sel->r, sel->which);
+ *rect = sel->r;
+ }
+ mutex_unlock(&isp_dev->stream_lock);
- /* Reset source crop selection */
- crop.which = sel->which;
- crop.pad = STF_ISP_PAD_SRC;
- crop.target = V4L2_SEL_TGT_CROP;
- crop.r = *rect;
- ret = isp_set_selection(sd, state, &crop);
- } else if (sel->target == V4L2_SEL_TGT_CROP) {
+ /* Reset source pad format width and height */
+ fmt.which = sel->which;
+ fmt.pad = STF_ISP_PAD_SRC;
+ ret = isp_get_format(sd, state, &fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt.format.width = rect->width;
+ fmt.format.height = rect->height;
+ ret = isp_set_format(sd, state, &fmt);
+
+ /* Reset scale */
+ for (i = STF_ISP_PAD_SRC_SS0; i <= STF_ISP_PAD_SRC_ITIR; i++) {
+ struct v4l2_subdev_selection scale = { 0 };
+
+ scale.which = sel->which;
+ scale.target = V4L2_SEL_TGT_COMPOSE;
+ scale.r = *rect;
+ scale.pad = i;
+ ret = isp_set_selection(sd, state, &scale);
+ }
+ } else if (sel->target == V4L2_SEL_TGT_COMPOSE
+ && ((sel->pad == STF_ISP_PAD_SRC_SS0)
+ || (sel->pad == STF_ISP_PAD_SRC_SS1))) {
struct v4l2_subdev_format fmt = { 0 };
- rect = __isp_get_crop(isp_dev, state, sel->which);
+ rect = __isp_get_scale(isp_dev, state, sel);
if (rect == NULL)
return -EINVAL;
- isp_try_crop(isp_dev, state, &sel->r, sel->which);
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count) {
+ sel->r = *rect;
+ mutex_unlock(&isp_dev->stream_lock);
+ ret = 0;
+ goto out;
+ } else {
+ isp_try_scale(isp_dev, state, &sel->r, sel->which);
+ *rect = sel->r;
+ }
+ mutex_unlock(&isp_dev->stream_lock);
- *rect = sel->r;
+ /* Reset source pad format width and height */
+ fmt.which = sel->which;
+ fmt.pad = sel->pad;
+ ret = isp_get_format(sd, state, &fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt.format.width = rect->width;
+ fmt.format.height = rect->height;
+ ret = isp_set_format(sd, state, &fmt);
+ } else if (sel->target == V4L2_SEL_TGT_COMPOSE
+ && ((sel->pad == STF_ISP_PAD_SRC_ITIW)
+ || (sel->pad == STF_ISP_PAD_SRC_ITIR))) {
+ struct v4l2_subdev_format fmt = { 0 };
+
+ rect = __isp_get_itiws(isp_dev, state, sel->which);
+ if (rect == NULL)
+ return -EINVAL;
+
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count) {
+ sel->r = *rect;
+ mutex_unlock(&isp_dev->stream_lock);
+ ret = 0;
+ goto out;
+ } else {
+ isp_try_itiws(isp_dev, state, &sel->r, sel->which);
+ *rect = sel->r;
+ }
+ mutex_unlock(&isp_dev->stream_lock);
/* Reset source pad format width and height */
fmt.which = sel->which;
- fmt.pad = STF_ISP_PAD_SRC;
+ fmt.pad = sel->pad;
ret = isp_get_format(sd, state, &fmt);
if (ret < 0)
return ret;
fmt.format.width = rect->width;
fmt.format.height = rect->height;
ret = isp_set_format(sd, state, &fmt);
+ } else if (sel->target == V4L2_SEL_TGT_CROP) {
+ struct v4l2_subdev_selection compose = { 0 };
+ int i;
+
+ rect = __isp_get_crop(isp_dev, state, sel->which);
+ if (rect == NULL)
+ return -EINVAL;
+
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count) {
+ sel->r = *rect;
+ mutex_unlock(&isp_dev->stream_lock);
+ ret = 0;
+ goto out;
+ } else {
+ isp_try_crop(isp_dev, state, &sel->r, sel->which);
+ *rect = sel->r;
+ }
+ mutex_unlock(&isp_dev->stream_lock);
+
+ /* Reset source compose selection */
+ compose.which = sel->which;
+ compose.target = V4L2_SEL_TGT_COMPOSE;
+ compose.r.width = rect->width;
+ compose.r.height = rect->height;
+ compose.pad = STF_ISP_PAD_SINK;
+ ret = isp_set_selection(sd, state, &compose);
+
+ /* Reset source pad format width and height */
+ for (i = STF_ISP_PAD_SRC_RAW; i < STF_ISP_PAD_MAX; i++) {
+ struct v4l2_subdev_format fmt = { 0 };
+
+ fmt.which = sel->which;
+ fmt.pad = i;
+ ret = isp_get_format(sd, state, &fmt);
+ if (ret < 0)
+ return ret;
+
+ fmt.format.width = rect->width;
+ fmt.format.height = rect->height;
+ ret = isp_set_format(sd, state, &fmt);
+ }
} else {
ret = -EINVAL;
}
- st_info(ST_ISP, "out left = %d, %d, %d, %d\n",
- sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+ st_info(ST_ISP, "%s pad = %d, left = %d, %d, %d, %d\n",
+ __func__, sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+out:
return ret;
}
static long stf_isp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ struct device *dev = isp_dev->stfcamss->dev;
int ret = -ENOIOCTLCMD;
switch (cmd) {
ret = stf_isp_load_setfile(isp_dev, fw_info->filename);
break;
}
+ case VIDIOC_STF_DMABUF_ALLOC:
+ case VIDIOC_STF_DMABUF_FREE:
+ ret = stf_dmabuf_ioctl(dev, cmd, arg);
+ break;
+ case VIDIOC_STFISP_GET_REG:
+ ret = isp_dev->hw_ops->isp_reg_read(isp_dev, arg);
+ break;
+ case VIDIOC_STFISP_SET_REG:
+ ret = isp_dev->hw_ops->isp_reg_write(isp_dev, arg);
+ break;
+ case VIDIOC_STFISP_SHADOW_LOCK:
+ if (atomic_add_unless(&isp_dev->shadow_count, 1, 1))
+ ret = 0;
+ else
+ ret = -EBUSY;
+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
+ break;
+ case VIDIOC_STFISP_SHADOW_UNLOCK:
+ if (atomic_dec_if_positive(&isp_dev->shadow_count) < 0)
+ ret = -EINVAL;
+ else
+ ret = 0;
+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
+ break;
+ case VIDIOC_STFISP_SHADOW_UNLOCK_N_TRIGGER:
+ {
+ isp_dev->hw_ops->isp_shadow_trigger(isp_dev);
+ if (atomic_dec_if_positive(&isp_dev->shadow_count) < 0)
+ ret = -EINVAL;
+ else
+ ret = 0;
+ st_debug(ST_ISP, "%s, %d, ret = %d\n", __func__, __LINE__, ret);
+ }
+ break;
+ case VIDIOC_STFISP_SET_USER_CONFIG_ISP:
+ st_debug(ST_ISP, "%s, %d set user_config_isp\n", __func__, __LINE__);
+ user_config_isp = 1;
+ break;
default:
break;
}
return ret;
}
+int isp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+
+ st_debug(ST_ISP, "%s, %d\n", __func__, __LINE__);
+ while (atomic_dec_if_positive(&isp_dev->shadow_count) > 0)
+ st_warn(ST_ISP, "user not unlocked the shadow lock, driver unlock it!\n");
+
+ return 0;
+}
+
+static int stf_isp_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+ default:
+ st_debug(ST_ISP, "unspport subscribe_event\n");
+ return -EINVAL;
+ }
+}
+
static const struct v4l2_subdev_core_ops isp_core_ops = {
.s_power = isp_set_power,
.ioctl = stf_isp_ioctl,
.log_status = v4l2_ctrl_subdev_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ // .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .subscribe_event = stf_isp_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_internal_ops isp_v4l2_internal_ops = {
.open = isp_init_formats,
+ .close = isp_close,
};
static const struct media_entity_operations isp_media_ops = {
sd->internal_ops = &isp_v4l2_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d",
- STF_ISP_NAME, isp_dev->id);
+ STF_ISP_NAME, 0);
v4l2_set_subdevdata(sd, isp_dev);
ret = isp_init_formats(sd, NULL);
pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_SS0].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_SS1].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_ITIW].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_ITIR].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_RAW].flags = MEDIA_PAD_FL_SOURCE;
+ pads[STF_ISP_PAD_SRC_SCD_Y].flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
sd->entity.ops = &isp_media_ops;
- ret = media_entity_pads_init(&sd->entity, STF_ISP_PADS_NUM, pads);
+ ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads);
if (ret < 0) {
st_err(ST_ISP, "Failed to init media entity: %d\n", ret);
return ret;
goto free_ctrls;
}
- if (isp_dev->id == 0)
- stf_isp_load_setfile(isp_dev, STF_ISP0_SETFILE);
- else
- stf_isp_load_setfile(isp_dev, STF_ISP1_SETFILE);
-
return 0;
free_ctrls:
media_entity_cleanup(&isp_dev->subdev.entity);
v4l2_ctrl_handler_free(&isp_dev->ctrls.handler);
mutex_destroy(&isp_dev->stream_lock);
+ mutex_destroy(&isp_dev->power_lock);
mutex_destroy(&isp_dev->setfile_lock);
return 0;
}
#include <media/media-entity.h>
#include <video/stf-vin.h>
-#define STF_ISP_PAD_SINK 0
-#define STF_ISP_PAD_SRC 1
-#define STF_ISP_PADS_NUM 2
-
-#define STF_ISP0_SETFILE "stf_isp0_fw.bin"
-#define STF_ISP1_SETFILE "stf_isp1_fw.bin"
-#define FILENAME_MAX_LEN 30
-
-#define SCALER_RATIO_MAX 1 // no compose function
+#define STF_ISP_NAME "stf_isp"
+#define STF_ISP_SETFILE "stf_isp0_fw.bin"
+
+#define ISP_SCD_BUFFER_SIZE (19 * 256 * 4) // align 128
+#define ISP_YHIST_BUFFER_SIZE (64 * 4)
+#define ISP_SCD_Y_BUFFER_SIZE (ISP_SCD_BUFFER_SIZE + ISP_YHIST_BUFFER_SIZE)
+#define ISP_RAW_DATA_BITS 12
+#define SCALER_RATIO_MAX 1 // no compose function
#define STF_ISP_REG_OFFSET_MAX 0x0FFF
#define STF_ISP_REG_DELAY_MAX 100
#define ISP_REG_CSIINTS_ADDR 0x00000008
+#define ISP_REG_SENSOR 0x00000014
#define ISP_REG_DUMP_CFG_0 0x00000024
#define ISP_REG_DUMP_CFG_1 0x00000028
+#define ISP_REG_SCD_CFG_0 0x00000098
+#define ISP_REG_SCD_CFG_1 0x0000009C
+#define ISP_REG_SC_CFG_1 0x000000BC
#define ISP_REG_IESHD_ADDR 0x00000A50
+#define ISP_REG_SS0AY 0x00000A94
+#define ISP_REG_SS0AUV 0x00000A98
+#define ISP_REG_SS0S 0x00000A9C
+#define ISP_REG_SS0IW 0x00000AA8
+#define ISP_REG_SS1AY 0x00000AAC
+#define ISP_REG_SS1AUV 0x00000AB0
+#define ISP_REG_SS1S 0x00000AB4
+#define ISP_REG_SS1IW 0x00000AC0
+#define ISP_REG_YHIST_CFG_4 0x00000CD8
+#define ISP_REG_ITIIWSR 0x00000B20
+#define ISP_REG_ITIDWLSR 0x00000B24
+#define ISP_REG_ITIDWYSAR 0x00000B28
+#define ISP_REG_ITIDWUSAR 0x00000B2C
+#define ISP_REG_ITIDRYSAR 0x00000B30
+#define ISP_REG_ITIDRUSAR 0x00000B34
+#define ISP_REG_ITIPDFR 0x00000B38
+#define ISP_REG_ITIDRLSR 0x00000B3C
+#define ISP_REG_ITIBSR 0x00000B40
+#define ISP_REG_ITIAIR 0x00000B44
+#define ISP_REG_ITIDPSR 0x00000B48
+
+/* The output line of a isp controller */
+enum isp_line_id {
+ STF_ISP_LINE_INVALID = -1,
+ STF_ISP_LINE_SRC = 1,
+ STF_ISP_LINE_SRC_SS0 = 2,
+ STF_ISP_LINE_SRC_SS1 = 3,
+ STF_ISP_LINE_SRC_ITIW = 4,
+ STF_ISP_LINE_SRC_ITIR = 5,
+ STF_ISP_LINE_SRC_RAW = 6,
+ STF_ISP_LINE_SRC_SCD_Y = 7,
+ STF_ISP_LINE_MAX = STF_ISP_LINE_SRC_SCD_Y
+};
+
+/* pad id for media framework */
+enum isp_pad_id {
+ STF_ISP_PAD_SINK = 0,
+ STF_ISP_PAD_SRC = 1,
+ STF_ISP_PAD_SRC_SS0 = 2,
+ STF_ISP_PAD_SRC_SS1 = 3,
+ STF_ISP_PAD_SRC_ITIW = 4,
+ STF_ISP_PAD_SRC_ITIR = 5,
+ STF_ISP_PAD_SRC_RAW = 6,
+ STF_ISP_PAD_SRC_SCD_Y = 7,
+ STF_ISP_PAD_MAX = 8
+};
+
+enum {
+ EN_INT_NONE = 0,
+ EN_INT_ISP_DONE = (0x1 << 24),
+ EN_INT_CSI_DONE = (0x1 << 25),
+ EN_INT_SC_DONE = (0x1 << 26),
+ EN_INT_LINE_INT = (0x1 << 27),
+ EN_INT_ALL = (0xF << 24),
+};
-struct stfisp_fw_info {
- char __user filename[FILENAME_MAX_LEN];
+enum {
+ DVP_SENSOR = 0,
+ CSI_SENSOR,
};
-#define VIDIOC_STFISP_LOAD_FW \
- _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct stfisp_fw_info)
+#define ISP_AWB_OECF_SKIP_FRAME 0
+// 0x0BC [31:30] SEL - sc0 input mux for sc awb
+// 00 : after DEC, 01 : after OBC, 10 : after OECF, 11 : after AWB
+enum scd_type {
+ DEC_TYPE = 0,
+ OBC_TYPE,
+ OECF_TYPE,
+ AWB_TYPE
+};
struct isp_format {
u32 code;
u8 bpp;
};
+struct isp_format_table {
+ const struct isp_format *fmts;
+ int nfmts;
+};
+
struct regval_t {
u32 addr;
u32 val;
int regval_num;
};
+struct isp_stream_format {
+ struct v4l2_rect rect;
+ u32 bpp;
+};
+
struct stf_isp_dev;
enum subdev_type;
int (*isp_reset)(struct stf_isp_dev *isp_dev);
int (*isp_config_set)(struct stf_isp_dev *isp_dev);
int (*isp_set_format)(struct stf_isp_dev *isp_dev,
- struct v4l2_rect *crop, u32 mcode);
+ struct isp_stream_format *crop, u32 mcode,
+ int type);
// u32 width, u32 height);
int (*isp_stream_set)(struct stf_isp_dev *isp_dev, int on);
+ int (*isp_reg_read)(struct stf_isp_dev *isp_dev, void *arg);
+ int (*isp_reg_write)(struct stf_isp_dev *isp_dev, void *arg);
+ int (*isp_shadow_trigger)(struct stf_isp_dev *isp_dev);
};
struct isp_ctrls {
unsigned int state;
};
+enum {
+ ISP_CROP = 0,
+ ISP_COMPOSE,
+ ISP_SCALE_SS0,
+ ISP_SCALE_SS1,
+ ISP_ITIWS,
+ ISP_RECT_MAX
+};
+
struct stf_isp_dev {
enum subdev_type sdev_type; // must be frist
struct stfcamss *stfcamss;
- atomic_t ref_count;
- u8 id;
struct v4l2_subdev subdev;
- struct media_pad pads[STF_ISP_PADS_NUM];
- struct v4l2_mbus_framefmt fmt[STF_ISP_PADS_NUM];
- struct v4l2_rect compose;
- struct v4l2_rect crop;
- const struct isp_format *formats;
+ struct media_pad pads[STF_ISP_PAD_MAX];
+ struct v4l2_mbus_framefmt fmt[STF_ISP_PAD_MAX];
+ struct isp_stream_format rect[ISP_RECT_MAX];
+ const struct isp_format_table *formats;
unsigned int nformats;
struct isp_hw_ops *hw_ops;
+ struct mutex power_lock;
+ int power_count;
struct mutex stream_lock;
int stream_count;
+ atomic_t shadow_count;
struct isp_ctrls ctrls;
struct mutex setfile_lock;
struct isp_setfile setfile;
};
-extern int stf_isp_subdev_init(struct stfcamss *stfcamss, int id);
+extern int stf_isp_subdev_init(struct stfcamss *stfcamss);
extern int stf_isp_register(struct stf_isp_dev *isp_dev,
struct v4l2_device *v4l2_dev);
extern int stf_isp_unregister(struct stf_isp_dev *isp_dev);
extern struct isp_hw_ops isp_ops;
-extern void dump_isp_reg(void *__iomem ispbase, int id);
+extern void dump_isp_reg(void *__iomem ispbase);
#endif /* STF_ISP_H */
#include <linux/fb.h>
#include <linux/module.h>
#include <video/stf-vin.h>
+#include "stf_isp_ioctl.h"
+#include "stf_isp.h"
#include <linux/delay.h>
+#include <linux/clk.h>
+#define USE_NEW_CONFIG_SETTING
-static const struct regval_t isp_sc2235_reg_config_list[] = {
- {0x00000014, 0x0000000c, 0, 0},
-// {0x00000018, 0x000011BB, 0, 0},
+static const struct regval_t isp_reg_init_config_list[] = {
+ /* config DC(0040H~0044H) */
+ {0x00000044, 0x00000000, 0, 0},
+ /* config DEC(0030H) */
+ {0x00000030, 0x00000000, 0, 0},
+ /* config OBC(0034H, 02E0H~02FCH) */
+ {0x00000034, 0x000000BB, 0, 0},
+ {0x000002E0, 0x40404040, 0, 0},
+ {0x000002E4, 0x40404040, 0, 0},
+ {0x000002E8, 0x40404040, 0, 0},
+ {0x000002EC, 0x40404040, 0, 0},
+ {0x000002F0, 0x00000000, 0, 0},
+ {0x000002F4, 0x00000000, 0, 0},
+ {0x000002F8, 0x00000000, 0, 0},
+ {0x000002FC, 0x00000000, 0, 0},
+ /* config LCBQ(0074H, 007CH, 0300H~039FH, and 0400H~049FH) */
+ {0x00000074, 0x00009900, 0, 0},
+ {0x0000007C, 0x01E40040, 0, 0},
+ {0x00000300, 0x01000100, 0, 0},
+ {0x00000304, 0x01000100, 0, 0},
+ {0x00000308, 0x01000100, 0, 0},
+ {0x0000030C, 0x01000100, 0, 0},
+ {0x00000310, 0x01000100, 0, 0},
+ {0x00000314, 0x01000100, 0, 0},
+ {0x00000318, 0x01000100, 0, 0},
+ {0x0000031C, 0x01000100, 0, 0},
+ {0x00000320, 0x01000100, 0, 0},
+ {0x00000324, 0x01000100, 0, 0},
+ {0x00000328, 0x01000100, 0, 0},
+ {0x0000032C, 0x01000100, 0, 0},
+ {0x00000330, 0x00000100, 0, 0},
+ {0x00000334, 0x01000100, 0, 0},
+ {0x00000338, 0x01000100, 0, 0},
+ {0x0000033C, 0x01000100, 0, 0},
+ {0x00000340, 0x01000100, 0, 0},
+ {0x00000344, 0x01000100, 0, 0},
+ {0x00000348, 0x01000100, 0, 0},
+ {0x0000034C, 0x01000100, 0, 0},
+ {0x00000350, 0x01000100, 0, 0},
+ {0x00000354, 0x01000100, 0, 0},
+ {0x00000358, 0x01000100, 0, 0},
+ {0x0000035C, 0x01000100, 0, 0},
+ {0x00000360, 0x01000100, 0, 0},
+ {0x00000364, 0x00000100, 0, 0},
+ {0x00000368, 0x01000100, 0, 0},
+ {0x0000036C, 0x01000100, 0, 0},
+ {0x00000370, 0x01000100, 0, 0},
+ {0x00000374, 0x01000100, 0, 0},
+ {0x00000378, 0x01000100, 0, 0},
+ {0x0000037C, 0x01000100, 0, 0},
+ {0x00000380, 0x01000100, 0, 0},
+ {0x00000384, 0x01000100, 0, 0},
+ {0x00000388, 0x01000100, 0, 0},
+ {0x0000038C, 0x01000100, 0, 0},
+ {0x00000390, 0x01000100, 0, 0},
+ {0x00000394, 0x01000100, 0, 0},
+ {0x00000398, 0x00000100, 0, 0},
+ {0x0000039C, 0x01000100, 0, 0},
+ {0x000003A0, 0x01000100, 0, 0},
+ {0x000003A4, 0x01000100, 0, 0},
+ {0x000003A8, 0x01000100, 0, 0},
+ {0x000003AC, 0x01000100, 0, 0},
+ {0x000003B0, 0x01000100, 0, 0},
+ {0x000003B4, 0x01000100, 0, 0},
+ {0x000003B8, 0x01000100, 0, 0},
+ {0x000003BC, 0x01000100, 0, 0},
+ {0x000003C0, 0x01000100, 0, 0},
+ {0x000003C4, 0x01000100, 0, 0},
+ {0x000003C8, 0x01000100, 0, 0},
+ {0x000003CC, 0x00000100, 0, 0},
+ {0x00000400, 0x00000000, 0, 0},
+ {0x00000404, 0x00000000, 0, 0},
+ {0x00000408, 0x00000000, 0, 0},
+ {0x0000040C, 0x00000000, 0, 0},
+ {0x00000410, 0x00000000, 0, 0},
+ {0x00000414, 0x00000000, 0, 0},
+ {0x00000418, 0x00000000, 0, 0},
+ {0x0000041C, 0x00000000, 0, 0},
+ {0x00000420, 0x00000000, 0, 0},
+ {0x00000424, 0x00000000, 0, 0},
+ {0x00000428, 0x00000000, 0, 0},
+ {0x0000042C, 0x00000000, 0, 0},
+ {0x00000430, 0x00000000, 0, 0},
+ {0x00000434, 0x00000000, 0, 0},
+ {0x00000438, 0x00000000, 0, 0},
+ {0x0000043C, 0x00000000, 0, 0},
+ {0x00000440, 0x00000000, 0, 0},
+ {0x00000444, 0x00000000, 0, 0},
+ {0x00000448, 0x00000000, 0, 0},
+ {0x0000044C, 0x00000000, 0, 0},
+ {0x00000450, 0x00000000, 0, 0},
+ {0x00000454, 0x00000000, 0, 0},
+ {0x00000458, 0x00000000, 0, 0},
+ {0x0000045C, 0x00000000, 0, 0},
+ {0x00000460, 0x00000000, 0, 0},
+ {0x00000464, 0x00000000, 0, 0},
+ {0x00000468, 0x00000000, 0, 0},
+ {0x0000046C, 0x00000000, 0, 0},
+ {0x00000470, 0x00000000, 0, 0},
+ {0x00000474, 0x00000000, 0, 0},
+ {0x00000478, 0x00000000, 0, 0},
+ {0x0000047C, 0x00000000, 0, 0},
+ {0x00000480, 0x00000000, 0, 0},
+ {0x00000484, 0x00000000, 0, 0},
+ {0x00000488, 0x00000000, 0, 0},
+ {0x0000048C, 0x00000000, 0, 0},
+ {0x00000490, 0x00000000, 0, 0},
+ {0x00000494, 0x00000000, 0, 0},
+ {0x00000498, 0x00000000, 0, 0},
+ {0x0000049C, 0x00000000, 0, 0},
+ {0x000004A0, 0x00000000, 0, 0},
+ {0x000004A4, 0x00000000, 0, 0},
+ {0x000004A8, 0x00000000, 0, 0},
+ {0x000004AC, 0x00000000, 0, 0},
+ {0x000004B0, 0x00000000, 0, 0},
+ {0x000004B4, 0x00000000, 0, 0},
+ {0x000004B8, 0x00000000, 0, 0},
+ {0x000004BC, 0x00000000, 0, 0},
+ {0x000004C0, 0x00000000, 0, 0},
+ {0x000004C4, 0x00000000, 0, 0},
+ {0x000004C8, 0x00000000, 0, 0},
+ {0x000004CC, 0x00000000, 0, 0},
+ /* config OECF(0100H~027CH) */
+ {0x00000100, 0x00100000, 0, 0},
+ {0x00000104, 0x00400020, 0, 0},
+ {0x00000108, 0x00800060, 0, 0},
+ {0x0000010C, 0x00C000A0, 0, 0},
+ {0x00000110, 0x010000E0, 0, 0},
+ {0x00000114, 0x02000180, 0, 0},
+ {0x00000118, 0x03000280, 0, 0},
+ {0x0000011C, 0x03FE0380, 0, 0},
+ {0x00000120, 0x00100000, 0, 0},
+ {0x00000124, 0x00400020, 0, 0},
+ {0x00000128, 0x00800060, 0, 0},
+ {0x0000012C, 0x00C000A0, 0, 0},
+ {0x00000130, 0x010000E0, 0, 0},
+ {0x00000134, 0x02000180, 0, 0},
+ {0x00000138, 0x03000280, 0, 0},
+ {0x0000013C, 0x03FE0380, 0, 0},
+ {0x00000140, 0x00100000, 0, 0},
+ {0x00000144, 0x00400020, 0, 0},
+ {0x00000148, 0x00800060, 0, 0},
+ {0x0000014C, 0x00C000A0, 0, 0},
+ {0x00000150, 0x010000E0, 0, 0},
+ {0x00000154, 0x02000180, 0, 0},
+ {0x00000158, 0x03000280, 0, 0},
+ {0x0000015C, 0x03FE0380, 0, 0},
+ {0x00000160, 0x00100000, 0, 0},
+ {0x00000164, 0x00400020, 0, 0},
+ {0x00000168, 0x00800060, 0, 0},
+ {0x0000016C, 0x00C000A0, 0, 0},
+ {0x00000170, 0x010000E0, 0, 0},
+ {0x00000174, 0x02000180, 0, 0},
+ {0x00000178, 0x03000280, 0, 0},
+ {0x0000017C, 0x03FE0380, 0, 0},
+ {0x00000180, 0x00100000, 0, 0},
+ {0x00000184, 0x00400020, 0, 0},
+ {0x00000188, 0x00800060, 0, 0},
+ {0x0000018C, 0x00C000A0, 0, 0},
+ {0x00000190, 0x010000E0, 0, 0},
+ {0x00000194, 0x02000180, 0, 0},
+ {0x00000198, 0x03000280, 0, 0},
+ {0x0000019C, 0x03FE0380, 0, 0},
+ {0x000001A0, 0x00100000, 0, 0},
+ {0x000001A4, 0x00400020, 0, 0},
+ {0x000001A8, 0x00800060, 0, 0},
+ {0x000001AC, 0x00C000A0, 0, 0},
+ {0x000001B0, 0x010000E0, 0, 0},
+ {0x000001B4, 0x02000180, 0, 0},
+ {0x000001B8, 0x03000280, 0, 0},
+ {0x000001BC, 0x03FE0380, 0, 0},
+ {0x000001C0, 0x00100000, 0, 0},
+ {0x000001C4, 0x00400020, 0, 0},
+ {0x000001C8, 0x00800060, 0, 0},
+ {0x000001CC, 0x00C000A0, 0, 0},
+ {0x000001D0, 0x010000E0, 0, 0},
+ {0x000001D4, 0x02000180, 0, 0},
+ {0x000001D8, 0x03000280, 0, 0},
+ {0x000001DC, 0x03FE0380, 0, 0},
+ {0x000001E0, 0x00100000, 0, 0},
+ {0x000001E4, 0x00400020, 0, 0},
+ {0x000001E8, 0x00800060, 0, 0},
+ {0x000001EC, 0x00C000A0, 0, 0},
+ {0x000001F0, 0x010000E0, 0, 0},
+ {0x000001F4, 0x02000180, 0, 0},
+ {0x000001F8, 0x03000280, 0, 0},
+ {0x000001FC, 0x03FE0380, 0, 0},
+ {0x00000200, 0x00800080, 0, 0},
+ {0x00000204, 0x00800080, 0, 0},
+ {0x00000208, 0x00800080, 0, 0},
+ {0x0000020C, 0x00800080, 0, 0},
+ {0x00000210, 0x00800080, 0, 0},
+ {0x00000214, 0x00800080, 0, 0},
+ {0x00000218, 0x00800080, 0, 0},
+ {0x0000021C, 0x00800080, 0, 0},
+ {0x00000220, 0x00800080, 0, 0},
+ {0x00000224, 0x00800080, 0, 0},
+ {0x00000228, 0x00800080, 0, 0},
+ {0x0000022C, 0x00800080, 0, 0},
+ {0x00000230, 0x00800080, 0, 0},
+ {0x00000234, 0x00800080, 0, 0},
+ {0x00000238, 0x00800080, 0, 0},
+ {0x0000023C, 0x00800080, 0, 0},
+ {0x00000240, 0x00800080, 0, 0},
+ {0x00000244, 0x00800080, 0, 0},
+ {0x00000248, 0x00800080, 0, 0},
+ {0x0000024C, 0x00800080, 0, 0},
+ {0x00000250, 0x00800080, 0, 0},
+ {0x00000254, 0x00800080, 0, 0},
+ {0x00000258, 0x00800080, 0, 0},
+ {0x0000025C, 0x00800080, 0, 0},
+ {0x00000260, 0x00800080, 0, 0},
+ {0x00000264, 0x00800080, 0, 0},
+ {0x00000268, 0x00800080, 0, 0},
+ {0x0000026C, 0x00800080, 0, 0},
+ {0x00000270, 0x00800080, 0, 0},
+ {0x00000274, 0x00800080, 0, 0},
+ {0x00000278, 0x00800080, 0, 0},
+ {0x0000027C, 0x00800080, 0, 0},
+ /* config OECFHM(03D0H~03E4H) */
+ {0x000003D0, 0x04000000, 0, 0},
+ {0x000003D4, 0x0C000800, 0, 0},
+ {0x000003D8, 0x00000FFF, 0, 0},
+ {0x000003DC, 0x08000800, 0, 0},
+ {0x000003E0, 0x08000800, 0, 0},
+ {0x000003E4, 0x00000800, 0, 0},
+ /* config LCCF(0050H, 0058H, 00E0H~00ECH) */
+ {0x00000050, 0x021C03C0, 0, 0},
+ {0x00000058, 0x0000000B, 0, 0},
+ {0x000000E0, 0x00000000, 0, 0},
+ {0x000000E4, 0x00000000, 0, 0},
+ {0x000000E8, 0x00000000, 0, 0},
+ {0x000000EC, 0x00000000, 0, 0},
+ /* config AWB(0280H~02DCH) */
+ {0x00000280, 0x00000000, 0, 0},
+ {0x00000284, 0x00000000, 0, 0},
+ {0x00000288, 0x00000000, 0, 0},
+ {0x0000028C, 0x00000000, 0, 0},
+ {0x00000290, 0x00000000, 0, 0},
+ {0x00000294, 0x00000000, 0, 0},
+ {0x00000298, 0x00000000, 0, 0},
+ {0x0000029C, 0x00000000, 0, 0},
+ {0x000002A0, 0x00000000, 0, 0},
+ {0x000002A4, 0x00000000, 0, 0},
+ {0x000002A8, 0x00000000, 0, 0},
+ {0x000002AC, 0x00000000, 0, 0},
+ {0x000002B0, 0x00000000, 0, 0},
+ {0x000002B4, 0x00000000, 0, 0},
+ {0x000002B8, 0x00000000, 0, 0},
+ {0x000002BC, 0x00000000, 0, 0},
+ {0x000002C0, 0x00800080, 0, 0},
+ {0x000002C4, 0x00800080, 0, 0},
+ {0x000002C8, 0x00800080, 0, 0},
+ {0x000002CC, 0x00800080, 0, 0},
+ {0x000002D0, 0x00800080, 0, 0},
+ {0x000002D4, 0x00800080, 0, 0},
+ {0x000002D8, 0x00800080, 0, 0},
+ {0x000002DC, 0x00800080, 0, 0},
+ /* config CTC(0A10H) and DBC(0A14H) filter */
+ {0x00000A10, 0x41400040, 0, 0},
+ {0x00000A14, 0x02000200, 0, 0},
+ /* config CFA(0018H, 0A1CH) */
+ {0x00000018, 0x000011BB, 0, 0},
{0x00000A1C, 0x00000032, 0, 0},
-// {0x0000001C, 0x00000000, 0, 0},
-// {0x00000020, 0x0437077F, 0, 0},
-// {0x00000A0C, 0x04380780, 0, 0},
- {0x00000A80, 0x88000000, 0, 0},
- {0x00000A84, 0x881fa400, 0, 0},
-// {0x00000A88, 0x00000780, 0, 0},
- {0x00000A8C, 0x00000010, 0, 0},
+ /* config CCM(0C40H~0CA4H) */
+ {0x00000C40, 0x00060000, 0, 0},
+ {0x00000C44, 0x00000000, 0, 0},
+ {0x00000C48, 0x00000000, 0, 0},
+ {0x00000C4C, 0x00000000, 0, 0},
+ {0x00000C50, 0x00000000, 0, 0},
+ {0x00000C54, 0x00000000, 0, 0},
+ {0x00000C58, 0x00000000, 0, 0},
+ {0x00000C5C, 0x00000000, 0, 0},
+ {0x00000C60, 0x00000000, 0, 0},
+ {0x00000C64, 0x00000000, 0, 0},
+ {0x00000C68, 0x00000000, 0, 0},
+ {0x00000C6C, 0x00000000, 0, 0},
+ {0x00000C70, 0x00000080, 0, 0},
+ {0x00000C74, 0x00000000, 0, 0},
+ {0x00000C78, 0x00000000, 0, 0},
+ {0x00000C7C, 0x00000000, 0, 0},
+ {0x00000C80, 0x00000080, 0, 0},
+ {0x00000C84, 0x00000000, 0, 0},
+ {0x00000C88, 0x00000000, 0, 0},
+ {0x00000C8C, 0x00000000, 0, 0},
+ {0x00000C90, 0x00000080, 0, 0},
+ {0x00000C94, 0x00000000, 0, 0},
+ {0x00000C98, 0x00000000, 0, 0},
+ {0x00000C9C, 0x00000000, 0, 0},
+ {0x00000CA0, 0x00000700, 0, 0},
+ {0x00000CA4, 0x00000200, 0, 0},
+ /* config GMARGB(0E00H~0E38H) */
+ {0x00000E00, 0x24000000, 0, 0},
+ {0x00000E04, 0x08000020, 0, 0},
+ {0x00000E08, 0x08000040, 0, 0},
+ {0x00000E0C, 0x08000060, 0, 0},
+ {0x00000E10, 0x08000080, 0, 0},
+ {0x00000E14, 0x080000A0, 0, 0},
+ {0x00000E18, 0x080000C0, 0, 0},
+ {0x00000E1C, 0x080000E0, 0, 0},
+ {0x00000E20, 0x08000100, 0, 0},
+ {0x00000E24, 0x08000180, 0, 0},
+ {0x00000E28, 0x08000200, 0, 0},
+ {0x00000E2C, 0x08000280, 0, 0},
+ {0x00000E30, 0x08000300, 0, 0},
+ {0x00000E34, 0x08000380, 0, 0},
+ {0x00000E38, 0x080003FE, 0, 0},
+ /* config R2Y(0E40H~0E60H) */
+ {0x00000E40, 0x0000004C, 0, 0},
+ {0x00000E44, 0x00000097, 0, 0},
+ {0x00000E48, 0x0000001D, 0, 0},
+ {0x00000E4C, 0x000001D5, 0, 0},
+ {0x00000E50, 0x000001AC, 0, 0},
+ {0x00000E54, 0x00000080, 0, 0},
+ {0x00000E58, 0x00000080, 0, 0},
+ {0x00000E5C, 0x00000194, 0, 0},
+ {0x00000E60, 0x000001EC, 0, 0},
+ /* config YCRV(0F00H~0FFCH) */
+ {0x00000F00, 0x00000000, 0, 0},
+ {0x00000F04, 0x00000010, 0, 0},
+ {0x00000F08, 0x00000020, 0, 0},
+ {0x00000F0C, 0x00000030, 0, 0},
+ {0x00000F10, 0x00000040, 0, 0},
+ {0x00000F14, 0x00000050, 0, 0},
+ {0x00000F18, 0x00000060, 0, 0},
+ {0x00000F1C, 0x00000070, 0, 0},
+ {0x00000F20, 0x00000080, 0, 0},
+ {0x00000F24, 0x00000090, 0, 0},
+ {0x00000F28, 0x000000A0, 0, 0},
+ {0x00000F2C, 0x000000B0, 0, 0},
+ {0x00000F30, 0x000000C0, 0, 0},
+ {0x00000F34, 0x000000D0, 0, 0},
+ {0x00000F38, 0x000000E0, 0, 0},
+ {0x00000F3C, 0x000000F0, 0, 0},
+ {0x00000F40, 0x00000100, 0, 0},
+ {0x00000F44, 0x00000110, 0, 0},
+ {0x00000F48, 0x00000120, 0, 0},
+ {0x00000F4C, 0x00000130, 0, 0},
+ {0x00000F50, 0x00000140, 0, 0},
+ {0x00000F54, 0x00000150, 0, 0},
+ {0x00000F58, 0x00000160, 0, 0},
+ {0x00000F5C, 0x00000170, 0, 0},
+ {0x00000F60, 0x00000180, 0, 0},
+ {0x00000F64, 0x00000190, 0, 0},
+ {0x00000F68, 0x000001A0, 0, 0},
+ {0x00000F6C, 0x000001B0, 0, 0},
+ {0x00000F70, 0x000001C0, 0, 0},
+ {0x00000F74, 0x000001D0, 0, 0},
+ {0x00000F78, 0x000001E0, 0, 0},
+ {0x00000F7C, 0x000001F0, 0, 0},
+ {0x00000F80, 0x00000200, 0, 0},
+ {0x00000F84, 0x00000210, 0, 0},
+ {0x00000F88, 0x00000220, 0, 0},
+ {0x00000F8C, 0x00000230, 0, 0},
+ {0x00000F90, 0x00000240, 0, 0},
+ {0x00000F94, 0x00000250, 0, 0},
+ {0x00000F98, 0x00000260, 0, 0},
+ {0x00000F9C, 0x00000270, 0, 0},
+ {0x00000FA0, 0x00000280, 0, 0},
+ {0x00000FA4, 0x00000290, 0, 0},
+ {0x00000FA8, 0x000002A0, 0, 0},
+ {0x00000FAC, 0x000002B0, 0, 0},
+ {0x00000FB0, 0x000002C0, 0, 0},
+ {0x00000FB4, 0x000002D0, 0, 0},
+ {0x00000FB8, 0x000002E0, 0, 0},
+ {0x00000FBC, 0x000002F0, 0, 0},
+ {0x00000FC0, 0x00000300, 0, 0},
+ {0x00000FC4, 0x00000310, 0, 0},
+ {0x00000FC8, 0x00000320, 0, 0},
+ {0x00000FCC, 0x00000330, 0, 0},
+ {0x00000FD0, 0x00000340, 0, 0},
+ {0x00000FD4, 0x00000350, 0, 0},
+ {0x00000FD8, 0x00000360, 0, 0},
+ {0x00000FDC, 0x00000370, 0, 0},
+ {0x00000FE0, 0x00000380, 0, 0},
+ {0x00000FE4, 0x00000390, 0, 0},
+ {0x00000FE8, 0x000003A0, 0, 0},
+ {0x00000FEC, 0x000003B0, 0, 0},
+ {0x00000FF0, 0x000003C0, 0, 0},
+ {0x00000FF4, 0x000003D0, 0, 0},
+ {0x00000FF8, 0x000003E0, 0, 0},
+ {0x00000FFC, 0x000003F0, 0, 0},
+ /* config Shrp(0E80H~0EE8H) */
+ {0x00000E80, 0x00070F00, 0, 0},
+ {0x00000E84, 0x00180F00, 0, 0},
+ {0x00000E88, 0x00800F00, 0, 0},
+ {0x00000E8C, 0x01000F00, 0, 0},
+ {0x00000E90, 0x00100F00, 0, 0},
+ {0x00000E94, 0x00600F00, 0, 0},
+ {0x00000E98, 0x01000F00, 0, 0},
+ {0x00000E9C, 0x01900F00, 0, 0},
+ {0x00000EA0, 0x00000F00, 0, 0},
+ {0x00000EA4, 0x00000F00, 0, 0},
+ {0x00000EA8, 0x00000F00, 0, 0},
+ {0x00000EAC, 0x00000F00, 0, 0},
+ {0x00000EB0, 0x00000F00, 0, 0},
+ {0x00000EB4, 0x00000F00, 0, 0},
+ {0x00000EB8, 0x00000F00, 0, 0},
+ {0x00000EBC, 0x10000000, 0, 0},
+ {0x00000EC0, 0x10000000, 0, 0},
+ {0x00000EC4, 0x10000000, 0, 0},
+ {0x00000EC8, 0x10000000, 0, 0},
+ {0x00000ECC, 0x10000000, 0, 0},
+ {0x00000ED0, 0x10000000, 0, 0},
+ {0x00000ED4, 0x88000D7C, 0, 0},
+ {0x00000ED8, 0x00C00040, 0, 0},
+ {0x00000EDC, 0xFF000000, 0, 0},
+ {0x00000EE0, 0x00A00040, 0, 0},
+ {0x00000EE4, 0x00000000, 0, 0},
+ {0x00000EE8, 0x00000000, 0, 0},
+ /* config DNYUV(0C00H~0C24H) */
+ {0x00000C00, 0x00777777, 0, 0},
+ {0x00000C04, 0x00007777, 0, 0},
+ {0x00000C08, 0x00777777, 0, 0},
+ {0x00000C0C, 0x00007777, 0, 0},
+ {0x00000C10, 0x00600040, 0, 0},
+ {0x00000C14, 0x00D80090, 0, 0},
+ {0x00000C18, 0x01E60144, 0, 0},
+ {0x00000C1C, 0x00600040, 0, 0},
+ {0x00000C20, 0x00D80090, 0, 0},
+ {0x00000C24, 0x01E60144, 0, 0},
+ /* config SAT(0A30H~0A40H, 0A54H~0A58H) */
+ {0x00000A30, 0x00000100, 0, 0},
+ {0x00000A34, 0x001F0001, 0, 0},
+ {0x00000A38, 0x00000000, 0, 0},
+ {0x00000A3C, 0x00000100, 0, 0},
+ {0x00000A40, 0x00000008, 0, 0},
+ {0x00000A54, 0x04010001, 0, 0},
+ {0x00000A58, 0x03FF0001, 0, 0},
+ /* config OBA(0090H~0094H) */
+ {0x00000090, 0x04380000, 0, 0},
+ {0x00000094, 0x04390780, 0, 0},
+ /* config SC(0098H~009CH, 00B8H~00BCH,
+ * 00C0H, 0C4H~0D4H, 04D0H~054CH, 5D0H~5D4H)
+ */
+ {0x0000009C, 0x01000000, 0, 0},
+ {0x000000B8, 0x000C0000, 0, 0},
+ {0x000000BC, 0xC010151D, 0, 0},
+ {0x000000C0, 0x01F1BF08, 0, 0},
+ {0x000000C4, 0xFF00FF00, 0, 0},
+ {0x000000C8, 0xFF00FF00, 0, 0},
+ {0x000000CC, 0xFFFF0000, 0, 0},
+ {0x000000D0, 0xFFFF0000, 0, 0},
+ {0x000000D4, 0xFFFF0000, 0, 0},
+ {0x000000D8, 0x01050107, 0, 0},
+ {0x000004D0, 0x00000000, 0, 0},
+ {0x000004D4, 0x00000000, 0, 0},
+ {0x000004D8, 0x00000000, 0, 0},
+ {0x000004DC, 0x00000000, 0, 0},
+ {0x000004E0, 0x00000000, 0, 0},
+ {0x000004E4, 0x00000000, 0, 0},
+ {0x000004E8, 0x00000000, 0, 0},
+ {0x000004EC, 0x00000000, 0, 0},
+ {0x000004F0, 0x00100000, 0, 0},
+ {0x000004F4, 0x00000000, 0, 0},
+ {0x000004F8, 0x03D20000, 0, 0},
+ {0x000004FC, 0x00000000, 0, 0},
+ {0x00000500, 0x00950000, 0, 0},
+ {0x00000504, 0x00000000, 0, 0},
+ {0x00000508, 0x00253000, 0, 0},
+ {0x0000050C, 0x00000000, 0, 0},
+ {0x00000510, 0x00000000, 0, 0},
+ {0x00000514, 0x00000000, 0, 0},
+ {0x00000518, 0x00000000, 0, 0},
+ {0x0000051C, 0x00000000, 0, 0},
+ {0x00000520, 0x00000000, 0, 0},
+ {0x00000524, 0x00000000, 0, 0},
+ {0x00000528, 0x00000000, 0, 0},
+ {0x0000052C, 0x00000000, 0, 0},
+ {0x00000530, 0x00000000, 0, 0},
+ {0x00000534, 0x00000000, 0, 0},
+ {0x00000538, 0xFFFFFFF0, 0, 0},
+ {0x0000053C, 0x8FFFFFFF, 0, 0},
+ {0x00000540, 0x0000001E, 0, 0},
+ {0x00000544, 0x00000000, 0, 0},
+ {0x00000548, 0x00000000, 0, 0},
+ {0x0000054C, 0xF0F20000, 0, 0},
+ {0x000005D0, 0xFF00FF00, 0, 0},
+ {0x000005D4, 0xFF00FF00, 0, 0},
+ /* config YHIST(0CC8H~0CD8H) */
+ {0x00000CC8, 0x00000000, 0, 0},
+ {0x00000CCC, 0x0437077F, 0, 0},
+ {0x00000CD0, 0x00010002, 0, 0},
+ {0x00000CD4, 0x00000000, 0, 0},
+ /* config CBAR(0600H-0653H) */
+ {0x00000600, 0x043E0782, 0, 0},
+ {0x00000604, 0x00000000, 0, 0},
+ {0x00000608, 0x0437077F, 0, 0},
+ {0x0000060C, 0x00443150, 0, 0},
+ {0x00000610, 0x00000000, 0, 0},
+ {0x00000614, 0x08880888, 0, 0},
+ {0x00000618, 0x02220222, 0, 0},
+ {0x0000061C, 0x04440444, 0, 0},
+ {0x00000620, 0x08880888, 0, 0},
+ {0x00000624, 0x0AAA0AAA, 0, 0},
+ {0x00000628, 0x0CCC0CCC, 0, 0},
+ {0x0000062C, 0x0EEE0EEE, 0, 0},
+ {0x00000630, 0x0FFF0FFF, 0, 0},
+ {0x00000634, 0x08880888, 0, 0},
+ {0x00000638, 0x02220222, 0, 0},
+ {0x0000063C, 0x04440444, 0, 0},
+ {0x00000640, 0x08880888, 0, 0},
+ {0x00000644, 0x0AAA0AAA, 0, 0},
+ {0x00000648, 0x0CCC0CCC, 0, 0},
+ {0x0000064C, 0x0EEE0EEE, 0, 0},
+ {0x00000650, 0x0FFF0FFF, 0, 0},
+ /* config sensor(0014H) */
+ {0x00000014, 0x0000000c, 0, 0},
+ /* config CROP(001CH, 0020H) */
+ {0x0000001C, 0x00000000, 0, 0},
+ {0x00000020, 0x0437077F, 0, 0},
+ /* config isp pileline X/Y size(A0CH) */
+ {0x00000A0C, 0x04380780, 0, 0},
+ /* config CSI dump (24H/28H) */
+ {0x00000028, 0x00030B80, 0, 0},
+ /* Video Output */
+ /* config UO(0A80H~0A90H) */
+ {0x00000A88, 0x00000780, 0, 0},
+ /* NV12 */
+ {0x00000A8C, 0x00000000, 0, 0},
+ /* NV21
+ *{0x00000A8C, 0x00000020, 0, 0},
+ */
{0x00000A90, 0x00000000, 0, 0},
- {0x00000A94, 0x803f4810, 0, 0},
- {0x00000A98, 0x80517990, 0, 0},
- {0x00000A9c, 0x000005c0, 0, 0},
- {0x00000AA0, 0x0c000000, 0, 0},
- {0x00000AA4, 0x0c000000, 0, 0},
- {0x00000AA8, 0x05a0032a, 0, 0},
- {0x00000AAC, 0x0418e410, 0, 0},
- {0x00000AB0, 0x0420cd10, 0, 0},
- {0x00000AB4, 0x0000021c, 0, 0},
- {0x00000AB8, 0x08000000, 0, 0},
- {0x00000ABc, 0x08000000, 0, 0},
- {0x00000AC0, 0x021c03c0, 0, 0},
+ {0x00000A9C, 0x00000780, 0, 0},
+ {0x00000AA0, 0x00000002, 0, 0},
+ {0x00000AA4, 0x00000002, 0, 0},
+ {0x00000AA8, 0x07800438, 0, 0},
+ {0x00000AB4, 0x00000780, 0, 0},
+ {0x00000AB8, 0x00000002, 0, 0},
+ {0x00000ABC, 0x00000002, 0, 0},
+ {0x00000AC0, 0x07800438, 0, 0},
{0x00000AC4, 0x00000000, 0, 0},
- {0x00000E40, 0x0000004D, 0, 0},
- {0x00000E44, 0x00000096, 0, 0},
- {0x00000E48, 0x0000001D, 0, 0},
- {0x00000E4C, 0x000001DA, 0, 0},
- {0x00000E50, 0x000001B6, 0, 0},
- {0x00000E54, 0x00000070, 0, 0},
- {0x00000E58, 0x0000009D, 0, 0},
- {0x00000E5C, 0x0000017C, 0, 0},
- {0x00000E60, 0x000001E6, 0, 0},
- {0x00000010, 0x00000000, 0, 0},
- {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
- {0x00000044, 0x00000000, 0, 0},
- {0x00000A00, 0x00120002, 0, 0},
- {0x00000A00, 0x00120000, 0, 0},
- {0x00000A50, 0x00000002, 0, 0},
- {0x00000A00, 0x00120001, 0, 0},
- {0x00000008, 0x00010000, 0, 0},
- {0x00000008, 0x00020004, 0, 0},
- {0x00000000, 0x00000001, 0, 0},
+ /* config TIL(0B20H~0B48H) */
+ {0x00000B20, 0x04380780, 0, 0},
+ {0x00000B24, 0x00000960, 0, 0},
+ {0x00000B38, 0x00030003, 0, 0},
+ {0x00000B3C, 0x00000960, 0, 0},
+ {0x00000B44, 0x00000000, 0, 0},
+ {0x00000B48, 0x00000000, 0, 0},
+ /* Enable DEC/OBC/OECF/LCCF/AWB/SC/DUMP */
+ {0x00000010, 0x000A00D6, 0x00000000, 0x00},
+ /* Enable CFA/CAR/CCM/GMARGB/R2Y/SHRP/SAT/DNYUV/YCRV/YHIST/CTC/DBC */
+ {0x00000A08, 0x107A01BE, 0x00000000, 0x00},
};
-static const struct regval_t isp_ov13850_reg_config_list[] = {
- {0x00000014, 0x00000001, 0, 0},
-// {0x00000018, 0x000011BB, 0, 0},
- {0x00000A1C, 0x00000030, 0, 0},
-// {0x0000001C, 0x00000000, 0, 0},
-// {0x00000020, 0x0437077F, 0, 0},
-// {0x00000A0C, 0x04380780, 0, 0},
- {0x00000A80, 0x88000000, 0, 0},
- {0x00000A84, 0x881fa400, 0, 0},
-// {0x00000A88, 0x00000780, 0, 0},
- {0x00000A8C, 0x00000010, 0, 0},
- {0x00000A90, 0x00000000, 0, 0},
- {0x00000A94, 0x803f4810, 0, 0},
- {0x00000A98, 0x80517990, 0, 0},
- {0x00000A9c, 0x000005c0, 0, 0},
- {0x00000AA0, 0x0c000000, 0, 0},
- {0x00000AA4, 0x0c000000, 0, 0},
- {0x00000AA8, 0x05a0032a, 0, 0},
- {0x00000AAC, 0x0418e410, 0, 0},
- {0x00000AB0, 0x0420cd10, 0, 0},
- {0x00000AB4, 0x0000021c, 0, 0},
- {0x00000AB8, 0x08000000, 0, 0},
- {0x00000ABc, 0x08000000, 0, 0},
- {0x00000AC0, 0x021c03c0, 0, 0},
- {0x00000AC4, 0x00000000, 0, 0},
- {0x00000E40, 0x0000004D, 0, 0},
- {0x00000E44, 0x00000096, 0, 0},
- {0x00000E48, 0x0000001D, 0, 0},
- {0x00000E4C, 0x000001DA, 0, 0},
- {0x00000E50, 0x000001B6, 0, 0},
- {0x00000E54, 0x00000070, 0, 0},
- {0x00000E58, 0x0000009D, 0, 0},
- {0x00000E5C, 0x0000017C, 0, 0},
- {0x00000E60, 0x000001E6, 0, 0},
- {0x00000010, 0x00000000, 0, 0},
- {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
- {0x00000044, 0x00000000, 0, 0},
- {0x00000008, 0x00010005, 0, 0},
- {0x00000A00, 0x00120002, 0, 0},
- {0x00000A00, 0x00120000, 0, 0},
- {0x00000A00, 0x00120001, 0, 0},
- {0x00000000, 0x00000001, 0, 0},
+const struct reg_table isp_reg_init_settings[] = {
+ {isp_reg_init_config_list,
+ ARRAY_SIZE(isp_reg_init_config_list)},
+};
+
+static const struct regval_t isp_reg_start_config_list[] = {
+#if defined(ENABLE_SS0_SS1)
+ /* ENABLE UO/SS0/SS1/Multi-Frame and Reset ISP */
+ {0x00000A00, 0x00121802, 0x00000000, 0x0A},
+ /* ENABLE UO/SS0/SS1/Multi-Frame and Leave ISP reset */
+ {0x00000A00, 0x00121800, 0x00000000, 0x0A},
+#else
+ /* ENABLE UO/Multi-Frame and Reset ISP */
+ {0x00000A00, 0x00120002, 0x00000000, 0x0A},
+ /* ENABLE UO/Multi-Frame and Leave ISP reset */
+ {0x00000A00, 0x00120000, 0x00000000, 0x0A},
+#endif
+ /* Config ISP shadow mode as next-vsync */
+ {0x00000A50, 0x00000002, 0x00000000, 0x00},
+#if defined(ENABLE_SS0_SS1)
+ /* ENABLE UO/SS0/SS1/Multi-Frame and Enable ISP */
+ {0x00000A00, 0x00121801, 0x00000000, 0x0A},
+#else
+ /* ENABLE UO/Multi-Frame and Enable ISP */
+ {0x00000A00, 0x00120001, 0x00000000, 0x0A},
+#endif
+ /* Config CSI shadow mode as immediate to fetch current setting */
+ {0x00000008, 0x00010004, 0x00000000, 0x0A},
+ /* Config CSI shadow mode as next-vsync */
+ {0x00000008, 0x00020004, 0x00000000, 0x00},
+ /* Enable CSI */
+ {0x00000000, 0x00000001, 0x00000000, 0x0A},
};
-static const struct regval_t isp_1080p_reg_config_list[] = {
+const struct reg_table isp_reg_start_settings[] = {
+ {isp_reg_start_config_list,
+ ARRAY_SIZE(isp_reg_start_config_list)},
+};
+
+static const struct regval_t isp_imx_219_reg_config_list[] = {
+ /* MIPI sensor */
{0x00000014, 0x0000000D, 0, 0},
- // {0x00000018, 0x000011BB, 0, 0},
+ /* config CFA(0018H, 0A1CH) */
{0x00000A1C, 0x00000032, 0, 0},
- // {0x0000001C, 0x00000000, 0, 0},
- // {0x00000020, 0x0437077F, 0, 0},
- // {0x00000A0C, 0x04380780, 0, 0},
- // {0x00000A80, 0xF9000000, 0, 0},
- // {0x00000A84, 0xF91FA400, 0, 0},
- // {0x00000A88, 0x00000780, 0, 0},
{0x00000A8C, 0x00000000, 0, 0},
{0x00000A90, 0x00000000, 0, 0},
+ /* config R2Y(0E40H~0E60H) */
{0x00000E40, 0x0000004C, 0, 0},
{0x00000E44, 0x00000097, 0, 0},
{0x00000E48, 0x0000001D, 0, 0},
{0x00000E58, 0x00000080, 0, 0},
{0x00000E5C, 0x00000194, 0, 0},
{0x00000E60, 0x000001EC, 0, 0},
+ /* Config AWB(0280H~02DCH). Fixed WB gain for IMX-219 sensor. */
{0x00000280, 0x00000000, 0, 0},
{0x00000284, 0x00000000, 0, 0},
{0x00000288, 0x00000000, 0, 0},
{0x000002D4, 0x00800080, 0, 0},
{0x000002D8, 0x00B000B0, 0, 0},
{0x000002DC, 0x00B000B0, 0, 0},
+ /* config GMARGB(0E00H~0E38H)
+ * Gamma RGB 1.9 for IMX-219 sensor
+ */
{0x00000E00, 0x24000000, 0, 0},
{0x00000E04, 0x159500A5, 0, 0},
{0x00000E08, 0x0F9900EE, 0, 0},
{0x00000E34, 0x047C03BB, 0, 0},
{0x00000E38, 0x043703FF, 0, 0},
{0x00000010, 0x00000080, 0, 0},
- {0x00000A08, 0x10000032, 0xFFFFFFF, 0},
+ /* Enable CFA/GMARGB/R2Y */
+ {0x00000A08, 0x10000032, 0x0FFFFFFF, 0x00},
{0x00000A00, 0x00120002, 0, 0},
{0x00000A00, 0x00120000, 0, 0},
{0x00000A50, 0x00000002, 0, 0},
- {0x00000A00, 0x00120001, 0, 0},
{0x00000008, 0x00010000, 0, 0},
{0x00000008, 0x0002000A, 0, 0},
{0x00000000, 0x00000001, 0, 0},
};
-const struct reg_table isp_1920_1080_settings[] = {
- {isp_1080p_reg_config_list,
- ARRAY_SIZE(isp_1080p_reg_config_list)},
-};
-
-const struct reg_table isp_sc2235_settings[] = {
- {isp_sc2235_reg_config_list,
- ARRAY_SIZE(isp_sc2235_reg_config_list)},
-};
-
-const struct reg_table isp_ov13850_settings[] = {
- {isp_ov13850_reg_config_list,
- ARRAY_SIZE(isp_ov13850_reg_config_list)},
+const struct reg_table isp_imx_219_settings[] = {
+ {isp_imx_219_reg_config_list,
+ ARRAY_SIZE(isp_imx_219_reg_config_list)},
};
static struct regval_t isp_format_reg_list[] = {
- {0x0000001C, 0x00000000, 0, 0},
- {0x00000020, 0x0437077F, 0, 0},
- {0x00000A0C, 0x04380780, 0, 0},
- {0x00000A88, 0x00000780, 0, 0},
- {0x00000018, 0x000011BB, 0, 0},
- {0x00000A08, 0x10000022, 0xF0000000, 0},
+ {0x0000001C, 0x00000000, 0x00000000, 0},
+ {0x00000020, 0x0437077F, 0x00000000, 0},
+ {0x00000A0C, 0x04380780, 0x00000000, 0},
+ {0x00000A88, 0x00000780, 0x00000000, 0},
+ {0x00000018, 0x000011BB, 0x00000000, 0},
+ {0x00000A08, 0x10000000, 0xF0000000, 0},
+ {0x00000028, 0x00030B80, 0x0003FFFF, 0},
+ {0x00000AA8, 0x07800438, 0x00000000, 0},
+ {0x00000A9C, 0x00000780, 0x00000000, 0},
+ {0x00000AC0, 0x07800438, 0x00000000, 0},
+ {0x00000AB4, 0x00000780, 0x00000000, 0},
+ {0x00000B20, 0x04380780, 0x00000000, 0},
+ {0x00000B24, 0x00000960, 0x00000000, 0},
+ {0x00000B3C, 0x00000960, 0x00000000, 0},
+ {0x00000014, 0x00000008, 0x00000000, 0},
};
const struct reg_table isp_format_settings[] = {
ARRAY_SIZE(isp_format_reg_list)},
};
-static const struct reg_table *isp_settings = isp_1920_1080_settings;
+#if defined(USE_NEW_CONFIG_SETTING)
+#else
+static struct reg_table *isp_settings = (struct reg_table *)isp_imx_219_settings;
+#endif
static void isp_load_regs(void __iomem *ispbase, const struct reg_table *table)
{
}
}
+static void isp_load_regs_exclude_csi_isp_enable(
+ void __iomem *ispbase,
+ const struct reg_table *table)
+{
+ int j;
+ u32 delay_ms, reg_addr, mask, val;
+
+ for (j = 0; j < table->regval_num; j++) {
+ delay_ms = table->regval[j].delay_ms;
+ reg_addr = table->regval[j].addr;
+ val = table->regval[j].val;
+ mask = table->regval[j].mask;
+
+ if (reg_addr % 4
+ || reg_addr > STF_ISP_REG_OFFSET_MAX
+ || delay_ms > STF_ISP_REG_DELAY_MAX
+ || ((reg_addr == ISP_REG_CSI_INPUT_EN_AND_STATUS) && (val & 0x01))
+ || ((reg_addr == ISP_REG_ISP_CTRL_0) && (val & 0x01)))
+ continue;
+
+ if (mask)
+ reg_set_bit(ispbase, reg_addr, mask, val);
+ else
+ reg_write(ispbase, reg_addr, val);
+ if (delay_ms)
+ usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
+ }
+}
+
static int stf_isp_clk_enable(struct stf_isp_dev *isp_dev)
{
struct stfcamss *stfcamss = isp_dev->stfcamss;
- if (isp_dev->id == 0) {
- clk_prepare_enable(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
- reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
- reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
- } else {
- st_err(ST_ISP, "please check isp id :%d\n", isp_dev->id);
- }
+ clk_prepare_enable(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
return 0;
}
{
struct stfcamss *stfcamss = isp_dev->stfcamss;
- if (isp_dev->id == 0) {
- reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
- reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
- clk_disable_unprepare(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
- } else {
- st_err(ST_ISP, "please check isp id :%d\n", isp_dev->id);
- }
+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_C].rstc);
+ reset_control_deassert(stfcamss->sys_rst[STFRST_WRAPPER_P].rstc);
+ clk_disable_unprepare(stfcamss->sys_clk[STFCLK_WRAPPER_CLK_C].clk);
return 0;
}
+static void __iomem *stf_isp_get_ispbase(struct stf_vin_dev *vin)
+{
+ void __iomem *base = vin->isp_base;
+
+ return base;
+}
+
static int stf_isp_reset(struct stf_isp_dev *isp_dev)
{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ void __iomem *ispbase;
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(1), BIT(1));
+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(1), 0);
+
return 0;
}
struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
void __iomem *ispbase;
- if (isp_dev->id == 0)
- ispbase = vin->isp_isp0_base;
- else
- ispbase = vin->isp_isp1_base;
+ ispbase = stf_isp_get_ispbase(vin);
- st_debug(ST_ISP, "%s, isp_id = %d\n", __func__, isp_dev->id);
+ st_debug(ST_ISP, "%s\n", __func__);
- isp_load_regs(ispbase, isp_format_settings);
+#if defined(USE_NEW_CONFIG_SETTING)
+ mutex_lock(&isp_dev->setfile_lock);
+ isp_load_regs(ispbase, isp_reg_init_settings);
+ if (isp_dev->setfile.state) {
+ st_info(ST_ISP, "%s, Program extra ISP setting!\n", __func__);
+ isp_load_regs_exclude_csi_isp_enable(ispbase,
+ &isp_dev->setfile.settings);
+ }
+
+ mutex_unlock(&isp_dev->setfile_lock);
+#else
mutex_lock(&isp_dev->setfile_lock);
if (isp_dev->setfile.state)
isp_load_regs(ispbase, &isp_dev->setfile.settings);
st_debug(ST_ISP, "config 0x%x = 0x%x\n",
isp_format_reg_list[3].addr,
isp_format_reg_list[3].val);
+#endif
return 0;
}
static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
- struct v4l2_rect *crop, u32 mcode)
- // u32 width, u32 height)
+ struct isp_stream_format *crop_array, u32 mcode,
+ int type)
{
struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ struct stf_dvp_dev *dvp_dev = isp_dev->stfcamss->dvp_dev;
+ struct v4l2_rect *crop = &crop_array[ISP_COMPOSE].rect;
+ u32 bpp = crop_array[ISP_COMPOSE].bpp;
void __iomem *ispbase;
u32 val, val1;
- if (isp_dev->id == 0) {
- ispbase = vin->isp_isp0_base;
- //isp_settings = isp_sc2235_settings;
- //isp_settings = isp_ov13850_settings;
- isp_settings = isp_1920_1080_settings;
- } else {
- ispbase = vin->isp_isp1_base;
- isp_settings = isp_sc2235_settings;
+ ispbase = stf_isp_get_ispbase(vin);
+
+ st_debug(ST_ISP, "interface type is %d(%s)\n",
+ type, type == CSI_SENSOR ? "CSI" : "DVP");
+
+ if (type == DVP_SENSOR) {
+ unsigned int flags = dvp_dev->dvp->flags;
+
+ st_debug(ST_ISP, "dvp flags = 0x%x, hsync active is %s, vsync active is %s\n",
+ flags, flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH ? "high" : "low",
+ flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? "high" : "low");
}
val = crop->left + (crop->top << 16);
isp_format_reg_list[2].val = val;
isp_format_reg_list[3].addr = ISP_REG_STRIDE;
- isp_format_reg_list[3].val = crop->width;
+ isp_format_reg_list[3].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
switch (mcode) {
case MEDIA_BUS_FMT_SRGGB10_1X10:
val1 = 0x10000000;
break;
}
+
isp_format_reg_list[4].addr = ISP_REG_RAW_FORMAT_CFG;
isp_format_reg_list[4].val = val;
isp_format_reg_list[5].val = val1;
isp_format_reg_list[5].mask = 0xF0000000;
- st_info(ST_ISP, "left: %d, top: %d, width = %d, height = %d, code = 0x%x\n",
- crop->left, crop->top, crop->width, crop->height, mcode);
+ st_info(ST_ISP, "src left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+ crop->left, crop->top, crop->width, crop->height, bpp);
+
+ crop = &crop_array[ISP_CROP].rect;
+ bpp = crop_array[ISP_CROP].bpp;
+ val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_128);
+ isp_format_reg_list[6].addr = ISP_REG_DUMP_CFG_1;
+ isp_format_reg_list[6].val = val | 3 << 16;
+ isp_format_reg_list[6].mask = 0x0003FFFF;
+
+ st_info(ST_ISP, "raw left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+ crop->left, crop->top, crop->width, crop->height, bpp);
+
+ crop = &crop_array[ISP_SCALE_SS0].rect;
+ bpp = crop_array[ISP_SCALE_SS0].bpp;
+ isp_format_reg_list[7].addr = ISP_REG_SS0IW;
+ isp_format_reg_list[7].val = (crop->width << 16) + crop->height;
+ isp_format_reg_list[8].addr = ISP_REG_SS0S;
+ isp_format_reg_list[8].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+
+ st_info(ST_ISP, "ss0 left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+ crop->left, crop->top, crop->width, crop->height, bpp);
+
+ crop = &crop_array[ISP_SCALE_SS1].rect;
+ bpp = crop_array[ISP_SCALE_SS1].bpp;
+ isp_format_reg_list[9].addr = ISP_REG_SS1IW;
+ isp_format_reg_list[9].val = (crop->width << 16) + crop->height;
+ isp_format_reg_list[10].addr = ISP_REG_SS1S;
+ isp_format_reg_list[10].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+
+ crop = &crop_array[ISP_ITIWS].rect;
+ bpp = crop_array[ISP_ITIWS].bpp;
+ isp_format_reg_list[11].addr = ISP_REG_ITIIWSR;
+ isp_format_reg_list[11].val = (crop->height << 16) + crop->width;
+ isp_format_reg_list[12].addr = ISP_REG_ITIDWLSR;
+ isp_format_reg_list[12].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ isp_format_reg_list[13].addr = ISP_REG_ITIDRLSR;
+ isp_format_reg_list[13].val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ st_info(ST_ISP, "iti left: %d, top: %d, width = %d, height = %d, bpp = %d\n",
+ crop->left, crop->top, crop->width, crop->height, bpp);
+
+ isp_format_reg_list[14].addr = ISP_REG_SENSOR;
+ isp_format_reg_list[14].val = 0x00000000;
+ if (type == DVP_SENSOR) {
+ unsigned int flags = dvp_dev->dvp->flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ isp_format_reg_list[14].val |= 0x08;
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ isp_format_reg_list[14].val |= 0x04;
+ } else {
+ isp_format_reg_list[14].val |= 0x01;
+ }
+
+ isp_load_regs(ispbase, isp_format_settings);
return 0;
}
static int stf_isp_stream_set(struct stf_isp_dev *isp_dev, int on)
{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+
+ void __iomem *ispbase;
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ if (on) {
+#if defined(USE_NEW_CONFIG_SETTING)
+ isp_load_regs(ispbase, isp_reg_start_settings);
+#else
+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x3FFFF, 0x3000a);
+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
+ reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
+#endif //#if defined(USE_NEW_CONFIG_SETTING)
+ }
+ //else //disable crash
+ // reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 0);
+ return 0;
+}
+
+static union reg_buf reg_buf;
+static int stf_isp_reg_read(struct stf_isp_dev *isp_dev, void *arg)
+{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ void __iomem *ispbase;
+ struct isp_reg_param *reg_param = arg;
+ u32 size;
+ unsigned long r;
+
+ if (reg_param->reg_buf == NULL) {
+ st_err(ST_ISP, "Failed to access register. The pointer is NULL!!!\n");
+ return -EINVAL;
+ }
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ size = 0;
+ switch (reg_param->reg_info.method) {
+ case STF_ISP_REG_METHOD_ONE_REG:
+ break;
+
+ case STF_ISP_REG_METHOD_SERIES:
+ if (reg_param->reg_info.length > STF_ISP_REG_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_BUF_SIZE);
+ return -EINVAL;
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_MODULE:
+ /* This mode is not supported in the V4L2 version. */
+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
+ STF_ISP_REG_METHOD_MODULE is not supported!!!\n");
+ return -ENOTTY;
+
+ case STF_ISP_REG_METHOD_TABLE:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 2;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_2:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_2_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_2_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 3;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_3:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_3_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_3_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 4;
+ break;
+
+ case STF_ISP_REG_METHOD_SMPL_PACK:
+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
+ STF_ISP_REG_METHOD_SMPL_PACK is not supported!!!\n");
+ return -ENOTTY;
+
+ case STF_ISP_REG_METHOD_SOFT_RDMA:
+ // This mode is not supported in the V4L2 version.
+ st_err(ST_ISP, "Reg Read - Failed to access register. The method = \
+ STF_ISP_REG_METHOD_SOFT_RDMA is not supported!!!\n");
+ return -ENOTTY;
+
+ default:
+ st_err(ST_ISP, "Failed to access register. The method=%d \
+ is not supported!!!\n", reg_param->reg_info.method);
+ return -ENOTTY;
+ }
+
+ memset(®_buf, 0, sizeof(union reg_buf));
+ if (size) {
+ r = copy_from_user((u8 *)reg_buf.buffer,
+ (u8 *)reg_param->reg_buf->buffer, size);
+ if (r) {
+ st_err(ST_ISP, "Failed to call copy_from_user for the \
+ reg_param->reg_buf value\n");
+ return -EIO;
+ }
+ }
+
+ size = 0;
+ switch (reg_param->reg_info.method) {
+ case STF_ISP_REG_METHOD_ONE_REG:
+ reg_buf.buffer[0] = reg_read(ispbase, reg_param->reg_info.offset);
+ size = sizeof(u32);
+ break;
+
+ case STF_ISP_REG_METHOD_SERIES:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ reg_buf.buffer[r] = reg_read(ispbase,
+ reg_param->reg_info.offset + (r * 4));
+ }
+ size = sizeof(u32) * reg_param->reg_info.length;
+ break;
+
+ case STF_ISP_REG_METHOD_MODULE:
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ reg_buf.reg_tbl[r].value = reg_read(ispbase,
+ reg_buf.reg_tbl[r].offset);
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 2;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_2:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ if (reg_buf.reg_tbl2[r].mask) {
+ reg_buf.reg_tbl2[r].value = (reg_read(ispbase,
+ reg_buf.reg_tbl2[r].offset)
+ & reg_buf.reg_tbl2[r].mask);
+ } else {
+ reg_buf.reg_tbl2[r].value = reg_read(ispbase,
+ reg_buf.reg_tbl2[r].offset);
+ }
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 3;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_3:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ if (reg_buf.reg_tbl3[r].mask) {
+ reg_buf.reg_tbl3[r].value = (reg_read(ispbase,
+ reg_buf.reg_tbl3[r].offset)
+ & reg_buf.reg_tbl3[r].mask);
+ } else {
+ reg_buf.reg_tbl3[r].value = reg_read(ispbase,
+ reg_buf.reg_tbl3[r].offset);
+ }
+ if (reg_buf.reg_tbl3[r].delay_ms) {
+ usleep_range(1000 * reg_buf.reg_tbl3[r].delay_ms,
+ 1000 * reg_buf.reg_tbl3[r].delay_ms + 100);
+ }
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 4;
+ break;
+
+ case STF_ISP_REG_METHOD_SMPL_PACK:
+ break;
+
+ case STF_ISP_REG_METHOD_SOFT_RDMA:
+ break;
+
+ default:
+ break;
+ }
+
+ r = copy_to_user((u8 *)reg_param->reg_buf->buffer, (u8 *)reg_buf.buffer,
+ size);
+ if (r) {
+ st_err(ST_ISP, "Failed to call copy_to_user for the \
+ reg_param->buffer value\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int stf_isp_soft_rdma(struct stf_isp_dev *isp_dev, u32 rdma_addr)
+{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ void __iomem *ispbase;
+ struct isp_rdma_info *rdma_info = NULL;
+ s32 len;
+ u32 offset;
+ int ret = 0;
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ rdma_info = phys_to_virt(rdma_addr);
+ while (1) {
+ if (rdma_info->tag == RDMA_WR_ONE) {
+ reg_write(ispbase, rdma_info->offset, rdma_info->param);
+ rdma_info++;
+ } else if (rdma_info->tag == RDMA_WR_SRL) {
+ offset = rdma_info->offset;
+ len = rdma_info->param;
+ rdma_info++;
+ while (len > 0) {
+ reg_write(ispbase, offset, rdma_info->param);
+ offset += 4;
+ len--;
+ if (len > 0) {
+ reg_write(ispbase, offset, rdma_info->value);
+ len--;
+ }
+ offset += 4;
+ rdma_info++;
+ }
+ } else if (rdma_info->tag == RDMA_LINK) {
+ rdma_info = phys_to_virt(rdma_info->param);
+ } else if (rdma_info->tag == RDMA_SINT) {
+ /* Software not support this command. */
+ rdma_info++;
+ } else if (rdma_info->tag == RDMA_END) {
+ break;
+ } else
+ rdma_info++;
+ }
+
+ return ret;
+}
+
+static int stf_isp_reg_write(struct stf_isp_dev *isp_dev, void *arg)
+{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ void __iomem *ispbase;
+ struct isp_reg_param *reg_param = arg;
+ struct isp_rdma_info *rdma_info = NULL;
+ s32 len;
+ u32 offset;
+ u32 size;
+ unsigned long r;
+ int ret = 0;
+
+ if ((reg_param->reg_buf == NULL)
+ && (reg_param->reg_info.method != STF_ISP_REG_METHOD_SOFT_RDMA)) {
+ st_err(ST_ISP, "Failed to access register. \
+ The register buffer pointer is NULL!!!\n");
+ return -EINVAL;
+ }
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ size = 0;
+ switch (reg_param->reg_info.method) {
+ case STF_ISP_REG_METHOD_ONE_REG:
+ size = sizeof(u32);
+ break;
+
+ case STF_ISP_REG_METHOD_SERIES:
+ if (reg_param->reg_info.length > STF_ISP_REG_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length;
+ break;
+
+ case STF_ISP_REG_METHOD_MODULE:
+ // This mode is not supported in the V4L2 version.
+ st_err(ST_ISP, "Reg Write - Failed to access register. \
+ The method = STF_ISP_REG_METHOD_MODULE is not supported!!!\n");
+ return -ENOTTY;
+
+ case STF_ISP_REG_METHOD_TABLE:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 2;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_2:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_2_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_2_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 3;
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_3:
+ if (reg_param->reg_info.length > STF_ISP_REG_TBL_3_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_TBL_3_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 4;
+ break;
+
+ case STF_ISP_REG_METHOD_SMPL_PACK:
+ if (reg_param->reg_info.length > STF_ISP_REG_SMPL_PACK_BUF_SIZE) {
+ st_err(ST_ISP, "Failed to access register. \
+ The (length=0x%08X > 0x%08X) is out of size!!!\n",
+ reg_param->reg_info.length, STF_ISP_REG_SMPL_PACK_BUF_SIZE);
+ return -EINVAL;
+ }
+ size = sizeof(u32) * reg_param->reg_info.length * 2;
+ break;
+
+ case STF_ISP_REG_METHOD_SOFT_RDMA:
+ break;
+
+ default:
+ st_err(ST_ISP, "Failed to access register. The method=%d \
+ is not supported!!!\n", reg_param->reg_info.method);
+ return -ENOTTY;
+ }
+
+ memset(®_buf, 0, sizeof(union reg_buf));
+ if (size) {
+ r = copy_from_user((u8 *)reg_buf.buffer,
+ (u8 *)reg_param->reg_buf->buffer, size);
+ if (r) {
+ st_err(ST_ISP, "Failed to call copy_from_user for the \
+ reg_param->reg_buf value\n");
+ return -EIO;
+ }
+ }
+
+ switch (reg_param->reg_info.method) {
+ case STF_ISP_REG_METHOD_ONE_REG:
+ reg_write(ispbase, reg_param->reg_info.offset, reg_buf.buffer[0]);
+ break;
+
+ case STF_ISP_REG_METHOD_SERIES:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ reg_write(ispbase, reg_param->reg_info.offset + (r * 4),
+ reg_buf.buffer[r]);
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_MODULE:
+ /* This mode is not supported in the V4L2 version. */
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ reg_write(ispbase, reg_buf.reg_tbl[r].offset,
+ reg_buf.reg_tbl[r].value);
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_2:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ if (reg_buf.reg_tbl2[r].mask) {
+ reg_set_bit(ispbase, reg_buf.reg_tbl2[r].offset,
+ reg_buf.reg_tbl2[r].mask, reg_buf.reg_tbl2[r].value);
+ } else {
+ reg_write(ispbase, reg_buf.reg_tbl2[r].offset,
+ reg_buf.reg_tbl2[r].value);
+ }
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_TABLE_3:
+ for (r = 0; r < reg_param->reg_info.length; r++) {
+ if (reg_buf.reg_tbl3[r].mask) {
+ reg_set_bit(ispbase, reg_buf.reg_tbl3[r].offset,
+ reg_buf.reg_tbl3[r].mask, reg_buf.reg_tbl3[r].value);
+ } else {
+ reg_write(ispbase, reg_buf.reg_tbl3[r].offset,
+ reg_buf.reg_tbl3[r].value);
+ }
+ if (reg_buf.reg_tbl3[r].delay_ms) {
+ usleep_range(1000 * reg_buf.reg_tbl3[r].delay_ms,
+ 1000 * reg_buf.reg_tbl3[r].delay_ms + 100);
+ }
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_SMPL_PACK:
+ size = reg_param->reg_info.length;
+ rdma_info = ®_buf.rdma_cmd[0];
+ while (size) {
+ if (rdma_info->tag == RDMA_WR_ONE) {
+ reg_write(ispbase, rdma_info->offset, rdma_info->param);
+ rdma_info++;
+ size--;
+ } else if (rdma_info->tag == RDMA_WR_SRL) {
+ offset = rdma_info->offset;
+ len = rdma_info->param;
+ rdma_info++;
+ size--;
+ while (size && (len > 0)) {
+ reg_write(ispbase, offset, rdma_info->param);
+ offset += 4;
+ len--;
+ if (len > 0) {
+ reg_write(ispbase, offset, rdma_info->value);
+ len--;
+ }
+ offset += 4;
+ rdma_info++;
+ size--;
+ }
+ } else if (rdma_info->tag == RDMA_END) {
+ break;
+ } else {
+ rdma_info++;
+ size--;
+ }
+ }
+ break;
+
+ case STF_ISP_REG_METHOD_SOFT_RDMA:
+ /*
+ * Simulation the hardware RDMA behavior to debug and verify
+ * the RDMA chain.
+ */
+ ret = stf_isp_soft_rdma(isp_dev, reg_param->reg_info.offset);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int stf_isp_shadow_trigger(struct stf_isp_dev *isp_dev)
+{
+ struct stf_vin_dev *vin = isp_dev->stfcamss->vin;
+ void __iomem *ispbase;
+
+ ispbase = stf_isp_get_ispbase(vin);
+
+ // shadow update
+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, (BIT(17) | BIT(16)), 0x30000);
+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, (BIT(1) | BIT(0)), 0x3);
return 0;
}
-void dump_isp_reg(void *__iomem ispbase, int id)
+void dump_isp_reg(void *__iomem ispbase)
{
int j;
u32 addr, val;
- st_debug(ST_ISP, "DUMP ISP%d register:\n", id);
+ st_debug(ST_ISP, "DUMP ISP register:\n");
+
+ for (j = 0; j < isp_reg_init_settings->regval_num; j++) {
+ addr = isp_reg_init_settings->regval[j].addr;
+ val = ioread32(ispbase + addr);
+ st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", addr, val);
+ }
+
for (j = 0; j < isp_format_settings->regval_num; j++) {
addr = isp_format_settings->regval[j].addr;
val = ioread32(ispbase + addr);
val = ioread32(ispbase + ISP_REG_DUMP_CFG_1);
st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", ISP_REG_DUMP_CFG_1, val);
- for (j = 0; j < isp_settings->regval_num; j++) {
- addr = isp_settings->regval[j].addr;
+ for (j = 0; j < isp_reg_start_settings->regval_num; j++) {
+ addr = isp_reg_start_settings->regval[j].addr;
val = ioread32(ispbase + addr);
st_debug(ST_ISP, "{0x%08x, 0x%08x}\n", addr, val);
}
.isp_config_set = stf_isp_config_set,
.isp_set_format = stf_isp_set_format,
.isp_stream_set = stf_isp_stream_set,
+ .isp_reg_read = stf_isp_reg_read,
+ .isp_reg_write = stf_isp_reg_write,
+ .isp_shadow_trigger = stf_isp_shadow_trigger,
};
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ */
+#ifndef STF_ISP_IOCTL_H
+#define STF_ISP_IOCTL_H
+
+
+#include <media/v4l2-ctrls.h>
+
+
+#define FILENAME_MAX_LEN 30
+
+#define ISP_IOC ('V')
+#define STF_ISP_REG_BUF_SIZE (768)
+#define STF_ISP_REG_TBL_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 2)
+#define STF_ISP_REG_TBL_2_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 3)
+#define STF_ISP_REG_TBL_3_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 4)
+#define STF_ISP_REG_SMPL_PACK_BUF_SIZE (STF_ISP_REG_BUF_SIZE / 2)
+#define RDMA_WR_ONE (0xA0)
+#define RDMA_WR_SRL (0xA1)
+#define RDMA_LINK (0xA2)
+#define RDMA_SINT (0xA3)
+#define RDMA_END (0xAF)
+
+
+enum _STF_ISP_IOCTL {
+ STF_ISP_IOCTL_LOAD_FW = BASE_VIDIOC_PRIVATE + 1,
+ STF_ISP_IOCTL_DMABUF_ALLOC,
+ STF_ISP_IOCTL_DMABUF_FREE,
+ STF_ISP_IOCTL_GET_HW_VER,
+ STF_ISP_IOCTL_REG,
+ STF_ISP_IOCTL_SHADOW_LOCK,
+ STF_ISP_IOCTL_SHADOW_UNLOCK,
+ STF_ISP_IOCTL_SHADOW_UNLOCK_N_TRIGGER,
+ STF_ISP_IOCTL_SET_USER_CONFIG_ISP,
+ STF_ISP_IOCTL_MAX
+};
+
+enum _STF_ISP_REG_METHOD {
+ STF_ISP_REG_METHOD_ONE_REG = 0,
+ STF_ISP_REG_METHOD_SERIES,
+ STF_ISP_REG_METHOD_MODULE,
+ STF_ISP_REG_METHOD_TABLE,
+ STF_ISP_REG_METHOD_TABLE_2,
+ STF_ISP_REG_METHOD_TABLE_3,
+ STF_ISP_REG_METHOD_SMPL_PACK,
+ STF_ISP_REG_METHOD_SOFT_RDMA,
+ STF_ISP_REG_METHOD_MAX
+};
+
+
+struct stfisp_fw_info {
+ char __user filename[FILENAME_MAX_LEN];
+};
+
+struct dmabuf_create {
+ __u32 fd;
+ __u32 size;
+ __u32 paddr;
+};
+
+struct isp_rdma_info {
+ u32 param;
+ union {
+ u32 value;
+ struct {
+ u32 offset : 24;
+ u32 tag : 8;
+ };
+ };
+};
+
+struct isp_reg_info {
+ /** @brief [in] access method of register */
+ u8 method;
+ /** @brief [in] offset indicated which register will be read/write */
+ u32 offset;
+ /** @brief [in] length for indicated how much register will be read/write */
+ u32 length;
+};
+
+union reg_buf {
+ u32 buffer[STF_ISP_REG_BUF_SIZE];
+ struct {
+ u32 offset;
+ u32 value;
+ } reg_tbl[STF_ISP_REG_TBL_BUF_SIZE];
+ struct {
+ u32 offset;
+ u32 value;
+ u32 mask;
+ } reg_tbl2[STF_ISP_REG_TBL_2_BUF_SIZE];
+ struct {
+ u32 offset;
+ u32 value;
+ u32 mask;
+ u32 delay_ms;
+ } reg_tbl3[STF_ISP_REG_TBL_3_BUF_SIZE];
+ struct isp_rdma_info rdma_cmd[STF_ISP_REG_SMPL_PACK_BUF_SIZE];
+};
+
+struct isp_reg_param {
+ /** @brief [in, out] register read/write information */
+ struct isp_reg_info reg_info;
+ /** @brief [in, out] buffer */
+ union reg_buf *reg_buf;
+};
+
+
+#define VIDIOC_STFISP_LOAD_FW \
+ _IOW(ISP_IOC, STF_ISP_IOCTL_LOAD_FW, struct stfisp_fw_info)
+#define VIDIOC_STF_DMABUF_ALLOC \
+ _IOWR(ISP_IOC, STF_ISP_IOCTL_DMABUF_ALLOC, struct dmabuf_create)
+#define VIDIOC_STF_DMABUF_FREE \
+ _IOWR(ISP_IOC, STF_ISP_IOCTL_DMABUF_FREE, struct dmabuf_create)
+#define VIDIOC_STFISP_GET_REG \
+ _IOWR(ISP_IOC, STF_ISP_IOCTL_REG, struct isp_reg_param)
+#define VIDIOC_STFISP_SET_REG \
+ _IOW(ISP_IOC, STF_ISP_IOCTL_REG, struct isp_reg_param)
+#define VIDIOC_STFISP_SHADOW_LOCK \
+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_LOCK)
+#define VIDIOC_STFISP_SHADOW_UNLOCK \
+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_UNLOCK)
+#define VIDIOC_STFISP_SHADOW_UNLOCK_N_TRIGGER \
+ _IO(ISP_IOC, STF_ISP_IOCTL_SHADOW_UNLOCK_N_TRIGGER)
+#define VIDIOC_STFISP_SET_USER_CONFIG_ISP \
+ _IO(ISP_IOC, STF_ISP_IOCTL_SET_USER_CONFIG_ISP)
+
+
+#endif /* STF_ISP_IOCTL_H */
{ { 1, 1 } }, { { 1, 1 } }, { 16 } },
{ MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_PIX_FMT_RGB565, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 16 } },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 8 } },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
};
static const struct stfcamss_format_info formats_raw_st7110_isp[] = {
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB12, 1,
+ { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG12, 1,
+ { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG12, 1,
+ { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR12, 1,
+ { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
{ { 1, 1 } }, { { 1, 1 } }, { 12 } },
};
static const struct stfcamss_format_info formats_pix_st7110_isp[] = {
- // { MEDIA_BUS_FMT_YUYV12_2X12, V4L2_PIX_FMT_NV21M, 2,
+ // { MEDIA_BUS_FMT_YUYV12_2X12, V4L2_PIX_FMT_NV12M, 2,
// { { 1, 1 }, { 1, 1 } }, { { 1, 1 }, { 1, 1 } }, { 8 , 4 } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_NV21, 1,
+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
{ { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_NV21, 1,
+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
{ { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_NV12, 1,
+};
+
+static const struct stfcamss_format_info formats_st7110_isp_iti[] = {
+ // raw format
+ { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 10 } },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 1,
+ { { 1, 1 } }, { { 1, 1 } }, { 12 } },
+
+ // YUV420
+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV12, 1,
{ { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_NV12, 1,
+ { MEDIA_BUS_FMT_Y12_1X12, V4L2_PIX_FMT_NV21, 1,
{ { 1, 1 } }, { { 2, 3 } }, { 8 } },
+
+ // YUV444
+ { MEDIA_BUS_FMT_YUV8_1X24, V4L2_PIX_FMT_NV24, 1,
+ { { 1, 1 } }, { { 1, 3 } }, { 8 } },
+ { MEDIA_BUS_FMT_VUY8_1X24, V4L2_PIX_FMT_NV42, 1,
+ { { 1, 1 } }, { { 1, 3 } }, { 8 } },
};
static int video_find_format(u32 code, u32 pixelformat,
memset(pix_mp, 0, sizeof(*pix_mp));
pix_mp->pixelformat = fi->pixelformat;
- pix_mp->width = clamp_t(u32, width, 1,
+ pix_mp->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
STFCAMSS_FRAME_MAX_WIDTH);
- pix_mp->height = clamp_t(u32, height, 1,
- STFCAMSS_FRAME_MAX_HEIGHT_RDI);
+ pix_mp->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
pix_mp->num_planes = fi->planes;
for (j = 0; j < pix_mp->num_planes; j++) {
bpl = pix_mp->width / fi->hsub[j].numerator *
memset(pix, 0, sizeof(*pix));
pix->pixelformat = fi->pixelformat;
- pix->width = clamp_t(u32, width, 1,
+ pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
STFCAMSS_FRAME_MAX_WIDTH);
- pix->height = clamp_t(u32, height, 1,
- STFCAMSS_FRAME_MAX_HEIGHT_RDI);
+ pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
bpl = pix->width / fi->hsub[0].numerator *
fi->hsub[0].denominator * fi->bpp[0] / 8;
bpl = ALIGN(bpl, video->bpl_alignment);
{
int ret;
struct v4l2_format format = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .type = video->type,
.fmt.pix = {
.width = 1920,
.height = 1080,
},
};
- struct v4l2_format format_mp = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
- .fmt.pix = {
- .width = 1920,
- .height = 1080,
- .pixelformat = V4L2_PIX_FMT_NV21,
- },
- };
-
- if (is_mp)
- ret = __video_try_fmt(video, &format_mp, true);
- else
- ret = __video_try_fmt(video, &format, false);
+ ret = __video_try_fmt(video, &format, is_mp);
if (ret < 0)
return ret;
- video->active_fmt = is_mp ? format_mp : format;
+ video->active_fmt = format;
return 0;
}
if (!sizes[0])
st_err(ST_VIDEO, "%s: error size is zero!!!\n", __func__);
}
+ if ((stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC)
+ == STF_ISP_PAD_SRC_SCD_Y) &&
+ sizes[0] < ISP_SCD_Y_BUFFER_SIZE) {
+ sizes[0] = ISP_SCD_Y_BUFFER_SIZE;
+ }
st_info(ST_VIDEO, "%s, planes = %d, size = %d\n",
__func__, *num_planes, sizes[0]);
//struct sg_table *sgt;
dma_addr_t *paddr;
unsigned int i;
+ buffer->sizeimage = 0;
if (video->is_mp) {
for (i = 0; i < fmt_mp->num_planes; i++) {
paddr = vb2_plane_cookie(vb, i);
buffer->addr[i] = *paddr;
+ buffer->sizeimage += vb2_plane_size(vb, i);
}
if (fmt_mp->num_planes == 1
|| fmt_mp->pixelformat == V4L2_PIX_FMT_NV16
|| fmt_mp->pixelformat == V4L2_PIX_FMT_NV61))
buffer->addr[1] = buffer->addr[0] +
- fmt_mp->width *
+ fmt_mp->plane_fmt[0].bytesperline *
fmt_mp->height;
} else {
paddr = vb2_plane_cookie(vb, 0);
+ buffer->sizeimage = vb2_plane_size(vb, 0);
buffer->addr[0] = *paddr;
if (fmt->pixelformat == V4L2_PIX_FMT_NV12
|| fmt->pixelformat == V4L2_PIX_FMT_NV21
|| fmt->pixelformat == V4L2_PIX_FMT_NV16
|| fmt->pixelformat == V4L2_PIX_FMT_NV61)
buffer->addr[1] = buffer->addr[0] +
- fmt->width *
+ fmt->bytesperline *
fmt->height;
}
+ if (stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC)
+ == STF_ISP_PAD_SRC_SCD_Y)
+ buffer->addr[1] = buffer->addr[0] + ISP_YHIST_BUFFER_SIZE;
+
return 0;
}
fmt_mp->plane_fmt[i].sizeimage);
}
} else {
- if (fmt->sizeimage > vb2_plane_size(vb, 0))
+ if (fmt->sizeimage > vb2_plane_size(vb, 0)) {
+ st_err(ST_VIDEO, "sizeimage = %d, plane size = %d\n",
+ fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0));
return -EINVAL;
+ }
vb2_set_plane_payload(vb, 0, fmt->sizeimage);
}
static int video_get_subdev_format(struct stfcamss_video *video,
struct v4l2_format *format)
{
+ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
+ struct v4l2_pix_format_mplane *pix_mp =
+ &video->active_fmt.fmt.pix_mp;
struct v4l2_subdev_format fmt;
struct v4l2_subdev *subdev;
u32 pixelformat;
if (ret)
return ret;
- pixelformat = video->is_mp ? format->fmt.pix.pixelformat
- : format->fmt.pix_mp.pixelformat;
+ if (video->is_mp)
+ pixelformat = pix_mp->pixelformat;
+ else
+ pixelformat = pix->pixelformat;
ret = video_find_format(fmt.format.code, pixelformat,
video->formats, video->nformats);
if (ret < 0)
int ret;
#ifdef USE_MEDIA_PIPELINE
- ret = media_pipeline_start(&vdev->entity, &video->pipe);
+ // ret = media_pipeline_start(&vdev->entity, &video->pipe);
+ ret = media_pipeline_start(&vdev->entity, &video->stfcamss->pipe);
if (ret < 0) {
st_err(ST_VIDEO,
"Failed to media_pipeline_start: %d\n", ret);
* V4L2 ioctls
*/
+static int getcrop_pad_id(int video_id)
+{
+ return stf_vin_map_isp_pad(video_id, STF_ISP_PAD_SRC);
+}
+
static int video_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH;
fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH;
fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT;
- fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT_PIX;
+ fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT;
fsize->stepwise.step_width = 1;
fsize->stepwise.step_height = 1;
}
return 0;
}
+static int video_entity_s_fmt(struct stfcamss_video *video,
+ struct media_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt, u32 dst_code)
+{
+ struct v4l2_subdev *subdev;
+ struct media_pad *pad;
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ u32 width, height, code;
+ int ret, index = 0;
+
+ code = mf->code;
+ width = mf->width;
+ height = mf->height;
+ subdev = media_entity_to_v4l2_subdev(entity);
+ while (1) {
+ if (index >= entity->num_pads)
+ break;
+ pad = &entity->pads[index];
+ pad = media_entity_remote_pad(pad);
+ if (pad && is_media_entity_v4l2_subdev(pad->entity)) {
+ fmt->pad = index;
+ if (index)
+ mf->code = dst_code;
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, state, fmt);
+ st_warn(ST_VIDEO,
+ "\"%s\":%d pad fmt set to 0x%x %ux%u, dst_code = 0x%x\n",
+ subdev->name, fmt->pad, mf->code,
+ mf->width, mf->height, dst_code);
+ if (mf->code != code ||
+ mf->width != width || mf->height != height) {
+ st_warn(ST_VIDEO,
+ "\"%s\":%d pad fmt has been"
+ " changed to 0x%x %ux%u\n",
+ subdev->name, fmt->pad, mf->code,
+ mf->width, mf->height);
+ }
+ if (index)
+ ret = video_entity_s_fmt(video, pad->entity, state, fmt, dst_code);
+ }
+
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ break;
+ index++;
+ }
+ return ret;
+}
+
static int video_pipeline_s_fmt(struct stfcamss_video *video,
struct v4l2_subdev_state *state,
struct v4l2_format *f)
struct video_device *vdev = &video->vdev;
struct media_entity *entity = &vdev->entity;
struct v4l2_subdev *subdev;
- struct media_device *mdev = entity->graph_obj.mdev;
- struct media_graph graph;
int ret, index;
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .reserved = {getcrop_pad_id(video->id)}
};
struct v4l2_mbus_framefmt *mf = &fmt.format;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct media_entity *sensor;
u32 width, height, code;
+ struct media_pad *pad;
/* pix to mbus format */
if (video->is_mp) {
return index;
v4l2_fill_mbus_format_mplane(mf, pix_mp);
mf->code = video->formats[index].code;
- code = mf->code;
- width = mf->width;
- height = mf->height;
} else {
index = video_find_format(mf->code,
pix->pixelformat,
if (index < 0)
return index;
v4l2_fill_mbus_format(mf, pix, video->formats[index].code);
- code = mf->code;
- width = mf->width;
- height = mf->height;
+ }
+ code = mf->code;
+ width = mf->width;
+ height = mf->height;
+ sensor = stfcamss_find_sensor(entity);
+ if (sensor) {
+ subdev = media_entity_to_v4l2_subdev(sensor);
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, state, &fmt);
+ st_warn(ST_VIDEO,
+ "\"%s\":%d pad fmt set to 0x%x %ux%u\n",
+ subdev->name, fmt.pad, mf->code,
+ mf->width, mf->height);
+ if (mf->code != code ||
+ mf->width != width || mf->height != height) {
+ st_warn(ST_VIDEO,
+ "\"%s\":%d pad fmt has been"
+ " changed to 0x%x %ux%u\n",
+ subdev->name, fmt.pad, mf->code,
+ mf->width, mf->height);
+ }
+ } else {
+ st_err(ST_VIDEO, "Can't find sensor\n");
+ return -EINVAL;
}
/*
* Starting from sensor subdevice, walk within
* pipeline and set format on each subdevice
*/
- mutex_lock(&mdev->graph_mutex);
- ret = media_graph_walk_init(&graph, mdev);
- if (ret) {
- mutex_unlock(&mdev->graph_mutex);
- return ret;
- }
-
- media_graph_walk_start(&graph, entity);
-
- while (!ret && (entity = media_graph_walk_next(&graph)))
- if (is_media_entity_v4l2_subdev(entity)) {
- subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, pad, set_fmt, state, &fmt);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- break;
- if (mf->code != code ||
- mf->width != width || mf->height != height) {
- // st_warn(ST_VIDEO,
- // "\"%s\":%d pad fmt has been"
- // " changed to 0x%x %ux%u\n",
- // subdev->name, fmt.pad, mf->code,
- // mf->width, mf->height);
- }
- }
-
- mutex_unlock(&mdev->graph_mutex);
-
- media_graph_walk_cleanup(&graph);
+ sensor = stfcamss_find_sensor(entity);
+ pad = media_entity_remote_pad(&sensor->pads[0]);
+ ret = video_entity_s_fmt(video, pad->entity, state, &fmt, code);
if (ret < 0 && ret != -ENOIOCTLCMD) {
- // st_err(ST_VIDEO,
- // "%s: Failed to set fmt 0x%x %ux%u"
- // " on \"%s\":%d pad (%d)\n",
- // __func__, mf->code,
- // mf->width, mf->height,
- // subdev->name, fmt.pad, ret);
return ret;
}
+ index = video_find_format(mf->code,
+ video->formats[index].pixelformat,
+ video->formats, video->nformats);
+ if (index < 0)
+ return index;
+
if (video->is_mp)
video_mbus_to_pix_mp(mf, pix_mp,
&video->formats[index], video->bpl_alignment);
struct media_pad *pad;
struct v4l2_subdev_selection sel = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = getcrop_pad_id(video->id),
.target = s->target,
.r = s->r,
.flags = s->flags,
struct media_pad *pad;
struct v4l2_subdev_selection sel = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = getcrop_pad_id(video->id),
.target = s->target,
.r = s->r,
.flags = s->flags,
struct v4l2_subdev *subdev;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
struct v4l2_fh *vfh;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
struct v4l2_subdev *subdev;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
struct v4l2_subdev *subdev;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
struct v4l2_fh *vfh;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
struct v4l2_fh *vfh;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
return ret;
}
+
#ifdef UNUSED_CODE
static int video_querymenu(struct file *file, void *fh,
struct v4l2_querymenu *qm)
struct v4l2_subdev *subdev;
int ret;
- subdev = get_senname(file, __func__);
+ subdev = get_senname(file, (char *)__func__);
if (!subdev)
return -EINVAL;
+
ret = v4l2_querymenu(subdev->ctrl_handler, qm);
return ret;
.vidioc_queryctrl = video_queryctrl,
.vidioc_s_ext_ctrls = video_s_ext_ctrls,
.vidioc_try_ext_ctrls = video_try_ext_ctrls,
- //.vidioc_query_ext_ctrl = video_query_ext_ctrl,
- //.vidioc_querymenu = video_querymenu,
-
};
static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_mp = {
.vidioc_queryctrl = video_queryctrl,
.vidioc_s_ext_ctrls = video_s_ext_ctrls,
.vidioc_try_ext_ctrls = video_try_ext_ctrls,
-// .vidioc_querymenu = video_querymenu,
-// .vidioc_query_ext_ctrl = video_query_ext_ctrl,
+};
+
+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops_out = {
+ .vidioc_querycap = video_querycap,
+ .vidioc_enum_fmt_vid_out = video_enum_fmt,
+ .vidioc_enum_framesizes = video_enum_framesizes,
+ .vidioc_enum_frameintervals = video_enum_frameintervals,
+ .vidioc_g_fmt_vid_out = video_g_fmt,
+ .vidioc_s_fmt_vid_out = video_s_fmt,
+ .vidioc_try_fmt_vid_out = video_try_fmt,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
};
static int video_open(struct file *file)
struct vb2_queue *q;
struct media_pad *pad = &video->pad;
int ret;
+ enum isp_pad_id isp_pad;
vdev = &video->vdev;
q->drv_priv = video;
q->mem_ops = &vb2_dma_contig_memops;
q->ops = &stf_video_vb2_q_ops;
- q->type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
- V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ //q->type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ // V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->type = video->type;
q->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->buf_struct_size = sizeof(struct stfcamss_buffer);
q->dev = video->stfcamss->dev;
q->lock = &video->q_lock;
+ q->min_buffers_needed = STFCAMSS_MIN_BUFFERS;
ret = vb2_queue_init(q);
if (ret < 0) {
st_err(ST_VIDEO,
mutex_init(&video->lock);
+ isp_pad = stf_vin_map_isp_pad(video->id, STF_ISP_PAD_SRC);
if (video->id == VIN_LINE_WR) {
video->formats = formats_pix_st7110_wr;
video->nformats = ARRAY_SIZE(formats_pix_st7110_wr);
- video->bpl_alignment = 8;
- } else if (video->id == VIN_LINE_ISP0
- || video->id == VIN_LINE_ISP1) { // ISP0/ISP1
+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
+ } else if (isp_pad == STF_ISP_PAD_SRC
+ || isp_pad == STF_ISP_PAD_SRC_SS0
+ || isp_pad == STF_ISP_PAD_SRC_SS1) {
video->formats = formats_pix_st7110_isp;
video->nformats = ARRAY_SIZE(formats_pix_st7110_isp);
- video->bpl_alignment = 8;
- } else {
+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
+ } else if (isp_pad == STF_ISP_PAD_SRC_ITIW
+ || isp_pad == STF_ISP_PAD_SRC_ITIR) {
+ video->formats = formats_st7110_isp_iti;
+ video->nformats = ARRAY_SIZE(formats_st7110_isp_iti);
+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_8;
+ } else { // raw/scdump/yhist
video->formats = formats_raw_st7110_isp;
video->nformats = ARRAY_SIZE(formats_raw_st7110_isp);
- video->bpl_alignment = 16 * 8;
+ video->bpl_alignment = STFCAMSS_FRAME_WIDTH_ALIGN_128;
}
video->is_mp = is_mp;
}
vdev->fops = &stf_vid_fops;
- vdev->device_caps = is_mp ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
+ if (isp_pad == STF_ISP_PAD_SRC_ITIR) {
+ vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT;
+ vdev->vfl_dir = VFL_DIR_TX;
+ } else {
+ vdev->device_caps = is_mp ? V4L2_CAP_VIDEO_CAPTURE_MPLANE :
V4L2_CAP_VIDEO_CAPTURE;
+ vdev->vfl_dir = VFL_DIR_RX;
+ }
vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- vdev->ioctl_ops = is_mp ? &stf_vid_ioctl_ops_mp : &stf_vid_ioctl_ops;
+ if (video->type == V4L2_CAP_VIDEO_OUTPUT)
+ vdev->ioctl_ops = &stf_vid_ioctl_ops_out;
+ else
+ vdev->ioctl_ops = is_mp ? &stf_vid_ioctl_ops_mp : &stf_vid_ioctl_ops;
vdev->release = stf_video_release;
vdev->v4l2_dev = v4l2_dev;
- vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = &video->vb2_q;
vdev->lock = &video->lock;
//strlcpy(vdev->name, name, sizeof(vdev->name));
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
-#define STFCAMSS_FRAME_MIN_WIDTH 1
+#define STFCAMSS_FRAME_MIN_WIDTH 64
#define STFCAMSS_FRAME_MAX_WIDTH 8191
-#define STFCAMSS_FRAME_MIN_HEIGHT 1
-#define STFCAMSS_FRAME_MAX_HEIGHT_RDI 8191
-#define STFCAMSS_FRAME_MAX_HEIGHT_PIX 4096
-#define STFCAMSS_FRAME_WIDTH_ALIGN 8
+#define STFCAMSS_FRAME_MIN_HEIGHT 64
+#define STFCAMSS_FRAME_MAX_HEIGHT 8191
+#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8
+#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128
+#define STFCAMSS_MIN_BUFFERS 2
struct stfcamss_buffer {
struct vb2_v4l2_buffer vb;
dma_addr_t addr[3];
struct list_head queue;
+ int sizeimage;
};
struct stfcamss_video;
#include "stfcamss.h"
-#define STF_VIN_NAME "stf_vin"
-
-#define vin_line_array(ptr_line) \
+#define vin_line_array(ptr_line) \
((const struct vin_line (*)[]) &(ptr_line[-(ptr_line->id)]))
-#define line_to_vin2_dev(ptr_line) \
+#define line_to_vin2_dev(ptr_line) \
container_of(vin_line_array(ptr_line), struct stf_vin2_dev, line)
#define VIN_FRAME_DROP_MAX_VAL 30
static const struct vin2_format vin2_formats_st7110[] = {
{ MEDIA_BUS_FMT_YUYV8_2X8, 16},
{ MEDIA_BUS_FMT_RGB565_2X8_LE, 16},
- { MEDIA_BUS_FMT_SRGGB10_1X10, 12},
- { MEDIA_BUS_FMT_SGRBG10_1X10, 12},
- { MEDIA_BUS_FMT_SGBRG10_1X10, 12},
- { MEDIA_BUS_FMT_SBGGR10_1X10, 12},
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8},
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8},
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8},
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8},
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+ { MEDIA_BUS_FMT_Y12_1X12, 8},
+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+static const struct vin2_format isp_formats_st7110_raw[] = {
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+};
+
+static const struct vin2_format isp_formats_st7110_uo[] = {
+ { MEDIA_BUS_FMT_Y12_1X12, 8},
+};
+
+static const struct vin2_format isp_formats_st7110_iti[] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10},
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10},
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10},
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10},
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12},
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12},
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12},
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12},
+ { MEDIA_BUS_FMT_Y12_1X12, 8},
+ { MEDIA_BUS_FMT_YUV8_1X24, 8},
+};
+
+static const struct vin2_format_table vin2_formats_table[] = {
+ /* VIN_LINE_WR */
+ { vin2_formats_st7110, ARRAY_SIZE(vin2_formats_st7110) },
+ /* VIN_LINE_ISP */
+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
+ /* VIN_LINE_ISP_SS0 */
+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
+ /* VIN_LINE_ISP_SS1 */
+ { isp_formats_st7110_uo, ARRAY_SIZE(isp_formats_st7110_uo) },
+ /* VIN_LINE_ISP_ITIW */
+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },
+ /* VIN_LINE_ISP_ITIR */
+ { isp_formats_st7110_iti, ARRAY_SIZE(isp_formats_st7110_iti) },
+ /* VIN_LINE_ISP_RAW */
+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },
+ /* VIN_LINE_ISP_SCD_Y */
+ { isp_formats_st7110_raw, ARRAY_SIZE(isp_formats_st7110_raw) },
};
static void vin_buffer_done(struct vin_line *line, struct vin_params *params);
+static void vin_change_buffer(struct vin_line *line);
static struct stfcamss_buffer *vin_buf_get_pending(struct vin_output *output);
static void vin_output_init_addrs(struct vin_line *line);
static void vin_init_outputs(struct vin_line *line);
+static struct v4l2_mbus_framefmt *
+__vin_get_format(struct vin_line *line,
+ struct v4l2_subdev_state *state,
+ unsigned int pad,
+ enum v4l2_subdev_format_whence which);
static char *get_line_subdevname(int line_id)
{
case VIN_LINE_WR:
name = "wr";
break;
- case VIN_LINE_ISP0:
+ case VIN_LINE_ISP:
name = "isp0";
break;
- case VIN_LINE_ISP1:
- name = "isp1";
+ case VIN_LINE_ISP_SS0:
+ name = "isp0_ss0";
+ break;
+ case VIN_LINE_ISP_SS1:
+ name = "isp0_ss1";
break;
- case VIN_LINE_ISP0_RAW:
+ case VIN_LINE_ISP_ITIW:
+ name = "isp0_itiw";
+ break;
+ case VIN_LINE_ISP_ITIR:
+ name = "isp0_itir";
+ break;
+ case VIN_LINE_ISP_RAW:
name = "isp0_raw";
break;
- case VIN_LINE_ISP1_RAW:
- name = "isp1_raw";
+ case VIN_LINE_ISP_SCD_Y:
+ name = "isp0_scd_y";
break;
default:
name = "unknow";
return name;
}
+static enum isp_line_id stf_vin_map_isp_line(enum vin_line_id line)
+{
+ enum isp_line_id line_id;
+
+ if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX)) {
+ line_id = line % STF_ISP_LINE_SRC_SCD_Y;
+ if (line_id == 0)
+ line_id = line_id ? line_id : STF_ISP_LINE_SRC_SCD_Y;
+ } else
+ line_id = STF_ISP_LINE_INVALID;
+
+ return line_id;
+}
+
+enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line, enum isp_pad_id def)
+{
+ enum isp_pad_id pad_id;
+
+ if (line == VIN_LINE_WR)
+ pad_id = STF_ISP_PAD_SINK;
+ else if ((line > VIN_LINE_WR) && (line < VIN_LINE_MAX))
+ pad_id = stf_vin_map_isp_line(line);
+ else
+ pad_id = def;
+
+ return pad_id;
+}
+
int stf_vin_subdev_init(struct stfcamss *stfcamss)
{
struct stf_vin_dev *vin;
struct device *dev = stfcamss->dev;
struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
- int ret = 0, i;
+ int i, ret = 0;
vin_dev->stfcamss = stfcamss;
vin_dev->hw_ops = &vin_ops;
vin_dev->hw_ops->isr_buffer_done = vin_buffer_done;
+ vin_dev->hw_ops->isr_change_buffer = vin_change_buffer;
vin = stfcamss->vin;
atomic_set(&vin_dev->ref_count, 0);
}
ret = devm_request_irq(dev,
- vin->isp0_irq, vin_dev->hw_ops->vin_isp_irq_handler,
- 0, "vin_isp0_irq", vin_dev);
+ vin->isp_irq, vin_dev->hw_ops->vin_isp_irq_handler,
+ 0, "vin_isp_irq", vin_dev);
if (ret) {
- st_err(ST_VIN, "failed to request isp0 irq\n");
+ st_err(ST_VIN, "failed to request isp irq\n");
+ goto out;
+ }
+
+ st_info(ST_CAMSS, "%s, %d!\n", __func__, __LINE__);
+#ifdef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
+ ret = devm_request_irq(dev,
+ vin->isp_csi_irq, vin_dev->hw_ops->vin_isp_csi_irq_handler,
+ 0, "vin_isp_csi_irq", vin_dev);
+ if (ret) {
+ st_err(ST_VIN, "failed to request isp raw irq\n");
goto out;
}
-#ifdef UNUSED_CODE
ret = devm_request_irq(dev,
- vin->isp1_irq, vin_dev->hw_ops->vin_isp_irq_handler,
- 0, "vin_isp1_irq", vin_dev);
+ vin->isp_scd_irq, vin_dev->hw_ops->vin_isp_scd_irq_handler,
+ 0, "vin_isp_scd_irq", vin_dev);
if (ret) {
- st_err(ST_VIN, "failed to request isp1 irq\n");
+ st_err(ST_VIN, "failed to request isp scd irq\n");
+ goto out;
+ }
+#endif
+
+ ret = devm_request_irq(dev,
+ vin->isp_irq_csiline, vin_dev->hw_ops->vin_isp_irq_csiline_handler,
+ 0, "vin_isp_irq_csiline", vin_dev);
+ if (ret) {
+ st_err(ST_VIN, "failed to request isp irq csiline\n");
goto out;
}
/*Do not configure the CLK before powering on the device,
*add vin_power_on() to vin_set_power() 2021 1111
*/
- ret = vin_dev->hw_ops->vin_clk_init(vin_dev);
+ ret = vin_dev->hw_ops->vin_top_clk_init(vin_dev);
if (ret) {
st_err(ST_VIN, "Failed to reset device\n");
goto out;
// st_err(ST_VIN, "Failed to config device\n");
// goto out;
// }
-#endif
+
mutex_init(&vin_dev->power_lock);
vin_dev->power_count = 0;
- for (i = VIN_LINE_WR; i < VIN_LINE_MAX; i++) {
+ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++) {
+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[i];
+
+ mutex_init(&dummy_buffer->stream_lock);
+ dummy_buffer->nums = i == 0 ? VIN_DUMMY_BUFFER_NUMS : ISP_DUMMY_BUFFER_NUMS;
+ dummy_buffer->stream_count = 0;
+ dummy_buffer->buffer = devm_kzalloc(dev,
+ dummy_buffer->nums * sizeof(struct vin_dummy_buffer), GFP_KERNEL);
+ atomic_set(&dummy_buffer->frame_skip, 0);
+ }
+
+ for (i = VIN_LINE_WR;
+ i < STF_ISP_LINE_MAX + 1; i++) {
struct vin_line *l = &vin_dev->line[i];
int is_mp;
is_mp = i == VIN_LINE_WR ? false : true;
is_mp = false;
- l->video_out.type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ if (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIR)
+ l->video_out.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ else
+ l->video_out.type = is_mp ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
V4L2_BUF_TYPE_VIDEO_CAPTURE;
l->video_out.stfcamss = stfcamss;
l->id = i;
l->sdev_type = VIN_DEV_TYPE;
- l->formats = vin2_formats_st7110;
- l->nformats = ARRAY_SIZE(vin2_formats_st7110);
+ l->formats = vin2_formats_table[i].fmts;
+ l->nformats = vin2_formats_table[i].nfmts;
spin_lock_init(&l->output_lock);
mutex_init(&l->stream_lock);
return 0;
}
-static int vin_enable_output(struct vin_line *line)
+static unsigned int get_frame_skip(struct vin_line *line)
{
- struct vin_output *output = &line->output;
- unsigned long flags;
unsigned int frame_skip = 0;
struct media_entity *sensor;
st_debug(ST_VIN, "%s, frame_skip %d\n", __func__, frame_skip);
}
+ return frame_skip;
+}
+
+static int vin_enable_output(struct vin_line *line)
+{
+ struct vin_output *output = &line->output;
+ unsigned long flags;
+
spin_lock_irqsave(&line->output_lock, flags);
- output->frame_skip = frame_skip;
output->state = VIN_OUTPUT_IDLE;
return 0;
}
+static u32 line_to_dummy_module(struct vin_line *line)
+{
+ u32 dummy_module = 0;
+
+ switch (line->id) {
+ case VIN_LINE_WR:
+ dummy_module = STF_DUMMY_VIN;
+ break;
+ case VIN_LINE_ISP:
+ case VIN_LINE_ISP_SS0:
+ case VIN_LINE_ISP_SS1:
+ case VIN_LINE_ISP_ITIW:
+ case VIN_LINE_ISP_ITIR:
+ case VIN_LINE_ISP_RAW:
+ case VIN_LINE_ISP_SCD_Y:
+ dummy_module = STF_DUMMY_ISP;
+ break;
+ default:
+ dummy_module = STF_DUMMY_VIN;
+ break;
+ }
+
+ return dummy_module;
+}
+
+static int vin_alloc_dummy_buffer(struct stf_vin2_dev *vin_dev,
+ struct v4l2_mbus_framefmt *fmt, int dummy_module)
+{
+ struct device *dev = vin_dev->stfcamss->dev;
+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
+ struct vin_dummy_buffer *buffer = NULL;
+ int ret = 0, i;
+ u32 aligns;
+
+ for (i = 0; i < dummy_buffer->nums; i++) {
+ buffer = &vin_dev->dummy_buffer[dummy_module].buffer[i];
+ buffer->width = fmt->width;
+ buffer->height = fmt->height;
+ buffer->mcode = fmt->code;
+ if (i == STF_VIN_PAD_SINK) {
+ aligns = ALIGN(fmt->width * 4, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height);
+ } else if (i == STF_ISP_PAD_SRC
+ || i == STF_ISP_PAD_SRC_SS0
+ || i == STF_ISP_PAD_SRC_SS1) {
+ aligns = ALIGN(fmt->width, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height * 3 / 2);
+ } else if (i == STF_ISP_PAD_SRC_ITIW
+ || i == STF_ISP_PAD_SRC_ITIR) {
+ aligns = ALIGN(fmt->width, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height * 3);
+ } else if (i == STF_ISP_PAD_SRC_RAW) {
+ aligns = ALIGN(fmt->width * ISP_RAW_DATA_BITS / 8,
+ STFCAMSS_FRAME_WIDTH_ALIGN_128);
+ buffer->buffer_size = PAGE_ALIGN(aligns * fmt->height);
+ } else if (i == STF_ISP_PAD_SRC_SCD_Y)
+ buffer->buffer_size = PAGE_ALIGN(ISP_SCD_Y_BUFFER_SIZE);
+ else
+ continue;
+
+ buffer->vaddr = dma_alloc_coherent(dev, buffer->buffer_size,
+ &buffer->paddr[0], GFP_DMA | GFP_KERNEL);
+
+ if (buffer->vaddr) {
+ if (i == STF_ISP_PAD_SRC
+ || i == STF_ISP_PAD_SRC_SS0
+ || i == STF_ISP_PAD_SRC_SS1
+ || i == STF_ISP_PAD_SRC_ITIW
+ || i == STF_ISP_PAD_SRC_ITIR)
+ buffer->paddr[1] = (dma_addr_t)(buffer->paddr[0] +
+ aligns * fmt->height);
+ else if (i == STF_ISP_PAD_SRC_SCD_Y)
+ buffer->paddr[1] = (dma_addr_t)(buffer->paddr[0] +
+ ISP_YHIST_BUFFER_SIZE);
+ else
+ st_debug(ST_VIN, "signal plane\n");
+ }
+ {
+ char szPadName[][32] = {
+ "VIN_PAD_SINK",
+ "ISP_PAD_SRC",
+ "ISP_PAD_SRC_SS0",
+ "ISP_PAD_SRC_SS1",
+ "ISP_PAD_SRC_ITIW",
+ "ISP_PAD_SRC_ITIR",
+ "ISP_PAD_SRC_RAW",
+ "ISP_PAD_SRC_SCD_Y",
+ "Unknown Pad"
+ };
+
+ st_debug(ST_VIN, "%s: i = %d(%s) addr[0] = %llx, addr[1] = %llx, size = %u bytes\n",
+ __func__,
+ i,
+ szPadName[i],
+ buffer->paddr[0],
+ buffer->paddr[1],
+ buffer->buffer_size
+ );
+ }
+ }
+
+ return ret;
+}
+
+static void vin_free_dummy_buffer(struct stf_vin2_dev *vin_dev, int dummy_module)
+{
+ struct device *dev = vin_dev->stfcamss->dev;
+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
+ struct vin_dummy_buffer *buffer = NULL;
+ int i;
+
+ for (i = 0; i < dummy_buffer->nums; i++) {
+ buffer = &dummy_buffer->buffer[i];
+ if (buffer->vaddr)
+ dma_free_coherent(dev, buffer->buffer_size,
+ buffer->vaddr, buffer->paddr[0]);
+ memset(buffer, 0, sizeof(struct vin_dummy_buffer));
+ }
+}
+
+static void vin_set_dummy_buffer(struct vin_line *line, u32 pad)
+{
+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
+ int dummy_module = line_to_dummy_module(line);
+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
+ struct vin_dummy_buffer *buffer = NULL;
+
+ switch (pad) {
+ case STF_VIN_PAD_SINK:
+ if (line->id == VIN_LINE_WR) {
+ buffer = &dummy_buffer->buffer[STF_VIN_PAD_SINK];
+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev, buffer->paddr[0]);
+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, buffer->paddr[0]);
+ } else {
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS0];
+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS1];
+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIW];
+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIR];
+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_RAW];
+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, buffer->paddr[0]);
+
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SCD_Y];
+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1], AWB_TYPE);
+ }
+ break;
+ case STF_ISP_PAD_SRC:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC];
+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+ break;
+ case STF_ISP_PAD_SRC_SS0:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS0];
+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+ break;
+ case STF_ISP_PAD_SRC_SS1:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SS1];
+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+ break;
+ case STF_ISP_PAD_SRC_ITIW:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIW];
+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+ break;
+ case STF_ISP_PAD_SRC_ITIR:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_ITIR];
+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1]);
+ break;
+ case STF_ISP_PAD_SRC_RAW:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_RAW];
+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, buffer->paddr[0]);
+ break;
+ case STF_ISP_PAD_SRC_SCD_Y:
+ buffer = &dummy_buffer->buffer[STF_ISP_PAD_SRC_SCD_Y];
+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+ buffer->paddr[0], buffer->paddr[1], AWB_TYPE);
+ break;
+ default:
+ break;
+ }
+}
+
static int vin_set_stream(struct v4l2_subdev *sd, int enable)
{
struct vin_line *line = v4l2_get_subdevdata(sd);
struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
+ int dummy_module = line_to_dummy_module(line);
+ struct dummy_buffer *dummy_buffer = &vin_dev->dummy_buffer[dummy_module];
+ struct v4l2_mbus_framefmt *fmt;
+
+ st_debug(ST_VIN, "%s, %d\n", __func__, __LINE__);
+ fmt = __vin_get_format(line, NULL, STF_VIN_PAD_SINK, V4L2_SUBDEV_FORMAT_ACTIVE);
+ mutex_lock(&dummy_buffer->stream_lock);
+ if (enable) {
+ if (dummy_buffer->stream_count == 0) {
+ vin_alloc_dummy_buffer(vin_dev, fmt, dummy_module);
+ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
+ atomic_set(&dummy_buffer->frame_skip, get_frame_skip(line));
+ }
+ dummy_buffer->stream_count++;
+ } else {
+ if (dummy_buffer->stream_count == 1) {
+ vin_free_dummy_buffer(vin_dev, dummy_module);
+ // set buffer addr to zero
+ vin_set_dummy_buffer(line, STF_VIN_PAD_SINK);
+ } else
+ vin_set_dummy_buffer(line,
+ stf_vin_map_isp_pad(line->id, STF_ISP_PAD_SINK));
+
+ dummy_buffer->stream_count--;
+ }
+ mutex_unlock(&dummy_buffer->stream_lock);
if (line->id == VIN_LINE_WR) {
mutex_lock(&line->stream_lock);
/* If not found, use UYVY as default */
if (i >= line->nformats)
- fmt->code = MEDIA_BUS_FMT_RGB565_2X8_LE;
+ fmt->code = line->formats[0].code;
fmt->width = clamp_t(u32,
- fmt->width, 1, STFCAMSS_FRAME_MAX_WIDTH);
+ fmt->width, STFCAMSS_FRAME_MIN_WIDTH, STFCAMSS_FRAME_MAX_WIDTH);
fmt->height = clamp_t(u32,
- fmt->height, 1, STFCAMSS_FRAME_MAX_HEIGHT_PIX);
+ fmt->height, STFCAMSS_FRAME_MIN_HEIGHT, STFCAMSS_FRAME_MAX_HEIGHT);
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_SRGB;
if (format == NULL)
return -EINVAL;
- vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
- *format = fmt->format;
+ mutex_lock(&line->stream_lock);
+ if (line->stream_count) {
+ fmt->format = *format;
+ mutex_unlock(&line->stream_lock);
+ goto out;
+ } else {
+ vin_try_format(line, state, fmt->pad, &fmt->format, fmt->which);
+ *format = fmt->format;
+ }
+ mutex_unlock(&line->stream_lock);
if (fmt->pad == STF_VIN_PAD_SINK) {
/* Propagate the format from sink to source */
fmt->which);
}
+out:
return 0;
}
ping_addr = output->buf[0]->addr[0];
y_addr = output->buf[0]->addr[0];
uv_addr = output->buf[0]->addr[1];
-
} else
- ping_addr = 0;
+ return;
if (output->buf[1])
pong_addr = output->buf[1]->addr[0];
else
pong_addr = ping_addr;
- switch (line->id) {
- case VIN_LINE_WR: // wr
- vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev, ping_addr);
-#ifdef VIN_TWO_BUFFER
- vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, pong_addr);
-#else
- vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, ping_addr);
-#endif
- break;
- case VIN_LINE_ISP0: // isp0
- case VIN_LINE_ISP1: // isp1
-
+ switch (stf_vin_map_isp_line(line->id)) {
+ case STF_ISP_LINE_SRC:
vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
- line->id - VIN_LINE_ISP0,
y_addr, uv_addr);
-
break;
- case VIN_LINE_ISP0_RAW: // isp0_raw
- case VIN_LINE_ISP1_RAW: // isp1_raw
- vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev,
- line->id - VIN_LINE_ISP0_RAW, y_addr);
+ case STF_ISP_LINE_SRC_SS0:
+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+ y_addr, uv_addr);
+ break;
+ case STF_ISP_LINE_SRC_SS1:
+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+ y_addr, uv_addr);
+ break;
+ case STF_ISP_LINE_SRC_ITIW:
+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+ y_addr, uv_addr);
+ break;
+ case STF_ISP_LINE_SRC_ITIR:
+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+ y_addr, uv_addr);
+ break;
+ case STF_ISP_LINE_SRC_RAW:
+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, y_addr);
+ break;
+ case STF_ISP_LINE_SRC_SCD_Y:
+ output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+ y_addr, uv_addr, AWB_TYPE);
break;
default:
+ if (line->id == VIN_LINE_WR) {
+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev, ping_addr);
+#ifdef VIN_TWO_BUFFER
+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, pong_addr);
+#else
+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev, ping_addr);
+#endif
+ }
break;
}
}
output->buf[1] = NULL;
output->active_buf = 0;
INIT_LIST_HEAD(&output->pending_bufs);
+ INIT_LIST_HEAD(&output->ready_bufs);
+}
+
+static void vin_buf_add_ready(struct vin_output *output,
+ struct stfcamss_buffer *buffer)
+{
+ INIT_LIST_HEAD(&buffer->queue);
+ list_add_tail(&buffer->queue, &output->ready_bufs);
+}
+
+static struct stfcamss_buffer *vin_buf_get_ready(struct vin_output *output)
+{
+ struct stfcamss_buffer *buffer = NULL;
+
+ if (!list_empty(&output->ready_bufs)) {
+ buffer = list_first_entry(&output->ready_bufs,
+ struct stfcamss_buffer,
+ queue);
+ list_del(&buffer->queue);
+ }
+
+ return buffer;
}
static void vin_buf_add_pending(struct vin_output *output,
struct vin_output *output,
struct stfcamss_buffer *new_buf)
{
+#ifdef VIN_TWO_BUFFER
+ struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
+ int inactive_idx;
+#endif
+
switch (output->state) {
case VIN_OUTPUT_SINGLE:
#ifdef VIN_TWO_BUFFER
}
}
-static void vin_buf_flush_pending(struct vin_output *output,
+static void vin_buf_flush(struct vin_output *output,
enum vb2_buffer_state state)
{
struct stfcamss_buffer *buf;
vb2_buffer_done(&buf->vb.vb2_buf, state);
list_del(&buf->queue);
}
+ list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->queue);
+ }
}
+extern void sifive_l2_flush64_range(unsigned long start, unsigned long len);
static void vin_buffer_done(struct vin_line *line, struct vin_params *params)
{
struct stfcamss_buffer *ready_buf;
struct vin_output *output = &line->output;
+ unsigned long flags;
+ u64 ts = ktime_get_ns();
+
+ if (output->state == VIN_OUTPUT_OFF
+ || output->state == VIN_OUTPUT_RESERVED)
+ return;
+
+ spin_lock_irqsave(&line->output_lock, flags);
+
+ while ((ready_buf = vin_buf_get_ready(output))) {
+ ready_buf->vb.vb2_buf.timestamp = ts;
+ ready_buf->vb.sequence = output->sequence++;
+
+ /* The stf_isp_ctrl currently buffered with mmap,
+ * which will not update cache by default.
+ * Flush L2 cache to make sure data is updated.
+ */
+ if (ready_buf->vb.vb2_buf.memory == VB2_MEMORY_MMAP)
+ sifive_l2_flush64_range(ready_buf->addr[0], ready_buf->sizeimage);
+
+ vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+
+ spin_unlock_irqrestore(&line->output_lock, flags);
+}
+
+static void vin_change_buffer(struct vin_line *line)
+{
+ struct stfcamss_buffer *ready_buf;
+ struct vin_output *output = &line->output;
struct stf_vin2_dev *vin_dev = line_to_vin2_dev(line);
dma_addr_t *new_addr;
unsigned long flags;
u32 active_index;
- u64 ts = ktime_get_ns();
+ int scd_type;
if (output->state == VIN_OUTPUT_OFF
|| output->state == VIN_OUTPUT_STOPPING
|| output->state == VIN_OUTPUT_RESERVED
|| output->state == VIN_OUTPUT_IDLE) {
- st_warn(ST_VIN,
- "output state no ready %d!, %d\n",
- output->state, line->id);
+ st_err_ratelimited(ST_VIN,
+ "%s: output state no ready %d!, %d\n",
+ __func__, output->state, line->id);
return;
}
spin_lock_irqsave(&line->output_lock, flags);
- if (output->frame_skip) {
- output->frame_skip--;
- goto out_unlock;
- }
-
active_index = output->active_buf;
ready_buf = output->buf[active_index];
vin_buf_update_on_next(line);
}
- switch (line->id) {
- case VIN_LINE_WR: // wr
+ if (output->state == VIN_OUTPUT_STOPPING)
+ output->last_buffer = ready_buf;
+ else {
+ switch (stf_vin_map_isp_line(line->id)) {
+ case STF_ISP_LINE_SRC:
+ vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
+ new_addr[0], new_addr[1]);
+ break;
+ case STF_ISP_LINE_SRC_SS0:
+ vin_dev->hw_ops->vin_isp_set_ss0_addr(vin_dev,
+ new_addr[0], new_addr[1]);
+ break;
+ case STF_ISP_LINE_SRC_SS1:
+ vin_dev->hw_ops->vin_isp_set_ss1_addr(vin_dev,
+ new_addr[0], new_addr[1]);
+ break;
+ case STF_ISP_LINE_SRC_ITIW:
+ vin_dev->hw_ops->vin_isp_set_itiw_addr(vin_dev,
+ new_addr[0], new_addr[1]);
+ break;
+ case STF_ISP_LINE_SRC_ITIR:
+ vin_dev->hw_ops->vin_isp_set_itir_addr(vin_dev,
+ new_addr[0], new_addr[1]);
+ break;
+ case STF_ISP_LINE_SRC_RAW:
+ vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev, new_addr[0]);
+ break;
+ case STF_ISP_LINE_SRC_SCD_Y:
+ scd_type = vin_dev->hw_ops->vin_isp_get_scd_type(vin_dev);
+ ready_buf->vb.flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME);
+ if (scd_type == AWB_TYPE)
+ ready_buf->vb.flags |= V4L2_BUF_FLAG_PFRAME;
+ else
+ ready_buf->vb.flags |= V4L2_BUF_FLAG_BFRAME;
+ if (!output->frame_skip) {
+ output->frame_skip = ISP_AWB_OECF_SKIP_FRAME;
+ scd_type = scd_type == AWB_TYPE ? OECF_TYPE : AWB_TYPE;
+ } else {
+ output->frame_skip--;
+ scd_type = scd_type == AWB_TYPE ? AWB_TYPE : OECF_TYPE;
+ }
+ vin_dev->hw_ops->vin_isp_set_scd_addr(vin_dev,
+ new_addr[0], new_addr[1], scd_type);
+ break;
+ default:
+ if (line->id == VIN_LINE_WR) {
#ifdef VIN_TWO_BUFFER
- if (active_index)
- vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
- new_addr[0]);
- else
- vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
- new_addr[0]);
+ if (active_index)
+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
+ new_addr[0]);
+ else
+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
+ new_addr[0]);
#else
- vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
- new_addr[0]);
- vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
- new_addr[0]);
+ vin_dev->hw_ops->vin_wr_set_ping_addr(vin_dev,
+ new_addr[0]);
+ vin_dev->hw_ops->vin_wr_set_pong_addr(vin_dev,
+ new_addr[0]);
#endif
- break;
- case VIN_LINE_ISP0: // isp0
- case VIN_LINE_ISP1: // isp1
- vin_dev->hw_ops->vin_isp_set_yuv_addr(vin_dev,
- line->id - VIN_LINE_ISP0,
- new_addr[0], new_addr[1]);
- break;
- case VIN_LINE_ISP0_RAW: // isp0_raw
- case VIN_LINE_ISP1_RAW: // isp1_raw
- vin_dev->hw_ops->vin_isp_set_raw_addr(vin_dev,
- line->id - VIN_LINE_ISP0_RAW, new_addr[0]);
- break;
+ }
+ break;
+ }
- default:
- break;
- }
-
- if (output->state == VIN_OUTPUT_STOPPING)
- output->last_buffer = ready_buf;
- else {
- ready_buf->vb.vb2_buf.timestamp = ts;
- ready_buf->vb.sequence = output->sequence++;
- vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ vin_buf_add_ready(output, ready_buf);
}
spin_unlock_irqrestore(&line->output_lock, flags);
spin_lock_irqsave(&line->output_lock, flags);
- vin_buf_flush_pending(output, state);
+ vin_buf_flush(output, state);
if (output->buf[0])
vb2_buffer_done(&output->buf[0]->vb.vb2_buf, state);
int ret;
int i;
- for (i = 0; i < VIN_LINE_MAX; i++) {
+ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
char name[32];
char *sub_name = get_line_subdevname(i);
int is_mp;
- is_mp = (i == VIN_LINE_ISP0) || (i == VIN_LINE_ISP1) ? true : false;
+ is_mp = (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC) ? true : false;
is_mp = false;
sd = &vin_dev->line[i].subdev;
pads = vin_dev->line[i].pads;
int i;
mutex_destroy(&vin_dev->power_lock);
- for (i = 0; i < VIN_LINE_MAX; i++) {
+ for (i = 0; i < STF_DUMMY_MODULE_NUMS; i++)
+ mutex_destroy(&vin_dev->dummy_buffer[i].stream_lock);
+
+ for (i = 0; i < STF_ISP_LINE_MAX + 1; i++) {
sd = &vin_dev->line[i].subdev;
video_out = &vin_dev->line[i].video_out;
#include "stf_video.h"
+#define STF_VIN_NAME "stf_vin"
+
#define STF_VIN_PAD_SINK 0
#define STF_VIN_PAD_SRC 1
#define STF_VIN_PADS_NUM 2
u8 bpp;
};
+struct vin2_format_table {
+ const struct vin2_format *fmts;
+ int nfmts;
+};
+
enum vin_output_state {
VIN_OUTPUT_OFF,
VIN_OUTPUT_RESERVED,
struct stfcamss_buffer *buf[2];
struct stfcamss_buffer *last_buffer;
struct list_head pending_bufs;
+ struct list_head ready_bufs;
enum vin_output_state state;
unsigned int sequence;
unsigned int frame_skip;
};
+/* The vin output lines include all isp controller lines,
+ * and one vin_wr output line.
+ */
enum vin_line_id {
VIN_LINE_NONE = -1,
VIN_LINE_WR = 0,
- VIN_LINE_ISP0 = 1,
- VIN_LINE_ISP1 = 2,
- VIN_LINE_ISP0_RAW = 3,
- VIN_LINE_ISP1_RAW = 4,
- VIN_LINE_MAX = 5
+ VIN_LINE_ISP = 1,
+ VIN_LINE_ISP_SS0 = 2,
+ VIN_LINE_ISP_SS1 = 3,
+ VIN_LINE_ISP_ITIW = 4,
+ VIN_LINE_ISP_ITIR = 5,
+ VIN_LINE_ISP_RAW = 6,
+ VIN_LINE_ISP_SCD_Y = 7,
+ VIN_LINE_MAX = 8,
};
enum subdev_type;
dma_addr_t addr);
void (*vin_wr_get_ping_pong_status)(struct stf_vin2_dev *vin_dev);
void (*vin_isp_set_yuv_addr)(struct stf_vin2_dev *vin_dev,
- int isp_id,
dma_addr_t y_addr, dma_addr_t uv_addr);
void (*vin_isp_set_raw_addr)(struct stf_vin2_dev *vin_dev,
- int isp_id, dma_addr_t raw_addr);
+ dma_addr_t raw_addr);
+ void (*vin_isp_set_ss0_addr)(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr);
+ void (*vin_isp_set_ss1_addr)(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr);
+ void (*vin_isp_set_itiw_addr)(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr);
+ void (*vin_isp_set_itir_addr)(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr);
+ void (*vin_isp_set_scd_addr)(struct stf_vin2_dev *vin_dev,
+ dma_addr_t yhist_addr,
+ dma_addr_t scd_addr, int scd_type);
+ int (*vin_isp_get_scd_type)(struct stf_vin2_dev *vin_dev);
irqreturn_t (*vin_wr_irq_handler)(int irq, void *priv);
irqreturn_t (*vin_isp_irq_handler)(int irq, void *priv);
+ irqreturn_t (*vin_isp_csi_irq_handler)(int irq, void *priv);
+ irqreturn_t (*vin_isp_scd_irq_handler)(int irq, void *priv);
+ irqreturn_t (*vin_isp_irq_csiline_handler)(int irq, void *priv);
void (*isr_buffer_done)(struct vin_line *line,
struct vin_params *params);
+ void (*isr_change_buffer)(struct vin_line *line);
+};
+
+#define ISP_DUMMY_BUFFER_NUMS STF_ISP_PAD_MAX
+#define VIN_DUMMY_BUFFER_NUMS 1
+
+enum {
+ STF_DUMMY_VIN,
+ STF_DUMMY_ISP,
+ STF_DUMMY_MODULE_NUMS,
+};
+
+struct vin_dummy_buffer {
+ dma_addr_t paddr[3];
+ void *vaddr;
+ u32 buffer_size;
+ u32 width;
+ u32 height;
+ u32 mcode;
+};
+
+struct dummy_buffer {
+ struct vin_dummy_buffer *buffer;
+ u32 nums;
+ struct mutex stream_lock;
+ int stream_count;
+ atomic_t frame_skip;
};
struct stf_vin2_dev {
struct stfcamss *stfcamss;
u8 id;
struct vin_line line[VIN_LINE_MAX];
+ struct dummy_buffer dummy_buffer[STF_DUMMY_MODULE_NUMS];
struct vin_hw_ops *hw_ops;
atomic_t ref_count;
struct mutex power_lock;
extern struct vin_hw_ops vin_ops;
extern void dump_vin_reg(void *__iomem regbase);
+extern enum isp_pad_id stf_vin_map_isp_pad(enum vin_line_id line,
+ enum isp_pad_id def);
#endif /* STF_VIN_H */
static struct vin_params params;
struct stf_vin2_dev *vin_dev = priv;
struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ struct dummy_buffer *dummy_buffer =
+ &vin_dev->dummy_buffer[STF_DUMMY_VIN];
+
+ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
+ vin_dev->hw_ops->isr_change_buffer(&vin_dev->line[VIN_LINE_WR]);
+ vin_dev->hw_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR], ¶ms);
+ }
- vin_dev->hw_ops->isr_buffer_done(&vin_dev->line[VIN_LINE_WR], ¶ms);
vin_intr_clear(vin->sysctrl_base);
return IRQ_HANDLED;
}
+static void __iomem *stf_vin_get_ispbase(struct stf_vin_dev *vin)
+{
+ void __iomem *base = vin->isp_base;
+
+ return base;
+}
+
static irqreturn_t stf_vin_isp_irq_handler(int irq, void *priv)
{
static struct vin_params params;
struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
void __iomem *ispbase;
u32 int_status, value;
- int isp_id = irq == vin->isp0_irq ? 0 : 1;
- if (isp_id == 0)
- ispbase = vin->isp_isp0_base;
- else
- ispbase = vin->isp_isp1_base;
+ ispbase = stf_vin_get_ispbase(vin);
+
+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
+
+ if (int_status & BIT(24)) {
+ if ((int_status & BIT(11)))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_SS0], ¶ms);
+
+ if ((int_status & BIT(12)))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_SS1], ¶ms);
+
+ if ((int_status & BIT(20)))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP], ¶ms);
+
+ value = reg_read(ispbase, ISP_REG_ITIDPSR);
+ if ((value & BIT(17)))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_ITIW], ¶ms);
+ if ((value & BIT(16)))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_ITIR], ¶ms);
+
+#ifndef ISP_USE_CSI_AND_SC_DONE_INTERRUPT
+ if (int_status & BIT(25))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_RAW], ¶ms);
+
+ if (int_status & BIT(26))
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_SCD_Y], ¶ms);
+
+ /* clear interrupt */
+ reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL)
+ | EN_INT_ISP_DONE | EN_INT_CSI_DONE | EN_INT_SC_DONE);
+#else
+ /* clear interrupt */
+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+ (int_status & ~EN_INT_ALL) | EN_INT_ISP_DONE);
+#endif
+ } else
+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t stf_vin_isp_csi_irq_handler(int irq, void *priv)
+{
+ static struct vin_params params;
+ struct stf_vin2_dev *vin_dev = priv;
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase;
+ u32 int_status;
+
+ ispbase = stf_vin_get_ispbase(vin);
int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
- // if (int_status & BIT(24))
- vin_dev->hw_ops->isr_buffer_done(
- &vin_dev->line[VIN_LINE_ISP0 + isp_id], ¶ms);
+ if (int_status & BIT(25)) {
+ vin_dev->hw_ops->isr_buffer_done(
+ &vin_dev->line[VIN_LINE_ISP_RAW], ¶ms);
+
+ /* clear interrupt */
+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+ (int_status & ~EN_INT_ALL) | EN_INT_CSI_DONE);
+ } else
+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t stf_vin_isp_scd_irq_handler(int irq, void *priv)
+{
+ static struct vin_params params;
+ struct stf_vin2_dev *vin_dev = priv;
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase;
+ u32 int_status;
- value = reg_read(ispbase, ISP_REG_CIS_MODULE_CFG);
- if ((value & BIT(19)) && (int_status & BIT(25)))
+ ispbase = stf_vin_get_ispbase(vin);
+
+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
+
+ if (int_status & BIT(26)) {
vin_dev->hw_ops->isr_buffer_done(
- &vin_dev->line[VIN_LINE_ISP0_RAW + isp_id], ¶ms);
+ &vin_dev->line[VIN_LINE_ISP_SCD_Y], ¶ms);
- /* clear interrupt */
- reg_write(ispbase, ISP_REG_ISP_CTRL_0, int_status);
+ /* clear interrupt */
+ reg_write(ispbase, ISP_REG_ISP_CTRL_0, (int_status & ~EN_INT_ALL) | EN_INT_SC_DONE);
+ } else
+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
return IRQ_HANDLED;
}
+static irqreturn_t stf_vin_isp_irq_csiline_handler(int irq, void *priv)
+{
+ struct stf_vin2_dev *vin_dev = priv;
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ struct stf_isp_dev *isp_dev;
+ void __iomem *ispbase;
+ u32 int_status, value;
+
+ ispbase = stf_vin_get_ispbase(vin);
+
+ isp_dev = vin_dev->stfcamss->isp_dev;
+
+ int_status = reg_read(ispbase, ISP_REG_ISP_CTRL_0);
+ if (int_status & BIT(27)) {
+ struct dummy_buffer *dummy_buffer =
+ &vin_dev->dummy_buffer[STF_DUMMY_ISP];
+
+ if (!atomic_read(&isp_dev->shadow_count)) {
+ if (atomic_dec_if_positive(&dummy_buffer->frame_skip) < 0) {
+ if ((int_status & BIT(11)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_SS0]);
+ if ((int_status & BIT(12)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_SS1]);
+ if ((int_status & BIT(20)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP]);
+
+ value = reg_read(ispbase, ISP_REG_ITIDPSR);
+ if ((value & BIT(17)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_ITIW]);
+ if ((value & BIT(16)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_ITIR]);
+
+ value = reg_read(ispbase, ISP_REG_CSI_MODULE_CFG);
+ if ((value & BIT(19)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_RAW]);
+ if ((value & BIT(17)))
+ vin_dev->hw_ops->isr_change_buffer(
+ &vin_dev->line[VIN_LINE_ISP_SCD_Y]);
+ }
+
+ // shadow update
+ reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x30000, 0x30000);
+ reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3);
+ } else {
+ st_err_ratelimited(ST_VIN,
+ "isp shadow_lock locked. skip this frame\n");
+ }
+
+ /* clear interrupt */
+ reg_write(ispbase, ISP_REG_ISP_CTRL_0,
+ (int_status & ~EN_INT_ALL) | EN_INT_LINE_INT);
+ } else
+ st_debug(ST_VIN, "%s, Unknown interrupt!!!\n", __func__);
+
+ return IRQ_HANDLED;
+}
static int stf_vin_top_clk_init(struct stf_vin2_dev *vin_dev)
{
reg_write(vin->sysctrl_base, SYSCONSAIF_SYSCFG_32, (long)addr);
}
-void stf_vin_isp_set_yuv_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+void stf_vin_isp_set_yuv_addr(struct stf_vin2_dev *vin_dev,
dma_addr_t y_addr, dma_addr_t uv_addr)
{
struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
- void __iomem *ispbase =
- isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
reg_write(ispbase, ISP_REG_Y_PLANE_START_ADDR, y_addr);
reg_write(ispbase, ISP_REG_UV_PLANE_START_ADDR, uv_addr);
- // shadow update
- //reg_set_bit(ispbase, ISP_REG_IESHD_ADDR, BIT(1) | BIT(0), 0x3); //fw no configure 2021 1110
+ // reg_set_bit(ispbase, ISP_REG_ISP_CTRL_0, BIT(0), 1);
}
-void stf_vin_isp_set_raw_addr(struct stf_vin2_dev *vin_dev, int isp_id,
+void stf_vin_isp_set_raw_addr(struct stf_vin2_dev *vin_dev,
dma_addr_t raw_addr)
{
-#ifdef UNUSED_CODE
struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
- void __iomem *ispbase =
- isp_id ? vin->isp_isp1_base : vin->isp_isp0_base;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
reg_write(ispbase, ISP_REG_DUMP_CFG_0, raw_addr);
- reg_set_bit(ispbase, ISP_REG_CSIINTS_ADDR, 0x3FFFF, 0x3000a);
-#endif
+}
+
+void stf_vin_isp_set_ss0_addr(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ reg_write(ispbase, ISP_REG_SS0AY, y_addr);
+ reg_write(ispbase, ISP_REG_SS0AUV, uv_addr);
+}
+
+void stf_vin_isp_set_ss1_addr(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ reg_write(ispbase, ISP_REG_SS1AY, y_addr);
+ reg_write(ispbase, ISP_REG_SS1AUV, uv_addr);
+}
+
+void stf_vin_isp_set_itiw_addr(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ reg_write(ispbase, ISP_REG_ITIDWYSAR, y_addr);
+ reg_write(ispbase, ISP_REG_ITIDWUSAR, uv_addr);
+}
+
+void stf_vin_isp_set_itir_addr(struct stf_vin2_dev *vin_dev,
+ dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ reg_write(ispbase, ISP_REG_ITIDRYSAR, y_addr);
+ reg_write(ispbase, ISP_REG_ITIDRUSAR, uv_addr);
+}
+
+int stf_vin_isp_get_scd_type(struct stf_vin2_dev *vin_dev)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ return (reg_read(ispbase, ISP_REG_SC_CFG_1) & (0x3 << 30)) >> 30;
+}
+
+void stf_vin_isp_set_scd_addr(struct stf_vin2_dev *vin_dev,
+ dma_addr_t yhist_addr, dma_addr_t scd_addr, int scd_type)
+{
+ struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
+ void __iomem *ispbase = stf_vin_get_ispbase(vin);
+
+ reg_set_bit(ispbase, ISP_REG_SC_CFG_1, 0x3 << 30, scd_type << 30);
+ reg_write(ispbase, ISP_REG_SCD_CFG_0, scd_addr);
+ reg_write(ispbase, ISP_REG_YHIST_CFG_4, yhist_addr);
}
void dump_vin_reg(void *__iomem regbase)
.vin_wr_set_pong_addr = stf_vin_wr_set_pong_addr,
.vin_isp_set_yuv_addr = stf_vin_isp_set_yuv_addr,
.vin_isp_set_raw_addr = stf_vin_isp_set_raw_addr,
+ .vin_isp_set_ss0_addr = stf_vin_isp_set_ss0_addr,
+ .vin_isp_set_ss1_addr = stf_vin_isp_set_ss1_addr,
+ .vin_isp_set_itiw_addr = stf_vin_isp_set_itiw_addr,
+ .vin_isp_set_itir_addr = stf_vin_isp_set_itir_addr,
+ .vin_isp_set_scd_addr = stf_vin_isp_set_scd_addr,
+ .vin_isp_get_scd_type = stf_vin_isp_get_scd_type,
.vin_wr_irq_handler = stf_vin_wr_irq_handler,
.vin_isp_irq_handler = stf_vin_isp_irq_handler,
+ .vin_isp_csi_irq_handler = stf_vin_isp_csi_irq_handler,
+ .vin_isp_scd_irq_handler = stf_vin_isp_scd_irq_handler,
+ .vin_isp_irq_csiline_handler = stf_vin_isp_irq_csiline_handler,
};
unsigned int stdbg_level = ST_ERR;
unsigned int stdbg_mask = 0x7F;
#endif
+EXPORT_SYMBOL_GPL(stdbg_level);
+EXPORT_SYMBOL_GPL(stdbg_mask);
static const struct reg_name mem_reg_name[] = {
#ifndef CONFIG_VIDEO_CADENCE_CSI2RX
{"vrst"},
{"mipi1"},
{"sctrl"},
- {"isp0"},
- {"isp1"},
+ {"isp"},
{"trst"},
{"pmu"},
{"syscrg"},
for (i = 0; i < ARRAY_SIZE(mem_reg_name); i++) {
name = (char *)(&mem_reg_name[i]);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+
if (!res)
return -EINVAL;
vin->sysctrl_base = devm_ioremap_resource(dev, res);
if (IS_ERR(vin->sysctrl_base))
return PTR_ERR(vin->sysctrl_base);
- } else if (!strcmp(name, "isp0")) {
- vin->isp_isp0_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(vin->isp_isp0_base))
- return PTR_ERR(vin->isp_isp0_base);
- } else if (!strcmp(name, "isp1")) {
- vin->isp_isp1_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(vin->isp_isp1_base))
- return PTR_ERR(vin->isp_isp1_base);
+ } else if (!strcmp(name, "isp")) {
+ vin->isp_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vin->isp_base))
+ return PTR_ERR(vin->isp_base);
} else if (!strcmp(name, "trst")) {
vin->vin_top_rstgen_base = devm_ioremap_resource(dev, res);
if (IS_ERR(vin->vin_top_rstgen_base))
if (!vin->sys_crg)
return -ENOMEM;
} else {
+
st_err(ST_CAMSS, "Could not match resource name\n");
}
}
struct media_pad *pad;
while (1) {
+ if (!entity->pads)
+ return NULL;
+
pad = &entity->pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
return NULL;
}
#endif
- for (i = 0; i < stfcamss->isp_num; i++) {
- ret = stf_isp_subdev_init(stfcamss, i);
- if (ret < 0) {
- st_err(ST_CAMSS,
- "Failed to init stf_isp sub-device: %d\n",
- ret);
- return ret;
- }
+ ret = stf_isp_subdev_init(stfcamss);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to init stf_isp sub-device: %d\n",
+ ret);
+ return ret;
}
ret = stf_vin_subdev_init(stfcamss);
}
#endif
- for (i = 0; i < stfcamss->isp_num; i++) {
- ret = stf_isp_register(&isp_dev[i],
- &stfcamss->v4l2_dev);
- if (ret < 0) {
- st_err(ST_CAMSS,
- "Failed to register stf isp%d entity: %d\n",
- i, ret);
- goto err_reg_isp;
- }
+ ret = stf_isp_register(isp_dev,
+ &stfcamss->v4l2_dev);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to register stf isp%d entity: %d\n",
+ i, ret);
+ goto err_reg_isp;
}
ret = stf_vin_register(vin_dev, &stfcamss->v4l2_dev);
STF_CSIPHY_PAD_SRC,
&csi_dev[j].subdev.entity,
STF_CSI_PAD_SINK,
- 0);
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
if (ret < 0) {
st_err(ST_CAMSS,
"Failed to link %s->%s entities: %d\n",
}
}
#endif
- for (i = 0; i < stfcamss->isp_num; i++) {
- ret = media_create_pad_link(
- &isp_dev[i].subdev.entity,
- STF_ISP_PAD_SRC,
- &vin_dev->line[i + VIN_LINE_ISP0].subdev.entity,
- STF_VIN_PAD_SINK,
- 0);
- if (ret < 0) {
- st_err(ST_CAMSS,
- "Failed to link %s->%s entities: %d\n",
- isp_dev[i].subdev.entity.name,
- vin_dev->line[i + VIN_LINE_ISP0]
- .subdev.entity.name,
- ret);
- goto err_link;
- }
- ret = media_create_pad_link(
- &isp_dev[i].subdev.entity,
- STF_ISP_PAD_SRC,
- &vin_dev->line[i + VIN_LINE_ISP0_RAW].subdev.entity,
- STF_VIN_PAD_SINK,
- 0);
- if (ret < 0) {
- st_err(ST_CAMSS,
- "Failed to link %s->%s entities: %d\n",
- isp_dev[i].subdev.entity.name,
- vin_dev->line[i + VIN_LINE_ISP0_RAW]
- .subdev.entity.name,
- ret);
- goto err_link;
- }
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC,
+ &vin_dev->line[VIN_LINE_ISP].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_SS0,
+ &vin_dev->line[VIN_LINE_ISP_SS0].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[i + VIN_LINE_ISP_SS0]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_SS1,
+ &vin_dev->line[VIN_LINE_ISP_SS1].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP_SS1]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_ITIW,
+ &vin_dev->line[VIN_LINE_ISP_ITIW].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP_ITIW]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_ITIR,
+ &vin_dev->line[VIN_LINE_ISP_ITIR].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP_ITIR]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_RAW,
+ &vin_dev->line[VIN_LINE_ISP_RAW].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP_RAW]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SRC_SCD_Y,
+ &vin_dev->line[VIN_LINE_ISP_SCD_Y].subdev.entity,
+ STF_VIN_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ isp_dev->subdev.entity.name,
+ vin_dev->line[VIN_LINE_ISP_SCD_Y]
+ .subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+ ret = media_create_pad_link(
+ &dvp_dev->subdev.entity,
+ STF_DVP_PAD_SRC,
+ &isp_dev->subdev.entity,
+ STF_ISP_PAD_SINK,
+ 0);
+ if (ret < 0) {
+ st_err(ST_CAMSS,
+ "Failed to link %s->%s entities: %d\n",
+ dvp_dev->subdev.entity.name,
+ isp_dev->subdev.entity.name,
+ ret);
+ goto err_link;
+ }
+
+#ifndef CONFIG_VIDEO_CADENCE_CSI2RX
+ for (j = 0; j < stfcamss->csi_num; j++) {
ret = media_create_pad_link(
- &dvp_dev->subdev.entity,
- STF_DVP_PAD_SRC,
- &isp_dev[i].subdev.entity,
+ &csi_dev[j].subdev.entity,
+ STF_CSI_PAD_SRC,
+ &isp_dev->subdev.entity,
STF_ISP_PAD_SINK,
0);
if (ret < 0) {
st_err(ST_CAMSS,
"Failed to link %s->%s entities: %d\n",
- dvp_dev->subdev.entity.name,
- isp_dev[i].subdev.entity.name,
- ret);
+ csi_dev[j].subdev.entity.name,
+ isp_dev->subdev.entity.name,
+ ret);
goto err_link;
}
- #ifndef CONFIG_VIDEO_CADENCE_CSI2RX
- for (j = 0; j < stfcamss->csi_num; j++) {
- ret = media_create_pad_link(
- &csi_dev[j].subdev.entity,
- STF_CSI_PAD_SRC,
- &isp_dev[i].subdev.entity,
- STF_ISP_PAD_SINK,
- 0);
- if (ret < 0) {
- st_err(ST_CAMSS,
- "Failed to link %s->%s entities: %d\n",
- csi_dev[j].subdev.entity.name,
- isp_dev[i].subdev.entity.name,
- ret);
- goto err_link;
- }
- }
- #endif
}
+#endif
return ret;
err_link:
stf_vin_unregister(stfcamss->vin_dev);
err_reg_vin:
- i = stfcamss->isp_num;
+ stf_isp_unregister(stfcamss->isp_dev);
err_reg_isp:
- for (i--; i >= 0; i--)
- stf_isp_unregister(&stfcamss->isp_dev[i]);
-
#ifndef CONFIG_VIDEO_CADENCE_CSI2RX
i = stfcamss->csi_num;
err_reg_csi:
stf_csi_unregister(&stfcamss->csi_dev[i]);
#endif
- i = stfcamss->isp_num;
- for (i--; i >= 0; i--)
- stf_isp_unregister(&stfcamss->isp_dev[i]);
+ stf_isp_unregister(stfcamss->isp_dev);
stf_vin_unregister(stfcamss->vin_dev);
}
case CSI2RX0_PORT_NUMBER:
case CSI2RX1_PORT_NUMBER:
id = port - CSI2RX0_PORT_NUMBER;
- isp_dev = &isp_dev[id];
subdev->host_priv = &isp_dev->subdev.entity;
break;
case DVP_SENSOR_PORT_NUMBER:
static const struct v4l2_async_notifier_operations
stfcamss_subdev_notifier_ops = {
.bound = stfcamss_subdev_notifier_bound,
- // .complete = stfcamss_subdev_notifier_complete,
};
static const struct media_device_ops stfcamss_media_ops = {
#ifdef CONFIG_DEBUG_FS
enum module_id {
VIN_MODULE = 0,
- ISP0_MODULE,
- ISP1_MODULE,
+ ISP_MODULE,
CSI0_MODULE,
CSI1_MODULE,
CSIPHY_MODULE,
CLK_MODULE,
};
-static enum module_id id_num = ISP0_MODULE;
+static enum module_id id_num = ISP_MODULE;
void dump_clk_reg(void __iomem *reg_base)
{
int i;
st_info(ST_CAMSS, "DUMP Clk register:\n");
- for (i = 0; i <= CLK_C_ISP1_CTRL; i += 4)
+ for (i = 0; i <= CLK_C_ISP_CTRL; i += 4)
print_reg(ST_CAMSS, reg_base, i);
}
struct stfcamss *stfcamss = dev_get_drvdata(dev);
struct stf_vin_dev *vin = stfcamss->vin;
struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
- struct stf_isp_dev *isp0_dev = &stfcamss->isp_dev[0];
- struct stf_isp_dev *isp1_dev = &stfcamss->isp_dev[1];
+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
struct stf_csi_dev *csi0_dev = &stfcamss->csi_dev[0];
struct stf_csi_dev *csi1_dev = &stfcamss->csi_dev[1];
}
mutex_unlock(&vin_dev->power_lock);
break;
- case ISP0_MODULE:
- mutex_lock(&isp0_dev->stream_lock);
- if (isp0_dev->stream_count > 0) {
- reg_base = vin->isp_isp0_base;
- dump_isp_reg(reg_base, 0);
+ case ISP_MODULE:
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count > 0) {
+ reg_base = vin->isp_base;
+ dump_isp_reg(reg_base);
}
- mutex_unlock(&isp0_dev->stream_lock);
- break;
- case ISP1_MODULE:
- mutex_lock(&isp1_dev->stream_lock);
- if (isp1_dev->stream_count > 0) {
- reg_base = vin->isp_isp1_base;
- dump_isp_reg(reg_base, 1);
- }
- mutex_unlock(&isp1_dev->stream_lock);
+ mutex_unlock(&isp_dev->stream_lock);
break;
case CSI0_MODULE:
mutex_lock(&csi0_dev->stream_lock);
{
struct stf_vin_dev *vin = stfcamss->vin;
struct stf_vin2_dev *vin_dev = stfcamss->vin_dev;
- struct stf_isp_dev *isp0_dev = &stfcamss->isp_dev[0];
- struct stf_isp_dev *isp1_dev = &stfcamss->isp_dev[1];
+ struct stf_isp_dev *isp_dev = stfcamss->isp_dev;
struct stf_csi_dev *csi0_dev = &stfcamss->csi_dev[0];
struct stf_csi_dev *csi1_dev = &stfcamss->csi_dev[1];
void __iomem *reg_base;
}
mutex_unlock(&vin_dev->power_lock);
break;
- case ISP0_MODULE:
- mutex_lock(&isp0_dev->stream_lock);
- if (isp0_dev->stream_count > 0) {
- reg_base = vin->isp_isp0_base;
- print_reg(ST_ISP, reg_base, offset);
- reg_write(reg_base, offset, val);
- print_reg(ST_ISP, reg_base, offset);
- }
- mutex_unlock(&isp0_dev->stream_lock);
- break;
- case ISP1_MODULE:
- mutex_lock(&isp1_dev->stream_lock);
- if (isp1_dev->stream_count > 0) {
- reg_base = vin->isp_isp1_base;
+ case ISP_MODULE:
+ mutex_lock(&isp_dev->stream_lock);
+ if (isp_dev->stream_count > 0) {
+ reg_base = vin->isp_base;
print_reg(ST_ISP, reg_base, offset);
reg_write(reg_base, offset, val);
print_reg(ST_ISP, reg_base, offset);
}
- mutex_unlock(&isp1_dev->stream_lock);
+ mutex_unlock(&isp_dev->stream_lock);
break;
case CSI0_MODULE:
mutex_lock(&csi0_dev->stream_lock);
if (!stfcamss)
return -ENOMEM;
- stfcamss->isp_num = 2;
stfcamss->csi_num = 2;
#ifndef CONFIG_VIDEO_CADENCE_CSI2RX
stfcamss->csiphy_num = 2;
}
stfcamss->isp_dev = devm_kzalloc(dev,
- stfcamss->isp_num * sizeof(*stfcamss->isp_dev),
+ sizeof(*stfcamss->isp_dev),
GFP_KERNEL);
if (!stfcamss->isp_dev) {
ret = -ENOMEM;
goto err_cam;
}
- vin->isp0_irq = platform_get_irq(pdev, 1);
- if (vin->isp0_irq <= 0) {
- st_err(ST_CAMSS, "Could not get isp0 irq\n");
+ vin->isp_irq = platform_get_irq(pdev, 1);
+ if (vin->isp_irq <= 0) {
+ st_err(ST_CAMSS, "Could not get isp irq\n");
goto err_cam;
}
-#ifdef UNUSED_CODE
- vin->isp1_irq = platform_get_irq(pdev, 2);
- if (vin->isp1_irq <= 0) {
- st_err(ST_CAMSS, "Could not get isp1 irq\n");
+ vin->isp_csi_irq = platform_get_irq(pdev, 2);
+ if (vin->isp_csi_irq <= 0) {
+ st_err(ST_CAMSS, "Could not get isp csi irq\n");
+ goto err_cam;
+ }
+
+ vin->isp_scd_irq = platform_get_irq(pdev, 3);
+ if (vin->isp_scd_irq <= 0) {
+ st_err(ST_CAMSS, "Could not get isp scd irq\n");
+ goto err_cam;
+ }
+
+ vin->isp_irq_csiline = platform_get_irq(pdev, 4);
+ if (vin->isp_irq_csiline <= 0) {
+ st_err(ST_CAMSS, "Could not get isp irq csiline\n");
goto err_cam;
}
-#endif
stfcamss->nclks = ARRAY_SIZE(stfcamss_clocks);
stfcamss->sys_clk = stfcamss_clocks;
enum sensor_type {
SENSOR_VIN,
- SENSOR_ISP0, // need replace sensor
- SENSOR_ISP1, // need replace sensor
+ /* need replace sensor */
+ SENSOR_ISP,
};
enum subdev_type {
VIN_DEV_TYPE,
- ISP0_DEV_TYPE,
- ISP1_DEV_TYPE,
+ ISP_DEV_TYPE,
};
#include "stf_common.h"
struct stf_vin_dev *vin; // stfcamss phy res
struct v4l2_device v4l2_dev;
struct media_device media_dev;
+ struct media_pipeline pipe;
struct device *dev;
struct stf_vin2_dev *vin_dev; // subdev
struct stf_dvp_dev *dvp_dev; // subdev
struct stf_csi_dev *csi_dev; // subdev
int csiphy_num;
struct stf_csiphy_dev *csiphy_dev; // subdev
- int isp_num;
struct stf_isp_dev *isp_dev; // subdev
struct v4l2_async_notifier notifier;
struct clk_bulk_data *sys_clk;
#define CLK_MIPI_RX1_PXL_2_CTRL 0X30
#define CLK_MIPI_RX1_PXL_3_CTRL 0X34
#define CLK_MIPI_RX1_SYS1_CTRL 0x38
-#define CLK_ISP0_CTRL 0x3c
-#define CLK_ISP0_2X_CTRL 0x40
-#define CLK_ISP0_MIPI_CTRL 0x44
-#define CLK_C_ISP0_CTRL 0x64
-#define CLK_ISP1_CTRL 0x48
-#define CLK_ISP1_2X_CTRL 0x4C
-#define CLK_ISP1_MIPI_CTRL 0x50
-#define CLK_C_ISP1_CTRL 0x68
+#define CLK_ISP_CTRL 0x3c
+#define CLK_ISP_2X_CTRL 0x40
+#define CLK_ISP_MIPI_CTRL 0x44
+#define CLK_C_ISP_CTRL 0x64
#define CLK_CSI2RX0_APB_CTRL 0x58
#define ISP_REG_RGB_TO_YUV_COVERSION6 0x00000E58
#define ISP_REG_RGB_TO_YUV_COVERSION7 0x00000E5C
#define ISP_REG_RGB_TO_YUV_COVERSION8 0x00000E60
-#define ISP_REG_CIS_MODULE_CFG 0x00000010
+#define ISP_REG_CSI_MODULE_CFG 0x00000010
#define ISP_REG_ISP_CTRL_1 0x00000A08
#define ISP_REG_ISP_CTRL_0 0x00000A00
#define ISP_REG_DC_AXI_ID 0x00000044
void __iomem *rstgen_base;
void __iomem *mipi1_base;
void __iomem *sysctrl_base;
- void __iomem *isp_isp0_base;
- void __iomem *isp_isp1_base;
+ void __iomem *isp_base;
void __iomem *vin_top_clkgen_base;
void __iomem *vin_top_rstgen_base;
void __iomem *vin_top_iopad_base;
void __iomem * sys_crg;
struct vin_framesize frame;
struct vin_format format;
- bool isp0;
- bool isp1;
- int isp0_irq;
- int isp1_irq;
+ bool isp;
+ int isp_irq;
+ int isp_csi_irq;
+ int isp_scd_irq;
+ int isp_irq_csiline;
u32 major;
struct vin_buf buf;