From nobody Fri Sep 25 23:51:05 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 00B7147CC91 for ; Fri, 25 Sep 2026 09:09:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327399; cv=none; b=nh8nks1n8g2v1ty2uDWithdYGbldDs9p8/nU1Lzqou9sROqqIizG+6F4YrHmRkKofMS4wAEl+PxY2QBiQp7fDX5Bl3/Klyo8ERtXk/hDO9RJlUDh/7ncWpEWY/xqTEu5OmL9Cqa3iCXEUM0zi/IvjnF4965zcTYUqzvUlnLYIQo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327399; c=relaxed/simple; bh=t9VRl1nMX4c51HXGRlVcUrJ2vYPgoDYjYMTLiyXwefU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jLjjprwdNo2RbL3Aj+TZ9dZnt9BQ+MRhgmFKln1UuqdKoAVQVCYZ2LLzIhTYB+ev1CiZuLAMUsKrEUfnc/1v3Lp+3lHV3D79xTmwGNuhG6gJE+n1FlKhgP+RaNFFdoDtsVi+miWopuItyXg56xpimjTmfV5hsqM7mQTPeO6EB18= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=O/QXYNGB; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=gjPv/i3Q; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="O/QXYNGB"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="gjPv/i3Q" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4YYHK208419 for ; Fri, 25 Sep 2026 09:09:55 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= owC/0Uitd+RPnqSaxCQ8n2UoAK7Gqnd+PP1VG0zdCcc=; b=O/QXYNGBS0gU2Wwj BSACMd2AutM8Wriv9s3EDD/t0SeQ3tHAxUJCPc5yhB9muONFusmu+Jjt36mWXMtZ t+Rukl2AF9W/Asz26zxAB/wEvf44UQL57ydgo+ggP0bFMSyCVJdW3YbuerqVOtXg wEMK7PfZeq1HgBMmnBj+ueByLT1p4ZPdd8kZEWxNIYc9UxYLQto/IpPtFX8efeQN 0c1W63ycPoeuBp6YoXZeB8+pYDJPyPBIdXzyn5O8Xm5FLMHe1dVghbAZRFKZ3MSg Xw1EVOYHHsr7Apwf3sjreOFobu+8QRIqL+hlO3zS1jw1YQmNs85WVCFQRYsRJVpk IFGSbg== Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw898tuf7-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:09:55 +0000 (GMT) Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-934956beec8so145371085a.0 for ; Fri, 25 Sep 2026 02:09:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327394; x=1790932194; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=owC/0Uitd+RPnqSaxCQ8n2UoAK7Gqnd+PP1VG0zdCcc=; b=gjPv/i3QM7yR6P7n1zqh9tT5okYYsu7GteMflD4j0ouMYrFaLAIv1BRGX9/liZl+sR O1M1MZBlBvwYn5CEsxjSWdQl17jWeHyYYqZ5l/Jzse0+aBPm6489ZeF5m7CLtbRL5Aay 9Y/bZaEHQ3Prfxl5pYxUO3Ge36isz6KUcHNCV6UHvvCRGe+R7rx6K5ypK9SM/92/cHEI wBLkvH/3s4nW7gFrSti2SGtix8JwEgWNbvbbp5/q91sLAHe6LtQQ1bGo7HeuucqY2Fko 6FqCh4k2MswEQRv6sjuJPTc/KwG1tdpZdupSH7h4zUB8bDRVABuZXS96lOn846R4+bkU w1xA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327394; x=1790932194; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=owC/0Uitd+RPnqSaxCQ8n2UoAK7Gqnd+PP1VG0zdCcc=; b=kDcmuamqnpffOvoeo0BBldyWzBl0QKRJKlBKdh6xn8x1t25TsF7Cyou+XgrDYAGVJ4 muY9+1aXhzLJZu0z2xCy0I+neQBydMnd574DEZEcVxNSqS33Wul47UAiX6oY7lTYsR2t v32VkBlLhKEfOiJJ8oSDkJsf40unzqhQNDJGNrmDGmhqx9rFimTPnUm3WjNBlOYYgvjX /KIoDC/Inq8jklUbkUfVgdTh0caIySMXN+OdGrwQUtF/9Lcp0nPnMVKN/lnt8WwASlUV 1+Tajeu5hwGBQ3E/vFDp2DHGuIC2L64ZN/CxXin3mH7XkT/MnIb4qV8bL6OdXGx7F7RT Idpw== X-Forwarded-Encrypted: i=1; AKwUvBy5uwlylSNQS263NjZsO65vdUZPzK6DHm8457ZwnqIgk12GJqy9jRviL2sP6n1Au17i/m7ahE8DC/DKTC4=@vger.kernel.org X-Gm-Message-State: AFuF++kXwQ/8FWpwk4tJrDi2kHreoahzzHljoiVHoxX1D39OSTfuydh2 ase0rPGLJW9DH0seLtc4X77tXByz3FJMUC7pejQvKuXxjSAWoRPeY9XrewLUKMBBq53Aodli301 H01cnd3CdnEDSsyl3wrxSoYQ+2ECsWvV9Q6mjXqp/3UaECJhDxXr1V6GZFIK1zdRTijU= X-Gm-Gg: AYBFou39jGxB02rRDesmmJ4q+vE8m90VVEIaAil4kiIE354oxheAS1DVpn3Mx8W9KVn nb0I08tTz6X+av6ekLe8aFAWN4VvkVq/A9WIuA/xMbfZB9aipWDookXgWbsbg86wlJKypxWpGyL 6eekrirb5Sp19dyBwW8SKa5isptsTnXuh0jHhJFvb2wZG6/0MieLKdmEdo441UtvkGtsl5buJ+Z zsqWGYQG1+xpOO5wo0iausVOLmjBpd197XW/rpOPqW2WEIVMHsNFf0HUGz0iBnpauAybc6dNHIQ hDkd2pi+NF+k7hErqrA+6CorqWeIWFob/cW6MNCOnU0rooKjRfx454cFTC6G55LRkHYsgjwN3XI A+J+ML4OdbJsk3LPDWb1+XasUalHEC1yvzH3cUKQrMsVQ/aezutn6Lim5VpwKHueZgPj133Lh9b bPLaHD7KjEndg0kashO6xdW9HeRJ62Iika/g28TjI6wjs+eBvFXY8= X-Received: by 2002:a05:620a:4451:b0:937:19d3:3fda with SMTP id af79cd13be357-93c43c1247fmr298752585a.28.1790327394330; Fri, 25 Sep 2026 02:09:54 -0700 (PDT) X-Received: by 2002:a05:620a:4451:b0:937:19d3:3fda with SMTP id af79cd13be357-93c43c1247fmr298749485a.28.1790327393853; Fri, 25 Sep 2026 02:09:53 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.09.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:09:53 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:48 +0200 Subject: [PATCH v10 1/9] media: qcom: camss: Add V4L2 meta format for CAMSS ISP parameters Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-1-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org X-Mailer: b4 0.14.2 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfXzPIB3Z/jwYzN o+w7iEVi1+5xxEvoRF13bSvH2YTh7vhVQqmA1g1dRxka+VtX+VhcnoKjz2aqBrMna/nZeZcFxOa wJpIr3z0xNqqb8UXKr7BRXBa3qLlQI1mxVtB54fi0Zdm7o6LRQYYcj9bJzvvgT6yILVHRS/hydN jGoIwZVDVFHS598zUv2NSz+DcM1ADA9QPjSwXzXRTwHnYNF63PTw7Ce1y9v+CJ/8QPQU3h0yu7I +rw+yq0cDl6O5klWvIL+ODBFMe5UtGnAHDazsLTiiVVk9qo8gLJuKH9FVyqmMMbMGhcD9MrD6Ro Q2TMP3//c8FXpJLTAarhc/c2wdthgwOjkPD5PBqMY3JMe8Hpg3BmPQJVJb8qTLH2i0lcYBORLZ9 hAY/AdRpyL0wMWdmBeuqsJWOr7QxWLzfQBbtF4gBAY/vXom43C/oq1/vZhvpA/eXGZ3HdRTYI0w BffC9tYUxElVbgJuPyg== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX2qT2LXjrxtJJ 03yg9SCwO1beTV2lvrZVz7gwdE5oEaBvK4/5byLtl9OXsW/YJMxZKLb0tMZqDR6cQfBUdr8AqDE v6U3BHKfwwYxqt6alikL6QCRf/N2mLs= X-Proofpoint-GUID: klx8MWeY_73VGBP3VUIVErzYNqBhQQdO X-Proofpoint-ORIG-GUID: klx8MWeY_73VGBP3VUIVErzYNqBhQQdO X-Authority-Analysis: v=2.4 cv=EJWTQFZC c=1 sm=1 tr=0 ts=6ab63a63 cx=c_pps a=50t2pK5VMbmlHzFWWp8p/g==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yOCtJkima9RkubShWh1s:22 a=EUspDBNiAAAA:8 a=mDm0RygAtmZY0osY0NEA:9 a=QEXdDO2ut3YA:10 a=IoWCM6iH3mJn3m4BftBB:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 clxscore=1015 spamscore=0 lowpriorityscore=0 suspectscore=0 impostorscore=0 bulkscore=0 phishscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add a V4L2 meta format code (V4L2_META_FMT_QCOM_ISP_PARAMS) for the Qualcomm CAMSS ISP parameter buffer. This format is used by the params video node exposed by CAMSS offline ISP drivers (e.g. OPE) to carry ISP tuning data such as white balance, color correction and chroma enhancement settings. Signed-off-by: Loic Poulain --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core= /v4l2-ioctl.c index 17ba1ae707355a134047de646f61fcc2d1512d4c..cef1593c1835070f7b34a8b8c86= 0738fb77f533a 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1471,6 +1471,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_C3ISP_STATS: descr =3D "Amlogic C3 ISP Statistics"; b= reak; case V4L2_META_FMT_MALI_C55_PARAMS: descr =3D "ARM Mali-C55 ISP Parameter= s"; break; case V4L2_META_FMT_MALI_C55_STATS: descr =3D "ARM Mali-C55 ISP 3A Statist= ics"; break; + case V4L2_META_FMT_QCOM_ISP_PARAMS: descr =3D "Qualcomm CAMSS ISP Paramet= ers"; break; case V4L2_META_FMT_RPPX1_PARAMS: descr =3D "Dreamchip RPP-X1 ISP Paramete= rs"; break; case V4L2_META_FMT_RPPX1_STATS: descr =3D "Dreamchip RPP-X1 ISP Statistic= s"; break; case V4L2_PIX_FMT_NV12_8L128: descr =3D "NV12 (8x128 Linear)"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 5373dba640fae3d19247ab1c74ba336e05dc0fe0..70208a9443d8ade569f130e2fc3= d6beebab6b636 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -893,6 +893,9 @@ struct v4l2_pix_format { #define V4L2_META_FMT_RPPX1_PARAMS v4l2_fourcc('D', 'R', '1', 'P') /* Drea= mchip RPP-X1 Parameters */ #define V4L2_META_FMT_RPPX1_STATS v4l2_fourcc('D', 'R', '1', 'S') /* Dream= chip RPP-X1 Statistics */ =20 +/* Vendor specific - used for Qualcomm CAMSS ISP */ +#define V4L2_META_FMT_QCOM_ISP_PARAMS v4l2_fourcc('Q', 'C', 'I', 'P') /* Q= ualcomm CAMSS ISP Parameters */ + #ifdef __KERNEL__ /* * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5BEFC47FAE1 for ; Fri, 25 Sep 2026 09:09:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327401; cv=none; b=u74SZOQ+hPoNfTki8nzZfIMocp5ISFlaRQk8SkR5IXzgUyG+1DzrKuMfpqUAuhwcgSgtpXx9a1Pnrxdai+uZ+qb494aTOICCk670Z+yC9Yy8ksYD1R+cmHU+yVuuYZ+OfGuFbOc0Qgjb9EOE1z94LhTyspj2K0xXMzIzDWjoPvo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327401; c=relaxed/simple; bh=Z6cS8aJK/HbBm0d7OT7Xq+/FQXVHHZKwWRt5CJiiGpk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eh/0qTJxjS9RILpQ/omBwBfLI0ptLMvtt+V0ctjshrCqvwDWtHzSapA5BZ7hLitrKeJAEWwtcODwn99UtFeowqMFcMEqw0Wxl5p1ReeLrnW0Tjkm0eF5b2cvQUi1mkKgavdGPUgoW5bPArF9nBRT3YSNxIMxqy8EpubR7Sh9GfQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=W50s/3to; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=I8ma6WjG; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="W50s/3to"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="I8ma6WjG" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4Yorj1194081 for ; Fri, 25 Sep 2026 09:09:57 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= yQgJsfAJIwc1P3YmgjY5JtZQxBkIW43VtHK4ofExmak=; b=W50s/3toqVcpZ5Ad 9LvlZgFauYpjQzpDm7D7Y0sdy9A2Cs8FzD4i59NAvmxV5dBLX84bQ0AL2WxeqSkj ZkgWnS4/960Qcd1T+OwYv6K1Q/OLbydaRx0x38D08NbeP+/j5cMpbdpwT7V8B53R jscgHTt2CDueZx8HquauNx7GPrjbNVZAcCGNT01aE8nQ1963/2h3AhRaslz92KoZ iNaoE3sP5hqWvQDpk+EXNwxTIUb7CtV+Pe+VNNfc/ntjJ5BghWa8RPkBr/p4Pq25 rzjVkHKxIdxcTo1hq/LhZqgSNY7gaGEBqYyU3bKEE9+FRv+6jS2gTR5HrI4ZpwSJ NxktIQ== Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw874jsvw-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:09:57 +0000 (GMT) Received: by mail-qk1-f198.google.com with SMTP id af79cd13be357-93bfb2da664so195689685a.1 for ; Fri, 25 Sep 2026 02:09:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327396; x=1790932196; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=yQgJsfAJIwc1P3YmgjY5JtZQxBkIW43VtHK4ofExmak=; b=I8ma6WjG2HgpnvxSc0uEB3SJLUN31itF/TRAl4tECFH3ei1mjyEqOYf39p5WjZvP4T MPYhx97FdcHX1LGq337w8OspIV6hnJ1uyTNRDEp+37viZ/H4loFwe6YUeL3aKi4sKGOg 8/0PuiEB30vMBz0ZMTZZ/dw8ktirIvW/fH1Xj0/+Xqse2LePkM+bKw07qf//CpfkOIIJ yaxsEChDXUXZrkMuhkc/6ShMqQCn56vSleiVfqS+uOLR8AJNVaHxmr1MRd7cKu3Q9lHY nXPf+MR9sMtM8xSlp5nHjmPiA4oG3lVKtlS6EfTYRa4gNphNauu7E3TTRCkjvnXVVBuy Dtww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327396; x=1790932196; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=yQgJsfAJIwc1P3YmgjY5JtZQxBkIW43VtHK4ofExmak=; b=urc61FR7oudocZR7bdGXYy8bFTkKAgqnUKdfhIm/IM5qMNm1z6YQHIDhewLowKKh8h 7mELzHYLC/fJ2nOcUhYtZPImwzql+cSf6bqZBzvvlFpJPWctOAfmD3w+4tevt5X4zANN adRSakm/ySPByfL++5C1GmJ9DsUp5JrpNwCrcEZAbmZDeaAvonMaXD1JVgEyGea3/lL6 lyzulSLpdPBkZgubQer1b/RMzQSEK1PHkt1UVr64DGc73ynh1wAyxjhsMBsgbgEL8S6G Z1Lr1OeWsDiClDJKVr/nBekEVSdiEdNH2tIB4Bbi/Ng9hBHQrtqko9UqLdfNsj77DZQ5 L6Dw== X-Forwarded-Encrypted: i=1; AKwUvBwU2kMw2P1yneMXNvZpGSpilZfcLMaRFuZWqxMfPAzRl7ire1KyNodGiugclhToMn99YXWyzAYdscVnCWE=@vger.kernel.org X-Gm-Message-State: AFuF++m7JI4SuYlkH7V6I3weI/3uBMGk+BNQS5Sr7mY9ZwRaCiJRnfah OSag/3aCMuZ2muhy52MhG+AbA/TVpbZfmF+z4mzgpHscfXS23ejano8be5mC0Dh1cgMU2pno+l+ qKlKV0yoHOCKdiKmeSDLeAWzIxgv/vooyu56SXlsQLCL++3Qx7xlGZx6zX2YiT6AFGTM= X-Gm-Gg: AYBFou1R5X/K8R0lJ0/M8Ovto+gfQVmWrh3mwHnyw0bw8DHJpbRUeKKB/2OjMnF3+rk MlaQtk+BTb3WewgTQZ7t9EiZIF8kPOM4ZPz5zsGEcqQXgwM2owSYq8qGo3UrFi/Z12GZJ9IzA9n /nTKBzI9QQFVaVBnNiDgrZmmohGPBJA4f2sGgUUmayshjUwnxmoVl5pvmNu5VwkD3F+7x/PE0vK ybNRcdAFM6JZhoUnjjbA6wS/fumAjbXPav9nDkUNqlhP/PoEp0yLeSRgnzHGeAsFqqgLBLT5nAn d19JdxHchZ9Ju+GdAgFQMcDw1UmIaIOK3Xw3+/VkWsBr/dyN/RItHSl6AvVxtoijpdP53467zES LQM5PyizVr+clcvToLfGZdacr1yH3ed9J7ELOHRKPa1T5lJQHQX/w19Z+6goWJxUfBcXlzOo6zp yuuS+QGBVjZJy0Oo7H4Yk1j/bMAPME8RAuUkSQ2i2+rKQjwKb54Es= X-Received: by 2002:a05:620a:1d05:b0:93c:739:dd5c with SMTP id af79cd13be357-93c4738b2e3mr205795385a.25.1790327396019; Fri, 25 Sep 2026 02:09:56 -0700 (PDT) X-Received: by 2002:a05:620a:1d05:b0:93c:739:dd5c with SMTP id af79cd13be357-93c4738b2e3mr205791985a.25.1790327395548; Fri, 25 Sep 2026 02:09:55 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.09.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:09:54 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:49 +0200 Subject: [PATCH v10 2/9] dt-bindings: media: qcom: Add CAMSS Offline Processing Engine (OPE) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-2-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Krzysztof Kozlowski X-Mailer: b4 0.14.2 X-Proofpoint-ORIG-GUID: XYeS_FnhhFnvnrTe3u0PZI-lnAbj5TBS X-Authority-Analysis: v=2.4 cv=MI71C8Zl c=1 sm=1 tr=0 ts=6ab63a65 cx=c_pps a=qKBjSQ1v91RyAK45QCPf5w==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=gEfo2CItAAAA:8 a=EUspDBNiAAAA:8 a=l64rWm3OqFMOLA4dSg0A:9 a=QEXdDO2ut3YA:10 a=NFOGd7dJGGMPyQGDc5-O:22 a=sptkURWiP4Gy88Gu7hUp:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX2vmegZgQQpfa p3Wa/ZOoYHh7K6Y54PsA/BIH9AlK3pcvgCWTrFUUb0MSFbz0+gkLy+1TzMktV8JGS8RMvEC1UlZ u15hZAxa3gsp3BX0mN2v2yfmg0y0jhPBJ7LJa1UD6wj1sKvC2HFCYtJyGYrGrHTmNO8FQuUzHsM ZHWWi8DhUX3qlZPoUZPI2UGid39ugnzbmDfgbY6htsoztP/Ki+NBIDaPRoPDNlZe2+81JXpIQu4 Bi2JialPwqZ5oyUNqtzI2yaPhysnVtrdXscA5OGCloSDSx0g761SVThILNp83G9PhKUVZIGBC2J BjRmvfIOSosYygIhgWneZ6eGobBfDigr3MJJyp4PhswUL7fQ9iO0FoabX2ovDlJMs09qrEsVOUy gbwh19XtyNbTWyjO5zQaA8iqXhZYtKldesYEIWQJZ5+wQ5OVnZ+5dThsxLEPb3MHS9bjECVwPar iB3eax7gy7KxZDuxG5g== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX87jcnuE8niFu lhiAJsrKYqmXWqhMWMRE4M6fu/1NGl5vh+M31DomEtTe/71M/jCnY0fjAqSXcU4bO1CdfsjLP6X Vr+2IqkStvmWrHOYQ6OM4w52KqOpZvc= X-Proofpoint-GUID: XYeS_FnhhFnvnrTe3u0PZI-lnAbj5TBS X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 malwarescore=0 clxscore=1015 spamscore=0 priorityscore=1501 impostorscore=0 phishscore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add Devicetree binding documentation for the Qualcomm Camera Subsystem Offline Processing Engine (OPE) found on platforms such as Agatti. The OPE is a memory-to-memory image processing block which operates on frames read from and written back to system memory. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Loic Poulain --- .../bindings/media/qcom,qcm2290-camss-ope.yaml | 151 +++++++++++++++++= ++++ 1 file changed, 151 insertions(+) diff --git a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope= .yaml b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f9c31bc88e94b028c241060bbd8= e56e0bdc49af5 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,qcm2290-camss-ope.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Camera Subsystem Offline Processing Engine + +maintainers: + - Loic Poulain + +description: + The Qualcomm Camera Subsystem (CAMSS) Offline Processing Engine (OPE) + is a memory-to-memory image processing block. It supports a range of + pixel-processing operations such as scaling, cropping, gain adjustments, + white-balancing, and various format conversions. The OPE does not + interface directly with image sensors, instead, it processes frames + sourced from and written back to system memory. + +properties: + compatible: + const: qcom,qcm2290-camss-ope + + reg: + maxItems: 6 + + reg-names: + items: + - const: cdm + - const: top + - const: qos + - const: pipeline + - const: bus_read + - const: bus_write + + clocks: + maxItems: 5 + + clock-names: + items: + - const: axi + - const: core + - const: iface + - const: nrt + - const: top + + interrupts: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: config + - const: data + + iommus: + items: + - description: OPE CDM (Configuration DMA) port. + - description: OPE read (fetch engine) port. + - description: OPE write (write engine) port. + + operating-points-v2: true + + opp-table: + type: object + + power-domains: + items: + - description: GDSC CAMSS Block, Global Distributed Switch Controlle= r. + - description: CX power domain. + + power-domain-names: + items: + - const: camss + - const: cx + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - interrupts + - interconnects + - interconnect-names + - iommus + - power-domains + - power-domain-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + camss_ope: isp@5c42000 { + compatible =3D "qcom,qcm2290-camss-ope"; + + reg =3D <0x5c42000 0x400>, + <0x5c42400 0x200>, + <0x5c42600 0x200>, + <0x5c42800 0x4400>, + <0x5c46c00 0x190>, + <0x5c46d90 0xa00>; + reg-names =3D "cdm", "top", "qos", "pipeline", + "bus_read", "bus_write"; + + clocks =3D <&gcc GCC_CAMSS_AXI_CLK>, + <&gcc GCC_CAMSS_OPE_CLK>, + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_NRT_AXI_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>; + clock-names =3D "axi", "core", "iface", "nrt", "top"; + + interrupts =3D ; + + interconnects =3D <&bimc MASTER_APPSS_PROC RPM_ACTIVE_TAG + &config_noc SLAVE_CAMERA_CFG RPM_ACTIVE_TAG>, + <&mmnrt_virt MASTER_CAMNOC_SF RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names =3D "config", "data"; + + iommus =3D <&apps_smmu 0x800 0x0>, + <&apps_smmu 0x820 0x0>, + <&apps_smmu 0x840 0x0>; + + operating-points-v2 =3D <&ope_opp_table>; + power-domains =3D <&gcc GCC_CAMSS_TOP_GDSC>, + <&rpmpd QCM2290_VDDCX>; + power-domain-names =3D "camss", "cx"; + + ope_opp_table: opp-table { + compatible =3D "operating-points-v2"; + + opp-200000000 { + opp-hz =3D /bits/ 64 <200000000>; + required-opps =3D <&rpmpd_opp_svs>; + }; + + opp-465000000 { + opp-hz =3D /bits/ 64 <465000000>; + required-opps =3D <&rpmpd_opp_nom>; + }; + }; + }; --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E003C374E64 for ; Fri, 25 Sep 2026 09:09:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327403; cv=none; b=uaveUbqI8+gVpFu+h7FXqtBXO1mPF1GDpiYm3KrS4DpVkVH6p0FDT0r/X3Xth5VK58N+751OhLC2efiUR5eIOEjtT1pYMRxMNzcAShA8AnUV7c4coa8PIyAf5s06Lv0H5W1FMWbxyJcwYzCNJX/UOH9/BMzWAaiT91rS2ngEfhQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327403; c=relaxed/simple; bh=H3FZ7znaCS6E2tCa+3jHj85kDw9yZ0pmbfqMcQI6JqA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rsIm8UPrVvlyDiEzEVnU4tTgp7O7G7jBJa/iBNQ5M/DERxetT5v6RI1fHOZs61+UdHNh3KdGUeoNqVTNx7N/IKhQd7KlmNJG45VzxpFgm+JDTZ0La3hHrRFU2KOwIuv8pet5zzXnc0MNPHhUU/S7d8m2NrVO+LJl5LlzoZMSQqA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=IvCfmozJ; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=AhvRiYrT; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="IvCfmozJ"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="AhvRiYrT" Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4Yi8m4102869 for ; Fri, 25 Sep 2026 09:09:58 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= PagDSuh7l2ZhcYiXNCHSTvc79NuxyK2nfl6x2BVYD44=; b=IvCfmozJ6Tw88OYG BQftPtdyHnoCJIoCSWojfqPs3/I8gxD/0hGPQIT4LuU8U61KiKfUWNFjZjt4trhu CJrIPCjCpjFVmvi261T3d1cyw6cEIbFaICH6lRuw0tlhPt0m0JXRw1Iefo/otIPS RWX6N8dbyJ1MGnhuWlY2EDFBb8izgok5qdU/p84Zy1TWp1d4EnW89KLCR02EuLGx t8Mej/ANUlLDMwfc9w8y3w2ls31dh0xykVB9aIakGe58dRZk/N0gOJBQykkwynVm B8kXPAcHAO6i6lS4C6qsra/nKpkz3GQ5KBj9GQqgSdBgoY87P9AFESDeHXyl/fwy CkSzYw== Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw5q8un9t-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:09:58 +0000 (GMT) Received: by mail-qv1-f70.google.com with SMTP id 6a1803df08f44-90e80ce3597so14706046d6.1 for ; Fri, 25 Sep 2026 02:09:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327398; x=1790932198; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=PagDSuh7l2ZhcYiXNCHSTvc79NuxyK2nfl6x2BVYD44=; b=AhvRiYrTn4VPsMthPWcebWBXXIXWFUvYxZUX4uX6gcIQLkh5ZeGkoemWW8F/7N12r6 uhiR1ZjPV38+dj9qE+AhWgZUS79yF7KX07AGP4f41XW90JhBxzhFHkk+xe3rC8kcy/ov S1L8ieXtIKFKU8LztCLHCv3n3tsLUxEYKroTeZ458Y34YbpRQA7O5i68izMt1Jzl3Uvi 3xCymafp4lH21Dx25cXi/fmtqtDUh67WnAQeHdvDEN2VoxfmBUQVmGS+NIblOku1hyzP zD1ats2SN+UDVCs+4veWB1cWJsGgvpyKApKZ696K3rSkLHl+eK7xkMarwtWRCnQg4UwT AEHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327398; x=1790932198; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=PagDSuh7l2ZhcYiXNCHSTvc79NuxyK2nfl6x2BVYD44=; b=mhHnOzcA6Lkz5XCyTvon/pfWxaSJfiiVE33RdRZY/PrwEQcbolCFRArXnjKeidPozw lhluxuAoFIJgn7YM7jlrUvjQkKW9xjc/3X6Z8P55ZhRnLaAo4GPWp2YTxUYX2/iYSi3F xJExsqUe9jvMN/0o8Q0FuE+Cjb/JReijTnrCJh8goZwWEnh/y2s65TkXj/w8+61L9fQB dFf5Uq9e2itR5lpDoORBjTHTjGtKg+9ySOqfw8/JXclNM3/Z2VamfDrZ6LyiddRaD1B8 uJRHm3E5HeUL4HMZQna+l85Fc/pxfRJg9u6dmeErfLp9JryskF9Cx9js+cmz3IjPv84Z GGpQ== X-Forwarded-Encrypted: i=1; AKwUvBwKBUBHsa2o3yaYy4CLKiAFLbkouFHFRCufztfsQbf7g3QJy4KZvOk+dR82jcejCzrOqgAXh6kXRWa34vc=@vger.kernel.org X-Gm-Message-State: AFuF++lDtnisHLz0EIw7UJL4I2zyg7mcZ41hCCvUSzoIZ+fJKRDXDRCb CebC6AqFwD9wjebI2boagIu0+lK7+v/Xs2625T5Sw4jCEEJOXJ7nU29WxHAusIdcoc+4KkGIW1Q A4IX+Q0GC8K7PNBfOtdPkIAGtNy/O904SxlvL10GTOFaUg395/+3wmTLBdi4EjsnP3mo= X-Gm-Gg: AYBFou0txhvEx4HQ4dHCNAemYv8qICnYVdcxl6QIDu9qlhy/mkMEJI2FSKkzfEGkaE+ w1REWQ1Xjf0mpH6b9owKrHTqkYBjCp7hZYaC3+WQ5qAS0TVSsbBLb6ZQ8SXSnWURm6IAg8oDZZb NbUWgaRjrEhHQxCpdgj8fnKpFERyyjuCFSFrG6atqzTat9gR954wWt7HyH/vnMSJi5p5u4iSXs5 3K3OYt3O7igLPV1xJCfs2z9RAjKB7x5oAvqyKCXkLLUP0rAVGTcrd3biB9Akmn3eHpJSaOk6WeE sauSyZqgA5FT5MYlEK/6cod+3Ww6SoOmZUjYlDpNLm+8TUqlKUyidcxXYHe9aAiQ8zlN7pNIsqI 90UVhtolCbCyP9Pjeg11K8Is7/b8OL89fPPZGc892MwFCsRZwjuHw8NxAuox2QQ841AOK6KWpVB utFjfd0hKi8S0lSuZtHR94e2X52KTNwFTu3KR11ItW/WbqgW12enQ= X-Received: by 2002:a05:620a:471f:b0:93b:d7a3:45d5 with SMTP id af79cd13be357-93c43d77939mr320252785a.62.1790327397667; Fri, 25 Sep 2026 02:09:57 -0700 (PDT) X-Received: by 2002:a05:620a:471f:b0:93b:d7a3:45d5 with SMTP id af79cd13be357-93c43d77939mr320248985a.62.1790327397175; Fri, 25 Sep 2026 02:09:57 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.09.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:09:56 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:50 +0200 Subject: [PATCH v10 3/9] dt-bindings: media: qcom,qcm2290-camss-ope: Document shikra compatible Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-3-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Nihal Kumar Gupta X-Mailer: b4 0.14.2 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX3Zg4vh9HKRfw ErpmNJ6pSMEzVkQGJiwEHPDdzj6BitQnCuIwUef5wYRcVcqmx72jrgifeZllGZDyuyxWW3TtZZq cxHi9EzHLo8QVn+IKxmSASdGBANl/uE= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX+hnMR9C+wwlc xXbluJW+H+pe9gPnZV55BaHApIq8HmxH6g8Cmd1j/spwVtDEb/CNKXj1gm7cCiHHvt5yYVBDzQ8 fpSFi1xaHcfKkWm9fuPtftMz4tP+dqLLBPZ3CMxqDo9ogFy28Mi23l9IxhUTsAkTkLknSa54AUe 2PSWfTEnm2E5DpRCDDDu0tDTQiTjOnTu0EpB/T6IXyfSxOZLjtfpYURA6ej4zE5tFXjIG6QlUGw SAW9zV5IqeR37NjP/hWE/8HyAR/mYmASheu3xBD5sco/b5cZ3yqnLH++SFqNa4SZvnrR2E6le/h oxTeywgAUoHw4XsMDRkVnJc+SJtCEa+Ow+BFH1bOWbKVgYe11HEursTSRUX93mSJnlXUep+KTUf PhTevHZORdvewmgFXUiz8NQUQu3GDimx7dZDp8HSAN8oQun6dBXOslmxdqpWwkwmtsPyfm9+Jc0 EGcHPozJ5IBkzix7isQ== X-Authority-Analysis: v=2.4 cv=SYRi5fRu c=1 sm=1 tr=0 ts=6ab63a66 cx=c_pps a=oc9J++0uMp73DTRD5QyR2A==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=ZpdpYltYx_vBUK5n70dp:22 a=EUspDBNiAAAA:8 a=yPTVd8cUMD2GasGf7IAA:9 a=QEXdDO2ut3YA:10 a=iYH6xdkBrDN1Jqds4HTS:22 X-Proofpoint-GUID: phxMCXwqSJn8ctJjp1HT6EJN6SODVe8V X-Proofpoint-ORIG-GUID: phxMCXwqSJn8ctJjp1HT6EJN6SODVe8V X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 phishscore=0 malwarescore=0 suspectscore=0 bulkscore=0 impostorscore=0 clxscore=1015 adultscore=0 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 From: Nihal Kumar Gupta Shikra uses the same Offline Processing Engine hardware as QCM2290, add qcom,shikra-camss-ope compatible string with qcom,qcm2290-camss-ope as the fallback. Signed-off-by: Nihal Kumar Gupta Signed-off-by: Loic Poulain --- Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml | 6 ++= +++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope= .yaml b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml index f9c31bc88e94b028c241060bbd8e56e0bdc49af5..3359581bfb13e918bb4efb3bc41= 749e60d772ef4 100644 --- a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml +++ b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss-ope.yaml @@ -19,7 +19,11 @@ description: =20 properties: compatible: - const: qcom,qcm2290-camss-ope + oneOf: + - items: + - const: qcom,shikra-camss-ope + - const: qcom,qcm2290-camss-ope + - const: qcom,qcm2290-camss-ope =20 reg: maxItems: 6 --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 04D5047F796 for ; Fri, 25 Sep 2026 09:10:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327407; cv=none; b=mqDpqZPeljt6aUyW5RWJksrjFFFl7RXH2PmTNWRUVhYYznb8QDnR3bAgmrpZqgRBNw1JigYGzUy7noIy+Ai86oqZNGRWv+i2sy7CC7/mc45LDsyDhNPLheEHA0aH355irbMmcAGoXyNbHfRw8LqHe6RTtbBEMBz4cIdHj9CqzmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327407; c=relaxed/simple; bh=eFX4xFKGu1d2iMPrSFu9VG2KHuB4iXe/IQlKD1I5PhY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AK+ORfLJor7ho7JqtL3WKjF31jTQSFscCAJ2fo8aCFF4KidxDPePvcjnv06cUPPOvbNq3dz0b+1n3cc0yR5pzCKAfeBa+7hD0rHG0iRA+nVLLF15B1Mhi9ZxCsDsC9fWRHhLP4GSlPkt5VqIn8OMonrz6s+eaw6G3Klv+kvcuiU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=Yhv7d+ab; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=GdJnYFco; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="Yhv7d+ab"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="GdJnYFco" Received: from pps.filterd (m0279870.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4YXP0289462 for ; Fri, 25 Sep 2026 09:10:00 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= lQGoGb2ujLMFHLGciJF9hIS3vNu7w27PseR4q+F9Fug=; b=Yhv7d+abFLQGf5t3 mrQkbVYc1kRTjGA3oBmGW+QzziDvK0z1w71LlFrAM0ImYTjexx3C1LNCwsuUJtxD INojZxOxberVnYRHMx0cfch3Fm1+3IFCmhdFFVSYRbOG+t8sWGggG6NP2o8C+V1H PQNLjpdSczlfhbR3RLXNIumByvrnC9xQ8ySRcqLTY2a1rpFsyEg4cTgp1atYOX5X deXuWH0s+rvgI4jMt4OcI3C80kN4bqI/BO9MrEH0UtQXk/UPEh9mHxBxPXXocPmf /jdpVzdU88W+TOz5mwdc+OtDlyD1oN0xGco6o3bB7xYXclvEi94Z0O7LcXkFOYWW phc0EQ== Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw881tus9-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:00 +0000 (GMT) Received: by mail-qv1-f70.google.com with SMTP id 6a1803df08f44-9143cb073b9so1031516d6.1 for ; Fri, 25 Sep 2026 02:10:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327399; x=1790932199; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=lQGoGb2ujLMFHLGciJF9hIS3vNu7w27PseR4q+F9Fug=; b=GdJnYFco8ezFwVwmv+sluwUwa4ya4M82YBhTjc0soIYp1d7rvl9RtmZ41uePMHzCJm bGBPNI4m2ga4vPFThjDU+i/mSNCW2srV2mqWMekDrEdema9tYcVK37pGdqoZVfJCjjAs CbPtzLJKl3Z07ctB2sZxu1PDe2wwxPhQbop/QmCL6fjCt1j1YN50HuataSOCajFPMMTA 5ee6RSOdo9FUoF4rqt5xa9EESRdrITUPc4ssfCvivT1Jv2ZeFgkg6Sf2c0mw1ts+YZDD kUuH3drVlBeJBC7jbBPaowhMHaM1BBv5moW7XVvnKYXsBbXr8KCBe9Q+ZzbdOLzicb03 tj1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327399; x=1790932199; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=lQGoGb2ujLMFHLGciJF9hIS3vNu7w27PseR4q+F9Fug=; b=HPpGCfpiOu4uuNR7+J4ITctAh8nwkBMk0Uv/Y2uuWv4unTt93lub+AtZPwnzRf0mhK QP+Bp8y9rK0dXPeE8S4e04KkheCu5LBjBQj9wF7byWTzKTvo0qX7tTFjUJ2ATJkYvao3 p6VOhNfmQcmVKmRlSBGb3Ah4ZgIT6PyWWqKiDkMQEMKiZQ2aLV2Upxp6LDNPj39fRIiv vurPXCEcf5LIxJMWdQ31ToeDxGmj0z4hxYqQSGAvUd9D+BqQtmR49h4q/AsjKeHDksBE 4/Hny4hWjHR35hEhqjpeSlhvznzah25xh5+JnUhT2M+m4/eutUL5WEFGVD93or76QnMG rWBA== X-Forwarded-Encrypted: i=1; AKwUvBxbhgJQyZzoS6YuBfpc+9u3cXY1mCbkz/Vq3UCrWSG65V15fbfY3yoI5Nu5n9DgQpBsqxg3QJW8beR0y1U=@vger.kernel.org X-Gm-Message-State: AFuF++kQoSrmSaGphThhr3AfVEaT3Hh66DMCCe0+4xRz9g/aIxj6gwUS EA6yADsmsB3SQxEnU6VLrVyPZmab8yvdHvUjsBpcID7a8XKp9Btxd3eNk0FJ728wo4Ah31UU1PW nJtxr2mKdJOqawgrJpTdRj8zVwVvc1N/TfoToZyza9YZVS9AmZ0hmE9rbEAPsnrJVjBo= X-Gm-Gg: AYBFou3EO7xfEkVnWqhWOWLUsnuGUy+trmFQjbc42uyZIW+1xe8vIB4ctagCb6pNqXM /bF6x/V8QPbcXiSWoQQrvDxI2c3UheM03jpIreyBumjzx5Gu1/ZkAVj6YoGfTHJulA0S4+lBN/5 LiCPH+cZ5CdNMS+Q8dSC1oCz2OMWYt0ByrXN1bT7UdyD/vqy/ElMHSzEh4Urn3m99Bda2udaKwr f1I0ioih01F1Wg/2qoxk3xa0acAciwp2B28wxT+oio/t+nRcOMeG7mGrG+UK0mP5JQDXRM70Yii d7xPhbx0zI0iA7RMwCtq/1GW58hnHCoHftoeZKckLOC9U+ppjQCe465bUs8QB8Y4v2eFUcwKME6 Wzpmc4vXQ3IJorbov8T4v5qnnCnwBuQv9/iF/RKjBdcs4yJjYhRLAQ56S9nyXDfm/dNvfIigz6o VV1/Mj1Qy/6zsUtAzaq4gnajc7yf1dbId1Prb0KOFN8nG2Ki1N8w8= X-Received: by 2002:a05:620a:7010:b0:939:f522:b2f7 with SMTP id af79cd13be357-93c43cd31b9mr320614285a.33.1790327399365; Fri, 25 Sep 2026 02:09:59 -0700 (PDT) X-Received: by 2002:a05:620a:7010:b0:939:f522:b2f7 with SMTP id af79cd13be357-93c43cd31b9mr320610485a.33.1790327398804; Fri, 25 Sep 2026 02:09:58 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.09.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:09:58 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:51 +0200 Subject: [PATCH v10 4/9] media: uapi: Add CAMSS ISP configuration definition Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-4-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org X-Mailer: b4 0.14.2 X-Authority-Analysis: v=2.4 cv=TptzFzXh c=1 sm=1 tr=0 ts=6ab63a68 cx=c_pps a=oc9J++0uMp73DTRD5QyR2A==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=gowsoOTTUOVcmtlkKump:22 a=EUspDBNiAAAA:8 a=cBt3T3tByBXynNCq78MA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=iYH6xdkBrDN1Jqds4HTS:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfXys0F4vuFn/FC YtJUcKT9PglfKVTls8bhXgp9UuaZtzR7fz+1WhVbnl9y527hKbe5mL36qg8+OjQW/3eTu8icau5 zvYtXCcc7unPvxciz9oFmptD3Brc138yJIkSmiEeuqeKaCOm6lhoatzvUstmw/RF2D2VI+vUvou Z40Ys9/vnr5dn2tHa0eQLCCGPm4IeKSxbDiG6GBJzgmDGODB1Ox07CZhLquoYdrk6WGlmaRA8z/ 90P2ZraLlFtkRegZl7E2lE8TqkhM1CST4wnhi9/OBXXIuROS9uibowMLUJGUpARWWdI05hF7zqj 7xNV6xLixB55FlX8Jz+QD7jbCt8RfzzUlZgFZRIwEt1BjHpeAcIzkec6IkbFrXL+Oh6NpgUXWFO HiOxPzrTnKTezeTRSYsjzDd7z8fL5Jbsy8bxSUc2u0csQVKdNKsVnSR/c6IQ+oCFzhrMaO9zqxo EEH+Aq3yUt3Fk+wNyeA== X-Proofpoint-ORIG-GUID: t8uJLnN-EugiowLmSdflL5aTsXz7zswG X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX6DExWE4i0GeF 6WqamBprpGHiM1wvjS2rGPpYMosD/jgFvAU3NYziZ/EjR4wAPlRbh6IVB2nhOlDlkxXjiZeedXv aiOA4o6dTr+E+ra7AByloPZaB/q28KA= X-Proofpoint-GUID: t8uJLnN-EugiowLmSdflL5aTsXz7zswG X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 phishscore=0 clxscore=1015 priorityscore=1501 impostorscore=0 malwarescore=0 suspectscore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add the uapi header qcom-camss-config.h defining the ISP parameter structures used by the CAMSS Offline Processing Engine (OPE) driver. This includes structures for white balance, chroma enhancement and color correction configuration. The block type enum is shared across CAMSS ISPs so that userspace only has to deal with a single set of block identifiers. Signed-off-by: Loic Poulain --- include/uapi/linux/qcom-camss-config.h | 212 +++++++++++++++++++++++++++++= ++++ 1 file changed, 212 insertions(+) diff --git a/include/uapi/linux/qcom-camss-config.h b/include/uapi/linux/qc= om-camss-config.h new file mode 100644 index 0000000000000000000000000000000000000000..aa3d97cfcc78e22a6f7ed79bee3= 31c2dfd06f662 --- /dev/null +++ b/include/uapi/linux/qcom-camss-config.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Qualcomm CAMSS ISP Driver - Userspace API + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _UAPI_LINUX_QCOM_CAMSS_CONFIG_H +#define _UAPI_LINUX_QCOM_CAMSS_CONFIG_H + +#include +#include + +/** + * enum camss_params_block_type - CAMSS ISP parameter block identifiers + * + * Each value identifies one ISP processing block. The value is placed in + * the @type field of &struct v4l2_isp_params_block_header. + * + * @CAMSS_PARAMS_WB_GAIN: white balance gains and offsets (CLC_WB), + * &struct camss_params_wb_gain + * @CAMSS_PARAMS_CHROMA_ENHAN: RGB to YUV colour transfer matrix + * (CLC_CHROMA_ENHAN), &struct camss_params_chroma_enhan + * @CAMSS_PARAMS_COLOR_CORRECT: colour correction matrix (CLC_CC), + * &struct camss_params_color_correct + * @CAMSS_PARAMS_GAMMA: per-channel gamma correction curves (CLC_GLUT), + * &struct camss_params_gamma + */ +enum camss_params_block_type { + CAMSS_PARAMS_WB_GAIN =3D 1, + CAMSS_PARAMS_CHROMA_ENHAN =3D 2, + CAMSS_PARAMS_COLOR_CORRECT =3D 3, + CAMSS_PARAMS_GAMMA =3D 4, +}; + +/* Number of entries in each gamma channel LUT. */ +#define CAMSS_GAMMA_LUT_SIZE 256 + +/** + * struct camss_params_wb_gain - White Balance gains + * + * Implements the CLC_WB pipeline module. The pipeline applies three + * sequential operations per channel: + * 1. Subtract sub-offset (black-level subtraction) + * 2. Multiply by gain (colour balance) + * 3. Add add-offset (output pedestal) + * + * Gains are 15uQ10 (15-bit unsigned, 10 fractional bits). Offsets + * are 16-bit unsigned, normalised to full input scale (65535 =3D 1.0) + * + * @header: block header; @header.type =3D CAMSS_PARAMS_WB_GAIN + * @g_gain: green channel gain (15uQ10, 1024 =3D 1.0) + * @b_gain: blue channel gain (15uQ10, 1024 =3D 1.0) + * @r_gain: red channel gain (15uQ10, 1024 =3D 1.0) + * @g_sub: green sub-offset, subtracted before gain (16u) + * @b_sub: blue sub-offset, subtracted before gain (16u) + * @r_sub: red sub-offset, subtracted before gain (16u) + * @g_add: green add-offset, added after gain (16u) + * @b_add: blue add-offset, added after gain (16u) + * @r_add: red add-offset, added after gain (16u) + * @_pad: padding for 64-bit alignment, must be zero + */ +struct camss_params_wb_gain { + struct v4l2_isp_params_block_header header; + __u16 g_gain; + __u16 b_gain; + __u16 r_gain; + __u16 g_sub; + __u16 b_sub; + __u16 r_sub; + __u16 g_add; + __u16 b_add; + __u16 r_add; + __u16 _pad[3]; +} __attribute__((aligned(8))); + +/** + * struct camss_params_chroma_enhan - RGB to YUV colour transfer matrix + * + * Implements the CLC_CHROMA_ENHAN pipeline module. All coefficients are + * signed 12-bit fixed-point Q3.8 (range roughly -8.0 to +7.996). + * + * RGB2Y - Luma (Y) coefficients + * Y =3D v0 * R + v1 * G + v2 * B + * + * @luma_v0: R-to-Y coefficient (12sQ8) + * @luma_v1: G-to-Y coefficient (12sQ8) + * @luma_v2: B-to-Y coefficient (12sQ8) + * @luma_k: Y output offset (9s, 0 =3D no offset) + * + * RGB2Cb - Chroma (Cb) coefficients + * Cb =3D a x ((B - G) + b(R - G)) + KCb + * with: + * a =3D ap, when (B-G) + b(R-G) > 0; a =3D am, when (B-G) + b(R-G) =E2= =89=A4 0; + * b =3D bp when (R-G) > 0; b =3D bm when (R-G) =E2=89=A4 0 + * + * @coeff_ap: Cb positive coefficient (12sQ8) + * @coeff_am: Cb negative coefficient (12sQ8) + * @coeff_bp: Cb positive coefficient (12sQ8) + * @coeff_bm: Cb negative coefficient (12sQ8) + * @kcb: Cb output offset (11s) + * + * RGB2Cr - Chroma (Cr) coefficients: + * Cr =3D c x ((R - G) + d(B - G)) + KCr + * with: + * c =3D cp, when (R-G) + d(B-G) > 0; c =3D cm, when (R-G) + d(B-G) =E2= =89=A4 0 + * d =3D dp when (B-G) > 0; d =3D dm when (B-G) =E2=89=A4 0 + * + * @coeff_cp: Cr positive coefficient (12sQ8) + * @coeff_cm: Cr negative coefficient (12sQ8) + * @coeff_dp: Cr positive coefficient (12sQ8) + * @coeff_dm: Cr negative coefficient (12sQ8) + * @kcr: Cr output offset (11s) + * + * @header: generic block header; @header.type =3D CAMSS_PARAMS_CHROMA_ENH= AN + * @_pad: padding for 64-bit alignment, must be zero + */ +struct camss_params_chroma_enhan { + struct v4l2_isp_params_block_header header; + __u16 luma_v0; + __u16 luma_v1; + __u16 luma_v2; + __u16 luma_k; + __u16 coeff_ap; + __u16 coeff_am; + __u16 coeff_bp; + __u16 coeff_bm; + __u16 coeff_cp; + __u16 coeff_cm; + __u16 coeff_dp; + __u16 coeff_dm; + __u16 kcb; + __u16 kcr; + __u16 _pad[2]; +} __attribute__((aligned(8))); + +/** + * struct camss_params_color_correct - colour correction matrix + * + * Implements the CLC_CC pipeline module. The matrix computes: + * Out_ch0 (G) =3D a0*G + b0*B + c0*R + k0 + * Out_ch1 (B) =3D a1*G + b1*B + c1*R + k1 + * Out_ch2 (R) =3D a2*G + b2*B + c2*R + k2 + * + * @header: block header; @header.type =3D CAMSS_PARAMS_COLOR_CORRECT + * @a: G-input coefficients per output channel (12s; + * a[0]=3DOut_G, a[1]=3DOut_B, a[2]=3DOut_R) + * @b: B-input coefficients (12s) + * @c: R-input coefficients (12s) + * @k: per-output-channel offsets (typically 9s effective) + * @qfactor: Q-format selector (2u): + * 0 =3D 12sQ7 (range ~-16.0 .. +15.992) + * 1 =3D 12sQ8 (range ~-8.0 .. +7.996) + * 2 =3D 12sQ9 (range ~-4.0 .. +3.998) + * 3 =3D 12sQ10 (range ~-2.0 .. +1.999) + * @_pad: padding for 64-bit alignment, must be zero + */ +struct camss_params_color_correct { + struct v4l2_isp_params_block_header header; + __u16 a[3]; + __u16 b[3]; + __u16 c[3]; + __u16 k[3]; + __u16 qfactor; + __u16 _pad[3]; +} __attribute__((aligned(8))); + +/** + * struct camss_params_gamma - per-channel gamma correction curves + * + * Implements the CLC_GLUT pipeline module, applied in the RGB domain. It + * holds one independent lookup table per colour channel. Each table is a + * direct (not segmented) map of input level to output level. + * + * Each table has @CAMSS_GAMMA_LUT_SIZE (256) entries of 16-bit unsigned + * output. The number of significant output bits follows the width of the + * engine's internal bus; the upper bits are ignored by the hardware. + * + * The module maps a 12-bit input to an 8-bit output: the top 8 input bits + * index the table and the low 4 bits are used to linearly interpolate + * between adjacent entries. Entry i therefore represents the output for + * input level i/255 of full scale. + * Output range: 0x00 =3D black, 0xFF =3D white. + * + * How to fill a curve (same on all three channels for pure luminance + * gamma; different curves per channel additionally shift colour balance): + * + * Identity (pass-through, gamma 1.0): + * lut[i] =3D i; // i =3D 0..255 + * + * Encode with gamma g (e.g. sRGB-like, g =3D 2.2): + * lut[i] =3D round(pow(i / 255.0, 1.0 / g) * 255.0); + * + * @header: block header; @header.type =3D CAMSS_PARAMS_GAMMA + * @glut: green channel gamma curve + * @blut: blue channel gamma curve + * @rlut: red channel gamma curve + */ +struct camss_params_gamma { + struct v4l2_isp_params_block_header header; + __u16 glut[CAMSS_GAMMA_LUT_SIZE]; + __u16 blut[CAMSS_GAMMA_LUT_SIZE]; + __u16 rlut[CAMSS_GAMMA_LUT_SIZE]; +} __attribute__((aligned(8))); + +#define CAMSS_PARAMS_OPE_MAX_PAYLOAD \ + (sizeof(struct camss_params_wb_gain) +\ + sizeof(struct camss_params_chroma_enhan) +\ + sizeof(struct camss_params_color_correct) +\ + sizeof(struct camss_params_gamma)) + +#endif /* _UAPI_LINUX_QCOM_CAMSS_CONFIG_H */ --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED50D477E53 for ; Fri, 25 Sep 2026 09:10:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327407; cv=none; b=tUc5F7K0lXtQrAbanu7tMDdwItONRWYBsINShH2z5nIbM6BghRHBD1EL4oiG0nxIoLc8kle8ofv++jD3BRp7BHDEMprx66DF9apJPzLAqVr0wfy/LCCGtamyoAKNlt8TBuETXVZe1wJlK2OFZ+nx4s0TFoCTFgwjLfaEP5IR2ag= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327407; c=relaxed/simple; bh=FBaxmp4RMgRnrPItYfxrye8DWG+UjGhnzM+Jbssrx9s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UJ93Fiu2WruSWd3ZtMkHrGpLXiFvhCAV9p8UGIwUmmu+tuFXmEKnjOND415nQp7f4eQUPmwMteTabUUTOkdyt4yqI/8cGye0EtrEez9iKJ2agjAMEIjbT6O5stXPcG3k7kVgH5q9fkkta1jGhlDsrYVkXW7LKpom4Z4aa5b4lRc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=E5X03eSM; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=Xi4Y1Hpx; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="E5X03eSM"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="Xi4Y1Hpx" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P5In7Q600190 for ; Fri, 25 Sep 2026 09:10:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= ezSgm0eHPd43DlPu4NAZMO75tx3TP1BnI44kHNSTRVA=; b=E5X03eSMaB7dzDKg Ygkz5Pwe78Qa4Emy4a8ztrggFAxUG9VMhI6DY/TBh1p9XBbvWbV/NGR0ucCxl8Ei vaNq+Ehqtchq7qgcIps1MgnyPNY6CPux0rYdXy01TxFT+zZVFf/USOnTznFpEloh ysb9AtS/r4fkGIMvR7/5pEhE+rXCCEENU6hQWCij19LnTYnq7JWaUDKC3lPu1Rc+ lF6vDlDpEROutChhHDmv3YrQtzChH3ZRR12Znls+2+KU1y14IDmxZCAlHiWJL6mr yFPOCFzF8Yhw2c8FkoIeQApj8TValyOTPmuc46ure4S73HN5O/EYI8C0f76pwaBm /UhAZA== Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gwjpvrnv9-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:01 +0000 (GMT) Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-9393ac4961fso98421385a.2 for ; Fri, 25 Sep 2026 02:10:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327401; x=1790932201; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ezSgm0eHPd43DlPu4NAZMO75tx3TP1BnI44kHNSTRVA=; b=Xi4Y1HpxmsWiSPh12vxk74KxUlnWSlBBV7ZKTkds9NaekJEcNl7zNMnTSUmy2KmA8d kQfL+pqkg/x6iLSNe15zyF+4+ohJASKhz7j/zSUll4FzT6ScR1xT2t15Y6ykem6bgheb J6JX5pUyh5b9uD5iee3qZgAzjhBAxuliSU4e8C1IiRibKyK/f9gIO68kpytEDGKsHA78 MuOJmPzT0dqjMXFwxqmy/bVcxrxqcZVlomgwqZrMo721sD/fiA6kEcI2cGN7TSCGhQWO Gh+bWXnm1djanSB+1jcY4T8a/gk/BCJVOuE43UkioxhG9Lz7dCwM8FtVqfsvfqf68jz7 ZmxA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327401; x=1790932201; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ezSgm0eHPd43DlPu4NAZMO75tx3TP1BnI44kHNSTRVA=; b=Pm8d21iBdRygcHtv0UHcjUAgWP9NbTHZ5qqZpngEZXFiyIV1YJVsrGhzeJXsmycz4F Gs+3Po2xlQOoj4YxIPQIUp2qEeh37z9CuJVnub1ahfcRn6ujwe0QmkndLQg4BTzi/TKA pPhF1/MklJjUQ89Gkjl1SeIWXOY4hMuZ7JRG6Q0SJUnlyMsJOVbN7P26sl/8VH9CPhJ/ aBymUW+6ey4A7Gk3y+AIKFcIQVtVg2/ErY2Sszi6JwwMHRK/3AK7UWVX1olPD9bBRto5 KRHlHzy72nZTIFvP90f7/yt4g2aeEMglcYZ2GzqZyYRUSH3YhzXIP/Hg9MgNHtaO7XpP FdgA== X-Forwarded-Encrypted: i=1; AKwUvBx/tqkCouzWnh2n0pR+R5Mk8m6iUStAayhzV7s+Ycxg2kjHhsXtAepOoaaiNF29SoWtJUGTJ29e0i63Pyw=@vger.kernel.org X-Gm-Message-State: AFuF++naEtAYOFEezcLB1tPxC82sGIbPwzEkmyU9gidfrPrUDeIhPsu6 ctEGxUlGZTLK2U8W61yw3AectgyUlnjTQSTvuR/QqaeUTlpBUQ83I6YtC0teqvwmWPZ4oTQHdgm bvmXUjQAFBqWuIjp9q6p8zBDZyedovfjBGgyTEsmBFRAJafxXWGyUVOhJaZiwYDtNTAY= X-Gm-Gg: AYBFou0VEtBqaH60DnsoqqpVCZqJJ3QCdZkxT9+qzjyB7J09sXCoht6wszJ7Kfpdf9U sMTDdCMu1ONIW1Co7ZzgYB4uVEWPTFNoSta3AtU2rks7iABsIi502EPLFjtQTWhp+LhNh+wQVGM g2yE/XXOGR8K5YZ13oltpctXFjBdrbHhu7CASZiufJ95nxsqQD5xvxGkgBTxJ0mIrnBGp/TjSYG IVda63StmsftM7FIrIaAU6ui8BQSo7EIZM4sI0Quv53LODxRbwP3Y5896r/G7Fjbyr4mt1Gkdbj 1R3OKsitGvPbbUXhtLtdfa/8JXkL6nxV4N/fda+LhIPlKpT5ovQ2txSwEdNTNkquKdU0wRht7XQ MuE1c7KkFO2CO0eLBsnkNi+IwndQk9bprRTRhL7wwdgjKLKcLXPriCMmEj//mTc5MXBeLFPBrGd sMLJ5UAm9tJJ+jjuhtovS1k37xOxWshpCqLczBh9EzfeDTjk5Megs= X-Received: by 2002:a05:620a:26aa:b0:93a:2a59:2ad0 with SMTP id af79cd13be357-93c43bca4b9mr342528785a.16.1790327400975; Fri, 25 Sep 2026 02:10:00 -0700 (PDT) X-Received: by 2002:a05:620a:26aa:b0:93a:2a59:2ad0 with SMTP id af79cd13be357-93c43bca4b9mr342524785a.16.1790327400462; Fri, 25 Sep 2026 02:10:00 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.09.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:09:59 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:52 +0200 Subject: [PATCH v10 5/9] media: Documentation: uapi: Add qcom-camss ISP params documentation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-5-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org X-Mailer: b4 0.14.2 X-Proofpoint-GUID: yu3EZJNXpc_6xwKg5NO5RXWLSEXGz9iq X-Proofpoint-ORIG-GUID: yu3EZJNXpc_6xwKg5NO5RXWLSEXGz9iq X-Authority-Analysis: v=2.4 cv=aLBlOr9m c=1 sm=1 tr=0 ts=6ab63a69 cx=c_pps a=50t2pK5VMbmlHzFWWp8p/g==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=Nff7jVtaK1xTle8F27sA:9 a=QEXdDO2ut3YA:10 a=IoWCM6iH3mJn3m4BftBB:22 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX030Zcpobv0c/ WRjXAmOUqECuQQ9etWXqPGtk9o2moyFXxdK39E/TxsOazmm8M+FZpNThbDKtfYJrGvnaWchT+Nb 3FOWX4JKywdgJlw43EShQY1ki8NO4jk= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfXyVzKvXBM6XTT 4FN5mRI8Sz5BQIgXSAKNIuYwHPrD7/H/aAhp+ru092sgRXVHxIxe0fhLx307S0DlepxQt9+aeQE ecaFaRveuyIj5u6fduORWF0WcY1qau+WCer/cwCIBbROa0hUvaM5VtN7uqOuEoJD6yF39kG+Pwv CJ/gt9fGSmq1EfpLuR6YxQLxB8MN92Fp3z5Jqo4lLqsat47u/XfCPUMhTLxUpVDlTN6EBgfOHTn iP9JaqnjQUKjY+lM/OFx5yHDSDJvJOePUc3R5dGOg5oZSETFmF6/c68ZhGyuVtWa3E9Vjq12N1E nIQ2acEahplC2idPRIKhgD9LrbCQrwmCq4lvIP57bRk+BZR5F2HbM08Pvq1Ux5P94haffzMIpwk MZcp7PF04F6v/fW0K6n1Q/wbenx622PmVlIVZB+DobTIznME/09j9YsQdyQW+owPQC2N2CoUaou Ilv9QT9jn4E3NBwNoVw== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 suspectscore=0 malwarescore=0 priorityscore=1501 clxscore=1015 phishscore=0 adultscore=0 impostorscore=0 spamscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add documentation for the Qualcomm CAMSS ISP parameters metadata format (V4L2_META_FMT_QCOM_ISP_PARAMS). The format is built on the V4L2 extensible ISP parameters system, with per-block structs defined in the qcom-camss-config.h uAPI header, and is designed to be shared by any CAMSS ISP engine exposing a parameters metadata output video node. The Offline Processing Engine (OPE) ope_params node is the first consumer, with additional engines expected to add their own parameter blocks in the future. Signed-off-by: Loic Poulain --- .../userspace-api/media/v4l/meta-formats.rst | 1 + .../userspace-api/media/v4l/metafmt-qcom-isp.rst | 147 +++++++++++++++++= ++++ MAINTAINERS | 1 + 3 files changed, 149 insertions(+) diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Docum= entation/userspace-api/media/v4l/meta-formats.rst index b5455229837e707c24e134438d5e2fd12cb3bf37..25b46af4d9f7faab37000076c53= 0e9aad5b4a076 100644 --- a/Documentation/userspace-api/media/v4l/meta-formats.rst +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst @@ -20,6 +20,7 @@ These formats are used for the :ref:`metadata` interface = only. metafmt-intel-ipu3 metafmt-pisp-be metafmt-pisp-fe + metafmt-qcom-isp metafmt-rkisp1 metafmt-rppx1 metafmt-uvc diff --git a/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst b/D= ocumentation/userspace-api/media/v4l/metafmt-qcom-isp.rst new file mode 100644 index 0000000000000000000000000000000000000000..2f3654a9ba897d0d1481d38a711= 7be8e84b1a99e --- /dev/null +++ b/Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst @@ -0,0 +1,147 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. c:namespace:: V4L + +.. _v4l2-meta-fmt-qcom-isp-params: + +************************************** +V4L2_META_FMT_QCOM_ISP_PARAMS ('QCIP') +************************************** + +Configuration Parameters +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The ``V4L2_META_FMT_QCOM_ISP_PARAMS`` format carries image processing +configuration for the ISP engines found in the Qualcomm Camera Subsystem +(CAMSS). It is passed to a metadata output video node using the +:c:type:`v4l2_meta_format` interface. + +Rather than a single struct containing sub-structs for each configurable a= rea +of the ISP, parameters use the :ref:`v4l2-isp` parameters system, through = which +groups of parameters are defined as distinct structs or "blocks" which may= be +added to the data member of :c:type:`v4l2_isp_params_buffer`. Userspace is +responsible for populating the data member with the blocks that need to be +configured by the driver. Each block-specific struct embeds +:c:type:`v4l2_isp_params_block_header` as its first member and userspace m= ust +populate the type member with a value from :c:type:`camss_params_block_typ= e`. +Populated blocks must be placed consecutively in the data member, and the +combined size of all populated blocks must be set in the data_size member = of +:c:type:`v4l2_isp_params_buffer`. + +The set of supported blocks depends on the CAMSS engine consuming the buff= er. +The block definitions themselves are shared across CAMSS ISPs; currently t= he +Offline Processing Engine (OPE) is the only engine consuming them, through= its +``ope_params`` metadata output video node. Additional engines and blocks m= ay be +added to this format in the future. + +A block carrying ``V4L2_ISP_PARAMS_FL_BLOCK_DISABLE`` bypasses the +corresponding hardware module. Any other block updates the module's +configuration and leaves it enabled. Blocks omitted from a buffer keep the= ir +previously programmed configuration and enable state; until userspace subm= its +a block for a given module, the driver's default configuration applies. + +OPE processing pipeline +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The OPE is a memory-to-memory engine that reads a Bayer RAW frame from its +``ope_input`` node and writes a YUV frame to its ``ope_disp_output`` node.= The +parameter blocks configure fixed-function hardware modules that the frame = data +passes through, in the following order: + +.. code-block:: none + + Bayer RAW in RGB domain YUV domain = YUV out + (8/10-bit) +------+ +------+ +------+ +------+ +------+ +---= ---+ (NV12/NV16/ + ----------> | WB |-->| DEMO |-->| CC |-->| GLUT |-->|CHROMA|-->| DS= C |-----------> + +------+ +------+ +------+ +------+ |ENHAN | +---= ---+ NV24/GREY) + +------+ + +The stages, and the parameter block that configures each one, are: + +.. flat-table:: OPE pipeline stages + :header-rows: 1 + :stub-columns: 0 + + * - Stage + - Module + - Parameter block + - Function + * - WB + - CLC_WB + - :c:type:`camss_params_wb_gain` + - Per-channel white balance gains and black-level / pedestal offsets, + applied to the raw Bayer data. + * - DEMO + - CLC_DEMO + - *(none)* + - Demosaic: reconstructs a full-resolution RGB image from the Bayer + mosaic. Always enabled; not configurable through this format. + * - CC + - CLC_CC + - :c:type:`camss_params_color_correct` + - Color correction matrix applied in the RGB domain. + * - GLUT + - CLC_GLUT + - :c:type:`camss_params_gamma` + - Per-channel gamma correction curves (256-entry LUTs). + * - CHROMA_ENHAN + - CLC_CHROMA_ENHAN + - :c:type:`camss_params_chroma_enhan` + - RGB to YUV color transfer matrix. + * - DSC + - Downscaler + - *(none)* + - Chroma (and, when required, luma) downscaling to produce the reque= sted + YUV subsampling, e.g. YUV 4:4:4 to 4:2:2 (NV16) or 4:2:0 (NV12). + +The input node accepts 8-bit and 10-bit packed Bayer RAW formats (for exam= ple +``V4L2_PIX_FMT_SRGGB8`` and ``V4L2_PIX_FMT_SRGGB10P``). The output node +produces semi-planar YUV (``V4L2_PIX_FMT_NV12`` / ``NV21`` / ``NV16`` / +``NV61`` / ``NV24`` / ``NV42``) or luma-only ``V4L2_PIX_FMT_GREY``. A +configurable stage is bypassed while its block carries +``V4L2_ISP_PARAMS_FL_BLOCK_DISABLE``. + +The following example populates an OPE parameters buffer with a white bala= nce +and a gamma correction block: + +.. code-block:: c + + struct v4l2_isp_params_buffer *params =3D + (struct v4l2_isp_params_buffer *)buffer; + + params->version =3D V4L2_ISP_PARAMS_VERSION_V1; + params->data_size =3D sizeof(struct camss_params_wb_gain) + + sizeof(struct camss_params_gamma); + + __u8 *data =3D params->data; + + struct camss_params_wb_gain *wb =3D + (struct camss_params_wb_gain *)data; + + memset(wb, 0, sizeof(*wb)); + wb->header.type =3D CAMSS_PARAMS_WB_GAIN; + wb->header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_ENABLE; + wb->header.size =3D sizeof(struct camss_params_wb_gain); + + /* Unity gain on all three channels (15uQ10, 1024 =3D 1.0) */ + wb->g_gain =3D 1024; + wb->b_gain =3D 1024; + wb->r_gain =3D 1024; + + data +=3D sizeof(struct camss_params_wb_gain); + + struct camss_params_gamma *gamma =3D + (struct camss_params_gamma *)data; + + memset(gamma, 0, sizeof(*gamma)); + gamma->header.type =3D CAMSS_PARAMS_GAMMA; + gamma->header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_ENABLE; + gamma->header.size =3D sizeof(struct camss_params_gamma); + + /* Identity curve (pass-through, gamma 1.0) */ + for (unsigned int i =3D 0; i < CAMSS_GAMMA_LUT_SIZE; i++) + gamma->glut[i] =3D gamma->blut[i] =3D gamma->rlut[i] =3D i; + +Qualcomm CAMSS ISP uAPI data types +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. kernel-doc:: include/uapi/linux/qcom-camss-config.h diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c9dfb48e900df71a86d4686d3ec2c..b5593f814b60fcbcd88f4b4aad2= 5880d19825dc0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22363,6 +22363,7 @@ L: linux-media@vger.kernel.org S: Maintained F: Documentation/admin-guide/media/qcom_camss.rst F: Documentation/devicetree/bindings/media/qcom,*camss* +F: Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst F: drivers/media/platform/qcom/camss/ =20 QUALCOMM CLOCK DRIVERS --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84FE148423C for ; Fri, 25 Sep 2026 09:10:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327421; cv=none; b=dY7KYsc5qeVK5rUn1SnxliyqbjOBbBgGuxCd6RIgExZwXoKCfxbXZp/JyxWc3PTdii/rrjz+F75mpRV8pC+SwJ+nUjLSKs7crm4uw5xnH/ByJW2vG8TZUVH/Dfb1/I5cS3sZT18IV5ImCp1ea1e6DY5pSOMosqhkbyuDLZ9V+sU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327421; c=relaxed/simple; bh=7fvGNXXvmcUhzmdGtuoIN8oBOedbemratYejOIiRYso=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pwDFN5dJgjhk5G41tCPtYoi21e9BTvW2fGRwnV6IcwukLMcCVa+mF7TEdvogu6DBS4BaWuVUmMunKKuZJT9JhKtmdkRTZQ6q326WTKHA7pr+VCCOVplWkCbcvaHt08rbgM2jn+IULQZghgtEOveW2ww232of2dQiR2JywnNareE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=QMBMnQ1x; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=gQZ7PmH/; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="QMBMnQ1x"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="gQZ7PmH/" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4Z2kt1194495 for ; Fri, 25 Sep 2026 09:10:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 62t1krISk4lQqvhEUosAG7z2ayuU/95aHi8bt3Y7miM=; b=QMBMnQ1xaZlJabYk vtAs2GCblpUGreUQzxHp5Yjq5HTZUAzMzm4LATozOIZoQewlSv7IEt7D/gtWwzWT eAG/FihfJMlNtazF7q0LIrNCvI2S2tUuDh/8k48HgII1DNM8YXss4TE0aXyEXPVC +mc1Q0TSvYSKV9KUaiQD7tqi+/AsS1GeX4ZRbaf7lu1a0L9nboDIinmaHGLiyI7G FaHLwp6i+YZNmwG9eYYPGEWciLsQ5TY4AXBGkEpnxO9qTvVkkWEv3/rtuXFA3Pe5 eXk2dgvqrHQ069pbyS9ZGZXauQ3lmNCU3I2YLpbnn1fkEY98AlD92UbclpFOUW1p zISkNQ== Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw874jswr-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:06 +0000 (GMT) Received: by mail-qk1-f198.google.com with SMTP id af79cd13be357-93a00c70d28so113328785a.0 for ; Fri, 25 Sep 2026 02:10:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327406; x=1790932206; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=62t1krISk4lQqvhEUosAG7z2ayuU/95aHi8bt3Y7miM=; b=gQZ7PmH/+Ss9Ed4+ORV7820r2L/ecBYFHwOlQm+gjjf6R5Im8DkHuzcCYWFDBq+jYK zkFtxBa6AF82DvIvoeVGwBKh7UH3KDL0o8x0YIxijk8ODxgqfDZBbAZ+/PI1JcEDhtBZ 5CMsChHYtxnCy/rWOrhguIWfEAJ5zm4PCeX0WTgK66tHWP4P1MSHPo9tiHmZywCdFCh+ sy4E9DQIooKPnfQBZ4uLLQVSUvaRJkzyNWB78/gkm4KDPYxwH3OCMG1mKQfCL2fmF/9V /bNrZH/xBmJX4vuz2nSp0OSG7tzEh15NuSSIfg7x8r3VZ/y+KPa8tGR+IHlw4pRtWjVX zyGQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327406; x=1790932206; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=62t1krISk4lQqvhEUosAG7z2ayuU/95aHi8bt3Y7miM=; b=mHZvN7VAeH36rrA1yP2WBRXFTXll+u1gJvqOGT4XRoDnT+joCjtEbFi1d3eMY1zks2 oj0Qkx44q1AMhtXASjsAFgslNRyEpk3bFI7v8cm6q+D0RfvjMNA0EttYT/oE4+Gyo6gr 5mUmd0L1+lC9f6qjFI7i9CYrZpMgxgJfjg5O+pEupNFQI5SuFn7NAt2SbuHC+LUF1kIA Ows+g5v/HhGBfvCT8qSmH3XvKxqg8rx0QL7bs26v0rNg7tlyjRQbSRP8dkfl+J8Xcw+j XR/kUrG8akon/mS8q8tJ0RfrS3zs36QUxWHa1FWOdZp+Euu5Fi4Xpsg/4jnFovtnIksT cJBQ== X-Forwarded-Encrypted: i=1; AKwUvBz0SifkYSh0E2RQSb0ocQLxoJ5fhX7zFqKAXOfRkxPbVziG7Mc4+jreZvTKmZeMv6gKiO9Q4oyf2ZuhI7w=@vger.kernel.org X-Gm-Message-State: AFuF++kJ0qiO9LLH20be4PiD1B+YtWL0Xy0QOZyEvmZeiIc4yocl86zc 4FVWZo9pj44ZXjRXH5dZCxqKhSoxhmW2ap9vbTUng+Tne4ZDmElSUqZE+GEmFm11Qcg93n7QcfR GTZ7ZzSPLJ6AiMD/gVEM31Px/N4wtfzuBVrwp7ewpc5DMdnnzB0riMDp5C3xSoCI4ygs= X-Gm-Gg: AYBFou3xEwY54uAh8Xh8VfkyRhLUZFw5224Q5km5q6ayP5CntiPcquPVqo0chmpnw8z A8ryufUrxLOTwlh8zoaPPuakGtWPb5uJHEF4crddA73KuVj83NuX+PWHK2XYhgGI4IYulIbarAx Yt9nZMdP2EtXsfzLnF+PH4q2ehVTFaE2MIHC1x3P61tBIdWhkOmZvWvmG1OQksB27d8rXhru2wa +9MMOcwEhbxRjUoNvk3xDYGnJtMsr86WsN/tyf/JqM5Fead4TvHq3uHN9CkZTbMW5TOrNCcqNdu Rp7fS1+RRyP7+Rr8QydUDeGd/t7aL8ip8b4Lprr94Ut9nNNXoe5iBJs2u1hZpJTFFdyTVfhnLcu 42zGMlu4YkWHlT5Z0Gf9vZWfKZzD+Kr1gS/RfFDfUBt0qcSEHEUDqstWQIMfCvVN0kmgRtmBZRL qkvq6cN8UyI+6nJjaJMvcTi2aA5p/2OPYgEPHkkdIAw3LbuBVfCmw= X-Received: by 2002:a05:620a:43a3:b0:93b:be6d:4f3e with SMTP id af79cd13be357-93c43be5053mr341471985a.25.1790327403830; Fri, 25 Sep 2026 02:10:03 -0700 (PDT) X-Received: by 2002:a05:620a:43a3:b0:93b:be6d:4f3e with SMTP id af79cd13be357-93c43be5053mr341462885a.25.1790327402512; Fri, 25 Sep 2026 02:10:02 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.10.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:10:01 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:53 +0200 Subject: [PATCH v10 6/9] media: qcom: camss: Add CAMSS Offline Processing Engine driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-6-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Hans de Goede X-Mailer: b4 0.14.2 X-Proofpoint-ORIG-GUID: jge3RIoQl7u0BI7vawISGi0kBFTz0pk3 X-Authority-Analysis: v=2.4 cv=MI71C8Zl c=1 sm=1 tr=0 ts=6ab63a6f cx=c_pps a=qKBjSQ1v91RyAK45QCPf5w==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=NEAV23lmAAAA:8 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=7-FJklI2-Zo6aJ5MJCUA:9 a=nsvEtg1wbKX51V2b:21 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 a=O8hF6Hzn-FEA:10 a=NFOGd7dJGGMPyQGDc5-O:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfXyJuBiN2Eyh7n AhKBO45R22RdlmUVZOf196Ryfp6wyOpd0b3yTIKoMyTR/3e2kGdV/j2uhG3oXOeTtuGM2WTzpvj 9ul67Lyj8N5QJqCN/f3N20khXy28tI/SIN8+yQiA7fwvzd9dXMS+HJPbbL8+LQ73brVSb8MBYuL h8n+wMSPwZ7CDKMkEIjRuNZLi0u0kTRaanXHPuYOGuy5hsVTwslwp0TgqsR/8ou1LL99fXhJ2I0 EsVTwDZR8NgWbA0F2psz3QV2+zYV3opxdZVTL+rAr8tp01vITjAkNsaTPlfD/hrA6/+ROp3D22w yziy/VhwSRzHjR0cDxzW/FnVJ8rhcXU2PEik9SKQ4w0ur7xK7j+vCbXIFnByKdQ9+0zmb7JcXPB 2d/75uDaQ6J9pRAnlqnheKZjxDdX4lPpC/nyW+QENxc4IALiXYdSBhaH3JaBnNJZNAqVw7NWuVB 2Vy35I4LVdguJ/6diIw== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX3hbAtxr/GXDi UQMWBUOYNVmnHrRkFZ/ufDJZRAF1H0tw8xzLOQ3ZyQCln3z2qOAjzGyFx65/zuSI85yy6sIykxk dpV1fU6cyZ9ElYYlOWT5qFzUTjE9rvo= X-Proofpoint-GUID: jge3RIoQl7u0BI7vawISGi0kBFTz0pk3 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 malwarescore=0 clxscore=1015 spamscore=0 priorityscore=1501 impostorscore=0 phishscore=0 lowpriorityscore=0 adultscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add an image processing driver for the Qualcomm Offline Processing Engine (OPE). OPE is a memory-to-memory ISP block that converts raw Bayer frames to YUV, performing white balance, demosaic, chroma enhancement, color correction and downscaling. The hardware architecture consists of Fetch Engines and Write Engines, connected through intermediate pipeline modules for pix processing. The driver exposes three video nodes per pipeline instance: - ope_input: Bayer RAW input (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - ope_disp_output: YUV output (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - ope_params: ISP parameters (V4L2_BUF_TYPE_META_OUTPUT) Hardware features: - Stripe-based processing (up to 336 pixels wide per stripe) - White balance (CLC_WB) - Demosaic / Bayer-to-RGB (CLC_DEMO) - Color correction matrix (CLC_CC) - Gamma LUT (CLC_GAMMA) - RGB-to-YUV conversion (CLC_CHROMA_ENHAN) - MN downscaler for chroma and luma planes Default configuration values are based on public standards such as BT.601. Processing Model: OPE processes frames in stripes of up to 336 pixels. Therefore, frames must be split into stripes for processing. Each stripe is configured after the previous one has been acquired (double buffered registers). To minimize inter-stripe latency, stripe configurations are generated ahead of time. The driver is split into three source files under the ope/ directory: - core.c: the OPE m2m driver itself: probe, power management, V4L2/media device setup, format handling, stripe generation and hardware programming. - pipeline.c/.h: a small declarative media-controller topology builder. Drivers describe their entire media graph, entities (video devices, subdevs, or base entities), their pads, and the links between them, in a static descriptor table. The builder validates the table, allocates and registers all entities, and creates all MC pad links. It is kept generic but currently only used by OPE. - params.c/.h: V4L2 ISP parameter buffer validation and dispatch. It wraps the extensible V4L2 ISP parameters buffer format, validating the buffer size and each per-block header before forwarding every block to its driver-supplied handler. A userspace libcamera support can be found at: https://github.com/jwrdegoede/libcamera/commits/camss_pipeline_v2.1/ A test tool, camss-isp-m2m, can be found at: https://github.com/loicpoulain/camss-isp-m2m-test Assisted-by: LLM Co-developed-by: Hans de Goede Signed-off-by: Hans de Goede Link: https://github.com/jwrdegoede/libcamera/commits/camss_pipeline_v2.1/ Link: https://github.com/loicpoulain/camss-isp-m2m-test Signed-off-by: Loic Poulain --- MAINTAINERS | 1 + drivers/media/platform/qcom/camss/Kconfig | 2 + drivers/media/platform/qcom/camss/Makefile | 2 + drivers/media/platform/qcom/camss/ope/Kconfig | 17 + drivers/media/platform/qcom/camss/ope/Makefile | 9 + drivers/media/platform/qcom/camss/ope/core.c | 3843 ++++++++++++++++++= ++++ drivers/media/platform/qcom/camss/ope/params.c | 78 + drivers/media/platform/qcom/camss/ope/params.h | 95 + drivers/media/platform/qcom/camss/ope/pipeline.c | 405 +++ drivers/media/platform/qcom/camss/ope/pipeline.h | 239 ++ 10 files changed, 4691 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b5593f814b60fcbcd88f4b4aad25880d19825dc0..a165b356e81d5cb362831245c18= 382452bac12ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22365,6 +22365,7 @@ F: Documentation/admin-guide/media/qcom_camss.rst F: Documentation/devicetree/bindings/media/qcom,*camss* F: Documentation/userspace-api/media/v4l/metafmt-qcom-isp.rst F: drivers/media/platform/qcom/camss/ +F: include/uapi/linux/qcom-camss-config.h =20 QUALCOMM CLOCK DRIVERS M: Bjorn Andersson diff --git a/drivers/media/platform/qcom/camss/Kconfig b/drivers/media/plat= form/qcom/camss/Kconfig index 4eda48cb1adf049a7fb6cb59b9da3c0870fe57f4..414dfd3d0ecea0d0c575f5a2aba= 31846d10deb11 100644 --- a/drivers/media/platform/qcom/camss/Kconfig +++ b/drivers/media/platform/qcom/camss/Kconfig @@ -7,3 +7,5 @@ config VIDEO_QCOM_CAMSS select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_SG select V4L2_FWNODE + +source "drivers/media/platform/qcom/camss/ope/Kconfig" diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/pla= tform/qcom/camss/Makefile index 27898b3cc7d3c8f275567f81f0952e2a0e18f189..b79c40626c401767fe31b3a2fc6= 8c1db38a5a11d 100644 --- a/drivers/media/platform/qcom/camss/Makefile +++ b/drivers/media/platform/qcom/camss/Makefile @@ -31,3 +31,5 @@ qcom-camss-objs +=3D \ camss-video.o =20 obj-$(CONFIG_VIDEO_QCOM_CAMSS) +=3D qcom-camss.o + +obj-$(CONFIG_VIDEO_QCOM_CAMSS_OPE) +=3D ope/ diff --git a/drivers/media/platform/qcom/camss/ope/Kconfig b/drivers/media/= platform/qcom/camss/ope/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..d9f96430f145aa9a90c1744a93b= 80ef9d706e0e2 --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/Kconfig @@ -0,0 +1,17 @@ +config VIDEO_QCOM_CAMSS_OPE + tristate "Qualcomm Offline Processing Engine (OPE) driver" + depends on V4L_PLATFORM_DRIVERS + depends on MEDIA_CONTROLLER + depends on VIDEO_DEV + depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST + select V4L2_ISP + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + help + Enable support for the Qualcomm Offline Processing Engine (OPE). + OPE is a memory-to-memory ISP block that converts raw Bayer frames + to YUV, performing white balance, demosaic, chroma enhancement and + downscaling. Found on QCM2290 and related SoCs. + + To compile this driver as a module, choose M here: the module + will be called qcom-camss-ope. diff --git a/drivers/media/platform/qcom/camss/ope/Makefile b/drivers/media= /platform/qcom/camss/ope/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..02599a7b46e17640cbdda8600c9= 5bb268ef8ab31 --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Makefile for Qualcomm CAMSS Offline Processing Engine (OPE) driver + +qcom-camss-ope-objs :=3D \ + core.o \ + pipeline.o \ + params.o + +obj-$(CONFIG_VIDEO_QCOM_CAMSS_OPE) +=3D qcom-camss-ope.o diff --git a/drivers/media/platform/qcom/camss/ope/core.c b/drivers/media/p= latform/qcom/camss/ope/core.c new file mode 100644 index 0000000000000000000000000000000000000000..122e6c8deb022080b0e304a2b0b= 3ddce78da062f --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/core.c @@ -0,0 +1,3843 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ope/core.c + * + * Qualcomm MSM Camera Subsystem - Offline Processing Engine + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +/* + * This driver provides driver implementation for the Qualcomm Offline + * Processing Engine (OPE). OPE is a memory-to-memory hardware block + * designed for image processing on a source frame. Typically, the input + * frame originates from the SoC CSI capture path, though not limited to. + * + * The hardware architecture consists of Fetch Engines and Write Engines, + * connected through intermediate pipeline modules: + * [FETCH ENGINES] =3D> [Pipeline Modules] =3D> [WRITE ENGINES] + * + * Current Configuration: + * Fetch Engine: One fetch engine is used for Bayer frame input. + * Write Engines: Two display write engines for Y and UV planes output. + * + * Only a subset of the pipeline modules are enabled: + * WB: White balance for channel gain configuration + * DEMO: Demosaic for Bayer to RGB conversion + * CC: Color Correct, coefficient based RGB correction + * GLUT: Gamma LUT, redistributes brightness levels + * CHROMA_ENHAN: for RGB to YUV conversion + * DOWNSCALE*: Downscaling for UV (YUV444 -> YUV422/YUV420) and YUV plan= es + * + * Default configuration values are based on public standards such as BT.6= 01. + * + * Processing Model: + * OPE processes frames in stripes of up to 336 pixels. Therefore, frames = must + * be split into stripes for processing. Each stripe is configured after t= he + * previous one has been acquired (double buffered registers). To minimize + * inter-stripe latency, the stripe configurations are generated ahead of = time. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pipeline.h" + +#include +#include + +#include + +#include "params.h" + +#define OPE_NAME "qcom-camss-ope" + +/* Format descriptor */ +struct ope_fmt { + u32 fourcc; + unsigned int depth; + unsigned int align; + unsigned int num_planes; + u32 mbus_code; + unsigned int c_hsub; + unsigned int c_vsub; +}; + +/* Per-queue format state */ +struct ope_fmt_state { + const struct ope_fmt *fmt; + unsigned int width; + unsigned int height; + struct v4l2_rect crop; + unsigned int bytesperline; + unsigned int sizeimage; + enum v4l2_colorspace colorspace; + enum v4l2_xfer_func xfer_func; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + unsigned int sequence; + struct v4l2_fract timeperframe; +}; + +/* -------- Register layout -------- */ + +#define OPE_TOP_HW_VERSION 0x000 +#define OPE_TOP_HW_VERSION_STEP GENMASK(15, 0) +#define OPE_TOP_HW_VERSION_REV GENMASK(27, 16) +#define OPE_TOP_HW_VERSION_GEN GENMASK(31, 28) +#define OPE_TOP_RESET_CMD 0x004 +#define OPE_TOP_RESET_CMD_HW BIT(0) +#define OPE_TOP_RESET_CMD_SW BIT(1) +#define OPE_TOP_IRQ_STATUS 0x014 +#define OPE_TOP_IRQ_MASK 0x018 +#define OPE_TOP_IRQ_STATUS_RST_DONE BIT(0) +#define OPE_TOP_IRQ_STATUS_WE BIT(1) +#define OPE_TOP_IRQ_STATUS_FE BIT(2) +#define OPE_TOP_IRQ_STATUS_VIOL BIT(3) +#define OPE_TOP_IRQ_STATUS_IDLE BIT(4) +#define OPE_TOP_IRQ_CLEAR 0x01c +#define OPE_TOP_IRQ_CMD 0x024 +#define OPE_TOP_IRQ_CMD_CLEAR BIT(0) +#define OPE_TOP_VIOLATION_STATUS 0x028 + +/* Fetch engine */ +#define OPE_BUS_RD_INPUT_IF_IRQ_MASK 0x00c +#define OPE_BUS_RD_INPUT_IF_IRQ_CLEAR 0x010 +#define OPE_BUS_RD_INPUT_IF_IRQ_CMD 0x014 +#define OPE_BUS_RD_INPUT_IF_IRQ_CMD_CLEAR BIT(0) +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS 0x018 +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS_RST_DONE BIT(0) +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS_RUP_DONE BIT(1) +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS_BUF_DONE GENMASK(3, 2) +#define OPE_BUS_RD_INPUT_IF_IRQ_STATUS_CCIF_VIOL GENMASK(17, 16) +#define OPE_BUS_RD_INPUT_IF_CMD 0x01c +#define OPE_BUS_RD_INPUT_IF_CMD_GO_CMD BIT(0) +#define OPE_BUS_RD_CLIENT_0_CORE_CFG 0x050 +#define OPE_BUS_RD_CLIENT_0_CORE_CFG_EN BIT(0) +#define OPE_BUS_RD_CLIENT_0_CCIF_META_DATA 0x054 +#define OPE_BUS_RD_CLIENT_0_CCIF_MD_PIX_PATTERN GENMASK(7, 2) +#define OPE_BUS_RD_CLIENT_0_ADDR_IMAGE 0x058 +#define OPE_BUS_RD_CLIENT_0_RD_BUFFER_SIZE 0x05c +#define OPE_BUS_RD_CLIENT_0_RD_STRIDE 0x060 +#define OPE_BUS_RD_CLIENT_0_UNPACK_CFG_0 0x064 + +/* Write engines */ +#define OPE_BUS_WR_INPUT_IF_IRQ_MASK_0 0x018 +#define OPE_BUS_WR_INPUT_IF_IRQ_MASK_1 0x01c +#define OPE_BUS_WR_INPUT_IF_IRQ_CLEAR_0 0x020 +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0 0x028 +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_RUP_DONE BIT(0) +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_BUF_DONE BIT(8) +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_CONS_VIOL BIT(28) +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_VIOL BIT(30) +#define OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_IMG_SZ_VIOL BIT(31) +#define OPE_BUS_WR_INPUT_IF_IRQ_CMD 0x030 +#define OPE_BUS_WR_INPUT_IF_IRQ_CMD_CLEAR BIT(0) +#define OPE_BUS_WR_VIOLATION_STATUS 0x064 +#define OPE_BUS_WR_IMAGE_SIZE_VIOLATION_STATUS 0x070 +#define OPE_BUS_WR_CLIENT_CFG(c) (0x200 + (c) * 0x100) +#define OPE_BUS_WR_CLIENT_CFG_EN BIT(0) +#define OPE_BUS_WR_CLIENT_CFG_AUTORECOVER BIT(4) +#define OPE_BUS_WR_CLIENT_ADDR_IMAGE(c) (0x204 + (c) * 0x100) +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_0(c) (0x20c + (c) * 0x100) +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_1(c) (0x210 + (c) * 0x100) +#define OPE_BUS_WR_CLIENT_IMAGE_CFG_2(c) (0x214 + (c) * 0x100) +#define OPE_BUS_WR_CLIENT_PACKER_CFG(c) (0x218 + (c) * 0x100) + +/* Pipeline modules */ + +#define OPE_PP_HW_VERSION(base) ((base) + 0x00) +#define OPE_PP_HW_STATUS(base) ((base) + 0x04) +#define OPE_HW_VERSION_GEN(v) ((u32)FIELD_GET(OPE_TOP_HW_VERSION_GEN, (v))) +#define OPE_HW_VERSION_REV(v) ((u32)FIELD_GET(OPE_TOP_HW_VERSION_REV, (v))) +#define OPE_HW_VERSION_STEP(v) ((u32)FIELD_GET(OPE_TOP_HW_VERSION_STEP, (v= ))) + +#define OPE_PP_WB_GAIN_BASE 0x200 +#define OPE_PP_WB_GAIN_MODULE_CFG (OPE_PP_WB_GAIN_BASE + 0x60) +#define OPE_PP_WB_GAIN_MODULE_CFG_EN BIT(0) +#define OPE_PP_WB_GAIN_WB_CFG(ch) (OPE_PP_WB_GAIN_BASE + 0x68 + 4 * (ch)) +#define OPE_PP_WB_GAIN_WB_CFG_GAIN GENMASK(14, 0) +#define OPE_PP_WB_GAIN_WB_SUB_CFG(ch) (OPE_PP_WB_GAIN_BASE + 0x74 + 4 * = (ch)) +#define OPE_PP_WB_GAIN_WB_SUB_CFG_VAL GENMASK(31, 20) +#define OPE_PP_WB_GAIN_WB_ADD_CFG(ch) (OPE_PP_WB_GAIN_BASE + 0x80 + 4 * = (ch)) +#define OPE_PP_WB_GAIN_WB_ADD_CFG_VAL GENMASK(31, 20) + +#define OPE_PP_CC_BASE 0xa00 +#define OPE_PP_CC_MODULE_CFG (OPE_PP_CC_BASE + 0x60) +#define OPE_PP_CC_MODULE_CFG_EN BIT(0) +#define OPE_PP_CC_COEFF_A_CFG_0 (OPE_PP_CC_BASE + 0x68) +#define OPE_PP_CC_COEFF_A_CFG_0_A0 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_A_CFG_0_A1 GENMASK(27, 16) +#define OPE_PP_CC_COEFF_A_CFG_1 (OPE_PP_CC_BASE + 0x6c) +#define OPE_PP_CC_COEFF_A_CFG_1_A2 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_B_CFG_0 (OPE_PP_CC_BASE + 0x70) +#define OPE_PP_CC_COEFF_B_CFG_0_B0 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_B_CFG_0_B1 GENMASK(27, 16) +#define OPE_PP_CC_COEFF_B_CFG_1 (OPE_PP_CC_BASE + 0x74) +#define OPE_PP_CC_COEFF_B_CFG_1_B2 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_C_CFG_0 (OPE_PP_CC_BASE + 0x78) +#define OPE_PP_CC_COEFF_C_CFG_0_C0 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_C_CFG_0_C1 GENMASK(27, 16) +#define OPE_PP_CC_COEFF_C_CFG_1 (OPE_PP_CC_BASE + 0x7c) +#define OPE_PP_CC_COEFF_C_CFG_1_C2 GENMASK(11, 0) +#define OPE_PP_CC_COEFF_K_CFG_0 (OPE_PP_CC_BASE + 0x80) +#define OPE_PP_CC_COEFF_K_CFG_0_K0 GENMASK(31, 21) +#define OPE_PP_CC_COEFF_K_CFG_1 (OPE_PP_CC_BASE + 0x84) +#define OPE_PP_CC_COEFF_K_CFG_1_K1 GENMASK(31, 21) +#define OPE_PP_CC_COEFF_K_CFG_2 (OPE_PP_CC_BASE + 0x88) +#define OPE_PP_CC_COEFF_K_CFG_2_K2 GENMASK(31, 21) +#define OPE_PP_CC_COEFF_M_CFG (OPE_PP_CC_BASE + 0x8c) +#define OPE_PP_CC_COEFF_M_CFG_M GENMASK(1, 0) + +#define OPE_PP_GLUT_BASE 0x1000 +#define OPE_PP_GLUT_DMI_CFG (OPE_PP_GLUT_BASE + 0x08) +#define OPE_PP_GLUT_DMI_CFG_AUTO_LOAD_EN BIT(20) +#define OPE_PP_GLUT_DMI_CFG_ADDR GENMASK(7, 0) +#define OPE_PP_GLUT_DMI_LUT_CFG (OPE_PP_GLUT_BASE + 0x0c) +#define OPE_PP_GLUT_DMI_LUT_CFG_SEL GENMASK(1, 0) +#define OPE_PP_GLUT_DMI_DATA (OPE_PP_GLUT_BASE + 0x10) +#define OPE_PP_GLUT_DMI_LUT_BANK_CFG (OPE_PP_GLUT_BASE + 0x58) +#define OPE_PP_GLUT_DMI_LUT_BANK_CFG_SEL BIT(0) +#define OPE_PP_GLUT_MODULE_LUT_BANK_CFG (OPE_PP_GLUT_BASE + 0x5c) +#define OPE_PP_GLUT_MODULE_LUT_BANK_CFG_SEL BIT(0) +#define OPE_PP_GLUT_MODULE_CFG (OPE_PP_GLUT_BASE + 0x60) +#define OPE_PP_GLUT_MODULE_CFG_EN BIT(0) + +#define OPE_PP_DEMO_BASE 0x800 +#define OPE_PP_DEMO_MODULE_CFG (OPE_PP_DEMO_BASE + 0x60) +#define OPE_PP_DEMO_MODULE_CFG_EN BIT(0) +#define OPE_PP_DEMO_MODULE_CFG_DYN_G_CLAMP_EN BIT(14) +#define OPE_PP_DEMO_MODULE_CFG_DYN_RB_CLAMP_EN BIT(15) +#define OPE_PP_DEMO_INTERP_COEFF_CFG (OPE_PP_DEMO_BASE + 0x68) +#define OPE_PP_DEMO_INTERP_COEFF_CFG_LAMBDA_G GENMASK(7, 0) +#define OPE_PP_DEMO_INTERP_COEFF_CFG_LAMBDA_RB GENMASK(23, 16) +#define OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_0 (OPE_PP_DEMO_BASE + 0x6c) +#define OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_0_AK GENMASK(31, 20) +#define OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_1 (OPE_PP_DEMO_BASE + 0x70) +#define OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_1_WK GENMASK(9, 0) + +#define OPE_PP_DOWNSCALE_MN_DS_C_PRE_BASE 0x1c00 +#define OPE_PP_DOWNSCALE_MN_DS_Y_DISP_BASE 0x3000 +#define OPE_PP_DOWNSCALE_MN_DS_C_DISP_BASE 0x3200 +#define OPE_PP_CROP_RND_CLAMP_Y_DISP_BASE 0x3400 +#define OPE_PP_CROP_RND_CLAMP_C_DISP_BASE 0x3600 +#define OPE_PP_CROP_RND_CLAMP_HW_STATUS(base) OPE_PP_HW_STATUS(base) +#define OPE_PP_CROP_RND_CLAMP_HEIGHT_VIOL BIT(2) +#define OPE_PP_CROP_RND_CLAMP_WIDTH_VIOL BIT(1) +#define OPE_PP_CROP_RND_CLAMP_MODULE_CFG(base) ((base) + 0x60) +#define OPE_PP_CROP_RND_CLAMP_EN BIT(0) +#define OPE_PP_CROP_RND_CLAMP_CROP_EN BIT(9) +#define OPE_PP_CROP_RND_CLAMP_CROP_LINE_CFG(base) ((base) + 0x68) +#define OPE_PP_CROP_RND_CLAMP_CROP_PIXEL_CFG(base) ((base) + 0x6c) +#define OPE_PP_CROP_RND_CLAMP_CROP_FIRST GENMASK(29, 16) +#define OPE_PP_CROP_RND_CLAMP_CROP_LAST GENMASK(13, 0) +#define OPE_PP_DOWNSCALE_MN_CFG(ds) ((ds) + 0x60) +#define OPE_PP_DOWNSCALE_MN_CFG_EN BIT(0) +#define OPE_PP_DOWNSCALE_MN_DS_CFG(ds) ((ds) + 0x64) +#define OPE_PP_DOWNSCALE_MN_DS_CFG_H_SCALE_EN BIT(9) +#define OPE_PP_DOWNSCALE_MN_DS_CFG_V_SCALE_EN BIT(10) +#define OPE_PP_DOWNSCALE_MN_DS_IMAGE_SIZE_CFG(ds) ((ds) + 0x68) +#define OPE_PP_DOWNSCALE_MN_DS_MN_H_CFG(ds) ((ds) + 0x6c) +#define OPE_PP_DOWNSCALE_MN_DS_MN_H_PHASE_CFG(ds) ((ds) + 0x70) +#define OPE_PP_DOWNSCALE_MN_DS_MN_V_CFG(ds) ((ds) + 0x74) +#define OPE_PP_DOWNSCALE_MN_DS_MN_V_PHASE_CFG(ds) ((ds) + 0x78) + +#define OPE_PP_CHROMA_ENHAN_BASE 0x1200 +#define OPE_PP_CHROMA_ENHAN_MODULE_CFG (OPE_PP_CHROMA_ENHAN_BASE + 0x60) +#define OPE_PP_CHROMA_ENHAN_MODULE_CFG_EN BIT(0) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_0 (OPE_PP_CHROMA_ENHAN_BASE + 0x68) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_0_V0 GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_0_V1 GENMASK(27, 16) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_1 (OPE_PP_CHROMA_ENHAN_BASE + 0x6c) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_1_K GENMASK(31, 23) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_2 (OPE_PP_CHROMA_ENHAN_BASE + 0x70) +#define OPE_PP_CHROMA_ENHAN_LUMA_CFG_2_V2 GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_A_CFG (OPE_PP_CHROMA_ENHAN_BASE + 0x7= 4) +#define OPE_PP_CHROMA_ENHAN_COEFF_A_CFG_AP GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_A_CFG_AM GENMASK(27, 16) +#define OPE_PP_CHROMA_ENHAN_COEFF_B_CFG (OPE_PP_CHROMA_ENHAN_BASE + 0x7= 8) +#define OPE_PP_CHROMA_ENHAN_COEFF_B_CFG_BP GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_B_CFG_BM GENMASK(27, 16) +#define OPE_PP_CHROMA_ENHAN_COEFF_C_CFG (OPE_PP_CHROMA_ENHAN_BASE + 0x7= C) +#define OPE_PP_CHROMA_ENHAN_COEFF_C_CFG_CP GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_C_CFG_CM GENMASK(27, 16) +#define OPE_PP_CHROMA_ENHAN_COEFF_D_CFG (OPE_PP_CHROMA_ENHAN_BASE + 0x8= 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_D_CFG_DP GENMASK(11, 0) +#define OPE_PP_CHROMA_ENHAN_COEFF_D_CFG_DM GENMASK(27, 16) +#define OPE_PP_CHROMA_ENHAN_CHROMA_CFG_0 (OPE_PP_CHROMA_ENHAN_BASE + 0x8= 4) +#define OPE_PP_CHROMA_ENHAN_CHROMA_CFG_0_KCB GENMASK(31, 21) +#define OPE_PP_CHROMA_ENHAN_CHROMA_CFG_1 (OPE_PP_CHROMA_ENHAN_BASE + 0x8= 8) +#define OPE_PP_CHROMA_ENHAN_CHROMA_CFG_1_KCR GENMASK(31, 21) + +/* -------- OPE-specific constants -------- */ + +#define OPE_STRIPE_MAX_W 336 +#define OPE_STRIPE_MAX_H 8192 +#define OPE_STRIPE_MIN_W 16 +#define OPE_STRIPE_MIN_H OPE_STRIPE_MIN_W +#define OPE_MAX_STRIPE 16 +#define OPE_ALIGN_H 1 +#define OPE_ALIGN_W 1 +#define OPE_MIN_W 24 +#define OPE_MIN_H 16 +#define OPE_MAX_W (OPE_STRIPE_MAX_W * OPE_MAX_STRIPE) +#define OPE_MAX_H OPE_STRIPE_MAX_H +#define OPE_MAX_STRIDE 0xffff +#define OPE_RESET_TIMEOUT_MS 100 +#define OPE_RESET_POLL_US 50 +#define DEFAULT_FRAMERATE 60 +#define OPE_MAX_FRAMERATE 1000 + +/* + * AXI clock is shared across CAMSS blocks and not dynamically scaled, + * just request the highest supported rate. + */ +#define OPE_AXI_CLK_RATE (300 * HZ_PER_MHZ) + +/* Downscaler fixed-point helpers */ +#define Q21(v) (((uint64_t)(v)) << 21) +#define DS_Q21(n, d) ((uint32_t)(((uint64_t)(n) << 21) / (d))) +#define DS_RESOLUTION(in, out) \ + (((out) * 128 <=3D (in)) ? 0x0 : \ + ((out) * 16 <=3D (in)) ? 0x1 : \ + ((out) * 8 <=3D (in)) ? 0x2 : 0x3) +#define DS_OUTPUT_PIX(in, phase_init, phase_step) \ + ((Q21(in) - (phase_init)) / (phase_step)) +#define OPE_WB(n, d) (((n) << 10) / (d)) + +enum ope_downscaler { + OPE_DS_C_PRE, + OPE_DS_C_DISP, + OPE_DS_Y_DISP, + OPE_DS_MAX, +}; + +enum ope_glut_sel { + OPE_GLUT_SEL_NONE, + OPE_GLUT_SEL_G, + OPE_GLUT_SEL_B, + OPE_GLUT_SEL_R, +}; + +static const u32 ope_ds_base[OPE_DS_MAX] =3D { + OPE_PP_DOWNSCALE_MN_DS_C_PRE_BASE, + OPE_PP_DOWNSCALE_MN_DS_C_DISP_BASE, + OPE_PP_DOWNSCALE_MN_DS_Y_DISP_BASE, +}; + +enum ope_wr_client { + OPE_WR_CLIENT_VID_Y, + OPE_WR_CLIENT_VID_C, + OPE_WR_CLIENT_DISP_Y, + OPE_WR_CLIENT_DISP_C, + OPE_WR_CLIENT_MAX, +}; + +enum ope_pixel_pattern { + OPE_PIXEL_PATTERN_RGRGRG, + OPE_PIXEL_PATTERN_GRGRGR, + OPE_PIXEL_PATTERN_BGBGBG, + OPE_PIXEL_PATTERN_GBGBGB, + OPE_PIXEL_PATTERN_YCBYCR, + OPE_PIXEL_PATTERN_YCRYCB, + OPE_PIXEL_PATTERN_CBYCRY, + OPE_PIXEL_PATTERN_CRYCBY, +}; + +enum ope_stripe_location { + OPE_STRIPE_LOCATION_FULL, + OPE_STRIPE_LOCATION_LEFT, + OPE_STRIPE_LOCATION_RIGHT, + OPE_STRIPE_LOCATION_MIDDLE, +}; + +enum ope_unpacker_format { + OPE_UNPACKER_FMT_PLAIN_8 =3D 1, + OPE_UNPACKER_FMT_PLAIN_16_10BPP =3D 2, + OPE_UNPACKER_FMT_MIPI_10 =3D 13, +}; + +enum ope_packer_format { + OPE_PACKER_FMT_PLAIN_8 =3D 1, + OPE_PACKER_FMT_PLAIN_8_ODD_EVEN =3D 2, + OPE_PACKER_FMT_MIPI_10 =3D 12, +}; + +struct ope_hw_fmt { + u32 fourcc; + enum ope_pixel_pattern pattern; + enum ope_unpacker_format unpacker; + enum ope_packer_format packer; +}; + +static const struct ope_hw_fmt ope_hw_fmts[] =3D { + { V4L2_PIX_FMT_SBGGR10P, OPE_PIXEL_PATTERN_BGBGBG, + OPE_UNPACKER_FMT_MIPI_10, OPE_PACKER_FMT_MIPI_10 }, + { V4L2_PIX_FMT_SGBRG10P, OPE_PIXEL_PATTERN_GBGBGB, + OPE_UNPACKER_FMT_MIPI_10, OPE_PACKER_FMT_MIPI_10 }, + { V4L2_PIX_FMT_SGRBG10P, OPE_PIXEL_PATTERN_GRGRGR, + OPE_UNPACKER_FMT_MIPI_10, OPE_PACKER_FMT_MIPI_10 }, + { V4L2_PIX_FMT_SRGGB10P, OPE_PIXEL_PATTERN_RGRGRG, + OPE_UNPACKER_FMT_MIPI_10, OPE_PACKER_FMT_MIPI_10 }, + { V4L2_PIX_FMT_SRGGB8, OPE_PIXEL_PATTERN_RGRGRG, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_SBGGR8, OPE_PIXEL_PATTERN_BGBGBG, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_SGBRG8, OPE_PIXEL_PATTERN_GBGBGB, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_SGRBG8, OPE_PIXEL_PATTERN_GRGRGR, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_NV24, OPE_PIXEL_PATTERN_YCBYCR, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_NV42, OPE_PIXEL_PATTERN_YCRYCB, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8_ODD_EVEN }, + { V4L2_PIX_FMT_NV16, OPE_PIXEL_PATTERN_CBYCRY, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_NV61, OPE_PIXEL_PATTERN_CBYCRY, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8_ODD_EVEN }, + { V4L2_PIX_FMT_NV12, OPE_PIXEL_PATTERN_CBYCRY, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, + { V4L2_PIX_FMT_NV21, OPE_PIXEL_PATTERN_CBYCRY, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8_ODD_EVEN }, + { V4L2_PIX_FMT_GREY, OPE_PIXEL_PATTERN_RGRGRG, + OPE_UNPACKER_FMT_PLAIN_8, OPE_PACKER_FMT_PLAIN_8 }, +}; + +static const struct ope_hw_fmt *ope_find_hw_fmt(u32 fourcc) +{ + for (unsigned int i =3D 0; i < ARRAY_SIZE(ope_hw_fmts); i++) + if (ope_hw_fmts[i].fourcc =3D=3D fourcc) + return &ope_hw_fmts[i]; + + return NULL; +} + +static const struct ope_fmt ope_input_fmts[] =3D { + { V4L2_PIX_FMT_SBGGR10P, 10, 2, 1, MEDIA_BUS_FMT_SBGGR10_1X10 }, + { V4L2_PIX_FMT_SGBRG10P, 10, 2, 1, MEDIA_BUS_FMT_SGBRG10_1X10 }, + { V4L2_PIX_FMT_SGRBG10P, 10, 2, 1, MEDIA_BUS_FMT_SGRBG10_1X10 }, + { V4L2_PIX_FMT_SRGGB10P, 10, 2, 1, MEDIA_BUS_FMT_SRGGB10_1X10 }, + { V4L2_PIX_FMT_SRGGB8, 8, 0, 1, MEDIA_BUS_FMT_SRGGB8_1X8 }, + { V4L2_PIX_FMT_SBGGR8, 8, 0, 1, MEDIA_BUS_FMT_SBGGR8_1X8 }, + { V4L2_PIX_FMT_SGBRG8, 8, 0, 1, MEDIA_BUS_FMT_SGBRG8_1X8 }, + { V4L2_PIX_FMT_SGRBG8, 8, 0, 1, MEDIA_BUS_FMT_SGRBG8_1X8 }, +}; + +static const struct ope_fmt ope_output_fmts[] =3D { + { V4L2_PIX_FMT_NV24, 24, 0, 1, MEDIA_BUS_FMT_YUV8_1X24, 1, 1 }, + { V4L2_PIX_FMT_NV42, 24, 0, 1, MEDIA_BUS_FMT_YUV8_1X24, 1, 1 }, + { V4L2_PIX_FMT_NV16, 16, 1, 1, MEDIA_BUS_FMT_YUYV8_2X8, 2, 1 }, + { V4L2_PIX_FMT_NV61, 16, 1, 1, MEDIA_BUS_FMT_YUYV8_2X8, 2, 1 }, + { V4L2_PIX_FMT_NV12, 12, 1, 1, MEDIA_BUS_FMT_YUYV8_1_5X8, 2, 2 }, + { V4L2_PIX_FMT_NV21, 12, 1, 1, MEDIA_BUS_FMT_YUYV8_1_5X8, 2, 2 }, + { V4L2_PIX_FMT_GREY, 8, 0, 1, MEDIA_BUS_FMT_Y8_1X8, 1, 1 }, +}; + +struct ope_dsc_config { + u32 input_width; + u32 input_height; + u32 output_width; + u32 output_height; + u32 phase_step_h; + u32 phase_step_v; + u32 crop_last_pixel; + u32 crop_last_line; +}; + +struct ope_stripe { + struct { + dma_addr_t addr; + u32 width; + u32 height; + u32 stride; + enum ope_stripe_location location; + enum ope_pixel_pattern pattern; + enum ope_unpacker_format format; + } src; + struct { + dma_addr_t addr; + u32 width; + u32 height; + u32 stride; + u32 x_init; + enum ope_packer_format format; + bool enabled; + } dst[OPE_WR_CLIENT_MAX]; + struct ope_dsc_config dsc[OPE_DS_MAX]; +}; + +/* OPE tuning parameter state */ + +/* Demosaic (CLC_DEMO) coefficients, internal only, not user-configurable.= */ +#define CAMSS_PARAMS_INTERNAL (-1) + +struct ope_params_demo { + struct v4l2_isp_params_block_header header; + u8 lambda_rb; + u8 lambda_g; + u16 a_k; + u16 w_k; + u16 _pad; +}; + +/* OPE tuning parameter state */ +struct ope_config { + struct camss_params_wb_gain wb_gain; + struct camss_params_chroma_enhan chroma_enhan; + struct camss_params_color_correct color_correct; + struct camss_params_gamma gamma; + struct ope_params_demo demo; +}; + +enum ope_entity { + OPE_ENTITY_FRAME_IN, + OPE_ENTITY_PARAMS, + OPE_ENTITY_PROC, + OPE_ENTITY_DISP, + OPE_ENTITY_DISP_OUT, + OPE_ENTITY_COUNT +}; + +enum ope_queue_idx { + OPE_QUEUE_FRAME_IN, + OPE_QUEUE_DISP_OUT, + OPE_QUEUE_PARAMS, + OPE_QUEUE_COUNT +}; + +struct camss_isp_buf { + struct vb2_v4l2_buffer vb; /* must be first */ + struct list_head list; +}; + +struct ope_queue { + struct vb2_queue vq; + struct list_head rdy_queue; + spinlock_t rdy_spinlock; +}; + +enum ope_proc_pad { + OPE_PROC_PAD_SINK_IN, + OPE_PROC_PAD_SINK_PAR, + OPE_PROC_PAD_SOURCE, + OPE_PROC_PADS_NUM, +}; + +enum ope_disp_pad { + OPE_DISP_PAD_SINK, + OPE_DISP_PAD_SOURCE, + OPE_DISP_PADS_NUM, +}; + +/* per-context state */ +struct ope_ctx { + bool queued; + struct ope_dev *ope; + struct mutex vbq_lock; + struct ope_queue queues[OPE_QUEUE_COUNT]; + + unsigned int framerate; + struct ope_fmt_state fmt_in; + struct ope_fmt_state fmt_out; + + struct list_head list; + bool started; + + struct ope_config config; + u8 current_stripe; + struct ope_stripe stripe[OPE_MAX_STRIPE]; + + struct v4l2_isp_params_buffer *params_buf; +}; + +/* Per OPE device state */ +struct ope_dev { + struct device *dev; + struct v4l2_device v4l2_dev; + struct media_device mdev; + struct camss_isp_pipeline *pipeline; + struct mutex mutex; + struct work_struct run_work; + + /* Scheduler state, all owned by sched_lock */ + spinlock_t sched_lock; + struct ope_ctx *curr_ctx; + struct ope_ctx *hw_ctx; + bool hw_running; + + int irq; + u32 hw_version; + + struct icc_path *icc_data; + struct icc_path *icc_config; + + void __iomem *base; + void __iomem *base_rd; + void __iomem *base_wr; + void __iomem *base_pp; + + struct completion reset_complete; + + struct list_head ctx_list; + spinlock_t ctx_lock; + + struct ope_ctx *shared_ctx; + unsigned int open_count; + + /* Gamma LUTs handling */ + struct { + struct ope_ctx *owner; + bool valid; + } glut_bank[2]; + u8 glut_cur_bank; + u8 glut_mru_bank; +}; + +/* -------- Register accessors -------- */ + +static inline u32 ope_read(struct ope_dev *ope, u32 reg) +{ + return readl(ope->base + reg); +} + +static inline void ope_write(struct ope_dev *ope, u32 reg, u32 val) +{ + writel(val, ope->base + reg); +} + +static inline void ope_write_wr(struct ope_dev *ope, u32 reg, u32 val) +{ + writel_relaxed(val, ope->base_wr + reg); +} + +static inline u32 ope_read_wr(struct ope_dev *ope, u32 reg) +{ + return readl_relaxed(ope->base_wr + reg); +} + +static inline void ope_write_rd(struct ope_dev *ope, u32 reg, u32 val) +{ + writel_relaxed(val, ope->base_rd + reg); +} + +static inline void ope_write_pp(struct ope_dev *ope, u32 reg, u32 val) +{ + writel_relaxed(val, ope->base_pp + reg); +} + +static inline u32 ope_read_pp(struct ope_dev *ope, u32 reg) +{ + return readl_relaxed(ope->base_pp + reg); +} + +static inline void ope_start(struct ope_dev *ope) +{ + wmb(); /* ensure all register writes are visible before GO_CMD */ + ope_write_rd(ope, OPE_BUS_RD_INPUT_IF_CMD, OPE_BUS_RD_INPUT_IF_CMD_GO_CMD= ); +} + +static inline bool ope_hw_available(struct ope_dev *ope) +{ + /* v4l2_device_unregister() clear the dev pointer */ + return !!ope->v4l2_dev.dev; +} + +/* -------- Stripe helpers -------- */ + +static inline enum ope_stripe_location ope_stripe_location(unsigned int id= x, unsigned int count) +{ + if (count =3D=3D 1) + return OPE_STRIPE_LOCATION_FULL; + if (idx =3D=3D 0) + return OPE_STRIPE_LOCATION_LEFT; + if (idx =3D=3D count - 1) + return OPE_STRIPE_LOCATION_RIGHT; + + return OPE_STRIPE_LOCATION_MIDDLE; +} + +static inline bool ope_stripe_is_last(const struct ope_stripe *s) +{ + return s && (s->src.location =3D=3D OPE_STRIPE_LOCATION_RIGHT || + s->src.location =3D=3D OPE_STRIPE_LOCATION_FULL); +} + +static inline struct ope_stripe *ope_current_stripe(struct ope_ctx *ctx) +{ + if (ctx->current_stripe >=3D OPE_MAX_STRIPE) + return NULL; + + return &ctx->stripe[ctx->current_stripe]; +} + +static inline unsigned int ope_stripe_index(struct ope_ctx *ctx, const str= uct ope_stripe *stripe) +{ + return stripe - &ctx->stripe[0]; +} + +static inline struct ope_stripe *ope_prev_stripe(struct ope_ctx *ctx, stru= ct ope_stripe *stripe) +{ + unsigned int idx =3D ope_stripe_index(ctx, stripe); + + return idx ? &ctx->stripe[idx - 1] : NULL; +} + +static unsigned int ope_split_stripes(unsigned int src_width, unsigned int= align, + unsigned int *widths, u32 *height) +{ + unsigned int nstripes, i; + u32 w; + + if (src_width > OPE_MAX_W) + return 0; + + nstripes =3D DIV_ROUND_UP(src_width, OPE_STRIPE_MAX_W); + w =3D ALIGN(DIV_ROUND_UP(src_width, nstripes), max(2u, 1u << align)); + + v4l_bound_align_image(&w, OPE_STRIPE_MIN_W, OPE_STRIPE_MAX_W, align, + height, OPE_STRIPE_MIN_H, OPE_STRIPE_MAX_H, + OPE_ALIGN_H, 0); + + for (i =3D 0; i + 1 < nstripes; i++) + widths[i] =3D w; + + /* The trailing stripe takes what is left */ + widths[nstripes - 1] =3D src_width - i * w; + + return nstripes; +} + +static unsigned int ope_calc_h_scale(unsigned int src, unsigned int dst, + const unsigned int *widths, unsigned int nstripes, + unsigned int c_hsub, unsigned int sw_align) +{ + unsigned int last_sw =3D widths[nstripes - 1]; + unsigned int denom; + + if (src =3D=3D dst) + return DS_Q21(src, src); + + /* Find the smallest h_scale denominator >=3D dst such that the + * last-stripe adjustment can satisfy both Y and C pixel counts. + */ + for (denom =3D dst; denom <=3D dst + 16 * nstripes; denom++) { + unsigned int hs =3D DS_Q21(src, denom); + unsigned int tw =3D 0, tc =3D 0; + unsigned int ry, rc, s_y, s_c, s, i; + + for (i =3D 0; i < nstripes - 1; i++) { + tw +=3D DS_OUTPUT_PIX(widths[i], 0, hs); + tc +=3D DS_OUTPUT_PIX(widths[i] / c_hsub, 0, hs); + } + + if (tw > dst || tc > dst / c_hsub) + continue; + + ry =3D dst - tw; + rc =3D dst / c_hsub - tc; + s_y =3D DIV_ROUND_UP((u64)ry * hs, Q21(1)); + s_c =3D DIV_ROUND_UP((u64)rc * hs, Q21(1)) * c_hsub; + s =3D ALIGN(max(s_y, s_c), sw_align); + + s =3D clamp(s, OPE_STRIPE_MIN_W, last_sw); + tw +=3D DS_OUTPUT_PIX(s, 0, hs); + tc +=3D DS_OUTPUT_PIX(s / c_hsub, 0, hs); + + if (tw =3D=3D dst && tc * c_hsub =3D=3D dst) + return hs; + } + + return DS_Q21(src, dst); +} + +static unsigned int ope_calc_v_scale(unsigned int src, unsigned int dst) +{ + return DS_Q21(src, dst); +} + +static void ope_gen_stripe_chroma_dsc(struct ope_ctx *ctx, + struct ope_stripe *stripe) +{ + struct ope_dsc_config *dsc =3D &stripe->dsc[OPE_DS_C_PRE]; + const struct ope_fmt *fmt =3D ctx->fmt_out.fmt; + + dsc->input_width =3D stripe->src.width; + dsc->input_height =3D stripe->src.height; + + dsc->output_width =3D dsc->input_width / fmt->c_hsub; + dsc->output_height =3D dsc->input_height / fmt->c_vsub; + + dsc->phase_step_h =3D DS_Q21(dsc->input_width, dsc->output_width); + dsc->phase_step_v =3D DS_Q21(dsc->input_height, dsc->output_height); +} + +static void ope_gen_stripe_dsc(struct ope_ctx *ctx, struct ope_stripe *str= ipe, + unsigned int h_scale, unsigned int v_scale) +{ + struct ope_dsc_config *dsc_c =3D &stripe->dsc[OPE_DS_C_DISP]; + struct ope_dsc_config *dsc_y =3D &stripe->dsc[OPE_DS_Y_DISP]; + unsigned int sw =3D stripe->src.width; + unsigned int sw_c =3D stripe->dsc[OPE_DS_C_PRE].output_width; + + dsc_c->phase_step_h =3D dsc_y->phase_step_h =3D h_scale; + dsc_c->phase_step_v =3D dsc_y->phase_step_v =3D v_scale; + + dsc_c->input_width =3D stripe->dsc[OPE_DS_C_PRE].output_width; + dsc_c->input_height =3D stripe->dsc[OPE_DS_C_PRE].output_height; + dsc_y->input_width =3D stripe->src.width; + dsc_y->input_height =3D stripe->src.height; + + /* Clip the output so the WE always receives the expected count */ + dsc_y->output_width =3D DS_OUTPUT_PIX(sw, 0, h_scale); + dsc_y->output_height =3D DS_OUTPUT_PIX(stripe->src.height, 0, v_scale); + dsc_c->output_width =3D DS_OUTPUT_PIX(sw_c, 0, h_scale); + dsc_c->output_height =3D DS_OUTPUT_PIX(stripe->dsc[OPE_DS_C_PRE].output_h= eight, 0, v_scale); + + dsc_y->output_width =3D max_t(unsigned int, dsc_y->output_width, 1); + dsc_y->output_height =3D max_t(unsigned int, dsc_y->output_height, 1); + dsc_c->output_width =3D max_t(unsigned int, dsc_c->output_width, 1); + dsc_c->output_height =3D max_t(unsigned int, dsc_c->output_height, 1); + + dsc_y->crop_last_pixel =3D dsc_y->output_width - 1; + dsc_y->crop_last_line =3D dsc_y->output_height - 1; + dsc_c->crop_last_pixel =3D dsc_c->output_width - 1; + dsc_c->crop_last_line =3D dsc_c->output_height - 1; +} + +static void ope_gen_stripe_yuv_dst(struct ope_ctx *ctx, struct ope_stripe = *stripe, + dma_addr_t dst, const struct v4l2_rect *compose) +{ + const struct ope_fmt_state *fo =3D &ctx->fmt_out; + const struct ope_hw_fmt *hw =3D ope_find_hw_fmt(fo->fmt->fourcc); + struct ope_stripe *prev =3D ope_prev_stripe(ctx, stripe); + unsigned int bpl =3D fo->bytesperline; + unsigned int img_h =3D fo->height; + unsigned int c_stride; + unsigned int x_init; + dma_addr_t base; + + stripe->dst[OPE_WR_CLIENT_DISP_Y].enabled =3D true; + stripe->dst[OPE_WR_CLIENT_DISP_C].enabled =3D true; + + /* Y plane */ + base =3D dst + compose->top * bpl; + + if (prev) + x_init =3D prev->dst[OPE_WR_CLIENT_DISP_Y].x_init + + prev->dst[OPE_WR_CLIENT_DISP_Y].width; + else + x_init =3D compose->left; + + stripe->dst[OPE_WR_CLIENT_DISP_Y].addr =3D base; + stripe->dst[OPE_WR_CLIENT_DISP_Y].x_init =3D x_init; + stripe->dst[OPE_WR_CLIENT_DISP_Y].width =3D stripe->dsc[OPE_DS_Y_DISP].o= utput_width; + stripe->dst[OPE_WR_CLIENT_DISP_Y].height =3D stripe->dsc[OPE_DS_Y_DISP].o= utput_height; + stripe->dst[OPE_WR_CLIENT_DISP_Y].stride =3D bpl; + stripe->dst[OPE_WR_CLIENT_DISP_Y].format =3D OPE_PACKER_FMT_PLAIN_8; + + /* UV plane (appended to Y plane)*/ + c_stride =3D bpl * 2 / fo->fmt->c_hsub; + base =3D dst + bpl * img_h + (compose->top / fo->fmt->c_vsub) * c_stride; + + if (prev) + x_init =3D prev->dst[OPE_WR_CLIENT_DISP_C].x_init + + prev->dst[OPE_WR_CLIENT_DISP_C].width; + else + x_init =3D compose->left * 2 / fo->fmt->c_hsub; + + stripe->dst[OPE_WR_CLIENT_DISP_C].addr =3D base; + stripe->dst[OPE_WR_CLIENT_DISP_C].x_init =3D x_init; + stripe->dst[OPE_WR_CLIENT_DISP_C].format =3D hw ? hw->packer : OPE_PACKER= _FMT_PLAIN_8; + stripe->dst[OPE_WR_CLIENT_DISP_C].width =3D stripe->dsc[OPE_DS_C_DISP].o= utput_width * 2; + stripe->dst[OPE_WR_CLIENT_DISP_C].height =3D stripe->dsc[OPE_DS_C_DISP].o= utput_height; + + switch (fo->fmt->fourcc) { + case V4L2_PIX_FMT_GREY: + stripe->dst[OPE_WR_CLIENT_DISP_C].enabled =3D false; + break; + default: + stripe->dst[OPE_WR_CLIENT_DISP_C].stride =3D c_stride; + break; + } +} + +static int ope_gen_stripes(struct ope_ctx *ctx, dma_addr_t src, dma_addr_t= dst) +{ + const struct ope_fmt_state *fi =3D &ctx->fmt_in; + const struct ope_hw_fmt *src_hw =3D ope_find_hw_fmt(fi->fmt->fourcc); + unsigned int h_scale, v_scale, num_stripes, x_out, x_out_c; + const struct ope_fmt_state *fo =3D &ctx->fmt_out; + const struct v4l2_rect *compose, *crop; + unsigned int c_hsub =3D fo->fmt->c_hsub; + unsigned int widths[OPE_MAX_STRIPE]; + struct v4l2_subdev_state *sd_state; + struct v4l2_subdev *proc_sd; + int ret =3D 0; + u32 height; + + proc_sd =3D camss_isp_pipeline_get_subdev(ctx->ope->pipeline, OPE_ENTITY_= PROC); + sd_state =3D v4l2_subdev_lock_and_get_active_state(proc_sd); + crop =3D v4l2_subdev_state_get_crop(sd_state, OPE_PROC_PAD_SINK_IN); + compose =3D v4l2_subdev_state_get_compose(sd_state, OPE_PROC_PAD_SOURCE); + + if (compose->left + compose->width > fo->width || + compose->top + compose->height > fo->height) { + ret =3D -ERANGE; + goto out; + } + + /* Advance source pointer to the crop origin */ + src +=3D crop->top * fi->bytesperline + crop->left * fi->fmt->depth / 8; + + height =3D crop->height; + num_stripes =3D ope_split_stripes(crop->width, fi->fmt->align, widths, &h= eight); + if (!num_stripes) { + ret =3D -ERANGE; + goto out; + } + + h_scale =3D ope_calc_h_scale(crop->width, compose->width, widths, num_st= ripes, c_hsub, + max(2u, 1u << fi->fmt->align)); + v_scale =3D ope_calc_v_scale(crop->height, compose->height); + + x_out =3D x_out_c =3D 0; + + for (unsigned int i =3D 0; i < num_stripes; i++) { + struct ope_stripe *stripe =3D &ctx->stripe[i]; + + memset(stripe, 0, sizeof(*stripe)); + + stripe->src.addr =3D src; + stripe->src.width =3D widths[i]; + stripe->src.height =3D height; + stripe->src.stride =3D fi->bytesperline; + stripe->src.location =3D ope_stripe_location(i, num_stripes); + stripe->src.pattern =3D src_hw ? src_hw->pattern : 0; + stripe->src.format =3D src_hw ? src_hw->unpacker : 0; + + src +=3D stripe->src.width * fi->fmt->depth / 8; + + /* Last-stripe adjustment: compute the minimum input width that + * delivers exactly the remaining output pixels for Y and C. + */ + if (ope_stripe_is_last(stripe)) { + unsigned int rem_y =3D compose->width - x_out; + unsigned int rem_c =3D compose->width / c_hsub - x_out_c; + unsigned int s_y =3D DIV_ROUND_UP((u64)rem_y * h_scale, Q21(1)); + unsigned int s_c =3D DIV_ROUND_UP((u64)rem_c * h_scale, Q21(1)) * c_hsu= b; + unsigned int s =3D ALIGN(max(s_y, s_c), max(2u, 1u << fi->fmt->align)); + + stripe->src.width =3D clamp(s, OPE_STRIPE_MIN_W, stripe->src.width); + } + + ope_gen_stripe_chroma_dsc(ctx, stripe); + ope_gen_stripe_dsc(ctx, stripe, h_scale, v_scale); + ope_gen_stripe_yuv_dst(ctx, stripe, dst, compose); + + x_out +=3D stripe->dsc[OPE_DS_Y_DISP].output_width; + x_out_c +=3D stripe->dsc[OPE_DS_C_DISP].output_width; + + /* Width in bytes for the fetch engine */ + stripe->src.width =3D stripe->src.width * fi->fmt->depth / 8; + } + + if (x_out !=3D compose->width || x_out_c !=3D compose->width / c_hsub) + ret =3D -ERANGE; + +out: + v4l2_subdev_unlock_state(sd_state); + + return ret; +} + +/* -------- Pipeline IQ module programming -------- */ + +static bool ope_module_update(struct ope_ctx *ctx, u32 module_cfg_reg, u32= enable_mask, + struct v4l2_isp_params_block_header *hdr, bool force) +{ + bool enable =3D !(hdr->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE); + bool dirty =3D hdr->flags & CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY; + + /* skip if neither forced (new context) nor dirty (updated params) */ + if (!force && !dirty) + return false; + + hdr->flags &=3D ~CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY; + + ope_write_pp(ctx->ope, module_cfg_reg, enable ? enable_mask : 0); + + /* If module is disabled, not need to update content */ + if (!enable) + return false; + + dev_dbg(ctx->ope->dev, "IQ module (%u) update (flags:0x%x)\n", hdr->type,= hdr->flags); + + return true; +} + +static void ope_prog_wb(struct ope_ctx *ctx, bool force) +{ + struct camss_params_wb_gain *wb =3D &ctx->config.wb_gain; + struct ope_dev *ope =3D ctx->ope; + + if (!ope_module_update(ctx, OPE_PP_WB_GAIN_MODULE_CFG, + OPE_PP_WB_GAIN_MODULE_CFG_EN, + &wb->header, force)) + return; + + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_CFG(0), + FIELD_PREP(OPE_PP_WB_GAIN_WB_CFG_GAIN, wb->g_gain)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_CFG(1), + FIELD_PREP(OPE_PP_WB_GAIN_WB_CFG_GAIN, wb->b_gain)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_CFG(2), + FIELD_PREP(OPE_PP_WB_GAIN_WB_CFG_GAIN, wb->r_gain)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_SUB_CFG(0), + FIELD_PREP(OPE_PP_WB_GAIN_WB_SUB_CFG_VAL, wb->g_sub)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_SUB_CFG(1), + FIELD_PREP(OPE_PP_WB_GAIN_WB_SUB_CFG_VAL, wb->b_sub)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_SUB_CFG(2), + FIELD_PREP(OPE_PP_WB_GAIN_WB_SUB_CFG_VAL, wb->r_sub)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_ADD_CFG(0), + FIELD_PREP(OPE_PP_WB_GAIN_WB_ADD_CFG_VAL, wb->g_add)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_ADD_CFG(1), + FIELD_PREP(OPE_PP_WB_GAIN_WB_ADD_CFG_VAL, wb->b_add)); + ope_write_pp(ope, OPE_PP_WB_GAIN_WB_ADD_CFG(2), + FIELD_PREP(OPE_PP_WB_GAIN_WB_ADD_CFG_VAL, wb->r_add)); +} + +static void ope_prog_bayer2rgb(struct ope_ctx *ctx, bool force) +{ + struct ope_params_demo *demo =3D &ctx->config.demo; + struct ope_dev *ope =3D ctx->ope; + + if (!ope_module_update(ctx, OPE_PP_DEMO_MODULE_CFG, + OPE_PP_DEMO_MODULE_CFG_EN | + OPE_PP_DEMO_MODULE_CFG_DYN_G_CLAMP_EN | + OPE_PP_DEMO_MODULE_CFG_DYN_RB_CLAMP_EN, + &demo->header, force)) + return; + + ope_write_pp(ope, OPE_PP_DEMO_INTERP_COEFF_CFG, + FIELD_PREP(OPE_PP_DEMO_INTERP_COEFF_CFG_LAMBDA_G, demo->lambda_g) | + FIELD_PREP(OPE_PP_DEMO_INTERP_COEFF_CFG_LAMBDA_RB, demo->lambda_rb)= ); + ope_write_pp(ope, OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_0, + FIELD_PREP(OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_0_AK, demo->a_k)); + ope_write_pp(ope, OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_1, + FIELD_PREP(OPE_PP_DEMO_INTERP_CLASSIFIER_CFG_1_WK, demo->w_k)); +} + +static void ope_prog_rgb2yuv(struct ope_ctx *ctx, bool force) +{ + struct camss_params_chroma_enhan *cc =3D &ctx->config.chroma_enhan; + struct ope_dev *ope =3D ctx->ope; + + if (!ope_module_update(ctx, OPE_PP_CHROMA_ENHAN_MODULE_CFG, + OPE_PP_CHROMA_ENHAN_MODULE_CFG_EN, + &cc->header, force)) + return; + + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_LUMA_CFG_0, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_LUMA_CFG_0_V0, cc->luma_v0) | + FIELD_PREP(OPE_PP_CHROMA_ENHAN_LUMA_CFG_0_V1, cc->luma_v1)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_LUMA_CFG_1, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_LUMA_CFG_1_K, cc->luma_k)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_LUMA_CFG_2, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_LUMA_CFG_2_V2, cc->luma_v2)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_COEFF_A_CFG, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_A_CFG_AP, cc->coeff_ap) | + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_A_CFG_AM, cc->coeff_am)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_COEFF_B_CFG, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_B_CFG_BP, cc->coeff_bp) | + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_B_CFG_BM, cc->coeff_bm)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_COEFF_C_CFG, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_C_CFG_CP, cc->coeff_cp) | + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_C_CFG_CM, cc->coeff_cm)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_COEFF_D_CFG, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_D_CFG_DP, cc->coeff_dp) | + FIELD_PREP(OPE_PP_CHROMA_ENHAN_COEFF_D_CFG_DM, cc->coeff_dm)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_CHROMA_CFG_0, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_CHROMA_CFG_0_KCB, cc->kcb)); + ope_write_pp(ope, OPE_PP_CHROMA_ENHAN_CHROMA_CFG_1, + FIELD_PREP(OPE_PP_CHROMA_ENHAN_CHROMA_CFG_1_KCR, cc->kcr)); +} + +static void ope_prog_color_correct(struct ope_ctx *ctx, bool force) +{ + struct camss_params_color_correct *cc =3D &ctx->config.color_correct; + struct ope_dev *ope =3D ctx->ope; + + if (!ope_module_update(ctx, OPE_PP_CC_MODULE_CFG, + OPE_PP_CC_MODULE_CFG_EN, + &cc->header, force)) + return; + + ope_write_pp(ope, OPE_PP_CC_COEFF_A_CFG_0, + FIELD_PREP(OPE_PP_CC_COEFF_A_CFG_0_A0, cc->a[0]) | + FIELD_PREP(OPE_PP_CC_COEFF_A_CFG_0_A1, cc->a[1])); + ope_write_pp(ope, OPE_PP_CC_COEFF_A_CFG_1, + FIELD_PREP(OPE_PP_CC_COEFF_A_CFG_1_A2, cc->a[2])); + ope_write_pp(ope, OPE_PP_CC_COEFF_B_CFG_0, + FIELD_PREP(OPE_PP_CC_COEFF_B_CFG_0_B0, cc->b[0]) | + FIELD_PREP(OPE_PP_CC_COEFF_B_CFG_0_B1, cc->b[1])); + ope_write_pp(ope, OPE_PP_CC_COEFF_B_CFG_1, + FIELD_PREP(OPE_PP_CC_COEFF_B_CFG_1_B2, cc->b[2])); + ope_write_pp(ope, OPE_PP_CC_COEFF_C_CFG_0, + FIELD_PREP(OPE_PP_CC_COEFF_C_CFG_0_C0, cc->c[0]) | + FIELD_PREP(OPE_PP_CC_COEFF_C_CFG_0_C1, cc->c[1])); + ope_write_pp(ope, OPE_PP_CC_COEFF_C_CFG_1, + FIELD_PREP(OPE_PP_CC_COEFF_C_CFG_1_C2, cc->c[2])); + ope_write_pp(ope, OPE_PP_CC_COEFF_K_CFG_0, + FIELD_PREP(OPE_PP_CC_COEFF_K_CFG_0_K0, cc->k[0])); + ope_write_pp(ope, OPE_PP_CC_COEFF_K_CFG_1, + FIELD_PREP(OPE_PP_CC_COEFF_K_CFG_1_K1, cc->k[1])); + ope_write_pp(ope, OPE_PP_CC_COEFF_K_CFG_2, + FIELD_PREP(OPE_PP_CC_COEFF_K_CFG_2_K2, cc->k[2])); + ope_write_pp(ope, OPE_PP_CC_COEFF_M_CFG, + FIELD_PREP(OPE_PP_CC_COEFF_M_CFG_M, cc->qfactor)); +} + +static void ope_glut_load_lut(struct ope_dev *ope, enum ope_glut_sel ch, + u8 bank, const u16 *lut) +{ + ope_write_pp(ope, OPE_PP_GLUT_DMI_LUT_BANK_CFG, + FIELD_PREP(OPE_PP_GLUT_DMI_LUT_BANK_CFG_SEL, bank)); + ope_write_pp(ope, OPE_PP_GLUT_DMI_LUT_CFG, + FIELD_PREP(OPE_PP_GLUT_DMI_LUT_CFG_SEL, ch)); + ope_write_pp(ope, OPE_PP_GLUT_DMI_CFG, + OPE_PP_GLUT_DMI_CFG_AUTO_LOAD_EN | + FIELD_PREP(OPE_PP_GLUT_DMI_CFG_ADDR, 0)); + for (unsigned int i =3D 0; i < CAMSS_GAMMA_LUT_SIZE; i++) + ope_write_pp(ope, OPE_PP_GLUT_DMI_DATA, lut[i]); +} + +static void ope_glut_upload(struct ope_ctx *ctx, u8 bank) +{ + struct camss_params_gamma *gamma =3D &ctx->config.gamma; + struct ope_dev *ope =3D ctx->ope; + + ope_glut_load_lut(ope, OPE_GLUT_SEL_R, bank, gamma->rlut); + ope_glut_load_lut(ope, OPE_GLUT_SEL_G, bank, gamma->glut); + ope_glut_load_lut(ope, OPE_GLUT_SEL_B, bank, gamma->blut); + + ope_write_pp(ope, OPE_PP_GLUT_DMI_LUT_CFG, + FIELD_PREP(OPE_PP_GLUT_DMI_LUT_CFG_SEL, + OPE_GLUT_SEL_NONE)); + + ope->glut_bank[bank].owner =3D ctx; + ope->glut_bank[bank].valid =3D true; +} + +static bool ope_glut_bank_resident(struct ope_dev *ope, u8 bank, + struct ope_ctx *ctx) +{ + return ope->glut_bank[bank].valid && + ope->glut_bank[bank].owner =3D=3D ctx; +} + +static void ope_prog_gamma(struct ope_ctx *ctx, bool force) +{ + struct camss_params_gamma *gamma =3D &ctx->config.gamma; + bool enable =3D !(gamma->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE); + bool dirty =3D gamma->header.flags & CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY; + struct ope_dev *ope =3D ctx->ope; + u8 bank; + + if (!force && !dirty) + return; + + gamma->header.flags &=3D ~CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY; + + if (!enable) { + ope_write_pp(ope, OPE_PP_GLUT_MODULE_CFG, 0); + return; + } + + if (!dirty && ope_glut_bank_resident(ope, ope->glut_cur_bank, ctx)) { + /* Already active in the read bank: only (re)enable the module. */ + bank =3D ope->glut_cur_bank; + } else if (!dirty && ope_glut_bank_resident(ope, !ope->glut_cur_bank, ctx= )) { + /* Resident in the other bank: flip to it, no upload. */ + bank =3D !ope->glut_cur_bank; + } else { + /* Dirty, or miss in both banks: upload into the LRU bank. */ + bank =3D !ope->glut_mru_bank; + ope_glut_upload(ctx, bank); + } + + ope->glut_mru_bank =3D bank; + + dev_dbg(ope->dev, + "IQ module (%u) update (flags:0x%x) glut bank %u->%u)\n", + gamma->header.type, gamma->header.flags, + ope->glut_cur_bank, bank); + + ope_write_pp(ope, OPE_PP_GLUT_MODULE_LUT_BANK_CFG, + FIELD_PREP(OPE_PP_GLUT_MODULE_LUT_BANK_CFG_SEL, bank)); + ope->glut_cur_bank =3D bank; + + ope_write_pp(ope, OPE_PP_GLUT_MODULE_CFG, OPE_PP_GLUT_MODULE_CFG_EN); +} + +static void ope_glut_cache_invalidate(struct ope_dev *ope) +{ + ope->glut_bank[0].valid =3D false; + ope->glut_bank[1].valid =3D false; + ope->glut_cur_bank =3D 0; + ope->glut_mru_bank =3D 0; +} + +static void ope_prog_crop_rnd_clamp(struct ope_dev *ope, const struct ope_= stripe *stripe) +{ + static const u32 crop_bases[] =3D { + OPE_PP_CROP_RND_CLAMP_Y_DISP_BASE, + OPE_PP_CROP_RND_CLAMP_C_DISP_BASE, + }; + static const enum ope_downscaler ds_idx[] =3D { + OPE_DS_Y_DISP, + OPE_DS_C_DISP, + }; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(crop_bases); i++) { + const struct ope_dsc_config *dsc =3D &stripe->dsc[ds_idx[i]]; + u32 cbase =3D crop_bases[i]; + + if (!dsc->output_width || !dsc->output_height) { + ope_write_pp(ope, OPE_PP_CROP_RND_CLAMP_MODULE_CFG(cbase), 0); + continue; + } + + ope_write_pp(ope, OPE_PP_CROP_RND_CLAMP_CROP_PIXEL_CFG(cbase), + FIELD_PREP(OPE_PP_CROP_RND_CLAMP_CROP_FIRST, 0) | + FIELD_PREP(OPE_PP_CROP_RND_CLAMP_CROP_LAST, + dsc->crop_last_pixel)); + ope_write_pp(ope, OPE_PP_CROP_RND_CLAMP_CROP_LINE_CFG(cbase), + FIELD_PREP(OPE_PP_CROP_RND_CLAMP_CROP_FIRST, 0) | + FIELD_PREP(OPE_PP_CROP_RND_CLAMP_CROP_LAST, dsc->crop_last_line)); + ope_write_pp(ope, OPE_PP_CROP_RND_CLAMP_MODULE_CFG(cbase), + OPE_PP_CROP_RND_CLAMP_EN | OPE_PP_CROP_RND_CLAMP_CROP_EN); + } +} + +static void ope_prog_stripe(struct ope_ctx *ctx, struct ope_stripe *stripe) +{ + struct ope_dev *ope =3D ctx->ope; + + dev_dbg(ope->dev, "ctx=3D%p programming stripe %u\n", + ctx, (unsigned int)(stripe - ctx->stripe)); + + /* Fetch Engine */ + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_UNPACK_CFG_0, stripe->src.format); + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_RD_BUFFER_SIZE, + (stripe->src.width << 16) | stripe->src.height); + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_ADDR_IMAGE, stripe->src.addr); + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_RD_STRIDE, stripe->src.stride); + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_CCIF_META_DATA, + FIELD_PREP(OPE_BUS_RD_CLIENT_0_CCIF_MD_PIX_PATTERN, + stripe->src.pattern)); + ope_write_rd(ope, OPE_BUS_RD_CLIENT_0_CORE_CFG, + OPE_BUS_RD_CLIENT_0_CORE_CFG_EN); + + /* Write Engines */ + for (int i =3D 0; i < OPE_WR_CLIENT_MAX; i++) { + if (!stripe->dst[i].enabled) { + ope_write_wr(ope, OPE_BUS_WR_CLIENT_CFG(i), 0); + continue; + } + + ope_write_wr(ope, OPE_BUS_WR_CLIENT_ADDR_IMAGE(i), + stripe->dst[i].addr); + ope_write_wr(ope, OPE_BUS_WR_CLIENT_IMAGE_CFG_0(i), + (stripe->dst[i].height << 16) | stripe->dst[i].width); + ope_write_wr(ope, OPE_BUS_WR_CLIENT_IMAGE_CFG_1(i), + stripe->dst[i].x_init); + ope_write_wr(ope, OPE_BUS_WR_CLIENT_IMAGE_CFG_2(i), + stripe->dst[i].stride); + ope_write_wr(ope, OPE_BUS_WR_CLIENT_PACKER_CFG(i), + stripe->dst[i].format); + ope_write_wr(ope, OPE_BUS_WR_CLIENT_CFG(i), + OPE_BUS_WR_CLIENT_CFG_EN | + OPE_BUS_WR_CLIENT_CFG_AUTORECOVER); + } + + /* Downscalers */ + for (int i =3D 0; i < OPE_DS_MAX; i++) { + struct ope_dsc_config *dsc =3D &stripe->dsc[i]; + u32 base =3D ope_ds_base[i]; + u32 cfg =3D 0; + + if (dsc->input_width !=3D dsc->output_width) { + dsc->phase_step_h |=3D + DS_RESOLUTION(dsc->input_width, + dsc->output_width) << 30; + cfg |=3D OPE_PP_DOWNSCALE_MN_DS_CFG_H_SCALE_EN; + } + if (dsc->input_height !=3D dsc->output_height) { + dsc->phase_step_v |=3D + DS_RESOLUTION(dsc->input_height, + dsc->output_height) << 30; + cfg |=3D OPE_PP_DOWNSCALE_MN_DS_CFG_V_SCALE_EN; + } + + ope_write_pp(ope, OPE_PP_DOWNSCALE_MN_DS_CFG(base), cfg); + ope_write_pp(ope, OPE_PP_DOWNSCALE_MN_DS_IMAGE_SIZE_CFG(base), + ((dsc->input_width - 1) << 16) | (dsc->input_height - 1)); + ope_write_pp(ope, OPE_PP_DOWNSCALE_MN_DS_MN_H_CFG(base), + dsc->phase_step_h); + ope_write_pp(ope, OPE_PP_DOWNSCALE_MN_DS_MN_V_CFG(base), + dsc->phase_step_v); + ope_write_pp(ope, OPE_PP_DOWNSCALE_MN_CFG(base), + cfg ? OPE_PP_DOWNSCALE_MN_CFG_EN : 0); + + dev_dbg(ope->dev, "DS[%d] cfg=3D0x%x in=3D%ux%u out=3D%ux%u\n", + i, cfg, dsc->input_width, dsc->input_height, + dsc->output_width, dsc->output_height); + } + + ope_prog_crop_rnd_clamp(ope, stripe); +} + +static void ope_params_apply_wb(void *priv, const union camss_isp_params_b= lock *block) +{ + struct ope_ctx *ctx =3D priv; + + if (!camss_isp_params_copy_block(&ctx->config.wb_gain, block, sizeof(ctx-= >config.wb_gain))) + return; + + ctx->config.wb_gain.g_sub =3D block->wb_gain.g_sub >> 4; + ctx->config.wb_gain.b_sub =3D block->wb_gain.b_sub >> 4; + ctx->config.wb_gain.r_sub =3D block->wb_gain.r_sub >> 4; + ctx->config.wb_gain.g_add =3D block->wb_gain.g_add >> 4; + ctx->config.wb_gain.b_add =3D block->wb_gain.b_add >> 4; + ctx->config.wb_gain.r_add =3D block->wb_gain.r_add >> 4; +} + +static void ope_params_apply_chroma_enhan(void *priv, const union camss_is= p_params_block *block) +{ + struct ope_ctx *ctx =3D priv; + + camss_isp_params_copy_block(&ctx->config.chroma_enhan, block, + sizeof(ctx->config.chroma_enhan)); +} + +static void ope_params_apply_color_correct(void *priv, const union camss_i= sp_params_block *block) +{ + struct ope_ctx *ctx =3D priv; + + camss_isp_params_copy_block(&ctx->config.color_correct, block, + sizeof(ctx->config.color_correct)); +} + +static void ope_params_apply_gamma(void *priv, const union camss_isp_param= s_block *block) +{ + struct ope_ctx *ctx =3D priv; + + camss_isp_params_copy_block(&ctx->config.gamma, block, sizeof(ctx->config= .gamma)); +} + +static const struct v4l2_isp_params_block_type_info ope_params_type_info[]= =3D { + [CAMSS_PARAMS_WB_GAIN] =3D { sizeof(struct camss_params_wb_gain) }, + [CAMSS_PARAMS_CHROMA_ENHAN] =3D { sizeof(struct camss_params_chroma_enha= n) }, + [CAMSS_PARAMS_COLOR_CORRECT] =3D { sizeof(struct camss_params_color_corre= ct) }, + [CAMSS_PARAMS_GAMMA] =3D { sizeof(struct camss_params_gamma) }, +}; + +static const camss_isp_params_handler_fn ope_params_handlers[] =3D { + [CAMSS_PARAMS_WB_GAIN] =3D ope_params_apply_wb, + [CAMSS_PARAMS_CHROMA_ENHAN] =3D ope_params_apply_chroma_enhan, + [CAMSS_PARAMS_COLOR_CORRECT] =3D ope_params_apply_color_correct, + [CAMSS_PARAMS_GAMMA] =3D ope_params_apply_gamma, +}; + +static struct vb2_v4l2_buffer *ope_queue_remove(struct ope_ctx *ctx, + unsigned int idx) +{ + struct ope_queue *q =3D &ctx->queues[idx]; + struct camss_isp_buf *buf; + + scoped_guard(spinlock_irqsave, &q->rdy_spinlock) { + buf =3D list_first_entry_or_null(&q->rdy_queue, struct camss_isp_buf, li= st); + if (buf) + list_del(&buf->list); + } + + return buf ? &buf->vb : NULL; +} + +static struct vb2_v4l2_buffer *ope_queue_peek(struct ope_ctx *ctx, + unsigned int idx) +{ + struct ope_queue *q =3D &ctx->queues[idx]; + struct camss_isp_buf *buf; + + scoped_guard(spinlock_irqsave, &q->rdy_spinlock) + buf =3D list_first_entry_or_null(&q->rdy_queue, struct camss_isp_buf, li= st); + + return buf ? &buf->vb : NULL; +} + +static void ope_queue_drain(struct ope_ctx *ctx, unsigned int idx, + enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *vbuf; + + while ((vbuf =3D ope_queue_remove(ctx, idx))) + vb2_buffer_done(&vbuf->vb2_buf, state); +} + +static int ope_apply_params(struct ope_ctx *ctx) +{ + struct vb2_v4l2_buffer *vbuf; + + vbuf =3D ope_queue_peek(ctx, OPE_QUEUE_PARAMS); + if (!vbuf) + return 0; + + return camss_isp_params_apply(ctx->ope->dev, &vbuf->vb2_buf, + ctx->params_buf, + ope_params_type_info, + ope_params_handlers, + ARRAY_SIZE(ope_params_handlers), + ctx); +} + +/* Default/initial tuning parameters */ +static const struct ope_config ope_default_config =3D { + .wb_gain =3D { + .header.type =3D CAMSS_PARAMS_WB_GAIN, + .header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_ENABLE | + CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY, + .g_gain =3D OPE_WB(1, 1), + .b_gain =3D OPE_WB(3, 2), + .r_gain =3D OPE_WB(3, 2), + }, + .demo =3D { + .header.type =3D CAMSS_PARAMS_INTERNAL, + .header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_ENABLE | + CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY, + .lambda_rb =3D 0, + .lambda_g =3D 128, + .a_k =3D 128, + .w_k =3D 102, + }, + .chroma_enhan =3D { /* RGB -> YUV values from BT.601/Full-Range */ + .header.type =3D CAMSS_PARAMS_CHROMA_ENHAN, + .header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_ENABLE | + CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY, + .luma_v0 =3D 0x04d, /* 0.299 */ + .luma_v1 =3D 0x096, /* 0.587 */ + .luma_v2 =3D 0x01d, /* 0.114 */ + .luma_k =3D 0, + .coeff_ap =3D 0x077, /* 0.464 */ + .coeff_am =3D 0x070, /* 0.438 */ + .coeff_bp =3D 0xfac, /* -0.329 */ + .coeff_bm =3D 0xfc4, /* -0.234 */ + .coeff_cp =3D 0x086, /* 0.524 */ + .coeff_cm =3D 0x089, /* 0.535 */ + .coeff_dp =3D 0xfff, /* -0.004 */ + .coeff_dm =3D 0xfdf, /* -0.130 */ + .kcb =3D 128, + .kcr =3D 128, + }, + .color_correct =3D { + .header.type =3D CAMSS_PARAMS_COLOR_CORRECT, + .header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_DISABLE | + CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY, + }, + .gamma =3D { + .header.type =3D CAMSS_PARAMS_GAMMA, + .header.flags =3D V4L2_ISP_PARAMS_FL_BLOCK_DISABLE | + CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY, + }, +}; + +static void ope_try_schedule(struct ope_ctx *ctx); + +static int ope_hw_reset_sync(struct ope_dev *ope) +{ + reinit_completion(&ope->reset_complete); + ope_write(ope, OPE_TOP_RESET_CMD, OPE_TOP_RESET_CMD_SW); + + if (!wait_for_completion_timeout(&ope->reset_complete, + msecs_to_jiffies(OPE_RESET_TIMEOUT_MS))) + return -ETIMEDOUT; + + return 0; +} + +static int ope_hw_reset_poll(struct ope_dev *ope) +{ + u32 status; + int ret; + + ope_write(ope, OPE_TOP_IRQ_MASK, OPE_TOP_IRQ_STATUS_RST_DONE); + ope_write(ope, OPE_TOP_RESET_CMD, OPE_TOP_RESET_CMD_SW); + + ret =3D read_poll_timeout(ope_read, status, + status & OPE_TOP_IRQ_STATUS_RST_DONE, + OPE_RESET_POLL_US, + OPE_RESET_TIMEOUT_MS * USEC_PER_MSEC, false, + ope, OPE_TOP_IRQ_STATUS); + + ope_write(ope, OPE_TOP_IRQ_CLEAR, OPE_TOP_IRQ_STATUS_RST_DONE); + ope_write(ope, OPE_TOP_IRQ_CMD, OPE_TOP_IRQ_CMD_CLEAR); + ope_write(ope, OPE_TOP_IRQ_MASK, 0); + + if (ret) + return ret; + + ope_glut_cache_invalidate(ope); + + return 0; +} + +/* -------- Job scheduling -------- */ +static bool ope_job_ready(void *priv) +{ + struct ope_ctx *ctx =3D priv; + + return ctx->started && + !list_empty(&ctx->queues[OPE_QUEUE_FRAME_IN].rdy_queue) && + !list_empty(&ctx->queues[OPE_QUEUE_DISP_OUT].rdy_queue); +} + +static void ope_job_finish(struct ope_ctx *ctx, enum vb2_buffer_state stat= e) +{ + struct vb2_v4l2_buffer *src, *dst, *params; + struct ope_dev *ope =3D ctx->ope; + + src =3D ope_queue_remove(ctx, OPE_QUEUE_FRAME_IN); + dst =3D ope_queue_remove(ctx, OPE_QUEUE_DISP_OUT); + params =3D ope_queue_remove(ctx, OPE_QUEUE_PARAMS); + + if (dst) { + dst->sequence =3D ctx->fmt_in.sequence++; + if (src) + dst->vb2_buf.timestamp =3D src->vb2_buf.timestamp; + } + + if (dst) + vb2_buffer_done(&dst->vb2_buf, state); + if (src) + vb2_buffer_done(&src->vb2_buf, state); + if (params) + vb2_buffer_done(¶ms->vb2_buf, state); + + scoped_guard(spinlock_irqsave, &ope->sched_lock) { + ope->hw_running =3D false; + ope->curr_ctx =3D NULL; + ctx->queued =3D false; + + /* A failed job leaves the configuration in an unknown state */ + if (state !=3D VB2_BUF_STATE_DONE) + ope->hw_ctx =3D NULL; + } + + dev_dbg(ctx->ope->dev, "done ctx=3D%p state=3D%u\n", ctx, state); + + ope_try_schedule(ctx); +} + +static dma_addr_t ope_buf_dma_addr(struct ope_ctx *ctx, unsigned int queue= _idx) +{ + struct vb2_v4l2_buffer *vbuf =3D ope_queue_peek(ctx, queue_idx); + + if (!vbuf) + return 0; + + return vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); +} + +static void ope_run_job(void *priv, bool ctx_changed) +{ + struct ope_ctx *ctx =3D priv; + struct ope_dev *ope =3D ctx->ope; + dma_addr_t src, dst; + + src =3D ope_buf_dma_addr(ctx, OPE_QUEUE_FRAME_IN); + dst =3D ope_buf_dma_addr(ctx, OPE_QUEUE_DISP_OUT); + + if (!src || !dst) { + dev_warn(ope->dev, "Job cannot run, missing buffer\n"); + ope_hw_reset_sync(ope); + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + return; + } + + dev_dbg(ope->dev, "start ctx=3D%p->%p src=3D%pad dst=3D%pad\n", + ope->hw_ctx, ctx, &src, &dst); + + if (ope_apply_params(ctx)) + dev_warn_ratelimited(ope->dev, "Invalid parameters\n"); + + if (ope_gen_stripes(ctx, src, dst)) { + dev_warn_ratelimited(ope->dev, "Job cannot run, invalid geometry\n"); + ope_hw_reset_sync(ope); + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + return; + } + + ope_prog_wb(ctx, ctx_changed); + ope_prog_bayer2rgb(ctx, ctx_changed); + ope_prog_color_correct(ctx, ctx_changed); + ope_prog_gamma(ctx, ctx_changed); + ope_prog_rgb2yuv(ctx, ctx_changed); + + ctx->current_stripe =3D 0; + + scoped_guard(spinlock_irqsave, &ope->sched_lock) { + ope->hw_ctx =3D ctx; + ope->hw_running =3D true; + } + + ope_prog_stripe(ctx, &ctx->stripe[0]); + + ope_start(ope); +} + +static void ope_sched_cancel(struct ope_ctx *ctx) +{ + struct ope_dev *ope =3D ctx->ope; + bool running; + + disable_work_sync(&ope->run_work); + + scoped_guard(spinlock_irqsave, &ope->sched_lock) + running =3D (ope->hw_running && ope->hw_ctx =3D=3D ctx); + + if (running && ope_hw_reset_sync(ope)) { + dev_err(ope->dev, "reset timeout during cancel\n"); + synchronize_irq(ope->irq); + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + } + + scoped_guard(spinlock_irqsave, &ope->sched_lock) { + ctx->queued =3D false; + if (ope->curr_ctx =3D=3D ctx) + ope->curr_ctx =3D NULL; + if (ope->hw_ctx =3D=3D ctx) { + ope->hw_ctx =3D NULL; + ope->hw_running =3D false; + } + } +} + +static void ope_sched_resume(struct ope_ctx *ctx) +{ + if (enable_work(&ctx->ope->run_work)) + ope_try_schedule(ctx); +} + +static void ope_run_work(struct work_struct *work) +{ + struct ope_dev *ope =3D container_of(work, struct ope_dev, run_work); + struct ope_ctx *ctx; + bool ctx_changed; + + if (unlikely(!ope_hw_available(ope))) + return; + + scoped_guard(spinlock_irqsave, &ope->sched_lock) { + ctx =3D ope->curr_ctx; + + if (!ctx || !ctx->queued || ope->hw_running) + return; + + if (!ope_job_ready(ctx)) { + ctx->queued =3D false; + ope->curr_ctx =3D NULL; + return; + } + + /* The registers still hold the parameters of @hw_ctx */ + ctx_changed =3D (ope->hw_ctx !=3D ctx); + } + + ope_run_job(ctx, ctx_changed); +} + +static void ope_try_schedule(struct ope_ctx *ctx) +{ + struct ope_dev *ope =3D ctx->ope; + + if (!ope_job_ready(ctx)) + return; + + /* Claim the job slot. */ + scoped_guard(spinlock_irqsave, &ope->sched_lock) { + if (ctx->queued || ope->curr_ctx) + return; + ctx->queued =3D true; + ope->curr_ctx =3D ctx; + } + + schedule_work(&ope->run_work); +} + +/* -------- Interrupt handlers -------- */ + +static void ope_fe_irq(struct ope_dev *ope) +{ + u32 status =3D readl_relaxed(ope->base_rd + OPE_BUS_RD_INPUT_IF_IRQ_STATU= S); + + writel_relaxed(status, ope->base_rd + OPE_BUS_RD_INPUT_IF_IRQ_CLEAR); + writel_relaxed(OPE_BUS_RD_INPUT_IF_IRQ_CMD_CLEAR, + ope->base_rd + OPE_BUS_RD_INPUT_IF_IRQ_CMD); + + if (status & OPE_BUS_RD_INPUT_IF_IRQ_STATUS_CCIF_VIOL) + dev_err_ratelimited(ope->dev, "FE: CCIF violation (status=3D0x%08x)\n", = status); +} + +static bool ope_we_irq(struct ope_dev *ope, struct ope_ctx *ctx) +{ + bool reset =3D false; + u32 status; + + status =3D ope_read_wr(ope, OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0); + ope_write_wr(ope, OPE_BUS_WR_INPUT_IF_IRQ_CLEAR_0, status); + ope_write_wr(ope, OPE_BUS_WR_INPUT_IF_IRQ_CMD, OPE_BUS_WR_INPUT_IF_IRQ_CM= D_CLEAR); + + if (!ctx) + return false; + + if (status & OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_CONS_VIOL) { + u32 viol =3D ope_read_wr(ope, OPE_BUS_WR_VIOLATION_STATUS); + + dev_err_ratelimited(ope->dev, "constraint violation (clients=3D0x%x)\n",= viol); + reset =3D true; + } + + if (status & OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_IMG_SZ_VIOL) { + u32 viol =3D ope_read_wr(ope, OPE_BUS_WR_IMAGE_SIZE_VIOLATION_STATUS); + + for (int i =3D 0; i < OPE_WR_CLIENT_MAX; i++) { + if (BIT(i) & viol) + dev_err_ratelimited(ope->dev, "WE%d: image size violation\n", i); + } + reset =3D true; + } + + if (status & OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_VIOL) { + u32 viol =3D ope_read_wr(ope, OPE_BUS_WR_VIOLATION_STATUS); + + dev_err_ratelimited(ope->dev, "fatal violation (status=3D0x%08x)\n", vio= l); + reset =3D true; + } + + if (reset) { + ope_write(ctx->ope, OPE_TOP_RESET_CMD, OPE_TOP_RESET_CMD_SW); + return true; + } + + if (status & OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_RUP_DONE) { + /* Register update done: program next stripe (double-buffered) */ + struct ope_stripe *stripe =3D ope_current_stripe(ctx); + + if (stripe && !ope_stripe_is_last(stripe)) + ope_prog_stripe(ctx, stripe + 1); + } + + return false; +} + + +static void __ope_irq_init(struct ope_dev *ope) +{ + ope_write(ope, OPE_TOP_IRQ_MASK, + OPE_TOP_IRQ_STATUS_RST_DONE | + OPE_TOP_IRQ_STATUS_WE | + OPE_TOP_IRQ_STATUS_FE | + OPE_TOP_IRQ_STATUS_VIOL | + OPE_TOP_IRQ_STATUS_IDLE); + ope_write_wr(ope, OPE_BUS_WR_INPUT_IF_IRQ_MASK_0, + OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_RUP_DONE | + OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_CONS_VIOL | + OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_VIOL | + OPE_BUS_WR_INPUT_IF_IRQ_STATUS_0_IMG_SZ_VIOL); + /* The fetch engine only needs to report bus errors */ + writel_relaxed(OPE_BUS_RD_INPUT_IF_IRQ_STATUS_CCIF_VIOL, + ope->base_rd + OPE_BUS_RD_INPUT_IF_IRQ_MASK); +} + +static irqreturn_t ope_irq(int irq, void *dev_id) +{ + struct ope_dev *ope =3D dev_id; + struct ope_ctx *ctx; + u32 status; + + /* + * The running job is safe to read here without a lock: ope_run_job() + * publishes it before calling ope_start(), so the hardware cannot raise + * an IRQ before it is visible. ope_job_finish() clears hw_running in IRQ + * context here, so the clear is serialised with this read by the IRQ + * itself. + */ + ctx =3D ope->hw_running ? ope->hw_ctx : NULL; + + status =3D ope_read(ope, OPE_TOP_IRQ_STATUS); + if (!status) + return IRQ_NONE; + + ope_write(ope, OPE_TOP_IRQ_CLEAR, status); + ope_write(ope, OPE_TOP_IRQ_CMD, OPE_TOP_IRQ_CMD_CLEAR); + + if (status & OPE_TOP_IRQ_STATUS_RST_DONE) { + dev_dbg(ope->dev, "reset done ctx=3D%p\n", ctx); + ope_glut_cache_invalidate(ope); + if (ctx) + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + + complete(&ope->reset_complete); + + return IRQ_HANDLED; + } + + if (status & OPE_TOP_IRQ_STATUS_VIOL) + dev_warn(ope->dev, "OPE violation: 0x%08x\n", + ope_read(ope, OPE_TOP_VIOLATION_STATUS)); + + if (status & OPE_TOP_IRQ_STATUS_FE) + ope_fe_irq(ope); + + if (status & OPE_TOP_IRQ_STATUS_WE) { + if (ope_we_irq(ope, ctx)) + return IRQ_HANDLED; + } + + if ((status & OPE_TOP_IRQ_STATUS_IDLE) && ctx) { + struct ope_stripe *stripe =3D ope_current_stripe(ctx); + + dev_dbg(ope->dev, "stripe %u done ctx=3D%p\n", ctx->current_stripe, ctx); + + if (unlikely(!stripe)) { + dev_err(ope->dev, "stripe index %u out of range\n", ctx->current_stripe= ); + ctx->current_stripe =3D 0; + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + } else if (ope_stripe_is_last(stripe)) { + ctx->current_stripe =3D 0; + ope_job_finish(ctx, VB2_BUF_STATE_DONE); + } else { + ctx->current_stripe++; + ope_start(ope); + } + } + + return IRQ_HANDLED; +} + +/* -------- vb2 queue private data -------- */ + +struct ope_vq_priv { + struct ope_ctx *ctx; + unsigned int queue_idx; + struct video_device *vdev; +}; + +static inline struct ope_ctx *ope_ctx_from_vq(struct vb2_queue *q) +{ + return ((struct ope_vq_priv *)vb2_get_drv_priv(q))->ctx; +} + +static inline unsigned int ope_idx_from_vq(struct vb2_queue *q) +{ + return ((struct ope_vq_priv *)vb2_get_drv_priv(q))->queue_idx; +} + +static inline struct video_device *ope_vdev_from_vq(struct vb2_queue *q) +{ + return ((struct ope_vq_priv *)vb2_get_drv_priv(q))->vdev; +} + +/* -------- vb2 ops -------- */ + +static int ope_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ope_ctx *ctx =3D ope_ctx_from_vq(q); + unsigned int idx =3D ope_idx_from_vq(q); + unsigned int size; + + if (idx =3D=3D OPE_QUEUE_FRAME_IN) + size =3D ctx->fmt_in.sizeimage ? ctx->fmt_in.sizeimage : PAGE_SIZE; + else if (idx =3D=3D OPE_QUEUE_DISP_OUT) + size =3D ctx->fmt_out.sizeimage ? ctx->fmt_out.sizeimage : PAGE_SIZE; + else + size =3D v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYLOAD); + + if (*nplanes) { + if (*nplanes !=3D 1 || sizes[0] < size) + return -EINVAL; + } else { + *nplanes =3D 1; + sizes[0] =3D size; + } + + return 0; +} + +static int ope_buf_prepare(struct vb2_buffer *vb) +{ + struct ope_ctx *ctx =3D ope_ctx_from_vq(vb->vb2_queue); + unsigned int idx =3D ope_idx_from_vq(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + unsigned int sizeimage; + + if (idx =3D=3D OPE_QUEUE_FRAME_IN) + sizeimage =3D ctx->fmt_in.sizeimage; + else if (idx =3D=3D OPE_QUEUE_DISP_OUT) + sizeimage =3D ctx->fmt_out.sizeimage; + else + sizeimage =3D v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYLOAD); + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vb->vb2_queue->type =3D=3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (vbuf->field =3D=3D V4L2_FIELD_ANY) + vbuf->field =3D V4L2_FIELD_NONE; + if (vbuf->field !=3D V4L2_FIELD_NONE) + return -EINVAL; + } + } + + if (vb2_plane_size(vb, 0) < sizeimage) + return -EINVAL; + + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) + vb2_set_plane_payload(vb, 0, sizeimage); + + return 0; +} + +static void ope_buf_queue(struct vb2_buffer *vb) +{ + struct ope_ctx *ctx =3D ope_ctx_from_vq(vb->vb2_queue); + unsigned int idx =3D ope_idx_from_vq(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf =3D to_vb2_v4l2_buffer(vb); + struct ope_queue *q =3D &ctx->queues[idx]; + struct camss_isp_buf *buf =3D container_of(vbuf, struct camss_isp_buf, vb= ); + + guard(spinlock_irqsave)(&q->rdy_spinlock); + list_add_tail(&buf->list, &q->rdy_queue); + + ope_try_schedule(ctx); +} + +/* -------- Power scaling -------- */ + +static inline unsigned long ope_pixclk(const struct ope_fmt_state *fs, uns= igned int fps) +{ + return (unsigned long)fs->width * fs->height * fps; +} + +static inline unsigned int ope_load_avg(const struct ope_fmt_state *fs, un= signed int fps) +{ + return mult_frac(ope_pixclk(fs, fps), fs->fmt->depth, 1000) / 8; +} + +static inline unsigned int ope_load_peak(const struct ope_fmt_state *fs, u= nsigned int fps) +{ + return ope_load_avg(fs, fps) * 2; +} + +static inline unsigned int ope_load_config(const struct ope_fmt_state *fs,= unsigned int fps) +{ + unsigned int stripe_count =3D fs->width / OPE_STRIPE_MAX_W + 1; + + /* In worst case we have ~50 32-bit registers to write */ + return mult_frac(stripe_count * 50 * 4, fps, 1000); +} + +static void ope_adjust_power(struct ope_dev *ope) +{ + unsigned int loadavg =3D 0, loadpeak =3D 0, loadconfig =3D 0; + unsigned long pixclk =3D 0; + struct dev_pm_opp *opp; + struct ope_ctx *ctx; + int ret; + + if (unlikely(!ope_hw_available(ope))) + return; + + scoped_guard(spinlock, &ope->ctx_lock) { + list_for_each_entry(ctx, &ope->ctx_list, list) { + unsigned int fps; + + if (!ctx->started) + continue; + + fps =3D ctx->framerate ? ctx->framerate : DEFAULT_FRAMERATE; + + pixclk +=3D ope_pixclk(&ctx->fmt_in, fps); + loadavg +=3D ope_load_avg(&ctx->fmt_in, fps); + loadavg +=3D ope_load_avg(&ctx->fmt_out, fps); + loadpeak +=3D ope_load_peak(&ctx->fmt_in, fps); + loadpeak +=3D ope_load_peak(&ctx->fmt_out, fps); + loadconfig +=3D ope_load_config(&ctx->fmt_in, fps); + } + } + + /* 30% margin for overhead */ + pixclk =3D mult_frac(pixclk, 13, 10); + + dev_dbg(ope->dev, "adjust power: clk=3D%luHz avg=3D%uKBps peak=3D%uKBps c= fg=3D%uKBps\n", + pixclk, loadavg, loadpeak, loadconfig); + + opp =3D dev_pm_opp_find_freq_ceil(ope->dev, &pixclk); + if (IS_ERR(opp)) + dev_warn(ope->dev, "Requested pixel clock %luHz exceeds hardware limit\n= ", pixclk); + else + dev_pm_opp_put(opp); + + ret =3D dev_pm_opp_set_rate(ope->dev, pixclk); + if (ret) + dev_warn(ope->dev, "Failed to set OPP rate: %d\n", ret); + + ret =3D icc_set_bw(ope->icc_data, loadavg, loadpeak); + if (ret) + dev_warn(ope->dev, "Failed to set data path BW: %d\n", ret); + + ret =3D icc_set_bw(ope->icc_config, loadconfig, loadconfig * 5); + if (ret) + dev_warn(ope->dev, "Failed to set config path BW: %d\n", ret); +} + +static int ope_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct ope_ctx *ctx =3D ope_ctx_from_vq(q); + struct video_device *vdev =3D ope_vdev_from_vq(q); + unsigned int idx =3D ope_idx_from_vq(q); + int ret; + + dev_dbg(ctx->ope->dev, "streaming start ctx=3D%p queue=3D%u\n", ctx, idx); + + if (!ope_hw_available(ctx->ope)) { + ret =3D -ENODEV; + goto err_drain; + } + + ret =3D video_device_pipeline_alloc_start(vdev); + if (ret) + goto err_drain; + + ret =3D pm_runtime_resume_and_get(ctx->ope->dev); + if (ret) { + dev_err(ctx->ope->dev, "resume failed (%d)\n", ret); + goto err_pipeline_stop; + } + + if (idx =3D=3D OPE_QUEUE_FRAME_IN) { + ctx->fmt_in.sequence =3D 0; + ctx->started =3D true; + ope_adjust_power(ctx->ope); + __ope_irq_init(ctx->ope); + } + + ope_try_schedule(ctx); + + return 0; + +err_pipeline_stop: + video_device_pipeline_stop(vdev); +err_drain: + ope_queue_drain(ctx, idx, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void ope_stop_streaming(struct vb2_queue *q) +{ + struct ope_ctx *ctx =3D ope_ctx_from_vq(q); + struct video_device *vdev =3D ope_vdev_from_vq(q); + unsigned int idx =3D ope_idx_from_vq(q); + + dev_dbg(ctx->ope->dev, "streaming stop ctx=3D%p queue=3D%u\n", ctx, idx); + + if (idx =3D=3D OPE_QUEUE_FRAME_IN) { + ctx->started =3D false; + ope_adjust_power(ctx->ope); + } + + /* Drain with the scheduler held off, so no job can pick up a buffer */ + ope_sched_cancel(ctx); + ope_queue_drain(ctx, idx, VB2_BUF_STATE_ERROR); + ope_sched_resume(ctx); + + pm_runtime_put(ctx->ope->dev); + + if (video_device_pipeline(vdev)) + video_device_pipeline_stop(vdev); +} + +static const struct vb2_ops ope_vb2_ops =3D { + .queue_setup =3D ope_queue_setup, + .buf_prepare =3D ope_buf_prepare, + .buf_queue =3D ope_buf_queue, + .start_streaming =3D ope_start_streaming, + .stop_streaming =3D ope_stop_streaming, +}; + +static const unsigned int ope_queue_to_entity[] =3D { + [OPE_QUEUE_FRAME_IN] =3D OPE_ENTITY_FRAME_IN, + [OPE_QUEUE_DISP_OUT] =3D OPE_ENTITY_DISP_OUT, + [OPE_QUEUE_PARAMS] =3D OPE_ENTITY_PARAMS, +}; + +static int ope_init_vq(struct ope_ctx *ctx, unsigned int idx) +{ + struct ope_dev *ope =3D ctx->ope; + struct ope_vq_priv *qpriv; + struct vb2_queue *q =3D &ctx->queues[idx].vq; + int ret; + + qpriv =3D kzalloc_obj(*qpriv); + if (!qpriv) + return -ENOMEM; + + qpriv->ctx =3D ctx; + qpriv->queue_idx =3D idx; + qpriv->vdev =3D camss_isp_pipeline_get_vdev(ope->pipeline, ope_queue_to_e= ntity[idx]); + q->drv_priv =3D qpriv; + q->ops =3D &ope_vb2_ops; + q->lock =3D &ctx->vbq_lock; + q->dev =3D ope->dev; + q->buf_struct_size =3D sizeof(struct camss_isp_buf); + q->timestamp_flags =3D V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->min_queued_buffers =3D (idx =3D=3D OPE_QUEUE_PARAMS) ? 0 : 1; + + if (idx =3D=3D OPE_QUEUE_PARAMS) { + q->type =3D V4L2_BUF_TYPE_META_OUTPUT; + q->mem_ops =3D &vb2_vmalloc_memops; + q->io_modes =3D VB2_MMAP | VB2_USERPTR; + } else if (idx =3D=3D OPE_QUEUE_DISP_OUT) { + q->type =3D V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->mem_ops =3D &vb2_dma_contig_memops; + q->io_modes =3D VB2_MMAP | VB2_DMABUF; + } else { + q->type =3D V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->mem_ops =3D &vb2_dma_contig_memops; + q->io_modes =3D VB2_MMAP | VB2_DMABUF; + } + + ret =3D vb2_queue_init(q); + if (ret) { + q->drv_priv =3D NULL; + kfree(qpriv); + } + + return ret; +} + +static void ope_deinit_vq(struct ope_ctx *ctx, unsigned int idx) +{ + struct vb2_queue *q =3D &ctx->queues[idx].vq; + + vb2_queue_release(q); + q->owner =3D NULL; + kfree(q->drv_priv); + q->drv_priv =3D NULL; +} + +/* -------- Format helpers -------- */ + +static const struct ope_fmt *ope_find_fmt(const struct ope_fmt *fmts, + unsigned int n, u32 fourcc) +{ + for (unsigned int i =3D 0; i < n; i++) + if (fmts[i].fourcc =3D=3D fourcc) + return &fmts[i]; + + return NULL; +} + +static const struct ope_fmt *ope_fmt_try(struct ope_dev *ope, bool is_outp= ut, + struct v4l2_pix_format_mplane *pix) +{ + const struct ope_fmt *fmts =3D is_output ? ope_output_fmts : ope_input_fm= ts; + unsigned int n =3D is_output ? ARRAY_SIZE(ope_output_fmts) : ARRAY_SIZE(o= pe_input_fmts); + unsigned int max_w =3D OPE_MAX_W, max_h =3D OPE_MAX_H; + const struct ope_fmt *fmt; + unsigned int bytesperline; + unsigned int align; + + fmt =3D ope_find_fmt(fmts, n, pix->pixelformat); + if (!fmt) { + fmt =3D &fmts[0]; + pix->pixelformat =3D fmt->fourcc; + } + + v4l_bound_align_image(&pix->width, OPE_MIN_W, max_w, fmt->align, + &pix->height, OPE_MIN_H, max_h, 0, 0); + + pix->num_planes =3D 1; + pix->field =3D V4L2_FIELD_NONE; + if (!pix->colorspace) + pix->colorspace =3D is_output ? V4L2_COLORSPACE_SRGB : V4L2_COLORSPACE_R= AW; + if (is_output) { + pix->ycbcr_enc =3D V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); + pix->quantization =3D V4L2_QUANTIZATION_FULL_RANGE; + } + + /* + * Output formats are semi-planar or grey-scale (Y plane only) always + * using 1 byte per Y value. pix->bytesperline stores the Y-plane bpl. + * Depth tracks the total storage size including the second combined + * Cb + Cr plane which directly follows the Y plane and is used for + * sizeimage calculations rather then for bytesperline. + */ + if (is_output) + bytesperline =3D pix->width; + else + bytesperline =3D pix->width * fmt->depth / 8; + + if (pix->plane_fmt[0].bytesperline > bytesperline) + bytesperline =3D pix->plane_fmt[0].bytesperline; + + /* + * The WE requires the C plane base address to be 16-byte aligned. + * c_base =3D bpl * img_h + (compose_top / c_vsub) * c_stride where + * c_stride =3D bpl * 2 / c_hsub. To guarantee alignment for any + * compose_top, bpl must be a multiple of 16 / c_hsub: + * NV12/NV16 (c_hsub=3D2): bpl must be multiple of 8... but c_stride=3D= bpl + * so we need bpl % 16 =3D=3D 0. + * NV24/NV42 (c_hsub=3D1): c_stride=3Dbpl*2, need bpl*2 % 16 =3D=3D 0, + * so bpl must be a multiple of 8. + * GREY: no C plane, no constraint. + */ + if (is_output && fmt->fourcc !=3D V4L2_PIX_FMT_GREY) + align =3D 8 * fmt->c_hsub; + else + align =3D 1; + + bytesperline =3D min(bytesperline, ALIGN_DOWN(OPE_MAX_STRIDE, align)); + bytesperline =3D ALIGN(bytesperline, align); + + pix->plane_fmt[0].bytesperline =3D bytesperline; + + if (is_output) + pix->plane_fmt[0].sizeimage =3D (u64)bytesperline * pix->height * fmt->d= epth / 8; + else + pix->plane_fmt[0].sizeimage =3D (u64)bytesperline * pix->height; + + return fmt; +} + +/* -------- ioctl helpers/ops -------- */ + +static inline unsigned int ope_queue_idx_from_file(struct file *file) +{ + return (unsigned int)(uintptr_t)video_get_drvdata(video_devdata(file)); +} + +static struct vb2_queue *ope_vq_from_file(struct file *file, struct ope_ct= x *ctx) +{ + unsigned int idx =3D ope_queue_idx_from_file(file); + + if (idx >=3D OPE_QUEUE_COUNT) + return NULL; + + return &ctx->queues[idx].vq; +} + +static struct ope_ctx *ope_ctx_from_file(struct file *file) +{ + struct ope_dev *ope =3D container_of(video_devdata(file)->v4l2_dev, + struct ope_dev, v4l2_dev); + + return ope->shared_ctx; +} + +static int ope_querycap(struct file *file, void *priv, struct v4l2_capabil= ity *cap) +{ + strscpy(cap->driver, OPE_NAME, sizeof(cap->driver)); + strscpy(cap->card, "Qualcomm CAMSS OPE", sizeof(cap->card)); + + return 0; +} + +static int ope_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2= _fmtdesc *f) +{ + unsigned int i, n =3D 0; + + for (i =3D 0; i < ARRAY_SIZE(ope_input_fmts); i++) { + if (f->mbus_code && ope_input_fmts[i].mbus_code !=3D f->mbus_code) + continue; + if (n++ =3D=3D f->index) { + f->pixelformat =3D ope_input_fmts[i].fourcc; + return 0; + } + } + + return -EINVAL; +} + +static int ope_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_fo= rmat *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct ope_fmt_state *fs =3D &ctx->fmt_in; + struct v4l2_pix_format_mplane *pix =3D &f->fmt.pix_mp; + + pix->pixelformat =3D fs->fmt->fourcc; + pix->width =3D fs->width; + pix->height =3D fs->height; + pix->num_planes =3D 1; + pix->field =3D V4L2_FIELD_NONE; + pix->colorspace =3D fs->colorspace; + pix->xfer_func =3D fs->xfer_func; + pix->ycbcr_enc =3D fs->ycbcr_enc; + pix->quantization =3D fs->quantization; + pix->plane_fmt[0].bytesperline =3D fs->bytesperline; + pix->plane_fmt[0].sizeimage =3D fs->sizeimage; + + return 0; +} + +static int ope_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_= format *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + + ope_fmt_try(ctx->ope, false, &f->fmt.pix_mp); + + return 0; +} + +static int ope_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_fo= rmat *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + const struct ope_fmt *fmt; + + if (vb2_is_busy(&ctx->queues[OPE_QUEUE_FRAME_IN].vq)) + return -EBUSY; + + fmt =3D ope_fmt_try(ctx->ope, false, &f->fmt.pix_mp); + ctx->fmt_in.fmt =3D fmt; + ctx->fmt_in.width =3D f->fmt.pix_mp.width; + ctx->fmt_in.height =3D f->fmt.pix_mp.height; + ctx->fmt_in.bytesperline =3D f->fmt.pix_mp.plane_fmt[0].bytesperline; + ctx->fmt_in.sizeimage =3D f->fmt.pix_mp.plane_fmt[0].sizeimage; + ctx->fmt_in.colorspace =3D f->fmt.pix_mp.colorspace; + ctx->fmt_in.xfer_func =3D f->fmt.pix_mp.xfer_func; + ctx->fmt_in.ycbcr_enc =3D f->fmt.pix_mp.ycbcr_enc; + ctx->fmt_in.quantization =3D f->fmt.pix_mp.quantization; + + return 0; +} + +static int ope_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2= _fmtdesc *f) +{ + unsigned int i, n =3D 0; + + for (i =3D 0; i < ARRAY_SIZE(ope_output_fmts); i++) { + if (f->mbus_code && ope_output_fmts[i].mbus_code !=3D f->mbus_code) + continue; + if (n++ =3D=3D f->index) { + f->pixelformat =3D ope_output_fmts[i].fourcc; + return 0; + } + } + + return -EINVAL; +} + +static int ope_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fo= rmat *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct ope_fmt_state *fs =3D &ctx->fmt_out; + struct v4l2_pix_format_mplane *pix =3D &f->fmt.pix_mp; + + pix->pixelformat =3D fs->fmt->fourcc; + pix->width =3D fs->width; + pix->height =3D fs->height; + pix->num_planes =3D 1; + pix->field =3D V4L2_FIELD_NONE; + pix->colorspace =3D fs->colorspace; + pix->xfer_func =3D fs->xfer_func; + pix->ycbcr_enc =3D fs->ycbcr_enc; + pix->quantization =3D fs->quantization; + pix->plane_fmt[0].bytesperline =3D fs->bytesperline; + pix->plane_fmt[0].sizeimage =3D fs->sizeimage; + + return 0; +} + +static int ope_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_= format *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + + ope_fmt_try(ctx->ope, true, &f->fmt.pix_mp); + + return 0; +} + +static int ope_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fo= rmat *f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + const struct ope_fmt *fmt; + + if (vb2_is_busy(&ctx->queues[OPE_QUEUE_DISP_OUT].vq)) + return -EBUSY; + + fmt =3D ope_fmt_try(ctx->ope, true, &f->fmt.pix_mp); + + ctx->fmt_out.fmt =3D fmt; + ctx->fmt_out.width =3D f->fmt.pix_mp.width; + ctx->fmt_out.height =3D f->fmt.pix_mp.height; + ctx->fmt_out.bytesperline =3D f->fmt.pix_mp.plane_fmt[0].bytesperline; + ctx->fmt_out.sizeimage =3D f->fmt.pix_mp.plane_fmt[0].sizeimage; + ctx->fmt_out.colorspace =3D f->fmt.pix_mp.colorspace; + ctx->fmt_out.xfer_func =3D f->fmt.pix_mp.xfer_func; + ctx->fmt_out.ycbcr_enc =3D f->fmt.pix_mp.ycbcr_enc; + ctx->fmt_out.quantization =3D f->fmt.pix_mp.quantization; + + return 0; +} + +static int ope_g_fmt_meta(struct file *file, void *priv, struct v4l2_forma= t *f) +{ + f->fmt.meta.dataformat =3D V4L2_META_FMT_QCOM_ISP_PARAMS; + f->fmt.meta.buffersize =3D v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYL= OAD); + + return 0; +} + +static int ope_enum_fmt_meta_out(struct file *file, void *priv, struct v4l= 2_fmtdesc *f) +{ + if (f->index > 0) + return -EINVAL; + + f->pixelformat =3D V4L2_META_FMT_QCOM_ISP_PARAMS; + + return 0; +} + +static int ope_g_parm(struct file *file, void *priv, struct v4l2_streampar= m *sp) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + + if (!V4L2_TYPE_IS_OUTPUT(sp->type)) + return -EINVAL; + + sp->parm.output.capability =3D V4L2_CAP_TIMEPERFRAME; + sp->parm.output.timeperframe =3D ctx->fmt_in.timeperframe; + + return 0; +} + +static int ope_s_parm(struct file *file, void *priv, struct v4l2_streampar= m *sp) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct v4l2_fract *tpf =3D &sp->parm.output.timeperframe; + + if (!V4L2_TYPE_IS_OUTPUT(sp->type)) + return -EINVAL; + + if (vb2_is_busy(&ctx->queues[OPE_QUEUE_FRAME_IN].vq)) + return -EBUSY; + + if (!tpf->denominator) + tpf->denominator =3D 1; + if (!tpf->numerator) + tpf->numerator =3D 1; + + ctx->framerate =3D clamp(tpf->denominator / tpf->numerator, 1U, (u32)OPE_= MAX_FRAMERATE); + tpf->numerator =3D 1; + tpf->denominator =3D ctx->framerate; + + ctx->fmt_in.timeperframe =3D *tpf; + sp->parm.output.capability =3D V4L2_CAP_TIMEPERFRAME; + + ope_adjust_power(ctx->ope); + + return 0; +} + +static int ope_enum_framesizes(struct file *file, void *priv, struct v4l2_= frmsizeenum *fsize) +{ + unsigned int idx =3D ope_queue_idx_from_file(file); + const struct ope_fmt *fmts; + unsigned int n; + + if (idx =3D=3D OPE_QUEUE_FRAME_IN) { + fmts =3D ope_input_fmts; + n =3D ARRAY_SIZE(ope_input_fmts); + } else { + fmts =3D ope_output_fmts; + n =3D ARRAY_SIZE(ope_output_fmts); + } + + if (fsize->index > 0 || !ope_find_fmt(fmts, n, fsize->pixel_format)) + return -EINVAL; + + fsize->type =3D V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width =3D OPE_MIN_W; + fsize->stepwise.max_width =3D OPE_MAX_W; + fsize->stepwise.step_width =3D 1; + fsize->stepwise.min_height =3D OPE_MIN_H; + fsize->stepwise.max_height =3D OPE_MAX_H; + fsize->stepwise.step_height =3D 1; + + return 0; +} + +static int ope_reqbufs(struct file *file, void *priv, struct v4l2_requestb= uffers *rb) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + int ret; + + if (!vq) + return -EINVAL; + + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + ret =3D vb2_reqbufs(vq, rb); + if (!ret) + vq->owner =3D rb->count ? file->private_data : NULL; + + return ret; +} + +static int ope_querybuf(struct file *file, void *priv, struct v4l2_buffer = *buf) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + return vq ? vb2_querybuf(vq, buf) : -EINVAL; +} + +static int ope_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct video_device *vdev =3D video_devdata(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + if (!vq) + return -EINVAL; + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + return vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf); +} + +static int ope_dqbuf(struct file *file, void *priv, struct v4l2_buffer *bu= f) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + return vq ? vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK) : -EINVAL; +} + +static int ope_prepare_buf(struct file *file, void *priv, struct v4l2_buff= er *buf) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct video_device *vdev =3D video_devdata(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + if (!vq) + return -EINVAL; + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + return vb2_prepare_buf(vq, vdev->v4l2_dev->mdev, buf); +} + +static int ope_create_bufs(struct file *file, void *priv, struct v4l2_crea= te_buffers *create) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + int ret; + + if (!vq) + return -EINVAL; + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + ret =3D vb2_create_bufs(vq, create); + if (!ret && create->count) + vq->owner =3D file->private_data; + + return ret; +} + +static int ope_expbuf(struct file *file, void *priv, struct v4l2_exportbuf= fer *eb) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + if (!vq) + return -EINVAL; + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + return vb2_expbuf(vq, eb); +} + +static int ope_streamon(struct file *file, void *priv, enum v4l2_buf_type = type) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + if (!vq) + return -EINVAL; + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + return vb2_streamon(vq, type); +} + +static int ope_streamoff(struct file *file, void *priv, enum v4l2_buf_type= type) +{ + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct vb2_queue *vq =3D ope_vq_from_file(file, ctx); + + if (!vq) + return -EINVAL; + + if (vb2_queue_is_busy(vq, file)) + return -EBUSY; + + return vb2_streamoff(vq, type); +} + +/* -------- proc subdev ops -------- */ + +static const struct v4l2_rect ope_sd_min_rect =3D { + .width =3D OPE_MIN_W, + .height =3D OPE_MIN_H, +}; + +static const struct ope_fmt *ope_fmt_from_mbus_code(const struct ope_fmt *= fmts, + unsigned int num_fmts, u32 code) +{ + for (unsigned int i =3D 0; i < num_fmts; i++) + if (fmts[i].mbus_code =3D=3D code) + return &fmts[i]; + + return NULL; +} + +static void ope_sd_adjust_crop_rect(struct v4l2_rect *crop, const struct v= 4l2_rect *bounds, + unsigned int halign, unsigned int valign) +{ + v4l2_rect_set_min_size(crop, &ope_sd_min_rect); + v4l2_rect_map_inside(crop, bounds); + + crop->width =3D ALIGN_DOWN(crop->width, halign); + crop->height =3D ALIGN_DOWN(crop->height, valign); + crop->left =3D ALIGN_DOWN(crop->left, halign); + crop->top =3D ALIGN_DOWN(crop->top, valign); +} + +static void ope_sd_adjust_crop(struct v4l2_rect *crop, const struct v4l2_m= bus_framefmt *bounds) +{ + struct v4l2_rect crop_bounds =3D { + .left =3D 0, .top =3D 0, + .width =3D bounds->width, .height =3D bounds->height, + }; + const struct ope_fmt *fmt; + unsigned int halign =3D 2; + + /* Source packing unit, at least a Bayer pair */ + fmt =3D ope_fmt_from_mbus_code(ope_input_fmts, ARRAY_SIZE(ope_input_fmts)= , bounds->code); + if (fmt) + halign =3D max(2u, 1u << fmt->align); + + ope_sd_adjust_crop_rect(crop, &crop_bounds, halign, 2); +} + +static void ope_proc_adjust_src_compose(struct v4l2_subdev_state *state, s= truct v4l2_rect *compose) +{ + const struct v4l2_rect *sink_crop =3D + v4l2_subdev_state_get_crop(state, OPE_PROC_PAD_SINK_IN); + const struct v4l2_mbus_framefmt *src_fmt =3D + v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SOURCE); + unsigned int halign =3D 1, valign =3D 1; + const struct ope_fmt *fmt; + struct v4l2_rect bounds; + + fmt =3D ope_fmt_from_mbus_code(ope_output_fmts, ARRAY_SIZE(ope_output_fmt= s), + src_fmt->code); + if (fmt) { + halign =3D fmt->c_hsub; + valign =3D fmt->c_vsub; + } + + bounds =3D (struct v4l2_rect){ 0, 0, sink_crop->width, sink_crop->height = }; + ope_sd_adjust_crop_rect(compose, &bounds, halign, valign); +} + +static void ope_proc_set_src_fmt(struct v4l2_subdev_state *state, + struct v4l2_mbus_framefmt *format) +{ + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_rect *compose; + const struct ope_fmt *fmt; + + src_fmt =3D v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SOURCE); + compose =3D v4l2_subdev_state_get_compose(state, OPE_PROC_PAD_SOURCE); + + fmt =3D ope_fmt_from_mbus_code(ope_output_fmts, ARRAY_SIZE(ope_output_fmt= s), format->code); + src_fmt->code =3D fmt ? fmt->mbus_code : MEDIA_BUS_FMT_YUYV8_1_5X8; + + ope_proc_adjust_src_compose(state, compose); + + src_fmt->width =3D compose->width; + src_fmt->height =3D compose->height; + src_fmt->field =3D V4L2_FIELD_NONE; + src_fmt->colorspace =3D V4L2_COLORSPACE_SRGB; + *format =3D *src_fmt; +} + +static void ope_proc_set_src_compose(struct v4l2_subdev_state *state, stru= ct v4l2_rect *r) +{ + struct v4l2_rect *compose =3D v4l2_subdev_state_get_compose(state, OPE_PR= OC_PAD_SOURCE); + + *compose =3D *r; + ope_proc_adjust_src_compose(state, compose); + *r =3D *compose; + + /* Propagate to out format */ + ope_proc_set_src_fmt(state, v4l2_subdev_state_get_format(state, OPE_PROC_= PAD_SOURCE)); +} + +static void ope_proc_set_sink_crop(struct v4l2_subdev_state *state, struct= v4l2_rect *r) +{ + struct v4l2_rect *crop; + + crop =3D v4l2_subdev_state_get_crop(state, OPE_PROC_PAD_SINK_IN); + + *crop =3D *r; + ope_sd_adjust_crop(crop, v4l2_subdev_state_get_format(state, OPE_PROC_PAD= _SINK_IN)); + *r =3D *crop; + + /* Propagate to out format */ + ope_proc_set_src_compose(state, v4l2_subdev_state_get_compose(state, OPE_= PROC_PAD_SOURCE)); +} + +static void ope_proc_set_sink_fmt(struct v4l2_subdev_state *state, + struct v4l2_mbus_framefmt *format) +{ + struct v4l2_mbus_framefmt *sink_fmt; + const struct ope_fmt *fmt; + struct v4l2_rect *crop; + + sink_fmt =3D v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SINK_IN); + crop =3D v4l2_subdev_state_get_crop(state, OPE_PROC_PAD_SINK_IN); + + fmt =3D ope_fmt_from_mbus_code(ope_input_fmts, ARRAY_SIZE(ope_input_fmts)= , format->code); + sink_fmt->code =3D fmt ? fmt->mbus_code : ope_input_fmts[0].mbus_code; + + sink_fmt->width =3D clamp(format->width, (u32)OPE_MIN_W, (u32)OPE_MAX_W); + sink_fmt->height =3D clamp(format->height, (u32)OPE_MIN_H, (u32)OPE_MAX_H= ); + sink_fmt->field =3D V4L2_FIELD_NONE; + sink_fmt->colorspace =3D V4L2_COLORSPACE_RAW; + *format =3D *sink_fmt; + + /* Propagate to in crop */ + ope_proc_set_sink_crop(state, crop); +} + +static int ope_proc_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt fmt =3D { + .width =3D OPE_MIN_W, + .height =3D OPE_MIN_H, + .code =3D MEDIA_BUS_FMT_SRGGB8_1X8, + }; + + /* Params sink: fixed format, width carries the payload size in bytes */ + *v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SINK_PAR) =3D + (struct v4l2_mbus_framefmt){ + .code =3D MEDIA_BUS_FMT_FIXED, + .width =3D v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYLOAD), + .height =3D 1, + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_DEFAULT, + }; + + /* Initialise source compose default before cascade */ + *v4l2_subdev_state_get_compose(state, OPE_PROC_PAD_SOURCE) =3D + (struct v4l2_rect){ 0, 0, OPE_MIN_W, OPE_MIN_H }; + v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SOURCE)->code =3D + MEDIA_BUS_FMT_YUYV8_1_5X8; + + /* Drive the full cascade from sink-in fmt */ + ope_proc_set_sink_fmt(state, &fmt); + + return 0; +} + +static bool ope_state_is_busy(struct v4l2_subdev *sd, struct v4l2_subdev_s= tate *state) +{ + struct ope_dev *ope =3D container_of(sd->v4l2_dev, struct ope_dev, v4l2_d= ev); + struct ope_ctx *ctx; + bool busy =3D false; + + if (state !=3D sd->active_state) + return false; + + scoped_guard(spinlock, &ope->ctx_lock) + list_for_each_entry(ctx, &ope->ctx_list, list) + busy |=3D ctx->started; + + return busy; +} + +static int ope_proc_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + if (fmt->pad =3D=3D OPE_PROC_PAD_SINK_PAR) + return v4l2_subdev_get_fmt(sd, state, fmt); + + if (ope_state_is_busy(sd, state)) + return -EBUSY; + + if (fmt->pad =3D=3D OPE_PROC_PAD_SINK_IN) { + ope_proc_set_sink_fmt(state, &fmt->format); + return 0; + } + + ope_proc_set_src_fmt(state, &fmt->format); + + return 0; +} + +static int ope_proc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct ope_fmt *fmts; + unsigned int nfmts; + unsigned int n =3D 0; + + if (code->pad =3D=3D OPE_PROC_PAD_SINK_PAR) { + if (code->index) + return -EINVAL; + code->code =3D MEDIA_BUS_FMT_FIXED; + return 0; + } + + if (code->pad =3D=3D OPE_PROC_PAD_SOURCE) { + fmts =3D ope_output_fmts; + nfmts =3D ARRAY_SIZE(ope_output_fmts); + } else { + fmts =3D ope_input_fmts; + nfmts =3D ARRAY_SIZE(ope_input_fmts); + } + + for (unsigned int i =3D 0; i < nfmts; i++) { + u32 mc =3D fmts[i].mbus_code; + bool seen =3D false; + + for (unsigned int j =3D 0; j < i; j++) { + if (fmts[j].mbus_code =3D=3D mc) { + seen =3D true; + break; + } + } + if (!seen && n++ =3D=3D code->index) { + code->code =3D mc; + return 0; + } + } + + return -EINVAL; +} + +static int ope_proc_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->pad =3D=3D OPE_PROC_PAD_SINK_IN) { + const struct v4l2_mbus_framefmt *sink_fmt =3D + v4l2_subdev_state_get_format(state, OPE_PROC_PAD_SINK_IN); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r =3D *v4l2_subdev_state_get_crop(state, OPE_PROC_PAD_SINK_IN); + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r =3D (struct v4l2_rect){ 0, 0, sink_fmt->width, sink_fmt->height = }; + return 0; + default: + return -EINVAL; + } + } + + if (sel->pad =3D=3D OPE_PROC_PAD_SOURCE) { + const struct v4l2_rect *crop =3D + v4l2_subdev_state_get_crop(state, OPE_PROC_PAD_SINK_IN); + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE: + sel->r =3D *v4l2_subdev_state_get_compose(state, OPE_PROC_PAD_SOURCE); + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r =3D *crop; + return 0; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static int ope_proc_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (ope_state_is_busy(sd, state)) + return -EBUSY; + + if (sel->pad =3D=3D OPE_PROC_PAD_SINK_IN) { + if (sel->target !=3D V4L2_SEL_TGT_CROP) + return -EINVAL; + ope_proc_set_sink_crop(state, &sel->r); + return 0; + } + + if (sel->pad =3D=3D OPE_PROC_PAD_SOURCE) { + if (sel->target !=3D V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + ope_proc_set_src_compose(state, &sel->r); + return 0; + } + + return -EINVAL; +} + +static const struct v4l2_subdev_pad_ops ope_proc_pad_ops =3D { + .get_fmt =3D v4l2_subdev_get_fmt, + .set_fmt =3D ope_proc_set_fmt, + .enum_mbus_code =3D ope_proc_enum_mbus_code, + .get_selection =3D ope_proc_get_selection, + .set_selection =3D ope_proc_set_selection, +}; + +static const struct v4l2_subdev_internal_ops ope_proc_internal_ops =3D { + .init_state =3D ope_proc_init_state, +}; + +static const struct v4l2_subdev_ops ope_proc_ops =3D { + .pad =3D &ope_proc_pad_ops, +}; + +/* -------- disp subdev ops -------- */ + +static int ope_disp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *pad_fmt; + u32 code =3D fmt->format.code; + + /* The disp subdev is pass-through: the source pad always mirrors the + * sink pad, so source format is read-only and derived from the sink. + */ + if (fmt->pad =3D=3D OPE_DISP_PAD_SOURCE) + return v4l2_subdev_get_fmt(sd, state, fmt); + + if (ope_state_is_busy(sd, state)) + return -EBUSY; + + fmt->format.code =3D MEDIA_BUS_FMT_YUYV8_1_5X8; + for (unsigned int i =3D 0; i < ARRAY_SIZE(ope_output_fmts); i++) { + if (ope_output_fmts[i].mbus_code =3D=3D code) { + fmt->format.code =3D code; + break; + } + } + + v4l_bound_align_image(&fmt->format.width, OPE_MIN_W, OPE_MAX_W, 0, + &fmt->format.height, OPE_MIN_H, OPE_MAX_H, 0, 0); + fmt->format.field =3D V4L2_FIELD_NONE; + fmt->format.colorspace =3D V4L2_COLORSPACE_SRGB; + + pad_fmt =3D v4l2_subdev_state_get_format(state, fmt->pad); + *pad_fmt =3D fmt->format; + + /* Propagate to source */ + *v4l2_subdev_state_get_format(state, OPE_DISP_PAD_SOURCE) =3D fmt->format; + + return 0; +} + +static int ope_disp_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt def =3D { + .width =3D OPE_MIN_W, + .height =3D OPE_MIN_H, + .code =3D MEDIA_BUS_FMT_YUYV8_1_5X8, + .field =3D V4L2_FIELD_NONE, + .colorspace =3D V4L2_COLORSPACE_SRGB, + }; + + *v4l2_subdev_state_get_format(state, OPE_DISP_PAD_SINK) =3D def; + *v4l2_subdev_state_get_format(state, OPE_DISP_PAD_SOURCE) =3D def; + return 0; +} + +static const struct v4l2_subdev_pad_ops ope_disp_pad_ops =3D { + .get_fmt =3D v4l2_subdev_get_fmt, + .set_fmt =3D ope_disp_set_fmt, + .link_validate =3D v4l2_subdev_link_validate_default, +}; + +static const struct media_entity_operations ope_disp_entity_ops =3D { + .link_validate =3D v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops ope_disp_internal_ops =3D { + .init_state =3D ope_disp_init_state, +}; + +static const struct v4l2_subdev_ops ope_disp_ops =3D { + .pad =3D &ope_disp_pad_ops, +}; + +/* -------- disp-output video ops -------- */ + +static int ope_disp_output_link_validate(struct media_link *link) +{ + struct video_device *vdev =3D media_entity_to_video_device(link->sink->en= tity); + struct v4l2_subdev *sd =3D media_entity_to_v4l2_subdev(link->source->enti= ty); + struct ope_dev *ope =3D container_of(vdev->v4l2_dev, struct ope_dev, v4l2= _dev); + struct ope_ctx *ctx =3D ope->shared_ctx; + struct v4l2_subdev_state *sd_state; + struct v4l2_subdev_format sd_fmt =3D { + .which =3D V4L2_SUBDEV_FORMAT_ACTIVE, + .pad =3D link->source->index, + }; + int ret; + + if (!ctx) + return 0; + + sd_state =3D v4l2_subdev_lock_and_get_active_state(sd); + ret =3D v4l2_subdev_call(sd, pad, get_fmt, sd_state, &sd_fmt); + v4l2_subdev_unlock_state(sd_state); + if (ret) + return ret; + + if (ctx->fmt_out.fmt->mbus_code !=3D sd_fmt.format.code) { + dev_dbg(ctx->ope->dev, "link validate: mbus 0x%04x incompatible with %p4= cc\n", + sd_fmt.format.code, &ctx->fmt_out.fmt->fourcc); + return -EPIPE; + } + + if (sd_fmt.format.width > ctx->fmt_out.width || + sd_fmt.format.height > ctx->fmt_out.height) { + dev_dbg(ctx->ope->dev, + "link validate: compose %ux%u exceeds output buffer %ux%u\n", + sd_fmt.format.width, sd_fmt.format.height, + ctx->fmt_out.width, ctx->fmt_out.height); + return -EPIPE; + } + + /* Check compose rect (including offset) fits within output buffer */ + { + struct v4l2_subdev *proc_sd =3D + camss_isp_pipeline_get_subdev(ctx->ope->pipeline, + OPE_ENTITY_PROC); + struct v4l2_subdev_state *proc_state =3D + v4l2_subdev_lock_and_get_active_state(proc_sd); + const struct v4l2_rect *compose =3D + v4l2_subdev_state_get_compose(proc_state, + OPE_PROC_PAD_SOURCE); + + if (compose->left + compose->width > ctx->fmt_out.width || + compose->top + compose->height > ctx->fmt_out.height) { + dev_dbg(ctx->ope->dev, + "link: compose %ux%u+%u+%u overflows output buffer %ux%u\n", + compose->width, compose->height, + compose->left, compose->top, + ctx->fmt_out.width, ctx->fmt_out.height); + v4l2_subdev_unlock_state(proc_state); + return -EPIPE; + } + v4l2_subdev_unlock_state(proc_state); + } + + return 0; +} + +static const struct media_entity_operations ope_disp_output_entity_ops =3D= { + .link_validate =3D ope_disp_output_link_validate, +}; + +static int ope_input_link_validate(struct media_link *link) +{ + struct video_device *vdev =3D media_entity_to_video_device(link->source->= entity); + struct v4l2_subdev *sd =3D media_entity_to_v4l2_subdev(link->sink->entity= ); + struct ope_dev *ope =3D container_of(vdev->v4l2_dev, struct ope_dev, v4l2= _dev); + struct ope_ctx *ctx =3D ope->shared_ctx; + struct v4l2_subdev_state *sd_state; + struct v4l2_subdev_format sd_fmt =3D { + .which =3D V4L2_SUBDEV_FORMAT_ACTIVE, + .pad =3D link->sink->index, + }; + int ret; + + if (!ctx) + return 0; + + sd_state =3D v4l2_subdev_lock_and_get_active_state(sd); + ret =3D v4l2_subdev_call(sd, pad, get_fmt, sd_state, &sd_fmt); + v4l2_subdev_unlock_state(sd_state); + if (ret) + return ret; + + if (ctx->fmt_in.fmt->mbus_code !=3D sd_fmt.format.code || + ctx->fmt_in.width !=3D sd_fmt.format.width || + ctx->fmt_in.height !=3D sd_fmt.format.height) { + dev_dbg(ctx->ope->dev, + "link validate: input %dx%d/0x%04x !=3D pad %dx%d/0x%04x\n", + ctx->fmt_in.width, ctx->fmt_in.height, + ctx->fmt_in.fmt->mbus_code, + sd_fmt.format.width, sd_fmt.format.height, + sd_fmt.format.code); + return -EPIPE; + } + + return 0; +} + +static const struct media_entity_operations ope_input_entity_ops =3D { + .link_validate =3D ope_input_link_validate, +}; + +static const struct v4l2_ioctl_ops ope_video_ioctl_ops =3D { + .vidioc_querycap =3D ope_querycap, + .vidioc_enum_fmt_vid_out =3D ope_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out_mplane =3D ope_g_fmt_vid_out, + .vidioc_try_fmt_vid_out_mplane =3D ope_try_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane =3D ope_s_fmt_vid_out, + .vidioc_enum_fmt_vid_cap =3D ope_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane =3D ope_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane =3D ope_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane =3D ope_s_fmt_vid_cap, + .vidioc_enum_framesizes =3D ope_enum_framesizes, + .vidioc_g_parm =3D ope_g_parm, + .vidioc_s_parm =3D ope_s_parm, + .vidioc_reqbufs =3D ope_reqbufs, + .vidioc_querybuf =3D ope_querybuf, + .vidioc_qbuf =3D ope_qbuf, + .vidioc_dqbuf =3D ope_dqbuf, + .vidioc_prepare_buf =3D ope_prepare_buf, + .vidioc_create_bufs =3D ope_create_bufs, + .vidioc_expbuf =3D ope_expbuf, + .vidioc_streamon =3D ope_streamon, + .vidioc_streamoff =3D ope_streamoff, + .vidioc_subscribe_event =3D v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event =3D v4l2_event_unsubscribe, +}; + +static const struct v4l2_ioctl_ops ope_meta_ioctl_ops =3D { + .vidioc_querycap =3D ope_querycap, + .vidioc_enum_fmt_meta_out =3D ope_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out =3D ope_g_fmt_meta, + .vidioc_s_fmt_meta_out =3D ope_g_fmt_meta, + .vidioc_try_fmt_meta_out =3D ope_g_fmt_meta, + .vidioc_reqbufs =3D ope_reqbufs, + .vidioc_querybuf =3D ope_querybuf, + .vidioc_qbuf =3D ope_qbuf, + .vidioc_dqbuf =3D ope_dqbuf, + .vidioc_prepare_buf =3D ope_prepare_buf, + .vidioc_create_bufs =3D ope_create_bufs, + .vidioc_expbuf =3D ope_expbuf, + .vidioc_streamon =3D ope_streamon, + .vidioc_streamoff =3D ope_streamoff, +}; + +/* -------- File/Context ops -------- */ + +static struct ope_ctx *ope_ctx_create(struct ope_dev *ope) +{ + struct v4l2_pix_format_mplane pix_in =3D { .pixelformat =3D ope_input_fmt= s[0].fourcc }; + struct v4l2_pix_format_mplane pix_out =3D { .pixelformat =3D ope_output_f= mts[0].fourcc }; + struct ope_ctx *ctx; + unsigned int i; + int ret; + + lockdep_assert_held(&ope->mutex); + + ctx =3D kvzalloc_obj(*ctx); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->ope =3D ope; + + mutex_init(&ctx->vbq_lock); + + ctx->params_buf =3D kvzalloc(v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PA= YLOAD), + GFP_KERNEL); + if (!ctx->params_buf) { + ret =3D -ENOMEM; + goto err_destroy_lock; + } + + ctx->config =3D ope_default_config; + + ctx->fmt_in.fmt =3D ope_fmt_try(ope, false, &pix_in); + ctx->fmt_in.width =3D pix_in.width; + ctx->fmt_in.height =3D pix_in.height; + ctx->fmt_in.bytesperline =3D pix_in.plane_fmt[0].bytesperline; + ctx->fmt_in.sizeimage =3D pix_in.plane_fmt[0].sizeimage; + ctx->fmt_in.colorspace =3D pix_in.colorspace; + ctx->fmt_in.xfer_func =3D pix_in.xfer_func; + ctx->fmt_in.ycbcr_enc =3D pix_in.ycbcr_enc; + ctx->fmt_in.quantization =3D pix_in.quantization; + ctx->fmt_in.timeperframe.numerator =3D 1; + ctx->fmt_in.timeperframe.denominator =3D DEFAULT_FRAMERATE; + + ctx->fmt_out.fmt =3D ope_fmt_try(ope, true, &pix_out); + ctx->fmt_out.width =3D pix_out.width; + ctx->fmt_out.height =3D pix_out.height; + ctx->fmt_out.bytesperline =3D pix_out.plane_fmt[0].bytesperline; + ctx->fmt_out.sizeimage =3D pix_out.plane_fmt[0].sizeimage; + ctx->fmt_out.colorspace =3D pix_out.colorspace; + ctx->fmt_out.xfer_func =3D pix_out.xfer_func; + ctx->fmt_out.ycbcr_enc =3D pix_out.ycbcr_enc; + ctx->fmt_out.quantization =3D pix_out.quantization; + + for (i =3D 0; i < OPE_QUEUE_COUNT; i++) { + INIT_LIST_HEAD(&ctx->queues[i].rdy_queue); + spin_lock_init(&ctx->queues[i].rdy_spinlock); + ret =3D ope_init_vq(ctx, i); + if (ret) + goto err_release_vq; + } + + INIT_LIST_HEAD(&ctx->list); + + scoped_guard(spinlock, &ope->ctx_lock) + list_add(&ctx->list, &ope->ctx_list); + + ope->shared_ctx =3D ctx; + + return ctx; + +err_release_vq: + while (i--) + ope_deinit_vq(ctx, i); + kvfree(ctx->params_buf); +err_destroy_lock: + mutex_destroy(&ctx->vbq_lock); + kvfree(ctx); + return ERR_PTR(ret); +} + +static void ope_queues_release(struct ope_ctx *ctx, struct v4l2_fh *fh) +{ + bool owned =3D false; + + for (unsigned int i =3D 0; i < OPE_QUEUE_COUNT; i++) + owned |=3D (ctx->queues[i].vq.owner =3D=3D fh); + + if (!owned) + return; + + ope_sched_cancel(ctx); + + for (unsigned int i =3D 0; i < OPE_QUEUE_COUNT; i++) { + struct vb2_queue *vq =3D &ctx->queues[i].vq; + + if (vq->owner !=3D fh) + continue; + + vb2_queue_release(vq); + vq->owner =3D NULL; + } + + ope_sched_resume(ctx); +} + +static void ope_ctx_destroy(struct ope_ctx *ctx) +{ + ctx->started =3D false; + + ope_sched_cancel(ctx); + + for (unsigned int i =3D 0; i < OPE_QUEUE_COUNT; i++) + ope_deinit_vq(ctx, i); + + ope_sched_resume(ctx); + + /* Do not leave the LUT cache pointing at a context about to be freed */ + ope_glut_cache_invalidate(ctx->ope); + + kvfree(ctx->params_buf); + mutex_destroy(&ctx->vbq_lock); + kvfree(ctx); +} + +static int ope_open(struct file *file) +{ + struct video_device *vdev =3D video_devdata(file); + struct ope_dev *ope =3D container_of(vdev->v4l2_dev, struct ope_dev, v4l2= _dev); + struct v4l2_fh *fh; + int ret =3D 0; + + fh =3D kzalloc_obj(*fh); + if (!fh) + return -ENOMEM; + + if (mutex_lock_interruptible(&ope->mutex)) { + kfree(fh); + return -ERESTARTSYS; + } + + v4l2_fh_init(fh, vdev); + v4l2_fh_add(fh, file); + + /* + * For now, only a single shared context is supported, + * until media multi-context support is available. + */ + if (!ope->shared_ctx) { + struct ope_ctx *ctx =3D ope_ctx_create(ope); + + if (IS_ERR(ctx)) { + ret =3D PTR_ERR(ctx); + goto err_fh_del; + } + } + + ope->open_count++; + mutex_unlock(&ope->mutex); + + return 0; + +err_fh_del: + v4l2_fh_del(fh, file); + v4l2_fh_exit(fh); + mutex_unlock(&ope->mutex); + kfree(fh); + return ret; +} + +static int ope_release(struct file *file) +{ + struct video_device *vdev =3D video_devdata(file); + struct v4l2_fh *fh =3D file_to_v4l2_fh(file); + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct ope_dev *ope =3D ctx->ope; + + scoped_guard(mutex, vdev->lock) + ope_queues_release(ctx, fh); + + v4l2_fh_del(fh, file); + v4l2_fh_exit(fh); + kfree(fh); + + scoped_guard(mutex, &ope->mutex) { + if (--ope->open_count !=3D 0) + return 0; + ope->shared_ctx =3D NULL; + scoped_guard(spinlock, &ope->ctx_lock) + list_del(&ctx->list); + } + + ope_ctx_destroy(ctx); + + return 0; +} + +static __poll_t ope_poll(struct file *file, poll_table *wait) +{ + unsigned int idx =3D ope_queue_idx_from_file(file); + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + struct v4l2_fh *fh =3D file_to_v4l2_fh(file); + struct vb2_queue *vq; + unsigned long flags; + __poll_t rc =3D 0; + + if (idx >=3D OPE_QUEUE_COUNT) + return EPOLLERR; + + vq =3D &ctx->queues[idx].vq; + + poll_wait(file, &vq->done_wq, wait); + poll_wait(file, &fh->wait, wait); + + spin_lock_irqsave(&vq->done_lock, flags); + if (!list_empty(&vq->done_list)) { + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + rc |=3D EPOLLOUT | EPOLLWRNORM; + else + rc |=3D EPOLLIN | EPOLLRDNORM; + } + spin_unlock_irqrestore(&vq->done_lock, flags); + + if (v4l2_event_pending(fh)) + rc |=3D EPOLLPRI; + + return rc; +} + +static int ope_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned int idx =3D ope_queue_idx_from_file(file); + struct ope_ctx *ctx =3D ope_ctx_from_file(file); + + if (idx >=3D OPE_QUEUE_COUNT) + return -EINVAL; + + return vb2_mmap(&ctx->queues[idx].vq, vma); +} + +static const struct v4l2_file_operations ope_fops =3D { + .owner =3D THIS_MODULE, + .open =3D ope_open, + .release =3D ope_release, + .poll =3D ope_poll, + .unlocked_ioctl =3D video_ioctl2, + .mmap =3D ope_mmap, +}; + +/* Pipeline descriptor */ +static const struct camss_isp_entity_desc ope_entity_descs[] =3D { + [OPE_ENTITY_FRAME_IN] =3D { + .name =3D "ope_input", + .obj_type =3D MEDIA_ENTITY_TYPE_VIDEO_DEVICE, + .function =3D MEDIA_ENT_F_IO_V4L, + .vdev.caps =3D V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING, + .vdev.drvdata =3D (void *)(uintptr_t)OPE_QUEUE_FRAME_IN, + .vdev.fops =3D &ope_fops, + .vdev.ioctl_ops =3D &ope_video_ioctl_ops, + .vdev.entity_ops =3D &ope_input_entity_ops, + .pads =3D (const struct camss_isp_pad_desc[]) { + { MEDIA_PAD_FL_SOURCE, OPE_ENTITY_PROC, OPE_PROC_PAD_SINK_IN, 0 }, + { } + }, + }, + [OPE_ENTITY_DISP_OUT] =3D { + .name =3D "ope_disp_output", + .obj_type =3D MEDIA_ENTITY_TYPE_VIDEO_DEVICE, + .function =3D MEDIA_ENT_F_IO_V4L, + .vdev.caps =3D V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING, + .vdev.drvdata =3D (void *)(uintptr_t)OPE_QUEUE_DISP_OUT, + .vdev.fops =3D &ope_fops, + .vdev.ioctl_ops =3D &ope_video_ioctl_ops, + .vdev.entity_ops =3D &ope_disp_output_entity_ops, + .pads =3D (const struct camss_isp_pad_desc[]) { + { MEDIA_PAD_FL_SINK, OPE_ENTITY_DISP, OPE_DISP_PAD_SOURCE, 0 }, + { } + }, + }, + [OPE_ENTITY_PARAMS] =3D { + .name =3D "ope_params", + .obj_type =3D MEDIA_ENTITY_TYPE_VIDEO_DEVICE, + .function =3D MEDIA_ENT_F_IO_V4L, + .vdev.caps =3D V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING, + .vdev.drvdata =3D (void *)(uintptr_t)OPE_QUEUE_PARAMS, + .vdev.fops =3D &ope_fops, + .vdev.ioctl_ops =3D &ope_meta_ioctl_ops, + .pads =3D (const struct camss_isp_pad_desc[]) { + { MEDIA_PAD_FL_SOURCE, OPE_ENTITY_PROC, OPE_PROC_PAD_SINK_PAR, 0 }, + { } + }, + }, + [OPE_ENTITY_PROC] =3D { + .name =3D "ope_proc", + .obj_type =3D MEDIA_ENTITY_TYPE_V4L2_SUBDEV, + .function =3D MEDIA_ENT_F_PROC_VIDEO_ISP, + .subdev.ops =3D &ope_proc_ops, + .subdev.internal_ops =3D &ope_proc_internal_ops, + .pads =3D (const struct camss_isp_pad_desc[]) { + { MEDIA_PAD_FL_SINK, OPE_ENTITY_FRAME_IN, 0, 0 }, + { MEDIA_PAD_FL_SINK, OPE_ENTITY_PARAMS, 0, 0 }, + { MEDIA_PAD_FL_SOURCE, OPE_ENTITY_DISP, OPE_DISP_PAD_SINK, + MEDIA_LNK_FL_ENABLED }, + { } + }, + }, + [OPE_ENTITY_DISP] =3D { + .name =3D "ope_disp", + .obj_type =3D MEDIA_ENTITY_TYPE_V4L2_SUBDEV, + .function =3D MEDIA_ENT_F_PROC_VIDEO_SCALER, + .subdev.ops =3D &ope_disp_ops, + .subdev.internal_ops =3D &ope_disp_internal_ops, + .subdev.entity_ops =3D &ope_disp_entity_ops, + .pads =3D (const struct camss_isp_pad_desc[]) { + { MEDIA_PAD_FL_SINK, OPE_ENTITY_PROC, OPE_PROC_PAD_SOURCE, 0 }, + { MEDIA_PAD_FL_SOURCE, OPE_ENTITY_DISP_OUT, 0, 0 }, + { } + }, + }, +}; + +static void ope_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct ope_dev *ope =3D container_of(v4l2_dev, struct ope_dev, v4l2_dev); + + /* Reached once the V4L2 core has released every video and subdev node */ + camss_isp_pipeline_free(ope->pipeline); + media_device_cleanup(&ope->mdev); + mutex_destroy(&ope->mutex); + kfree(ope); +} + +static int ope_v4l2_register(struct ope_dev *ope) +{ + int ret; + + ope->mdev.dev =3D ope->dev; + strscpy(ope->mdev.model, OPE_NAME, sizeof(ope->mdev.model)); + ope->mdev.hw_revision =3D ope->hw_version; + media_device_init(&ope->mdev); + ope->v4l2_dev.mdev =3D &ope->mdev; + ope->v4l2_dev.release =3D ope_v4l2_dev_release; + + ret =3D v4l2_device_register(ope->dev, &ope->v4l2_dev); + if (ret) { + /* No v4l2_device reference exists yet, so release @ope directly */ + ope_v4l2_dev_release(&ope->v4l2_dev); + return ret; + } + + ope->pipeline =3D camss_isp_pipeline_alloc(OPE_ENTITY_COUNT); + if (IS_ERR(ope->pipeline)) { + ret =3D PTR_ERR(ope->pipeline); + ope->pipeline =3D NULL; + goto err_v4l2; + } + + ret =3D camss_isp_pipeline_register(ope->pipeline, &ope->v4l2_dev, ope_en= tity_descs, + ARRAY_SIZE(ope_entity_descs)); + if (ret) + goto err_v4l2; + + /* Expose the graph to userspace only once every entity and link exists */ + ret =3D media_device_register(&ope->mdev); + if (ret) + goto err_pipeline; + + ope->pipeline->drv_priv =3D ope; + return 0; + +err_pipeline: + camss_isp_pipeline_unregister(ope->pipeline); +err_v4l2: + /* Rely on the v4l2_device release callback to free @ope */ + v4l2_device_unregister(&ope->v4l2_dev); + v4l2_device_put(&ope->v4l2_dev); + return ret; +} + +static void ope_unregister(struct ope_dev *ope) +{ + struct ope_ctx *ctx; + + disable_work_sync(&ope->run_work); + + scoped_guard(spinlock_irqsave, &ope->sched_lock) + ctx =3D ope->curr_ctx; + + if (ctx) { + if (ope_hw_reset_poll(ope)) + dev_err(ope->dev, "reset timeout on unbind\n"); + ope_job_finish(ctx, VB2_BUF_STATE_ERROR); + } + + if (ope->pipeline) + camss_isp_pipeline_unregister(ope->pipeline); + + media_device_unregister(&ope->mdev); + + /* Clears v4l2_dev.dev, after which no new job can reach the hardware */ + v4l2_device_unregister(&ope->v4l2_dev); + + /* + * Drops the reference this driver holds. @ope may be freed here, or + * later by the V4L2 core if userspace still has a node open. + * media_device_cleanup() is deferred to ope_v4l2_dev_release(). + */ + v4l2_device_put(&ope->v4l2_dev); +} + +static void ope_dump_pipeline(struct ope_dev *ope) +{ + static const struct { + const char *name; + u32 base; + } blocks[] =3D { + { "wb_gain", OPE_PP_WB_GAIN_BASE }, + { "demo", OPE_PP_DEMO_BASE }, + { "cc", OPE_PP_CC_BASE }, + { "glut", OPE_PP_GLUT_BASE }, + { "chroma_enhan", OPE_PP_CHROMA_ENHAN_BASE }, + { "ds_c_pre", OPE_PP_DOWNSCALE_MN_DS_C_PRE_BASE }, + { "ds_y_disp", OPE_PP_DOWNSCALE_MN_DS_Y_DISP_BASE }, + { "ds_c_disp", OPE_PP_DOWNSCALE_MN_DS_C_DISP_BASE }, + { "crop_y_disp", OPE_PP_CROP_RND_CLAMP_Y_DISP_BASE }, + { "crop_c_disp", OPE_PP_CROP_RND_CLAMP_C_DISP_BASE }, + }; + + for (unsigned int i =3D 0; i < ARRAY_SIZE(blocks); i++) { + u32 version =3D ope_read_pp(ope, OPE_PP_HW_VERSION(blocks[i].base)); + + dev_dbg(ope->dev, "pipeline %-13s HW version %u.%u.%u\n", + blocks[i].name, + OPE_HW_VERSION_GEN(version), + OPE_HW_VERSION_REV(version), + OPE_HW_VERSION_STEP(version)); + } +} + +static int ope_soft_reset(struct ope_dev *ope) +{ + u32 version; + int ret; + + ret =3D pm_runtime_resume_and_get(ope->dev); + if (ret) + return dev_err_probe(ope->dev, ret, "resume failed\n"); + + version =3D ope_read(ope, OPE_TOP_HW_VERSION); + ope->hw_version =3D version; + dev_dbg(ope->dev, "HW version %u.%u.%u\n", + OPE_HW_VERSION_GEN(version), + OPE_HW_VERSION_REV(version), + OPE_HW_VERSION_STEP(version)); + + ope_dump_pipeline(ope); + + ret =3D ope_hw_reset_poll(ope); + if (ret) + dev_err(ope->dev, "Reset timeout\n"); + + pm_runtime_put_sync(ope->dev); + + return ret; +} + +static const char * const ope_pds[] =3D { "camss" }; +static const char * const ope_opp_pds[] =3D { "cx" }; + +static const struct dev_pm_domain_attach_data ope_pd_data =3D { + .pd_names =3D ope_pds, + .num_pd_names =3D ARRAY_SIZE(ope_pds), +}; + +static const struct dev_pm_domain_attach_data ope_opp_pd_data =3D { + .pd_names =3D ope_opp_pds, + .num_pd_names =3D ARRAY_SIZE(ope_opp_pds), + .pd_flags =3D PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, +}; + +static int ope_init_power(struct ope_dev *ope) +{ + struct device *dev =3D ope->dev; + struct dev_pm_domain_list *pmdomains; + struct dev_pm_domain_list *opp_pmdomains; + struct clk *axi_clk; + int ret; + + ope->icc_data =3D devm_of_icc_get(dev, "data"); + if (IS_ERR(ope->icc_data)) + return dev_err_probe(dev, PTR_ERR(ope->icc_data), + "failed to get interconnect data path\n"); + + ope->icc_config =3D devm_of_icc_get(dev, "config"); + if (IS_ERR(ope->icc_config)) + return dev_err_probe(dev, PTR_ERR(ope->icc_config), + "failed to get interconnect config path\n"); + + ret =3D devm_pm_domain_attach_list(dev, &ope_pd_data, &pmdomains); + if (ret < 0 && ret !=3D -EEXIST) + return dev_err_probe(dev, ret, "failed to attach power domains\n"); + + ret =3D devm_pm_domain_attach_list(dev, &ope_opp_pd_data, &opp_pmdomains); + if (ret < 0 && ret !=3D -EEXIST) + return dev_err_probe(dev, ret, "failed to attach OPP power domain\n"); + + axi_clk =3D devm_clk_get_optional(dev, "axi"); + if (IS_ERR(axi_clk)) + return dev_err_probe(dev, PTR_ERR(axi_clk), "failed to get AXI clock\n"); + + ret =3D clk_set_rate(axi_clk, OPE_AXI_CLK_RATE); + if (ret) + return dev_err_probe(dev, ret, "failed to set AXI clock rate\n"); + + ret =3D devm_pm_opp_set_clkname(dev, "core"); + if (ret) + return ret; + + ret =3D devm_pm_opp_of_add_table(dev); + if (ret && ret !=3D -ENODEV) + return dev_err_probe(dev, ret, "invalid OPP table\n"); + + ret =3D devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret =3D devm_pm_clk_create(dev); + if (ret) + return ret; + + ret =3D of_pm_clk_add_clks(dev); + if (ret < 0) + return ret; + + return 0; +} + +static int ope_init_mmio(struct ope_dev *ope) +{ + struct platform_device *pdev =3D to_platform_device(ope->dev); + + ope->base =3D devm_platform_ioremap_resource_byname(pdev, "top"); + if (IS_ERR(ope->base)) + return PTR_ERR(ope->base); + + ope->base_rd =3D devm_platform_ioremap_resource_byname(pdev, "bus_read"); + if (IS_ERR(ope->base_rd)) + return PTR_ERR(ope->base_rd); + + ope->base_wr =3D devm_platform_ioremap_resource_byname(pdev, "bus_write"); + if (IS_ERR(ope->base_wr)) + return PTR_ERR(ope->base_wr); + + ope->base_pp =3D devm_platform_ioremap_resource_byname(pdev, "pipeline"); + if (IS_ERR(ope->base_pp)) + return PTR_ERR(ope->base_pp); + + return 0; +} + +static int ope_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ope_dev *ope; + int ret, irq; + + /* OPE lifetime is refcounted through the embedded v4l2_device */ + ope =3D kzalloc_obj(*ope); + if (!ope) + return -ENOMEM; + + ope->dev =3D dev; + init_completion(&ope->reset_complete); + mutex_init(&ope->mutex); + INIT_LIST_HEAD(&ope->ctx_list); + spin_lock_init(&ope->ctx_lock); + spin_lock_init(&ope->sched_lock); + INIT_WORK(&ope->run_work, ope_run_work); + + ret =3D dma_set_mask(dev, DMA_BIT_MASK(32)); + if (ret) { + ret =3D dev_err_probe(dev, ret, "Failed to set DMA mask\n"); + goto err_free; + } + + ret =3D ope_init_power(ope); + if (ret) { + ret =3D dev_err_probe(dev, ret, "Power init failed\n"); + goto err_free; + } + + ret =3D ope_init_mmio(ope); + if (ret) { + ret =3D dev_err_probe(dev, ret, "MMIO init failed\n"); + goto err_free; + } + + ret =3D ope_soft_reset(ope); + if (ret) + goto err_free; + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) { + ret =3D dev_err_probe(dev, irq, "Unable to get IRQ\n"); + goto err_free; + } + + ope->irq =3D irq; + + ret =3D devm_request_irq(dev, ope->irq, ope_irq, IRQF_NO_AUTOEN, + "camss-ope", ope); + if (ret < 0) { + ret =3D dev_err_probe(dev, ret, "Requesting IRQ failed\n"); + goto err_free; + } + + /* ope ownership is transferred to ope_v4l2_register(), even on failure */ + ret =3D ope_v4l2_register(ope); + if (ret) + return dev_err_probe(dev, ret, "V4L2 registration failed\n"); + + platform_set_drvdata(pdev, ope); + + /* Everything @ope_irq() touches is in place, let interrupts in */ + enable_irq(ope->irq); + + return 0; + +err_free: + mutex_destroy(&ope->mutex); + kfree(ope); + return ret; +} + +static void ope_remove(struct platform_device *pdev) +{ + struct ope_dev *ope =3D platform_get_drvdata(pdev); + + disable_irq(ope->irq); + ope_unregister(ope); +} + +static const struct of_device_id ope_dt_ids[] =3D { + { .compatible =3D "qcom,qcm2290-camss-ope" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ope_dt_ids); + +static const struct dev_pm_ops ope_pm_ops =3D { + SET_RUNTIME_PM_OPS(pm_clk_suspend, pm_clk_resume, NULL) +}; + +static struct platform_driver ope_driver =3D { + .probe =3D ope_probe, + .remove =3D ope_remove, + .driver =3D { + .name =3D OPE_NAME, + .of_match_table =3D ope_dt_ids, + .pm =3D pm_ptr(&ope_pm_ops), + }, +}; + +module_platform_driver(ope_driver); + +MODULE_DESCRIPTION("CAMSS Offline Processing Engine"); +MODULE_AUTHOR("Loic Poulain "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/qcom/camss/ope/params.c b/drivers/media= /platform/qcom/camss/ope/params.c new file mode 100644 index 0000000000000000000000000000000000000000..55f9a9002e34818e828ce51f5cd= e25955926018c --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/params.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ope/params.c + * + * CAMSS ISP parameter buffer parser. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include +#include +#include +#include +#include + +#include "params.h" + +int camss_isp_params_apply(struct device *dev, + struct vb2_buffer *vb, + struct v4l2_isp_params_buffer *scratch, + const struct v4l2_isp_params_block_type_info *type_info, + const camss_isp_params_handler_fn *handlers, + unsigned int num_handlers, + void *priv) +{ + const struct v4l2_isp_params_buffer *buf =3D scratch; + const void *src; + unsigned int remaining; + unsigned int offset =3D 0; + int ret; + + ret =3D v4l2_isp_params_validate_buffer_size(dev, vb, + v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYLOAD)); + if (ret) + return ret; + + src =3D vb2_plane_vaddr(vb, 0); + + if (!src) { + dev_dbg(dev, "params: buffer has no kernel mapping\n"); + return -EFAULT; + } + + /* + * The payload lives in a vmalloc'd buffer that userspace keeps mapped + * while the buffer is queued, so it must not be validated in place: + * copy it into kernel-only memory first, then work exclusively on the + * copy. See the v4l2_isp_params_validate_buffer() documentation. + */ + memcpy(scratch, src, vb2_get_plane_payload(vb, 0)); + + ret =3D v4l2_isp_params_validate_buffer(dev, vb, buf, type_info, num_hand= lers); + if (ret) + return ret; + + dev_dbg(dev, "params: version=3D%u data_size=3D%u\n", buf->version, buf->= data_size); + + remaining =3D buf->data_size; + + while (remaining >=3D sizeof(struct v4l2_isp_params_block_header)) { + const union camss_isp_params_block *block =3D + (const union camss_isp_params_block *)&buf->data[offset]; + u16 type =3D block->header.type; + u32 bsize =3D block->header.size; + + if (type < num_handlers && handlers[type]) + handlers[type](priv, block); + else + dev_dbg(dev, "params: no handler for block type %u\n", type); + + offset +=3D bsize; + remaining -=3D bsize; + } + + dev_dbg(dev, "params: buffer parsed successfully\n"); + + return 0; +} diff --git a/drivers/media/platform/qcom/camss/ope/params.h b/drivers/media= /platform/qcom/camss/ope/params.h new file mode 100644 index 0000000000000000000000000000000000000000..b3388b5ce22643d5f19bc556df2= 9060fab5bc227 --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/params.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ope/params.h + * + * CAMSS ISP parameter buffer parser. + * + * Wraps the upstream v4l2_isp_params_validate_buffer() validation and adds + * a dispatch layer: after validation each block is forwarded to a + * driver-supplied handler. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef CAMSS_PARAMS_H +#define CAMSS_PARAMS_H + +#include +#include +#include +#include + +#define CAMSS_ISP_PARAMS_FMT_INIT \ + { .fourcc =3D V4L2_META_FMT_QCOM_ISP_PARAMS, .depth =3D 8, .align =3D 0, = .num_planes =3D 1 } + +#define CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY (1U << V4L2_ISP_FL_DRIVER_FLAGS(= 0)) + +struct device; +struct vb2_buffer; +struct camss_isp_fmt; + +union camss_isp_params_block { + struct v4l2_isp_params_block_header header; + struct camss_params_wb_gain wb_gain; + struct camss_params_chroma_enhan chroma_enhan; + struct camss_params_color_correct color_correct; + struct camss_params_gamma gamma; +}; + +typedef void (*camss_isp_params_handler_fn)(void *priv, const union camss_= isp_params_block *block); + +/** + * camss_isp_params_copy_block - copy one validated block into driver state + * + * @dst: destination block in the driver's shadow configuration + * @block: validated source block + * @size: size of the destination block + * + * Returns true if the payload was copied, false if only the header was. + */ +static inline bool camss_isp_params_copy_block(void *dst, + const union camss_isp_params_block *block, + size_t size) +{ + struct v4l2_isp_params_block_header *hdr =3D dst; + bool header_only =3D block->header.size =3D=3D sizeof(block->header); + + if (header_only) + *hdr =3D block->header; + else + memcpy(dst, block, size); + + hdr->flags |=3D CAMSS_ISP_PARAMS_FL_BLOCK_DIRTY; + + return !header_only; +} + +/** + * camss_isp_params_apply - validate and dispatch a params buffer + * + * @dev: device for error logging + * @vb: the vb2 buffer (used for size validation) + * @scratch: kernel-only bounce buffer, at least + * v4l2_isp_buffer_size(CAMSS_PARAMS_OPE_MAX_PAYLOAD) bytes + * @type_info: per-block-type validation info, indexed by block type + * @handlers: per-block-type handlers, indexed by block type + * @num_handlers: number of entries in @type_info and @handlers + * @priv: opaque pointer forwarded to each handler + * + * Copies the buffer payload into @scratch, calls + * v4l2_isp_params_validate_buffer_size(), then + * v4l2_isp_params_validate_buffer(), then walks the validated block stream + * dispatching each block to its handler. Validation and dispatch operate + * only on @scratch, never on the userspace-visible mapping. + * + * Returns 0 on success, negative errno on validation failure. + */ +int camss_isp_params_apply(struct device *dev, + struct vb2_buffer *vb, + struct v4l2_isp_params_buffer *scratch, + const struct v4l2_isp_params_block_type_info *type_info, + const camss_isp_params_handler_fn *handlers, + unsigned int num_handlers, + void *priv); + +#endif /* CAMSS_PARAMS_H */ diff --git a/drivers/media/platform/qcom/camss/ope/pipeline.c b/drivers/med= ia/platform/qcom/camss/ope/pipeline.c new file mode 100644 index 0000000000000000000000000000000000000000..a888d5027fc785614690b219336= e05751b88d617 --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/pipeline.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * CAMSS ISP pipeline helper =E2=80=94 declarative MC topology builder + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include + +#include +#include +#include +#include +#include +#include "pipeline.h" + +/* -------- Internal helpers -------- */ + +static enum vfl_devnode_direction isp_caps_to_vfl_dir(u32 caps) +{ + if (caps & (V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE)) + return VFL_DIR_M2M; + if (caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_META_OUTPUT | V4L2_CAP_VBI_OUTPUT | V4L2_CAP_SDR_OUTPUT)) + return VFL_DIR_TX; + return VFL_DIR_RX; +} + +static unsigned int isp_count_pads(const struct camss_isp_pad_desc *pads) +{ + unsigned int n =3D 0; + + if (!pads) + return 0; + while (pads[n].flags) + n++; + return n; +} + +static struct media_entity *isp_pipeline_media_entity(struct camss_isp_pip= eline *pipeline, + unsigned int idx) +{ + struct camss_isp_pipeline_entity *slot =3D &pipeline->entities[idx]; + + switch (slot->obj_type) { + case MEDIA_ENTITY_TYPE_VIDEO_DEVICE: + return &slot->vdev.entity; + case MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + return &slot->subdev.entity; + default: + return &slot->entity; + } +} + +/* -------- Validation -------- */ + +static int isp_pipeline_validate(struct device *dev, + const struct camss_isp_entity_desc *descs, + unsigned int num_entities) +{ + unsigned int i, pi; + + for (i =3D 0; i < num_entities; i++) { + const struct camss_isp_pad_desc *pads =3D descs[i].pads; + unsigned int num_pads =3D isp_count_pads(pads); + + for (pi =3D 0; pi < num_pads; pi++) { + const struct camss_isp_pad_desc *pad =3D &pads[pi]; + const struct camss_isp_pad_desc *peer_pad; + unsigned int peer_num_pads; + int peer_ent =3D pad->peer_entity; + + if (peer_ent < 0) + continue; + + if ((unsigned int)peer_ent >=3D num_entities) { + dev_err(dev, "entity[%u].p%u: peer_entity %d out of range\n", + i, pi, peer_ent); + return -EINVAL; + } + + peer_num_pads =3D isp_count_pads(descs[peer_ent].pads); + if (pad->peer_pad >=3D peer_num_pads) { + dev_err(dev, "entity[%u].p%u: peer_pad %u out of range\n", + i, pi, pad->peer_pad); + return -EINVAL; + } + + peer_pad =3D &descs[peer_ent].pads[pad->peer_pad]; + + /* Links are SOURCE->SINK; reject SOURCE->SOURCE or SINK->SINK */ + if (((pad->flags & MEDIA_PAD_FL_SOURCE) && + (peer_pad->flags & MEDIA_PAD_FL_SOURCE)) || + ((pad->flags & MEDIA_PAD_FL_SINK) && + (peer_pad->flags & MEDIA_PAD_FL_SINK))) { + dev_err(dev, "entity[%u].p%u -> entity[%d].p%u: invalid\n", + i, pi, peer_ent, pad->peer_pad); + return -EINVAL; + } + + /* A link must be described symmetrically from both ends */ + if ((unsigned int)peer_pad->peer_entity !=3D i || + peer_pad->peer_pad !=3D pi) { + dev_err(dev, "entity[%u].p%u <-> entity[%d].p%u: mismatch\n", + i, pi, peer_ent, pad->peer_pad); + return -EINVAL; + } + } + } + + return 0; +} + +/* -------- Allocation / Release -------- */ + +struct camss_isp_pipeline *camss_isp_pipeline_alloc(unsigned int num_entit= ies) +{ + struct camss_isp_pipeline *pipeline; + + pipeline =3D kzalloc(struct_size(pipeline, entities, num_entities), + GFP_KERNEL); + if (!pipeline) + return ERR_PTR(-ENOMEM); + + pipeline->num_entities =3D num_entities; + mutex_init(&pipeline->vdev_lock); + return pipeline; +} + +void camss_isp_pipeline_free(struct camss_isp_pipeline *pipeline) +{ + unsigned int i; + + if (!pipeline) + return; + + /* Release pads and subdevs state */ + for (i =3D 0; i < pipeline->num_entities; i++) { + struct camss_isp_pipeline_entity *slot =3D &pipeline->entities[i]; + + if (slot->obj_type =3D=3D MEDIA_ENTITY_TYPE_V4L2_SUBDEV) + v4l2_subdev_cleanup(&slot->subdev); + + kfree(slot->pads); + slot->pads =3D NULL; + } + + mutex_destroy(&pipeline->vdev_lock); + kfree(pipeline); +} + +/* -------- Registration -------- */ + +void camss_isp_pipeline_unregister(struct camss_isp_pipeline *pipeline) +{ + int i; + + /* Unregister entities in reverse order. */ + for (i =3D (int)pipeline->num_entities - 1; i >=3D 0; i--) { + struct camss_isp_pipeline_entity *slot =3D &pipeline->entities[i]; + + if (slot->registered) { + switch (slot->obj_type) { + case MEDIA_ENTITY_TYPE_VIDEO_DEVICE: + if (video_device_pipeline(&slot->vdev)) + video_device_pipeline_stop(&slot->vdev); + video_unregister_device(&slot->vdev); + break; + case MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + v4l2_device_unregister_subdev(&slot->subdev); + break; + case MEDIA_ENTITY_TYPE_BASE: + media_entity_remove_links(&slot->entity); + media_device_unregister_entity(&slot->entity); + slot->entity.name =3D NULL; + break; + } + + slot->registered =3D false; + } + } + + pipeline->v4l2_dev =3D NULL; +} + +static int isp_register_vdev(struct camss_isp_pipeline *pipeline, + struct camss_isp_pipeline_entity *slot, + const struct camss_isp_entity_desc *desc, + struct v4l2_device *v4l2_dev) +{ + struct video_device *vdev =3D &slot->vdev; + int ret; + + if (!desc->name || !desc->name[0] || !desc->vdev.fops) + return -EINVAL; + + strscpy(vdev->name, desc->name, sizeof(vdev->name)); + vdev->vfl_dir =3D isp_caps_to_vfl_dir(desc->vdev.caps); + vdev->v4l2_dev =3D v4l2_dev; + vdev->device_caps =3D desc->vdev.caps | V4L2_CAP_IO_MC; + vdev->release =3D video_device_release_empty; + vdev->fops =3D desc->vdev.fops; + vdev->lock =3D &pipeline->vdev_lock; + if (desc->vdev.ioctl_ops) + vdev->ioctl_ops =3D desc->vdev.ioctl_ops; + if (desc->vdev.entity_ops) + vdev->entity.ops =3D desc->vdev.entity_ops; + + vdev->entity.obj_type =3D MEDIA_ENTITY_TYPE_VIDEO_DEVICE; + vdev->entity.function =3D desc->function ? desc->function : MEDIA_ENT_F_I= O_V4L; + + ret =3D media_entity_pads_init(&vdev->entity, slot->num_pads, slot->pads); + if (ret) + return ret; + + video_set_drvdata(vdev, desc->vdev.drvdata); + + ret =3D video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) + return ret; + + return 0; +} + +static int isp_register_subdev(struct camss_isp_pipeline_entity *slot, + const struct camss_isp_entity_desc *desc, + struct v4l2_device *v4l2_dev) +{ + struct v4l2_subdev *sd =3D &slot->subdev; + int ret; + + if (!desc->name || !desc->name[0] || !desc->subdev.ops) + return -EINVAL; + + v4l2_subdev_init(sd, desc->subdev.ops); + strscpy(sd->name, desc->name, sizeof(sd->name)); + sd->entity.function =3D desc->function ? + desc->function : MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + /* Create a /dev/v4l-subdevN node so userspace can query pad formats */ + sd->flags |=3D V4L2_SUBDEV_FL_HAS_DEVNODE; + if (desc->subdev.internal_ops) + sd->internal_ops =3D desc->subdev.internal_ops; + if (desc->subdev.entity_ops) + sd->entity.ops =3D desc->subdev.entity_ops; + + ret =3D media_entity_pads_init(&sd->entity, slot->num_pads, slot->pads); + if (ret) + return ret; + + ret =3D v4l2_subdev_init_finalize(sd); + if (ret) + return ret; + + ret =3D v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) { + v4l2_subdev_cleanup(sd); + return ret; + } + + return 0; +} + +static int isp_register_base_entity(struct camss_isp_pipeline_entity *slot, + const struct camss_isp_entity_desc *desc, + struct v4l2_device *v4l2_dev) +{ + struct media_entity *entity =3D &slot->entity; + int ret; + + if (!desc->name || !desc->name[0]) + return -EINVAL; + + entity->obj_type =3D MEDIA_ENTITY_TYPE_BASE; + entity->name =3D desc->name; + entity->function =3D desc->function; + + ret =3D media_entity_pads_init(entity, slot->num_pads, slot->pads); + if (ret) { + entity->name =3D NULL; + return ret; + } + + ret =3D media_device_register_entity(v4l2_dev->mdev, entity); + if (ret) { + entity->name =3D NULL; + return ret; + } + + return 0; +} + +static int isp_alloc_pads(struct camss_isp_pipeline_entity *slot, + const struct camss_isp_entity_desc *desc) +{ + unsigned int num_pads =3D isp_count_pads(desc->pads); + unsigned int i; + + if (!num_pads) + goto done; + + slot->pads =3D kcalloc(num_pads, sizeof(*slot->pads), GFP_KERNEL); + if (!slot->pads) + return -ENOMEM; + + for (i =3D 0; i < num_pads; i++) + slot->pads[i].flags =3D desc->pads[i].flags; +done: + slot->num_pads =3D num_pads; + return 0; +} + +int camss_isp_pipeline_register(struct camss_isp_pipeline *pipeline, + struct v4l2_device *v4l2_dev, + const struct camss_isp_entity_desc *descs, + unsigned int num_entities) +{ + unsigned int i, pi; + int ret; + + if (WARN_ON(num_entities !=3D pipeline->num_entities)) + return -EINVAL; + + if (WARN_ON(!v4l2_dev || !v4l2_dev->mdev)) + return -EINVAL; + + ret =3D isp_pipeline_validate(v4l2_dev->dev, descs, num_entities); + if (ret) + return ret; + + pipeline->v4l2_dev =3D v4l2_dev; + + /* Register each entity */ + for (i =3D 0; i < num_entities; i++) { + const struct camss_isp_entity_desc *desc =3D &descs[i]; + struct camss_isp_pipeline_entity *slot =3D &pipeline->entities[i]; + + slot->obj_type =3D desc->obj_type; + + ret =3D isp_alloc_pads(slot, desc); + if (ret) + goto err_unregister; + + switch (desc->obj_type) { + case MEDIA_ENTITY_TYPE_VIDEO_DEVICE: + ret =3D isp_register_vdev(pipeline, slot, desc, v4l2_dev); + break; + case MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + ret =3D isp_register_subdev(slot, desc, v4l2_dev); + break; + case MEDIA_ENTITY_TYPE_BASE: + default: + ret =3D isp_register_base_entity(slot, desc, v4l2_dev); + break; + } + if (ret) + goto err_unregister; + + slot->registered =3D true; + } + + /* Create links =E2=80=94 only from SOURCE side to avoid duplicates */ + for (i =3D 0; i < num_entities; i++) { + const struct camss_isp_entity_desc *desc =3D &descs[i]; + unsigned int num_pads =3D isp_count_pads(desc->pads); + + for (pi =3D 0; pi < num_pads; pi++) { + const struct camss_isp_pad_desc *pad =3D &desc->pads[pi]; + struct media_entity *src_entity, *sink_entity; + unsigned int src_pad_idx, sink_pad_idx; + u32 lflags; + + if (!(pad->flags & MEDIA_PAD_FL_SOURCE)) + continue; + if (pad->peer_entity < 0) + continue; + + src_entity =3D isp_pipeline_media_entity(pipeline, i); + sink_entity =3D isp_pipeline_media_entity(pipeline, + (unsigned int)pad->peer_entity); + src_pad_idx =3D pi; + sink_pad_idx =3D pad->peer_pad; + + lflags =3D pad->link_flags ? + pad->link_flags : + (MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + + ret =3D media_create_pad_link(src_entity, src_pad_idx, + sink_entity, sink_pad_idx, + lflags); + if (ret) + goto err_unregister; + } + } + + /* Create /dev/v4l-subdevN nodes for all registered subdevs */ + ret =3D v4l2_device_register_subdev_nodes(v4l2_dev); + if (ret) + goto err_unregister; + + return 0; + +err_unregister: + camss_isp_pipeline_unregister(pipeline); + return ret; +} diff --git a/drivers/media/platform/qcom/camss/ope/pipeline.h b/drivers/med= ia/platform/qcom/camss/ope/pipeline.h new file mode 100644 index 0000000000000000000000000000000000000000..f7d50734ed61f45e988328de980= ac5793f7d38dd --- /dev/null +++ b/drivers/media/platform/qcom/camss/ope/pipeline.h @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * CAMSS ISP pipeline helper =E2=80=94 declarative MC topology builder + * + * Drivers describe their entire media graph =E2=80=94 entities (video dev= ices, + * subdevs, or base entities), their pads, and the links between them =E2= =80=94 + * in a single static descriptor table. The builder validates the table, + * allocates and registers all entities, and creates all MC links. + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef _CAMSS_PIPELINE_H +#define _CAMSS_PIPELINE_H + +#include +#include +#include +#include +#include +#include + +/** + * struct camss_isp_pad_desc - descriptor for one pad and its optional link + * + * @flags: Pad flags: MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE, + * MEDIA_PAD_FL_MUST_CONNECT. A zero @flags value acts as + * the sentinel that terminates the pad list. + * @peer_entity: Index of the peer entity in the descriptor array, or -1 + * if this pad has no link. + * @peer_pad: Pad index on the peer entity to link to. + * @link_flags: MC link flags (MEDIA_LNK_FL_*). Defaults to + * MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED when zero. + * + * Links are described from both sides (each endpoint references the other= ), + * but the builder only creates each link once =E2=80=94 from the SOURCE s= ide. + */ +struct camss_isp_pad_desc { + u32 flags; + int peer_entity; + unsigned int peer_pad; + u32 link_flags; +}; + +/** + * struct camss_isp_entity_desc - descriptor for one entity in the pipeline + * + * @name: Human-readable entity name (also used as video device name + * suffix when @obj_type is MEDIA_ENTITY_TYPE_VIDEO_DEVICE). + * Mandatory and must be non-empty. + * @obj_type: MEDIA_ENTITY_TYPE_VIDEO_DEVICE, MEDIA_ENTITY_TYPE_V4L2_SUBD= EV, + * or MEDIA_ENTITY_TYPE_BASE. + * @function: MEDIA_ENT_F_* function identifier. + * @pads: Sentinel-terminated (flags =3D=3D 0) array of pad descripto= rs. + * + * Fields used only for MEDIA_ENTITY_TYPE_VIDEO_DEVICE: + * @vdev.caps: V4L2_CAP_* device capabilities. + * The video device direction (VFL_DIR_RX/TX/M2M) is derived + * automatically from @caps by the builder. + * @vdev.drvdata: Opaque pointer set via video_set_drvdata() after registr= ation. + * @vdev.fops: File operations (mandatory). + * @vdev.ioctl_ops: ioctl operations (may be NULL). + * + * Fields used only for MEDIA_ENTITY_TYPE_V4L2_SUBDEV: + * @subdev.ops: Subdev operations (mandatory). + * @subdev.internal_ops: Internal subdev operations (may be NULL). + */ +struct camss_isp_entity_desc { + const char *name; + u32 obj_type; + u32 function; + const struct camss_isp_pad_desc *pads; + + union { + /* MEDIA_ENTITY_TYPE_VIDEO_DEVICE */ + struct { + u32 caps; + void *drvdata; + const struct v4l2_file_operations *fops; + const struct v4l2_ioctl_ops *ioctl_ops; + const struct media_entity_operations *entity_ops; + } vdev; + /* MEDIA_ENTITY_TYPE_V4L2_SUBDEV */ + struct { + const struct v4l2_subdev_ops *ops; + const struct v4l2_subdev_internal_ops *internal_ops; + const struct media_entity_operations *entity_ops; + } subdev; + }; +}; + +/** + * struct camss_isp_pipeline_entity - one registered entity slot + * + * Internal to the pipeline; drivers access entities via the accessor help= ers. + * + * @obj_type: mirrors the descriptor's @obj_type. + * @registered: set once the entity has been successfully registered, so t= hat + * teardown only undoes what actually succeeded. + * @pads: allocated pad array for this entity. + * @num_pads: number of entries in @pads. + * @vdev: valid when @obj_type =3D=3D MEDIA_ENTITY_TYPE_VIDEO_DEVICE. + * @subdev: valid when @obj_type =3D=3D MEDIA_ENTITY_TYPE_V4L2_SUBDEV. + * @entity: valid when @obj_type =3D=3D MEDIA_ENTITY_TYPE_BASE. + */ +struct camss_isp_pipeline_entity { + u32 obj_type; + bool registered; + struct media_pad *pads; + unsigned int num_pads; + union { + struct video_device vdev; + struct v4l2_subdev subdev; + struct media_entity entity; + }; +}; + +/** + * struct camss_isp_pipeline - registered ISP pipeline topology + * + * Allocate with camss_isp_pipeline_alloc(), register with + * camss_isp_pipeline_register(), tear down with + * camss_isp_pipeline_unregister(), free with camss_isp_pipeline_free(). + * + * @v4l2_dev: Pointer to the caller-provided V4L2 device. + * @drv_priv: Driver-private pointer; not touched by the framework. + * @vdev_lock: Pipeline-wide mutex assigned to video_device.lock of eve= ry + * registered video device, so the V4L2 core serialises ioc= tl2 + * handlers across all of the pipeline's video nodes. + * @num_entities: Number of entries in @entities. + * @entities: Per-entity state; flexible array. + */ +struct camss_isp_pipeline { + struct v4l2_device *v4l2_dev; + void *drv_priv; + struct mutex vdev_lock; + + unsigned int num_entities; + struct camss_isp_pipeline_entity entities[] __counted_by(num_entities); +}; + +/** + * camss_isp_pipeline_alloc() - allocate a pipeline for @num_entities enti= ties + * + * Returns a pointer to the new pipeline or ERR_PTR on failure. + * Free with camss_isp_pipeline_free(). + */ +struct camss_isp_pipeline *camss_isp_pipeline_alloc(unsigned int num_entit= ies); + +/** + * camss_isp_pipeline_free() - free a pipeline + * @pipeline: pipeline to free (may be NULL) + */ +void camss_isp_pipeline_free(struct camss_isp_pipeline *pipeline); + +/** + * camss_isp_pipeline_register() - validate descriptors and register the g= raph + * @pipeline: pipeline (allocated with camss_isp_pipeline_alloc()) + * @v4l2_dev: caller-owned and already-registered V4L2 device; its + * associated media_device (v4l2_dev->mdev) must also be + * initialised and registered before this call. + * @descs: array of @num_entities entity descriptors + * @num_entities: number of entities; must equal pipeline->num_entities + * + * Validates the descriptor table (link direction consistency, index bound= s), + * then registers all entities into the provided v4l2_device / media_device + * and creates all MC pad links. + * + * Returns 0 on success or a negative error code. + */ +int camss_isp_pipeline_register(struct camss_isp_pipeline *pipeline, + struct v4l2_device *v4l2_dev, + const struct camss_isp_entity_desc *descs, + unsigned int num_entities); + +/** + * camss_isp_pipeline_unregister() - tear down a registered pipeline + * @pipeline: pipeline to unregister. + */ +void camss_isp_pipeline_unregister(struct camss_isp_pipeline *pipeline); + +/** + * camss_isp_pipeline_get_vdev() - return the video_device for entity @idx + * @pipeline: registered pipeline + * @idx: entity index (must be MEDIA_ENTITY_TYPE_VIDEO_DEVICE) + * + * Returns NULL if @idx is out of range or the entity is not a video devic= e. + */ +static inline struct video_device * +camss_isp_pipeline_get_vdev(struct camss_isp_pipeline *pipeline, + unsigned int idx) +{ + if (WARN_ON(idx >=3D pipeline->num_entities)) + return NULL; + if (WARN_ON(pipeline->entities[idx].obj_type !=3D + MEDIA_ENTITY_TYPE_VIDEO_DEVICE)) + return NULL; + return &pipeline->entities[idx].vdev; +} + +/** + * camss_isp_pipeline_get_subdev() - return the v4l2_subdev for entity @idx + * @pipeline: registered pipeline + * @idx: entity index (must be MEDIA_ENTITY_TYPE_V4L2_SUBDEV) + * + * Returns NULL if @idx is out of range or the entity is not a subdev. + */ +static inline struct v4l2_subdev * +camss_isp_pipeline_get_subdev(struct camss_isp_pipeline *pipeline, + unsigned int idx) +{ + if (WARN_ON(idx >=3D pipeline->num_entities)) + return NULL; + if (WARN_ON(pipeline->entities[idx].obj_type !=3D + MEDIA_ENTITY_TYPE_V4L2_SUBDEV)) + return NULL; + return &pipeline->entities[idx].subdev; +} + +/** + * camss_isp_pipeline_get_entity() - return the media_entity for entity @i= dx + * @pipeline: registered pipeline + * @idx: entity index (must be MEDIA_ENTITY_TYPE_BASE) + * + * Returns NULL if @idx is out of range or the entity is not a base entity. + */ +static inline struct media_entity * +camss_isp_pipeline_get_entity(struct camss_isp_pipeline *pipeline, + unsigned int idx) +{ + if (WARN_ON(idx >=3D pipeline->num_entities)) + return NULL; + if (WARN_ON(pipeline->entities[idx].obj_type !=3D + MEDIA_ENTITY_TYPE_BASE)) + return NULL; + return &pipeline->entities[idx].entity; +} + +#endif /* _CAMSS_PIPELINE_H */ --=20 2.34.1 From nobody Fri Sep 25 23:51:05 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A3A5347F3A2 for ; Fri, 25 Sep 2026 09:10:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327410; cv=none; b=N7NWqwlAmhYrD8B/ptOEtz1ZYYH4TqrEqgiEi0416se56UzpbROadK9cCUq2rPOqh4jNXr8BbNPBI4UZuWxvBNsnBhzZ6Wt9TW+5R4RUeK9JjFjEtG3w0pDO1KhWK3ZYCs0W96zhWt/vkDYsnkgXOMmR/4Fs9GSXXd5NCDVWBm4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327410; c=relaxed/simple; bh=HmeR1l9JD8JvYgGsyzO5QvZGodxO5bhsmjCW69cOhmI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=O64fgVi48/ZmelTuAgI2Brhwk4jqnvM9d3xCwl9V05qu3C2kx3+yLZl72AKOCYN3v9qu5l/CKzdJXy//RyzOT2VMZg2dssty2tpzLsK1HPA1x0heZH11Pgqeh6sYgtep25g1kC5v5jSdSdrw4nR2PW1YeBkBCUTulmp8jEGWlZA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=ZbW5Beuk; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=EL8lhapE; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="ZbW5Beuk"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="EL8lhapE" Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4YwJ74103023 for ; Fri, 25 Sep 2026 09:10:05 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= vjzv0biNUKG1BiKaowTeTkIFJcvCjq/9OvYidNdvtc8=; b=ZbW5BeukrFMoBP6g 0797bv4FA0kh+w3/6w3sOgzaeSQHsjqjKeCybGrvbBbzqDXf00P/CI6G1zO+gJaB 4pzlJ7o9+RMeHX1Z7RGYA5baoqOjWuoo1dj4QXnJkzv69CryAZotSy8S4ISXCUjs wxVlSXZ0na8dWnILEIcfYfcIufk6ZE9Y7lWSQRbEaBR43JYtKDGC9GQj79jr+eld 5NzIZhOGQg06NNxzccnW93diBNqP6gd4N0eWBAptG65RcEGw67Utn5czlpCIWiqj te0oPMHaOVjfkbziqfWRd7nkH3L1HlVm1+g/V4n8LE1XwSqZuLNX6vJjToO+BrYf 9Oc7bg== Received: from mail-qk1-f197.google.com (mail-qk1-f197.google.com [209.85.222.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw5q8unad-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:05 +0000 (GMT) Received: by mail-qk1-f197.google.com with SMTP id af79cd13be357-93a3f673221so194403785a.0 for ; Fri, 25 Sep 2026 02:10:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327405; x=1790932205; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vjzv0biNUKG1BiKaowTeTkIFJcvCjq/9OvYidNdvtc8=; b=EL8lhapEWIuSfe09FX3B4DNnVCcj8i+hwAU2/9o2nEnteqrKQTtiXWCV1yDnUGGUXa UZ4ziSX7dYu8AlQh70AFs4piCD0m71fmWovo++DujITCr6UCPly3JME2MaGUWFczMCk7 rO0XhYnNSH2dkPcGo9z9DET6BbtXTnq0/W8OaHX5hIzYcL7vnzZ+Z4rzL0KIM7XInXOi 5zx8dEU98J7FgCgcTcZhGkUbHC+VwzdLggYOBvvS6+YjDHD3W7U8KmgvmOeB6Y1v5gAy KiPZSWnigvvYssp0C7d7T8S2mMl7/pX+4LNEMFS6+YFvxlqT4jg+rPXDhQdni2X2Ni0T 9rJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327405; x=1790932205; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=vjzv0biNUKG1BiKaowTeTkIFJcvCjq/9OvYidNdvtc8=; b=k70H2ENC/Pfg8JqpSFsJb09563kVqVhxXWMGNKQHadpiOCW4Wszhz5z0Y7uoz2ilou MefRtPUKvzCPu4b4i46FgsFPz22/TmyY/GddJJD5M7jRA/NhwRGSvMcG+ORO7dCPlAd6 04wRppq/kTa96Gcaq129o9obu1sVLABHe5Dm92v43ASZ4meW9wJznYm2djuneQ7tkYnJ /HucGwYi/Ji3WngoA+y8uozWeCuYunRDsFHYWxtPVLrY1bWdYAGasJTzlbPHRZyN7CeL GYH535KoDgAQSd5xSUzt2muQ6kNhh6EDsUTnvM+NZLVEIhMqv7hhoYkfb1k0FjmknQXD ZrHA== X-Forwarded-Encrypted: i=1; AKwUvBzIKq0HQ63TjRwwHB4Xr5CyqY+P3Etiyp0spq31kzaX7923jwoWlzSkSEV//sZyUxbempLkJgHu4h8wG5I=@vger.kernel.org X-Gm-Message-State: AFuF++nqQowO53LenJJwCyExAwTWe0pdZk10ruG9swXIix55tngKGWv8 nVePDSX7EqVOjeC18dGg3r9soDetVAgvqBeTXPVZEUBpWyRYIMX4rP+XW6uXlVROrz99fJpGDCg fuyDwu78Q4eRWfUcGnSkB4Ub2iLq+cvOCoOjNRyvS9epg8AE2WDjE6tIZUKg/uTCHhfc= X-Gm-Gg: AYBFou1T5WCmAyLEz1I5OFmfDCInZZwqMya295C1haKD9VDgdQmhM7zFW5a22VQvQAb qV3H/0mPsOuKiAVqdLd6A60WMBaFiUxF0k7NirrzM3Qb6u1GWb2aTAr9a9WaIrknWprHuvtiLGw Kkt3khoCM/a1X8pWNhk+K/RG6RCNjaGGEwIdwLo/NKp6HaXjPHFgEk0DHz1t1lzLtHDsIDSWbJw Fc5ptSuh0KY8H0D7N6otV3COt1YLGul0Na0v+tqFvswd7oeTib1wPZjubd8r0AT2ZpyeyOiMKm6 3dDcsTHcZyuD8seMGFE51U2wOhGZXGw3EvJVd3dcXE5oXhF2VlRlvApLiukOB/STq1V3a4wyqdr +z2bU9u7hAkoe/HNit7nSPMW7KY5L+ourZBuEKMqIjSKIGzEW4X06m73tH5p+dudQDxnCj7n03X A5e8fOu1JeMK0NBJVzYqQgCYDak785oLApz1RP/9qDf6rFxrqwupg= X-Received: by 2002:a05:620a:6018:b0:939:869:a8bb with SMTP id af79cd13be357-93c4735e449mr224787085a.14.1790327404648; Fri, 25 Sep 2026 02:10:04 -0700 (PDT) X-Received: by 2002:a05:620a:6018:b0:939:869:a8bb with SMTP id af79cd13be357-93c4735e449mr224783385a.14.1790327404194; Fri, 25 Sep 2026 02:10:04 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.10.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:10:03 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:54 +0200 Subject: [PATCH v10 7/9] arm64: dts: qcom: agatti: Add OPE node Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-7-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Abel Vesa X-Mailer: b4 0.14.2 X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX/4q1WyGr5XHz 0Jl+pLvZR35m+3zUHKR9HZhObAoVkETvHkkRiO6dDAO1Wh+Gt4w0No1opnR+zLo08QgGzieMS77 pAKbD4r4q33vL7GY1xx9AsqoU9baTTU= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX5NJqE61cg8IL knoab95z2pd1SaO2oUxRrYnVruX0SsD4XZdoOEaN/E1LrfHNsJJYu2MI1/CciZUxOlZO5rRd2RU 4V5gIBWQQlzUsb3CAF+T/70Ujs1L3NagFBZaOyhITFxEA7X/b2hUEhyfgxtDkC8TiF2gnXAxQ2P 5yaGdRbNh1GXqJGetEDR3lMP6t0nD489QTkefjQOIJSK+oqWeCF0gnpmJRRBm8agpnxZkIIypy/ ABsdfzK4b1dPHwMbU581OHro9cpX9HxjV3f/hqtAAycat8DGEZldSX7C1lPDNIb7XzODhkOhQC1 c+X5MvdYLolVzT4gRNhpRmOgdldYHHbQIZH18IeIdIg7EQS3wlBxx9ErnD5vLdDVz5z6m7T07Bo pRKdGKhTVduO94jRYTSjGdadwyry1BzYp0+I87xDUCJfZ1ADHkJEAk4hhPKLtF0JGqxIO+t1zPK P2hFuY1oOUaM9pkHvgQ== X-Authority-Analysis: v=2.4 cv=SYRi5fRu c=1 sm=1 tr=0 ts=6ab63a6d cx=c_pps a=50t2pK5VMbmlHzFWWp8p/g==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=ZpdpYltYx_vBUK5n70dp:22 a=EUspDBNiAAAA:8 a=1BEw5LmG3YzgyHxDt7YA:9 a=QEXdDO2ut3YA:10 a=IoWCM6iH3mJn3m4BftBB:22 X-Proofpoint-GUID: tlQZIf_r-u6qyOOwP6lYOtx0pxJO1pk3 X-Proofpoint-ORIG-GUID: tlQZIf_r-u6qyOOwP6lYOtx0pxJO1pk3 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 phishscore=0 malwarescore=0 suspectscore=0 bulkscore=0 impostorscore=0 clxscore=1015 adultscore=0 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 Add the Offline Processing Engine (OPE) device tree node for the Agatti platform (QCM2290). The node describes the six register regions (cdm, top, qos, pipeline, bus_read, bus_write), clocks, interrupt, interconnects, IOMMU mappings, and OPP table. OPE is a memory-to-memory block with no board-level dependencies, so the node is left enabled for all Agatti boards. Reviewed-by: Abel Vesa Signed-off-by: Loic Poulain --- arch/arm64/boot/dts/qcom/agatti.dtsi | 77 ++++++++++++++++++++++++++++++++= ++++ 1 file changed, 77 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/agatti.dtsi b/arch/arm64/boot/dts/qco= m/agatti.dtsi index 397d61a8a27c2505833466bd349acc27ef4ffe0c..7746c58b5b1cb25206e72b888b7= 559cfe27553b9 100644 --- a/arch/arm64/boot/dts/qcom/agatti.dtsi +++ b/arch/arm64/boot/dts/qcom/agatti.dtsi @@ -2020,6 +2020,83 @@ port@1 { }; }; =20 + isp_ope: isp@5c42000 { + compatible =3D "qcom,qcm2290-camss-ope"; + + reg =3D <0x0 0x5c42000 0x0 0x400>, + <0x0 0x5c42400 0x0 0x200>, + <0x0 0x5c42600 0x0 0x200>, + <0x0 0x5c42800 0x0 0x4400>, + <0x0 0x5c46c00 0x0 0x190>, + <0x0 0x5c46d90 0x0 0xa00>; + reg-names =3D "cdm", + "top", + "qos", + "pipeline", + "bus_read", + "bus_write"; + + clocks =3D <&gcc GCC_CAMSS_AXI_CLK>, + <&gcc GCC_CAMSS_OPE_CLK>, + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_NRT_AXI_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>; + clock-names =3D "axi", + "core", + "iface", + "nrt", + "top"; + + interrupts =3D ; + + interconnects =3D <&bimc MASTER_APPSS_PROC RPM_ACTIVE_TAG + &config_noc SLAVE_CAMERA_CFG RPM_ACTIVE_TAG>, + <&mmnrt_virt MASTER_CAMNOC_SF RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names =3D "config", + "data"; + + iommus =3D <&apps_smmu 0x800 0x0>, + <&apps_smmu 0x820 0x0>, + <&apps_smmu 0x840 0x0>; + + operating-points-v2 =3D <&ope_opp_table>; + power-domains =3D <&gcc GCC_CAMSS_TOP_GDSC>, + <&rpmpd QCM2290_VDDCX>; + power-domain-names =3D "camss", + "cx"; + + ope_opp_table: opp-table { + compatible =3D "operating-points-v2"; + + opp-19200000 { + opp-hz =3D /bits/ 64 <19200000>; + required-opps =3D <&rpmpd_opp_min_svs>; + }; + + opp-200000000 { + opp-hz =3D /bits/ 64 <200000000>; + required-opps =3D <&rpmpd_opp_svs>; + }; + + opp-266600000 { + opp-hz =3D /bits/ 64 <266600000>; + required-opps =3D <&rpmpd_opp_svs_plus>; + }; + + opp-465000000 { + opp-hz =3D /bits/ 64 <465000000>; + required-opps =3D <&rpmpd_opp_nom>; + }; + + opp-580000000 { + opp-hz =3D /bits/ 64 <580000000>; + required-opps =3D <&rpmpd_opp_turbo>; + turbo-mode; + }; + }; + }; + mdss: display-subsystem@5e00000 { compatible =3D "qcom,qcm2290-mdss"; reg =3D <0x0 0x05e00000 0x0 0x1000>; --=20 2.34.1 From nobody Fri Sep 25 23:51:06 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4FAE44854F2 for ; Fri, 25 Sep 2026 09:10:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327413; cv=none; b=p1KzlSt587t5GW3UVRZWhjUqabeaYAwEdk+eWTFixoH5QTCp/j/7aODwKxYy8PL6haa+378/k7OQYkJlaJW74rPBwSYXSpYfS2a9f0ln8m6qoFjSVMJC0SEHXpjK2AwPvVcpkEOlgAfDoIdZkOZLA6OgCXfpaUangy6Z/BBMpKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327413; c=relaxed/simple; bh=KacuOzfLT7ghT0l8x9+HoH6R9vGKNBZqubpcPoF6wZ0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ewIubnYITbt2vsK0kqYl6apkWWVHRfttW6Ut0z0FEskpM93FiQypvC8IgJ/RkSOvoseuRW6Rnj7MilTzdUDze22OlfRqxBI05BSM2P1Ck7zfEE+IauuWBLPbAuxW120zALTrbLaAlqT6+cXwyUI7wbTJOkwpvNdLFHG0Sd84S4s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=OpYNDB9a; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=Poshcal5; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="OpYNDB9a"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="Poshcal5" Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4YW5L039598 for ; Fri, 25 Sep 2026 09:10:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= posbByi2C22vAqDX2ezu/Vx97adQ0JmvEhOqcNgZPY0=; b=OpYNDB9amq3IPPHA GQ9b3nwmdrCb4zGFzHx1gNfUp2OiDu8S7riLLmIHvcdmbQ+mshZqKed/EFYuUHU2 MlsoF5fdW82rBuWPAIEAFVjwlxPDg4itM/cwBLLq47jDXZ+2bpqlsi9wD6QVVInO hvggE/E1Tk6tYF7258Bz8SFwPKe7R+zw0RVrVoBM0NTuMw5d9x8wa4Z+4jiqW4J3 oS4Bx47q3Fd9njBrd9hCoB7htTSBM48ZvCyo9/izJRDZn2uCNdT564DMW35VliCX 5RejgwsIxGIqd2fsaYdCCZQPjfGj6sqTdUHcQuZKe7EgrA3ilcbXjsmA7uO5Fopw nPM46g== Received: from mail-qv1-f69.google.com (mail-qv1-f69.google.com [209.85.219.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw465417h-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:07 +0000 (GMT) Received: by mail-qv1-f69.google.com with SMTP id 6a1803df08f44-9143cb073b9so1033086d6.1 for ; Fri, 25 Sep 2026 02:10:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327406; x=1790932206; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=posbByi2C22vAqDX2ezu/Vx97adQ0JmvEhOqcNgZPY0=; b=Poshcal5xM3X1Og/6lUs1gY3jbn3U88B8VJarKNX7BpZT3p7olKnbAbrpXsgKTS1sz bA6YEav8kcOZhKxiZW490JcdrlTaKqTxFh3Qd4UbrLPTGlyb6wwj8gHqYMg6r51Zezql 5H/YscacXSas+CDL0yV+0xTXl8cEnJfeVd3FCuxBa3LA85/TvuOHPX89UtI/7rqPT24p kkHbT5QSoxmyJ0C8HmeD7Z+mQ21AeFtwi8DbKqWqOEzBwqieT6AN6dmQWKbfRQiKyHVo sQRZ0LBQIdqYnrXlwOcIqJv44+ds74LXpZ07ahwM0qXu7vn634GwKkJJutRmW2u0vHxl c5hg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327406; x=1790932206; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=posbByi2C22vAqDX2ezu/Vx97adQ0JmvEhOqcNgZPY0=; b=JDCi+iv46gsN/XW+qOuOwBY3r+xTzzvEWQ9bSkJhsj9KbYl92qljM/xF3w1RvSugSJ ggPPmHo3WvgnK+JXOH9sWnPRJcr5Pbn8HBLL6hyDPTtvMDpawE2SC5uwaMxQZcW5DgCq CXetlQJUNiK6TZ7I0SbTQKiqnx+GzBh8HmWOu/tl+lO66sHgnXfNe0nsymTzaZoILbVk rLmbfKiXlbyf2V3YPLszAf1FsguQoh6gwv7+04RTCoPy0KuTBRYnzqzuCEZtUNtU/yRQ Dl5ooSmBawGsrlRBYwULWYhXlpKrjiH2gWWsJU486acLKhdkX5m9mhj+nzLt6JcMLAF1 gqSQ== X-Forwarded-Encrypted: i=1; AKwUvByAvNr+W3n+Uh2Jr3IUan0aYkfknIvQzHiWtR6nDY8Fxw4N3ywSxkBCJV+Ramhh63G7qzBvlkDwr2KQnv4=@vger.kernel.org X-Gm-Message-State: AFuF++klCPU4cXaql83fjZlbbU1o65TrDerRZ49cIoO7IACO0m93st+K QhaNYjepPzICMxSSRMjzSk//b7Wf0EOd6SBla46jG8ctAI84OdULdiGPF9pZUnlOyG4g7YRCG8Y /NWy/d1rVuatENOVUObpgzWKPbqtEGVeIaVlLoBG9BXzySifbxZjnXVEQpOJcDPL0TGc= X-Gm-Gg: AYBFou2obeKayWJ2zlSNEWpMSva98wvWj3BVPHLMGCFtCc6yQA2y5tQMHO2/CIZkYbV m5dxWmf0SCxcHjfUdMFreFI/CGXqSZ1Nod3mX70SRL10jXwG7uJ6fObu+2d2eWWM0qA1fOfz01u OeVIa7TRhQROdTD4CI1JqVnIj5bkhLgTTD7sjGzzvDZ20a+BVzNUeKn8YWG9YXykMFGrF+o7kSE NTTu4aP8d5hzqmBrZ9ixomIUyelOTGJKDS1v0CVNkqzQ4kZPkEWdcARIw7sPEUC7tP9BV4M8xJL wVXnYeZCZliEsPnJ0QJdExiQpQ+TkKqLW0nD8GDNT44kt3XaTYILISYXE96nOfn2sqOYFgBke+q ygEvLytvYdCVkMEaWr/nSC7vfdw5PZSW8A96foYCMwcXO/ViTbjBg9pUNdg/hY2KYH/W3DlnCzp XdSqShdOrm12iU7ivjVAN4H+rjEGacxkjNuJne65ThXMxgHquCxe8= X-Received: by 2002:a05:620a:4495:b0:936:6c8a:f7aa with SMTP id af79cd13be357-93c43b86612mr335564185a.4.1790327406372; Fri, 25 Sep 2026 02:10:06 -0700 (PDT) X-Received: by 2002:a05:620a:4495:b0:936:6c8a:f7aa with SMTP id af79cd13be357-93c43b86612mr335559785a.4.1790327405903; Fri, 25 Sep 2026 02:10:05 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.10.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:10:05 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:55 +0200 Subject: [PATCH v10 8/9] arm64: dts: qcom: shikra: Add OPE node Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-8-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Nihal Kumar Gupta , Abel Vesa X-Mailer: b4 0.14.2 X-Authority-Analysis: v=2.4 cv=Wrq+otfv c=1 sm=1 tr=0 ts=6ab63a6f cx=c_pps a=wEM5vcRIz55oU/E2lInRtA==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=rJkE3RaqiGZ5pbrm-msn:22 a=EUspDBNiAAAA:8 a=EzCDy3pf2FPqfMyO2-oA:9 a=QEXdDO2ut3YA:10 a=OIgjcC2v60KrkQgK7BGD:22 X-Proofpoint-ORIG-GUID: jB4Gc5xJYCPhxvq_yYI43U3zs8q07o_C X-Proofpoint-GUID: jB4Gc5xJYCPhxvq_yYI43U3zs8q07o_C X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX6enYtR7H4ZPN WuBYJw7hCd1PSHI+EdNYYnpdFouULxAitpKNZxBDGxdrpT+HoKMMU2+aGORMehfrKKP6tAk/nSe Bw/zgZKcPk/CEyF7UOvoDTQC11j3/aZsHzdVfMSnxO42IqG8dj+gSVLeKtIhpU04VU19elEEzlx XnAXmO1LNmA4OI/wk2p1zHw138Ak7rqS3pRvKaxr4dXnN22f5ngcz59ulWBL8i0XgncAABYvnlk tuo4IKbYZFvZD6MLGRsONcKjNjR1jXHZIsivf963ppHG/0IF+gNWo74BwelLrKh/vzP2Z/tmCYl 6DurmurLRdGD6nFrO8S/bwtNBe5V6FvZQRaiJi7aMADBTLSCxB/YX5VmkPHAKtjyFVfqiBJQPfQ 35jnzb52besKZi4rJItQnwQaEQCkkpxak8D2iB8Xz2bYDDemYEnQ3gd0VO00/dP3KSJAIDzHGhX N9itQgu0LiVRUy/zQSQ== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX8uZVG34bTAu2 CAgMQ+4mlNIXzhGA1mUJBSlyCXtxo3DrWO9WsSuxvv1invUAJ0TtHmIsVMP1zX1JGEYxNEaCA2s uuEiWRL1l4WlfEyemjXrBv1oKhOKwHU= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 lowpriorityscore=0 adultscore=0 impostorscore=0 bulkscore=0 suspectscore=0 priorityscore=1501 clxscore=1015 malwarescore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 From: Nihal Kumar Gupta Add the Offline Processing Engine (OPE) device tree node for Shikra. The node describes the six register regions (cdm, top, qos, pipeline, bus_read, bus_write), clocks, interrupt, interconnects, IOMMU mappings, and OPP table. OPE is a memory-to-memory block with no board-level dependencies, so the node is left enabled for all Shikra boards. Signed-off-by: Nihal Kumar Gupta Reviewed-by: Abel Vesa Signed-off-by: Loic Poulain --- arch/arm64/boot/dts/qcom/shikra.dtsi | 77 ++++++++++++++++++++++++++++++++= ++++ 1 file changed, 77 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qco= m/shikra.dtsi index 92d22e3b6931cf49f213d1807f78fc1a261f290d..5adc28e9aa64508366e6c7fdad1= 91a152b8cb6dc 100644 --- a/arch/arm64/boot/dts/qcom/shikra.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi @@ -1828,6 +1828,83 @@ &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, }; }; =20 + isp_ope: isp@5c42000 { + compatible =3D "qcom,shikra-camss-ope", "qcom,qcm2290-camss-ope"; + + reg =3D <0x0 0x5c42000 0x0 0x400>, + <0x0 0x5c42400 0x0 0x200>, + <0x0 0x5c42600 0x0 0x200>, + <0x0 0x5c42800 0x0 0x4400>, + <0x0 0x5c46c00 0x0 0x190>, + <0x0 0x5c46d90 0x0 0xa00>; + reg-names =3D "cdm", + "top", + "qos", + "pipeline", + "bus_read", + "bus_write"; + + clocks =3D <&gcc GCC_CAMSS_AXI_CLK>, + <&gcc GCC_CAMSS_OPE_CLK>, + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_NRT_AXI_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>; + clock-names =3D "axi", + "core", + "iface", + "nrt", + "top"; + + interrupts =3D ; + + interconnects =3D <&mem_noc MASTER_AMPSS_M0 RPM_ACTIVE_TAG + &config_noc SLAVE_CAMERA_CFG RPM_ACTIVE_TAG>, + <&mmnrt_virt MASTER_CAMNOC_SF RPM_ALWAYS_TAG + &mc_virt SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names =3D "config", + "data"; + + iommus =3D <&apps_smmu 0x600 0x0>, + <&apps_smmu 0x620 0x0>, + <&apps_smmu 0x640 0x0>; + + operating-points-v2 =3D <&ope_opp_table>; + power-domains =3D <&gcc GCC_CAMSS_TOP_GDSC>, + <&rpmpd RPMPD_VDDCX>; + power-domain-names =3D "camss", + "cx"; + + ope_opp_table: opp-table { + compatible =3D "operating-points-v2"; + + opp-19200000 { + opp-hz =3D /bits/ 64 <19200000>; + required-opps =3D <&rpmpd_opp_min_svs>; + }; + + opp-200000000 { + opp-hz =3D /bits/ 64 <200000000>; + required-opps =3D <&rpmpd_opp_svs>; + }; + + opp-266600000 { + opp-hz =3D /bits/ 64 <266600000>; + required-opps =3D <&rpmpd_opp_svs_plus>; + }; + + opp-465000000 { + opp-hz =3D /bits/ 64 <465000000>; + required-opps =3D <&rpmpd_opp_nom>; + }; + + opp-580000000 { + opp-hz =3D /bits/ 64 <580000000>; + required-opps =3D <&rpmpd_opp_turbo>; + turbo-mode; + }; + }; + }; + remoteproc_mpss: remoteproc@6080000 { compatible =3D "qcom,shikra-mpss-pas"; reg =3D <0x0 0x06080000 0x0 0x100>; --=20 2.34.1 From nobody Fri Sep 25 23:51:06 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 23C3F488234 for ; Fri, 25 Sep 2026 09:10:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327416; cv=none; b=XUjvwi8MS9qkk+HQkFC4U2epuna7vXTkXf25qUxEtIKZQyxivttisBYjEeBb2bJkHqT9FQXSY4UhQSLR+pyEKIXu4sTRLN/66A29fBSip5PJkoHxXaH5dLzkavmo7pTi2xySuvSTINRiL+zLstNGPRDYLZxLloroRzvujw+KXv0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790327416; c=relaxed/simple; bh=Dzpg26Vur2DCvULsTE9E1JAC2Y7NSf6GVeoLlup85aI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lgL+dxbT+R47/SZh8EPEkQo8ECKBH77Wcmg0/Aw+8ErkcWa1Jjhj/TDBXWtswUZrXJ/2O1yuQEieVYjG+ybPN810vGEwcnNgwXROrQK6FXnG98+NpW2GjBLt0JHaIZhwvVp8cOe4rnuOP+bGwUSh/KTCWYKnRjVKB6muHrJunvg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=VCXfdnzs; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=JFXYL+eo; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="VCXfdnzs"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="JFXYL+eo" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68P4YpIk208828 for ; Fri, 25 Sep 2026 09:10:12 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= ooijHQlhry9x8ePNW1MEInw6PQc9F5ZMCpXfK0l0qXU=; b=VCXfdnzsBuAxysu4 O6uJHtTkow49ha/+RPdqHJab41tX5nEczGltusQP0GLq5MsO4Nt1yHTL09vacODl OVmcsrgON/EaByj2NDK0DIcw7vhOe4+wHKJWp0aAUKkn8zgXLrlasPU0eNPVvRgs rQTntLrm4AmkJTowsjg1cJ14Add6dE6IHzwhlginxV2GxGzY4wo7mXoKyuRz964h A46AOhScf3JcRZmV76f+3mlqnJOQKUBxEJ9hgYDuD+mmb13ou8TwgDj/yN96MeDN oaDgBBcaP7GAtNIchR19Ypx0UNMVLWTU4+R7ZZ+bKT0pCrcftaEkBJjhPJeCYqKC udwEiQ== Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4gw898tugb-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 25 Sep 2026 09:10:10 +0000 (GMT) Received: by mail-qk1-f199.google.com with SMTP id af79cd13be357-939c30aa9a0so70256585a.0 for ; Fri, 25 Sep 2026 02:10:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1790327409; x=1790932209; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ooijHQlhry9x8ePNW1MEInw6PQc9F5ZMCpXfK0l0qXU=; b=JFXYL+eonL3NXP0P2pMWehXGcBhZT4a/3iDTpPm9fAHUzn2kvxbI7TPWNteVhQzOs/ dab7ULbyvb9JiHtvb08qc/QUEoQefJsNQc7SXIrHArR1jSE80J9sJCR8ABDmkxPcKkHM 4GDjmoVYXALxWkSc+cdsWmvxPDCqnT67Odx2Jcgo5xnRU662pVxQDRya2+Yo4ZW7C7Ml yefvJURjCJDoF0vo1QsPzro2u3v+zcLxkbNdvKht9BgOwl8ugusla4mZv/OjLNwdraQN rjUofeg+x3KD5LCVprFWYSz8FCC40TV5sL8tQ+ZYHS6cjuzoKNF7u17nYUxB8MpZ1zzD nxVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790327409; x=1790932209; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ooijHQlhry9x8ePNW1MEInw6PQc9F5ZMCpXfK0l0qXU=; b=FSGsDLo1azbUqRC2Q+/BBzx3li8R5aQRrC30NxS6yFpyr67Meq1q3sOtwfvyx2jvqR FxrdR84kfA6sQGBXmZYHItOkGXvvukkZVG3vOfIUw/ErBv+NO5D5zvEZ+l4lMo+bEePA T570CkKcKcDGrFOw6Lt1YA6m0GVvZiSnpaJGnF4HKgv4CdDzIjQ6DGI3UxuIyg8y6t3Q H6CT+q95Bg2N0VszdrrzO4yBYKfBUK4K/JYK5l6pz+JCrY8inXeVbnGedjTvKVZbbKjM ts+mYGnheBfXbyGnEbAcv+uTbywhee1Tl82ryn72X4DvNvBKPr39vyovXADHuxlilobH Ah8A== X-Forwarded-Encrypted: i=1; AKwUvBw6t4oWUoSlOAnW1yZaLgVZEUmCO024El0X+DAAf7eL4HX8njl54m5hRrzCqQlumHVJmLPWTkuEikUQrVE=@vger.kernel.org X-Gm-Message-State: AFuF++nWenXuCDKuQ6L7VV4rXSMzBR1PtCwxKCLCRSyb/nnnQedPlG7N M+l9bZlHBXpEGm25s0LIPZki6oTBQcJ+a0a2DB82cq7P4Rq6DFxmX0iIHxfzJWtFfhIO7ZYrgje Voz3tYmcDH/m4BW+30FkLrMin5glW8obGTKjM/Mh5uKNy8o3TnsSK8CqLDbSS0w8dJDI= X-Gm-Gg: AYBFou1TDopRfV319+vmXIAHwUSQ0+3AwBlZOfse6t4AC4LRJyeOsVppNgEj28IFyf0 75/Vyar6bfH7K0rDZWGEPwnCGOhCsdsLoWraqYpuSk37Rg2Mp5MCNqQnwpwqdYpZwB/bV5xwpU8 uBcyWjjlF7xhrTrgI9Fm0bt3j87sTpshVc+foac6cfeEKFGAcFsfNGSKp37pQOQqshQFCkwq9Gx DoxDWGE0nR/WnP0TXiqFNnTp+RXnHuNIia340aDbB3MHUklD6Z3P3r19zcHfd7NDzBwlhAsla8w gneBGC6dBIJI/DQ+egEjTt30KAfq/qQT+S+wpOKQeTQ6cOU9Ria0mQ1xjAc6xTaiZdJI5LywaN4 mhOaLiAxzmbUSrk2j6epklv55AXbXxi+V/z5CDY0c4L9Z1fdQOeX/tZoBVLzvC+ouOpbnchS+9+ iqbkLtEACUmzslhF2sdnkTgAmlQXnslyD4b0/t0YAeJ1Sks/hgz0I= X-Received: by 2002:a05:620a:199b:b0:93b:e917:6888 with SMTP id af79cd13be357-93c43cb6c72mr320195985a.33.1790327409485; Fri, 25 Sep 2026 02:10:09 -0700 (PDT) X-Received: by 2002:a05:620a:199b:b0:93b:e917:6888 with SMTP id af79cd13be357-93c43cb6c72mr320192385a.33.1790327408916; Fri, 25 Sep 2026 02:10:08 -0700 (PDT) Received: from QCOM-eG0v1AUPpu.na.qualcomm.com ([2a01:e0a:830:450:5c1f:3897:a4a1:99e1]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a638sm5269890f8f.9.2026.09.25.02.10.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Sep 2026 02:10:06 -0700 (PDT) From: Loic Poulain Date: Fri, 25 Sep 2026 11:09:56 +0200 Subject: [PATCH v10 9/9] arm64: defconfig: Enable Qualcomm CAMSS OPE driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260925-camss-isp-ope-v10-9-2622411034cb@oss.qualcomm.com> References: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> In-Reply-To: <20260925-camss-isp-ope-v10-0-2622411034cb@oss.qualcomm.com> To: Mauro Carvalho Chehab , Bryan O'Donoghue , Vladimir Zapolskiy , Loic Poulain , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Kees Cook , "Gustavo A. R. Silva" , Bjorn Andersson , Konrad Dybcio , Bryan O'Donoghue Cc: linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-hardening@vger.kernel.org, Nihal Kumar Gupta X-Mailer: b4 0.14.2 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX+CPvNGZ171ri YwontOfh5seTLA7hdwQSNkPlizvyINte6AxjQe7ZlPtbnj1BxH9/NXH6wZuXcIIRPvP0mJOEW42 Vdoj/gbUU2Gue6XAxj+agWtegn0hA6L4z3eEuIKub6m0DT9d+0jjCGYrSbHnqfPvqOeM4o9arCs 1zKBxheJR1yTcj7pK8Rb5PWJgC/ZymirGAk9VP+vn+HUubFY4ZsGnnwk4PabMtbu5rUsHvJyZB3 zrpKz4WiMv2HddlnO5asX10VWPajo3SSlCo7T2cH8VmZibDjndIormP2HRLvbC7bHe9GolX9fAz u4nwQxFXD6e73wio+HeDQnAOOMK9XcY7AzMjUVzzk4eAR6jsZ64XQOwV+8gQFsj/uVKlOkb/02x OAhovYc/77MZ5P0XtTOK6wQEcyeMP1N/y6+ujGV65WO/Q4dxh6vQy+vKg5fdevlK/aF1gtRKvnW gSMB0f7IVSdhfe81FOw== X-Proofpoint-Spam-Info: AW1haW4tMjYwOTI1MDAzNiBTYWx0ZWRfX6v/+rxKbGHDO aVXSmjBbPhrKShGFap10RefY2suW+8fk98nk0jxcRBFqp7EPlAU11Ow+3Jg9ac4WtKz5lrrC0B4 2DjJMmySpVEl108cwb0zbnZQvyXpHZ8= X-Proofpoint-GUID: vk2PhhX-6aMZD3F-GuFdjo4-w0co9oS_ X-Proofpoint-ORIG-GUID: vk2PhhX-6aMZD3F-GuFdjo4-w0co9oS_ X-Authority-Analysis: v=2.4 cv=EJWTQFZC c=1 sm=1 tr=0 ts=6ab63a72 cx=c_pps a=HLyN3IcIa5EE8TELMZ618Q==:117 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=VdqzKS8jKosA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yOCtJkima9RkubShWh1s:22 a=EUspDBNiAAAA:8 a=BUwzsxYIp--Ly0ysDZIA:9 a=QEXdDO2ut3YA:10 a=bTQJ7kPSJx9SKPbeHEYW:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-25_02,2026-09-21_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 clxscore=1015 spamscore=0 lowpriorityscore=0 suspectscore=0 impostorscore=0 bulkscore=0 phishscore=0 adultscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609250036 From: Nihal Kumar Gupta Add CONFIG_VIDEO_QCOM_CAMSS_OPE=3Dm to enable the Qualcomm Offline Processi= ng Engine (OPE) driver, an image processing block available on Qualcomm Agatti and Shikra based platforms such as the Arduino UNO Q. Signed-off-by: Nihal Kumar Gupta Signed-off-by: Loic Poulain --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 6ec8d3a69c98e0da38465010d11166bb0e058f4a..604a0d58521dd6a1df8718ea3fc= e28cc727a08a0 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -931,6 +931,7 @@ CONFIG_VIDEO_IMX8_ISI=3Dm CONFIG_VIDEO_IMX8_ISI_M2M=3Dy CONFIG_VIDEO_IMX8_JPEG=3Dm CONFIG_VIDEO_QCOM_CAMSS=3Dm +CONFIG_VIDEO_QCOM_CAMSS_OPE=3Dm CONFIG_VIDEO_QCOM_IRIS=3Dm CONFIG_VIDEO_QCOM_VENUS=3Dm CONFIG_VIDEO_RCAR_CSI2=3Dm --=20 2.34.1