]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
UBUNTU: SAUCE: IPU6 driver release for kernel 5.14 on 2021-11-01
authorHao Yao <hao.yao@intel.com>
Mon, 1 Nov 2021 02:04:55 +0000 (10:04 +0800)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 31 May 2022 16:26:27 +0000 (18:26 +0200)
BugLink: https://bugs.launchpad.net/bugs/1955383
Add support for both Tiger Lake and Alder Lake platforms.
Add support for OV01A10 sensor.

Signed-off-by: Hao Yao <hao.yao@intel.com>
(backported from commit 1f26f0c8cb13d14c22d9f7010b1b4774b89136a9 github.com/intel/ipu6-drivers
added CONFIG_VIDEO_OV01A10 to drivers/media/i2c/Kconfig)
Signed-off-by: You-Sheng Yang <vicamo.yang@canonical.com>
Acked-by: Andrea Righi <andrea.righi@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
32 files changed:
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/hm11b1.c
drivers/media/i2c/ov01a10.c [new file with mode: 0644]
drivers/media/i2c/ov01a1s.c
drivers/media/i2c/power_ctrl_logic.c
drivers/media/pci/intel/Kconfig
drivers/media/pci/intel/ipu-buttress.c
drivers/media/pci/intel/ipu-buttress.h
drivers/media/pci/intel/ipu-isys-csi2-be-soc.c
drivers/media/pci/intel/ipu-isys-csi2-be.c [new file with mode: 0644]
drivers/media/pci/intel/ipu-isys-csi2.c
drivers/media/pci/intel/ipu-isys-subdev.c
drivers/media/pci/intel/ipu-isys-subdev.h
drivers/media/pci/intel/ipu-isys-tpg.c [new file with mode: 0644]
drivers/media/pci/intel/ipu-isys-tpg.h [new file with mode: 0644]
drivers/media/pci/intel/ipu-isys.c
drivers/media/pci/intel/ipu-isys.h
drivers/media/pci/intel/ipu-mmu.c
drivers/media/pci/intel/ipu-psys-compat32.c
drivers/media/pci/intel/ipu-psys.c
drivers/media/pci/intel/ipu-psys.h
drivers/media/pci/intel/ipu.c
drivers/media/pci/intel/ipu.h
drivers/media/pci/intel/ipu6/ipu-resources.c
drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
drivers/media/pci/intel/ipu6/ipu6-isys-gpc.c
drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
drivers/media/pci/intel/ipu6/ipu6-ppg.c
drivers/media/pci/intel/ipu6/ipu6-psys-gpc.c
drivers/media/pci/intel/ipu6/ipu6-psys.c
drivers/media/pci/intel/ipu6/ipu6ep-fw-resources.c

index 84bfb9b384abe59872f621636c35a3b83ae43a92..53f2272554606c2636c7ca3e44a2076c118f3c52 100644 (file)
@@ -1402,6 +1402,20 @@ config POWER_CTRL_LOGIC
          To compile this driver as a module, choose M here: the
          module will be called power_ctrl_logic.
 
+config VIDEO_OV01A10
+       tristate "OmniVision OV01A10 sensor support"
+       depends on VIDEO_V4L2 && I2C
+       depends on ACPI || COMPILE_TEST
+       select MEDIA_CONTROLLER
+       select VIDEO_V4L2_SUBDEV_API
+       select V4L2_FWNODE
+       help
+         This is a Video4Linux2 sensor driver for the OmniVision
+         OV01A10 camera.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ov01a10.
+
 config VIDEO_OV01A1S
        tristate "OmniVision OV01A1S sensor support"
        depends on POWER_CTRL_LOGIC
index 60951caf60043b8b62b06cd4f165f6e03ffee5fa..0a982ff282aefd868a506bcda5ffa43952c3d597 100644 (file)
@@ -137,4 +137,5 @@ obj-$(CONFIG_SDR_MAX2175) += max2175.o
 
 obj-$(CONFIG_VIDEO_HM11B1) += hm11b1.o
 obj-$(CONFIG_VIDEO_OV01A1S) += ov01a1s.o
+obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
 obj-$(CONFIG_POWER_CTRL_LOGIC) += power_ctrl_logic.o
index ecc74d2bc250917343d55c956e9c319b2e9d120c..27d5acebb73c3ac87ce55483e9e9c71a477a882a 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/version.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
@@ -847,7 +848,7 @@ exit:
 }
 
 static int hm11b1_set_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct hm11b1 *hm11b1 = to_hm11b1(sd);
@@ -862,7 +863,7 @@ static int hm11b1_set_format(struct v4l2_subdev *sd,
        mutex_lock(&hm11b1->mutex);
        hm11b1_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                hm11b1->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(hm11b1->link_freq, mode->link_freq_index);
@@ -887,15 +888,15 @@ static int hm11b1_set_format(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_get_format(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct hm11b1 *hm11b1 = to_hm11b1(sd);
 
        mutex_lock(&hm11b1->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&hm11b1->sd, cfg,
-                                                         fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(&hm11b1->sd,
+                                                         sd_state, fmt->pad);
        else
                hm11b1_update_pad_format(hm11b1->cur_mode, &fmt->format);
 
@@ -905,7 +906,7 @@ static int hm11b1_get_format(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -917,7 +918,7 @@ static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int hm11b1_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -940,7 +941,7 @@ static int hm11b1_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&hm11b1->mutex);
        hm11b1_update_pad_format(&supported_modes[0],
-                                v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                                v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&hm11b1->mutex);
 
        return 0;
diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c
new file mode 100644 (file)
index 0000000..54968bb
--- /dev/null
@@ -0,0 +1,934 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020-2021 Intel Corporation.
+
+#include <asm/unaligned.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <linux/vsc.h>
+
+#define OV01A10_LINK_FREQ_400MHZ       400000000ULL
+#define OV01A10_SCLK                   40000000LL
+#define OV01A10_MCLK                   19200000
+#define OV01A10_DATA_LANES             1
+#define OV01A10_RGB_DEPTH              10
+
+#define OV01A10_REG_CHIP_ID            0x300a
+#define OV01A10_CHIP_ID                        0x560141
+
+#define OV01A10_REG_MODE_SELECT                0x0100
+#define OV01A10_MODE_STANDBY           0x00
+#define OV01A10_MODE_STREAMING         0x01
+
+/* vertical-timings from sensor */
+#define OV01A10_REG_VTS                        0x380e
+#define OV01A10_VTS_DEF                        0x0380
+#define OV01A10_VTS_MIN                        0x0380
+#define OV01A10_VTS_MAX                        0xffff
+
+/* Exposure controls from sensor */
+#define OV01A10_REG_EXPOSURE           0x3501
+#define OV01A10_EXPOSURE_MIN           4
+#define OV01A10_EXPOSURE_MAX_MARGIN    8
+#define OV01A10_EXPOSURE_STEP          1
+
+/* Analog gain controls from sensor */
+#define OV01A10_REG_ANALOG_GAIN                0x3508
+#define OV01A10_ANAL_GAIN_MIN          0x100
+#define OV01A10_ANAL_GAIN_MAX          0xffff
+#define OV01A10_ANAL_GAIN_STEP         1
+
+/* Digital gain controls from sensor */
+#define OV01A10_REG_DIGILAL_GAIN_B     0x350A
+#define OV01A10_REG_DIGITAL_GAIN_GB    0x3510
+#define OV01A10_REG_DIGITAL_GAIN_GR    0x3513
+#define OV01A10_REG_DIGITAL_GAIN_R     0x3516
+#define OV01A10_DGTL_GAIN_MIN          0
+#define OV01A10_DGTL_GAIN_MAX          0x3ffff
+#define OV01A10_DGTL_GAIN_STEP         1
+#define OV01A10_DGTL_GAIN_DEFAULT      1024
+
+/* Test Pattern Control */
+#define OV01A10_REG_TEST_PATTERN               0x4503
+#define OV01A10_TEST_PATTERN_ENABLE    BIT(7)
+#define OV01A10_TEST_PATTERN_BAR_SHIFT 0
+
+enum {
+       OV01A10_LINK_FREQ_400MHZ_INDEX,
+};
+
+struct ov01a10_reg {
+       u16 address;
+       u8 val;
+};
+
+struct ov01a10_reg_list {
+       u32 num_of_regs;
+       const struct ov01a10_reg *regs;
+};
+
+struct ov01a10_link_freq_config {
+       const struct ov01a10_reg_list reg_list;
+};
+
+struct ov01a10_mode {
+       /* Frame width in pixels */
+       u32 width;
+
+       /* Frame height in pixels */
+       u32 height;
+
+       /* Horizontal timining size */
+       u32 hts;
+
+       /* Default vertical timining size */
+       u32 vts_def;
+
+       /* Min vertical timining size */
+       u32 vts_min;
+
+       /* Link frequency needed for this resolution */
+       u32 link_freq_index;
+
+       /* Sensor register settings for this resolution */
+       const struct ov01a10_reg_list reg_list;
+};
+
+static const struct ov01a10_reg mipi_data_rate_720mbps[] = {
+};
+
+static const struct ov01a10_reg sensor_1280x800_setting[] = {
+       {0x0103, 0x01},
+       {0x0302, 0x00},
+       {0x0303, 0x06},
+       {0x0304, 0x01},
+       {0x0305, 0xe0},
+       {0x0306, 0x00},
+       {0x0308, 0x01},
+       {0x0309, 0x00},
+       {0x030c, 0x01},
+       {0x0322, 0x01},
+       {0x0323, 0x06},
+       {0x0324, 0x01},
+       {0x0325, 0x68},
+       {0x3002, 0xa1},
+       {0x301e, 0xf0},
+       {0x3022, 0x01},
+       {0x3501, 0x03},
+       {0x3502, 0x78},
+       {0x3504, 0x0c},
+       {0x3508, 0x01},
+       {0x3509, 0x00},
+       {0x3601, 0xc0},
+       {0x3603, 0x71},
+       {0x3610, 0x68},
+       {0x3611, 0x86},
+       {0x3640, 0x10},
+       {0x3641, 0x80},
+       {0x3642, 0xdc},
+       {0x3646, 0x55},
+       {0x3647, 0x57},
+       {0x364b, 0x00},
+       {0x3653, 0x10},
+       {0x3655, 0x00},
+       {0x3656, 0x00},
+       {0x365f, 0x0f},
+       {0x3661, 0x45},
+       {0x3662, 0x24},
+       {0x3663, 0x11},
+       {0x3664, 0x07},
+       {0x3709, 0x34},
+       {0x370b, 0x6f},
+       {0x3714, 0x22},
+       {0x371b, 0x27},
+       {0x371c, 0x67},
+       {0x371d, 0xa7},
+       {0x371e, 0xe7},
+       {0x3730, 0x81},
+       {0x3733, 0x10},
+       {0x3734, 0x40},
+       {0x3737, 0x04},
+       {0x3739, 0x1c},
+       {0x3767, 0x00},
+       {0x376c, 0x81},
+       {0x3772, 0x14},
+       {0x37c2, 0x04},
+       {0x37d8, 0x03},
+       {0x37d9, 0x0c},
+       {0x37e0, 0x00},
+       {0x37e1, 0x08},
+       {0x37e2, 0x10},
+       {0x37e3, 0x04},
+       {0x37e4, 0x04},
+       {0x37e5, 0x03},
+       {0x37e6, 0x04},
+       {0x3800, 0x00},
+       {0x3801, 0x00},
+       {0x3802, 0x00},
+       {0x3803, 0x00},
+       {0x3804, 0x05},
+       {0x3805, 0x0f},
+       {0x3806, 0x03},
+       {0x3807, 0x2f},
+       {0x3808, 0x05},
+       {0x3809, 0x00},
+       {0x380a, 0x03},
+       {0x380b, 0x20},
+       {0x380c, 0x02},
+       {0x380d, 0xe8},
+       {0x380e, 0x03},
+       {0x380f, 0x80},
+       {0x3810, 0x00},
+       {0x3811, 0x09},
+       {0x3812, 0x00},
+       {0x3813, 0x08},
+       {0x3814, 0x01},
+       {0x3815, 0x01},
+       {0x3816, 0x01},
+       {0x3817, 0x01},
+       {0x3820, 0xa8},
+       {0x3822, 0x13},
+       {0x3832, 0x28},
+       {0x3833, 0x10},
+       {0x3b00, 0x00},
+       {0x3c80, 0x00},
+       {0x3c88, 0x02},
+       {0x3c8c, 0x07},
+       {0x3c8d, 0x40},
+       {0x3cc7, 0x80},
+       {0x4000, 0xc3},
+       {0x4001, 0xe0},
+       {0x4003, 0x40},
+       {0x4008, 0x02},
+       {0x4009, 0x19},
+       {0x400a, 0x01},
+       {0x400b, 0x6c},
+       {0x4011, 0x00},
+       {0x4041, 0x00},
+       {0x4300, 0xff},
+       {0x4301, 0x00},
+       {0x4302, 0x0f},
+       {0x4503, 0x00},
+       {0x4601, 0x50},
+       {0x4800, 0x64},
+       {0x481f, 0x34},
+       {0x4825, 0x33},
+       {0x4837, 0x11},
+       {0x4881, 0x40},
+       {0x4883, 0x01},
+       {0x4890, 0x00},
+       {0x4901, 0x00},
+       {0x4902, 0x00},
+       {0x4b00, 0x2a},
+       {0x4b0d, 0x00},
+       {0x450a, 0x04},
+       {0x450b, 0x00},
+       {0x5000, 0x65},
+       {0x5200, 0x18},
+       {0x5004, 0x00},
+       {0x5080, 0x40},
+       {0x0305, 0xf4},
+       {0x0325, 0xc2},
+       {0x380c, 0x05},
+       {0x380d, 0xd0},
+};
+
+static const char * const ov01a10_test_pattern_menu[] = {
+       "Disabled",
+       "Color Bar",
+       "Top-Bottom Darker Color Bar",
+       "Right-Left Darker Color Bar",
+       "Color Bar type 4",
+};
+
+static const s64 link_freq_menu_items[] = {
+       OV01A10_LINK_FREQ_400MHZ,
+};
+
+static const struct ov01a10_link_freq_config link_freq_configs[] = {
+       [OV01A10_LINK_FREQ_400MHZ_INDEX] = {
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mipi_data_rate_720mbps),
+                       .regs = mipi_data_rate_720mbps,
+               }
+       },
+};
+
+static const struct ov01a10_mode supported_modes[] = {
+       {
+               .width = 1280,
+               .height = 800,
+               .hts = 1488,
+               .vts_def = OV01A10_VTS_DEF,
+               .vts_min = OV01A10_VTS_MIN,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(sensor_1280x800_setting),
+                       .regs = sensor_1280x800_setting,
+               },
+               .link_freq_index = OV01A10_LINK_FREQ_400MHZ_INDEX,
+       },
+};
+
+struct ov01a10 {
+       struct v4l2_subdev sd;
+       struct media_pad pad;
+       struct v4l2_ctrl_handler ctrl_handler;
+
+       /* V4L2 Controls */
+       struct v4l2_ctrl *link_freq;
+       struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *vblank;
+       struct v4l2_ctrl *hblank;
+       struct v4l2_ctrl *exposure;
+
+       /* Current mode */
+       const struct ov01a10_mode *cur_mode;
+
+       /* To serialize asynchronus callbacks */
+       struct mutex mutex;
+
+       /* Streaming on/off */
+       bool streaming;
+};
+
+static inline struct ov01a10 *to_ov01a10(struct v4l2_subdev *subdev)
+{
+       return container_of(subdev, struct ov01a10, sd);
+}
+
+static int ov01a10_read_reg(struct ov01a10 *ov01a10, u16 reg, u16 len, u32 *val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       struct i2c_msg msgs[2];
+       u8 addr_buf[2];
+       u8 data_buf[4] = {0};
+       int ret = 0;
+
+       if (len > sizeof(data_buf))
+               return -EINVAL;
+
+       put_unaligned_be16(reg, addr_buf);
+       msgs[0].addr = client->addr;
+       msgs[0].flags = 0;
+       msgs[0].len = sizeof(addr_buf);
+       msgs[0].buf = addr_buf;
+       msgs[1].addr = client->addr;
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].len = len;
+       msgs[1].buf = &data_buf[sizeof(data_buf) - len];
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
+       if (ret != ARRAY_SIZE(msgs))
+               return ret < 0 ? ret : -EIO;
+
+       *val = get_unaligned_be32(data_buf);
+
+       return 0;
+}
+
+static int ov01a10_write_reg(struct ov01a10 *ov01a10, u16 reg, u16 len, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       u8 buf[6];
+       int ret = 0;
+
+       if (len > 4)
+               return -EINVAL;
+
+       put_unaligned_be16(reg, buf);
+       put_unaligned_be32(val << 8 * (4 - len), buf + 2);
+
+       ret = i2c_master_send(client, buf, len + 2);
+       if (ret != len + 2)
+               return ret < 0 ? ret : -EIO;
+
+       return 0;
+}
+
+static int ov01a10_write_reg_list(struct ov01a10 *ov01a10,
+                                 const struct ov01a10_reg_list *r_list)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       unsigned int i;
+       int ret = 0;
+
+       for (i = 0; i < r_list->num_of_regs; i++) {
+               ret = ov01a10_write_reg(ov01a10, r_list->regs[i].address, 1,
+                                       r_list->regs[i].val);
+               if (ret) {
+                       dev_err_ratelimited(&client->dev,
+                                           "write reg 0x%4.4x return err = %d",
+                                           r_list->regs[i].address, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int ov01a10_update_digital_gain(struct ov01a10 *ov01a10, u32 d_gain)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       u32 real = d_gain << 6;
+       int ret = 0;
+
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGILAL_GAIN_B, 3, real);
+       if (ret) {
+               dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_B");
+               return ret;
+       }
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_GB, 3, real);
+       if (ret) {
+               dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_GB");
+               return ret;
+       }
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_GR, 3, real);
+       if (ret) {
+               dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_GR");
+               return ret;
+       }
+
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_DIGITAL_GAIN_R, 3, real);
+       if (ret) {
+               dev_err(&client->dev, "failed to set OV01A10_REG_DIGITAL_GAIN_R");
+               return ret;
+       }
+       return ret;
+}
+
+static int ov01a10_test_pattern(struct ov01a10 *ov01a10, u32 pattern)
+{
+       if (pattern)
+               pattern = (pattern - 1) << OV01A10_TEST_PATTERN_BAR_SHIFT |
+                         OV01A10_TEST_PATTERN_ENABLE;
+
+       return ov01a10_write_reg(ov01a10, OV01A10_REG_TEST_PATTERN, 1, pattern);
+}
+
+static int ov01a10_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov01a10 *ov01a10 = container_of(ctrl->handler,
+                                            struct ov01a10, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       s64 exposure_max;
+       int ret = 0;
+
+       /* Propagate change of current control to all related controls */
+       if (ctrl->id == V4L2_CID_VBLANK) {
+               /* Update max exposure while meeting expected vblanking */
+               exposure_max = ov01a10->cur_mode->height + ctrl->val -
+                              OV01A10_EXPOSURE_MAX_MARGIN;
+               __v4l2_ctrl_modify_range(ov01a10->exposure,
+                                        ov01a10->exposure->minimum,
+                                        exposure_max, ov01a10->exposure->step,
+                                        exposure_max);
+       }
+
+       /* V4L2 controls values will be applied only when power is already up */
+       if (!pm_runtime_get_if_in_use(&client->dev))
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_ANALOGUE_GAIN:
+               ret = ov01a10_write_reg(ov01a10, OV01A10_REG_ANALOG_GAIN, 2,
+                                       ctrl->val);
+               break;
+
+       case V4L2_CID_DIGITAL_GAIN:
+               ret = ov01a10_update_digital_gain(ov01a10, ctrl->val);
+               break;
+
+       case V4L2_CID_EXPOSURE:
+               ret = ov01a10_write_reg(ov01a10, OV01A10_REG_EXPOSURE, 2,
+                                       ctrl->val);
+               break;
+
+       case V4L2_CID_VBLANK:
+               ret = ov01a10_write_reg(ov01a10, OV01A10_REG_VTS, 2,
+                                       ov01a10->cur_mode->height + ctrl->val);
+               break;
+
+       case V4L2_CID_TEST_PATTERN:
+               ret = ov01a10_test_pattern(ov01a10, ctrl->val);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       pm_runtime_put(&client->dev);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ov01a10_ctrl_ops = {
+       .s_ctrl = ov01a10_set_ctrl,
+};
+
+static int ov01a10_init_controls(struct ov01a10 *ov01a10)
+{
+       struct v4l2_ctrl_handler *ctrl_hdlr;
+       const struct ov01a10_mode *cur_mode;
+       s64 exposure_max, h_blank;
+       u32 vblank_min, vblank_max, vblank_default;
+       int size;
+       int ret = 0;
+
+       ctrl_hdlr = &ov01a10->ctrl_handler;
+       ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+       if (ret)
+               return ret;
+
+       ctrl_hdlr->lock = &ov01a10->mutex;
+       cur_mode = ov01a10->cur_mode;
+       size = ARRAY_SIZE(link_freq_menu_items);
+
+       ov01a10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+                                                   &ov01a10_ctrl_ops,
+                                                   V4L2_CID_LINK_FREQ,
+                                                   size - 1, 0,
+                                                   link_freq_menu_items);
+       if (ov01a10->link_freq)
+               ov01a10->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       ov01a10->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+                                               V4L2_CID_PIXEL_RATE, 0,
+                                               OV01A10_SCLK, 1, OV01A10_SCLK);
+
+       vblank_min = cur_mode->vts_min - cur_mode->height;
+       vblank_max = OV01A10_VTS_MAX - cur_mode->height;
+       vblank_default = cur_mode->vts_def - cur_mode->height;
+       ov01a10->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+                                           V4L2_CID_VBLANK, vblank_min,
+                                           vblank_max, 1, vblank_default);
+
+       h_blank = cur_mode->hts - cur_mode->width;
+       ov01a10->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+                                           V4L2_CID_HBLANK, h_blank, h_blank,
+                                           1, h_blank);
+       if (ov01a10->hblank)
+               ov01a10->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+                         OV01A10_ANAL_GAIN_MIN, OV01A10_ANAL_GAIN_MAX,
+                         OV01A10_ANAL_GAIN_STEP, OV01A10_ANAL_GAIN_MIN);
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+                         OV01A10_DGTL_GAIN_MIN, OV01A10_DGTL_GAIN_MAX,
+                         OV01A10_DGTL_GAIN_STEP, OV01A10_DGTL_GAIN_DEFAULT);
+       exposure_max = cur_mode->vts_def - OV01A10_EXPOSURE_MAX_MARGIN;
+       ov01a10->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a10_ctrl_ops,
+                                             V4L2_CID_EXPOSURE,
+                                             OV01A10_EXPOSURE_MIN,
+                                             exposure_max,
+                                             OV01A10_EXPOSURE_STEP,
+                                             exposure_max);
+       v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov01a10_ctrl_ops,
+                                    V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(ov01a10_test_pattern_menu) - 1,
+                                    0, 0, ov01a10_test_pattern_menu);
+       if (ctrl_hdlr->error)
+               return ctrl_hdlr->error;
+
+       ov01a10->sd.ctrl_handler = ctrl_hdlr;
+
+       return 0;
+}
+
+static void ov01a10_update_pad_format(const struct ov01a10_mode *mode,
+                                     struct v4l2_mbus_framefmt *fmt)
+{
+       fmt->width = mode->width;
+       fmt->height = mode->height;
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+static int ov01a10_start_streaming(struct ov01a10 *ov01a10)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       const struct ov01a10_reg_list *reg_list;
+       int link_freq_index;
+       int ret = 0;
+
+       link_freq_index = ov01a10->cur_mode->link_freq_index;
+       reg_list = &link_freq_configs[link_freq_index].reg_list;
+       ret = ov01a10_write_reg_list(ov01a10, reg_list);
+       if (ret) {
+               dev_err(&client->dev, "failed to set plls");
+               return ret;
+       }
+
+       reg_list = &ov01a10->cur_mode->reg_list;
+       ret = ov01a10_write_reg_list(ov01a10, reg_list);
+       if (ret) {
+               dev_err(&client->dev, "failed to set mode");
+               return ret;
+       }
+
+       ret = __v4l2_ctrl_handler_setup(ov01a10->sd.ctrl_handler);
+       if (ret)
+               return ret;
+
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_MODE_SELECT, 1,
+                               OV01A10_MODE_STREAMING);
+       if (ret)
+               dev_err(&client->dev, "failed to start streaming");
+
+       return ret;
+}
+
+static void ov01a10_stop_streaming(struct ov01a10 *ov01a10)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       int ret = 0;
+
+       ret = ov01a10_write_reg(ov01a10, OV01A10_REG_MODE_SELECT, 1,
+                               OV01A10_MODE_STANDBY);
+       if (ret)
+               dev_err(&client->dev, "failed to stop streaming");
+}
+
+static int ov01a10_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (ov01a10->streaming == enable)
+               return 0;
+
+       mutex_lock(&ov01a10->mutex);
+       if (enable) {
+               ret = pm_runtime_get_sync(&client->dev);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(&client->dev);
+                       mutex_unlock(&ov01a10->mutex);
+                       return ret;
+               }
+
+               ret = ov01a10_start_streaming(ov01a10);
+               if (ret) {
+                       enable = 0;
+                       ov01a10_stop_streaming(ov01a10);
+                       pm_runtime_put(&client->dev);
+               }
+       } else {
+               ov01a10_stop_streaming(ov01a10);
+               pm_runtime_put(&client->dev);
+       }
+
+       ov01a10->streaming = enable;
+       mutex_unlock(&ov01a10->mutex);
+
+       return ret;
+}
+
+static int __maybe_unused ov01a10_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+       mutex_lock(&ov01a10->mutex);
+       if (ov01a10->streaming)
+               ov01a10_stop_streaming(ov01a10);
+
+       mutex_unlock(&ov01a10->mutex);
+
+       return 0;
+}
+
+static int __maybe_unused ov01a10_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+       int ret = 0;
+
+       mutex_lock(&ov01a10->mutex);
+       if (!ov01a10->streaming)
+               goto exit;
+
+       ret = ov01a10_start_streaming(ov01a10);
+       if (ret) {
+               ov01a10->streaming = false;
+               ov01a10_stop_streaming(ov01a10);
+       }
+
+exit:
+       mutex_unlock(&ov01a10->mutex);
+       return ret;
+}
+
+static int ov01a10_set_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+       const struct ov01a10_mode *mode;
+       s32 vblank_def, h_blank;
+
+       mode = v4l2_find_nearest_size(supported_modes,
+                                     ARRAY_SIZE(supported_modes), width,
+                                     height, fmt->format.width,
+                                     fmt->format.height);
+
+       mutex_lock(&ov01a10->mutex);
+       ov01a10_update_pad_format(mode, &fmt->format);
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+       } else {
+               ov01a10->cur_mode = mode;
+               __v4l2_ctrl_s_ctrl(ov01a10->link_freq, mode->link_freq_index);
+               __v4l2_ctrl_s_ctrl_int64(ov01a10->pixel_rate, OV01A10_SCLK);
+
+               /* Update limits and set FPS to default */
+               vblank_def = mode->vts_def - mode->height;
+               __v4l2_ctrl_modify_range(ov01a10->vblank,
+                                        mode->vts_min - mode->height,
+                                        OV01A10_VTS_MAX - mode->height, 1,
+                                        vblank_def);
+               __v4l2_ctrl_s_ctrl(ov01a10->vblank, vblank_def);
+               h_blank = mode->hts - mode->width;
+               __v4l2_ctrl_modify_range(ov01a10->hblank, h_blank, h_blank, 1,
+                                        h_blank);
+       }
+       mutex_unlock(&ov01a10->mutex);
+
+       return 0;
+}
+
+static int ov01a10_get_format(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_state *sd_state,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+       mutex_lock(&ov01a10->mutex);
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+               fmt->format = *v4l2_subdev_get_try_format(&ov01a10->sd,
+                                                         sd_state, fmt->pad);
+       else
+               ov01a10_update_pad_format(ov01a10->cur_mode, &fmt->format);
+
+       mutex_unlock(&ov01a10->mutex);
+
+       return 0;
+}
+
+static int ov01a10_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_state *sd_state,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index > 0)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+       return 0;
+}
+
+static int ov01a10_enum_frame_size(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_state *sd_state,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+       if (fse->index >= ARRAY_SIZE(supported_modes))
+               return -EINVAL;
+
+       if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
+               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 ov01a10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+       mutex_lock(&ov01a10->mutex);
+       ov01a10_update_pad_format(&supported_modes[0],
+                                 v4l2_subdev_get_try_format(sd, fh->state, 0));
+       mutex_unlock(&ov01a10->mutex);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov01a10_video_ops = {
+       .s_stream = ov01a10_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov01a10_pad_ops = {
+       .set_fmt = ov01a10_set_format,
+       .get_fmt = ov01a10_get_format,
+       .enum_mbus_code = ov01a10_enum_mbus_code,
+       .enum_frame_size = ov01a10_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops ov01a10_subdev_ops = {
+       .video = &ov01a10_video_ops,
+       .pad = &ov01a10_pad_ops,
+};
+
+static const struct media_entity_operations ov01a10_subdev_entity_ops = {
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops ov01a10_internal_ops = {
+       .open = ov01a10_open,
+};
+
+static int ov01a10_identify_module(struct ov01a10 *ov01a10)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&ov01a10->sd);
+       int ret;
+       u32 val;
+
+       ret = ov01a10_read_reg(ov01a10, OV01A10_REG_CHIP_ID, 3, &val);
+       if (ret)
+               return ret;
+
+       if (val != OV01A10_CHIP_ID) {
+               dev_err(&client->dev, "chip id mismatch: %x!=%x",
+                       OV01A10_CHIP_ID, val);
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int ov01a10_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov01a10 *ov01a10 = to_ov01a10(sd);
+
+       v4l2_async_unregister_subdev(sd);
+       media_entity_cleanup(&sd->entity);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
+       pm_runtime_disable(&client->dev);
+       mutex_destroy(&ov01a10->mutex);
+
+       return 0;
+}
+
+static int ov01a10_probe(struct i2c_client *client)
+{
+       struct ov01a10 *ov01a10;
+       int ret = 0;
+       struct vsc_mipi_config conf;
+       struct vsc_camera_status status;
+       s64 link_freq;
+
+       conf.lane_num = OV01A10_DATA_LANES;
+       /* frequency unit 100k */
+       conf.freq = OV01A10_LINK_FREQ_400MHZ / 100000;
+       ret = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+       if (ret == -EAGAIN)
+               return -EPROBE_DEFER;
+       else if (ret) {
+               dev_err(&client->dev, "Acquire VSC failed.\n");
+               return ret;
+       }
+       ov01a10 = devm_kzalloc(&client->dev, sizeof(*ov01a10), GFP_KERNEL);
+       if (!ov01a10) {
+               ret = -ENOMEM;
+               goto probe_error_ret;
+       }
+
+       v4l2_i2c_subdev_init(&ov01a10->sd, client, &ov01a10_subdev_ops);
+
+       ret = ov01a10_identify_module(ov01a10);
+       if (ret) {
+               dev_err(&client->dev, "failed to find sensor: %d", ret);
+               goto probe_error_ret;
+       }
+
+       mutex_init(&ov01a10->mutex);
+       ov01a10->cur_mode = &supported_modes[0];
+       ret = ov01a10_init_controls(ov01a10);
+       if (ret) {
+               dev_err(&client->dev, "failed to init controls: %d", ret);
+               goto probe_error_v4l2_ctrl_handler_free;
+       }
+
+       ov01a10->sd.internal_ops = &ov01a10_internal_ops;
+       ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       ov01a10->sd.entity.ops = &ov01a10_subdev_entity_ops;
+       ov01a10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       ov01a10->pad.flags = MEDIA_PAD_FL_SOURCE;
+       ret = media_entity_pads_init(&ov01a10->sd.entity, 1, &ov01a10->pad);
+       if (ret) {
+               dev_err(&client->dev, "failed to init entity pads: %d", ret);
+               goto probe_error_v4l2_ctrl_handler_free;
+       }
+
+       ret = v4l2_async_register_subdev_sensor(&ov01a10->sd);
+       if (ret < 0) {
+               dev_err(&client->dev, "failed to register V4L2 subdev: %d",
+                       ret);
+               goto probe_error_media_entity_cleanup;
+       }
+
+       vsc_release_camera_sensor(&status);
+       /*
+        * Device is already turned on by i2c-core with ACPI domain PM.
+        * Enable runtime PM and turn off the device.
+        */
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_enable(&client->dev);
+       pm_runtime_idle(&client->dev);
+
+       return 0;
+
+probe_error_media_entity_cleanup:
+       media_entity_cleanup(&ov01a10->sd.entity);
+
+probe_error_v4l2_ctrl_handler_free:
+       v4l2_ctrl_handler_free(ov01a10->sd.ctrl_handler);
+       mutex_destroy(&ov01a10->mutex);
+
+probe_error_ret:
+       vsc_release_camera_sensor(&status);
+       return ret;
+}
+
+static const struct dev_pm_ops ov01a10_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(ov01a10_suspend, ov01a10_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id ov01a10_acpi_ids[] = {
+       {"OVTI01A0"},
+       {}
+};
+
+MODULE_DEVICE_TABLE(acpi, ov01a10_acpi_ids);
+#endif
+
+static struct i2c_driver ov01a10_i2c_driver = {
+       .driver = {
+               .name = "ov01a10",
+               .pm = &ov01a10_pm_ops,
+               .acpi_match_table = ACPI_PTR(ov01a10_acpi_ids),
+       },
+       .probe_new = ov01a10_probe,
+       .remove = ov01a10_remove,
+};
+
+module_i2c_driver(ov01a10_i2c_driver);
+
+MODULE_AUTHOR("Wang Yating <yating.wang@intel.com>");
+MODULE_DESCRIPTION("OmniVision OV01A10 sensor driver");
+MODULE_LICENSE("GPL v2");
index dd299204d9e9e5f94cadc0abeeb6b539b0f75177..2bda3122ff47c31b66a0cded242381c7bbe34010 100644 (file)
@@ -7,10 +7,12 @@
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
+#include <linux/version.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fwnode.h>
 #include "power_ctrl_logic.h"
+#include <linux/vsc.h>
 
 #define OV01A1S_LINK_FREQ_400MHZ       400000000ULL
 #define OV01A1S_SCLK                   40000000LL
@@ -677,7 +679,7 @@ exit:
 }
 
 static int ov01a1s_set_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct ov01a1s *ov01a1s = to_ov01a1s(sd);
@@ -692,7 +694,7 @@ static int ov01a1s_set_format(struct v4l2_subdev *sd,
        mutex_lock(&ov01a1s->mutex);
        ov01a1s_update_pad_format(mode, &fmt->format);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
-               *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+               *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
        } else {
                ov01a1s->cur_mode = mode;
                __v4l2_ctrl_s_ctrl(ov01a1s->link_freq, mode->link_freq_index);
@@ -715,15 +717,15 @@ static int ov01a1s_set_format(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_get_format(struct v4l2_subdev *sd,
-                             struct v4l2_subdev_pad_config *cfg,
+                             struct v4l2_subdev_state *sd_state,
                              struct v4l2_subdev_format *fmt)
 {
        struct ov01a1s *ov01a1s = to_ov01a1s(sd);
 
        mutex_lock(&ov01a1s->mutex);
        if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
-               fmt->format = *v4l2_subdev_get_try_format(&ov01a1s->sd, cfg,
-                                                         fmt->pad);
+               fmt->format = *v4l2_subdev_get_try_format(&ov01a1s->sd,
+                                                         sd_state, fmt->pad);
        else
                ov01a1s_update_pad_format(ov01a1s->cur_mode, &fmt->format);
 
@@ -733,7 +735,7 @@ static int ov01a1s_get_format(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_subdev_mbus_code_enum *code)
 {
        if (code->index > 0)
@@ -745,7 +747,7 @@ static int ov01a1s_enum_mbus_code(struct v4l2_subdev *sd,
 }
 
 static int ov01a1s_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
        if (fse->index >= ARRAY_SIZE(supported_modes))
@@ -768,7 +770,7 @@ static int ov01a1s_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        mutex_lock(&ov01a1s->mutex);
        ov01a1s_update_pad_format(&supported_modes[0],
-                                 v4l2_subdev_get_try_format(sd, fh->pad, 0));
+                                 v4l2_subdev_get_try_format(sd, fh->state, 0));
        mutex_unlock(&ov01a1s->mutex);
 
        return 0;
@@ -835,11 +837,20 @@ static int ov01a1s_probe(struct i2c_client *client)
 {
        struct ov01a1s *ov01a1s;
        int ret = 0;
-
-       if (power_ctrl_logic_set_power(1)) {
-               dev_dbg(&client->dev, "power control driver not ready.\n");
+       struct vsc_mipi_config conf;
+       struct vsc_camera_status status;
+       s64 link_freq;
+
+       conf.lane_num = OV01A1S_DATA_LANES;
+       /* frequency unit 100k */
+       conf.freq = OV01A1S_LINK_FREQ_400MHZ / 100000;
+       ret = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+       if (ret == -EAGAIN)
+               ret = power_ctrl_logic_set_power(1);
+       if (ret == -EAGAIN)
                return -EPROBE_DEFER;
-       }
+       else if (ret)
+               return ret;
        ov01a1s = devm_kzalloc(&client->dev, sizeof(*ov01a1s), GFP_KERNEL);
        if (!ov01a1s) {
                ret = -ENOMEM;
@@ -879,6 +890,7 @@ static int ov01a1s_probe(struct i2c_client *client)
                goto probe_error_media_entity_cleanup;
        }
 
+       vsc_release_camera_sensor(&status);
        /*
         * Device is already turned on by i2c-core with ACPI domain PM.
         * Enable runtime PM and turn off the device.
@@ -899,6 +911,7 @@ probe_error_v4l2_ctrl_handler_free:
 
 probe_error_ret:
        power_ctrl_logic_set_power(0);
+       vsc_release_camera_sensor(&status);
        return ret;
 }
 
index 1ccd94f9e97e3594ea61312a5cbc3619e5ac36d8..90ee1e23d6ea24f2b461cf1a69e92c63cee22b54 100644 (file)
@@ -126,7 +126,7 @@ int power_ctrl_logic_set_power(int on)
                pr_debug("@%s,failed to set power, gpio_ready=%d, on=%d\n",
                         __func__, pcl.gpio_ready, on);
                mutex_unlock(&pcl.status_lock);
-               return -EPROBE_DEFER;
+               return -EAGAIN;
        }
        if (pcl.power_on != on) {
                gpiod_set_value_cansleep(pcl.reset_gpio, on);
index defdca369fb5c73b064ff1e4f0b835e2336c103d..ee4a77acb66f3299a4d78cdfaf7334856b09f3cf 100644 (file)
@@ -3,10 +3,9 @@ config VIDEO_INTEL_IPU6
        depends on ACPI
        depends on MEDIA_SUPPORT
        depends on MEDIA_PCI_SUPPORT
-       depends on X86_64
        select IOMMU_API
        select IOMMU_IOVA
-       select X86_DEV_DMA_OPS
+       select X86_DEV_DMA_OPS if X86
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_FWNODE
        select PHYS_ADDR_T_64BIT
index eac4a43ed7b19a4e6d8cfa0f128819cca5d4c1f7..bf0b7916b381a7258f0af8ddb7e36c83d33bdf8b 100644 (file)
@@ -893,7 +893,6 @@ iunit_power_off:
 
        return rval;
 }
-EXPORT_SYMBOL(ipu_buttress_authenticate);
 
 static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
 {
@@ -963,50 +962,25 @@ struct clk_ipu_sensor {
 
 int ipu_buttress_tsc_read(struct ipu_device *isp, u64 *val)
 {
-       struct ipu_buttress *b = &isp->buttress;
-       u32 tsc_hi, tsc_lo_1, tsc_lo_2, tsc_lo_3, tsc_chk = 0;
+       u32 tsc_hi_1, tsc_hi_2, tsc_lo;
        unsigned long flags;
-       short retry = IPU_BUTTRESS_TSC_RETRY;
-
-       do {
-               spin_lock_irqsave(&b->tsc_lock, flags);
-               tsc_hi = readl(isp->base + BUTTRESS_REG_TSC_HI);
-
-               /*
-                * We are occasionally getting broken values from
-                * HH. Reading 3 times and doing sanity check as a WA
-                */
-               tsc_lo_1 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-               tsc_lo_2 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-               tsc_lo_3 = readl(isp->base + BUTTRESS_REG_TSC_LO);
-               tsc_chk = readl(isp->base + BUTTRESS_REG_TSC_HI);
-               spin_unlock_irqrestore(&b->tsc_lock, flags);
-               if (tsc_chk == tsc_hi && tsc_lo_2 &&
-                   tsc_lo_2 - tsc_lo_1 <= IPU_BUTTRESS_TSC_LIMIT &&
-                   tsc_lo_3 - tsc_lo_2 <= IPU_BUTTRESS_TSC_LIMIT) {
-                       *val = (u64)tsc_hi << 32 | tsc_lo_2;
-                       return 0;
-               }
 
-               /*
-                * Trace error only if limit checkings fails at least
-                *  by two consecutive readings.
-                */
-               if (retry < IPU_BUTTRESS_TSC_RETRY - 1 && tsc_lo_2)
-                       dev_err(&isp->pdev->dev,
-                               "%s = %u, %s = %u, %s = %u, %s = %u, %s = %u",
-                               "failure: tsc_hi", tsc_hi,
-                               "tsc_chk", tsc_chk,
-                               "tsc_lo_1", tsc_lo_1,
-                               "tsc_lo_2", tsc_lo_2, "tsc_lo_3", tsc_lo_3);
-       } while (retry--);
-
-       if (!tsc_chk && !tsc_lo_2)
-               return -EIO;
-
-       WARN_ON_ONCE(1);
+       local_irq_save(flags);
+       tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+       tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO);
+       tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+       if (tsc_hi_1 == tsc_hi_2) {
+               *val = (u64)tsc_hi_1 << 32 | tsc_lo;
+       } else {
+               /* Check if TSC has rolled over */
+               if (tsc_lo & BIT(31))
+                       *val = (u64)tsc_hi_1 << 32 | tsc_lo;
+               else
+                       *val = (u64)tsc_hi_2 << 32 | tsc_lo;
+       }
+       local_irq_restore(flags);
 
-       return -EINVAL;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(ipu_buttress_tsc_read);
 
@@ -1299,7 +1273,6 @@ int ipu_buttress_init(struct ipu_device *isp)
        mutex_init(&b->auth_mutex);
        mutex_init(&b->cons_mutex);
        mutex_init(&b->ipc_mutex);
-       spin_lock_init(&b->tsc_lock);
        init_completion(&b->ish.send_complete);
        init_completion(&b->cse.send_complete);
        init_completion(&b->ish.recv_complete);
index e1d054c3cd07505d34ad681e6aa24429bc5f591f..b57f4aaffa57136b0eb8df63fc419242f4e502c7 100644 (file)
@@ -58,7 +58,6 @@ struct ipu_buttress_ipc {
 
 struct ipu_buttress {
        struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
-       spinlock_t tsc_lock;    /* tsc lock */
        struct ipu_buttress_ipc cse;
        struct ipu_buttress_ipc ish;
        struct list_head constraints;
index daaed97d1b137f5c8c0e6864e9736b9f7d51c806..7072500d930a949abf814b1924e4fa445c0b9417 100644 (file)
@@ -116,7 +116,7 @@ __subdev_link_validate(struct v4l2_subdev *sd, struct media_link *link,
 
 static int
 ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_selection *sel)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -128,7 +128,7 @@ ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
                enum isys_subdev_prop_tgt tgt =
                    IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP;
                struct v4l2_mbus_framefmt *ffmt =
-                       __ipu_isys_get_ffmt(sd, cfg, sel->pad, sel->which);
+                       __ipu_isys_get_ffmt(sd, sd_state, sel->pad, sel->which);
 
                if (get_supported_code_index(ffmt->code) < 0) {
                        /* Non-bayer formats can't be odd lines cropped */
@@ -142,9 +142,9 @@ ipu_isys_csi2_be_soc_set_sel(struct v4l2_subdev *sd,
                sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT,
                                      IPU_ISYS_MAX_HEIGHT);
 
-               *__ipu_isys_get_selection(sd, cfg, sel->target, sel->pad,
+               *__ipu_isys_get_selection(sd, sd_state, sel->target, sel->pad,
                                          sel->which) = sel->r;
-               ipu_isys_subdev_fmt_propagate(sd, cfg, NULL, &sel->r,
+               ipu_isys_subdev_fmt_propagate(sd, sd_state, NULL, &sel->r,
                                              tgt, sel->pad, sel->which);
                return 0;
        }
@@ -171,11 +171,11 @@ static struct media_entity_operations csi2_be_soc_entity_ops = {
 };
 
 static void csi2_be_soc_set_ffmt(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *ffmt =
-               __ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+               __ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
                                    fmt->which);
 
        if (sd->entity.pads[fmt->pad].flags & MEDIA_PAD_FL_SINK) {
@@ -183,19 +183,19 @@ static void csi2_be_soc_set_ffmt(struct v4l2_subdev *sd,
                        fmt->format.field = V4L2_FIELD_NONE;
                *ffmt = fmt->format;
 
-               ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format,
+               ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format,
                                              NULL,
                                              IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT,
                                              fmt->pad, fmt->which);
        } else if (sd->entity.pads[fmt->pad].flags & MEDIA_PAD_FL_SOURCE) {
                struct v4l2_mbus_framefmt *sink_ffmt;
-               struct v4l2_rect *r = __ipu_isys_get_selection(sd, cfg,
+               struct v4l2_rect *r = __ipu_isys_get_selection(sd, sd_state,
                        V4L2_SEL_TGT_CROP, fmt->pad, fmt->which);
                struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
                u32 code;
                int idx;
 
-               sink_ffmt = __ipu_isys_get_ffmt(sd, cfg, 0, fmt->which);
+               sink_ffmt = __ipu_isys_get_ffmt(sd, sd_state, 0, fmt->which);
                code = sink_ffmt->code;
                idx = get_supported_code_index(code);
 
diff --git a/drivers/media/pci/intel/ipu-isys-csi2-be.c b/drivers/media/pci/intel/ipu-isys-csi2-be.c
new file mode 100644 (file)
index 0000000..1ef87fe
--- /dev/null
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2014 - 2020 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/ipu-isys.h>
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+
+#include "ipu.h"
+#include "ipu-bus.h"
+#include "ipu-isys.h"
+#include "ipu-isys-csi2-be.h"
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-video.h"
+
+/*
+ * Raw bayer format pixel order MUST BE MAINTAINED in groups of four codes.
+ * Otherwise pixel order calculation below WILL BREAK!
+ */
+static const u32 csi2_be_supported_codes_pad[] = {
+       MEDIA_BUS_FMT_SBGGR12_1X12,
+       MEDIA_BUS_FMT_SGBRG12_1X12,
+       MEDIA_BUS_FMT_SGRBG12_1X12,
+       MEDIA_BUS_FMT_SRGGB12_1X12,
+       MEDIA_BUS_FMT_SBGGR10_1X10,
+       MEDIA_BUS_FMT_SGBRG10_1X10,
+       MEDIA_BUS_FMT_SGRBG10_1X10,
+       MEDIA_BUS_FMT_SRGGB10_1X10,
+       MEDIA_BUS_FMT_SBGGR8_1X8,
+       MEDIA_BUS_FMT_SGBRG8_1X8,
+       MEDIA_BUS_FMT_SGRBG8_1X8,
+       MEDIA_BUS_FMT_SRGGB8_1X8,
+       0,
+};
+
+static const u32 *csi2_be_supported_codes[] = {
+       csi2_be_supported_codes_pad,
+       csi2_be_supported_codes_pad,
+};
+
+static struct v4l2_subdev_internal_ops csi2_be_sd_internal_ops = {
+       .open = ipu_isys_subdev_open,
+       .close = ipu_isys_subdev_close,
+};
+
+static const struct v4l2_subdev_core_ops csi2_be_sd_core_ops = {
+};
+
+static const struct v4l2_ctrl_config compression_ctrl_cfg = {
+       .ops = NULL,
+       .id = V4L2_CID_IPU_ISYS_COMPRESSION,
+       .name = "ISYS CSI-BE compression",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 0,
+};
+
+static int set_stream(struct v4l2_subdev *sd, int enable)
+{
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops csi2_be_sd_video_ops = {
+       .s_stream = set_stream,
+};
+
+static int __subdev_link_validate(struct v4l2_subdev *sd,
+                                 struct media_link *link,
+                                 struct v4l2_subdev_format *source_fmt,
+                                 struct v4l2_subdev_format *sink_fmt)
+{
+       struct ipu_isys_pipeline *ip = container_of(sd->entity.pipe,
+                                                   struct ipu_isys_pipeline,
+                                                   pipe);
+
+       ip->csi2_be = to_ipu_isys_csi2_be(sd);
+       return ipu_isys_subdev_link_validate(sd, link, source_fmt, sink_fmt);
+}
+
+static int get_supported_code_index(u32 code)
+{
+       int i;
+
+       for (i = 0; csi2_be_supported_codes_pad[i]; i++) {
+               if (csi2_be_supported_codes_pad[i] == code)
+                       return i;
+       }
+       return -EINVAL;
+}
+
+static int ipu_isys_csi2_be_set_sel(struct v4l2_subdev *sd,
+                                   struct v4l2_subdev_state *sd_state,
+                                   struct v4l2_subdev_selection *sel)
+{
+       struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
+       struct media_pad *pad = &asd->sd.entity.pads[sel->pad];
+
+       if (sel->target == V4L2_SEL_TGT_CROP &&
+           pad->flags & MEDIA_PAD_FL_SOURCE &&
+           asd->valid_tgts[CSI2_BE_PAD_SOURCE].crop) {
+               struct v4l2_mbus_framefmt *ffmt =
+                       __ipu_isys_get_ffmt(sd, sd_state, sel->pad, sel->which);
+               struct v4l2_rect *r = __ipu_isys_get_selection
+                   (sd, sd_state, sel->target, CSI2_BE_PAD_SINK, sel->which);
+
+               if (get_supported_code_index(ffmt->code) < 0) {
+                       /* Non-bayer formats can't be single line cropped */
+                       sel->r.left &= ~1;
+                       sel->r.top &= ~1;
+
+                       /* Non-bayer formats can't pe padded at all */
+                       sel->r.width = clamp(sel->r.width,
+                                            IPU_ISYS_MIN_WIDTH, r->width);
+               } else {
+                       sel->r.width = clamp(sel->r.width,
+                                            IPU_ISYS_MIN_WIDTH,
+                                            IPU_ISYS_MAX_WIDTH);
+               }
+
+               /*
+                * Vertical padding is not supported, height is
+                * restricted by sink pad resolution.
+                */
+               sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT,
+                                     r->height);
+               *__ipu_isys_get_selection(sd, sd_state, sel->target,
+                                       sel->pad, sel->which) = sel->r;
+               ipu_isys_subdev_fmt_propagate
+                   (sd, sd_state, NULL, &sel->r,
+                    IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP,
+                    sel->pad, sel->which);
+               return 0;
+       }
+       return ipu_isys_subdev_set_sel(sd, sd_state, sel);
+}
+
+static const struct v4l2_subdev_pad_ops csi2_be_sd_pad_ops = {
+       .link_validate = __subdev_link_validate,
+       .get_fmt = ipu_isys_subdev_get_ffmt,
+       .set_fmt = ipu_isys_subdev_set_ffmt,
+       .get_selection = ipu_isys_subdev_get_sel,
+       .set_selection = ipu_isys_csi2_be_set_sel,
+       .enum_mbus_code = ipu_isys_subdev_enum_mbus_code,
+};
+
+static struct v4l2_subdev_ops csi2_be_sd_ops = {
+       .core = &csi2_be_sd_core_ops,
+       .video = &csi2_be_sd_video_ops,
+       .pad = &csi2_be_sd_pad_ops,
+};
+
+static struct media_entity_operations csi2_be_entity_ops = {
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+static void csi2_be_set_ffmt(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_state *sd_state,
+                            struct v4l2_subdev_format *fmt)
+{
+       struct ipu_isys_csi2 *csi2 = to_ipu_isys_csi2(sd);
+       struct v4l2_mbus_framefmt *ffmt =
+               __ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
+
+       switch (fmt->pad) {
+       case CSI2_BE_PAD_SINK:
+               if (fmt->format.field != V4L2_FIELD_ALTERNATE)
+                       fmt->format.field = V4L2_FIELD_NONE;
+               *ffmt = fmt->format;
+
+               ipu_isys_subdev_fmt_propagate
+                   (sd, sd_state, &fmt->format, NULL,
+                    IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT, fmt->pad, fmt->which);
+               return;
+       case CSI2_BE_PAD_SOURCE: {
+               struct v4l2_mbus_framefmt *sink_ffmt =
+                       __ipu_isys_get_ffmt(sd, sd_state, CSI2_BE_PAD_SINK,
+                                           fmt->which);
+               struct v4l2_rect *r =
+                       __ipu_isys_get_selection(sd, sd_state, V4L2_SEL_TGT_CROP,
+                                                CSI2_BE_PAD_SOURCE,
+                                                fmt->which);
+               struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
+               u32 code = sink_ffmt->code;
+               int idx = get_supported_code_index(code);
+
+               if (asd->valid_tgts[CSI2_BE_PAD_SOURCE].crop && idx >= 0) {
+                       int crop_info = 0;
+
+                       if (r->top & 1)
+                               crop_info |= CSI2_BE_CROP_VER;
+                       if (r->left & 1)
+                               crop_info |= CSI2_BE_CROP_HOR;
+                       code = csi2_be_supported_codes_pad
+                               [((idx & CSI2_BE_CROP_MASK) ^ crop_info)
+                               + (idx & ~CSI2_BE_CROP_MASK)];
+               }
+               ffmt->width = r->width;
+               ffmt->height = r->height;
+               ffmt->code = code;
+               ffmt->field = sink_ffmt->field;
+               return;
+       }
+       default:
+               dev_err(&csi2->isys->adev->dev, "Unknown pad type\n");
+               WARN_ON(1);
+       }
+}
+
+void ipu_isys_csi2_be_cleanup(struct ipu_isys_csi2_be *csi2_be)
+{
+       v4l2_ctrl_handler_free(&csi2_be->av.ctrl_handler);
+       v4l2_device_unregister_subdev(&csi2_be->asd.sd);
+       ipu_isys_subdev_cleanup(&csi2_be->asd);
+       ipu_isys_video_cleanup(&csi2_be->av);
+}
+
+int ipu_isys_csi2_be_init(struct ipu_isys_csi2_be *csi2_be,
+                         struct ipu_isys *isys)
+{
+       struct v4l2_subdev_format fmt = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .pad = CSI2_BE_PAD_SINK,
+               .format = {
+                          .width = 4096,
+                          .height = 3072,
+                         },
+       };
+       struct v4l2_subdev_selection sel = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .pad = CSI2_BE_PAD_SOURCE,
+               .target = V4L2_SEL_TGT_CROP,
+               .r = {
+                     .width = fmt.format.width,
+                     .height = fmt.format.height,
+                    },
+       };
+       int rval;
+
+       csi2_be->asd.sd.entity.ops = &csi2_be_entity_ops;
+       csi2_be->asd.isys = isys;
+
+       rval = ipu_isys_subdev_init(&csi2_be->asd, &csi2_be_sd_ops, 0,
+                                   NR_OF_CSI2_BE_PADS,
+                                   NR_OF_CSI2_BE_SOURCE_PADS,
+                                   NR_OF_CSI2_BE_SINK_PADS, 0);
+       if (rval)
+               goto fail;
+
+       csi2_be->asd.pad[CSI2_BE_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+           | MEDIA_PAD_FL_MUST_CONNECT;
+       csi2_be->asd.pad[CSI2_BE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+       csi2_be->asd.valid_tgts[CSI2_BE_PAD_SOURCE].crop = true;
+       csi2_be->asd.set_ffmt = csi2_be_set_ffmt;
+
+       BUILD_BUG_ON(ARRAY_SIZE(csi2_be_supported_codes) != NR_OF_CSI2_BE_PADS);
+       csi2_be->asd.supported_codes = csi2_be_supported_codes;
+       csi2_be->asd.be_mode = IPU_BE_RAW;
+       csi2_be->asd.isl_mode = IPU_ISL_CSI2_BE;
+
+       ipu_isys_subdev_set_ffmt(&csi2_be->asd.sd, NULL, &fmt);
+       ipu_isys_csi2_be_set_sel(&csi2_be->asd.sd, NULL, &sel);
+
+       csi2_be->asd.sd.internal_ops = &csi2_be_sd_internal_ops;
+       snprintf(csi2_be->asd.sd.name, sizeof(csi2_be->asd.sd.name),
+                IPU_ISYS_ENTITY_PREFIX " CSI2 BE");
+       snprintf(csi2_be->av.vdev.name, sizeof(csi2_be->av.vdev.name),
+                IPU_ISYS_ENTITY_PREFIX " CSI2 BE capture");
+       csi2_be->av.aq.css_pin_type = IPU_FW_ISYS_PIN_TYPE_RAW_NS;
+       v4l2_set_subdevdata(&csi2_be->asd.sd, &csi2_be->asd);
+       rval = v4l2_device_register_subdev(&isys->v4l2_dev, &csi2_be->asd.sd);
+       if (rval) {
+               dev_info(&isys->adev->dev, "can't register v4l2 subdev\n");
+               goto fail;
+       }
+
+       csi2_be->av.isys = isys;
+       csi2_be->av.pfmts = ipu_isys_pfmts;
+       csi2_be->av.try_fmt_vid_mplane =
+           ipu_isys_video_try_fmt_vid_mplane_default;
+       csi2_be->av.prepare_fw_stream =
+           ipu_isys_prepare_fw_cfg_default;
+       csi2_be->av.aq.buf_prepare = ipu_isys_buf_prepare;
+       csi2_be->av.aq.fill_frame_buff_set_pin =
+           ipu_isys_buffer_to_fw_frame_buff_pin;
+       csi2_be->av.aq.link_fmt_validate = ipu_isys_link_fmt_validate;
+       csi2_be->av.aq.vbq.buf_struct_size =
+           sizeof(struct ipu_isys_video_buffer);
+
+       /* create v4l2 ctrl for csi-be video node */
+       rval = v4l2_ctrl_handler_init(&csi2_be->av.ctrl_handler, 0);
+       if (rval) {
+               dev_err(&isys->adev->dev,
+                       "failed to init v4l2 ctrl handler for csi2_be\n");
+               goto fail;
+       }
+
+       csi2_be->av.compression_ctrl =
+               v4l2_ctrl_new_custom(&csi2_be->av.ctrl_handler,
+                                    &compression_ctrl_cfg, NULL);
+       if (!csi2_be->av.compression_ctrl) {
+               dev_err(&isys->adev->dev,
+                       "failed to create CSI-BE cmprs ctrl\n");
+               goto fail;
+       }
+       csi2_be->av.compression = 0;
+       csi2_be->av.vdev.ctrl_handler = &csi2_be->av.ctrl_handler;
+
+       rval = ipu_isys_video_init(&csi2_be->av, &csi2_be->asd.sd.entity,
+                                  CSI2_BE_PAD_SOURCE, MEDIA_PAD_FL_SINK, 0);
+       if (rval) {
+               dev_info(&isys->adev->dev, "can't init video node\n");
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       ipu_isys_csi2_be_cleanup(csi2_be);
+
+       return rval;
+}
index 1242a79718b1e0280193748a772cbbe2a2cb9be1..e206200b6f4d96366e5b7db169afc949da719e2d 100644 (file)
@@ -1,9 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0
-// Copyright (C) 2013 - 2020 Intel Corporation
+// Copyright (C) 2013 - 2021 Intel Corporation
 
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/version.h>
+#include <linux/vsc.h>
 
 #include <media/ipu-isys.h>
 #include <media/media-entity.h>
@@ -224,6 +225,9 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
        struct ipu_isys_csi2_timing timing = {0};
        unsigned int nlanes;
        int rval;
+       struct vsc_mipi_config conf;
+       struct vsc_camera_status status;
+       s64 link_freq;
 
        dev_dbg(&csi2->isys->adev->dev, "csi2 s_stream %d\n", enable);
 
@@ -236,6 +240,12 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
 
        if (!enable) {
                ipu_isys_csi2_set_stream(sd, timing, 0, enable);
+               rval = vsc_release_camera_sensor(&status);
+               if (rval && rval != -EAGAIN) {
+                       dev_err(&csi2->isys->adev->dev,
+                               "Release VSC failed.\n");
+                       return rval;
+               }
                return 0;
        }
 
@@ -250,6 +260,20 @@ static int set_stream(struct v4l2_subdev *sd, int enable)
                return rval;
 
        rval = ipu_isys_csi2_set_stream(sd, timing, nlanes, enable);
+       rval = ipu_isys_csi2_get_link_freq(csi2, &link_freq);
+       if (rval)
+               return rval;
+
+       conf.lane_num = nlanes;
+       /* frequency unit 100k */
+       conf.freq = link_freq / 100000;
+       rval = vsc_acquire_camera_sensor(&conf, NULL, NULL, &status);
+       if (rval && rval != -EAGAIN) {
+               dev_err(&csi2->isys->adev->dev, "Acquire VSC failed.\n");
+               return rval;
+       } else {
+               return 0;
+       }
 
        return rval;
 }
@@ -314,17 +338,17 @@ static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
 };
 
 static int ipu_isys_csi2_get_fmt(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
-       return ipu_isys_subdev_get_ffmt(sd, cfg, fmt);
+       return ipu_isys_subdev_get_ffmt(sd, sd_state, fmt);
 }
 
 static int ipu_isys_csi2_set_fmt(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_state *sd_state,
                                 struct v4l2_subdev_format *fmt)
 {
-       return ipu_isys_subdev_set_ffmt(sd, cfg, fmt);
+       return ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
 }
 
 static int __subdev_link_validate(struct v4l2_subdev *sd,
@@ -360,12 +384,12 @@ static struct media_entity_operations csi2_entity_ops = {
 };
 
 static void csi2_set_ffmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_state *sd_state,
                          struct v4l2_subdev_format *fmt)
 {
        enum isys_subdev_prop_tgt tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT;
        struct v4l2_mbus_framefmt *ffmt =
-               __ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+               __ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
                                    fmt->which);
 
        if (fmt->format.field != V4L2_FIELD_ALTERNATE)
@@ -373,7 +397,7 @@ static void csi2_set_ffmt(struct v4l2_subdev *sd,
 
        if (fmt->pad == CSI2_PAD_SINK) {
                *ffmt = fmt->format;
-               ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format, NULL,
+               ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format, NULL,
                                              tgt, fmt->pad, fmt->which);
                return;
        }
index 71a5fa592d4469891a1e315b18eb44220906609c..7f00fa817252430f8734976a8e076c4195c70945 100644 (file)
@@ -134,8 +134,7 @@ u32 ipu_isys_subdev_code_to_uncompressed(u32 sink_code)
 }
 
 struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
-                                              struct v4l2_subdev_pad_config
-                                              *cfg,
+                                              struct v4l2_subdev_state *sd_state,
                                               unsigned int pad,
                                               unsigned int which)
 {
@@ -144,11 +143,11 @@ struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
        if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
                return &asd->ffmt[pad];
        else
-               return v4l2_subdev_get_try_format(sd, cfg, pad);
+               return v4l2_subdev_get_try_format(sd, sd_state, pad);
 }
 
 struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
-                                          struct v4l2_subdev_pad_config *cfg,
+                                          struct v4l2_subdev_state *sd_state,
                                           unsigned int target,
                                           unsigned int pad, unsigned int which)
 {
@@ -164,9 +163,9 @@ struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
        } else {
                switch (target) {
                case V4L2_SEL_TGT_CROP:
-                       return v4l2_subdev_get_try_crop(sd, cfg, pad);
+                       return v4l2_subdev_get_try_crop(sd, sd_state, pad);
                case V4L2_SEL_TGT_COMPOSE:
-                       return v4l2_subdev_get_try_compose(sd, cfg, pad);
+                       return v4l2_subdev_get_try_compose(sd, sd_state, pad);
                }
        }
        WARN_ON(1);
@@ -189,7 +188,7 @@ static int target_valid(struct v4l2_subdev *sd, unsigned int target,
 }
 
 int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_mbus_framefmt *ffmt,
                                  struct v4l2_rect *r,
                                  enum isys_subdev_prop_tgt tgt,
@@ -228,12 +227,11 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
        }
 
        for (i = 0; i < sd->entity.num_pads; i++) {
-               ffmts[i] = __ipu_isys_get_ffmt(sd, cfg, i, which);
-               crops[i] = __ipu_isys_get_selection(sd, cfg, V4L2_SEL_TGT_CROP,
-                                                   i, which);
-               compose[i] = __ipu_isys_get_selection(sd, cfg,
-                                                     V4L2_SEL_TGT_COMPOSE,
-                                                     i, which);
+               ffmts[i] = __ipu_isys_get_ffmt(sd, sd_state, i, which);
+               crops[i] = __ipu_isys_get_selection(sd, sd_state,
+                                                   V4L2_SEL_TGT_CROP, i, which);
+               compose[i] = __ipu_isys_get_selection(sd, sd_state,
+                                                     V4L2_SEL_TGT_COMPOSE, i, which);
        }
 
        switch (tgt) {
@@ -242,8 +240,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
                crops[pad]->top = 0;
                crops[pad]->width = ffmt->width;
                crops[pad]->height = ffmt->height;
-               rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt, crops[pad],
-                                                    tgt + 1, pad, which);
+               rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+                                                    crops[pad], tgt + 1, pad, which);
                goto out_subdev_fmt_propagate;
        case IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP:
                if (WARN_ON(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
@@ -253,9 +251,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
                compose[pad]->top = 0;
                compose[pad]->width = r->width;
                compose[pad]->height = r->height;
-               rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt,
-                                                    compose[pad], tgt + 1,
-                                                    pad, which);
+               rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+                                                    compose[pad], tgt + 1, pad, which);
                goto out_subdev_fmt_propagate;
        case IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE:
                if (WARN_ON(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE)) {
@@ -272,11 +269,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
                        compose[i]->top = 0;
                        compose[i]->width = r->width;
                        compose[i]->height = r->height;
-                       rval = ipu_isys_subdev_fmt_propagate(sd, cfg,
-                                                            ffmt,
-                                                            compose[i],
-                                                            tgt + 1, i,
-                                                            which);
+                       rval = ipu_isys_subdev_fmt_propagate(sd, sd_state,
+                                                       ffmt, compose[i], tgt + 1, i, which);
                        if (rval)
                                goto out_subdev_fmt_propagate;
                }
@@ -291,9 +285,8 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
                crops[pad]->top = 0;
                crops[pad]->width = r->width;
                crops[pad]->height = r->height;
-               rval = ipu_isys_subdev_fmt_propagate(sd, cfg, ffmt,
-                                                    crops[pad], tgt + 1,
-                                                    pad, which);
+               rval = ipu_isys_subdev_fmt_propagate(sd, sd_state, ffmt,
+                                                    crops[pad], tgt + 1, pad, which);
                goto out_subdev_fmt_propagate;
        case IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP:{
                        struct v4l2_subdev_format fmt = {
@@ -313,7 +306,7 @@ int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
                                },
                        };
 
-                       asd->set_ffmt(sd, cfg, &fmt);
+                       asd->set_ffmt(sd, sd_state, &fmt);
                        goto out_subdev_fmt_propagate;
                }
        }
@@ -326,16 +319,16 @@ out_subdev_fmt_propagate:
 }
 
 int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_format *fmt)
 {
        struct v4l2_mbus_framefmt *ffmt =
-               __ipu_isys_get_ffmt(sd, cfg, fmt->pad, fmt->which);
+               __ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
 
        /* No propagation for non-zero pads. */
        if (fmt->pad) {
                struct v4l2_mbus_framefmt *sink_ffmt =
-                       __ipu_isys_get_ffmt(sd, cfg, 0, fmt->which);
+                       __ipu_isys_get_ffmt(sd, sd_state, 0, fmt->which);
 
                ffmt->width = sink_ffmt->width;
                ffmt->height = sink_ffmt->height;
@@ -350,18 +343,18 @@ int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
        ffmt->code = fmt->format.code;
        ffmt->field = fmt->format.field;
 
-       return ipu_isys_subdev_fmt_propagate(sd, cfg, &fmt->format, NULL,
+       return ipu_isys_subdev_fmt_propagate(sd, sd_state, &fmt->format, NULL,
                                             IPU_ISYS_SUBDEV_PROP_TGT_SINK_FMT,
                                             fmt->pad, fmt->which);
 }
 
 int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
        struct v4l2_mbus_framefmt *ffmt =
-               __ipu_isys_get_ffmt(sd, cfg, fmt->pad, fmt->which);
+               __ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which);
        u32 code = asd->supported_codes[fmt->pad][0];
        unsigned int i;
 
@@ -381,7 +374,7 @@ int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
 
        fmt->format.code = code;
 
-       asd->set_ffmt(sd, cfg, fmt);
+       asd->set_ffmt(sd, sd_state, fmt);
 
        fmt->format = *ffmt;
 
@@ -389,27 +382,27 @@ int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
 }
 
 int ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
        int rval;
 
        mutex_lock(&asd->mutex);
-       rval = __ipu_isys_subdev_set_ffmt(sd, cfg, fmt);
+       rval = __ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
        mutex_unlock(&asd->mutex);
 
        return rval;
 }
 
 int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
 
        mutex_lock(&asd->mutex);
-       fmt->format = *__ipu_isys_get_ffmt(sd, cfg, fmt->pad,
+       fmt->format = *__ipu_isys_get_ffmt(sd, sd_state, fmt->pad,
                                           fmt->which);
        mutex_unlock(&asd->mutex);
 
@@ -417,7 +410,7 @@ int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
 }
 
 int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_selection *sel)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -432,7 +425,7 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
        case V4L2_SEL_TGT_CROP:
                if (pad->flags & MEDIA_PAD_FL_SINK) {
                        struct v4l2_mbus_framefmt *ffmt =
-                               __ipu_isys_get_ffmt(sd, cfg, sel->pad,
+                               __ipu_isys_get_ffmt(sd, sd_state, sel->pad,
                                                    sel->which);
 
                        __r.width = ffmt->width;
@@ -441,7 +434,7 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
                        tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_CROP;
                } else {
                        /* 0 is the sink pad. */
-                       r = __ipu_isys_get_selection(sd, cfg, sel->target, 0,
+                       r = __ipu_isys_get_selection(sd, sd_state, sel->target, 0,
                                                     sel->which);
                        tgt = IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_CROP;
                }
@@ -449,11 +442,11 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
                break;
        case V4L2_SEL_TGT_COMPOSE:
                if (pad->flags & MEDIA_PAD_FL_SINK) {
-                       r = __ipu_isys_get_selection(sd, cfg, V4L2_SEL_TGT_CROP,
+                       r = __ipu_isys_get_selection(sd, sd_state, V4L2_SEL_TGT_CROP,
                                                     sel->pad, sel->which);
                        tgt = IPU_ISYS_SUBDEV_PROP_TGT_SINK_COMPOSE;
                } else {
-                       r = __ipu_isys_get_selection(sd, cfg,
+                       r = __ipu_isys_get_selection(sd, sd_state,
                                                     V4L2_SEL_TGT_COMPOSE, 0,
                                                     sel->which);
                        tgt = IPU_ISYS_SUBDEV_PROP_TGT_SOURCE_COMPOSE;
@@ -465,27 +458,27 @@ int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
 
        sel->r.width = clamp(sel->r.width, IPU_ISYS_MIN_WIDTH, r->width);
        sel->r.height = clamp(sel->r.height, IPU_ISYS_MIN_HEIGHT, r->height);
-       *__ipu_isys_get_selection(sd, cfg, sel->target, sel->pad,
+       *__ipu_isys_get_selection(sd, sd_state, sel->target, sel->pad,
                                  sel->which) = sel->r;
-       return ipu_isys_subdev_fmt_propagate(sd, cfg, NULL, &sel->r, tgt,
+       return ipu_isys_subdev_fmt_propagate(sd, sd_state, NULL, &sel->r, tgt,
                                             sel->pad, sel->which);
 }
 
 int ipu_isys_subdev_get_sel(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_selection *sel)
 {
        if (!target_valid(sd, sel->target, sel->pad))
                return -EINVAL;
 
-       sel->r = *__ipu_isys_get_selection(sd, cfg, sel->target,
+       sel->r = *__ipu_isys_get_selection(sd, sd_state, sel->target,
                                           sel->pad, sel->which);
 
        return 0;
 }
 
 int ipu_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum *code)
 {
        struct ipu_isys_subdev *asd = to_ipu_isys_subdev(sd);
@@ -555,11 +548,11 @@ int ipu_isys_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 
        for (i = 0; i < asd->sd.entity.num_pads; i++) {
                struct v4l2_mbus_framefmt *try_fmt =
-                       v4l2_subdev_get_try_format(sd, fh->pad, i);
+                       v4l2_subdev_get_try_format(sd, fh->state, i);
                struct v4l2_rect *try_crop =
-                       v4l2_subdev_get_try_crop(sd, fh->pad, i);
+                       v4l2_subdev_get_try_crop(sd, fh->state, i);
                struct v4l2_rect *try_compose =
-                       v4l2_subdev_get_try_compose(sd, fh->pad, i);
+                       v4l2_subdev_get_try_compose(sd, fh->state, i);
 
                *try_fmt = asd->ffmt[i];
                *try_crop = asd->crop[i];
index 35eb9d1d3cb7367fe934d25ac94bfbc3ff60592a..053ac094642d5e3bcbabddba0ffca1a8c8f0d677 100644 (file)
@@ -75,7 +75,7 @@ struct ipu_isys_subdev {
        struct v4l2_ctrl_handler ctrl_handler;
        void (*ctrl_init)(struct v4l2_subdev *sd);
        void (*set_ffmt)(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg,
+                        struct v4l2_subdev_state *sd_state,
                         struct v4l2_subdev_format *fmt);
        struct {
                bool crop;
@@ -90,8 +90,7 @@ struct ipu_isys_subdev {
        container_of(__sd, struct ipu_isys_subdev, sd)
 
 struct v4l2_mbus_framefmt *__ipu_isys_get_ffmt(struct v4l2_subdev *sd,
-                                              struct v4l2_subdev_pad_config
-                                              *cfg,
+                                              struct v4l2_subdev_state *sd_state,
                                               unsigned int pad,
                                               unsigned int which);
 
@@ -102,37 +101,37 @@ u32 ipu_isys_subdev_code_to_uncompressed(u32 sink_code);
 enum ipu_isys_subdev_pixelorder ipu_isys_subdev_get_pixelorder(u32 code);
 
 int ipu_isys_subdev_fmt_propagate(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_state *sd_state,
                                  struct v4l2_mbus_framefmt *ffmt,
                                  struct v4l2_rect *r,
                                  enum isys_subdev_prop_tgt tgt,
                                  unsigned int pad, unsigned int which);
 
 int ipu_isys_subdev_set_ffmt_default(struct v4l2_subdev *sd,
-                                    struct v4l2_subdev_pad_config *cfg,
+                                    struct v4l2_subdev_state *sd_state,
                                     struct v4l2_subdev_format *fmt);
 int __ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-                              struct v4l2_subdev_pad_config *cfg,
+                              struct v4l2_subdev_state *sd_state,
                               struct v4l2_subdev_format *fmt);
 struct v4l2_rect *__ipu_isys_get_selection(struct v4l2_subdev *sd,
-                                          struct v4l2_subdev_pad_config *cfg,
+                                          struct v4l2_subdev_state *sd_state,
                                           unsigned int target,
                                           unsigned int pad,
                                           unsigned int which);
 int ipu_isys_subdev_set_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt);
 int ipu_isys_subdev_get_ffmt(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_pad_config *cfg,
+                            struct v4l2_subdev_state *sd_state,
                             struct v4l2_subdev_format *fmt);
 int ipu_isys_subdev_get_sel(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_selection *sel);
 int ipu_isys_subdev_set_sel(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_pad_config *cfg,
+                           struct v4l2_subdev_state *sd_state,
                            struct v4l2_subdev_selection *sel);
 int ipu_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_state *sd_state,
                                   struct v4l2_subdev_mbus_code_enum
                                   *code);
 int ipu_isys_subdev_link_validate(struct v4l2_subdev *sd,
diff --git a/drivers/media/pci/intel/ipu-isys-tpg.c b/drivers/media/pci/intel/ipu-isys-tpg.c
new file mode 100644 (file)
index 0000000..b77ea5d
--- /dev/null
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2013 - 2020 Intel Corporation
+
+#include <linux/device.h>
+#include <linux/module.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+
+#include "ipu.h"
+#include "ipu-bus.h"
+#include "ipu-isys.h"
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-tpg.h"
+#include "ipu-isys-video.h"
+#include "ipu-platform-isys-csi2-reg.h"
+
+static const u32 tpg_supported_codes_pad[] = {
+       MEDIA_BUS_FMT_SBGGR8_1X8,
+       MEDIA_BUS_FMT_SGBRG8_1X8,
+       MEDIA_BUS_FMT_SGRBG8_1X8,
+       MEDIA_BUS_FMT_SRGGB8_1X8,
+       MEDIA_BUS_FMT_SBGGR10_1X10,
+       MEDIA_BUS_FMT_SGBRG10_1X10,
+       MEDIA_BUS_FMT_SGRBG10_1X10,
+       MEDIA_BUS_FMT_SRGGB10_1X10,
+       0,
+};
+
+static const u32 *tpg_supported_codes[] = {
+       tpg_supported_codes_pad,
+};
+
+static struct v4l2_subdev_internal_ops tpg_sd_internal_ops = {
+       .open = ipu_isys_subdev_open,
+       .close = ipu_isys_subdev_close,
+};
+
+static const struct v4l2_subdev_video_ops tpg_sd_video_ops = {
+       .s_stream = tpg_set_stream,
+};
+
+static int ipu_isys_tpg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ipu_isys_tpg *tpg = container_of(container_of(ctrl->handler,
+                                                            struct
+                                                            ipu_isys_subdev,
+                                                            ctrl_handler),
+                                               struct ipu_isys_tpg, asd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_HBLANK:
+               writel(ctrl->val, tpg->base + MIPI_GEN_REG_SYNG_HBLANK_CYC);
+               break;
+       case V4L2_CID_VBLANK:
+               writel(ctrl->val, tpg->base + MIPI_GEN_REG_SYNG_VBLANK_CYC);
+               break;
+       case V4L2_CID_TEST_PATTERN:
+               writel(ctrl->val, tpg->base + MIPI_GEN_REG_TPG_MODE);
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops ipu_isys_tpg_ctrl_ops = {
+       .s_ctrl = ipu_isys_tpg_s_ctrl,
+};
+
+static s64 ipu_isys_tpg_rate(struct ipu_isys_tpg *tpg, unsigned int bpp)
+{
+       return MIPI_GEN_PPC * IPU_ISYS_FREQ / bpp;
+}
+
+static const char *const tpg_mode_items[] = {
+       "Ramp",
+       "Checkerboard", /* Does not work, disabled. */
+       "Frame Based Colour",
+};
+
+static struct v4l2_ctrl_config tpg_mode = {
+       .ops = &ipu_isys_tpg_ctrl_ops,
+       .id = V4L2_CID_TEST_PATTERN,
+       .name = "Test Pattern",
+       .type = V4L2_CTRL_TYPE_MENU,
+       .min = 0,
+       .max = ARRAY_SIZE(tpg_mode_items) - 1,
+       .def = 0,
+       .menu_skip_mask = 0x2,
+       .qmenu = tpg_mode_items,
+};
+
+static const struct v4l2_ctrl_config csi2_header_cfg = {
+       .id = V4L2_CID_IPU_STORE_CSI2_HEADER,
+       .name = "Store CSI-2 Headers",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 1,
+};
+
+static void ipu_isys_tpg_init_controls(struct v4l2_subdev *sd)
+{
+       struct ipu_isys_tpg *tpg = to_ipu_isys_tpg(sd);
+       int hblank;
+       u64 default_pixel_rate;
+
+       hblank = 1024;
+
+       tpg->hblank = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+                                       &ipu_isys_tpg_ctrl_ops,
+                                       V4L2_CID_HBLANK, 8, 65535, 1, hblank);
+
+       tpg->vblank = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+                                       &ipu_isys_tpg_ctrl_ops,
+                                       V4L2_CID_VBLANK, 8, 65535, 1, 1024);
+
+       default_pixel_rate = ipu_isys_tpg_rate(tpg, 8);
+       tpg->pixel_rate = v4l2_ctrl_new_std(&tpg->asd.ctrl_handler,
+                                           &ipu_isys_tpg_ctrl_ops,
+                                           V4L2_CID_PIXEL_RATE,
+                                           default_pixel_rate,
+                                           default_pixel_rate,
+                                           1, default_pixel_rate);
+       if (tpg->pixel_rate) {
+               tpg->pixel_rate->cur.val = default_pixel_rate;
+               tpg->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       }
+
+       v4l2_ctrl_new_custom(&tpg->asd.ctrl_handler, &tpg_mode, NULL);
+       tpg->store_csi2_header =
+               v4l2_ctrl_new_custom(&tpg->asd.ctrl_handler,
+                                    &csi2_header_cfg, NULL);
+}
+
+static void tpg_set_ffmt(struct v4l2_subdev *sd,
+                        struct v4l2_subdev_state *sd_state,
+                        struct v4l2_subdev_format *fmt)
+{
+       fmt->format.field = V4L2_FIELD_NONE;
+       *__ipu_isys_get_ffmt(sd, sd_state, fmt->pad, fmt->which) = fmt->format;
+}
+
+static int ipu_isys_tpg_set_ffmt(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_state *sd_state,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct ipu_isys_tpg *tpg = to_ipu_isys_tpg(sd);
+       __u32 code = tpg->asd.ffmt[TPG_PAD_SOURCE].code;
+       unsigned int bpp = ipu_isys_mbus_code_to_bpp(code);
+       s64 tpg_rate = ipu_isys_tpg_rate(tpg, bpp);
+       int rval;
+
+       mutex_lock(&tpg->asd.mutex);
+       rval = __ipu_isys_subdev_set_ffmt(sd, sd_state, fmt);
+       mutex_unlock(&tpg->asd.mutex);
+
+       if (rval || fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return rval;
+
+       v4l2_ctrl_s_ctrl_int64(tpg->pixel_rate, tpg_rate);
+
+       return 0;
+}
+
+static const struct ipu_isys_pixelformat *
+ipu_isys_tpg_try_fmt(struct ipu_isys_video *av,
+                    struct v4l2_pix_format_mplane *mpix)
+{
+       struct media_link *link = list_first_entry(&av->vdev.entity.links,
+                                                  struct media_link, list);
+       struct v4l2_subdev *sd =
+               media_entity_to_v4l2_subdev(link->source->entity);
+       struct ipu_isys_tpg *tpg;
+
+       if (!sd)
+               return NULL;
+
+       tpg = to_ipu_isys_tpg(sd);
+
+       return ipu_isys_video_try_fmt_vid_mplane(av, mpix,
+               v4l2_ctrl_g_ctrl(tpg->store_csi2_header));
+}
+
+static const struct v4l2_subdev_pad_ops tpg_sd_pad_ops = {
+       .get_fmt = ipu_isys_subdev_get_ffmt,
+       .set_fmt = ipu_isys_tpg_set_ffmt,
+       .enum_mbus_code = ipu_isys_subdev_enum_mbus_code,
+};
+
+static int subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                          struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+#ifdef IPU_TPG_FRAME_SYNC
+       case V4L2_EVENT_FRAME_SYNC:
+               return v4l2_event_subscribe(fh, sub, 10, NULL);
+#endif
+       case V4L2_EVENT_CTRL:
+               return v4l2_ctrl_subscribe_event(fh, sub);
+       default:
+               return -EINVAL;
+       }
+};
+
+/* V4L2 subdev core operations */
+static const struct v4l2_subdev_core_ops tpg_sd_core_ops = {
+       .subscribe_event = subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static struct v4l2_subdev_ops tpg_sd_ops = {
+       .core = &tpg_sd_core_ops,
+       .video = &tpg_sd_video_ops,
+       .pad = &tpg_sd_pad_ops,
+};
+
+static struct media_entity_operations tpg_entity_ops = {
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+void ipu_isys_tpg_cleanup(struct ipu_isys_tpg *tpg)
+{
+       v4l2_device_unregister_subdev(&tpg->asd.sd);
+       ipu_isys_subdev_cleanup(&tpg->asd);
+       ipu_isys_video_cleanup(&tpg->av);
+}
+
+int ipu_isys_tpg_init(struct ipu_isys_tpg *tpg,
+                     struct ipu_isys *isys,
+                     void __iomem *base, void __iomem *sel,
+                     unsigned int index)
+{
+       struct v4l2_subdev_format fmt = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .pad = TPG_PAD_SOURCE,
+               .format = {
+                          .width = 4096,
+                          .height = 3072,
+                          },
+       };
+       int rval;
+
+       tpg->isys = isys;
+       tpg->base = base;
+       tpg->sel = sel;
+       tpg->index = index;
+
+       tpg->asd.sd.entity.ops = &tpg_entity_ops;
+       tpg->asd.ctrl_init = ipu_isys_tpg_init_controls;
+       tpg->asd.isys = isys;
+
+       rval = ipu_isys_subdev_init(&tpg->asd, &tpg_sd_ops, 5,
+                                   NR_OF_TPG_PADS,
+                                   NR_OF_TPG_SOURCE_PADS,
+                                   NR_OF_TPG_SINK_PADS,
+                                   V4L2_SUBDEV_FL_HAS_EVENTS);
+       if (rval)
+               return rval;
+
+       tpg->asd.sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       tpg->asd.pad[TPG_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+       tpg->asd.source = IPU_FW_ISYS_STREAM_SRC_MIPIGEN_PORT0 + index;
+       tpg->asd.supported_codes = tpg_supported_codes;
+       tpg->asd.set_ffmt = tpg_set_ffmt;
+       ipu_isys_subdev_set_ffmt(&tpg->asd.sd, NULL, &fmt);
+
+       tpg->asd.sd.internal_ops = &tpg_sd_internal_ops;
+       snprintf(tpg->asd.sd.name, sizeof(tpg->asd.sd.name),
+                IPU_ISYS_ENTITY_PREFIX " TPG %u", index);
+       v4l2_set_subdevdata(&tpg->asd.sd, &tpg->asd);
+       rval = v4l2_device_register_subdev(&isys->v4l2_dev, &tpg->asd.sd);
+       if (rval) {
+               dev_info(&isys->adev->dev, "can't register v4l2 subdev\n");
+               goto fail;
+       }
+
+       snprintf(tpg->av.vdev.name, sizeof(tpg->av.vdev.name),
+                IPU_ISYS_ENTITY_PREFIX " TPG %u capture", index);
+       tpg->av.isys = isys;
+       tpg->av.aq.css_pin_type = IPU_FW_ISYS_PIN_TYPE_MIPI;
+       tpg->av.pfmts = ipu_isys_pfmts_packed;
+       tpg->av.try_fmt_vid_mplane = ipu_isys_tpg_try_fmt;
+       tpg->av.prepare_fw_stream =
+           ipu_isys_prepare_fw_cfg_default;
+       tpg->av.packed = true;
+       tpg->av.line_header_length = IPU_ISYS_CSI2_LONG_PACKET_HEADER_SIZE;
+       tpg->av.line_footer_length = IPU_ISYS_CSI2_LONG_PACKET_FOOTER_SIZE;
+       tpg->av.aq.buf_prepare = ipu_isys_buf_prepare;
+       tpg->av.aq.fill_frame_buff_set_pin =
+           ipu_isys_buffer_to_fw_frame_buff_pin;
+       tpg->av.aq.link_fmt_validate = ipu_isys_link_fmt_validate;
+       tpg->av.aq.vbq.buf_struct_size = sizeof(struct ipu_isys_video_buffer);
+
+       rval = ipu_isys_video_init(&tpg->av, &tpg->asd.sd.entity,
+                                  TPG_PAD_SOURCE, MEDIA_PAD_FL_SINK, 0);
+       if (rval) {
+               dev_info(&isys->adev->dev, "can't init video node\n");
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       ipu_isys_tpg_cleanup(tpg);
+
+       return rval;
+}
diff --git a/drivers/media/pci/intel/ipu-isys-tpg.h b/drivers/media/pci/intel/ipu-isys-tpg.h
new file mode 100644 (file)
index 0000000..332f087
--- /dev/null
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2013 - 2020 Intel Corporation */
+
+#ifndef IPU_ISYS_TPG_H
+#define IPU_ISYS_TPG_H
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+
+#include "ipu-isys-subdev.h"
+#include "ipu-isys-video.h"
+#include "ipu-isys-queue.h"
+
+struct ipu_isys_tpg_pdata;
+struct ipu_isys;
+
+#define TPG_PAD_SOURCE                 0
+#define NR_OF_TPG_PADS                 1
+#define NR_OF_TPG_SOURCE_PADS          1
+#define NR_OF_TPG_SINK_PADS            0
+#define NR_OF_TPG_STREAMS              1
+
+/*
+ * PPC is 4 pixels for clock for RAW8, RAW10 and RAW12.
+ * Source: FW validation test code.
+ */
+#define MIPI_GEN_PPC           4
+
+#define MIPI_GEN_REG_COM_ENABLE                                0x0
+#define MIPI_GEN_REG_COM_DTYPE                         0x4
+/* RAW8, RAW10 or RAW12 */
+#define MIPI_GEN_COM_DTYPE_RAW(n)                      (((n) - 8) / 2)
+#define MIPI_GEN_REG_COM_VTYPE                         0x8
+#define MIPI_GEN_REG_COM_VCHAN                         0xc
+#define MIPI_GEN_REG_COM_WCOUNT                                0x10
+#define MIPI_GEN_REG_PRBS_RSTVAL0                      0x14
+#define MIPI_GEN_REG_PRBS_RSTVAL1                      0x18
+#define MIPI_GEN_REG_SYNG_FREE_RUN                     0x1c
+#define MIPI_GEN_REG_SYNG_PAUSE                                0x20
+#define MIPI_GEN_REG_SYNG_NOF_FRAMES                   0x24
+#define MIPI_GEN_REG_SYNG_NOF_PIXELS                   0x28
+#define MIPI_GEN_REG_SYNG_NOF_LINES                    0x2c
+#define MIPI_GEN_REG_SYNG_HBLANK_CYC                   0x30
+#define MIPI_GEN_REG_SYNG_VBLANK_CYC                   0x34
+#define MIPI_GEN_REG_SYNG_STAT_HCNT                    0x38
+#define MIPI_GEN_REG_SYNG_STAT_VCNT                    0x3c
+#define MIPI_GEN_REG_SYNG_STAT_FCNT                    0x40
+#define MIPI_GEN_REG_SYNG_STAT_DONE                    0x44
+#define MIPI_GEN_REG_TPG_MODE                          0x48
+#define MIPI_GEN_REG_TPG_HCNT_MASK                     0x4c
+#define MIPI_GEN_REG_TPG_VCNT_MASK                     0x50
+#define MIPI_GEN_REG_TPG_XYCNT_MASK                    0x54
+#define MIPI_GEN_REG_TPG_HCNT_DELTA                    0x58
+#define MIPI_GEN_REG_TPG_VCNT_DELTA                    0x5c
+#define MIPI_GEN_REG_TPG_R1                            0x60
+#define MIPI_GEN_REG_TPG_G1                            0x64
+#define MIPI_GEN_REG_TPG_B1                            0x68
+#define MIPI_GEN_REG_TPG_R2                            0x6c
+#define MIPI_GEN_REG_TPG_G2                            0x70
+#define MIPI_GEN_REG_TPG_B2                            0x74
+
+/*
+ * struct ipu_isys_tpg
+ *
+ * @nlanes: number of lanes in the receiver
+ */
+struct ipu_isys_tpg {
+       struct ipu_isys_tpg_pdata *pdata;
+       struct ipu_isys *isys;
+       struct ipu_isys_subdev asd;
+       struct ipu_isys_video av;
+
+       void __iomem *base;
+       void __iomem *sel;
+       unsigned int index;
+       int streaming;
+
+       struct v4l2_ctrl *hblank;
+       struct v4l2_ctrl *vblank;
+       struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *store_csi2_header;
+};
+
+#define to_ipu_isys_tpg(sd)            \
+       container_of(to_ipu_isys_subdev(sd), \
+       struct ipu_isys_tpg, asd)
+#ifdef IPU_TPG_FRAME_SYNC
+void ipu_isys_tpg_sof_event(struct ipu_isys_tpg *tpg);
+void ipu_isys_tpg_eof_event(struct ipu_isys_tpg *tpg);
+#endif
+int ipu_isys_tpg_init(struct ipu_isys_tpg *tpg,
+                     struct ipu_isys *isys,
+                     void __iomem *base, void __iomem *sel,
+                     unsigned int index);
+void ipu_isys_tpg_cleanup(struct ipu_isys_tpg *tpg);
+int tpg_set_stream(struct v4l2_subdev *sd, int enable);
+
+#endif /* IPU_ISYS_TPG_H */
index d7c493228c69d06086fae195cbe7907ef8997904..69df93bf7b02116fceb562e511bb55b53a0ec661 100644 (file)
@@ -946,7 +946,6 @@ void ipu_put_fw_mgs_buf(struct ipu_isys *isys, u64 data)
        list_move(&msg->head, &isys->framebuflist);
        spin_unlock_irqrestore(&isys->listlock, flags);
 }
-EXPORT_SYMBOL_GPL(ipu_put_fw_mgs_buf);
 
 static int isys_probe(struct ipu_bus_device *adev)
 {
@@ -1314,34 +1313,6 @@ leave:
        return 0;
 }
 
-static void isys_isr_poll(struct ipu_bus_device *adev)
-{
-       struct ipu_isys *isys = ipu_bus_get_drvdata(adev);
-
-       if (!isys->fwcom) {
-               dev_dbg(&isys->adev->dev,
-                       "got interrupt but device not configured yet\n");
-               return;
-       }
-
-       mutex_lock(&isys->mutex);
-       isys_isr(adev);
-       mutex_unlock(&isys->mutex);
-}
-
-int ipu_isys_isr_run(void *ptr)
-{
-       struct ipu_isys *isys = ptr;
-
-       while (!kthread_should_stop()) {
-               usleep_range(500, 1000);
-               if (isys->stream_opened)
-                       isys_isr_poll(isys->adev);
-       }
-
-       return 0;
-}
-
 static struct ipu_bus_driver isys_driver = {
        .probe = isys_probe,
        .remove = isys_remove,
@@ -1359,7 +1330,8 @@ module_ipu_bus_driver(isys_driver);
 static const struct pci_device_id ipu_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
index 57bc4b55bf26145dc10fe4351584339b27eca13f..8b1228febdf63eb766817d154f5372ff1e5b7d08 100644 (file)
@@ -219,7 +219,6 @@ extern const struct v4l2_ioctl_ops ipu_isys_ioctl_ops;
 
 void isys_setup_hw(struct ipu_isys *isys);
 int isys_isr_one(struct ipu_bus_device *adev);
-int ipu_isys_isr_run(void *ptr);
 irqreturn_t isys_isr(struct ipu_bus_device *adev);
 #ifdef IPU_ISYS_GPC
 int ipu_isys_gpc_init_debugfs(struct ipu_isys *isys);
index ad84c7b6344143b7129239260ea42bc93aa75181..7d38529820b14cd9517e9ce4f679734f25624125 100644 (file)
@@ -785,7 +785,7 @@ static void ipu_mmu_destroy(struct ipu_mmu *mmu)
        }
 
        free_dummy_page(mmu_info);
-       dma_unmap_single(mmu_info->dev, mmu_info->l1_pt_dma,
+       dma_unmap_single(mmu_info->dev, mmu_info->l1_pt_dma << ISP_PADDR_SHIFT,
                         PAGE_SIZE, DMA_BIDIRECTIONAL);
        free_page((unsigned long)mmu_info->dummy_l2_pt);
        free_page((unsigned long)mmu_info->l1_pt);
@@ -840,7 +840,6 @@ struct ipu_mmu *ipu_mmu_init(struct device *dev,
 
        return mmu;
 }
-EXPORT_SYMBOL(ipu_mmu_init);
 
 void ipu_mmu_cleanup(struct ipu_mmu *mmu)
 {
@@ -852,7 +851,6 @@ void ipu_mmu_cleanup(struct ipu_mmu *mmu)
        put_iova_domain(&dmap->iovad);
        kfree(dmap);
 }
-EXPORT_SYMBOL(ipu_mmu_cleanup);
 
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Samu Onkalo <samu.onkalo@intel.com>");
index ba13127d946e35f42496a75653ae4ef01ec466ed..763ebc2c1a9f9cf3e81d8e4af8145d9d2c7fefb9 100644 (file)
@@ -223,4 +223,3 @@ long ipu_psys_compat_ioctl32(struct file *file, unsigned int cmd,
        }
        return err;
 }
-EXPORT_SYMBOL_GPL(ipu_psys_compat_ioctl32);
index d0c71c86928fa8918049b3b0496ed2337f169047..0774ebc8bc9c02ec803055155cf95f9c54d0de05 100644 (file)
@@ -1340,7 +1340,6 @@ static int ipu_psys_probe(struct ipu_bus_device *adev)
        INIT_LIST_HEAD(&psys->fhs);
        INIT_LIST_HEAD(&psys->pgs);
        INIT_LIST_HEAD(&psys->started_kcmds_list);
-       INIT_WORK(&psys->watchdog_work, ipu_psys_watchdog_work);
 
        init_waitqueue_head(&psys->sched_cmd_wq);
        atomic_set(&psys->wakeup_count, 0);
@@ -1360,18 +1359,11 @@ static int ipu_psys_probe(struct ipu_bus_device *adev)
 
        ipu_bus_set_drvdata(adev, psys);
 
-       rval = ipu_psys_resource_pool_init(&psys->resource_pool_started);
-       if (rval < 0) {
-               dev_err(&psys->dev,
-                       "unable to alloc process group resources\n");
-               goto out_mutex_destroy;
-       }
-
        rval = ipu_psys_resource_pool_init(&psys->resource_pool_running);
        if (rval < 0) {
                dev_err(&psys->dev,
                        "unable to alloc process group resources\n");
-               goto out_resources_started_free;
+               goto out_mutex_destroy;
        }
 
        ipu6_psys_hw_res_variant_init();
@@ -1459,8 +1451,6 @@ out_free_pgs:
        }
 
        ipu_psys_resource_pool_cleanup(&psys->resource_pool_running);
-out_resources_started_free:
-       ipu_psys_resource_pool_cleanup(&psys->resource_pool_started);
 out_mutex_destroy:
        mutex_destroy(&psys->mutex);
        cdev_del(&psys->cdev);
@@ -1514,7 +1504,6 @@ static void ipu_psys_remove(struct ipu_bus_device *adev)
 
        ipu_trace_uninit(&adev->dev);
 
-       ipu_psys_resource_pool_cleanup(&psys->resource_pool_started);
        ipu_psys_resource_pool_cleanup(&psys->resource_pool_running);
 
        device_unregister(&psys->dev);
@@ -1608,7 +1597,8 @@ static void __exit ipu_psys_exit(void)
 static const struct pci_device_id ipu_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
index b5ddf50791d7436d37870544cad174cc6060e144..80d70f2ef3cef3a99f443a30c728a1427879c5aa 100644 (file)
@@ -60,6 +60,8 @@ struct ipu_psys_resource_pool {
        struct ipu_resource ext_memory[32];
        struct ipu_resource dfms[16];
        DECLARE_BITMAP(cmd_queues, 32);
+       /* Protects cmd_queues bitmap */
+       spinlock_t queues_lock;
 };
 
 /*
@@ -95,7 +97,6 @@ struct ipu_psys {
        struct ia_css_syscom_config *syscom_config;
        struct ia_css_psys_server_init *server_init;
        struct task_struct *sched_cmd_thread;
-       struct work_struct watchdog_work;
        wait_queue_head_t sched_cmd_wq;
        atomic_t wakeup_count;  /* Psys schedule thread wakeup count */
 #ifdef CONFIG_DEBUG_FS
@@ -104,7 +105,6 @@ struct ipu_psys {
 
        /* Resources needed to be managed for process groups */
        struct ipu_psys_resource_pool resource_pool_running;
-       struct ipu_psys_resource_pool resource_pool_started;
 
        const struct firmware *fw;
        struct sg_table fw_sgt;
@@ -198,7 +198,6 @@ void ipu_psys_subdomains_power(struct ipu_psys *psys, bool on);
 void ipu_psys_handle_events(struct ipu_psys *psys);
 int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh);
 void ipu_psys_run_next(struct ipu_psys *psys);
-void ipu_psys_watchdog_work(struct work_struct *work);
 struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size);
 struct ipu_psys_kbuffer *
 ipu_psys_lookup_kbuffer(struct ipu_psys_fh *fh, int fd);
index f7826d07ea54c75b4dbb4beb8de985df044e63c3..691907561e9afa7744d9c95925d144ade44a8242 100644 (file)
@@ -415,7 +415,8 @@ static int ipu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                ipu_ver = IPU_VER_6SE;
                isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
                break;
-       case IPU6EP_PCI_ID:
+       case IPU6EP_ADL_P_PCI_ID:
+       case IPU6EP_ADL_N_PCI_ID:
                ipu_ver = IPU_VER_6EP;
                isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
                break;
@@ -750,7 +751,8 @@ static const struct dev_pm_ops ipu_pm_ops = {
 static const struct pci_device_id ipu_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6_PCI_ID)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6SE_PCI_ID)},
-       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_P_PCI_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU6EP_ADL_N_PCI_ID)},
        {0,}
 };
 MODULE_DEVICE_TABLE(pci, ipu_pci_tbl);
index 2b8758ccab9b6d94124f771e3305605bd6ddfc81..4ef08954dceaaf326b91bdf0548c8e771a87887e 100644 (file)
@@ -16,7 +16,8 @@
 
 #define IPU6_PCI_ID    0x9a19
 #define IPU6SE_PCI_ID  0x4e19
-#define IPU6EP_PCI_ID  0x465d
+#define IPU6EP_ADL_P_PCI_ID    0x465d
+#define IPU6EP_ADL_N_PCI_ID    0x462e
 
 enum ipu_version {
        IPU_VER_INVALID = 0,
index b246fc037890fda06f72ebfc779b7d927e7b5c82..dfe4fde7e83f340e57d34864b597c788e56d346b 100644 (file)
@@ -141,15 +141,14 @@ static void ipu_resource_cleanup(struct ipu_resource *res)
 }
 
 /********** IPU PSYS-specific resource handling **********/
-static DEFINE_SPINLOCK(cq_bitmap_lock);
-int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
-                               *pool)
+int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool *pool)
 {
        int i, j, k, ret;
        const struct ipu_fw_resource_definitions *res_defs;
 
        res_defs = get_res();
 
+       spin_lock_init(&pool->queues_lock);
        pool->cells = 0;
 
        for (i = 0; i < res_defs->num_dev_channels; i++) {
@@ -172,14 +171,14 @@ int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
                        goto dfm_error;
        }
 
-       spin_lock(&cq_bitmap_lock);
+       spin_lock(&pool->queues_lock);
        if (ipu_ver == IPU_VER_6SE)
                bitmap_zero(pool->cmd_queues,
                            IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
        else
                bitmap_zero(pool->cmd_queues,
                            IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID);
-       spin_unlock(&cq_bitmap_lock);
+       spin_unlock(&pool->queues_lock);
 
        return 0;
 
@@ -272,17 +271,6 @@ static int __alloc_one_resrc(const struct device *dev,
        return 0;
 }
 
-static inline unsigned int bit_count(unsigned int n)
-{
-       unsigned int counter = 0;
-
-       while (n) {
-               counter++;
-               n &= (n - 1);
-       }
-       return counter;
-}
-
 static int ipu_psys_allocate_one_dfm(const struct device *dev,
                                     struct ipu_fw_psys_process *process,
                                     struct ipu_resource *resource,
@@ -316,7 +304,7 @@ static int ipu_psys_allocate_one_dfm(const struct device *dev,
                }
                *resource->bitmap |= dfm_bitmap_req;
        } else {
-               unsigned int n = bit_count(dfm_bitmap_req);
+               unsigned int n = hweight32(dfm_bitmap_req);
 
                p = bitmap_find_next_zero_area(resource->bitmap,
                                               resource->elements, 0, n, 0);
@@ -398,17 +386,17 @@ int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
                start = IPU6SE_FW_PSYS_CMD_QUEUE_PPG0_COMMAND_ID;
        }
 
-       spin_lock(&cq_bitmap_lock);
+       spin_lock(&pool->queues_lock);
        /* find available cmd queue from ppg0_cmd_id */
        p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
 
        if (p >= size) {
-               spin_unlock(&cq_bitmap_lock);
+               spin_unlock(&pool->queues_lock);
                return -ENOSPC;
        }
 
        bitmap_set(pool->cmd_queues, p, 1);
-       spin_unlock(&cq_bitmap_lock);
+       spin_unlock(&pool->queues_lock);
 
        return p;
 }
@@ -416,9 +404,9 @@ int ipu_psys_allocate_cmd_queue_resource(struct ipu_psys_resource_pool *pool)
 void ipu_psys_free_cmd_queue_resource(struct ipu_psys_resource_pool *pool,
                                      u8 queue_id)
 {
-       spin_lock(&cq_bitmap_lock);
+       spin_lock(&pool->queues_lock);
        bitmap_clear(pool->cmd_queues, queue_id, 1);
-       spin_unlock(&cq_bitmap_lock);
+       spin_unlock(&pool->queues_lock);
 }
 
 int ipu_psys_try_allocate_resources(struct device *dev,
index 9569a146e739140617e40b011f1d53c57e0f50f9..338e90d8f29b5dd591425c69ad2e06fdd4a793ad 100644 (file)
@@ -13,7 +13,7 @@
 /*
  * Cell types by cell IDs
  */
-const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
+static const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
        IPU6_FW_PSYS_SP_CTRL_TYPE_ID,
        IPU6_FW_PSYS_VP_TYPE_ID,
        IPU6_FW_PSYS_ACC_PSA_TYPE_ID,
@@ -48,7 +48,7 @@ const u8 ipu6_fw_psys_cell_types[IPU6_FW_PSYS_N_CELL_ID] = {
        IPU6_FW_PSYS_TNR_TYPE_ID,
 };
 
-const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
+static const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT0_MAX_SIZE,
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_READ_MAX_SIZE,
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_WRITE_MAX_SIZE,
@@ -56,7 +56,7 @@ const u16 ipu6_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
        IPU6_FW_PSYS_DEV_CHN_DMA_ISA_MAX_SIZE,
 };
 
-const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
+static const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
        IPU6_FW_PSYS_VMEM0_MAX_SIZE,
        IPU6_FW_PSYS_TRANSFER_VMEM0_MAX_SIZE,
        IPU6_FW_PSYS_TRANSFER_VMEM1_MAX_SIZE,
@@ -69,7 +69,7 @@ const u16 ipu6_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
        IPU6_FW_PSYS_PMEM0_MAX_SIZE
 };
 
-const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
+static const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
        IPU6_FW_PSYS_DEV_DFM_BB_FULL_PORT_ID_MAX_SIZE,
        IPU6_FW_PSYS_DEV_DFM_BB_EMPTY_PORT_ID_MAX_SIZE,
        IPU6_FW_PSYS_DEV_DFM_ISL_FULL_PORT_ID_MAX_SIZE,
@@ -78,7 +78,7 @@ const u16 ipu6_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
        IPU6_FW_PSYS_DEV_DFM_LB_EMPTY_PORT_ID_MAX_SIZE,
 };
 
-const u8
+static const u8
 ipu6_fw_psys_c_mem[IPU6_FW_PSYS_N_CELL_ID][IPU6_FW_PSYS_N_MEM_TYPE_ID] = {
        {
                /* IPU6_FW_PSYS_SP0_ID */
@@ -539,6 +539,8 @@ int ipu6_fw_psys_get_program_manifest_by_process(
        return 0;
 }
 
+#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) || \
+       (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
 void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
                          struct ipu_psys_kcmd *kcmd, const char *note)
 {
@@ -593,3 +595,14 @@ void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
                }
        }
 }
+#else
+void ipu6_fw_psys_pg_dump(struct ipu_psys *psys,
+                         struct ipu_psys_kcmd *kcmd, const char *note)
+{
+       if (ipu_ver == IPU_VER_6SE || ipu_ver == IPU_VER_6 ||
+           ipu_ver == IPU_VER_6EP)
+               return;
+
+       WARN(1, "%s ipu_ver:[%u] is unsupported!\n", __func__, ipu_ver);
+}
+#endif
index bd8044255efe22133aba5ba99d6d3f1b59d7566e..a305c0c3e2cf93dda7611bb8e52867c69389c9bc 100644 (file)
@@ -173,10 +173,8 @@ int ipu_isys_gpc_init_debugfs(struct ipu_isys *isys)
                if (IS_ERR(dir))
                        goto err;
 
-               file = debugfs_create_bool("enable", 0600, dir,
-                                          &isys_gpcs->gpc[i].enable);
-               if (IS_ERR(file))
-                       goto err;
+               debugfs_create_bool("enable", 0600, dir,
+                                   &isys_gpcs->gpc[i].enable);
 
                debugfs_create_u32("source", 0600, dir,
                                   &isys_gpcs->gpc[i].source);
index a1165e718def157accf4adfb434a866b22636d78..c26780106c78f446471e0d4d580ecc8e54a88549 100644 (file)
@@ -25,7 +25,7 @@ struct phy_reg {
        u32 val;
 };
 
-struct phy_reg common_init_regs[] = {
+static const struct phy_reg common_init_regs[] = {
        /* for TGL-U, use 0x80000000 */
        {0x00000040, 0x80000000},
        {0x00000044, 0x00a80880},
@@ -45,7 +45,7 @@ struct phy_reg common_init_regs[] = {
        {0x00001944, 0xfa4401e2}
 };
 
-struct phy_reg x1_port0_config_regs[] = {
+static const struct phy_reg x1_port0_config_regs[] = {
        {0x00000694, 0xc80060fa},
        {0x00000680, 0x3d4f78ea},
        {0x00000690, 0x10a0140b},
@@ -69,7 +69,7 @@ struct phy_reg x1_port0_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port1_config_regs[] = {
+static const struct phy_reg x1_port1_config_regs[] = {
        {0x00000c94, 0xc80060fa},
        {0x00000c80, 0xcf47abea},
        {0x00000c90, 0x10a0840b},
@@ -93,7 +93,7 @@ struct phy_reg x1_port1_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port2_config_regs[] = {
+static const struct phy_reg x1_port2_config_regs[] = {
        {0x00001294, 0x28f000fa},
        {0x00001280, 0x08130cea},
        {0x00001290, 0x10a0140b},
@@ -117,7 +117,7 @@ struct phy_reg x1_port2_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x1_port3_config_regs[] = {
+static const struct phy_reg x1_port3_config_regs[] = {
        {0x00001894, 0xc80060fa},
        {0x00001880, 0x0f90fd6a},
        {0x00001890, 0x10a0840b},
@@ -141,7 +141,7 @@ struct phy_reg x1_port3_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port0_config_regs[] = {
+static const struct phy_reg x2_port0_config_regs[] = {
        {0x00000694, 0xc80060fa},
        {0x00000680, 0x3d4f78ea},
        {0x00000690, 0x10a0140b},
@@ -175,7 +175,7 @@ struct phy_reg x2_port0_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port1_config_regs[] = {
+static const struct phy_reg x2_port1_config_regs[] = {
        {0x00000c94, 0xc80060fa},
        {0x00000c80, 0xcf47abea},
        {0x00000c90, 0x10a0840b},
@@ -209,7 +209,7 @@ struct phy_reg x2_port1_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port2_config_regs[] = {
+static const struct phy_reg x2_port2_config_regs[] = {
        {0x00001294, 0xc80060fa},
        {0x00001280, 0x08130cea},
        {0x00001290, 0x10a0140b},
@@ -242,7 +242,7 @@ struct phy_reg x2_port2_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x2_port3_config_regs[] = {
+static const struct phy_reg x2_port3_config_regs[] = {
        {0x00001894, 0xc80060fa},
        {0x00001880, 0x0f90fd6a},
        {0x00001890, 0x10a0840b},
@@ -276,7 +276,7 @@ struct phy_reg x2_port3_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port0_config_regs[] = {
+static const struct phy_reg x4_port0_config_regs[] = {
        {0x00000694, 0xc80060fa},
        {0x00000680, 0x3d4f78fa},
        {0x00000690, 0x10a0140b},
@@ -330,11 +330,11 @@ struct phy_reg x4_port0_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port1_config_regs[] = {
+static const struct phy_reg x4_port1_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port2_config_regs[] = {
+static const struct phy_reg x4_port2_config_regs[] = {
        {0x00001294, 0x28f000fa},
        {0x00001280, 0x08130cfa},
        {0x00001290, 0x10c0140b},
@@ -388,32 +388,32 @@ struct phy_reg x4_port2_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg x4_port3_config_regs[] = {
+static const struct phy_reg x4_port3_config_regs[] = {
        {0x00000000, 0x00000000}
 };
 
-struct phy_reg *x1_config_regs[4] = {
+static const struct phy_reg *x1_config_regs[4] = {
        x1_port0_config_regs,
        x1_port1_config_regs,
        x1_port2_config_regs,
        x1_port3_config_regs
 };
 
-struct phy_reg *x2_config_regs[4] = {
+static const struct phy_reg *x2_config_regs[4] = {
        x2_port0_config_regs,
        x2_port1_config_regs,
        x2_port2_config_regs,
        x2_port3_config_regs
 };
 
-struct phy_reg *x4_config_regs[4] = {
+static const struct phy_reg *x4_config_regs[4] = {
        x4_port0_config_regs,
        x4_port1_config_regs,
        x4_port2_config_regs,
        x4_port3_config_regs
 };
 
-struct phy_reg **config_regs[3] = {
+static const struct phy_reg **config_regs[3] = {
        x1_config_regs,
        x2_config_regs,
        x4_config_regs,
@@ -561,7 +561,7 @@ int ipu6_isys_phy_config(struct ipu_isys *isys)
        struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
        struct ipu_device *isp = adev->isp;
        void __iomem *isp_base = isp->base;
-       struct phy_reg **phy_config_regs;
+       const struct phy_reg **phy_config_regs;
        struct v4l2_async_subdev *asd;
        struct sensor_async_subdev *s_asd;
        struct ipu_isys_csi2_config cfg;
index c6acf9cb70ef38b796ad4f11336e74e2a1415a15..8f6f413c03933ba56ec2b39d43a60ce4fbf4d24e 100644 (file)
@@ -97,12 +97,14 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd,
        buf_set_size = ipu_fw_psys_ppg_get_buffer_set_size(kcmd);
 
        kbuf_set = __get_buf_set(fh, buf_set_size);
-       if (!kbuf_set)
-               goto error;
+       if (!kbuf_set) {
+               dev_err(&psys->adev->dev, "failed to create buffer set\n");
+               return NULL;
+       }
 
        kbuf_set->buf_set = ipu_fw_psys_ppg_create_buffer_set(kcmd,
                                                              kbuf_set->kaddr,
-       0);
+                                                             0);
 
        ipu_fw_psys_ppg_buffer_set_vaddress(kbuf_set->buf_set,
                                            kbuf_set->dma_addr);
@@ -111,9 +113,6 @@ ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd,
                                                            keb);
 
        return kbuf_set;
-error:
-       dev_err(&psys->adev->dev, "failed to create buffer set\n");
-       return NULL;
 }
 
 int ipu_psys_ppg_get_bufset(struct ipu_psys_kcmd *kcmd,
index 3bf35d245a4fc149caed83159b32c17d81d148b9..b6b850a68398e12d56e89d83674db0ec5e7b3f67 100644 (file)
@@ -180,10 +180,8 @@ int ipu_psys_gpc_init_debugfs(struct ipu_psys *psys)
                if (IS_ERR(dir))
                        goto err;
 
-               file = debugfs_create_bool("enable", 0600, dir,
-                                          &psys_gpcs->gpc[idx].enable);
-               if (IS_ERR(file))
-                       goto err;
+               debugfs_create_bool("enable", 0600, dir,
+                                   &psys_gpcs->gpc[idx].enable);
 
                debugfs_create_u32("source", 0600, dir,
                                   &psys_gpcs->gpc[idx].source);
index 06560b91948b3c1e41a35efc6f8262d06ab73a95..294a6f1638e505a4b21bc8e180d620aa2d4fdbd4 100644 (file)
 #include "ipu-platform-regs.h"
 #include "ipu-trace.h"
 
-#define is_ppg_kcmd(kcmd) (ipu_fw_psys_pg_get_protocol(        \
-                       (struct ipu_psys_kcmd *)kcmd)   \
-                       == IPU_FW_PSYS_PROCESS_GROUP_PROTOCOL_PPG)
-
 static bool early_pg_transfer;
 module_param(early_pg_transfer, bool, 0664);
 MODULE_PARM_DESC(early_pg_transfer,
@@ -501,7 +497,7 @@ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd)
        ret = ipu_fw_psys_pg_start(kcmd);
        if (ret) {
                dev_err(&psys->adev->dev, "failed to start kcmd!\n");
-               goto error;
+               return ret;
        }
 
        ipu_fw_psys_pg_dump(psys, kcmd, "run");
@@ -509,29 +505,10 @@ int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd)
        ret = ipu_fw_psys_pg_disown(kcmd);
        if (ret) {
                dev_err(&psys->adev->dev, "failed to start kcmd!\n");
-               goto error;
+               return ret;
        }
 
        return 0;
-
-error:
-       dev_err(&psys->adev->dev, "failed to start process group\n");
-       return ret;
-}
-
-void ipu_psys_watchdog_work(struct work_struct *work)
-{
-       struct ipu_psys *psys = container_of(work,
-                                            struct ipu_psys, watchdog_work);
-       dev_dbg(&psys->adev->dev, "watchdog for ppg not implemented yet!\n");
-}
-
-static void ipu_psys_watchdog(struct timer_list *t)
-{
-       struct ipu_psys_kcmd *kcmd = from_timer(kcmd, t, watchdog);
-       struct ipu_psys *psys = kcmd->fh->psys;
-
-       queue_work(IPU_PSYS_WORK_QUEUE, &psys->watchdog_work);
 }
 
 static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd)
@@ -702,14 +679,13 @@ int ipu_psys_kcmd_new(struct ipu_psys_command *cmd, struct ipu_psys_fh *fh)
                goto error;
        }
 
-       if (!is_ppg_kcmd(kcmd)) {
+       if (ipu_fw_psys_pg_get_protocol(kcmd) !=
+                       IPU_FW_PSYS_PROCESS_GROUP_PROTOCOL_PPG) {
                dev_err(&psys->adev->dev, "No support legacy pg now\n");
                ret = -EINVAL;
                goto error;
        }
 
-       timer_setup(&kcmd->watchdog, ipu_psys_watchdog, 0);
-
        if (cmd->min_psys_freq) {
                kcmd->constraint.min_freq = cmd->min_psys_freq;
                ipu_buttress_add_psys_constraint(psys->adev->isp,
index ca2ab3967e5c099356d6219aa165506f6a28f617..7b1ee7c6dc4efae1691629b87f7378230b122e9e 100644 (file)
@@ -14,7 +14,7 @@
 /*
  * Cell types by cell IDs
  */
-const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
+static const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
        IPU6_FW_PSYS_SP_CTRL_TYPE_ID,
        IPU6_FW_PSYS_VP_TYPE_ID,
        IPU6_FW_PSYS_ACC_PSA_TYPE_ID,
@@ -46,7 +46,7 @@ const u8 ipu6ep_fw_psys_cell_types[IPU6EP_FW_PSYS_N_CELL_ID] = {
        IPU6_FW_PSYS_TNR_TYPE_ID,
 };
 
-const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
+static const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT0_MAX_SIZE,
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_READ_MAX_SIZE,
        IPU6_FW_PSYS_DEV_CHN_DMA_EXT1_WRITE_MAX_SIZE,
@@ -54,7 +54,7 @@ const u16 ipu6ep_fw_num_dev_channels[IPU6_FW_PSYS_N_DEV_CHN_ID] = {
        IPU6_FW_PSYS_DEV_CHN_DMA_ISA_MAX_SIZE,
 };
 
-const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
+static const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
        IPU6_FW_PSYS_VMEM0_MAX_SIZE,
        IPU6_FW_PSYS_TRANSFER_VMEM0_MAX_SIZE,
        IPU6_FW_PSYS_TRANSFER_VMEM1_MAX_SIZE,
@@ -67,7 +67,7 @@ const u16 ipu6ep_fw_psys_mem_size[IPU6_FW_PSYS_N_MEM_ID] = {
        IPU6_FW_PSYS_PMEM0_MAX_SIZE
 };
 
-const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
+static const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
        IPU6_FW_PSYS_DEV_DFM_BB_FULL_PORT_ID_MAX_SIZE,
        IPU6_FW_PSYS_DEV_DFM_BB_EMPTY_PORT_ID_MAX_SIZE,
        IPU6_FW_PSYS_DEV_DFM_ISL_FULL_PORT_ID_MAX_SIZE,
@@ -76,7 +76,7 @@ const u16 ipu6ep_fw_psys_dfms[IPU6_FW_PSYS_N_DEV_DFM_ID] = {
        IPU6_FW_PSYS_DEV_DFM_LB_EMPTY_PORT_ID_MAX_SIZE,
 };
 
-const u8
+static const u8
 ipu6ep_fw_psys_c_mem[IPU6EP_FW_PSYS_N_CELL_ID][IPU6_FW_PSYS_N_MEM_TYPE_ID] = {
        {
                /* IPU6_FW_PSYS_SP0_ID */