From patchwork Wed Apr 14 07:54:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: You-Sheng Yang X-Patchwork-Id: 1466041 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FKvsq1NM1z9sWS; Wed, 14 Apr 2021 17:55:43 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1lWaN9-0007B8-Jx; Wed, 14 Apr 2021 07:55:39 +0000 Received: from mail-pj1-f44.google.com ([209.85.216.44]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1lWaLz-00075y-H9 for kernel-team@lists.ubuntu.com; Wed, 14 Apr 2021 07:54:28 +0000 Received: by mail-pj1-f44.google.com with SMTP id s14so4991593pjl.5 for ; Wed, 14 Apr 2021 00:54:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ZQQKYLWXBeRkwwi+6wVj0YHsEBKFWfS6nR6AmF0dXYc=; b=YE6Pvys0k0yh8bK4MqTtbjlLHYityUk15alqJt780CHFtrZgeacHqtg7uvCokxm/Wx o3TRC/3vPlsq7AGCa5cIjNCjd1aRzu4X7A1GIaOjr30qlLc4F1XHWJUWBU8OuzMApzvr ThoRNLVFkmUWgLfZul8fqVGK+eNOEDBeEJ81VESCVDb+iEl+emTZM0p6F4F9wFvMhj7D OjqGjTAQ8x2rGY/urjqtRkQKWps3tBM/caqu+jdXWWFKGQ8ns6XpNVHZNdYHCztpq1oT vF0OMkIu79EBOKH0UNV4REjhTQJoeYN1kkdHD0pV/dHRRS3ikiQOb82Hq90vpdwHSBzv S/tA== X-Gm-Message-State: AOAM531ihBpOyq2cUb4mQkTYD/8nqM7mZb+ORKr/wLZu3Cwo2cmo9Kkd MAjQE4ZqFQDzLmfYRTrFZ7aBeOpJXz4rUw== X-Google-Smtp-Source: ABdhPJxsRR+BFSQzmvaN0gAaMZh2pL0cLiBR97OKhihh1AvGjoou2+Xx/oQofCSI8XTv8wM3rXssXg== X-Received: by 2002:a17:90a:9509:: with SMTP id t9mr2231138pjo.3.1618386864063; Wed, 14 Apr 2021 00:54:24 -0700 (PDT) Received: from localhost (61-220-137-37.HINET-IP.hinet.net. [61.220.137.37]) by smtp.gmail.com with ESMTPSA id j8sm824767pgn.55.2021.04.14.00.54.22 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 14 Apr 2021 00:54:23 -0700 (PDT) From: You-Sheng Yang To: kernel-team@lists.ubuntu.com Subject: [PATCH v3 2/9][SRU][OEM-5.10] UBUNTU: SAUCE: IPU driver release WW48 Date: Wed, 14 Apr 2021 15:54:05 +0800 Message-Id: <20210414075412.2288687-3-vicamo.yang@canonical.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210414075412.2288687-1-vicamo.yang@canonical.com> References: <20210414075412.2288687-1-vicamo.yang@canonical.com> MIME-Version: 1.0 Received-SPF: pass client-ip=209.85.216.44; envelope-from=vicamo@gmail.com; helo=mail-pj1-f44.google.com X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Wang Yating BugLink: https://bugs.launchpad.net/bugs/1921345 Signed-off-by: Wang Yating (backported from https://github.com/intel/ipu6-drivers/commit/5e7f876527d932189e6e7d30f0dba5651068f0df) Signed-off-by: You-Sheng Yang --- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_AUTHOR("Shawn Tu "); +MODULE_AUTHOR("Bingbu Cao "); +MODULE_AUTHOR("Lai, Jim "); +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 #include -#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 "); MODULE_AUTHOR("Lai, Jim "); MODULE_AUTHOR("Qiu, Tianshu "); MODULE_AUTHOR("Shawn Tu "); 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; }