[PATCH 02/13][SRU][OEM-5.13] UBUNTU: SAUCE: IPU driver release WW48
You-Sheng Yang
vicamo.yang at canonical.com
Thu Jul 29 06:48:21 UTC 2021
From: Wang Yating <yating.wang at intel.com>
BugLink: https://bugs.launchpad.net/bugs/1921345
Signed-off-by: Wang Yating <yating.wang at intel.com>
(backported from
https://github.com/intel/ipu6-drivers/commit/5e7f876527d932189e6e7d30f0dba5651068f0df)
Signed-off-by: You-Sheng Yang <vicamo.yang at canonical.com>
---
drivers/media/i2c/hm11b1.c | 1360 +++++++++++++++++
drivers/media/i2c/ov01a1s.c | 118 +-
drivers/media/pci/intel/Kconfig | 24 +
drivers/media/pci/intel/ipu-bus.c | 1 +
drivers/media/pci/intel/ipu-buttress.c | 139 +-
drivers/media/pci/intel/ipu-isys-csi2.c | 11 +-
drivers/media/pci/intel/ipu-isys-queue.c | 7 +-
drivers/media/pci/intel/ipu-isys-video.c | 8 +
drivers/media/pci/intel/ipu-isys-video.h | 3 +
drivers/media/pci/intel/ipu-isys.c | 51 +-
drivers/media/pci/intel/ipu-isys.h | 6 +
drivers/media/pci/intel/ipu-pdata.h | 4 +
drivers/media/pci/intel/ipu-psys.c | 136 +-
drivers/media/pci/intel/ipu-psys.h | 4 +-
drivers/media/pci/intel/ipu.c | 9 +
drivers/media/pci/intel/ipu6/Makefile | 7 +-
.../media/pci/intel/ipu6/ipu-platform-psys.h | 2 +-
.../pci/intel/ipu6/ipu-platform-resources.h | 4 +
drivers/media/pci/intel/ipu6/ipu-resources.c | 82 +-
.../media/pci/intel/ipu6/ipu6-fw-resources.c | 24 -
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 13 -
drivers/media/pci/intel/ipu6/ipu6-isys-phy.c | 36 -
drivers/media/pci/intel/ipu6/ipu6-isys-phy.h | 2 -
drivers/media/pci/intel/ipu6/ipu6-isys.c | 4 +
.../media/pci/intel/ipu6/ipu6-l-scheduler.c | 15 +-
drivers/media/pci/intel/ipu6/ipu6-ppg.c | 42 +-
drivers/media/pci/intel/ipu6/ipu6-psys.c | 171 ++-
drivers/media/pci/intel/ipu6/ipu6.c | 28 +-
28 files changed, 1855 insertions(+), 456 deletions(-)
create mode 100644 drivers/media/i2c/hm11b1.c
diff --git a/drivers/media/i2c/hm11b1.c b/drivers/media/i2c/hm11b1.c
new file mode 100644
index 000000000000..9c1662b842de
--- /dev/null
+++ b/drivers/media/i2c/hm11b1.c
@@ -0,0 +1,1360 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2020 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 <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define HM11B1_LINK_FREQ_384MHZ 384000000ULL
+#define HM11B1_SCLK 72000000LL
+#define HM11B1_MCLK 19200000
+#define HM11B1_DATA_LANES 1
+#define HM11B1_RGB_DEPTH 10
+
+#define HM11B1_REG_CHIP_ID 0x0000
+#define HM11B1_CHIP_ID 0x11B1
+
+#define HM11B1_REG_MODE_SELECT 0x0100
+#define HM11B1_MODE_STANDBY 0x00
+#define HM11B1_MODE_STREAMING 0x01
+
+/* vertical-timings from sensor */
+#define HM11B1_REG_VTS 0x3402
+#define HM11B1_VTS_DEF 0x037d
+#define HM11B1_VTS_MIN 0x0346
+#define HM11B1_VTS_MAX 0xffff
+
+/* horizontal-timings from sensor */
+#define HM11B1_REG_HTS 0x3404
+
+/* Exposure controls from sensor */
+#define HM11B1_REG_EXPOSURE 0x0202
+#define HM11B1_EXPOSURE_MIN 2
+#define HM11B1_EXPOSURE_MAX_MARGIN 2
+#define HM11B1_EXPOSURE_STEP 1
+
+/* Analog gain controls from sensor */
+#define HM11B1_REG_ANALOG_GAIN 0x0205
+#define HM11B1_ANAL_GAIN_MIN 0
+#define HM11B1_ANAL_GAIN_MAX 0x50
+#define HM11B1_ANAL_GAIN_STEP 1
+
+/* Digital gain controls from sensor */
+#define HM11B1_REG_DGTL_GAIN 0x0207
+#define HM11B1_DGTL_GAIN_MIN 0x0
+#define HM11B1_DGTL_GAIN_MAX 0x0200
+#define HM11B1_DGTL_GAIN_STEP 1
+#define HM11B1_DGTL_GAIN_DEFAULT 0x0100
+
+/* Test Pattern Control */
+#define HM11B1_REG_TEST_PATTERN 0x0601
+#define HM11B1_TEST_PATTERN_ENABLE 1
+#define HM11B1_TEST_PATTERN_BAR_SHIFT 1
+
+enum {
+ HM11B1_LINK_FREQ_384MHZ_INDEX,
+};
+
+struct hm11b1_reg {
+ u16 address;
+ u8 val;
+};
+
+struct hm11b1_reg_list {
+ u32 num_of_regs;
+ const struct hm11b1_reg *regs;
+};
+
+struct hm11b1_link_freq_config {
+ const struct hm11b1_reg_list reg_list;
+};
+
+struct hm11b1_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 hm11b1_reg_list reg_list;
+};
+
+static const struct hm11b1_reg mipi_data_rate_384mbps[] = {
+};
+
+//RAW 10bit 1292x800_30fps_MIPI 384Mbps/lane
+static const struct hm11b1_reg sensor_1292x800_30fps_setting[] = {
+ {0x0103, 0x00},
+ {0x0102, 0x01},
+ {0x0202, 0x03},
+ {0x0203, 0x7C},
+ {0x0205, 0x20},
+ {0x0207, 0x01},
+ {0x0208, 0x00},
+ {0x0209, 0x01},
+ {0x020A, 0x00},
+ {0x0300, 0x91},
+ {0x0301, 0x0A},
+ {0x0302, 0x02},
+ {0x0303, 0x2E},
+ {0x0304, 0x43},
+ {0x0306, 0x00},
+ {0x0307, 0x00},
+ {0x0340, 0x03},
+ {0x0341, 0x60},
+ {0x0342, 0x05},
+ {0x0343, 0xA0},
+ {0x0344, 0x00},
+ {0x0345, 0x00},
+ {0x0346, 0x03},
+ {0x0347, 0x2F},
+ {0x0350, 0xFF},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0370, 0x00},
+ {0x0371, 0x00},
+ {0x0380, 0x00},
+ {0x0381, 0x00},
+ {0x0382, 0x00},
+ {0x1000, 0xC3},
+ {0x1001, 0xD0},
+ {0x100A, 0x13},
+ {0x2000, 0x00},
+ {0x2061, 0x01},
+ {0x2062, 0x00},
+ {0x2063, 0xC8},
+ {0x2100, 0x03},
+ {0x2101, 0xF0},
+ {0x2102, 0xF0},
+ {0x2103, 0x01},
+ {0x2104, 0x10},
+ {0x2105, 0x10},
+ {0x2106, 0x02},
+ {0x2107, 0x0A},
+ {0x2108, 0x10},
+ {0x2109, 0x15},
+ {0x210A, 0x1A},
+ {0x210B, 0x20},
+ {0x210C, 0x08},
+ {0x210D, 0x0A},
+ {0x210E, 0x0F},
+ {0x210F, 0x12},
+ {0x2110, 0x1C},
+ {0x2111, 0x20},
+ {0x2112, 0x23},
+ {0x2113, 0x2A},
+ {0x2114, 0x30},
+ {0x2115, 0x10},
+ {0x2116, 0x00},
+ {0x2117, 0x01},
+ {0x2118, 0x00},
+ {0x2119, 0x06},
+ {0x211A, 0x00},
+ {0x211B, 0x00},
+ {0x2615, 0x08},
+ {0x2616, 0x00},
+ {0x2700, 0x01},
+ {0x2711, 0x01},
+ {0x272F, 0x01},
+ {0x2800, 0x29},
+ {0x2821, 0xCE},
+ {0x2839, 0x27},
+ {0x283A, 0x01},
+ {0x2842, 0x01},
+ {0x2843, 0x00},
+ {0x3022, 0x11},
+ {0x3024, 0x30},
+ {0x3025, 0x12},
+ {0x3026, 0x00},
+ {0x3027, 0x81},
+ {0x3028, 0x01},
+ {0x3029, 0x00},
+ {0x302A, 0x30},
+ {0x3030, 0x00},
+ {0x3032, 0x00},
+ {0x3035, 0x01},
+ {0x303E, 0x00},
+ {0x3051, 0x00},
+ {0x3082, 0x0E},
+ {0x3084, 0x0D},
+ {0x30A8, 0x03},
+ {0x30C4, 0xA0},
+ {0x30D5, 0xC1},
+ {0x30D8, 0x00},
+ {0x30D9, 0x0D},
+ {0x30DB, 0xC2},
+ {0x30DE, 0x25},
+ {0x30E1, 0xC3},
+ {0x30E4, 0x25},
+ {0x30E7, 0xC4},
+ {0x30EA, 0x25},
+ {0x30ED, 0xC5},
+ {0x30F0, 0x25},
+ {0x30F2, 0x0C},
+ {0x30F3, 0x85},
+ {0x30F6, 0x25},
+ {0x30F8, 0x0C},
+ {0x30F9, 0x05},
+ {0x30FB, 0x40},
+ {0x30FC, 0x25},
+ {0x30FD, 0x54},
+ {0x30FE, 0x0C},
+ {0x3100, 0xC2},
+ {0x3103, 0x00},
+ {0x3104, 0x2B},
+ {0x3106, 0xC3},
+ {0x3109, 0x25},
+ {0x310C, 0xC4},
+ {0x310F, 0x25},
+ {0x3112, 0xC5},
+ {0x3115, 0x25},
+ {0x3117, 0x0C},
+ {0x3118, 0x85},
+ {0x311B, 0x25},
+ {0x311D, 0x0C},
+ {0x311E, 0x05},
+ {0x3121, 0x25},
+ {0x3123, 0x0C},
+ {0x3124, 0x0D},
+ {0x3126, 0x40},
+ {0x3127, 0x25},
+ {0x3128, 0x54},
+ {0x3129, 0x0C},
+ {0x3130, 0x20},
+ {0x3134, 0x60},
+ {0x3135, 0xC2},
+ {0x3139, 0x12},
+ {0x313A, 0x07},
+ {0x313F, 0x52},
+ {0x3140, 0x34},
+ {0x3141, 0x2E},
+ {0x314F, 0x07},
+ {0x3151, 0x47},
+ {0x3153, 0xB0},
+ {0x3154, 0x4A},
+ {0x3155, 0xC0},
+ {0x3157, 0x55},
+ {0x3158, 0x01},
+ {0x3165, 0xFF},
+ {0x316B, 0x12},
+ {0x316E, 0x12},
+ {0x3176, 0x12},
+ {0x3178, 0x01},
+ {0x317C, 0x10},
+ {0x317D, 0x05},
+ {0x317F, 0x07},
+ {0x3182, 0x07},
+ {0x3183, 0x11},
+ {0x3184, 0x88},
+ {0x3186, 0x28},
+ {0x3191, 0x00},
+ {0x3192, 0x20},
+ {0x3400, 0x48},
+ {0x3401, 0x00},
+ {0x3402, 0x06},
+ {0x3403, 0xFA},
+ {0x3404, 0x05},
+ {0x3405, 0x40},
+ {0x3406, 0x00},
+ {0x3407, 0x00},
+ {0x3408, 0x03},
+ {0x3409, 0x2F},
+ {0x340A, 0x00},
+ {0x340B, 0x00},
+ {0x340C, 0x00},
+ {0x340D, 0x00},
+ {0x340E, 0x00},
+ {0x340F, 0x00},
+ {0x3410, 0x00},
+ {0x3411, 0x01},
+ {0x3412, 0x00},
+ {0x3413, 0x03},
+ {0x3414, 0xB0},
+ {0x3415, 0x4A},
+ {0x3416, 0xC0},
+ {0x3418, 0x55},
+ {0x3419, 0x03},
+ {0x341B, 0x7D},
+ {0x341C, 0x00},
+ {0x341F, 0x03},
+ {0x3420, 0x00},
+ {0x3421, 0x02},
+ {0x3422, 0x00},
+ {0x3423, 0x02},
+ {0x3424, 0x01},
+ {0x3425, 0x02},
+ {0x3426, 0x00},
+ {0x3427, 0xA2},
+ {0x3428, 0x01},
+ {0x3429, 0x06},
+ {0x342A, 0xF8},
+ {0x3440, 0x01},
+ {0x3441, 0xBE},
+ {0x3442, 0x02},
+ {0x3443, 0x18},
+ {0x3444, 0x03},
+ {0x3445, 0x0C},
+ {0x3446, 0x06},
+ {0x3447, 0x18},
+ {0x3448, 0x09},
+ {0x3449, 0x24},
+ {0x344A, 0x08},
+ {0x344B, 0x08},
+ {0x345C, 0x00},
+ {0x345D, 0x44},
+ {0x345E, 0x02},
+ {0x345F, 0x43},
+ {0x3460, 0x04},
+ {0x3461, 0x3B},
+ {0x3466, 0xF8},
+ {0x3467, 0x43},
+ {0x347D, 0x02},
+ {0x3483, 0x05},
+ {0x3484, 0x0C},
+ {0x3485, 0x03},
+ {0x3486, 0x20},
+ {0x3487, 0x00},
+ {0x3488, 0x00},
+ {0x3489, 0x00},
+ {0x348A, 0x09},
+ {0x348B, 0x00},
+ {0x348C, 0x00},
+ {0x348D, 0x02},
+ {0x348E, 0x01},
+ {0x348F, 0x40},
+ {0x3490, 0x00},
+ {0x3491, 0xC8},
+ {0x3492, 0x00},
+ {0x3493, 0x02},
+ {0x3494, 0x00},
+ {0x3495, 0x02},
+ {0x3496, 0x02},
+ {0x3497, 0x06},
+ {0x3498, 0x05},
+ {0x3499, 0x04},
+ {0x349A, 0x09},
+ {0x349B, 0x05},
+ {0x349C, 0x17},
+ {0x349D, 0x05},
+ {0x349E, 0x00},
+ {0x349F, 0x00},
+ {0x34A0, 0x00},
+ {0x34A1, 0x00},
+ {0x34A2, 0x08},
+ {0x34A3, 0x08},
+ {0x34A4, 0x00},
+ {0x34A5, 0x0B},
+ {0x34A6, 0x0C},
+ {0x34A7, 0x32},
+ {0x34A8, 0x10},
+ {0x34A9, 0xE0},
+ {0x34AA, 0x52},
+ {0x34AB, 0x00},
+ {0x34AC, 0x60},
+ {0x34AD, 0x2B},
+ {0x34AE, 0x25},
+ {0x34AF, 0x48},
+ {0x34B1, 0x06},
+ {0x34B2, 0xF8},
+ {0x34C3, 0xB0},
+ {0x34C4, 0x4A},
+ {0x34C5, 0xC0},
+ {0x34C7, 0x55},
+ {0x34C8, 0x03},
+ {0x34CB, 0x00},
+ {0x353A, 0x00},
+ {0x355E, 0x48},
+ {0x3572, 0xB0},
+ {0x3573, 0x4A},
+ {0x3574, 0xC0},
+ {0x3576, 0x55},
+ {0x3577, 0x03},
+ {0x357A, 0x00},
+ {0x35DA, 0x00},
+ {0x4003, 0x02},
+ {0x4004, 0x02},
+};
+
+//RAW 10bit 1292x800_60fps_MIPI 384Mbps/lane
+static const struct hm11b1_reg sensor_1292x800_60fps_setting[] = {
+ {0x0103, 0x00},
+ {0x0102, 0x01},
+ {0x0202, 0x03},
+ {0x0203, 0x7C},
+ {0x0205, 0x20},
+ {0x0207, 0x01},
+ {0x0208, 0x00},
+ {0x0209, 0x01},
+ {0x020A, 0x00},
+ {0x0300, 0x91},
+ {0x0301, 0x0A},
+ {0x0302, 0x02},
+ {0x0303, 0x2E},
+ {0x0304, 0x43},
+ {0x0306, 0x00},
+ {0x0307, 0x00},
+ {0x0340, 0x03},
+ {0x0341, 0x60},
+ {0x0342, 0x05},
+ {0x0343, 0xA0},
+ {0x0344, 0x00},
+ {0x0345, 0x00},
+ {0x0346, 0x03},
+ {0x0347, 0x2F},
+ {0x0350, 0xFF},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0370, 0x00},
+ {0x0371, 0x00},
+ {0x0380, 0x00},
+ {0x0381, 0x00},
+ {0x0382, 0x00},
+ {0x1000, 0xC3},
+ {0x1001, 0xD0},
+ {0x100A, 0x13},
+ {0x2000, 0x00},
+ {0x2061, 0x01},
+ {0x2062, 0x00},
+ {0x2063, 0xC8},
+ {0x2100, 0x03},
+ {0x2101, 0xF0},
+ {0x2102, 0xF0},
+ {0x2103, 0x01},
+ {0x2104, 0x10},
+ {0x2105, 0x10},
+ {0x2106, 0x02},
+ {0x2107, 0x0A},
+ {0x2108, 0x10},
+ {0x2109, 0x15},
+ {0x210A, 0x1A},
+ {0x210B, 0x20},
+ {0x210C, 0x08},
+ {0x210D, 0x0A},
+ {0x210E, 0x0F},
+ {0x210F, 0x12},
+ {0x2110, 0x1C},
+ {0x2111, 0x20},
+ {0x2112, 0x23},
+ {0x2113, 0x2A},
+ {0x2114, 0x30},
+ {0x2115, 0x10},
+ {0x2116, 0x00},
+ {0x2117, 0x01},
+ {0x2118, 0x00},
+ {0x2119, 0x06},
+ {0x211A, 0x00},
+ {0x211B, 0x00},
+ {0x2615, 0x08},
+ {0x2616, 0x00},
+ {0x2700, 0x01},
+ {0x2711, 0x01},
+ {0x272F, 0x01},
+ {0x2800, 0x29},
+ {0x2821, 0xCE},
+ {0x2839, 0x27},
+ {0x283A, 0x01},
+ {0x2842, 0x01},
+ {0x2843, 0x00},
+ {0x3022, 0x11},
+ {0x3024, 0x30},
+ {0x3025, 0x12},
+ {0x3026, 0x00},
+ {0x3027, 0x81},
+ {0x3028, 0x01},
+ {0x3029, 0x00},
+ {0x302A, 0x30},
+ {0x3030, 0x00},
+ {0x3032, 0x00},
+ {0x3035, 0x01},
+ {0x303E, 0x00},
+ {0x3051, 0x00},
+ {0x3082, 0x0E},
+ {0x3084, 0x0D},
+ {0x30A8, 0x03},
+ {0x30C4, 0xA0},
+ {0x30D5, 0xC1},
+ {0x30D8, 0x00},
+ {0x30D9, 0x0D},
+ {0x30DB, 0xC2},
+ {0x30DE, 0x25},
+ {0x30E1, 0xC3},
+ {0x30E4, 0x25},
+ {0x30E7, 0xC4},
+ {0x30EA, 0x25},
+ {0x30ED, 0xC5},
+ {0x30F0, 0x25},
+ {0x30F2, 0x0C},
+ {0x30F3, 0x85},
+ {0x30F6, 0x25},
+ {0x30F8, 0x0C},
+ {0x30F9, 0x05},
+ {0x30FB, 0x40},
+ {0x30FC, 0x25},
+ {0x30FD, 0x54},
+ {0x30FE, 0x0C},
+ {0x3100, 0xC2},
+ {0x3103, 0x00},
+ {0x3104, 0x2B},
+ {0x3106, 0xC3},
+ {0x3109, 0x25},
+ {0x310C, 0xC4},
+ {0x310F, 0x25},
+ {0x3112, 0xC5},
+ {0x3115, 0x25},
+ {0x3117, 0x0C},
+ {0x3118, 0x85},
+ {0x311B, 0x25},
+ {0x311D, 0x0C},
+ {0x311E, 0x05},
+ {0x3121, 0x25},
+ {0x3123, 0x0C},
+ {0x3124, 0x0D},
+ {0x3126, 0x40},
+ {0x3127, 0x25},
+ {0x3128, 0x54},
+ {0x3129, 0x0C},
+ {0x3130, 0x20},
+ {0x3134, 0x60},
+ {0x3135, 0xC2},
+ {0x3139, 0x12},
+ {0x313A, 0x07},
+ {0x313F, 0x52},
+ {0x3140, 0x34},
+ {0x3141, 0x2E},
+ {0x314F, 0x07},
+ {0x3151, 0x47},
+ {0x3153, 0xB0},
+ {0x3154, 0x4A},
+ {0x3155, 0xC0},
+ {0x3157, 0x55},
+ {0x3158, 0x01},
+ {0x3165, 0xFF},
+ {0x316B, 0x12},
+ {0x316E, 0x12},
+ {0x3176, 0x12},
+ {0x3178, 0x01},
+ {0x317C, 0x10},
+ {0x317D, 0x05},
+ {0x317F, 0x07},
+ {0x3182, 0x07},
+ {0x3183, 0x11},
+ {0x3184, 0x88},
+ {0x3186, 0x28},
+ {0x3191, 0x00},
+ {0x3192, 0x20},
+ {0x3400, 0x48},
+ {0x3401, 0x00},
+ {0x3402, 0x03},
+ {0x3403, 0x7D},
+ {0x3404, 0x05},
+ {0x3405, 0x40},
+ {0x3406, 0x00},
+ {0x3407, 0x00},
+ {0x3408, 0x03},
+ {0x3409, 0x2F},
+ {0x340A, 0x00},
+ {0x340B, 0x00},
+ {0x340C, 0x00},
+ {0x340D, 0x00},
+ {0x340E, 0x00},
+ {0x340F, 0x00},
+ {0x3410, 0x00},
+ {0x3411, 0x01},
+ {0x3412, 0x00},
+ {0x3413, 0x03},
+ {0x3414, 0xB0},
+ {0x3415, 0x4A},
+ {0x3416, 0xC0},
+ {0x3418, 0x55},
+ {0x3419, 0x03},
+ {0x341B, 0x7D},
+ {0x341C, 0x00},
+ {0x341F, 0x03},
+ {0x3420, 0x00},
+ {0x3421, 0x02},
+ {0x3422, 0x00},
+ {0x3423, 0x02},
+ {0x3424, 0x01},
+ {0x3425, 0x02},
+ {0x3426, 0x00},
+ {0x3427, 0xA2},
+ {0x3428, 0x01},
+ {0x3429, 0x06},
+ {0x342A, 0xF8},
+ {0x3440, 0x01},
+ {0x3441, 0xBE},
+ {0x3442, 0x02},
+ {0x3443, 0x18},
+ {0x3444, 0x03},
+ {0x3445, 0x0C},
+ {0x3446, 0x06},
+ {0x3447, 0x18},
+ {0x3448, 0x09},
+ {0x3449, 0x24},
+ {0x344A, 0x08},
+ {0x344B, 0x08},
+ {0x345C, 0x00},
+ {0x345D, 0x44},
+ {0x345E, 0x02},
+ {0x345F, 0x43},
+ {0x3460, 0x04},
+ {0x3461, 0x3B},
+ {0x3466, 0xF8},
+ {0x3467, 0x43},
+ {0x347D, 0x02},
+ {0x3483, 0x05},
+ {0x3484, 0x0C},
+ {0x3485, 0x03},
+ {0x3486, 0x20},
+ {0x3487, 0x00},
+ {0x3488, 0x00},
+ {0x3489, 0x00},
+ {0x348A, 0x09},
+ {0x348B, 0x00},
+ {0x348C, 0x00},
+ {0x348D, 0x02},
+ {0x348E, 0x01},
+ {0x348F, 0x40},
+ {0x3490, 0x00},
+ {0x3491, 0xC8},
+ {0x3492, 0x00},
+ {0x3493, 0x02},
+ {0x3494, 0x00},
+ {0x3495, 0x02},
+ {0x3496, 0x02},
+ {0x3497, 0x06},
+ {0x3498, 0x05},
+ {0x3499, 0x04},
+ {0x349A, 0x09},
+ {0x349B, 0x05},
+ {0x349C, 0x17},
+ {0x349D, 0x05},
+ {0x349E, 0x00},
+ {0x349F, 0x00},
+ {0x34A0, 0x00},
+ {0x34A1, 0x00},
+ {0x34A2, 0x08},
+ {0x34A3, 0x08},
+ {0x34A4, 0x00},
+ {0x34A5, 0x0B},
+ {0x34A6, 0x0C},
+ {0x34A7, 0x32},
+ {0x34A8, 0x10},
+ {0x34A9, 0xE0},
+ {0x34AA, 0x52},
+ {0x34AB, 0x00},
+ {0x34AC, 0x60},
+ {0x34AD, 0x2B},
+ {0x34AE, 0x25},
+ {0x34AF, 0x48},
+ {0x34B1, 0x06},
+ {0x34B2, 0xF8},
+ {0x34C3, 0xB0},
+ {0x34C4, 0x4A},
+ {0x34C5, 0xC0},
+ {0x34C7, 0x55},
+ {0x34C8, 0x03},
+ {0x34CB, 0x00},
+ {0x353A, 0x00},
+ {0x355E, 0x48},
+ {0x3572, 0xB0},
+ {0x3573, 0x4A},
+ {0x3574, 0xC0},
+ {0x3576, 0x55},
+ {0x3577, 0x03},
+ {0x357A, 0x00},
+ {0x35DA, 0x00},
+ {0x4003, 0x02},
+ {0x4004, 0x02},
+};
+
+static const char * const hm11b1_test_pattern_menu[] = {
+ "Disabled",
+ "Solid Color",
+ "Color Bar",
+ "Color Bar Blending",
+ "PN11",
+};
+
+static const s64 link_freq_menu_items[] = {
+ HM11B1_LINK_FREQ_384MHZ,
+};
+
+static const struct hm11b1_link_freq_config link_freq_configs[] = {
+ [HM11B1_LINK_FREQ_384MHZ_INDEX] = {
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_384mbps),
+ .regs = mipi_data_rate_384mbps,
+ }
+ },
+};
+
+static const struct hm11b1_mode supported_modes[] = {
+ {
+ .width = 1292,
+ .height = 800,
+ .hts = 1344,
+ .vts_def = HM11B1_VTS_DEF,
+ .vts_min = HM11B1_VTS_MIN,
+ .reg_list = {
+ .num_of_regs =
+ ARRAY_SIZE(sensor_1292x800_30fps_setting),
+ .regs = sensor_1292x800_30fps_setting,
+ },
+ .link_freq_index = HM11B1_LINK_FREQ_384MHZ_INDEX,
+ },
+};
+
+struct hm11b1 {
+ 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 hm11b1_mode *cur_mode;
+
+ /* To serialize asynchronus callbacks */
+ struct mutex mutex;
+
+ /* Streaming on/off */
+ bool streaming;
+};
+
+static inline struct hm11b1 *to_hm11b1(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct hm11b1, sd);
+}
+
+static u64 to_pixel_rate(u32 f_index)
+{
+ u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HM11B1_DATA_LANES;
+
+ do_div(pixel_rate, HM11B1_RGB_DEPTH);
+
+ return pixel_rate;
+}
+
+static u64 to_pixels_per_line(u32 hts, u32 f_index)
+{
+ u64 ppl = hts * to_pixel_rate(f_index);
+
+ do_div(ppl, HM11B1_SCLK);
+
+ return ppl;
+}
+
+static int hm11b1_read_reg(struct hm11b1 *hm11b1, u16 reg, u16 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 hm11b1_write_reg(struct hm11b1 *hm11b1, u16 reg, u16 len, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 hm11b1_write_reg_list(struct hm11b1 *hm11b1,
+ const struct hm11b1_reg_list *r_list)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < r_list->num_of_regs; i++) {
+ ret = hm11b1_write_reg(hm11b1, 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 hm11b1_update_digital_gain(struct hm11b1 *hm11b1, u32 d_gain)
+{
+ return hm11b1_write_reg(hm11b1, HM11B1_REG_DGTL_GAIN, 2, d_gain);
+}
+
+static int hm11b1_test_pattern(struct hm11b1 *hm11b1, u32 pattern)
+{
+ if (pattern)
+ pattern = pattern << HM11B1_TEST_PATTERN_BAR_SHIFT |
+ HM11B1_TEST_PATTERN_ENABLE;
+
+ return hm11b1_write_reg(hm11b1, HM11B1_REG_TEST_PATTERN, 1, pattern);
+}
+
+static int hm11b1_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct hm11b1 *hm11b1 = container_of(ctrl->handler,
+ struct hm11b1, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->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 = hm11b1->cur_mode->height + ctrl->val -
+ HM11B1_EXPOSURE_MAX_MARGIN;
+ __v4l2_ctrl_modify_range(hm11b1->exposure,
+ hm11b1->exposure->minimum,
+ exposure_max, hm11b1->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 = hm11b1_write_reg(hm11b1, HM11B1_REG_ANALOG_GAIN, 1,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = hm11b1_update_digital_gain(hm11b1, ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE:
+ /* 4 least significant bits of expsoure are fractional part */
+ ret = hm11b1_write_reg(hm11b1, HM11B1_REG_EXPOSURE, 2,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_VBLANK:
+ ret = hm11b1_write_reg(hm11b1, HM11B1_REG_VTS, 2,
+ hm11b1->cur_mode->height + ctrl->val);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = hm11b1_test_pattern(hm11b1, ctrl->val);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops hm11b1_ctrl_ops = {
+ .s_ctrl = hm11b1_set_ctrl,
+};
+
+static int hm11b1_init_controls(struct hm11b1 *hm11b1)
+{
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ const struct hm11b1_mode *cur_mode;
+ s64 exposure_max, h_blank, pixel_rate;
+ u32 vblank_min, vblank_max, vblank_default;
+ int size;
+ int ret = 0;
+
+ ctrl_hdlr = &hm11b1->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8);
+ if (ret)
+ return ret;
+
+ ctrl_hdlr->lock = &hm11b1->mutex;
+ cur_mode = hm11b1->cur_mode;
+ size = ARRAY_SIZE(link_freq_menu_items);
+
+ hm11b1->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ size - 1, 0,
+ link_freq_menu_items);
+ if (hm11b1->link_freq)
+ hm11b1->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ pixel_rate = to_pixel_rate(HM11B1_LINK_FREQ_384MHZ_INDEX);
+ hm11b1->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0,
+ pixel_rate, 1, pixel_rate);
+
+ vblank_min = cur_mode->vts_min - cur_mode->height;
+ vblank_max = HM11B1_VTS_MAX - cur_mode->height;
+ vblank_default = cur_mode->vts_def - cur_mode->height;
+ hm11b1->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_VBLANK, vblank_min,
+ vblank_max, 1, vblank_default);
+
+ h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index);
+ h_blank -= cur_mode->width;
+ hm11b1->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_HBLANK, h_blank, h_blank, 1,
+ h_blank);
+ if (hm11b1->hblank)
+ hm11b1->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ HM11B1_ANAL_GAIN_MIN, HM11B1_ANAL_GAIN_MAX,
+ HM11B1_ANAL_GAIN_STEP, HM11B1_ANAL_GAIN_MIN);
+ v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ HM11B1_DGTL_GAIN_MIN, HM11B1_DGTL_GAIN_MAX,
+ HM11B1_DGTL_GAIN_STEP, HM11B1_DGTL_GAIN_DEFAULT);
+ exposure_max = cur_mode->vts_def - HM11B1_EXPOSURE_MAX_MARGIN;
+ hm11b1->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ HM11B1_EXPOSURE_MIN, exposure_max,
+ HM11B1_EXPOSURE_STEP,
+ exposure_max);
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hm11b1_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(hm11b1_test_pattern_menu) - 1,
+ 0, 0, hm11b1_test_pattern_menu);
+ if (ctrl_hdlr->error)
+ return ctrl_hdlr->error;
+
+ hm11b1->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+}
+
+static void hm11b1_update_pad_format(const struct hm11b1_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->field = V4L2_FIELD_NONE;
+}
+
+static int hm11b1_start_streaming(struct hm11b1 *hm11b1)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+ const struct hm11b1_reg_list *reg_list;
+ int link_freq_index;
+ int ret = 0;
+
+ link_freq_index = hm11b1->cur_mode->link_freq_index;
+ reg_list = &link_freq_configs[link_freq_index].reg_list;
+ ret = hm11b1_write_reg_list(hm11b1, reg_list);
+ if (ret) {
+ dev_err(&client->dev, "failed to set plls");
+ return ret;
+ }
+
+ reg_list = &hm11b1->cur_mode->reg_list;
+ ret = hm11b1_write_reg_list(hm11b1, reg_list);
+ if (ret) {
+ dev_err(&client->dev, "failed to set mode");
+ return ret;
+ }
+
+ ret = __v4l2_ctrl_handler_setup(hm11b1->sd.ctrl_handler);
+ if (ret)
+ return ret;
+
+ ret = hm11b1_write_reg(hm11b1, HM11B1_REG_MODE_SELECT, 1,
+ HM11B1_MODE_STREAMING);
+ if (ret)
+ dev_err(&client->dev, "failed to start streaming");
+
+ return ret;
+}
+
+static void hm11b1_stop_streaming(struct hm11b1 *hm11b1)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+
+ if (hm11b1_write_reg(hm11b1, HM11B1_REG_MODE_SELECT, 1,
+ HM11B1_MODE_STANDBY))
+ dev_err(&client->dev, "failed to stop streaming");
+}
+
+static int hm11b1_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct hm11b1 *hm11b1 = to_hm11b1(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (hm11b1->streaming == enable)
+ return 0;
+
+ mutex_lock(&hm11b1->mutex);
+ if (enable) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&client->dev);
+ mutex_unlock(&hm11b1->mutex);
+ return ret;
+ }
+
+ ret = hm11b1_start_streaming(hm11b1);
+ if (ret) {
+ enable = 0;
+ hm11b1_stop_streaming(hm11b1);
+ pm_runtime_put(&client->dev);
+ }
+ } else {
+ hm11b1_stop_streaming(hm11b1);
+ pm_runtime_put(&client->dev);
+ }
+
+ hm11b1->streaming = enable;
+ mutex_unlock(&hm11b1->mutex);
+
+ return ret;
+}
+
+static int __maybe_unused hm11b1_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct hm11b1 *hm11b1 = to_hm11b1(sd);
+
+ mutex_lock(&hm11b1->mutex);
+ if (hm11b1->streaming)
+ hm11b1_stop_streaming(hm11b1);
+
+ mutex_unlock(&hm11b1->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused hm11b1_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct hm11b1 *hm11b1 = to_hm11b1(sd);
+ int ret = 0;
+
+ mutex_lock(&hm11b1->mutex);
+ if (!hm11b1->streaming)
+ goto exit;
+
+ ret = hm11b1_start_streaming(hm11b1);
+ if (ret) {
+ hm11b1->streaming = false;
+ hm11b1_stop_streaming(hm11b1);
+ }
+
+exit:
+ mutex_unlock(&hm11b1->mutex);
+ return ret;
+}
+
+static int hm11b1_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct hm11b1 *hm11b1 = to_hm11b1(sd);
+ const struct hm11b1_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(&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;
+ } else {
+ hm11b1->cur_mode = mode;
+ __v4l2_ctrl_s_ctrl(hm11b1->link_freq, mode->link_freq_index);
+ __v4l2_ctrl_s_ctrl_int64(hm11b1->pixel_rate,
+ to_pixel_rate(mode->link_freq_index));
+
+ /* Update limits and set FPS to default */
+ vblank_def = mode->vts_def - mode->height;
+ __v4l2_ctrl_modify_range(hm11b1->vblank,
+ mode->vts_min - mode->height,
+ HM11B1_VTS_MAX - mode->height, 1,
+ vblank_def);
+ __v4l2_ctrl_s_ctrl(hm11b1->vblank, vblank_def);
+ h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
+ mode->width;
+ __v4l2_ctrl_modify_range(hm11b1->hblank, h_blank, h_blank, 1,
+ h_blank);
+ }
+ mutex_unlock(&hm11b1->mutex);
+
+ return 0;
+}
+
+static int hm11b1_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ 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);
+ else
+ hm11b1_update_pad_format(hm11b1->cur_mode, &fmt->format);
+
+ mutex_unlock(&hm11b1->mutex);
+
+ return 0;
+}
+
+static int hm11b1_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+ return 0;
+}
+
+static int hm11b1_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ if (fse->code != MEDIA_BUS_FMT_SGRBG10_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 hm11b1_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct hm11b1 *hm11b1 = to_hm11b1(sd);
+
+ mutex_lock(&hm11b1->mutex);
+ hm11b1_update_pad_format(&supported_modes[0],
+ v4l2_subdev_get_try_format(sd, fh->pad, 0));
+ mutex_unlock(&hm11b1->mutex);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops hm11b1_video_ops = {
+ .s_stream = hm11b1_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops hm11b1_pad_ops = {
+ .set_fmt = hm11b1_set_format,
+ .get_fmt = hm11b1_get_format,
+ .enum_mbus_code = hm11b1_enum_mbus_code,
+ .enum_frame_size = hm11b1_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops hm11b1_subdev_ops = {
+ .video = &hm11b1_video_ops,
+ .pad = &hm11b1_pad_ops,
+};
+
+static const struct media_entity_operations hm11b1_subdev_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops hm11b1_internal_ops = {
+ .open = hm11b1_open,
+};
+
+static int hm11b1_identify_module(struct hm11b1 *hm11b1)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&hm11b1->sd);
+ int ret;
+ u32 val;
+
+ ret = hm11b1_read_reg(hm11b1, HM11B1_REG_CHIP_ID, 2, &val);
+ if (ret)
+ return ret;
+
+ if (val != HM11B1_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%x",
+ HM11B1_CHIP_ID, val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int hm11b1_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct hm11b1 *hm11b1 = to_hm11b1(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(&hm11b1->mutex);
+
+ return 0;
+}
+
+static int hm11b1_probe(struct i2c_client *client)
+{
+ struct hm11b1 *hm11b1;
+ int ret = 0;
+
+ hm11b1 = devm_kzalloc(&client->dev, sizeof(*hm11b1), GFP_KERNEL);
+ if (!hm11b1)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&hm11b1->sd, client, &hm11b1_subdev_ops);
+ ret = hm11b1_identify_module(hm11b1);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d", ret);
+ return ret;
+ }
+
+ mutex_init(&hm11b1->mutex);
+ hm11b1->cur_mode = &supported_modes[0];
+ ret = hm11b1_init_controls(hm11b1);
+ if (ret) {
+ dev_err(&client->dev, "failed to init controls: %d", ret);
+ goto probe_error_v4l2_ctrl_handler_free;
+ }
+
+ hm11b1->sd.internal_ops = &hm11b1_internal_ops;
+ hm11b1->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ hm11b1->sd.entity.ops = &hm11b1_subdev_entity_ops;
+ hm11b1->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ hm11b1->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&hm11b1->sd.entity, 1, &hm11b1->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_common(&hm11b1->sd);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to register V4L2 subdev: %d",
+ ret);
+ goto probe_error_media_entity_cleanup;
+ }
+
+ /*
+ * 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(&hm11b1->sd.entity);
+
+probe_error_v4l2_ctrl_handler_free:
+ v4l2_ctrl_handler_free(hm11b1->sd.ctrl_handler);
+ mutex_destroy(&hm11b1->mutex);
+
+ return ret;
+}
+
+static const struct dev_pm_ops hm11b1_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(hm11b1_suspend, hm11b1_resume)
+};
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hm11b1_acpi_ids[] = {
+ {"HM11B1"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, hm11b1_acpi_ids);
+#endif
+
+static struct i2c_driver hm11b1_i2c_driver = {
+ .driver = {
+ .name = "hm11b1",
+ .pm = &hm11b1_pm_ops,
+ .acpi_match_table = ACPI_PTR(hm11b1_acpi_ids),
+ },
+ .probe_new = hm11b1_probe,
+ .remove = hm11b1_remove,
+};
+
+module_i2c_driver(hm11b1_i2c_driver);
+
+MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu at intel.com>");
+MODULE_AUTHOR("Shawn Tu <shawnx.tu at intel.com>");
+MODULE_AUTHOR("Bingbu Cao <bingbu.cao at intel.com>");
+MODULE_AUTHOR("Lai, Jim <jim.lai at intel.com>");
+MODULE_DESCRIPTION("Himax HM11B1 sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/ov01a1s.c b/drivers/media/i2c/ov01a1s.c
index 44c991053b12..1d05b75347a1 100644
--- a/drivers/media/i2c/ov01a1s.c
+++ b/drivers/media/i2c/ov01a1s.c
@@ -11,8 +11,8 @@
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
-#define OV01A1S_LINK_FREQ_400MHZ 400000000ULL
-#define OV01A1S_SCLK 72000000LL
+#define OV01A1S_LINK_FREQ_400MHZ 400000000ULL
+#define OV01A1S_SCLK 40000000LL
#define OV01A1S_MCLK 19200000
#define OV01A1S_DATA_LANES 1
#define OV01A1S_RGB_DEPTH 10
@@ -46,7 +46,7 @@
#define OV01A1S_ANAL_GAIN_STEP 1
/* Digital gain controls from sensor */
-#define OV01A1S_REG_DGTL_GAIN 0x350A //24bits
+#define OV01A1S_REG_DGTL_GAIN 0x350A
#define OV01A1S_DGTL_GAIN_MIN 0
#define OV01A1S_DGTL_GAIN_MAX 0xfff
#define OV01A1S_DGTL_GAIN_STEP 1
@@ -101,7 +101,6 @@ struct ov01a1s_mode {
static const struct ov01a1s_reg mipi_data_rate_720mbps[] = {
};
-//RAW 10bit 1296x736_30fps_MIPI 480Mbps/lane
static const struct ov01a1s_reg sensor_1296x800_setting[] = {
{0x0103, 0x01},
{0x0302, 0x00},
@@ -214,12 +213,10 @@ static const struct ov01a1s_reg sensor_1296x800_setting[] = {
{0x4301, 0x00},
{0x4302, 0x0f},
{0x4503, 0x00},
- //{DATA_8BITS, {0x4601, 0x20},
- {0x4601, 0x50}, // PC
+ {0x4601, 0x50},
{0x481f, 0x34},
{0x4825, 0x33},
- //{DATA_8BITS, {0x4837, 0x11},
- {0x4837, 0x14}, // PC
+ {0x4837, 0x14},
{0x4881, 0x40},
{0x4883, 0x01},
{0x4890, 0x00},
@@ -229,32 +226,25 @@ static const struct ov01a1s_reg sensor_1296x800_setting[] = {
{0x4b0d, 0x00},
{0x450a, 0x04},
{0x450b, 0x00},
- //{DATA_8BITS, {0x5000, 0x75},
{0x5000, 0x65},
{0x5004, 0x00},
{0x5080, 0x40},
{0x5200, 0x18},
{0x4837, 0x14},
-
- // key setting for 19.2Mhz, 1296x736
{0x0305, 0xf4},
- //{DATA_8BITS, {0x0323, 0x05},
- //{DATA_8BITS, {0x0325, 0x2c},
- {0x0325, 0xc2}, // PC
+ {0x0325, 0xc2},
{0x3808, 0x05},
- {0x3809, 0x10}, //00
- {0x380a, 0x03},//{DATA_8BITS, {0x380a, 0x02}, //03
- {0x380b, 0x20},//{DATA_8BITS, {0x380b, 0xe0}, //20
- {0x380c, 0x05}, //02
- {0x380d, 0xd0}, //e8
+ {0x3809, 0x10},
+ {0x380a, 0x03},
+ {0x380b, 0x20},
+ {0x380c, 0x02},
+ {0x380d, 0xe8},
{0x380e, 0x03},
{0x380f, 0x80},
{0x3810, 0x00},
- {0x3811, 0x00}, //09
+ {0x3811, 0x00},
{0x3812, 0x00},
- // {DATA_8BITS, {0x3813, 0x08},
- {0x3813, 0x08}, // for demo
-
+ {0x3813, 0x09},
{0x3820, 0x88},
{0x373d, 0x24},
};
@@ -264,7 +254,7 @@ static const char * const ov01a1s_test_pattern_menu[] = {
"Color Bar",
"Top-Bottom Darker Color Bar",
"Right-Left Darker Color Bar",
- "Bottom-Top Darker Color Bar",
+ "Color Bar type 4",
};
static const s64 link_freq_menu_items[] = {
@@ -284,7 +274,7 @@ static const struct ov01a1s_mode supported_modes[] = {
{
.width = 1296,
.height = 800,
- .hts = 1080,
+ .hts = 744,
.vts_def = OV01A1S_VTS_DEF,
.vts_min = OV01A1S_VTS_MIN,
.reg_list = {
@@ -390,7 +380,7 @@ static int ov01a1s_write_reg(struct ov01a1s *ov01a1s, u16 reg, u16 len, u32 val)
}
static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
- const struct ov01a1s_reg_list *r_list)
+ const struct ov01a1s_reg_list *r_list)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov01a1s->sd);
unsigned int i;
@@ -398,7 +388,7 @@ static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
for (i = 0; i < r_list->num_of_regs; i++) {
ret = ov01a1s_write_reg(ov01a1s, r_list->regs[i].address, 1,
- r_list->regs[i].val);
+ r_list->regs[i].val);
if (ret) {
dev_err_ratelimited(&client->dev,
"write reg 0x%4.4x return err = %d",
@@ -412,8 +402,7 @@ static int ov01a1s_write_reg_list(struct ov01a1s *ov01a1s,
static int ov01a1s_update_digital_gain(struct ov01a1s *ov01a1s, u32 d_gain)
{
- // set digital gain
- u32 real = d_gain; // (1024 << 6) = 1X DG
+ u32 real = d_gain;
real = (real << 6);
@@ -423,7 +412,7 @@ static int ov01a1s_update_digital_gain(struct ov01a1s *ov01a1s, u32 d_gain)
static int ov01a1s_test_pattern(struct ov01a1s *ov01a1s, u32 pattern)
{
if (pattern)
- pattern = pattern << OV01A1S_TEST_PATTERN_BAR_SHIFT |
+ pattern = (pattern - 1) << OV01A1S_TEST_PATTERN_BAR_SHIFT |
OV01A1S_TEST_PATTERN_ENABLE;
return ov01a1s_write_reg(ov01a1s, OV01A1S_REG_TEST_PATTERN, 1, pattern);
@@ -455,7 +444,7 @@ static int ov01a1s_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_ANALOG_GAIN, 2,
- ctrl->val << 4);
+ ctrl->val << 4);
break;
case V4L2_CID_DIGITAL_GAIN:
@@ -464,12 +453,12 @@ static int ov01a1s_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_EXPOSURE, 2,
- ctrl->val);
+ ctrl->val);
break;
case V4L2_CID_VBLANK:
ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_VTS, 2,
- ov01a1s->cur_mode->height + ctrl->val);
+ ov01a1s->cur_mode->height + ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
@@ -508,30 +497,31 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
cur_mode = ov01a1s->cur_mode;
size = ARRAY_SIZE(link_freq_menu_items);
- ov01a1s->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov01a1s_ctrl_ops,
- V4L2_CID_LINK_FREQ,
- size - 1, 0,
- link_freq_menu_items);
+ ov01a1s->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &ov01a1s_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ size - 1, 0,
+ link_freq_menu_items);
if (ov01a1s->link_freq)
ov01a1s->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
pixel_rate = to_pixel_rate(OV01A1S_LINK_FREQ_400MHZ_INDEX);
ov01a1s->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0,
- pixel_rate, 1, pixel_rate);
+ V4L2_CID_PIXEL_RATE, 0,
+ pixel_rate, 1, pixel_rate);
vblank_min = cur_mode->vts_min - cur_mode->height;
vblank_max = OV01A1S_VTS_MAX - cur_mode->height;
vblank_default = cur_mode->vts_def - cur_mode->height;
ov01a1s->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
- V4L2_CID_VBLANK, vblank_min,
- vblank_max, 1, vblank_default);
+ V4L2_CID_VBLANK, vblank_min,
+ vblank_max, 1, vblank_default);
h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index);
h_blank -= cur_mode->width;
ov01a1s->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
- V4L2_CID_HBLANK, h_blank, h_blank, 1,
- h_blank);
+ V4L2_CID_HBLANK, h_blank, h_blank,
+ 1, h_blank);
if (ov01a1s->hblank)
ov01a1s->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
@@ -543,10 +533,11 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
OV01A1S_DGTL_GAIN_STEP, OV01A1S_DGTL_GAIN_DEFAULT);
exposure_max = cur_mode->vts_def - OV01A1S_EXPOSURE_MAX_MARGIN;
ov01a1s->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov01a1s_ctrl_ops,
- V4L2_CID_EXPOSURE,
- OV01A1S_EXPOSURE_MIN, exposure_max,
- OV01A1S_EXPOSURE_STEP,
- exposure_max);
+ V4L2_CID_EXPOSURE,
+ OV01A1S_EXPOSURE_MIN,
+ exposure_max,
+ OV01A1S_EXPOSURE_STEP,
+ exposure_max);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov01a1s_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov01a1s_test_pattern_menu) - 1,
@@ -560,7 +551,7 @@ static int ov01a1s_init_controls(struct ov01a1s *ov01a1s)
}
static void ov01a1s_update_pad_format(const struct ov01a1s_mode *mode,
- struct v4l2_mbus_framefmt *fmt)
+ struct v4l2_mbus_framefmt *fmt)
{
fmt->width = mode->width;
fmt->height = mode->height;
@@ -595,7 +586,7 @@ static int ov01a1s_start_streaming(struct ov01a1s *ov01a1s)
return ret;
ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
- OV01A1S_MODE_STREAMING);
+ OV01A1S_MODE_STREAMING);
if (ret)
dev_err(&client->dev, "failed to start streaming");
@@ -605,9 +596,11 @@ static int ov01a1s_start_streaming(struct ov01a1s *ov01a1s)
static void ov01a1s_stop_streaming(struct ov01a1s *ov01a1s)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov01a1s->sd);
+ int ret = 0;
- if (ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
- OV01A1S_MODE_STANDBY))
+ ret = ov01a1s_write_reg(ov01a1s, OV01A1S_REG_MODE_SELECT, 1,
+ OV01A1S_MODE_STANDBY);
+ if (ret)
dev_err(&client->dev, "failed to stop streaming");
}
@@ -684,8 +677,8 @@ static int __maybe_unused ov01a1s_resume(struct device *dev)
}
static int ov01a1s_set_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_format *fmt)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
{
struct ov01a1s *ov01a1s = to_ov01a1s(sd);
const struct ov01a1s_mode *mode;
@@ -724,8 +717,8 @@ 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_format *fmt)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
{
struct ov01a1s *ov01a1s = to_ov01a1s(sd);
@@ -742,8 +735,8 @@ 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_mbus_code_enum *code)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index > 0)
return -EINVAL;
@@ -754,8 +747,8 @@ 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_frame_size_enum *fse)
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
@@ -777,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->pad, 0));
mutex_unlock(&ov01a1s->mutex);
return 0;
@@ -908,7 +901,7 @@ static const struct dev_pm_ops ov01a1s_pm_ops = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id ov01a1s_acpi_ids[] = {
- {"OVTI01AF"}, /* OVTI01AF*/
+ { "OVTI01AF" },
{}
};
@@ -917,7 +910,7 @@ MODULE_DEVICE_TABLE(acpi, ov01a1s_acpi_ids);
static struct i2c_driver ov01a1s_i2c_driver = {
.driver = {
- .name = "ov01a1s", /* ov01a1s*/
+ .name = "ov01a1s",
.pm = &ov01a1s_pm_ops,
.acpi_match_table = ACPI_PTR(ov01a1s_acpi_ids),
},
@@ -927,6 +920,7 @@ static struct i2c_driver ov01a1s_i2c_driver = {
module_i2c_driver(ov01a1s_i2c_driver);
+MODULE_AUTHOR("Xu, Chongyang <chongyang.xu at intel.com>");
MODULE_AUTHOR("Lai, Jim <jim.lai at intel.com>");
MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu at intel.com>");
MODULE_AUTHOR("Shawn Tu <shawnx.tu at intel.com>");
diff --git a/drivers/media/pci/intel/Kconfig b/drivers/media/pci/intel/Kconfig
index eb19872b1df0..8ea99271932b 100644
--- a/drivers/media/pci/intel/Kconfig
+++ b/drivers/media/pci/intel/Kconfig
@@ -30,4 +30,28 @@ config VIDEO_INTEL_IPU6
To compile this driver, say Y here!
endchoice
+config VIDEO_INTEL_IPU_TPG
+ bool "Compile for TPG driver"
+ help
+ If selected, TPG device nodes would be created.
+
+ Recommended for driver developers only.
+
+ If you want to the TPG devices exposed to user as media entity,
+ you must select this option, otherwise no.
+
+config VIDEO_INTEL_IPU_WERROR
+ bool "Force GCC to throw an error instead of a warning when compiling"
+ depends on VIDEO_INTEL_IPU
+ depends on EXPERT
+ depends on !COMPILE_TEST
+ default n
+ help
+ Add -Werror to the build flags for (and only for) intel ipu module.
+ Do not enable this unless you are writing code for the ipu module.
+
+ Recommended for driver developers only.
+
+ If in doubt, say "N".
+
source "drivers/media/pci/intel/ipu3/Kconfig"
diff --git a/drivers/media/pci/intel/ipu-bus.c b/drivers/media/pci/intel/ipu-bus.c
index 3bc7277ae16b..1c671535fe27 100644
--- a/drivers/media/pci/intel/ipu-bus.c
+++ b/drivers/media/pci/intel/ipu-bus.c
@@ -196,6 +196,7 @@ void ipu_bus_del_devices(struct pci_dev *pdev)
mutex_lock(&ipu_bus_mutex);
list_for_each_entry_safe(adev, save, &isp->devices, list) {
+ pm_runtime_disable(&adev->dev);
list_del(&adev->list);
device_unregister(&adev->dev);
}
diff --git a/drivers/media/pci/intel/ipu-buttress.c b/drivers/media/pci/intel/ipu-buttress.c
index 77cf8556dc00..2ee8a9e554b6 100644
--- a/drivers/media/pci/intel/ipu-buttress.c
+++ b/drivers/media/pci/intel/ipu-buttress.c
@@ -39,6 +39,7 @@
#define BUTTRESS_CSE_FWRESET_TIMEOUT 100000
#define BUTTRESS_IPC_TX_TIMEOUT 1000
+#define BUTTRESS_IPC_RESET_TIMEOUT 2000
#define BUTTRESS_IPC_RX_TIMEOUT 1000
#define BUTTRESS_IPC_VALIDITY_TIMEOUT 1000000
#define BUTTRESS_TSC_SYNC_TIMEOUT 5000
@@ -74,8 +75,7 @@ static const u32 ipu_adev_irq_mask[] = {
int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
{
struct ipu_buttress *b = &isp->buttress;
- unsigned long tout_jfs;
- unsigned int tout = 500;
+ unsigned int timeout = BUTTRESS_IPC_RESET_TIMEOUT;
u32 val = 0, csr_in_clr;
if (!isp->secure_mode) {
@@ -91,7 +91,6 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
/* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */
writel(ENTRY, isp->base + ipc->csr_out);
-
/*
* Clear-by-1 all CSR bits EXCEPT following
* bits:
@@ -104,53 +103,43 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID |
BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ | QUERY;
- /*
- * How long we should wait here?
- */
- tout_jfs = jiffies + msecs_to_jiffies(tout);
- do {
+ while (timeout--) {
+ usleep_range(400, 500);
val = readl(isp->base + ipc->csr_in);
- dev_dbg(&isp->pdev->dev, "%s: csr_in = %x\n", __func__, val);
- if (val & ENTRY) {
- if (val & EXIT) {
- dev_dbg(&isp->pdev->dev,
- "%s:%s & %s\n", __func__,
- "IPC_PEER_COMP_ACTIONS_RST_PHASE1",
- "IPC_PEER_COMP_ACTIONS_RST_PHASE2");
- /*
- * 1) Clear-by-1 CSR bits
- * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
- * IPC_PEER_COMP_ACTIONS_RST_PHASE2).
- * 2) Set peer CSR bit
- * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
- */
- writel(ENTRY | EXIT,
- isp->base + ipc->csr_in);
-
- writel(QUERY, isp->base + ipc->csr_out);
-
- tout_jfs = jiffies + msecs_to_jiffies(tout);
- continue;
- } else {
- dev_dbg(&isp->pdev->dev,
- "%s:IPC_PEER_COMP_ACTIONS_RST_PHASE1\n",
- __func__);
- /*
- * 1) Clear-by-1 CSR bits
- * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
- * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE).
- * 2) Set peer CSR bit
- * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
- */
- writel(ENTRY | QUERY,
- isp->base + ipc->csr_in);
-
- writel(ENTRY, isp->base + ipc->csr_out);
-
- tout_jfs = jiffies + msecs_to_jiffies(tout);
- continue;
- }
- } else if (val & EXIT) {
+ switch (val) {
+ case (ENTRY | EXIT):
+ case (ENTRY | EXIT | QUERY):
+ dev_dbg(&isp->pdev->dev,
+ "%s:%s & %s\n", __func__,
+ "IPC_PEER_COMP_ACTIONS_RST_PHASE1",
+ "IPC_PEER_COMP_ACTIONS_RST_PHASE2");
+ /*
+ * 1) Clear-by-1 CSR bits
+ * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
+ * IPC_PEER_COMP_ACTIONS_RST_PHASE2).
+ * 2) Set peer CSR bit
+ * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
+ */
+ writel(ENTRY | EXIT, isp->base + ipc->csr_in);
+ writel(QUERY, isp->base + ipc->csr_out);
+ break;
+ case ENTRY:
+ case ENTRY | QUERY:
+ dev_dbg(&isp->pdev->dev,
+ "%s:IPC_PEER_COMP_ACTIONS_RST_PHASE1\n",
+ __func__);
+ /*
+ * 1) Clear-by-1 CSR bits
+ * (IPC_PEER_COMP_ACTIONS_RST_PHASE1,
+ * IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE).
+ * 2) Set peer CSR bit
+ * IPC_PEER_COMP_ACTIONS_RST_PHASE1.
+ */
+ writel(ENTRY | QUERY, isp->base + ipc->csr_in);
+ writel(ENTRY, isp->base + ipc->csr_out);
+ break;
+ case EXIT:
+ case EXIT | QUERY:
dev_dbg(&isp->pdev->dev,
"%s: IPC_PEER_COMP_ACTIONS_RST_PHASE2\n",
__func__);
@@ -168,30 +157,25 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
* IPC_PEER_COMP_ACTIONS_RST_PHASE2.
*/
writel(EXIT, isp->base + ipc->csr_in);
-
writel(0, isp->base + ipc->db0_in);
-
writel(csr_in_clr, isp->base + ipc->csr_in);
-
writel(EXIT, isp->base + ipc->csr_out);
/*
* Read csr_in again to make sure if RST_PHASE2 is done.
* If csr_in is QUERY, it should be handled again.
*/
- usleep_range(100, 500);
+ usleep_range(200, 300);
val = readl(isp->base + ipc->csr_in);
if (val & QUERY) {
dev_dbg(&isp->pdev->dev,
"%s: RST_PHASE2 retry csr_in = %x\n",
__func__, val);
- continue;
+ break;
}
-
mutex_unlock(&b->ipc_mutex);
-
return 0;
- } else if (val & QUERY) {
+ case QUERY:
dev_dbg(&isp->pdev->dev,
"%s: %s\n", __func__,
"IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE");
@@ -202,17 +186,18 @@ int ipu_buttress_ipc_reset(struct ipu_device *isp, struct ipu_buttress_ipc *ipc)
* IPC_PEER_COMP_ACTIONS_RST_PHASE1
*/
writel(QUERY, isp->base + ipc->csr_in);
-
writel(ENTRY, isp->base + ipc->csr_out);
-
- tout_jfs = jiffies + msecs_to_jiffies(tout);
+ break;
+ default:
+ dev_dbg_ratelimited(&isp->pdev->dev,
+ "%s: unexpected CSR 0x%x\n",
+ __func__, val);
+ break;
}
- usleep_range(100, 500);
- } while (!time_after(jiffies, tout_jfs));
+ }
mutex_unlock(&b->ipc_mutex);
-
- dev_err(&isp->pdev->dev, "Timed out while waiting for CSE!\n");
+ dev_err(&isp->pdev->dev, "Timed out while waiting for CSE\n");
return -ETIMEDOUT;
}
@@ -244,7 +229,7 @@ ipu_buttress_ipc_validity_open(struct ipu_device *isp,
ret = readl_poll_timeout(addr, val, val & mask, 200, tout);
if (ret) {
val = readl(addr);
- dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x!\n", val);
+ dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val);
ipu_buttress_ipc_validity_close(isp, ipc);
}
@@ -346,7 +331,7 @@ static int ipu_buttress_ipc_send_bulk(struct ipu_device *isp,
}
}
- dev_dbg(&isp->pdev->dev, "bulk IPC commands completed\n");
+ dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n");
out:
ipu_buttress_ipc_validity_close(isp, ipc);
@@ -717,10 +702,10 @@ int ipu_buttress_reset_authentication(struct ipu_device *isp)
BUTTRESS_CSE_FWRESET_TIMEOUT);
if (ret) {
dev_err(&isp->pdev->dev,
- "Timed out while resetting authentication state!\n");
+ "Time out while resetting authentication state\n");
} else {
dev_info(&isp->pdev->dev,
- "FW reset for authentication done!\n");
+ "FW reset for authentication done\n");
writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL);
/* leave some time for HW restore */
usleep_range(800, 1000);
@@ -843,7 +828,7 @@ int ipu_buttress_authenticate(struct ipu_device *isp)
(data & mask) == fail), 500,
BUTTRESS_CSE_BOOTLOAD_TIMEOUT);
if (rval) {
- dev_err(&isp->pdev->dev, "CSE boot_load timeout.\n");
+ dev_err(&isp->pdev->dev, "CSE boot_load timeout\n");
goto iunit_power_off;
}
@@ -858,7 +843,7 @@ int ipu_buttress_authenticate(struct ipu_device *isp)
data, data == BOOTLOADER_MAGIC_KEY, 500,
BUTTRESS_CSE_BOOTLOAD_TIMEOUT);
if (rval) {
- dev_err(&isp->pdev->dev, "Expect magic number timeout 0x%x.\n",
+ dev_err(&isp->pdev->dev, "Expect magic number timeout 0x%x\n",
data);
goto iunit_power_off;
}
@@ -918,7 +903,7 @@ static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
val = readl(isp->base + BUTTRESS_REG_PWR_STATE);
val = (val & mask) >> shift;
if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) {
- dev_err(&isp->pdev->dev, "Start tsc sync failed!\n");
+ dev_err(&isp->pdev->dev, "Start tsc sync failed\n");
return -EINVAL;
}
@@ -927,7 +912,7 @@ static int ipu_buttress_send_tsc_request(struct ipu_device *isp)
((val & mask) >> shift == done), 500,
BUTTRESS_TSC_SYNC_TIMEOUT);
if (ret)
- dev_err(&isp->pdev->dev, "Start tsc sync timeout!\n");
+ dev_err(&isp->pdev->dev, "Start tsc sync timeout\n");
return ret;
}
@@ -955,7 +940,7 @@ int ipu_buttress_start_tsc_sync(struct ipu_device *isp)
return ret;
}
- dev_err(&isp->pdev->dev, "TSC sync failed(timeout).\n");
+ dev_err(&isp->pdev->dev, "TSC sync failed(timeout)\n");
return -ETIMEDOUT;
}
@@ -1440,7 +1425,7 @@ int ipu_buttress_init(struct ipu_device *isp)
ipu_buttress_set_secure_mode(isp);
isp->secure_mode = ipu_buttress_get_secure_mode(isp);
if (isp->secure_mode != secure_mode_enable)
- dev_warn(&isp->pdev->dev, "Unable to set secure mode!\n");
+ dev_warn(&isp->pdev->dev, "Unable to set secure mode\n");
dev_info(&isp->pdev->dev, "IPU in %s mode\n",
isp->secure_mode ? "secure" : "non-secure");
@@ -1477,10 +1462,10 @@ int ipu_buttress_init(struct ipu_device *isp)
do {
rval = ipu_buttress_ipc_reset(isp, &b->cse);
if (rval) {
- dev_err(&isp->pdev->dev,
- "IPC reset protocol failed, retry!\n");
+ dev_warn(&isp->pdev->dev,
+ "IPC reset protocol failed, retrying\n");
} else {
- dev_dbg(&isp->pdev->dev, "IPC reset completed!\n");
+ dev_info(&isp->pdev->dev, "IPC reset done\n");
return 0;
}
} while (ipc_reset_retry--);
diff --git a/drivers/media/pci/intel/ipu-isys-csi2.c b/drivers/media/pci/intel/ipu-isys-csi2.c
index 4838537b0c40..bf0aba76c6ae 100644
--- a/drivers/media/pci/intel/ipu-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu-isys-csi2.c
@@ -595,12 +595,15 @@ void ipu_isys_csi2_eof_event(struct ipu_isys_csi2 *csi2)
if (ip) {
frame_sequence = atomic_read(&ip->sequence);
+ spin_unlock_irqrestore(&csi2->isys->lock, flags);
- spin_unlock_irqrestore(&csi2->isys->lock, flags);
-
- dev_dbg(&csi2->isys->adev->dev, "eof_event::csi2-%i sequence: %i\n",
- csi2->index, frame_sequence);
+ dev_dbg(&csi2->isys->adev->dev,
+ "eof_event::csi2-%i sequence: %i\n",
+ csi2->index, frame_sequence);
+ return;
}
+
+ spin_unlock_irqrestore(&csi2->isys->lock, flags);
}
/* Call this function only _after_ the sensor has been stopped */
diff --git a/drivers/media/pci/intel/ipu-isys-queue.c b/drivers/media/pci/intel/ipu-isys-queue.c
index 46d29d311098..10498dddaf09 100644
--- a/drivers/media/pci/intel/ipu-isys-queue.c
+++ b/drivers/media/pci/intel/ipu-isys-queue.c
@@ -359,14 +359,9 @@ ipu_isys_buffer_to_fw_frame_buff(struct ipu_fw_isys_frame_buff_set_abi *set,
set->send_irq_sof = 1;
set->send_resp_sof = 1;
-
set->send_irq_eof = 0;
set->send_resp_eof = 0;
- /*
- * In tpg case, the stream start timeout if the capture ack irq
- * disabled. So keep it active while starting the stream, then close
- * it after the stream start succeed.
- */
+
if (ip->streaming)
set->send_irq_capture_ack = 0;
else
diff --git a/drivers/media/pci/intel/ipu-isys-video.c b/drivers/media/pci/intel/ipu-isys-video.c
index 709f1aa6dfad..a4088b30c144 100644
--- a/drivers/media/pci/intel/ipu-isys-video.c
+++ b/drivers/media/pci/intel/ipu-isys-video.c
@@ -508,7 +508,9 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
static bool is_external(struct ipu_isys_video *av, struct media_entity *entity)
{
struct v4l2_subdev *sd;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
unsigned int i;
+#endif
/* All video nodes are ours. */
if (!is_media_entity_v4l2_subdev(entity))
@@ -519,10 +521,12 @@ static bool is_external(struct ipu_isys_video *av, struct media_entity *entity)
strlen(IPU_ISYS_ENTITY_PREFIX)) != 0)
return true;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
for (i = 0; i < av->isys->pdata->ipdata->tpg.ntpgs &&
av->isys->tpg[i].isys; i++)
if (entity == &av->isys->tpg[i].asd.sd.entity)
return true;
+#endif
return false;
}
@@ -922,9 +926,11 @@ static int start_stream_firmware(struct ipu_isys_video *av,
if (ip->csi2 && !v4l2_ctrl_g_ctrl(ip->csi2->store_csi2_header))
stream_cfg->input_pins[0].mipi_store_mode =
IPU_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
else if (ip->tpg && !v4l2_ctrl_g_ctrl(ip->tpg->store_csi2_header))
stream_cfg->input_pins[0].mipi_store_mode =
IPU_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER;
+#endif
stream_cfg->src = ip->source;
stream_cfg->vc = 0;
@@ -1238,7 +1244,9 @@ int ipu_isys_video_prepare_streaming(struct ipu_isys_video *av,
ip->csi2_be = NULL;
ip->csi2_be_soc = NULL;
ip->csi2 = NULL;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
ip->tpg = NULL;
+#endif
ip->seq_index = 0;
memset(ip->seq, 0, sizeof(ip->seq));
diff --git a/drivers/media/pci/intel/ipu-isys-video.h b/drivers/media/pci/intel/ipu-isys-video.h
index ebfc30a5fae9..455b534b41f7 100644
--- a/drivers/media/pci/intel/ipu-isys-video.h
+++ b/drivers/media/pci/intel/ipu-isys-video.h
@@ -54,7 +54,10 @@ struct ipu_isys_pipeline {
struct ipu_isys_csi2_be *csi2_be;
struct ipu_isys_csi2_be_soc *csi2_be_soc;
struct ipu_isys_csi2 *csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
struct ipu_isys_tpg *tpg;
+#endif
+
/*
* Number of capture queues, write access serialised using struct
* ipu_isys.stream_mutex
diff --git a/drivers/media/pci/intel/ipu-isys.c b/drivers/media/pci/intel/ipu-isys.c
index c1657ed95599..69043915fd43 100644
--- a/drivers/media/pci/intel/ipu-isys.c
+++ b/drivers/media/pci/intel/ipu-isys.c
@@ -29,7 +29,9 @@
#include "ipu-dma.h"
#include "ipu-isys.h"
#include "ipu-isys-csi2.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
#include "ipu-isys-tpg.h"
+#endif
#include "ipu-isys-video.h"
#include "ipu-platform-regs.h"
#include "ipu-buttress.h"
@@ -45,7 +47,7 @@
/* LTR & DID value are 10 bit at most */
#define LTR_DID_VAL_MAX 1023
-#define LTR_DEFAULT_VALUE 0x64503C19
+#define LTR_DEFAULT_VALUE 0x70503C19
#define FILL_TIME_DEFAULT_VALUE 0xFFF0783C
#define LTR_DID_PKGC_2R 20
#define LTR_DID_PKGC_8 100
@@ -131,8 +133,10 @@ isys_complete_ext_device_registration(struct ipu_isys *isys,
static void isys_unregister_subdevices(struct ipu_isys *isys)
{
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
const struct ipu_isys_internal_tpg_pdata *tpg =
&isys->pdata->ipdata->tpg;
+#endif
const struct ipu_isys_internal_csi2_pdata *csi2 =
&isys->pdata->ipdata->csi2;
unsigned int i;
@@ -141,8 +145,10 @@ static void isys_unregister_subdevices(struct ipu_isys *isys)
for (i = 0; i < NR_OF_CSI2_BE_SOC_DEV; i++)
ipu_isys_csi2_be_soc_cleanup(&isys->csi2_be_soc[i]);
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
for (i = 0; i < tpg->ntpgs; i++)
ipu_isys_tpg_cleanup(&isys->tpg[i]);
+#endif
for (i = 0; i < csi2->nports; i++)
ipu_isys_csi2_cleanup(&isys->csi2[i]);
@@ -150,8 +156,10 @@ static void isys_unregister_subdevices(struct ipu_isys *isys)
static int isys_register_subdevices(struct ipu_isys *isys)
{
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
const struct ipu_isys_internal_tpg_pdata *tpg =
&isys->pdata->ipdata->tpg;
+#endif
const struct ipu_isys_internal_csi2_pdata *csi2 =
&isys->pdata->ipdata->csi2;
struct ipu_isys_csi2_be_soc *csi2_be_soc;
@@ -175,6 +183,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
isys->isr_csi2_bits |= IPU_ISYS_UNISPART_IRQ_CSI2(i);
}
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
isys->tpg = devm_kcalloc(&isys->adev->dev, tpg->ntpgs,
sizeof(*isys->tpg), GFP_KERNEL);
if (!isys->tpg) {
@@ -191,6 +200,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
if (rval)
goto fail;
}
+#endif
for (k = 0; k < NR_OF_CSI2_BE_SOC_DEV; k++) {
rval = ipu_isys_csi2_be_soc_init(&isys->csi2_be_soc[k],
@@ -234,6 +244,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
}
}
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
for (i = 0; i < tpg->ntpgs; i++) {
rval = media_create_pad_link(&isys->tpg[i].asd.sd.entity,
TPG_PAD_SOURCE,
@@ -259,6 +270,7 @@ static int isys_register_subdevices(struct ipu_isys *isys)
}
}
}
+#endif
return 0;
@@ -349,6 +361,8 @@ static void set_iwake_ltrdid(struct ipu_isys *isys,
fc.bits.ltr_scale = ltr_scale;
fc.bits.did_val = did_val;
fc.bits.did_scale = 2;
+ dev_dbg(&isys->adev->dev,
+ "%s ltr: %d did: %d", __func__, ltr_val, did_val);
writel(fc.value, isp->base + IPU_BUTTRESS_FABIC_CONTROL);
}
@@ -379,7 +393,8 @@ void update_watermark_setting(struct ipu_isys *isys)
struct video_stream_watermark *p_watermark;
struct ltr_did ltrdid;
u16 calc_fill_time_us = 0;
- u16 ltr, did;
+ u16 ltr = 0;
+ u16 did = 0;
u32 iwake_threshold, iwake_critical_threshold;
u64 threshold_bytes;
u64 isys_pb_datarate_mbs = 0;
@@ -411,6 +426,7 @@ void update_watermark_setting(struct ipu_isys *isys)
mutex_unlock(&iwake_watermark->mutex);
if (!isys_pb_datarate_mbs) {
+ enable_iwake(isys, false);
set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
mutex_lock(&iwake_watermark->mutex);
set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
@@ -448,6 +464,8 @@ void update_watermark_setting(struct ipu_isys *isys)
iwake_critical_threshold = iwake_threshold +
(IS_PIXEL_BUFFER_PAGES - iwake_threshold) / 2;
+ dev_dbg(&isys->adev->dev, "%s threshold: %u critical: %u",
+ __func__, iwake_threshold, iwake_critical_threshold);
set_iwake_ltrdid(isys, ltr, did, LTR_IWAKE_ON);
mutex_lock(&iwake_watermark->mutex);
set_iwake_register(isys,
@@ -569,11 +587,17 @@ static int isys_notifier_init(struct ipu_isys *isys)
asd_struct_size,
isys_fwnode_parse);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(&isys->adev->dev,
+ "v4l2 parse_fwnode_endpoints() failed: %d\n", ret);
return ret;
+ }
- if (list_empty(&isys->notifier.asd_list))
- return -ENODEV; /* no endpoint */
+ if (list_empty(&isys->notifier.asd_list)) {
+ /* isys probe could continue with async subdevs missing */
+ dev_warn(&isys->adev->dev, "no subdev found in graph\n");
+ return 0;
+ }
isys->notifier.ops = &isys_async_ops;
ret = v4l2_async_notifier_register(&isys->v4l2_dev, &isys->notifier);
@@ -586,6 +610,12 @@ static int isys_notifier_init(struct ipu_isys *isys)
return ret;
}
+static void isys_notifier_cleanup(struct ipu_isys *isys)
+{
+ v4l2_async_notifier_unregister(&isys->notifier);
+ v4l2_async_notifier_cleanup(&isys->notifier);
+}
+
static struct media_device_ops isys_mdev_ops = {
.link_notify = v4l2_pipeline_link_notify,
};
@@ -622,15 +652,19 @@ static int isys_register_devices(struct ipu_isys *isys)
rval = isys_register_subdevices(isys);
if (rval)
goto out_v4l2_device_unregister;
+
rval = isys_notifier_init(isys);
if (rval)
goto out_isys_unregister_subdevices;
rval = v4l2_device_register_subdev_nodes(&isys->v4l2_dev);
if (rval)
- goto out_isys_unregister_subdevices;
+ goto out_isys_notifier_cleanup;
return 0;
+out_isys_notifier_cleanup:
+ isys_notifier_cleanup(isys);
+
out_isys_unregister_subdevices:
isys_unregister_subdevices(isys);
@@ -774,6 +808,7 @@ static void isys_remove(struct ipu_bus_device *adev)
isys_iwake_watermark_cleanup(isys);
ipu_trace_uninit(&adev->dev);
+ isys_notifier_cleanup(isys);
isys_unregister_devices(isys);
pm_qos_remove_request(&isys->pm_qos);
@@ -1326,9 +1361,11 @@ int isys_isr_one(struct ipu_bus_device *adev)
if (pipe->csi2)
ipu_isys_csi2_sof_event(pipe->csi2);
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
#ifdef IPU_TPG_FRAME_SYNC
if (pipe->tpg)
ipu_isys_tpg_sof_event(pipe->tpg);
+#endif
#endif
pipe->seq[pipe->seq_index].sequence =
atomic_read(&pipe->sequence) - 1;
@@ -1344,9 +1381,11 @@ int isys_isr_one(struct ipu_bus_device *adev)
if (pipe->csi2)
ipu_isys_csi2_eof_event(pipe->csi2);
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
#ifdef IPU_TPG_FRAME_SYNC
if (pipe->tpg)
ipu_isys_tpg_eof_event(pipe->tpg);
+#endif
#endif
dev_dbg(&adev->dev,
diff --git a/drivers/media/pci/intel/ipu-isys.h b/drivers/media/pci/intel/ipu-isys.h
index 5d82b934b453..343f0d773b9d 100644
--- a/drivers/media/pci/intel/ipu-isys.h
+++ b/drivers/media/pci/intel/ipu-isys.h
@@ -16,7 +16,9 @@
#include "ipu-isys-media.h"
#include "ipu-isys-csi2.h"
#include "ipu-isys-csi2-be.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
#include "ipu-isys-tpg.h"
+#endif
#include "ipu-isys-video.h"
#include "ipu-pdata.h"
#include "ipu-fw-isys.h"
@@ -131,7 +133,9 @@ struct ipu_isys_sensor_info {
* @lib_mutex: optional external library mutex
* @pdata: platform data pointer
* @csi2: CSI-2 receivers
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
* @tpg: test pattern generators
+#endif
* @csi2_be: CSI-2 back-ends
* @fw: ISYS firmware binary (unsecure firmware)
* @fw_sgt: fw scatterlist
@@ -171,7 +175,9 @@ struct ipu_isys {
struct ipu_isys_pdata *pdata;
struct ipu_isys_csi2 *csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
struct ipu_isys_tpg *tpg;
+#endif
struct ipu_isys_csi2_be csi2_be;
struct ipu_isys_csi2_be_soc csi2_be_soc[NR_OF_CSI2_BE_SOC_DEV];
const struct firmware *fw;
diff --git a/drivers/media/pci/intel/ipu-pdata.h b/drivers/media/pci/intel/ipu-pdata.h
index 575899746323..3dd7205994b4 100644
--- a/drivers/media/pci/intel/ipu-pdata.h
+++ b/drivers/media/pci/intel/ipu-pdata.h
@@ -207,11 +207,13 @@ struct ipu_isys_internal_csi2_pdata {
unsigned int *offsets;
};
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
struct ipu_isys_internal_tpg_pdata {
unsigned int ntpgs;
unsigned int *offsets;
unsigned int *sels;
};
+#endif
/*
* One place to handle all the IPU HW variations
@@ -228,7 +230,9 @@ struct ipu_hw_variants {
struct ipu_isys_internal_pdata {
struct ipu_isys_internal_csi2_pdata csi2;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
struct ipu_isys_internal_tpg_pdata tpg;
+#endif
struct ipu_hw_variants hw_variant;
u32 num_parallel_streams;
u32 isys_dma_overshoot;
diff --git a/drivers/media/pci/intel/ipu-psys.c b/drivers/media/pci/intel/ipu-psys.c
index c8370659d61a..904884f244b3 100644
--- a/drivers/media/pci/intel/ipu-psys.c
+++ b/drivers/media/pci/intel/ipu-psys.c
@@ -105,8 +105,8 @@ struct ipu_psys_pg *__get_pg_buf(struct ipu_psys *psys, size_t pg_size)
return kpg;
}
-static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
- struct ipu_psys_kbuffer *kbuf);
+static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh,
+ struct ipu_psys_kbuffer *kbuf);
struct ipu_psys_kbuffer *ipu_psys_lookup_kbuffer(struct ipu_psys_fh *fh, int fd)
{
struct ipu_psys_kbuffer *kbuf;
@@ -436,6 +436,27 @@ static int ipu_psys_open(struct inode *inode, struct file *file)
return rval;
}
+static inline void ipu_psys_kbuf_unmap(struct ipu_psys_kbuffer *kbuf)
+{
+ if (!kbuf)
+ return;
+
+ kbuf->valid = false;
+ if (kbuf->kaddr)
+ dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
+ if (kbuf->sgt)
+ dma_buf_unmap_attachment(kbuf->db_attach,
+ kbuf->sgt,
+ DMA_BIDIRECTIONAL);
+ if (kbuf->db_attach)
+ dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
+ dma_buf_put(kbuf->dbuf);
+
+ kbuf->db_attach = NULL;
+ kbuf->dbuf = NULL;
+ kbuf->sgt = NULL;
+}
+
static int ipu_psys_release(struct inode *inode, struct file *file)
{
struct ipu_psys *psys = inode_to_ipu_psys(inode);
@@ -452,19 +473,8 @@ static int ipu_psys_release(struct inode *inode, struct file *file)
/* Unmap and release buffers */
if (kbuf->dbuf && db_attach) {
- struct dma_buf *dbuf;
-
- kbuf->valid = false;
- dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
- dma_buf_unmap_attachment(db_attach,
- kbuf->sgt,
- DMA_BIDIRECTIONAL);
- dma_buf_detach(kbuf->dbuf, db_attach);
- dbuf = kbuf->dbuf;
- kbuf->dbuf = NULL;
- db_attach = NULL;
- kbuf->db_attach = NULL;
- dma_buf_put(dbuf);
+
+ ipu_psys_kbuf_unmap(kbuf);
} else {
if (db_attach)
ipu_psys_put_userpages(db_attach->priv);
@@ -536,10 +546,10 @@ static int ipu_psys_getbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh)
kbuf->flags = buf->flags |= IPU_BUFFER_FLAG_DMA_HANDLE;
mutex_lock(&fh->mutex);
- list_add_tail(&kbuf->list, &fh->bufmap);
+ list_add(&kbuf->list, &fh->bufmap);
mutex_unlock(&fh->mutex);
- dev_dbg(&psys->adev->dev, "IOC_GETBUF: userptr %p size %lu to fd %d",
+ dev_dbg(&psys->adev->dev, "IOC_GETBUF: userptr %p size %llu to fd %d",
buf->base.userptr, buf->len, buf->base.fd);
return 0;
@@ -550,8 +560,8 @@ static int ipu_psys_putbuf(struct ipu_psys_buffer *buf, struct ipu_psys_fh *fh)
return 0;
}
-int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
- struct ipu_psys_kbuffer *kbuf)
+int ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh,
+ struct ipu_psys_kbuffer *kbuf)
{
struct ipu_psys *psys = fh->psys;
struct dma_buf *dbuf;
@@ -567,10 +577,12 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
* add this kbuf to bufmap list.
*/
kbuf = kzalloc(sizeof(*kbuf), GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto mapbuf_fail;
+ }
- list_add_tail(&kbuf->list, &fh->bufmap);
+ list_add(&kbuf->list, &fh->bufmap);
}
/* fd valid and found, need remap */
@@ -578,17 +590,19 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
dev_dbg(&psys->adev->dev,
"dmabuf fd %d with kbuf %p changed, need remap.\n",
fd, kbuf);
- ret = ipu_psys_unmapbuf_with_lock(fd, fh, kbuf);
+ ret = ipu_psys_unmapbuf_locked(fd, fh, kbuf);
if (ret)
- return ret;
+ goto mapbuf_fail;
kbuf = ipu_psys_lookup_kbuffer(fh, fd);
/* changed external dmabuf */
if (!kbuf) {
kbuf = kzalloc(sizeof(*kbuf), GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
- list_add_tail(&kbuf->list, &fh->bufmap);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto mapbuf_fail;
+ }
+ list_add(&kbuf->list, &fh->bufmap);
}
}
@@ -608,15 +622,16 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
kbuf->db_attach = dma_buf_attach(kbuf->dbuf, &psys->adev->dev);
if (IS_ERR(kbuf->db_attach)) {
ret = PTR_ERR(kbuf->db_attach);
- goto error_put;
+ dev_dbg(&psys->adev->dev, "dma buf attach failed\n");
+ goto kbuf_map_fail;
}
kbuf->sgt = dma_buf_map_attachment(kbuf->db_attach, DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(kbuf->sgt)) {
ret = -EINVAL;
kbuf->sgt = NULL;
- dev_dbg(&psys->adev->dev, "map attachment failed\n");
- goto error_detach;
+ dev_dbg(&psys->adev->dev, "dma buf map attachment failed\n");
+ goto kbuf_map_fail;
}
kbuf->dma_addr = sg_dma_address(kbuf->sgt->sgl);
@@ -624,10 +639,11 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
kbuf->kaddr = dma_buf_vmap(kbuf->dbuf);
if (!kbuf->kaddr) {
ret = -EINVAL;
- goto error_unmap;
+ dev_dbg(&psys->adev->dev, "dma buf vmap failed\n");
+ goto kbuf_map_fail;
}
- dev_dbg(&psys->adev->dev, "%s kbuf %p fd %d with len %lu mapped\n",
+ dev_dbg(&psys->adev->dev, "%s kbuf %p fd %d with len %llu mapped\n",
__func__, kbuf, fd, kbuf->len);
mapbuf_end:
@@ -635,20 +651,18 @@ int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
return 0;
-error_unmap:
- dma_buf_unmap_attachment(kbuf->db_attach, kbuf->sgt, DMA_BIDIRECTIONAL);
-error_detach:
- dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
- kbuf->db_attach = NULL;
-error_put:
- list_del(&kbuf->list);
+kbuf_map_fail:
+ ipu_psys_kbuf_unmap(kbuf);
+ list_del(&kbuf->list);
if (!kbuf->userptr)
kfree(kbuf);
+ return ret;
+mapbuf_fail:
dma_buf_put(dbuf);
- dev_err(&psys->adev->dev, "%s failed\n", __func__);
+ dev_err(&psys->adev->dev, "%s failed for fd %d\n", __func__, fd);
return ret;
}
@@ -659,7 +673,7 @@ static long ipu_psys_mapbuf(int fd, struct ipu_psys_fh *fh)
mutex_lock(&fh->mutex);
kbuf = ipu_psys_lookup_kbuffer(fh, fd);
- ret = ipu_psys_mapbuf_with_lock(fd, fh, kbuf);
+ ret = ipu_psys_mapbuf_locked(fd, fh, kbuf);
mutex_unlock(&fh->mutex);
dev_dbg(&fh->psys->adev->dev, "IOC_MAPBUF ret %ld\n", ret);
@@ -667,11 +681,10 @@ static long ipu_psys_mapbuf(int fd, struct ipu_psys_fh *fh)
return ret;
}
-static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
- struct ipu_psys_kbuffer *kbuf)
+static int ipu_psys_unmapbuf_locked(int fd, struct ipu_psys_fh *fh,
+ struct ipu_psys_kbuffer *kbuf)
{
struct ipu_psys *psys = fh->psys;
- struct dma_buf *dmabuf;
if (!kbuf || fd != kbuf->fd) {
dev_err(&psys->adev->dev, "invalid kbuffer\n");
@@ -679,26 +692,13 @@ static int ipu_psys_unmapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
}
/* From now on it is not safe to use this kbuffer */
- kbuf->valid = false;
-
- dma_buf_vunmap(kbuf->dbuf, kbuf->kaddr);
- dma_buf_unmap_attachment(kbuf->db_attach, kbuf->sgt, DMA_BIDIRECTIONAL);
-
- dma_buf_detach(kbuf->dbuf, kbuf->db_attach);
-
- dmabuf = kbuf->dbuf;
-
- kbuf->db_attach = NULL;
- kbuf->dbuf = NULL;
- kbuf->sgt = NULL;
+ ipu_psys_kbuf_unmap(kbuf);
list_del(&kbuf->list);
if (!kbuf->userptr)
kfree(kbuf);
- dma_buf_put(dmabuf);
-
dev_dbg(&psys->adev->dev, "%s fd %d unmapped\n", __func__, fd);
return 0;
@@ -717,7 +717,7 @@ static long ipu_psys_unmapbuf(int fd, struct ipu_psys_fh *fh)
mutex_unlock(&fh->mutex);
return -EINVAL;
}
- ret = ipu_psys_unmapbuf_with_lock(fd, fh, kbuf);
+ ret = ipu_psys_unmapbuf_locked(fd, fh, kbuf);
mutex_unlock(&fh->mutex);
dev_dbg(&fh->psys->adev->dev, "IOC_UNMAPBUF\n");
@@ -1500,15 +1500,6 @@ static void ipu_psys_remove(struct ipu_bus_device *adev)
if (psys->fwcom && ipu_fw_com_release(psys->fwcom, 1))
dev_err(&adev->dev, "fw com release failed.\n");
- isp->pkg_dir = NULL;
- isp->pkg_dir_dma_addr = 0;
- isp->pkg_dir_size = 0;
-
- ipu_cpd_free_pkg_dir(adev, psys->pkg_dir,
- psys->pkg_dir_dma_addr, psys->pkg_dir_size);
-
- ipu_buttress_unmap_fw_image(adev, &psys->fw_sgt);
-
kfree(psys->server_init);
kfree(psys->syscom_config);
@@ -1538,13 +1529,8 @@ static irqreturn_t psys_isr_threaded(struct ipu_bus_device *adev)
mutex_lock(&psys->mutex);
#ifdef CONFIG_PM
- if (!READ_ONCE(psys->power)) {
- mutex_unlock(&psys->mutex);
- return IRQ_NONE;
- }
- r = pm_runtime_get_sync(&psys->adev->dev);
- if (r < 0) {
- pm_runtime_put(&psys->adev->dev);
+ r = pm_runtime_get_if_in_use(&psys->adev->dev);
+ if (!r || WARN_ON_ONCE(r < 0)) {
mutex_unlock(&psys->mutex);
return IRQ_NONE;
}
diff --git a/drivers/media/pci/intel/ipu-psys.h b/drivers/media/pci/intel/ipu-psys.h
index b227c2bc7415..61ff388f8458 100644
--- a/drivers/media/pci/intel/ipu-psys.h
+++ b/drivers/media/pci/intel/ipu-psys.h
@@ -202,8 +202,8 @@ 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);
-int ipu_psys_mapbuf_with_lock(int fd, struct ipu_psys_fh *fh,
- struct ipu_psys_kbuffer *kbuf);
+int ipu_psys_mapbuf_locked(int fd, struct ipu_psys_fh *fh,
+ struct ipu_psys_kbuffer *kbuf);
struct ipu_psys_kbuffer *
ipu_psys_lookup_kbuffer_by_kaddr(struct ipu_psys_fh *fh, void *kaddr);
#ifdef IPU_PSYS_GPC
diff --git a/drivers/media/pci/intel/ipu.c b/drivers/media/pci/intel/ipu.c
index 18b1ba01ebd6..84f301c72571 100644
--- a/drivers/media/pci/intel/ipu.c
+++ b/drivers/media/pci/intel/ipu.c
@@ -598,6 +598,15 @@ static void ipu_pci_remove(struct pci_dev *pdev)
#endif
ipu_trace_release(isp);
+ ipu_cpd_free_pkg_dir(isp->psys, isp->pkg_dir, isp->pkg_dir_dma_addr,
+ isp->pkg_dir_size);
+
+ ipu_buttress_unmap_fw_image(isp->psys, &isp->fw_sgt);
+
+ isp->pkg_dir = NULL;
+ isp->pkg_dir_dma_addr = 0;
+ isp->pkg_dir_size = 0;
+
ipu_bus_del_devices(pdev);
pm_runtime_forbid(&pdev->dev);
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 0c45215ad991..d845028191e8 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -31,8 +31,11 @@ intel-ipu6-isys-objs += ../ipu-isys.o \
../ipu-fw-isys.o \
../ipu-isys-video.o \
../ipu-isys-queue.o \
- ../ipu-isys-subdev.o \
- ../ipu-isys-tpg.o
+ ../ipu-isys-subdev.o
+
+ifdef CONFIG_VIDEO_INTEL_IPU_TPG
+intel-ipu6-isys-objs += ../ipu-isys-tpg.o
+endif
obj-$(CONFIG_VIDEO_INTEL_IPU) += intel-ipu6-isys.o
diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-psys.h b/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
index e8483e9a325b..5573e617d2b9 100644
--- a/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
+++ b/drivers/media/pci/intel/ipu6/ipu-platform-psys.h
@@ -69,7 +69,7 @@ struct ipu_psys_buffer_set {
};
int ipu_psys_kcmd_start(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd);
-void ipu_psys_kcmd_complete(struct ipu_psys *psys, struct ipu_psys_kcmd *kcmd,
+void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg, struct ipu_psys_kcmd *kcmd,
int error);
int ipu_psys_fh_init(struct ipu_psys_fh *fh);
int ipu_psys_fh_deinit(struct ipu_psys_fh *fh);
diff --git a/drivers/media/pci/intel/ipu6/ipu-platform-resources.h b/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
index 642c5c6ca6c1..f59d5fa86b01 100644
--- a/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
+++ b/drivers/media/pci/intel/ipu6/ipu-platform-resources.h
@@ -81,6 +81,10 @@ int ipu_psys_try_allocate_resources(struct device *dev,
void *pg_manifest,
struct ipu_psys_resource_pool *pool);
+void ipu_psys_reset_process_cell(const struct device *dev,
+ struct ipu_fw_psys_process_group *pg,
+ void *pg_manifest,
+ int process_count);
void ipu_psys_free_resources(struct ipu_psys_resource_alloc *alloc,
struct ipu_psys_resource_pool *pool);
diff --git a/drivers/media/pci/intel/ipu6/ipu-resources.c b/drivers/media/pci/intel/ipu6/ipu-resources.c
index e5932287b7f3..418dd55c1e3a 100644
--- a/drivers/media/pci/intel/ipu6/ipu-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu-resources.c
@@ -19,7 +19,6 @@ void ipu6_psys_hw_res_variant_init(void)
hw_var.queue_num = IPU6SE_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
hw_var.cell_num = IPU6SE_FW_PSYS_N_CELL_ID;
hw_var.set_proc_dev_chn = ipu6se_fw_psys_set_proc_dev_chn;
- hw_var.set_proc_dev_chn = ipu6se_fw_psys_set_proc_dev_chn;
hw_var.set_proc_dfm_bitmap = ipu6se_fw_psys_set_proc_dfm_bitmap;
hw_var.set_proc_ext_mem = ipu6se_fw_psys_set_process_ext_mem;
hw_var.get_pgm_by_proc =
@@ -29,7 +28,6 @@ void ipu6_psys_hw_res_variant_init(void)
hw_var.queue_num = IPU6_FW_PSYS_N_PSYS_CMD_QUEUE_ID;
hw_var.cell_num = IPU6_FW_PSYS_N_CELL_ID;
hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn;
- hw_var.set_proc_dev_chn = ipu6_fw_psys_set_proc_dev_chn;
hw_var.set_proc_dfm_bitmap = ipu6_fw_psys_set_proc_dfm_bitmap;
hw_var.set_proc_ext_mem = ipu6_fw_psys_set_process_ext_mem;
hw_var.get_pgm_by_proc =
@@ -142,7 +140,7 @@ 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)
{
@@ -173,12 +171,14 @@ int ipu_psys_resource_pool_init(struct ipu_psys_resource_pool
goto dfm_error;
}
+ spin_lock(&cq_bitmap_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);
return 0;
@@ -399,13 +399,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);
/* find available cmd queue from ppg0_cmd_id */
p = bitmap_find_next_zero_area(pool->cmd_queues, size, start, 1, 0);
- if (p >= size)
+ if (p >= size) {
+ spin_unlock(&cq_bitmap_lock);
return -ENOSPC;
+ }
bitmap_set(pool->cmd_queues, p, 1);
+ spin_unlock(&cq_bitmap_lock);
return p;
}
@@ -413,7 +417,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);
bitmap_clear(pool->cmd_queues, queue_id, 1);
+ spin_unlock(&cq_bitmap_lock);
}
int ipu_psys_try_allocate_resources(struct device *dev,
@@ -706,32 +712,8 @@ int ipu_psys_allocate_resources(const struct device *dev,
return 0;
free_out:
- for (; i >= 0; i--) {
- struct ipu_fw_psys_process *process =
- (struct ipu_fw_psys_process *)
- ((char *)pg + process_offset_table[i]);
- struct ipu_fw_generic_program_manifest pm;
- int retval;
-
- if (!process)
- break;
-
- retval = ipu_fw_psys_get_program_manifest_by_process
- (&pm, pg_manifest, process);
- if (retval < 0) {
- dev_err(dev, "can not get manifest\n");
- break;
- }
- if ((pm.cell_id != res_defs->num_cells &&
- pm.cell_type_id == res_defs->num_cells_type))
- continue;
- /* no return value check here because if finding free cell
- * failed, process cell would not set then calling clear_cell
- * will return non-zero.
- */
- ipu_fw_psys_clear_process_cell(process);
- }
dev_err(dev, "failed to allocate resources, ret %d\n", ret);
+ ipu_psys_reset_process_cell(dev, pg, pg_manifest, i + 1);
ipu_psys_free_resources(alloc, pool);
return ret;
}
@@ -825,6 +807,48 @@ int ipu_psys_move_resources(const struct device *dev,
return 0;
}
+void ipu_psys_reset_process_cell(const struct device *dev,
+ struct ipu_fw_psys_process_group *pg,
+ void *pg_manifest,
+ int process_count)
+{
+ int i;
+ u16 *process_offset_table;
+ const struct ipu_fw_resource_definitions *res_defs;
+
+ if (!pg)
+ return;
+
+ res_defs = get_res();
+ process_offset_table = (u16 *)((u8 *)pg + pg->processes_offset);
+ for (i = 0; i < process_count; i++) {
+ struct ipu_fw_psys_process *process =
+ (struct ipu_fw_psys_process *)
+ ((char *)pg + process_offset_table[i]);
+ struct ipu_fw_generic_program_manifest pm;
+ int ret;
+
+ if (!process)
+ break;
+
+ ret = ipu_fw_psys_get_program_manifest_by_process(&pm,
+ pg_manifest,
+ process);
+ if (ret < 0) {
+ dev_err(dev, "can not get manifest\n");
+ break;
+ }
+ if ((pm.cell_id != res_defs->num_cells &&
+ pm.cell_type_id == res_defs->num_cells_type))
+ continue;
+ /* no return value check here because if finding free cell
+ * failed, process cell would not set then calling clear_cell
+ * will return non-zero.
+ */
+ ipu_fw_psys_clear_process_cell(process);
+ }
+}
+
/* Free resources marked in `alloc' from `resources' */
void ipu_psys_free_resources(struct ipu_psys_resource_alloc
*alloc, struct ipu_psys_resource_pool *pool)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
index 4ac195f2f95d..6c2885a3d564 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-resources.c
@@ -444,30 +444,6 @@ int ipu6_fw_psys_set_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index,
return 0;
}
-u8 ipu6_fw_psys_get_process_cell_id(struct ipu_fw_psys_process *ptr, u8 index)
-{
- return ptr->cells[index];
-}
-
-int ipu6_fw_psys_clear_process_cell(struct ipu_fw_psys_process *ptr)
-{
- struct ipu_fw_psys_process_group *parent;
- u8 cell_id = ipu6_fw_psys_get_process_cell_id(ptr, 0);
- int retval = -1;
-
- parent = (struct ipu_fw_psys_process_group *)((char *)ptr +
- ptr->parent_offset);
- if ((1 << cell_id) != 0 &&
- ((1 << cell_id) & parent->resource_bitmap)) {
- ipu6_fw_psys_set_process_cell_id(ptr, 0,
- IPU6_FW_PSYS_N_CELL_ID);
- parent->resource_bitmap &= ~(1 << cell_id);
- retval = 0;
- }
-
- return retval;
-}
-
int ipu6_fw_psys_set_proc_dev_chn(struct ipu_fw_psys_process *ptr, u16 offset,
u16 value)
{
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 1f917721b70e..afd84e5ca814 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -92,24 +92,18 @@ static int ipu6_csi2_phy_power_set(struct ipu_isys *isys,
if (ret)
return ret;
- dev_dbg(&isys->adev->dev, "phy reset assert\n");
ipu6_isys_phy_reset(isys, phy_id, 0);
- dev_dbg(&isys->adev->dev, "phy common init\n");
ipu6_isys_phy_common_init(isys);
- dev_dbg(&isys->adev->dev, "phy config\n");
ret = ipu6_isys_phy_config(isys);
if (ret)
return ret;
- dev_dbg(&isys->adev->dev, "phy reset de-assert\n");
ipu6_isys_phy_reset(isys, phy_id, 1);
- dev_dbg(&isys->adev->dev, "phy check ready\n");
ret = ipu6_isys_phy_ready(isys, phy_id);
if (ret)
return ret;
- dev_dbg(&isys->adev->dev, "phy is ready now\n");
refcount_set(ref, 1);
return 0;
}
@@ -404,10 +398,8 @@ int ipu_isys_csi2_set_stream(struct v4l2_subdev *sd,
}
/* reset port reset */
- dev_dbg(&isys->adev->dev, "csi port reset assert\n");
writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
usleep_range(100, 200);
- dev_dbg(&isys->adev->dev, "csi port reset de-assert\n");
writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
/* Enable port clock */
@@ -472,11 +464,6 @@ int ipu_isys_csi2_set_stream(struct v4l2_subdev *sd,
writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
- if (ipu_ver == IPU_VER_6SE)
- return 0;
-
- ipu6_isys_phy_ppi_tinit_done(isys, cfg);
-
return 0;
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
index 6f4561ebb89f..82d457fc8d64 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.c
@@ -497,42 +497,6 @@ int ipu6_isys_phy_ready(struct ipu_isys *isys, unsigned int phy_id)
return -ETIMEDOUT;
}
-int ipu6_isys_phy_ppi_tinit_done(struct ipu_isys *isys,
- struct ipu_isys_csi2_config *cfg)
-{
- unsigned int i, j;
- unsigned int port, phy_id;
- u32 val;
- void __iomem *phy_base;
- struct ipu_bus_device *adev = to_ipu_bus_device(&isys->adev->dev);
- struct ipu_device *isp = adev->isp;
- void __iomem *isp_base = isp->base;
-
- port = cfg->port;
- phy_id = port / 4;
- phy_base = isp_base + IPU6_ISYS_PHY_BASE(phy_id);
- for (i = 0; i < 11; i++) {
- /* ignore 5 as it is not needed */
- if (i == 5)
- continue;
- for (j = 0; j < LOOP; j++) {
- val = readl(phy_base + IPU6_ISYS_PHY_DBBS_UDLN(i) +
- PHY_DBBUDLN_PPI_STATUS);
- if (val & PHY_DBBUDLN_TINIT_DONE) {
- j = 0xffff;
- continue;
- }
- usleep_range(10, 20);
- }
- if (j == LOOP)
- dev_dbg(&isys->adev->dev,
- "phy %d ppi %d tinit NOT done!",
- phy_id, i);
- }
-
- return -ETIMEDOUT;
-}
-
int ipu6_isys_phy_common_init(struct ipu_isys *isys)
{
unsigned int phy_id;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
index e8c063fcf452..10a1d88c3088 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-phy.h
@@ -155,7 +155,5 @@ int ipu6_isys_phy_reset(struct ipu_isys *isys, unsigned int phy_id,
bool assert);
int ipu6_isys_phy_ready(struct ipu_isys *isys, unsigned int phy_id);
int ipu6_isys_phy_common_init(struct ipu_isys *isys);
-int ipu6_isys_phy_ppi_tinit_done(struct ipu_isys *isys,
- struct ipu_isys_csi2_config *cfg);
int ipu6_isys_phy_config(struct ipu_isys *isys);
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index e2891606a63d..28c45f433e2f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -8,7 +8,9 @@
#include "ipu-platform-regs.h"
#include "ipu-trace.h"
#include "ipu-isys.h"
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
#include "ipu-isys-tpg.h"
+#endif
#include "ipu-platform-isys-csi2-reg.h"
const struct ipu_isys_pixelformat ipu_isys_pfmts[] = {
@@ -173,6 +175,7 @@ irqreturn_t isys_isr(struct ipu_bus_device *adev)
return IRQ_HANDLED;
}
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
void ipu_isys_tpg_sof_event(struct ipu_isys_tpg *tpg)
{
struct ipu_isys_pipeline *ip = NULL;
@@ -316,3 +319,4 @@ int tpg_set_stream(struct v4l2_subdev *sd, int enable)
writel(2, tpg->base + MIPI_GEN_REG_COM_ENABLE);
return 0;
}
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c b/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
index 2c9cdc1c376b..eed5022b88d3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-l-scheduler.c
@@ -371,17 +371,13 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys,
kppg->state == PPG_STATE_RESUMED ||
kppg->state == PPG_STATE_RUNNING) {
if (kcmd->state == KCMD_STATE_PPG_START) {
- dev_dbg(&psys->adev->dev, "ppg %p started!\n", kppg);
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
kppg->state = PPG_STATE_STOP;
}
} else if (kppg->state == PPG_STATE_SUSPENDED) {
if (kcmd->state == KCMD_STATE_PPG_START) {
- dev_dbg(&psys->adev->dev, "ppg %p started!\n", kppg);
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
/*
* Record the previous state
@@ -395,13 +391,10 @@ static void ipu_psys_update_ppg_state_by_kcmd(struct ipu_psys *psys,
if (kcmd->state == KCMD_STATE_PPG_START) {
kppg->state = PPG_STATE_START;
} else if (kcmd->state == KCMD_STATE_PPG_STOP) {
- dev_dbg(&psys->adev->dev, "ppg %p stopped!\n", kppg);
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
} else if (kcmd->state == KCMD_STATE_PPG_ENQUEUE) {
dev_err(&psys->adev->dev, "ppg %p stopped!\n", kppg);
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, -EIO);
+ ipu_psys_kcmd_complete(kppg, kcmd, -EIO);
}
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-ppg.c b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
index 4b8db1826eed..22b602306b4a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-ppg.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-ppg.c
@@ -32,6 +32,8 @@ struct ipu_psys_kcmd *ipu_psys_ppg_get_stop_kcmd(struct ipu_psys_ppg *kppg)
{
struct ipu_psys_kcmd *kcmd;
+ WARN(!mutex_is_locked(&kppg->mutex), "ppg locking error");
+
if (list_empty(&kppg->kcmds_processing_list))
return NULL;
@@ -235,14 +237,14 @@ int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg)
kcmd->buffers[i].len);
if (ret) {
dev_err(&psys->adev->dev, "Unable to set terminal\n");
- goto error;
+ return ret;
}
}
ret = ipu_fw_psys_pg_submit(kcmd);
if (ret) {
dev_err(&psys->adev->dev, "failed to submit kcmd!\n");
- goto error;
+ return ret;
}
ret = ipu_psys_allocate_resources(&psys->adev->dev,
@@ -258,26 +260,31 @@ int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg)
ret = pm_runtime_get_sync(&psys->adev->dev);
if (ret < 0) {
dev_err(&psys->adev->dev, "failed to power on psys\n");
- pm_runtime_put_noidle(&psys->adev->dev);
- return ret;
+ goto error;
}
ret = ipu_psys_kcmd_start(psys, kcmd);
if (ret) {
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, -EIO);
- return ret;
+ ipu_psys_kcmd_complete(kppg, kcmd, -EIO);
+ goto error;
}
dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
__func__, kppg, kppg->state, PPG_STATE_STARTED);
kppg->state = PPG_STATE_STARTED;
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
return 0;
error:
+ pm_runtime_put_noidle(&psys->adev->dev);
+ ipu_psys_reset_process_cell(&psys->adev->dev,
+ kcmd->kpg->pg,
+ kcmd->pg_manifest,
+ kcmd->kpg->pg->process_count);
+ ipu_psys_free_resources(&kppg->kpg->resource_alloc,
+ &psys->resource_pool_running);
+
dev_err(&psys->adev->dev, "failed to start ppg\n");
return ret;
}
@@ -309,7 +316,7 @@ int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg)
ret = ipu_fw_psys_ppg_resume(&tmp_kcmd);
if (ret) {
dev_err(&psys->adev->dev, "failed to resume ppg\n");
- return -EIO;
+ goto error;
}
} else {
kppg->kpg->pg->state = IPU_FW_PSYS_PROCESS_GROUP_READY;
@@ -332,13 +339,23 @@ int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg)
ret = ipu_psys_kcmd_start(psys, &tmp_kcmd);
if (ret) {
dev_err(&psys->adev->dev, "failed to start kcmd!\n");
- return ret;
+ goto error;
}
}
dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
__func__, kppg, kppg->state, PPG_STATE_RESUMED);
kppg->state = PPG_STATE_RESUMED;
+ return 0;
+
+error:
+ ipu_psys_reset_process_cell(&psys->adev->dev,
+ kppg->kpg->pg,
+ kppg->manifest,
+ kppg->kpg->pg->process_count);
+ ipu_psys_free_resources(&kppg->kpg->resource_alloc,
+ &psys->resource_pool_running);
+
return ret;
}
@@ -379,8 +396,7 @@ int ipu_psys_ppg_stop(struct ipu_psys_ppg *kppg)
ipu_psys_free_cmd_queue_resource(
&psys->resource_pool_running,
ipu_fw_psys_ppg_get_base_queue_id(kcmd));
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
spin_lock_irqsave(&psys->pgs_lock, flags);
kppg->kpg->pg_size = 0;
spin_unlock_irqrestore(&psys->pgs_lock, flags);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-psys.c b/drivers/media/pci/intel/ipu6/ipu6-psys.c
index baf208ac1a3f..10c6366c60c9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-psys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-psys.c
@@ -251,7 +251,7 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd,
}
/* check and remap if possibe */
- ret = ipu_psys_mapbuf_with_lock(fd, fh, kpgbuf);
+ ret = ipu_psys_mapbuf_locked(fd, fh, kpgbuf);
if (ret) {
dev_err(&psys->adev->dev, "%s remap failed\n", __func__);
mutex_unlock(&fh->mutex);
@@ -349,7 +349,7 @@ static struct ipu_psys_kcmd *ipu_psys_copy_cmd(struct ipu_psys_command *cmd,
goto error;
}
- ret = ipu_psys_mapbuf_with_lock(fd, fh, kpgbuf);
+ ret = ipu_psys_mapbuf_locked(fd, fh, kpgbuf);
if (ret) {
dev_err(&psys->adev->dev, "%s remap failed\n",
__func__);
@@ -448,15 +448,17 @@ static struct ipu_psys_ppg *ipu_psys_lookup_ppg(struct ipu_psys *psys,
* Move kcmd into completed state (due to running finished or failure).
* Fill up the event struct and notify waiters.
*/
-void ipu_psys_kcmd_complete(struct ipu_psys *psys,
+void ipu_psys_kcmd_complete(struct ipu_psys_ppg *kppg,
struct ipu_psys_kcmd *kcmd, int error)
{
struct ipu_psys_fh *fh = kcmd->fh;
+ struct ipu_psys *psys = fh->psys;
kcmd->ev.type = IPU_PSYS_EVENT_TYPE_CMD_COMPLETE;
kcmd->ev.user_token = kcmd->user_token;
kcmd->ev.issue_id = kcmd->issue_id;
kcmd->ev.error = error;
+ list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
if (kcmd->constraint.min_freq)
ipu_buttress_remove_psys_constraint(psys->adev->isp,
@@ -532,90 +534,101 @@ static void ipu_psys_watchdog(struct timer_list *t)
queue_work(IPU_PSYS_WORK_QUEUE, &psys->watchdog_work);
}
-static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
+static int ipu_psys_kcmd_send_to_ppg_start(struct ipu_psys_kcmd *kcmd)
{
struct ipu_psys_fh *fh = kcmd->fh;
struct ipu_psys_scheduler *sched = &fh->sched;
struct ipu_psys *psys = fh->psys;
struct ipu_psys_ppg *kppg;
struct ipu_psys_resource_pool *rpr;
- unsigned long flags;
- u8 id;
- bool resche = true;
+ int queue_id;
+ int ret;
rpr = &psys->resource_pool_running;
- if (kcmd->state == KCMD_STATE_PPG_START) {
- int queue_id;
- int ret;
- mutex_lock(&psys->mutex);
- queue_id = ipu_psys_allocate_cmd_queue_resource(rpr);
- if (queue_id == -ENOSPC) {
- dev_err(&psys->adev->dev, "no available queue\n");
- mutex_unlock(&psys->mutex);
- return -ENOMEM;
- }
+ kppg = kzalloc(sizeof(*kppg), GFP_KERNEL);
+ if (!kppg)
+ return -ENOMEM;
+
+ kppg->fh = fh;
+ kppg->kpg = kcmd->kpg;
+ kppg->state = PPG_STATE_START;
+ kppg->pri_base = kcmd->priority;
+ kppg->pri_dynamic = 0;
+ INIT_LIST_HEAD(&kppg->list);
+
+ mutex_init(&kppg->mutex);
+ INIT_LIST_HEAD(&kppg->kcmds_new_list);
+ INIT_LIST_HEAD(&kppg->kcmds_processing_list);
+ INIT_LIST_HEAD(&kppg->kcmds_finished_list);
+ INIT_LIST_HEAD(&kppg->sched_list);
+
+ kppg->manifest = kzalloc(kcmd->pg_manifest_size, GFP_KERNEL);
+ if (!kppg->manifest) {
+ kfree(kppg);
+ return -ENOMEM;
+ }
+ memcpy(kppg->manifest, kcmd->pg_manifest,
+ kcmd->pg_manifest_size);
+
+ queue_id = ipu_psys_allocate_cmd_queue_resource(rpr);
+ if (queue_id == -ENOSPC) {
+ dev_err(&psys->adev->dev, "no available queue\n");
+ kfree(kppg->manifest);
+ kfree(kppg);
mutex_unlock(&psys->mutex);
+ return -ENOMEM;
+ }
- kppg = kzalloc(sizeof(*kppg), GFP_KERNEL);
- if (!kppg)
- return -ENOMEM;
-
- kppg->fh = fh;
- kppg->kpg = kcmd->kpg;
- kppg->state = PPG_STATE_START;
- kppg->pri_base = kcmd->priority;
- kppg->pri_dynamic = 0;
- INIT_LIST_HEAD(&kppg->list);
-
- mutex_init(&kppg->mutex);
- INIT_LIST_HEAD(&kppg->kcmds_new_list);
- INIT_LIST_HEAD(&kppg->kcmds_processing_list);
- INIT_LIST_HEAD(&kppg->kcmds_finished_list);
- INIT_LIST_HEAD(&kppg->sched_list);
-
- kppg->manifest = kzalloc(kcmd->pg_manifest_size, GFP_KERNEL);
- if (!kppg->manifest) {
- kfree(kppg);
- return -ENOMEM;
- }
- memcpy(kppg->manifest, kcmd->pg_manifest,
- kcmd->pg_manifest_size);
+ /*
+ * set token as start cmd will immediately be followed by a
+ * enqueue cmd so that kppg could be retrieved.
+ */
+ kppg->token = (u64)kcmd->kpg;
+ ipu_fw_psys_pg_set_token(kcmd, kppg->token);
+ ipu_fw_psys_ppg_set_base_queue_id(kcmd, queue_id);
+ ret = ipu_fw_psys_pg_set_ipu_vaddress(kcmd,
+ kcmd->kpg->pg_dma_addr);
+ if (ret) {
+ ipu_psys_free_cmd_queue_resource(rpr, queue_id);
+ kfree(kppg->manifest);
+ kfree(kppg);
+ return -EIO;
+ }
+ memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size);
- /*
- * set token as start cmd will immediately be followed by a
- * enqueue cmd so that kppg could be retrieved.
- */
- kppg->token = (u64)kcmd->kpg;
- ipu_fw_psys_pg_set_token(kcmd, kppg->token);
- ipu_fw_psys_ppg_set_base_queue_id(kcmd, queue_id);
- ret = ipu_fw_psys_pg_set_ipu_vaddress(kcmd,
- kcmd->kpg->pg_dma_addr);
- if (ret) {
- kfree(kppg->manifest);
- kfree(kppg);
- return -EIO;
- }
- memcpy(kcmd->pg_user, kcmd->kpg->pg, kcmd->kpg->pg_size);
+ mutex_lock(&fh->mutex);
+ list_add_tail(&kppg->list, &sched->ppgs);
+ mutex_unlock(&fh->mutex);
- mutex_lock(&fh->mutex);
- list_add_tail(&kppg->list, &sched->ppgs);
- mutex_unlock(&fh->mutex);
+ mutex_lock(&kppg->mutex);
+ list_add(&kcmd->list, &kppg->kcmds_new_list);
+ mutex_unlock(&kppg->mutex);
- mutex_lock(&kppg->mutex);
- list_add(&kcmd->list, &kppg->kcmds_new_list);
- mutex_unlock(&kppg->mutex);
+ dev_dbg(&psys->adev->dev,
+ "START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n",
+ ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, queue_id);
- dev_dbg(&psys->adev->dev,
- "START ppg(%d, 0x%p) kcmd 0x%p, queue %d\n",
- ipu_fw_psys_pg_get_id(kcmd), kppg, kcmd, queue_id);
+ /* Kick l-scheduler thread */
+ atomic_set(&psys->wakeup_count, 1);
+ wake_up_interruptible(&psys->sched_cmd_wq);
- /* Kick l-scheduler thread */
- atomic_set(&psys->wakeup_count, 1);
- wake_up_interruptible(&psys->sched_cmd_wq);
+ return 0;
+}
- return 0;
- }
+static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
+{
+ struct ipu_psys_fh *fh = kcmd->fh;
+ struct ipu_psys *psys = fh->psys;
+ struct ipu_psys_ppg *kppg;
+ struct ipu_psys_resource_pool *rpr;
+ unsigned long flags;
+ u8 id;
+ bool resche = true;
+
+ rpr = &psys->resource_pool_running;
+ if (kcmd->state == KCMD_STATE_PPG_START)
+ return ipu_psys_kcmd_send_to_ppg_start(kcmd);
kppg = ipu_psys_identify_kppg(kcmd);
spin_lock_irqsave(&psys->pgs_lock, flags);
@@ -640,8 +653,7 @@ static int ipu_psys_kcmd_send_to_ppg(struct ipu_psys_kcmd *kcmd)
"kppg 0x%p stopped!\n", kppg);
id = ipu_fw_psys_ppg_get_base_queue_id(kcmd);
ipu_psys_free_cmd_queue_resource(rpr, id);
- list_add(&kcmd->list, &kppg->kcmds_finished_list);
- ipu_psys_kcmd_complete(psys, kcmd, 0);
+ ipu_psys_kcmd_complete(kppg, kcmd, 0);
spin_lock_irqsave(&psys->pgs_lock, flags);
kppg->kpg->pg_size = 0;
spin_unlock_irqrestore(&psys->pgs_lock, flags);
@@ -765,7 +777,7 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
bool error;
u32 hdl;
u16 cmd, status;
- int res, state;
+ int res;
do {
memset(&event, 0, sizeof(event));
@@ -815,22 +827,19 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
kppg = ipu_psys_lookup_ppg(psys, hdl);
if (kppg) {
mutex_lock(&kppg->mutex);
- state = kppg->state;
- if (state == PPG_STATE_STOPPING) {
+ if (kppg->state == PPG_STATE_STOPPING) {
kcmd = ipu_psys_ppg_get_stop_kcmd(kppg);
if (!kcmd)
error = true;
}
mutex_unlock(&kppg->mutex);
- } else {
- error = true;
}
} else {
dev_err(&psys->adev->dev, "invalid event\n");
continue;
}
- if (error) {
+ if (error || !kppg) {
dev_err(&psys->adev->dev, "event error, command %d\n",
cmd);
break;
@@ -839,17 +848,15 @@ void ipu_psys_handle_events(struct ipu_psys *psys)
dev_dbg(&psys->adev->dev, "event to kppg 0x%p, kcmd 0x%p\n",
kppg, kcmd);
- if (kppg)
- ipu_psys_ppg_complete(psys, kppg);
+ ipu_psys_ppg_complete(psys, kppg);
if (kcmd && ipu_psys_kcmd_is_valid(psys, kcmd)) {
res = (status == IPU_PSYS_EVENT_CMD_COMPLETE ||
status == IPU_PSYS_EVENT_FRAGMENT_COMPLETE) ?
0 : -EIO;
mutex_lock(&kppg->mutex);
- list_move_tail(&kcmd->list, &kppg->kcmds_finished_list);
+ ipu_psys_kcmd_complete(kppg, kcmd, res);
mutex_unlock(&kppg->mutex);
- ipu_psys_kcmd_complete(psys, kcmd, res);
}
} while (1);
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 79f4f3db0374..a404c2f301d0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -58,6 +58,7 @@ static unsigned int ipu6se_csi_offsets[] = {
IPU_CSI_PORT_D_ADDR_OFFSET,
};
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
static unsigned int ipu6se_tpg_offsets[] = {
IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
@@ -65,17 +66,6 @@ static unsigned int ipu6se_tpg_offsets[] = {
IPU_CSI_PORT_D_PIXGEN_ADDR_OFFSET,
};
-static unsigned int ipu6_csi_offsets[] = {
- IPU_CSI_PORT_A_ADDR_OFFSET,
- IPU_CSI_PORT_B_ADDR_OFFSET,
- IPU_CSI_PORT_C_ADDR_OFFSET,
- IPU_CSI_PORT_D_ADDR_OFFSET,
- IPU_CSI_PORT_E_ADDR_OFFSET,
- IPU_CSI_PORT_F_ADDR_OFFSET,
- IPU_CSI_PORT_G_ADDR_OFFSET,
- IPU_CSI_PORT_H_ADDR_OFFSET
-};
-
static unsigned int ipu6_tpg_offsets[] = {
IPU_CSI_PORT_A_PIXGEN_ADDR_OFFSET,
IPU_CSI_PORT_B_PIXGEN_ADDR_OFFSET,
@@ -86,6 +76,18 @@ static unsigned int ipu6_tpg_offsets[] = {
IPU_CSI_PORT_G_PIXGEN_ADDR_OFFSET,
IPU_CSI_PORT_H_PIXGEN_ADDR_OFFSET
};
+#endif
+
+static unsigned int ipu6_csi_offsets[] = {
+ IPU_CSI_PORT_A_ADDR_OFFSET,
+ IPU_CSI_PORT_B_ADDR_OFFSET,
+ IPU_CSI_PORT_C_ADDR_OFFSET,
+ IPU_CSI_PORT_D_ADDR_OFFSET,
+ IPU_CSI_PORT_E_ADDR_OFFSET,
+ IPU_CSI_PORT_F_ADDR_OFFSET,
+ IPU_CSI_PORT_G_ADDR_OFFSET,
+ IPU_CSI_PORT_H_ADDR_OFFSET
+};
struct ipu_isys_internal_pdata isys_ipdata = {
.hw_variant = {
@@ -367,18 +369,22 @@ void ipu_internal_pdata_init(void)
if (ipu_ver == IPU_VER_6) {
isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6_csi_offsets);
isys_ipdata.csi2.offsets = ipu6_csi_offsets;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6_tpg_offsets);
isys_ipdata.tpg.offsets = ipu6_tpg_offsets;
isys_ipdata.tpg.sels = NULL;
+#endif
isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
} else if (ipu_ver == IPU_VER_6SE) {
isys_ipdata.csi2.nports = ARRAY_SIZE(ipu6se_csi_offsets);
isys_ipdata.csi2.offsets = ipu6se_csi_offsets;
+#ifdef CONFIG_VIDEO_INTEL_IPU_TPG
isys_ipdata.tpg.ntpgs = ARRAY_SIZE(ipu6se_tpg_offsets);
isys_ipdata.tpg.offsets = ipu6se_tpg_offsets;
isys_ipdata.tpg.sels = NULL;
+#endif
isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
}
--
2.31.1
More information about the kernel-team
mailing list